| ... | ... | @@ -118,11 +118,6 @@ const MCValue = union(enum) { |
| 118 | 118 | /// A pointer-sized integer that fits in a register. |
| 119 | 119 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 120 | 120 | immediate: u32, |
| 121 | | /// The constant was emitted into the code, at this offset. |
| 122 | | /// If the type is a pointer, it means the pointer address is embedded in the code. |
| 123 | | embedded_in_code: usize, |
| 124 | | /// The value is a pointer to a constant which was emitted into the code, at this offset. |
| 125 | | ptr_embedded_in_code: usize, |
| 126 | 121 | /// The value is in a target-specific register. |
| 127 | 122 | register: Register, |
| 128 | 123 | /// The value is in memory at a hard-coded address. |
| ... | ... | @@ -144,7 +139,7 @@ const MCValue = union(enum) { |
| 144 | 139 | |
| 145 | 140 | fn isMemory(mcv: MCValue) bool { |
| 146 | 141 | return switch (mcv) { |
| 147 | | .embedded_in_code, .memory, .stack_offset, .stack_argument_offset => true, |
| 142 | .memory, .stack_offset, .stack_argument_offset => true, |
| 148 | 143 | else => false, |
| 149 | 144 | }; |
| 150 | 145 | } |
| ... | ... | @@ -163,12 +158,10 @@ const MCValue = union(enum) { |
| 163 | 158 | .dead => unreachable, |
| 164 | 159 | |
| 165 | 160 | .immediate, |
| 166 | | .embedded_in_code, |
| 167 | 161 | .memory, |
| 168 | 162 | .compare_flags_unsigned, |
| 169 | 163 | .compare_flags_signed, |
| 170 | 164 | .ptr_stack_offset, |
| 171 | | .ptr_embedded_in_code, |
| 172 | 165 | .undef, |
| 173 | 166 | .stack_argument_offset, |
| 174 | 167 | => false, |
| ... | ... | @@ -1358,24 +1351,28 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1358 | 1351 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1359 | 1352 | } |
| 1360 | 1353 | |
| 1354 | fn slicePtr(self: *Self, mcv: MCValue) !MCValue { |
| 1355 | switch (mcv) { |
| 1356 | .dead, .unreach => unreachable, |
| 1357 | .register => unreachable, // a slice doesn't fit in one register |
| 1358 | .stack_argument_offset => |off| { |
| 1359 | return MCValue{ .stack_argument_offset = off + 4 }; |
| 1360 | }, |
| 1361 | .stack_offset => |off| { |
| 1362 | return MCValue{ .stack_offset = off + 4 }; |
| 1363 | }, |
| 1364 | .memory => |addr| { |
| 1365 | return MCValue{ .memory = addr }; |
| 1366 | }, |
| 1367 | else => return self.fail("TODO implement slice_ptr for {}", .{mcv}), |
| 1368 | } |
| 1369 | } |
| 1370 | |
| 1361 | 1371 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1362 | 1372 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1363 | 1373 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1364 | 1374 | const mcv = try self.resolveInst(ty_op.operand); |
| 1365 | | switch (mcv) { |
| 1366 | | .dead, .unreach => unreachable, |
| 1367 | | .register => unreachable, // a slice doesn't fit in one register |
| 1368 | | .stack_argument_offset => |off| { |
| 1369 | | break :result MCValue{ .stack_argument_offset = off + 4 }; |
| 1370 | | }, |
| 1371 | | .stack_offset => |off| { |
| 1372 | | break :result MCValue{ .stack_offset = off + 4 }; |
| 1373 | | }, |
| 1374 | | .memory => |addr| { |
| 1375 | | break :result MCValue{ .memory = addr }; |
| 1376 | | }, |
| 1377 | | else => return self.fail("TODO implement slice_ptr for {}", .{mcv}), |
| 1378 | | } |
| 1375 | break :result try self.slicePtr(mcv); |
| 1379 | 1376 | }; |
| 1380 | 1377 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1381 | 1378 | } |
| ... | ... | @@ -1409,7 +1406,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1409 | 1406 | switch (mcv) { |
| 1410 | 1407 | .dead, .unreach => unreachable, |
| 1411 | 1408 | .ptr_stack_offset => |off| { |
| 1412 | | break :result MCValue{ .ptr_stack_offset = off + 4 }; |
| 1409 | break :result MCValue{ .ptr_stack_offset = off }; |
| 1413 | 1410 | }, |
| 1414 | 1411 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), |
| 1415 | 1412 | } |
| ... | ... | @@ -1424,7 +1421,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1424 | 1421 | switch (mcv) { |
| 1425 | 1422 | .dead, .unreach => unreachable, |
| 1426 | 1423 | .ptr_stack_offset => |off| { |
| 1427 | | break :result MCValue{ .ptr_stack_offset = off }; |
| 1424 | break :result MCValue{ .ptr_stack_offset = off + 4 }; |
| 1428 | 1425 | }, |
| 1429 | 1426 | else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{mcv}), |
| 1430 | 1427 | } |
| ... | ... | @@ -1455,15 +1452,17 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1455 | 1452 | if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register}); |
| 1456 | 1453 | defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register}); |
| 1457 | 1454 | |
| 1458 | | const base_mcv: MCValue = switch (slice_mcv) { |
| 1459 | | .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off + 4 }) }, |
| 1460 | | .stack_argument_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_argument_offset = off + 4 }) }, |
| 1461 | | else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), |
| 1462 | | }; |
| 1463 | | self.register_manager.freezeRegs(&.{base_mcv.register}); |
| 1455 | const base_mcv = try self.slicePtr(slice_mcv); |
| 1464 | 1456 | |
| 1465 | 1457 | switch (elem_size) { |
| 1466 | 1458 | 1, 4 => { |
| 1459 | const base_reg = switch (base_mcv) { |
| 1460 | .register => |r| r, |
| 1461 | else => try self.copyToTmpRegister(slice_ptr_field_type, base_mcv), |
| 1462 | }; |
| 1463 | self.register_manager.freezeRegs(&.{base_reg}); |
| 1464 | defer self.register_manager.unfreezeRegs(&.{base_reg}); |
| 1465 | |
| 1467 | 1466 | const dst_reg = try self.register_manager.allocReg(inst); |
| 1468 | 1467 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 1469 | 1468 | self.register_manager.freezeRegs(&.{dst_reg}); |
| ... | ... | @@ -1491,13 +1490,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1491 | 1490 | .tag = tag, |
| 1492 | 1491 | .data = .{ .rr_offset = .{ |
| 1493 | 1492 | .rt = dst_reg, |
| 1494 | | .rn = base_mcv.register, |
| 1493 | .rn = base_reg, |
| 1495 | 1494 | .offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) }, |
| 1496 | 1495 | } }, |
| 1497 | 1496 | }); |
| 1498 | 1497 | |
| 1499 | | self.register_manager.unfreezeRegs(&.{base_mcv.register}); |
| 1500 | | |
| 1501 | 1498 | break :result dst_mcv; |
| 1502 | 1499 | }, |
| 1503 | 1500 | else => { |
| ... | ... | @@ -1515,7 +1512,16 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1515 | 1512 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1516 | 1513 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1517 | 1514 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1518 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch}); |
| 1515 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1516 | const slice_mcv = try self.resolveInst(extra.lhs); |
| 1517 | const index_mcv = try self.resolveInst(extra.rhs); |
| 1518 | const base_mcv = try self.slicePtr(slice_mcv); |
| 1519 | |
| 1520 | const slice_ty = self.air.typeOf(extra.lhs); |
| 1521 | |
| 1522 | const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ty, Type.usize); |
| 1523 | break :result addr; |
| 1524 | }; |
| 1519 | 1525 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1520 | 1526 | } |
| 1521 | 1527 | |
| ... | ... | @@ -1535,7 +1541,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1535 | 1541 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1536 | 1542 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1537 | 1543 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1538 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch}); |
| 1544 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1545 | const ptr_mcv = try self.resolveInst(extra.lhs); |
| 1546 | const index_mcv = try self.resolveInst(extra.rhs); |
| 1547 | |
| 1548 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 1549 | |
| 1550 | const addr = try self.binOp(.ptr_add, null, ptr_mcv, index_mcv, ptr_ty, Type.usize); |
| 1551 | break :result addr; |
| 1552 | }; |
| 1539 | 1553 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1540 | 1554 | } |
| 1541 | 1555 | |
| ... | ... | @@ -1641,9 +1655,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1641 | 1655 | .compare_flags_signed => unreachable, |
| 1642 | 1656 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1643 | 1657 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 1644 | | .ptr_embedded_in_code => |off| { |
| 1645 | | try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off }); |
| 1646 | | }, |
| 1647 | 1658 | .register => |reg| { |
| 1648 | 1659 | self.register_manager.freezeRegs(&.{reg}); |
| 1649 | 1660 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| ... | ... | @@ -1652,7 +1663,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1652 | 1663 | .dead => unreachable, |
| 1653 | 1664 | .undef => unreachable, |
| 1654 | 1665 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 1655 | | .embedded_in_code => unreachable, |
| 1656 | 1666 | .register => |dst_reg| { |
| 1657 | 1667 | try self.genLdrRegister(dst_reg, reg, elem_ty); |
| 1658 | 1668 | }, |
| ... | ... | @@ -1690,7 +1700,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1690 | 1700 | } |
| 1691 | 1701 | }, |
| 1692 | 1702 | .memory, |
| 1693 | | .embedded_in_code, |
| 1694 | 1703 | .stack_offset, |
| 1695 | 1704 | .stack_argument_offset, |
| 1696 | 1705 | => { |
| ... | ... | @@ -1746,9 +1755,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1746 | 1755 | .ptr_stack_offset => |off| { |
| 1747 | 1756 | try self.genSetStack(value_ty, off, value); |
| 1748 | 1757 | }, |
| 1749 | | .ptr_embedded_in_code => |off| { |
| 1750 | | try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value); |
| 1751 | | }, |
| 1752 | 1758 | .register => |addr_reg| { |
| 1753 | 1759 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 1754 | 1760 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| ... | ... | @@ -1760,7 +1766,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1760 | 1766 | try self.genStrRegister(value_reg, addr_reg, value_ty); |
| 1761 | 1767 | }, |
| 1762 | 1768 | else => { |
| 1763 | | if (value_ty.abiSize(self.target.*) <= 4) { |
| 1769 | if (elem_size <= 4) { |
| 1764 | 1770 | const tmp_reg = try self.register_manager.allocReg(null); |
| 1765 | 1771 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 1766 | 1772 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| ... | ... | @@ -1784,6 +1790,17 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1784 | 1790 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 1785 | 1791 | }, |
| 1786 | 1792 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), |
| 1793 | .stack_argument_offset => |unadjusted_off| { |
| 1794 | const adj_off = unadjusted_off + elem_size; |
| 1795 | |
| 1796 | _ = try self.addInst(.{ |
| 1797 | .tag = .ldr_ptr_stack_argument, |
| 1798 | .data = .{ .r_stack_offset = .{ |
| 1799 | .rt = src_reg, |
| 1800 | .stack_offset = adj_off, |
| 1801 | } }, |
| 1802 | }); |
| 1803 | }, |
| 1787 | 1804 | else => return self.fail("TODO store {} to register", .{value}), |
| 1788 | 1805 | } |
| 1789 | 1806 | |
| ... | ... | @@ -1797,7 +1814,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1797 | 1814 | } |
| 1798 | 1815 | }, |
| 1799 | 1816 | .memory, |
| 1800 | | .embedded_in_code, |
| 1801 | 1817 | .stack_offset, |
| 1802 | 1818 | .stack_argument_offset, |
| 1803 | 1819 | => { |
| ... | ... | @@ -2680,12 +2696,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2680 | 2696 | .immediate => unreachable, |
| 2681 | 2697 | .unreach => unreachable, |
| 2682 | 2698 | .dead => unreachable, |
| 2683 | | .embedded_in_code => unreachable, |
| 2684 | 2699 | .memory => unreachable, |
| 2685 | 2700 | .compare_flags_signed => unreachable, |
| 2686 | 2701 | .compare_flags_unsigned => unreachable, |
| 2687 | 2702 | .ptr_stack_offset => unreachable, |
| 2688 | | .ptr_embedded_in_code => unreachable, |
| 2689 | 2703 | .register => |reg| { |
| 2690 | 2704 | try self.register_manager.getReg(reg, null); |
| 2691 | 2705 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| ... | ... | @@ -3584,7 +3598,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3584 | 3598 | .compare_flags_signed, |
| 3585 | 3599 | .immediate, |
| 3586 | 3600 | .ptr_stack_offset, |
| 3587 | | .ptr_embedded_in_code, |
| 3588 | 3601 | => { |
| 3589 | 3602 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3590 | 3603 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| ... | ... | @@ -3637,7 +3650,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3637 | 3650 | } |
| 3638 | 3651 | }, |
| 3639 | 3652 | .memory, |
| 3640 | | .embedded_in_code, |
| 3641 | 3653 | .stack_argument_offset, |
| 3642 | 3654 | .stack_offset, |
| 3643 | 3655 | => { |
| ... | ... | @@ -3684,7 +3696,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3684 | 3696 | } }, |
| 3685 | 3697 | }); |
| 3686 | 3698 | }, |
| 3687 | | .embedded_in_code => return self.fail("TODO genSetStack with src={}", .{mcv}), |
| 3688 | 3699 | else => unreachable, |
| 3689 | 3700 | } |
| 3690 | 3701 | |
| ... | ... | @@ -3704,7 +3715,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3704 | 3715 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3705 | 3716 | switch (mcv) { |
| 3706 | 3717 | .dead => unreachable, |
| 3707 | | .ptr_embedded_in_code => unreachable, |
| 3708 | 3718 | .unreach, .none => return, // Nothing to do. |
| 3709 | 3719 | .undef => { |
| 3710 | 3720 | if (!self.wantSafety()) |
| ... | ... | @@ -3964,7 +3974,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3964 | 3974 | } }, |
| 3965 | 3975 | }); |
| 3966 | 3976 | }, |
| 3967 | | else => return self.fail("TODO implement getSetReg for arm {}", .{mcv}), |
| 3968 | 3977 | } |
| 3969 | 3978 | } |
| 3970 | 3979 | |
| ... | ... | @@ -4028,7 +4037,6 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4028 | 4037 | .stack_offset, |
| 4029 | 4038 | .memory, |
| 4030 | 4039 | .stack_argument_offset, |
| 4031 | | .embedded_in_code, |
| 4032 | 4040 | => { |
| 4033 | 4041 | if (abi_size <= 4) { |
| 4034 | 4042 | const reg = try self.copyToTmpRegister(ty, mcv); |
| ... | ... | @@ -4054,9 +4062,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4054 | 4062 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 4055 | 4063 | }, |
| 4056 | 4064 | .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }), |
| 4057 | | .stack_argument_offset, |
| 4058 | | .embedded_in_code, |
| 4059 | | => return self.fail("TODO genSetStackArgument src={}", .{mcv}), |
| 4065 | .stack_argument_offset => return self.fail("TODO genSetStackArgument src={}", .{mcv}), |
| 4060 | 4066 | else => unreachable, |
| 4061 | 4067 | } |
| 4062 | 4068 | |
| ... | ... | @@ -4085,7 +4091,6 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4085 | 4091 | .compare_flags_signed, |
| 4086 | 4092 | .immediate, |
| 4087 | 4093 | .ptr_stack_offset, |
| 4088 | | .ptr_embedded_in_code, |
| 4089 | 4094 | => { |
| 4090 | 4095 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4091 | 4096 | return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg }); |