diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-05-10 01:13:13 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-05-10 01:15:14 +0200 |
| commit | 252c5a2339820d15bc7a063cdd68cc65b49ed413 (patch) | |
| tree | 662b34aeaaa8fd8f5f4391634d3551f7936e4a87 /src/arch/x86_64/CodeGen.zig | |
| parent | c3b7a5cc26d11a0349ff1d7812b00687cfa41c2e (diff) | |
| download | zig-252c5a2339820d15bc7a063cdd68cc65b49ed413.tar.gz zig-252c5a2339820d15bc7a063cdd68cc65b49ed413.zip | |
x64: migrate mod and rem into genBinOp
Diffstat (limited to 'src/arch/x86_64/CodeGen.zig')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 142 |
1 files changed, 60 insertions, 82 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 94f1195a3c..65293e0f46 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -595,8 +595,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .mul => try self.airBinOp(inst), .mulwrap => try self.airBinOp(inst), .mul_sat => try self.airMulSat(inst), - .rem => try self.airRem(inst), - .mod => try self.airMod(inst), + .rem => try self.airBinOp(inst), + .mod => try self.airBinOp(inst), .shl, .shl_exact => try self.airShl(inst), .shl_sat => try self.airShlSat(inst), .min => try self.airMin(inst), @@ -1539,6 +1539,7 @@ fn genIntMulDivOpMir( } } +/// Always returns a register. /// Clobbers .rax and .rdx registers. fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { const signedness = ty.intInfo(self.target.*).signedness; @@ -1687,86 +1688,6 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn airRem(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - - if (self.liveness.isUnused(inst)) { - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); - } - const ty = self.air.typeOfIndex(inst); - if (ty.zigTypeTag() != .Int) { - return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()}); - } - // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. - try self.register_manager.getReg(.rax, null); - try self.register_manager.getReg(.rdx, inst); - const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); - defer for (reg_locks) |reg| { - self.register_manager.unlockReg(reg); - }; - - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - - const signedness = ty.intInfo(self.target.*).signedness; - try self.genIntMulDivOpMir(switch (signedness) { - .signed => .idiv, - .unsigned => .div, - }, ty, signedness, lhs, rhs); - - const result: MCValue = .{ .register = .rdx }; - - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} - -fn airMod(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - - if (self.liveness.isUnused(inst)) { - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); - } - - const ty = self.air.typeOfIndex(inst); - if (ty.zigTypeTag() != .Int) { - return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); - } - const signedness = ty.intInfo(self.target.*).signedness; - - // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. - try self.register_manager.getReg(.rax, null); - try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); - const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); - defer for (reg_locks) |reg| { - self.register_manager.unlockReg(reg); - }; - - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - - const result: MCValue = result: { - switch (signedness) { - .unsigned => { - try self.genIntMulDivOpMir(switch (signedness) { - .signed => .idiv, - .unsigned => .div, - }, ty, signedness, lhs, rhs); - break :result MCValue{ .register = .rdx }; - }, - .signed => { - const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); - try self.genIntMulComplexOpMir(ty, div_floor, rhs); - - const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs); - try self.genBinOpMir(.sub, ty, result, div_floor); - - break :result result; - }, - } - }; - - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} - fn airShl(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; if (self.liveness.isUnused(inst)) { @@ -3234,12 +3155,18 @@ fn genBinOp( .subwrap, .mul, .mulwrap, + .div_exact, + .div_trunc, + .rem, + .mod, .shl, .shr, .ptr_add, .ptr_sub, => false, + .div_float => return self.fail("TODO implement genBinOp for {}", .{tag}), + else => unreachable, }; const dst_ty = self.air.typeOf(op_lhs); @@ -3278,6 +3205,57 @@ fn genBinOp( .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) }, }; }, + .mod, + .rem, + => { + const int_info = dst_ty.intInfo(self.target.*); + const track_inst_rdx: ?Air.Inst.Index = switch (tag) { + .mod => if (int_info.signedness == .unsigned) maybe_inst else null, + .rem => maybe_inst, + else => unreachable, + }; + + // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. + try self.register_manager.getReg(.rax, null); + try self.register_manager.getReg(.rdx, track_inst_rdx); + const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); + defer for (reg_locks) |reg| { + self.register_manager.unlockReg(reg); + }; + + const lhs = try self.resolveInst(op_lhs); + const rhs = try self.resolveInst(op_rhs); + + switch (int_info.signedness) { + .signed => { + switch (tag) { + .rem => { + try self.genIntMulDivOpMir(.idiv, dst_ty, .signed, lhs, rhs); + return MCValue{ .register = .rdx }; + }, + .mod => { + const div_floor = try self.genInlineIntDivFloor(dst_ty, lhs, rhs); + try self.genIntMulComplexOpMir(dst_ty, div_floor, rhs); + const div_floor_lock = self.register_manager.lockReg(div_floor.register); + defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); + + const result: MCValue = if (maybe_inst) |inst| + try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs) + else + MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) }; + try self.genBinOpMir(.sub, dst_ty, result, div_floor); + + return result; + }, + else => unreachable, + } + }, + .unsigned => { + try self.genIntMulDivOpMir(.div, dst_ty, .unsigned, lhs, rhs); + return MCValue{ .register = .rdx }; + }, + } + }, else => {}, } |
