diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 0376d5a11d..1ebed4e09a 100644 --- a/src-self-hosted/Module.zig +++ b/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); } } diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 7db3bcb4aa..7e71cc55db 100644 --- a/src-self-hosted/codegen.zig +++ b/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}), } } diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 4d82920e52..f501627691 100644 --- a/src-self-hosted/ir.zig +++ b/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 { diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index e54836ba11..8ca43c398b 100644 --- a/src-self-hosted/value.zig +++ b/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, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 3debb1efe4..d2df0afaf5 100644 --- a/src-self-hosted/zir.zig +++ b/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);