Commit 7e7d1df4da

Vexu <git@vexu.eu>
2020-07-21 16:14:40
stage2: add floatCast to zir and ir
1 parent 7b52dbb
Changed files (5)
src-self-hosted/codegen.zig
@@ -459,16 +459,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                 .sub => return self.genSub(inst.castTag(.sub).?),
                 .unreach => return MCValue{ .unreach = {} },
                 .not => return self.genNot(inst.castTag(.not).?),
-                .widenorshorten => return self.genWidenOrShorten(isnt.castTag(.widenorshorten).?),
+                .floatcast => return self.genFloatCast(inst.castTag(.floatcast).?),
+                .intcast => return self.genIntCast(inst.castTag(.intcast).?),
             }
         }
 
-        fn genWidenOrShorten(self: *Self, inst: *ir.Inst.WidenOrShorten) !MCValue {
+        fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
             // No side effects, so if it's unreferenced, do nothing.
             if (inst.base.isUnused())
                 return MCValue.dead;
             switch (arch) {
-                else => return self.fail(inst.base.src, "TODO implement widen or shorten for {}", .{self.target.cpu.arch}),
+                else => return self.fail(inst.base.src, "TODO implement floatCast for {}", .{self.target.cpu.arch}),
+            }
+        }
+
+        fn genIntCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
+            // No side effects, so if it's unreferenced, do nothing.
+            if (inst.base.isUnused())
+                return MCValue.dead;
+            switch (arch) {
+                else => return self.fail(inst.base.src, "TODO implement intCast for {}", .{self.target.cpu.arch}),
             }
         }
 
src-self-hosted/ir.zig
@@ -71,7 +71,8 @@ pub const Inst = struct {
         sub,
         unreach,
         not,
-        widenorshorten,
+        floatcast,
+        intcast,
 
         /// There is one-to-one correspondence between tag and type for now,
         /// but this will not always be the case. For example, binary operations
@@ -90,6 +91,8 @@ pub const Inst = struct {
                 .isnonnull,
                 .isnull,
                 .ptrtoint,
+                .floatcast,
+                .intcast,
                 => UnOp,
 
                 .add,
@@ -109,7 +112,6 @@ pub const Inst = struct {
                 .call => Call,
                 .condbr => CondBr,
                 .constant => Constant,
-                .widenorshorten => WidenOrShorten,
             };
         }
 
@@ -376,15 +378,6 @@ pub const Inst = struct {
             return null;
         }
     };
-
-    pub const WidenOrShorten = struct {
-        pub const base_tag = Tag.widenorshorten;
-
-        base: Inst,
-        args: struct {
-            operand: *Inst,
-        },
-    };
 };
 
 pub const Body = struct {
src-self-hosted/Module.zig
@@ -2352,6 +2352,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
         .fntype => return self.analyzeInstFnType(scope, old_inst.castTag(.fntype).?),
         .intcast => return self.analyzeInstIntCast(scope, old_inst.castTag(.intcast).?),
         .bitcast => return self.analyzeInstBitCast(scope, old_inst.castTag(.bitcast).?),
+        .floatcast => return self.analyzeInstFloatCast(scope, old_inst.castTag(.floatcast).?),
         .elemptr => return self.analyzeInstElemPtr(scope, old_inst.castTag(.elemptr).?),
         .add => return self.analyzeInstAdd(scope, old_inst.castTag(.add).?),
         .sub => return self.analyzeInstSub(scope, old_inst.castTag(.sub).?),
@@ -2796,16 +2797,16 @@ fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPt
     }
 }
 
-fn analyzeInstIntCast(self: *Module, scope: *Scope, intcast: *zir.Inst.IntCast) InnerError!*Inst {
-    const dest_type = try self.resolveType(scope, intcast.positionals.dest_type);
-    const new_inst = try self.resolveInst(scope, intcast.positionals.value);
+fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) InnerError!*Inst {
+    const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
+    const operand = try self.resolveInst(scope, inst.positionals.operand);
 
     const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
         .ComptimeInt => true,
         .Int => false,
         else => return self.fail(
             scope,
-            intcast.positionals.dest_type.src,
+            inst.positionals.dest_type.src,
             "expected integer type, found '{}'",
             .{
                 dest_type,
@@ -2813,21 +2814,23 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, intcast: *zir.Inst.IntCast)
         ),
     };
 
