| ... | @@ -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()); |
| 968 | | 968 | |
| 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); |
| 975 | | 974 | |
| 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 | } |
| 979 | | 981 | |
| ... | @@ -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 | } |
| 1406 | | 1408 | |
| | 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 | } |
| 1435 | | 1440 | |
| | 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.*); |
| 1463 | | 1468 | |
| 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 | } |
| 1467 | | 1472 | |
| 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 | } |
| 1489 | | 1497 | |
| | 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 | } |
| 2784 | | 2795 | |
| 2785 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | 2796 | fn 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 |
| 3000 | | 3010 | |
| 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 | }, |