authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-06 09:03:08+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-06 13:42:11+02:00
logac1aaec9c38eb44b93099ff18579a9401f107100
tree8769d87fe8299d790aa5d2b858f1d5a535c4a8c7
parentdf38dfa4d1c9028453f90c7e37dd6c06f829a995

x64: handle CF flags spilling in overflow calls

Handle spilling of CF flags set with an overflow call. Add saving stack offset to memory.

1 files changed, 34 insertions(+), 6 deletions(-)

src/arch/x86_64/CodeGen.zig+34-6
...@@ -966,14 +966,16 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -966,14 +966,16 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
966 const mcv = self.getResolvedInstValue(inst_to_save);966 const mcv = self.getResolvedInstValue(inst_to_save);
967 assert(mcv.usesCompareFlags());967 assert(mcv.usesCompareFlags());
968968
969 const new_mcv = try self.allocRegOrMem(inst_to_save, true);969 const new_mcv = try self.allocRegOrMem(inst_to_save, !mcv.isRegister());
970 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);970 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
971 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });971 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });
972
973 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];972 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
974 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);973 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
975974
976 self.compare_flags_inst = null;975 self.compare_flags_inst = null;
976 // TODO consolidate with register manager and spillInstruction
977 // this call should really belong in the register manager!
978 if (mcv.isRegister()) self.register_manager.freeReg(mcv.asRegister().?);
977 }979 }
978}980}
979981
...@@ -1404,6 +1406,9 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1404,6 +1406,9 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1404 return self.fail("TODO implement add_with_overflow for Ints larger than 64bits", .{});1406 return self.fail("TODO implement add_with_overflow for Ints larger than 64bits", .{});
1405 }1407 }
14061408
1409 try self.spillCompareFlagsIfOccupied();
1410 self.compare_flags_inst = inst;
1411
1407 const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);1412 const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1408 const result: MCValue = switch (int_info.signedness) {1413 const result: MCValue = switch (int_info.signedness) {
1409 .signed => .{ .register_overflow_signed = partial.register },1414 .signed => .{ .register_overflow_signed = partial.register },
...@@ -1433,6 +1438,9 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1433,6 +1438,9 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1433 return self.fail("TODO implement sub_with_overflow for Ints larger than 64bits", .{});1438 return self.fail("TODO implement sub_with_overflow for Ints larger than 64bits", .{});
1434 }1439 }
14351440
1441 try self.spillCompareFlagsIfOccupied();
1442 self.compare_flags_inst = inst;
1443
1436 const partial = try self.genSubOp(inst, bin_op.lhs, bin_op.rhs);1444 const partial = try self.genSubOp(inst, bin_op.lhs, bin_op.rhs);
1437 const result: MCValue = switch (int_info.signedness) {1445 const result: MCValue = switch (int_info.signedness) {
1438 .signed => .{ .register_overflow_signed = partial.register },1446 .signed => .{ .register_overflow_signed = partial.register },
...@@ -1456,9 +1464,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1456,9 +1464,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1456 switch (ty.zigTypeTag()) {1464 switch (ty.zigTypeTag()) {
1457 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),1465 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
1458 .Int => {1466 .Int => {
1459 try self.spillCompareFlagsIfOccupied();
1460 self.compare_flags_inst = null;
1461
1462 const int_info = ty.intInfo(self.target.*);1467 const int_info = ty.intInfo(self.target.*);
14631468
1464 if (int_info.bits > 64) {1469 if (int_info.bits > 64) {
...@@ -1466,6 +1471,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1466,6 +1471,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1466 }1471 }
14671472
1468 if (math.isPowerOfTwo(int_info.bits)) {1473 if (math.isPowerOfTwo(int_info.bits)) {
1474 try self.spillCompareFlagsIfOccupied();
1475 self.compare_flags_inst = inst;
1476
1469 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.1477 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1470 try self.register_manager.getReg(.rax, inst);1478 try self.register_manager.getReg(.rax, inst);
1471 try self.register_manager.getReg(.rdx, null);1479 try self.register_manager.getReg(.rdx, null);
...@@ -1487,6 +1495,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1487,6 +1495,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1487 break :result result;1495 break :result result;
1488 }1496 }
14891497
1498 try self.spillCompareFlagsIfOccupied();
1499 self.compare_flags_inst = null;
1500
1490 const dst_reg: Register = dst_reg: {1501 const dst_reg: Register = dst_reg: {
1491 switch (int_info.signedness) {1502 switch (int_info.signedness) {
1492 .signed => {1503 .signed => {
...@@ -2783,7 +2794,6 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue...@@ -2783,7 +2794,6 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2783}2794}
27842795
2785fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {2796fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
2786 _ = ptr_ty;
2787 const abi_size = value_ty.abiSize(self.target.*);2797 const abi_size = value_ty.abiSize(self.target.*);
2788 switch (ptr) {2798 switch (ptr) {
2789 .none => unreachable,2799 .none => unreachable,
...@@ -3000,6 +3010,24 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3000,6 +3010,24 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
30003010
3001 try self.genInlineMemcpy(.{ .register = addr_reg.to64() }, value, .{ .immediate = abi_size }, .{});3011 try self.genInlineMemcpy(.{ .register = addr_reg.to64() }, value, .{ .immediate = abi_size }, .{});
3002 },3012 },
3013 .stack_offset => {
3014 if (abi_size <= 8) {
3015 // TODO this should really be a recursive call
3016 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3017 _ = try self.addInst(.{
3018 .tag = .mov,
3019 .ops = (Mir.Ops{
3020 .reg1 = addr_reg.to64(),
3021 .reg2 = tmp_reg,
3022 .flags = 0b10,
3023 }).encode(),
3024 .data = .{ .imm = 0 },
3025 });
3026 return;
3027 }
3028
3029 try self.genInlineMemcpy(.{ .register = addr_reg.to64() }, value, .{ .immediate = abi_size }, .{});
3030 },
3003 else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}),3031 else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}),
3004 }3032 }
3005 },3033 },