stage2: add floatCast to zir and ir

This commit is contained in:
Vexu 2020-07-21 17:14:40 +03:00
parent 7b52dbbf83
commit 7e7d1df4da
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
5 changed files with 120 additions and 67 deletions

View File

@ -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);
}
}

View File

@ -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}),
}
}

View File

@ -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 {

View File

@ -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,

View File

@ -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);