diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-05-09 23:50:01 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-05-09 23:50:01 +0200 |
| commit | 7b9f8bfbd80aa37afc160c39b341c59fdd3cbad8 (patch) | |
| tree | e4def2bad75bdf226a51fbc31e156e762751dcc7 /src/arch | |
| parent | 20e7f1218b997e3da5d10cb5d038ed782d772716 (diff) | |
| download | zig-7b9f8bfbd80aa37afc160c39b341c59fdd3cbad8.tar.gz zig-7b9f8bfbd80aa37afc160c39b341c59fdd3cbad8.zip | |
x64: migrate mul to new genBinOp helper
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 151 |
1 files changed, 59 insertions, 92 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 8dbb6aef7a..726476f6c7 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -592,8 +592,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .sub => try self.airBinOp(inst), .subwrap => try self.airBinOp(inst), .sub_sat => try self.airSubSat(inst), - .mul => try self.airMul(inst), - .mulwrap => try self.airMul(inst), + .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), @@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { }, else => {}, } - break :result try self.genBinOp(inst, ty_op.operand, .bool_true); + break :result try self.genBinOp(inst, ty_op.operand, .bool_true, true); }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -1185,24 +1185,6 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result = if (self.liveness.isUnused(inst)) - .dead - else - try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} - -fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result = if (self.liveness.isUnused(inst)) - .dead - else - try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} - fn airSlice(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; @@ -1229,7 +1211,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .dead else - try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); + try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -1251,36 +1233,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn airMul(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const ty = self.air.typeOfIndex(inst); - - if (ty.zigTypeTag() != .Int) { - return self.fail("TODO implement 'mul' 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, inst); - try self.register_manager.getReg(.rdx, 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 signedness = ty.intInfo(self.target.*).signedness; - try self.genIntMulDivOpMir(switch (signedness) { - .signed => .imul, - .unsigned => .mul, - }, ty, signedness, lhs, rhs); - break :result MCValue{ .register = .rax }; - }; - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} - fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) @@ -1308,7 +1260,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { try self.spillCompareFlagsIfOccupied(); self.compare_flags_inst = inst; - const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); + const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); const result: MCValue = switch (int_info.signedness) { .signed => .{ .register_overflow_signed = partial.register }, .unsigned => .{ .register_overflow_unsigned = partial.register }, @@ -1340,7 +1292,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { try self.spillCompareFlagsIfOccupied(); self.compare_flags_inst = inst; - const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); + const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); const result: MCValue = switch (int_info.signedness) { .signed => .{ .register_overflow_signed = partial.register }, .unsigned => .{ .register_overflow_unsigned = partial.register }, @@ -1373,34 +1325,17 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); } + try self.spillCompareFlagsIfOccupied(); + if (math.isPowerOfTwo(int_info.bits)) { - try self.spillCompareFlagsIfOccupied(); self.compare_flags_inst = inst; - - // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. - try self.register_manager.getReg(.rax, inst); - try self.register_manager.getReg(.rdx, null); - const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); - defer for (reg_locks) |reg| { - self.register_manager.unlockReg(reg); + const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); + break :result switch (int_info.signedness) { + .signed => MCValue{ .register_overflow_signed = partial.register }, + .unsigned => MCValue{ .register_overflow_unsigned = partial.register }, }; - - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - - try self.genIntMulDivOpMir(switch (int_info.signedness) { - .signed => .imul, - .unsigned => .mul, - }, ty, int_info.signedness, lhs, rhs); - - const result: MCValue = switch (int_info.signedness) { - .signed => .{ .register_overflow_signed = .rax }, - .unsigned => .{ .register_overflow_unsigned = .rax }, - }; - break :result result; } - try self.spillCompareFlagsIfOccupied(); self.compare_flags_inst = null; const dst_reg: Register = dst_reg: { @@ -1437,20 +1372,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { break :dst_reg dst_reg; }, .unsigned => { - // 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, 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); - - try self.genIntMulDivOpMir(.mul, ty, .unsigned, lhs, rhs); - - break :dst_reg registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))); + const dst_mcv = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, false); + break :dst_reg dst_mcv.register; }, } }; @@ -3291,6 +3214,7 @@ fn genBinOp( inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref, + track: bool, ) !MCValue { const tag = self.air.instructions.items(.tag)[inst]; const is_commutative: bool = switch (tag) { @@ -3309,6 +3233,8 @@ fn genBinOp( .subwrap, .sub_with_overflow, .mul, + .mulwrap, + .mul_with_overflow, .shl, .shr, .ptr_add, @@ -3320,6 +3246,43 @@ fn genBinOp( const dst_ty = self.air.typeOf(op_lhs); const src_ty = self.air.typeOf(op_rhs); + if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) { + return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()}); + } + if (dst_ty.abiSize(self.target.*) > 8) { + return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()}); + } + + switch (tag) { + .mul, + .mulwrap, + .mul_with_overflow, + => { + // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. + try self.register_manager.getReg(.rax, if (track) inst else null); + try self.register_manager.getReg(.rdx, 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(op_lhs); + const rhs = try self.resolveInst(op_rhs); + + const int_info = dst_ty.intInfo(self.target.*); + try self.genIntMulDivOpMir(switch (int_info.signedness) { + .signed => .imul, + .unsigned => .mul, + }, dst_ty, int_info.signedness, lhs, rhs); + + return switch (int_info.signedness) { + .signed => MCValue{ .register = .rax }, + .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) }, + }; + }, + else => {}, + } + const lhs = try self.resolveInst(op_lhs); const lhs_lock: ?RegisterLock = switch (lhs) { .register => |reg| self.register_manager.lockRegAssumeUnused(reg), @@ -3343,7 +3306,11 @@ fn genBinOp( flipped = true; break :blk rhs; } - break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); + if (track) { + break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); + } else { + break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) }; + } }; const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { .register => |reg| self.register_manager.lockReg(reg), |
