| ... | @@ -21,7 +21,7 @@ const Emit = @import("Emit.zig"); | ... | @@ -21,7 +21,7 @@ const Emit = @import("Emit.zig"); |
| 21 | const Liveness = @import("../../Liveness.zig"); | 21 | const Liveness = @import("../../Liveness.zig"); |
| 22 | const Mir = @import("Mir.zig"); | 22 | const Mir = @import("Mir.zig"); |
| 23 | const Module = @import("../../Module.zig"); | 23 | const Module = @import("../../Module.zig"); |
| 24 | const RegisterManager = @import("../../register_manager.zig").RegisterManager; | 24 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 25 | const Target = std.Target; | 25 | const Target = std.Target; |
| 26 | const Type = @import("../../type.zig").Type; | 26 | const Type = @import("../../type.zig").Type; |
| 27 | const TypedValue = @import("../../TypedValue.zig"); | 27 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | @@ -33,6 +33,8 @@ const InnerError = error{ | ... | @@ -33,6 +33,8 @@ const InnerError = error{ |
| 33 | CodegenFail, | 33 | CodegenFail, |
| 34 | }; | 34 | }; |
| 35 | | 35 | |
| | 36 | const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs); |
| | 37 | |
| 36 | gpa: Allocator, | 38 | gpa: Allocator, |
| 37 | air: Air, | 39 | air: Air, |
| 38 | liveness: Liveness, | 40 | liveness: Liveness, |
| ... | @@ -73,7 +75,7 @@ branch_stack: *std.ArrayList(Branch), | ... | @@ -73,7 +75,7 @@ branch_stack: *std.ArrayList(Branch), |
| 73 | // Key is the block instruction | 75 | // Key is the block instruction |
| 74 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, | 76 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, |
| 75 | | 77 | |
| 76 | register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{}, | 78 | register_manager: RegisterManager = .{}, |
| 77 | /// Maps offset to what is stored there. | 79 | /// Maps offset to what is stored there. |
| 78 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, | 80 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 79 | | 81 | |
| ... | @@ -169,6 +171,24 @@ pub const MCValue = union(enum) { | ... | @@ -169,6 +171,24 @@ pub const MCValue = union(enum) { |
| 169 | else => false, | 171 | else => false, |
| 170 | }; | 172 | }; |
| 171 | } | 173 | } |
| | 174 | |
| | 175 | fn freezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { |
| | 176 | switch (mcv) { |
| | 177 | .register => |reg| { |
| | 178 | mgr.freezeRegs(&.{reg}); |
| | 179 | }, |
| | 180 | else => {}, |
| | 181 | } |
| | 182 | } |
| | 183 | |
| | 184 | fn unfreezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { |
| | 185 | switch (mcv) { |
| | 186 | .register => |reg| { |
| | 187 | mgr.unfreezeRegs(&.{reg}); |
| | 188 | }, |
| | 189 | else => {}, |
| | 190 | } |
| | 191 | } |
| 172 | }; | 192 | }; |
| 173 | | 193 | |
| 174 | const Branch = struct { | 194 | const Branch = struct { |
| ... | @@ -836,20 +856,6 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCVa | ... | @@ -836,20 +856,6 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCVa |
| 836 | return MCValue{ .register = reg }; | 856 | return MCValue{ .register = reg }; |
| 837 | } | 857 | } |
| 838 | | 858 | |
| 839 | /// Like `copyToNewRegister` but allows to specify a list of excluded registers which | | |
| 840 | /// will not be selected for allocation. This can be done via `exceptions` slice. | | |
| 841 | fn copyToNewRegisterWithExceptions( | | |
| 842 | self: *Self, | | |
| 843 | reg_owner: Air.Inst.Index, | | |
| 844 | ty: Type, | | |
| 845 | mcv: MCValue, | | |
| 846 | exceptions: []const Register, | | |
| 847 | ) !MCValue { | | |
| 848 | const reg = try self.register_manager.allocReg(reg_owner, exceptions); | | |
| 849 | try self.genSetReg(ty, reg, mcv); | | |
| 850 | return MCValue{ .register = reg }; | | |
| 851 | } | | |
| 852 | | | |
| 853 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { | 859 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 854 | const stack_offset = try self.allocMemPtr(inst); | 860 | const stack_offset = try self.allocMemPtr(inst); |
| 855 | return self.finishAir(inst, .{ .ptr_stack_offset = @intCast(i32, stack_offset) }, .{ .none, .none, .none }); | 861 | return self.finishAir(inst, .{ .ptr_stack_offset = @intCast(i32, stack_offset) }, .{ .none, .none, .none }); |
| ... | @@ -897,8 +903,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -897,8 +903,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 897 | return self.fail("TODO implement intCast for abi sizes larger than 8", .{}); | 903 | return self.fail("TODO implement intCast for abi sizes larger than 8", .{}); |
| 898 | } | 904 | } |
| 899 | | 905 | |
| 900 | if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register}); | 906 | operand.freezeIfRegister(&self.register_manager); |
| 901 | defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register}); | 907 | defer operand.unfreezeIfRegister(&self.register_manager); |
| | 908 | |
| 902 | break :blk try self.copyToNewRegister(inst, dest_ty, operand); | 909 | break :blk try self.copyToNewRegister(inst, dest_ty, operand); |
| 903 | }; | 910 | }; |
| 904 | | 911 | |
| ... | @@ -1366,8 +1373,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1366,8 +1373,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1366 | } | 1373 | } |
| 1367 | | 1374 | |
| 1368 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { | 1375 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 1369 | const reg = try self.register_manager.allocReg(null, &.{}); | 1376 | const reg = try self.copyToTmpRegister(index_ty, index); |
| 1370 | try self.genSetReg(index_ty, reg, index); | | |
| 1371 | try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); | 1377 | try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); |
| 1372 | return reg; | 1378 | return reg; |
| 1373 | } | 1379 | } |
| ... | @@ -1376,16 +1382,26 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1376,16 +1382,26 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1376 | const is_volatile = false; // TODO | 1382 | const is_volatile = false; // TODO |
| 1377 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1383 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1378 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { | 1384 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 1379 | const slice_mcv = try self.resolveInst(bin_op.lhs); | | |
| 1380 | const slice_ty = self.air.typeOf(bin_op.lhs); | 1385 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| | 1386 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| | 1387 | slice_mcv.freezeIfRegister(&self.register_manager); |
| | 1388 | defer slice_mcv.unfreezeIfRegister(&self.register_manager); |
| | 1389 | |
| 1381 | const elem_ty = slice_ty.childType(); | 1390 | const elem_ty = slice_ty.childType(); |
| 1382 | const elem_size = elem_ty.abiSize(self.target.*); | 1391 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1383 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1392 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1384 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | 1393 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| | 1394 | |
| 1385 | const index_ty = self.air.typeOf(bin_op.rhs); | 1395 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1386 | const index_mcv = try self.resolveInst(bin_op.rhs); | 1396 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| | 1397 | index_mcv.freezeIfRegister(&self.register_manager); |
| | 1398 | defer index_mcv.unfreezeIfRegister(&self.register_manager); |
| | 1399 | |
| 1387 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); | 1400 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); |
| 1388 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); | 1401 | self.register_manager.freezeRegs(&.{offset_reg}); |
| | 1402 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| | 1403 | |
| | 1404 | const addr_reg = try self.register_manager.allocReg(null, &.{}); |
| 1389 | switch (slice_mcv) { | 1405 | switch (slice_mcv) { |
| 1390 | .stack_offset => |off| { | 1406 | .stack_offset => |off| { |
| 1391 | // mov reg, [rbp - 8] | 1407 | // mov reg, [rbp - 8] |
| ... | @@ -1401,7 +1417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1401,7 +1417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1401 | }, | 1417 | }, |
| 1402 | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), | 1418 | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), |
| 1403 | } | 1419 | } |
| 1404 | // TODO we could allocate register here, but need to except addr register and potentially | 1420 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 1405 | // offset register. | 1421 | // offset register. |
| 1406 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1422 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1407 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg.to64() }, .{ | 1423 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg.to64() }, .{ |
| ... | @@ -1427,14 +1443,23 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1427,14 +1443,23 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1427 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1443 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1428 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1444 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1429 | const array_ty = self.air.typeOf(bin_op.lhs); | 1445 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 1430 | const array = try self.resolveInst(bin_op.lhs); | | |
| 1431 | const array_abi_size = array_ty.abiSize(self.target.*); | 1446 | const array_abi_size = array_ty.abiSize(self.target.*); |
| | 1447 | const array = try self.resolveInst(bin_op.lhs); |
| | 1448 | array.freezeIfRegister(&self.register_manager); |
| | 1449 | defer array.unfreezeIfRegister(&self.register_manager); |
| | 1450 | |
| 1432 | const elem_ty = array_ty.childType(); | 1451 | const elem_ty = array_ty.childType(); |
| 1433 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 1452 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 1434 | const index_ty = self.air.typeOf(bin_op.rhs); | 1453 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1435 | const index = try self.resolveInst(bin_op.rhs); | 1454 | const index = try self.resolveInst(bin_op.rhs); |
| | 1455 | index.freezeIfRegister(&self.register_manager); |
| | 1456 | defer index.unfreezeIfRegister(&self.register_manager); |
| | 1457 | |
| 1436 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 1458 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 1437 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); | 1459 | self.register_manager.freezeRegs(&.{offset_reg}); |
| | 1460 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| | 1461 | |
| | 1462 | const addr_reg = try self.register_manager.allocReg(null, &.{}); |
| 1438 | switch (array) { | 1463 | switch (array) { |
| 1439 | .stack_offset => |off| { | 1464 | .stack_offset => |off| { |
| 1440 | // lea reg, [rbp] | 1465 | // lea reg, [rbp] |
| ... | @@ -1449,7 +1474,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1449,7 +1474,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1449 | }, | 1474 | }, |
| 1450 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), | 1475 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| 1451 | } | 1476 | } |
| 1452 | // TODO we could allocate register here, but need to except addr register and potentially | 1477 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 1453 | // offset register. | 1478 | // offset register. |
| 1454 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1479 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1455 | try self.genBinMathOpMir(.add, array_ty, .{ .register = addr_reg.to64() }, .{ .register = offset_reg.to64() }); | 1480 | try self.genBinMathOpMir(.add, array_ty, .{ .register = addr_reg.to64() }, .{ .register = offset_reg.to64() }); |
| ... | @@ -1475,12 +1500,17 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1475,12 +1500,17 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1475 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1500 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1476 | const ptr_ty = self.air.typeOf(extra.lhs); | 1501 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 1477 | const ptr = try self.resolveInst(extra.lhs); | 1502 | const ptr = try self.resolveInst(extra.lhs); |
| | 1503 | ptr.freezeIfRegister(&self.register_manager); |
| | 1504 | defer ptr.unfreezeIfRegister(&self.register_manager); |
| | 1505 | |
| 1478 | const elem_ty = ptr_ty.elemType2(); | 1506 | const elem_ty = ptr_ty.elemType2(); |
| 1479 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 1507 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 1480 | const index_ty = self.air.typeOf(extra.rhs); | 1508 | const index_ty = self.air.typeOf(extra.rhs); |
| 1481 | const index = try self.resolveInst(extra.rhs); | 1509 | const index = try self.resolveInst(extra.rhs); |
| 1482 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 1510 | index.freezeIfRegister(&self.register_manager); |
| | 1511 | defer index.unfreezeIfRegister(&self.register_manager); |
| 1483 | | 1512 | |
| | 1513 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 1484 | self.register_manager.freezeRegs(&.{offset_reg}); | 1514 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 1485 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | 1515 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 1486 | | 1516 | |
| ... | @@ -1587,6 +1617,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1587,6 +1617,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1587 | return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); | 1617 | return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); |
| 1588 | }, | 1618 | }, |
| 1589 | .register => |reg| { | 1619 | .register => |reg| { |
| | 1620 | self.register_manager.freezeRegs(&.{reg}); |
| | 1621 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| | 1622 | |
| 1590 | switch (dst_mcv) { | 1623 | switch (dst_mcv) { |
| 1591 | .dead => unreachable, | 1624 | .dead => unreachable, |
| 1592 | .undef => unreachable, | 1625 | .undef => unreachable, |
| ... | @@ -1607,16 +1640,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1607,16 +1640,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1607 | }, | 1640 | }, |
| 1608 | .stack_offset => |off| { | 1641 | .stack_offset => |off| { |
| 1609 | if (abi_size <= 8) { | 1642 | if (abi_size <= 8) { |
| 1610 | const tmp_reg = try self.register_manager.allocReg(null, &.{reg}); | 1643 | const tmp_reg = try self.register_manager.allocReg(null, &.{}); |
| 1611 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); | 1644 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); |
| 1612 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); | 1645 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); |
| 1613 | } | 1646 | } |
| 1614 | | 1647 | |
| 1615 | const regs = try self.register_manager.allocRegs( | 1648 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 1616 | 3, | 1649 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 1617 | .{ null, null, null }, | 1650 | |
| 1618 | &.{ reg, .rax, .rcx }, | 1651 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{}); |
| 1619 | ); | | |
| 1620 | const addr_reg = regs[0]; | 1652 | const addr_reg = regs[0]; |
| 1621 | const count_reg = regs[1]; | 1653 | const count_reg = regs[1]; |
| 1622 | const tmp_reg = regs[2]; | 1654 | const tmp_reg = regs[2]; |
| ... | @@ -1634,7 +1666,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1634,7 +1666,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1634 | try self.register_manager.getReg(.rcx, null); | 1666 | try self.register_manager.getReg(.rcx, null); |
| 1635 | | 1667 | |
| 1636 | // TODO allow for abi size to be u64 | 1668 | // TODO allow for abi size to be u64 |
| 1637 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); | 1669 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 1638 | | 1670 | |
| 1639 | return self.genInlineMemcpy( | 1671 | return self.genInlineMemcpy( |
| 1640 | -(off + @intCast(i32, abi_size)), | 1672 | -(off + @intCast(i32, abi_size)), |
| ... | @@ -1786,8 +1818,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1786,8 +1818,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1786 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] | 1818 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] |
| 1787 | // instead of wasting an instruction copying the address to a register | 1819 | // instead of wasting an instruction copying the address to a register |
| 1788 | | 1820 | |
| 1789 | if (value.isRegister()) self.register_manager.freezeRegs(&.{value.register}); | 1821 | value.freezeIfRegister(&self.register_manager); |
| 1790 | defer if (value.isRegister()) self.register_manager.unfreezeRegs(&.{value.register}); | 1822 | defer value.unfreezeIfRegister(&self.register_manager); |
| 1791 | | 1823 | |
| 1792 | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); | 1824 | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); |
| 1793 | // to get the actual address of the value we want to modify we have to go through the GOT | 1825 | // to get the actual address of the value we want to modify we have to go through the GOT |
| ... | @@ -2012,22 +2044,16 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2012,22 +2044,16 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2012 | } | 2044 | } |
| 2013 | } else { | 2045 | } else { |
| 2014 | if (lhs.isMemory()) { | 2046 | if (lhs.isMemory()) { |
| 2015 | dst_mcv = if (rhs.isRegister()) | 2047 | rhs.freezeIfRegister(&self.register_manager); |
| 2016 | // If the allocated register is the same as the rhs register, don't allocate that one | 2048 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 2017 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation | 2049 | |
| 2018 | // in the presence of several binary operations performed in a single block. | 2050 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs); |
| 2019 | try self.copyToNewRegisterWithExceptions(inst, dst_ty, lhs, &.{rhs.register}) | | |
| 2020 | else | | |
| 2021 | try self.copyToNewRegister(inst, dst_ty, lhs); | | |
| 2022 | src_mcv = rhs; | 2051 | src_mcv = rhs; |
| 2023 | } else { | 2052 | } else { |
| 2024 | dst_mcv = if (lhs.isRegister()) | 2053 | lhs.freezeIfRegister(&self.register_manager); |
| 2025 | // If the allocated register is the same as the rhs register, don't allocate that one | 2054 | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 2026 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation | 2055 | |
| 2027 | // in the presence of several binary operations performed in a single block. | 2056 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs); |
| 2028 | try self.copyToNewRegisterWithExceptions(inst, dst_ty, rhs, &.{lhs.register}) | | |
| 2029 | else | | |
| 2030 | try self.copyToNewRegister(inst, dst_ty, rhs); | | |
| 2031 | src_mcv = lhs; | 2057 | src_mcv = lhs; |
| 2032 | } | 2058 | } |
| 2033 | } | 2059 | } |
| ... | @@ -2039,7 +2065,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2039,7 +2065,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2039 | switch (src_mcv) { | 2065 | switch (src_mcv) { |
| 2040 | .immediate => |imm| { | 2066 | .immediate => |imm| { |
| 2041 | if (imm > math.maxInt(u31)) { | 2067 | if (imm > math.maxInt(u31)) { |
| 2042 | src_mcv = MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.u64), src_mcv) }; | 2068 | dst_mcv.freezeIfRegister(&self.register_manager); |
| | 2069 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| | 2070 | |
| | 2071 | const tmp_reg = try self.copyToTmpRegister(Type.u64, src_mcv); |
| | 2072 | src_mcv = MCValue{ .register = tmp_reg }; |
| 2043 | } | 2073 | } |
| 2044 | }, | 2074 | }, |
| 2045 | else => {}, | 2075 | else => {}, |
| ... | @@ -2901,6 +2931,8 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2901,6 +2931,8 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2901 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2931 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2902 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2932 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2903 | const operand_ptr = try self.resolveInst(un_op); | 2933 | const operand_ptr = try self.resolveInst(un_op); |
| | 2934 | operand_ptr.freezeIfRegister(&self.register_manager); |
| | 2935 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 2904 | const operand: MCValue = blk: { | 2936 | const operand: MCValue = blk: { |
| 2905 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2937 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2906 | // The MCValue that holds the pointer can be re-used as the value. | 2938 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2930,6 +2962,8 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2930,6 +2962,8 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2930 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2962 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2931 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2963 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2932 | const operand_ptr = try self.resolveInst(un_op); | 2964 | const operand_ptr = try self.resolveInst(un_op); |
| | 2965 | operand_ptr.freezeIfRegister(&self.register_manager); |
| | 2966 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 2933 | const operand: MCValue = blk: { | 2967 | const operand: MCValue = blk: { |
| 2934 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2968 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2935 | // The MCValue that holds the pointer can be re-used as the value. | 2969 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2959,6 +2993,8 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2959,6 +2993,8 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2959 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2993 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2960 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2994 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2961 | const operand_ptr = try self.resolveInst(un_op); | 2995 | const operand_ptr = try self.resolveInst(un_op); |
| | 2996 | operand_ptr.freezeIfRegister(&self.register_manager); |
| | 2997 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 2962 | const operand: MCValue = blk: { | 2998 | const operand: MCValue = blk: { |
| 2963 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2999 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2964 | // The MCValue that holds the pointer can be re-used as the value. | 3000 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2988,6 +3024,8 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2988,6 +3024,8 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2988 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 3024 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2989 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3025 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2990 | const operand_ptr = try self.resolveInst(un_op); | 3026 | const operand_ptr = try self.resolveInst(un_op); |
| | 3027 | operand_ptr.freezeIfRegister(&self.register_manager); |
| | 3028 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 2991 | const operand: MCValue = blk: { | 3029 | const operand: MCValue = blk: { |
| 2992 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 3030 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2993 | // The MCValue that holds the pointer can be re-used as the value. | 3031 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -3345,7 +3383,10 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3345,7 +3383,10 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3345 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | 3383 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3346 | } | 3384 | } |
| 3347 | | 3385 | |
| 3348 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx }); | 3386 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| | 3387 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| | 3388 | |
| | 3389 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{}); |
| 3349 | const addr_reg = regs[0]; | 3390 | const addr_reg = regs[0]; |
| 3350 | const count_reg = regs[1]; | 3391 | const count_reg = regs[1]; |
| 3351 | const tmp_reg = regs[2]; | 3392 | const tmp_reg = regs[2]; |
| ... | @@ -3363,7 +3404,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3363,7 +3404,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3363 | }); | 3404 | }); |
| 3364 | | 3405 | |
| 3365 | // TODO allow for abi_size to be u64 | 3406 | // TODO allow for abi_size to be u64 |
| 3366 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); | 3407 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 3367 | try self.genInlineMemcpy( | 3408 | try self.genInlineMemcpy( |
| 3368 | -(stack_offset + @intCast(i32, abi_size)), | 3409 | -(stack_offset + @intCast(i32, abi_size)), |
| 3369 | .rsp, | 3410 | .rsp, |
| ... | @@ -3510,7 +3551,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3510,7 +3551,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3510 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3551 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3511 | } | 3552 | } |
| 3512 | | 3553 | |
| 3513 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx, .rbp }); | 3554 | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp }); |
| | 3555 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp }); |
| | 3556 | |
| | 3557 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{}); |
| 3514 | const addr_reg = regs[0]; | 3558 | const addr_reg = regs[0]; |
| 3515 | const count_reg = regs[1]; | 3559 | const count_reg = regs[1]; |
| 3516 | const tmp_reg = regs[2]; | 3560 | const tmp_reg = regs[2]; |
| ... | @@ -3528,7 +3572,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3528,7 +3572,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3528 | }); | 3572 | }); |
| 3529 | | 3573 | |
| 3530 | // TODO allow for abi_size to be u64 | 3574 | // TODO allow for abi_size to be u64 |
| 3531 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); | 3575 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 3532 | | 3576 | |
| 3533 | return self.genInlineMemcpy( | 3577 | return self.genInlineMemcpy( |
| 3534 | -(stack_offset + @intCast(i32, abi_size)), | 3578 | -(stack_offset + @intCast(i32, abi_size)), |