authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-07-20 22:45:27+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-07-21 22:29:29+03:00
log7b52dbbf83ec89b9337e2be7328480e83489dc0d
tree5f3070c46bc3a0e5c85de1cfb433845cf2e782f7
parentda217fadeb888ba1286e36ab42bdbe9918426a0a
signature Commit is signed but in an unrecognized format.

stage2: implement some casts for numbers


4 files changed, 74 insertions(+), 15 deletions(-)

src-self-hosted/Module.zig+47-15
......@@ -3358,6 +3358,14 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
33583358 return self.bitcast(scope, dest_type, inst);
33593359 }
33603360
3361 // undefined to anything
3362 if (inst.value()) |val| {
3363 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
3364 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3365 }
3366 }
3367 assert(inst.ty.zigTypeTag() != .Undefined);
3368
33613369 // *[N]T to []T
33623370 if (inst.ty.isSinglePointer() and dest_type.isSlice() and
33633371 (!inst.ty.pointerIsConst() or dest_type.pointerIsConst()))
......@@ -3371,34 +3379,58 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
33713379 }
33723380 }
33733381
3374 // comptime_int to fixed-width integer
3375 if (inst.ty.zigTypeTag() == .ComptimeInt and dest_type.zigTypeTag() == .Int) {
3376 // The representation is already correct; we only need to make sure it fits in the destination type.
3377 const val = inst.value().?; // comptime_int always has comptime known value
3378 if (!val.intFitsInType(dest_type, self.target())) {
3379 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
3382 // comptime known number to other number
3383 if (inst.value()) |val| {
3384 const src_zig_tag = inst.ty.zigTypeTag();
3385 const dst_zig_tag = dest_type.zigTypeTag();
3386
3387 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
3388 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3389 if (val.floatHasFraction()) {
3390 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
3391 }
3392 return self.fail(scope, inst.src, "TODO float to int", .{});
3393 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3394 if (!val.intFitsInType(dest_type, self.target())) {
3395 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
3396 }
3397 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3398 }
3399 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
3400 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3401 return self.fail(scope, inst.src, "TODO float cast", .{});
3402 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3403 return self.fail(scope, inst.src, "TODO int to float", .{});
3404 }
33803405 }
3381 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
33823406 }
33833407
33843408 // integer widening
33853409 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
3410 assert(inst.value() == null); // handled above
3411
33863412 const src_info = inst.ty.intInfo(self.target());
33873413 const dst_info = dest_type.intInfo(self.target());
33883414 if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) {
3389 if (inst.value()) |val| {
3390 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3391 } else {
3392 return self.fail(scope, inst.src, "TODO implement runtime integer widening ({} to {})", .{
3393 inst.ty,
3394 dest_type,
3395 });
3396 }
3415 const b = try self.requireRuntimeBlock(scope, inst.src);
3416 return self.addNewInstArgs(b, inst.src, dest_type, Inst.WidenOrShorten, .{ .operand = inst });
33973417 } else {
33983418 return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
33993419 }
34003420 }
34013421
3422 // float widening
3423 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
3424 assert(inst.value() == null); // handled above
3425
3426 const src_bits = inst.ty.floatBits(self.target());
3427 const dst_bits = dest_type.floatBits(self.target());
3428 if (dst_bits >= src_bits) {
3429 const b = try self.requireRuntimeBlock(scope, inst.src);
3430 return self.addNewInstArgs(b, inst.src, dest_type, Inst.WidenOrShorten, .{ .operand = inst });
3431 }
3432 }
3433
34023434 return self.fail(scope, inst.src, "TODO implement type coercion from {} to {}", .{ inst.ty, dest_type });
34033435}
34043436
src-self-hosted/codegen.zig+10
......@@ -459,6 +459,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
459459 .sub => return self.genSub(inst.castTag(.sub).?),
460460 .unreach => return MCValue{ .unreach = {} },
461461 .not => return self.genNot(inst.castTag(.not).?),
462 .widenorshorten => return self.genWidenOrShorten(isnt.castTag(.widenorshorten).?),
463 }
464 }
465
466 fn genWidenOrShorten(self: *Self, inst: *ir.Inst.WidenOrShorten) !MCValue {
467 // No side effects, so if it's unreferenced, do nothing.
468 if (inst.base.isUnused())
469 return MCValue.dead;
470 switch (arch) {
471 else => return self.fail(inst.base.src, "TODO implement widen or shorten for {}", .{self.target.cpu.arch}),
462472 }
463473 }
464474
src-self-hosted/ir.zig+11
......@@ -71,6 +71,7 @@ pub const Inst = struct {
7171 sub,
7272 unreach,
7373 not,
74 widenorshorten,
7475
7576 /// There is one-to-one correspondence between tag and type for now,
7677 /// but this will not always be the case. For example, binary operations
......@@ -108,6 +109,7 @@ pub const Inst = struct {
108109 .call => Call,
109110 .condbr => CondBr,
110111 .constant => Constant,
112 .widenorshorten => WidenOrShorten,
111113 };
112114 }
113115
......@@ -374,6 +376,15 @@ pub const Inst = struct {
374376 return null;
375377 }
376378 };
379
380 pub const WidenOrShorten = struct {
381 pub const base_tag = Tag.widenorshorten;
382
383 base: Inst,
384 args: struct {
385 operand: *Inst,
386 },
387 };
377388};
378389
379390pub const Body = struct {
src-self-hosted/zir.zig+6
......@@ -558,6 +558,7 @@ pub const Inst = struct {
558558
559559 pub const IntCast = struct {
560560 pub const base_tag = Tag.intcast;
561 pub const builtin_name = "@intCast";
561562 base: Inst,
562563
563564 positionals: struct {
......@@ -569,6 +570,7 @@ pub const Inst = struct {
569570
570571 pub const BitCast = struct {
571572 pub const base_tag = Tag.bitcast;
573 pub const builtin_name = "@bitCast";
572574 base: Inst,
573575
574576 positionals: struct {
......@@ -1820,6 +1822,10 @@ const EmitZIR = struct {
18201822 };
18211823 break :blk &new_inst.base;
18221824 },
1825 .widenorshorten => blk: {
1826 const old_inst = inst.cast(ir.Inst.WidenOrShorten).?;
1827 break :blk try self.resolveInst(new_body, old_inst.args.operand);
1828 },
18231829 };
18241830 try instructions.append(new_inst);
18251831 try inst_table.put(inst, new_inst);