-    switch (new_inst.ty.zigTypeTag()) {
+    switch (operand.ty.zigTypeTag()) {
         .ComptimeInt, .Int => {},
         else => return self.fail(
             scope,
-            intcast.positionals.value.src,
+            inst.positionals.operand.src,
             "expected integer type, found '{}'",
-            .{new_inst.ty},
+            .{operand.ty},
         ),
     }
 
-    if (dest_is_comptime_int or new_inst.value() != null) {
-        return self.coerce(scope, dest_type, new_inst);
+    if (operand.value() != null) {
+        return self.coerce(scope, dest_type, operand);
+    } else if (dest_is_comptime_int) {
+        return self.fail(scope, inst.base.src, "unable to cast runtime value to 'comptime_int'", .{});
     }
 
-    return self.fail(scope, intcast.base.src, "TODO implement analyze widen or shorten int", .{});
+    return self.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{});
 }
 
 fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) InnerError!*Inst {
@@ -2836,6 +2839,42 @@ fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) Inn
     return self.bitcast(scope, dest_type, operand);
 }
 
+fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.FloatCast) InnerError!*Inst {
+    const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
+    const operand = try self.resolveInst(scope, inst.positionals.operand);
+
+    const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
+        .ComptimeFloat => true,
+        .Float => false,
+        else => return self.fail(
+            scope,
+            inst.positionals.dest_type.src,
+            "expected float type, found '{}'",
+            .{
+                dest_type,
+            },
+        ),
+    };
+
+    switch (operand.ty.zigTypeTag()) {
+        .ComptimeFloat, .Float, .ComptimeInt => {},
+        else => return self.fail(
+            scope,
+            inst.positionals.operand.src,
+            "expected float type, found '{}'",
+            .{operand.ty},
+        ),
+    }
+
+    if (operand.value() != null) {
+        return self.coerce(scope, dest_type, operand);
+    } else if (dest_is_comptime_float) {
+        return self.fail(scope, inst.base.src, "unable to cast runtime value to 'comptime_float'", .{});
+    }
+
+    return self.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{});
+}
+
 fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) InnerError!*Inst {
     const array_ptr = try self.resolveInst(scope, inst.positionals.array_ptr);
     const uncasted_index = try self.resolveInst(scope, inst.positionals.index);
@@ -3411,11 +3450,12 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
 
         const src_info = inst.ty.intInfo(self.target());
         const dst_info = dest_type.intInfo(self.target());
-        if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) {
+        if ((src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) or
+        // small enough unsigned ints can get casted to large enough signed ints
+            (src_info.signed and !dst_info.signed and dst_info.bits > src_info.bits))
+        {
             const b = try self.requireRuntimeBlock(scope, inst.src);
-            return self.addNewInstArgs(b, inst.src, dest_type, Inst.WidenOrShorten, .{ .operand = inst });
-        } else {
-            return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
+            return self.addUnOp(b, inst.src, dest_type, .intcast, inst);
         }
     }
 
@@ -3427,7 +3467,7 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
         const dst_bits = dest_type.floatBits(self.target());
         if (dst_bits >= src_bits) {
             const b = try self.requireRuntimeBlock(scope, inst.src);
-            return self.addNewInstArgs(b, inst.src, dest_type, Inst.WidenOrShorten, .{ .operand = inst });
+            return self.addUnOp(b, inst.src, dest_type, .floatcast, inst);
         }
     }
 
src-self-hosted/value.zig
@@ -80,7 +80,6 @@ pub const Value = extern union {
         elem_ptr,
         bytes,
         repeated, // the value is a value repeated some number of times
-        float,
         float_16,
         float_32,
         float_64,
@@ -221,7 +220,7 @@ pub const Value = extern union {
             .float_16 => return self.copyPayloadShallow(allocator, Payload.Float_16),
             .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),
             .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
-            .float_128, .float => return self.copyPayloadShallow(allocator, Payload.Float_128),
+            .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),
         }
     }
 
@@ -312,7 +311,7 @@ pub const Value = extern union {
             .float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}),
             .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
             .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
-            .float_128, .float => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
+            .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
         };
     }
 
@@ -393,7 +392,6 @@ pub const Value = extern union {
             .elem_ptr,
             .bytes,
             .repeated,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -453,7 +451,6 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -525,7 +522,6 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -560,7 +556,7 @@ pub const Value = extern union {
             .float_16 => self.cast(Payload.Float_16).?.val,
             .float_32 => self.cast(Payload.Float_32).?.val,
             .float_64 => self.cast(Payload.Float_64).?.val,
-            .float_128, .float => self.cast(Payload.Float_128).?.val,
+            .float_128 => self.cast(Payload.Float_128).?.val,
 
             .zero, .the_one_possible_value => 0,
             .int_u64 => @intToFloat(f128, self.cast(Payload.Int_u64).?.int),
@@ -624,7 +620,6 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -701,7 +696,6 @@ pub const Value = extern union {
             .elem_ptr,
             .bytes,
             .repeated,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -830,8 +824,8 @@ pub const Value = extern union {
             .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
             .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
             .float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0,
-            // .float_128, .float => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
-            .float_128, .float => @panic("TODO lld: error: undefined symbol: fmodl"),
+            // .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
+            .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
         };
     }
 
@@ -902,7 +896,7 @@ pub const Value = extern union {
             .float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0),
             .float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0),
             .float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0),
