diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-02-08 06:03:38 +0100 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2024-02-12 05:25:07 +0100 |
| commit | c6b3db8910dc250a32aef49a2d5951bd0c24e5db (patch) | |
| tree | 0ce12431eefad8a9727c4ce912c4e4010dd823af /src/arch/x86_64/CodeGen.zig | |
| parent | 7c9a96111c373599a55c9a04ea04f56b1dd76318 (diff) | |
| download | zig-c6b3db8910dc250a32aef49a2d5951bd0c24e5db.tar.gz zig-c6b3db8910dc250a32aef49a2d5951bd0c24e5db.zip | |
x86_64: implement `@abs` of big integers
Diffstat (limited to 'src/arch/x86_64/CodeGen.zig')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 92 |
1 files changed, 72 insertions, 20 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 655a93d9e4..5bd6819e5b 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3919,7 +3919,7 @@ fn genSetFrameTruncatedOverflowCompare( const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_bits); const temp_regs = - try self.register_manager.allocRegs(3, .{ null, null, null }, abi.RegisterClass.gp); + try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp); const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); @@ -4000,11 +4000,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const lhs_mcv = try self.resolveInst(bin_op.lhs); const rhs_mcv = try self.resolveInst(bin_op.rhs); - const temp_regs = try self.register_manager.allocRegs( - 4, - .{ null, null, null, null }, - abi.RegisterClass.gp, - ); + const temp_regs = + try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs); defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); @@ -6582,6 +6579,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) { else => null, .Int => switch (ty.abiSize(mod)) { + 0 => unreachable, 1...8 => { try self.spillEflagsIfOccupied(); const src_mcv = try self.resolveInst(ty_op.operand); @@ -6647,7 +6645,64 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { break :result dst_mcv; }, - else => return self.fail("TODO implement abs for {}", .{ty.fmt(mod)}), + else => { + const abi_size: u31 = @intCast(ty.abiSize(mod)); + const limb_len = std.math.divCeil(u31, abi_size, 8) catch unreachable; + + const tmp_regs = + try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp); + const tmp_locks = self.register_manager.lockRegsAssumeUnused(3, tmp_regs); + defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); + + try self.spillEflagsIfOccupied(); + const src_mcv = try self.resolveInst(ty_op.operand); + const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) + src_mcv + else + try self.allocRegOrMem(inst, false); + + try self.asmMemoryImmediate( + .{ ._, .cmp }, + try dst_mcv.address().offset((limb_len - 1) * 8).deref().mem(self, .qword), + Immediate.u(0), + ); + const positive = try self.asmJccReloc(.ns, undefined); + + try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[0].to32(), tmp_regs[0].to32()); + try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[1].to8(), tmp_regs[1].to8()); + + const neg_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); + try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[2].to32(), tmp_regs[2].to32()); + try self.asmRegisterImmediate(.{ ._r, .sh }, tmp_regs[1].to8(), Immediate.u(1)); + try self.asmRegisterMemory(.{ ._, .sbb }, tmp_regs[2].to64(), .{ + .base = .{ .frame = dst_mcv.load_frame.index }, + .mod = .{ .rm = .{ + .size = .qword, + .index = tmp_regs[0].to64(), + .scale = .@"8", + } }, + }); + try self.asmSetccRegister(.c, tmp_regs[1].to8()); + try self.asmMemoryRegister(.{ ._, .mov }, .{ + .base = .{ .frame = dst_mcv.load_frame.index }, + .mod = .{ .rm = .{ + .size = .qword, + .index = tmp_regs[0].to64(), + .scale = .@"8", + } }, + }, tmp_regs[2].to64()); + + if (self.hasFeature(.slow_incdec)) { + try self.asmRegisterImmediate(.{ ._, .add }, tmp_regs[0].to32(), Immediate.u(1)); + } else { + try self.asmRegister(.{ ._, .inc }, tmp_regs[0].to32()); + } + try self.asmRegisterImmediate(.{ ._, .cmp }, tmp_regs[0].to32(), Immediate.u(limb_len)); + _ = try self.asmJccReloc(.b, neg_loop); + + try self.performReloc(positive); + break :result dst_mcv; + }, }, .Float => return self.floatSign(inst, ty_op.operand, ty), .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { @@ -7435,7 +7490,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { const dst_regs: [2]Register = if (field_rc.supersetOf(container_rc) and self.reuseOperand(inst, operand, 0, src_mcv)) src_regs else dst: { const dst_regs = - try self.register_manager.allocRegs(2, .{ null, null }, field_rc); + try self.register_manager.allocRegs(2, .{null} ** 2, field_rc); const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs); defer for (dst_locks) |lock| self.register_manager.unlockReg(lock); @@ -8343,11 +8398,8 @@ fn genMulDivBinOp( .{}, ); - const temp_regs = try self.register_manager.allocRegs( - 4, - .{ null, null, null, null }, - abi.RegisterClass.gp, - ); + const temp_regs = + try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); const temp_locks = self.register_manager.lockRegs(4, temp_regs); defer for (temp_locks) |temp_lock| if (temp_lock) |lock| self.register_manager.unlockReg(lock); @@ -8909,14 +8961,14 @@ fn genBinOp( const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs); break :locks .{ locks[0], locks[1] }; }, - else => .{ null, null }, + else => .{null} ** 2, }; defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock); const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) { .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null }, .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs), - else => .{ null, null }, + else => .{null} ** 2, }; defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock); @@ -8949,7 +9001,7 @@ fn genBinOp( const dst_locks: [2]?RegisterLock = switch (dst_mcv) { .register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null }, .register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs), - else => .{ null, null }, + else => .{null} ** 2, }; defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); @@ -8965,7 +9017,7 @@ fn genBinOp( const src_locks: [2]?RegisterLock = switch (src_mcv) { .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null }, .register_pair => |src_regs| self.register_manager.lockRegs(2, src_regs), - else => .{ null, null }, + else => .{null} ** 2, }; defer for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock); @@ -9025,7 +9077,7 @@ fn genBinOp( else => dst: { const dst_regs = try self.register_manager.allocRegs( 2, - .{ null, null }, + .{null} ** 2, abi.RegisterClass.gp, ); const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs); @@ -11631,7 +11683,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { const regs = try self.register_manager.allocRegs( 2, - .{ null, null }, + .{null} ** 2, abi.RegisterClass.gp, ); const acc_reg = regs[0].to64(); @@ -16298,7 +16350,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void { try self.spillEflagsIfOccupied(); const tmp_regs = - try self.register_manager.allocRegs(2, .{ null, null }, abi.RegisterClass.gp); + try self.register_manager.allocRegs(2, .{null} ** 2, abi.RegisterClass.gp); const offset_reg = tmp_regs[0].to32(); const addr_reg = tmp_regs[1].to64(); const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs); |
