aboutsummaryrefslogtreecommitdiff
path: root/src/arch/x86_64/CodeGen.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-05-10 01:13:13 +0200
committerJakub Konka <kubkon@jakubkonka.com>2022-05-10 01:15:14 +0200
commit252c5a2339820d15bc7a063cdd68cc65b49ed413 (patch)
tree662b34aeaaa8fd8f5f4391634d3551f7936e4a87 /src/arch/x86_64/CodeGen.zig
parentc3b7a5cc26d11a0349ff1d7812b00687cfa41c2e (diff)
downloadzig-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.zig142
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 => {},
}