From 575d430f92633f5bf4e1e1663d0dc5fefe1e02f5 Mon Sep 17 00:00:00 2001 From: mparadinha Date: Tue, 25 Jan 2022 14:44:57 +0000 Subject: stage2: x64: implement airTrunc --- src/arch/x86_64/CodeGen.zig | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 64a91fc2bf..822a2d0ad1 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -905,8 +905,46 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); const operand = try self.resolveInst(ty_op.operand); - _ = operand; - return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch}); + + const src_ty = self.air.typeOf(ty_op.operand); + const dst_ty = self.air.typeOfIndex(inst); + + const src_ty_size = src_ty.abiSize(self.target.*); + const dst_ty_size = dst_ty.abiSize(self.target.*); + if (src_ty_size > 8 or dst_ty_size > 8) { + return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); + } + + const src_reg = if (operand == .register) operand.register else blk: { + const tmp_reg = try self.register_manager.allocReg(inst, &.{}); + try self.genSetReg(dst_ty, tmp_reg, operand); + break :blk tmp_reg; + }; + const dst_reg = try self.register_manager.allocReg(inst, &.{}); + + // "convert" the src register to the smaller type so only those bytes are moved + const small_src = MCValue{ .register = registerAlias(src_reg, @intCast(u32, dst_ty_size)) }; + + try self.genSetReg(dst_ty, dst_reg, small_src); + + const result = MCValue{ .register = registerAlias(dst_reg, @intCast(u32, dst_ty_size)) }; + + // when truncating a `u16` to `u5`, for example, those top 3 bits in the result + // have to be removed. this only happens if the dst if not a power-of-two size. + const dst_bit_size = dst_ty.bitSize(self.target.*); + const is_power_of_two = (dst_bit_size & (dst_bit_size - 1)) == 0; + if (!is_power_of_two or dst_bit_size < 8) { + const mask = (~@as(u64, 0)) >> @intCast(u6, (64 - dst_ty.bitSize(self.target.*))); + try self.genBinMathOpMir( + .@"and", + dst_ty, + dst_ty.intInfo(self.target.*).signedness, + result, + .{ .immediate = mask }, + ); + } + + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { -- cgit v1.2.3