stage2: implement some casts for numbers
parent
da217fadeb
commit
7b52dbbf83
|
@ -3358,6 +3358,14 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
|
|||
return self.bitcast(scope, dest_type, inst);
|
||||
}
|
||||
|
||||
// undefined to anything
|
||||
if (inst.value()) |val| {
|
||||
if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
|
||||
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
|
||||
}
|
||||
}
|
||||
assert(inst.ty.zigTypeTag() != .Undefined);
|
||||
|
||||
// *[N]T to []T
|
||||
if (inst.ty.isSinglePointer() and dest_type.isSlice() and
|
||||
(!inst.ty.pointerIsConst() or dest_type.pointerIsConst()))
|
||||
|
@ -3371,34 +3379,58 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
|
|||
}
|
||||
}
|
||||
|
||||
// comptime_int to fixed-width integer
|
||||
if (inst.ty.zigTypeTag() == .ComptimeInt and dest_type.zigTypeTag() == .Int) {
|
||||
// The representation is already correct; we only need to make sure it fits in the destination type.
|
||||
const val = inst.value().?; // comptime_int always has comptime known value
|
||||
if (!val.intFitsInType(dest_type, self.target())) {
|
||||
return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
|
||||
// comptime known number to other number
|
||||
if (inst.value()) |val| {
|
||||
const src_zig_tag = inst.ty.zigTypeTag();
|
||||
const dst_zig_tag = dest_type.zigTypeTag();
|
||||
|
||||
if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
|
||||
if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
|
||||
if (val.floatHasFraction()) {
|
||||
return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
|
||||
}
|
||||
return self.fail(scope, inst.src, "TODO float to int", .{});
|
||||
} else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
|
||||
if (!val.intFitsInType(dest_type, self.target())) {
|
||||
return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
|
||||
}
|
||||
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
|
||||
}
|
||||
} else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
|
||||
if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
|
||||
return self.fail(scope, inst.src, "TODO float cast", .{});
|
||||
} else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
|
||||
return self.fail(scope, inst.src, "TODO int to float", .{});
|
||||
}
|
||||
}
|
||||
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
|
||||
}
|
||||
|
||||
// integer widening
|
||||
if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
|
||||
assert(inst.value() == null); // handled above
|
||||
|
||||
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 (inst.value()) |val| {
|
||||
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
|
||||
} else {
|
||||
return self.fail(scope, inst.src, "TODO implement runtime integer widening ({} to {})", .{
|
||||
inst.ty,
|
||||
dest_type,
|
||||
});
|
||||
}
|
||||
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 });
|
||||
}
|
||||
}
|
||||
|
||||
// float widening
|
||||
if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
|
||||
assert(inst.value() == null); // handled above
|
||||
|
||||
const src_bits = inst.ty.floatBits(self.target());
|
||||
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.fail(scope, inst.src, "TODO implement type coercion from {} to {}", .{ inst.ty, dest_type });
|
||||
}
|
||||
|
||||
|
|
|
@ -459,6 +459,16 @@ 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).?),
|
||||
}
|
||||
}
|
||||
|
||||
fn genWidenOrShorten(self: *Self, inst: *ir.Inst.WidenOrShorten) !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}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ pub const Inst = struct {
|
|||
sub,
|
||||
unreach,
|
||||
not,
|
||||
widenorshorten,
|
||||
|
||||
/// There is one-to-one correspondence between tag and type for now,
|
||||
/// but this will not always be the case. For example, binary operations
|
||||
|
@ -108,6 +109,7 @@ pub const Inst = struct {
|
|||
.call => Call,
|
||||
.condbr => CondBr,
|
||||
.constant => Constant,
|
||||
.widenorshorten => WidenOrShorten,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -374,6 +376,15 @@ 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 {
|
||||
|
|
|
@ -558,6 +558,7 @@ pub const Inst = struct {
|
|||
|
||||
pub const IntCast = struct {
|
||||
pub const base_tag = Tag.intcast;
|
||||
pub const builtin_name = "@intCast";
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
|
@ -569,6 +570,7 @@ pub const Inst = struct {
|
|||
|
||||
pub const BitCast = struct {
|
||||
pub const base_tag = Tag.bitcast;
|
||||
pub const builtin_name = "@bitCast";
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
|
@ -1820,6 +1822,10 @@ 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);
|
||||
|
|
Loading…
Reference in New Issue