-            .float_128, .float => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
+            .float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
         };
     }
 
@@ -923,7 +917,7 @@ pub const Value = extern union {
                     .float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val),
                     .float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val),
                     .float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val),
-                    .float_128, .float => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
+                    .float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
                     else => unreachable,
                 };
             }
@@ -1012,7 +1006,6 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -1088,7 +1081,6 @@ pub const Value = extern union {
             .elem_ptr,
             .ref_val,
             .decl_ref,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -1179,7 +1171,6 @@ pub const Value = extern union {
             .elem_ptr,
             .bytes,
             .repeated,
-            .float,
             .float_16,
             .float_32,
             .float_64,
@@ -1196,7 +1187,6 @@ pub const Value = extern union {
         return switch (self.tag()) {
             .undef => unreachable,
 
-            .float,
             .float_16,
             .float_32,
             .float_64,
src-self-hosted/zir.zig
@@ -76,6 +76,7 @@ pub const Inst = struct {
         primitive,
         intcast,
         bitcast,
+        floatcast,
         elemptr,
         add,
         sub,
@@ -137,6 +138,7 @@ pub const Inst = struct {
                 .fntype => FnType,
                 .intcast => IntCast,
                 .bitcast => BitCast,
+                .floatcast => FloatCast,
                 .elemptr => ElemPtr,
                 .condbr => CondBr,
             };
@@ -169,6 +171,7 @@ pub const Inst = struct {
                 .primitive,
                 .intcast,
                 .bitcast,
+                .floatcast,
                 .elemptr,
                 .add,
                 .sub,
@@ -556,6 +559,18 @@ pub const Inst = struct {
         };
     };
 
+    pub const FloatCast = struct {
+        pub const base_tag = Tag.floatcast;
+        pub const builtin_name = "@floatCast";
+        base: Inst,
+
+        positionals: struct {
+            dest_type: *Inst,
+            operand: *Inst,
+        },
+        kw_args: struct {},
+    };
+
     pub const IntCast = struct {
         pub const base_tag = Tag.intcast;
         pub const builtin_name = "@intCast";
@@ -563,7 +578,7 @@ pub const Inst = struct {
 
         positionals: struct {
             dest_type: *Inst,
-            value: *Inst,
+            operand: *Inst,
         },
         kw_args: struct {},
     };
@@ -1620,6 +1635,28 @@ const EmitZIR = struct {
         return &new_inst.base;
     }
 
+    fn emitCast(
+        self: *EmitZIR,
+        src: usize,
+        new_body: ZirBody,
+        old_inst: *ir.Inst.UnOp,
+        comptime I: type,
+    ) Allocator.Error!*Inst {
+        const new_inst = try self.arena.allocator.create(I);
+        new_inst.* = .{
+            .base = .{
+                .src = src,
+                .tag = I.base_tag,
+            },
+            .positionals = .{
+                .dest_type = (try self.emitType(src, old_inst.base.ty)).inst,
+                .operand = try self.resolveInst(new_body, old_inst.operand),
+            },
+            .kw_args = .{},
+        };
+        return &new_inst.base;
+    }
+
     fn emitBody(
         self: *EmitZIR,
         body: ir.Body,
@@ -1654,22 +1691,9 @@ const EmitZIR = struct {
                 .cmp_gt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gt).?, .cmp_gt),
                 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),
 
-                .bitcast => blk: {
-                    const old_inst = inst.castTag(.bitcast).?;
-                    const new_inst = try self.arena.allocator.create(Inst.BitCast);
-                    new_inst.* = .{
-                        .base = .{
-                            .src = inst.src,
-                            .tag = Inst.BitCast.base_tag,
-                        },
-                        .positionals = .{
-                            .dest_type = (try self.emitType(inst.src, inst.ty)).inst,
-                            .operand = try self.resolveInst(new_body, old_inst.operand),
-                        },
-                        .kw_args = .{},
-                    };
-                    break :blk &new_inst.base;
-                },
+                .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, Inst.BitCast),
+                .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, Inst.IntCast),
+                .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, Inst.FloatCast),
 
                 .block => blk: {
                     const old_inst = inst.castTag(.block).?;
@@ -1822,10 +1846,6 @@ const EmitZIR = struct {
                     };
                     break :blk &new_inst.base;
                 },
-                .widenorshorten => blk: {
-                    const old_inst = inst.cast(ir.Inst.WidenOrShorten).?;
-                    break :blk try self.resolveInst(new_body, old_inst.args.operand);
-                },
             };
             try instructions.append(new_inst);
             try inst_table.put(inst, new_inst);