| ... | @@ -115,11 +115,6 @@ const MCValue = union(enum) { | ... | @@ -115,11 +115,6 @@ const MCValue = union(enum) { |
| 115 | /// A pointer-sized integer that fits in a register. | 115 | /// A pointer-sized integer that fits in a register. |
| 116 | /// If the type is a pointer, this is the pointer address in virtual address space. | 116 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 117 | immediate: u64, | 117 | immediate: u64, |
| 118 | /// The constant was emitted into the code, at this offset. | | |
| 119 | /// If the type is a pointer, it means the pointer address is embedded in the code. | | |
| 120 | embedded_in_code: usize, | | |
| 121 | /// The value is a pointer to a constant which was emitted into the code, at this offset. | | |
| 122 | ptr_embedded_in_code: usize, | | |
| 123 | /// The value is in a target-specific register. | 118 | /// The value is in a target-specific register. |
| 124 | register: Register, | 119 | register: Register, |
| 125 | /// The value is in memory at a hard-coded address. | 120 | /// The value is in memory at a hard-coded address. |
| ... | @@ -147,7 +142,7 @@ const MCValue = union(enum) { | ... | @@ -147,7 +142,7 @@ const MCValue = union(enum) { |
| 147 | | 142 | |
| 148 | fn isMemory(mcv: MCValue) bool { | 143 | fn isMemory(mcv: MCValue) bool { |
| 149 | return switch (mcv) { | 144 | return switch (mcv) { |
| 150 | .embedded_in_code, .memory, .stack_offset => true, | 145 | .memory, .stack_offset => true, |
| 151 | else => false, | 146 | else => false, |
| 152 | }; | 147 | }; |
| 153 | } | 148 | } |
| ... | @@ -166,12 +161,10 @@ const MCValue = union(enum) { | ... | @@ -166,12 +161,10 @@ const MCValue = union(enum) { |
| 166 | .dead => unreachable, | 161 | .dead => unreachable, |
| 167 | | 162 | |
| 168 | .immediate, | 163 | .immediate, |
| 169 | .embedded_in_code, | | |
| 170 | .memory, | 164 | .memory, |
| 171 | .compare_flags_unsigned, | 165 | .compare_flags_unsigned, |
| 172 | .compare_flags_signed, | 166 | .compare_flags_signed, |
| 173 | .ptr_stack_offset, | 167 | .ptr_stack_offset, |
| 174 | .ptr_embedded_in_code, | | |
| 175 | .undef, | 168 | .undef, |
| 176 | => false, | 169 | => false, |
| 177 | | 170 | |
| ... | @@ -816,10 +809,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u | ... | @@ -816,10 +809,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 816 | if (abi_align > self.stack_align) | 809 | if (abi_align > self.stack_align) |
| 817 | self.stack_align = abi_align; | 810 | self.stack_align = abi_align; |
| 818 | // TODO find a free slot instead of always appending | 811 | // TODO find a free slot instead of always appending |
| 819 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align); | 812 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; |
| 820 | self.next_stack_offset = offset + abi_size; | 813 | self.next_stack_offset = offset; |
| 821 | if (self.next_stack_offset > self.max_end_stack) | 814 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 822 | self.max_end_stack = self.next_stack_offset; | | |
| 823 | try self.stack.putNoClobber(self.gpa, offset, .{ | 815 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 824 | .inst = inst, | 816 | .inst = inst, |
| 825 | .size = abi_size, | 817 | .size = abi_size, |
| ... | @@ -832,9 +824,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | ... | @@ -832,9 +824,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 832 | const elem_ty = self.air.typeOfIndex(inst).elemType(); | 824 | const elem_ty = self.air.typeOfIndex(inst).elemType(); |
| 833 | | 825 | |
| 834 | if (!elem_ty.hasRuntimeBits()) { | 826 | if (!elem_ty.hasRuntimeBits()) { |
| 835 | // As this stack item will never be dereferenced at runtime, | 827 | // return the stack offset 0. Stack offset 0 will be where all |
| 836 | // return the current stack offset | 828 | // zero-sized stack allocations live as non-zero-sized |
| 837 | return self.next_stack_offset; | 829 | // allocations will always have an offset > 0. |
| | 830 | return @as(u32, 0); |
| 838 | } | 831 | } |
| 839 | | 832 | |
| 840 | const target = self.target.*; | 833 | const target = self.target.*; |
| ... | @@ -1058,7 +1051,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1058,7 +1051,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1058 | | 1051 | |
| 1059 | _ = try self.addInst(.{ | 1052 | _ = try self.addInst(.{ |
| 1060 | .tag = .mvn, | 1053 | .tag = .mvn, |
| 1061 | .data = .{ .rr_imm6_shift = .{ | 1054 | .data = .{ .rr_imm6_logical_shift = .{ |
| 1062 | .rd = dest_reg, | 1055 | .rd = dest_reg, |
| 1063 | .rm = op_reg, | 1056 | .rm = op_reg, |
| 1064 | .imm6 = 0, | 1057 | .imm6 = 0, |
| ... | @@ -1104,8 +1097,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1104,8 +1097,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1104 | const ptr_bytes = @divExact(ptr_bits, 8); | 1097 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 1105 | | 1098 | |
| 1106 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | 1099 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); |
| 1107 | try self.genSetStack(ptr_ty, stack_offset + ptr_bytes, ptr); | 1100 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1108 | try self.genSetStack(len_ty, stack_offset, len); | 1101 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); |
| 1109 | break :result MCValue{ .stack_offset = stack_offset }; | 1102 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1110 | }; | 1103 | }; |
| 1111 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1104 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -1188,6 +1181,7 @@ fn binOpRegister( | ... | @@ -1188,6 +1181,7 @@ fn binOpRegister( |
| 1188 | .sub, | 1181 | .sub, |
| 1189 | .ptr_sub, | 1182 | .ptr_sub, |
| 1190 | => .sub_shifted_register, | 1183 | => .sub_shifted_register, |
| | 1184 | .cmp_eq => .cmp_shifted_register, |
| 1191 | .mul => .mul, | 1185 | .mul => .mul, |
| 1192 | .bit_and, | 1186 | .bit_and, |
| 1193 | .bool_and, | 1187 | .bool_and, |
| ... | @@ -1219,6 +1213,12 @@ fn binOpRegister( | ... | @@ -1219,6 +1213,12 @@ fn binOpRegister( |
| 1219 | .imm6 = 0, | 1213 | .imm6 = 0, |
| 1220 | .shift = .lsl, | 1214 | .shift = .lsl, |
| 1221 | } }, | 1215 | } }, |
| | 1216 | .cmp_eq => .{ .rr_imm6_shift = .{ |
| | 1217 | .rn = lhs_reg, |
| | 1218 | .rm = rhs_reg, |
| | 1219 | .imm6 = 0, |
| | 1220 | .shift = .lsl, |
| | 1221 | } }, |
| 1222 | .mul, | 1222 | .mul, |
| 1223 | .shl, | 1223 | .shl, |
| 1224 | .shl_exact, | 1224 | .shl_exact, |
| ... | @@ -1296,20 +1296,23 @@ fn binOpImmediate( | ... | @@ -1296,20 +1296,23 @@ fn binOpImmediate( |
| 1296 | }; | 1296 | }; |
| 1297 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); | 1297 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); |
| 1298 | | 1298 | |
| 1299 | const dest_reg = if (maybe_inst) |inst| blk: { | 1299 | const dest_reg = switch (tag) { |
| 1300 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1300 | .cmp_eq => undefined, // cmp has no destination register |
| | 1301 | else => if (maybe_inst) |inst| blk: { |
| | 1302 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1301 | | 1303 | |
| 1302 | if (lhs_is_register and self.reuseOperand( | 1304 | if (lhs_is_register and self.reuseOperand( |
| 1303 | inst, | 1305 | inst, |
| 1304 | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, | 1306 | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, |
| 1305 | if (lhs_and_rhs_swapped) 1 else 0, | 1307 | if (lhs_and_rhs_swapped) 1 else 0, |
| 1306 | lhs, | 1308 | lhs, |
| 1307 | )) { | 1309 | )) { |
| 1308 | break :blk lhs_reg; | 1310 | break :blk lhs_reg; |
| 1309 | } else { | 1311 | } else { |
| 1310 | break :blk try self.register_manager.allocReg(inst); | 1312 | break :blk try self.register_manager.allocReg(inst); |
| 1311 | } | 1313 | } |
| 1312 | } else try self.register_manager.allocReg(null); | 1314 | } else try self.register_manager.allocReg(null), |
| | 1315 | }; |
| 1313 | | 1316 | |
| 1314 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | 1317 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1315 | | 1318 | |
| ... | @@ -1325,6 +1328,7 @@ fn binOpImmediate( | ... | @@ -1325,6 +1328,7 @@ fn binOpImmediate( |
| 1325 | .signed => Mir.Inst.Tag.asr_immediate, | 1328 | .signed => Mir.Inst.Tag.asr_immediate, |
| 1326 | .unsigned => Mir.Inst.Tag.lsr_immediate, | 1329 | .unsigned => Mir.Inst.Tag.lsr_immediate, |
| 1327 | }, | 1330 | }, |
| | 1331 | .cmp_eq => .cmp_immediate, |
| 1328 | else => unreachable, | 1332 | else => unreachable, |
| 1329 | }; | 1333 | }; |
| 1330 | const mir_data: Mir.Inst.Data = switch (tag) { | 1334 | const mir_data: Mir.Inst.Data = switch (tag) { |
| ... | @@ -1344,6 +1348,10 @@ fn binOpImmediate( | ... | @@ -1344,6 +1348,10 @@ fn binOpImmediate( |
| 1344 | .rn = lhs_reg, | 1348 | .rn = lhs_reg, |
| 1345 | .shift = @intCast(u6, rhs.immediate), | 1349 | .shift = @intCast(u6, rhs.immediate), |
| 1346 | } }, | 1350 | } }, |
| | 1351 | .cmp_eq => .{ .r_imm12_sh = .{ |
| | 1352 | .rn = lhs_reg, |
| | 1353 | .imm12 = @intCast(u12, rhs.immediate), |
| | 1354 | } }, |
| 1347 | else => unreachable, | 1355 | else => unreachable, |
| 1348 | }; | 1356 | }; |
| 1349 | | 1357 | |
| ... | @@ -1381,6 +1389,7 @@ fn binOp( | ... | @@ -1381,6 +1389,7 @@ fn binOp( |
| 1381 | // Arithmetic operations on integers and floats | 1389 | // Arithmetic operations on integers and floats |
| 1382 | .add, | 1390 | .add, |
| 1383 | .sub, | 1391 | .sub, |
| | 1392 | .cmp_eq, |
| 1384 | => { | 1393 | => { |
| 1385 | switch (lhs_ty.zigTypeTag()) { | 1394 | switch (lhs_ty.zigTypeTag()) { |
| 1386 | .Float => return self.fail("TODO binary operations on floats", .{}), | 1395 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| ... | @@ -1394,12 +1403,13 @@ fn binOp( | ... | @@ -1394,12 +1403,13 @@ fn binOp( |
| 1394 | // operands | 1403 | // operands |
| 1395 | const lhs_immediate_ok = switch (tag) { | 1404 | const lhs_immediate_ok = switch (tag) { |
| 1396 | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), | 1405 | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 1397 | .sub => false, | 1406 | .sub, .cmp_eq => false, |
| 1398 | else => unreachable, | 1407 | else => unreachable, |
| 1399 | }; | 1408 | }; |
| 1400 | const rhs_immediate_ok = switch (tag) { | 1409 | const rhs_immediate_ok = switch (tag) { |
| 1401 | .add, | 1410 | .add, |
| 1402 | .sub, | 1411 | .sub, |
| | 1412 | .cmp_eq, |
| 1403 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), | 1413 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 1404 | else => unreachable, | 1414 | else => unreachable, |
| 1405 | }; | 1415 | }; |
| ... | @@ -1505,7 +1515,13 @@ fn binOp( | ... | @@ -1505,7 +1515,13 @@ fn binOp( |
| 1505 | const elem_size = elem_ty.abiSize(self.target.*); | 1515 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1506 | | 1516 | |
| 1507 | if (elem_size == 1) { | 1517 | if (elem_size == 1) { |
| 1508 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1518 | const base_tag: Air.Inst.Tag = switch (tag) { |
| | 1519 | .ptr_add => .add, |
| | 1520 | .ptr_sub => .sub, |
| | 1521 | else => unreachable, |
| | 1522 | }; |
| | 1523 | |
| | 1524 | return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1509 | } else { | 1525 | } else { |
| 1510 | // convert the offset into a byte offset by | 1526 | // convert the offset into a byte offset by |
| 1511 | // multiplying it with elem_size | 1527 | // multiplying it with elem_size |
| ... | @@ -1714,14 +1730,12 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1714,14 +1730,12 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1714 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | 1730 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1715 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1731 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1716 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1732 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1717 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | | |
| 1718 | const ptr_bytes = @divExact(ptr_bits, 8); | | |
| 1719 | const mcv = try self.resolveInst(ty_op.operand); | 1733 | const mcv = try self.resolveInst(ty_op.operand); |
| 1720 | switch (mcv) { | 1734 | switch (mcv) { |
| 1721 | .dead, .unreach, .none => unreachable, | 1735 | .dead, .unreach, .none => unreachable, |
| 1722 | .register => unreachable, // a slice doesn't fit in one register | 1736 | .register => unreachable, // a slice doesn't fit in one register |
| 1723 | .stack_offset => |off| { | 1737 | .stack_offset => |off| { |
| 1724 | break :result MCValue{ .stack_offset = off + ptr_bytes }; | 1738 | break :result MCValue{ .stack_offset = off }; |
| 1725 | }, | 1739 | }, |
| 1726 | .memory => |addr| { | 1740 | .memory => |addr| { |
| 1727 | break :result MCValue{ .memory = addr }; | 1741 | break :result MCValue{ .memory = addr }; |
| ... | @@ -1742,7 +1756,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1742,7 +1756,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1742 | .dead, .unreach, .none => unreachable, | 1756 | .dead, .unreach, .none => unreachable, |
| 1743 | .register => unreachable, // a slice doesn't fit in one register | 1757 | .register => unreachable, // a slice doesn't fit in one register |
| 1744 | .stack_offset => |off| { | 1758 | .stack_offset => |off| { |
| 1745 | break :result MCValue{ .stack_offset = off }; | 1759 | break :result MCValue{ .stack_offset = off - ptr_bytes }; |
| 1746 | }, | 1760 | }, |
| 1747 | .memory => |addr| { | 1761 | .memory => |addr| { |
| 1748 | break :result MCValue{ .memory = addr + ptr_bytes }; | 1762 | break :result MCValue{ .memory = addr + ptr_bytes }; |
| ... | @@ -1762,7 +1776,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1762,7 +1776,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1762 | switch (mcv) { | 1776 | switch (mcv) { |
| 1763 | .dead, .unreach, .none => unreachable, | 1777 | .dead, .unreach, .none => unreachable, |
| 1764 | .ptr_stack_offset => |off| { | 1778 | .ptr_stack_offset => |off| { |
| 1765 | break :result MCValue{ .ptr_stack_offset = off + ptr_bytes }; | 1779 | break :result MCValue{ .ptr_stack_offset = off - ptr_bytes }; |
| 1766 | }, | 1780 | }, |
| 1767 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), | 1781 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), |
| 1768 | } | 1782 | } |
| ... | @@ -1809,7 +1823,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1809,7 +1823,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1809 | defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register}); | 1823 | defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register}); |
| 1810 | | 1824 | |
| 1811 | const base_mcv: MCValue = switch (slice_mcv) { | 1825 | const base_mcv: MCValue = switch (slice_mcv) { |
| 1812 | .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off + 8 }) }, | 1826 | .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off }) }, |
| 1813 | else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), | 1827 | else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), |
| 1814 | }; | 1828 | }; |
| 1815 | self.register_manager.freezeRegs(&.{base_mcv.register}); | 1829 | self.register_manager.freezeRegs(&.{base_mcv.register}); |
| ... | @@ -1949,12 +1963,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1949,12 +1963,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1949 | .compare_flags_signed => unreachable, | 1963 | .compare_flags_signed => unreachable, |
| 1950 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 1964 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1951 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), | 1965 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 1952 | .ptr_embedded_in_code => |off| { | | |
| 1953 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off }); | | |
| 1954 | }, | | |
| 1955 | .embedded_in_code => { | | |
| 1956 | return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); | | |
| 1957 | }, | | |
| 1958 | .register => |addr_reg| { | 1966 | .register => |addr_reg| { |
| 1959 | self.register_manager.freezeRegs(&.{addr_reg}); | 1967 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 1960 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | 1968 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| ... | @@ -1963,7 +1971,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1963,7 +1971,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1963 | .dead => unreachable, | 1971 | .dead => unreachable, |
| 1964 | .undef => unreachable, | 1972 | .undef => unreachable, |
| 1965 | .compare_flags_signed, .compare_flags_unsigned => unreachable, | 1973 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 1966 | .embedded_in_code => unreachable, | | |
| 1967 | .register => |dst_reg| { | 1974 | .register => |dst_reg| { |
| 1968 | try self.genLdrRegister(dst_reg, addr_reg, elem_size); | 1975 | try self.genLdrRegister(dst_reg, addr_reg, elem_size); |
| 1969 | }, | 1976 | }, |
| ... | @@ -2036,8 +2043,7 @@ fn genInlineMemcpy( | ... | @@ -2036,8 +2043,7 @@ fn genInlineMemcpy( |
| 2036 | // cmp count, len | 2043 | // cmp count, len |
| 2037 | _ = try self.addInst(.{ | 2044 | _ = try self.addInst(.{ |
| 2038 | .tag = .cmp_shifted_register, | 2045 | .tag = .cmp_shifted_register, |
| 2039 | .data = .{ .rrr_imm6_shift = .{ | 2046 | .data = .{ .rr_imm6_shift = .{ |
| 2040 | .rd = .xzr, | | |
| 2041 | .rn = count, | 2047 | .rn = count, |
| 2042 | .rm = len, | 2048 | .rm = len, |
| 2043 | .imm6 = 0, | 2049 | .imm6 = 0, |
| ... | @@ -2227,12 +2233,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2227,12 +2233,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2227 | .ptr_stack_offset => |off| { | 2233 | .ptr_stack_offset => |off| { |
| 2228 | try self.genSetStack(value_ty, off, value); | 2234 | try self.genSetStack(value_ty, off, value); |
| 2229 | }, | 2235 | }, |
| 2230 | .ptr_embedded_in_code => |off| { | | |
| 2231 | try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value); | | |
| 2232 | }, | | |
| 2233 | .embedded_in_code => { | | |
| 2234 | return self.fail("TODO implement storing to MCValue.embedded_in_code", .{}); | | |
| 2235 | }, | | |
| 2236 | .register => |addr_reg| { | 2236 | .register => |addr_reg| { |
| 2237 | self.register_manager.freezeRegs(&.{addr_reg}); | 2237 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 2238 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | 2238 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| ... | @@ -2297,13 +2297,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -2297,13 +2297,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 2297 | const mcv = try self.resolveInst(operand); | 2297 | const mcv = try self.resolveInst(operand); |
| 2298 | const ptr_ty = self.air.typeOf(operand); | 2298 | const ptr_ty = self.air.typeOf(operand); |
| 2299 | const struct_ty = ptr_ty.childType(); | 2299 | const struct_ty = ptr_ty.childType(); |
| 2300 | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); | | |
| 2301 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 2300 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| 2302 | const struct_field_ty = struct_ty.structFieldType(index); | | |
| 2303 | const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); | | |
| 2304 | switch (mcv) { | 2301 | switch (mcv) { |
| 2305 | .ptr_stack_offset => |off| { | 2302 | .ptr_stack_offset => |off| { |
| 2306 | break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size }; | 2303 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| 2307 | }, | 2304 | }, |
| 2308 | else => { | 2305 | else => { |
| 2309 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ | 2306 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ |
| ... | @@ -2445,7 +2442,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -2445,7 +2442,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2445 | .immediate => unreachable, | 2442 | .immediate => unreachable, |
| 2446 | .unreach => unreachable, | 2443 | .unreach => unreachable, |
| 2447 | .dead => unreachable, | 2444 | .dead => unreachable, |
| 2448 | .embedded_in_code => unreachable, | | |
| 2449 | .memory => unreachable, | 2445 | .memory => unreachable, |
| 2450 | .compare_flags_signed => unreachable, | 2446 | .compare_flags_signed => unreachable, |
| 2451 | .compare_flags_unsigned => unreachable, | 2447 | .compare_flags_unsigned => unreachable, |
| ... | @@ -2461,9 +2457,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -2461,9 +2457,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2461 | .ptr_stack_offset => { | 2457 | .ptr_stack_offset => { |
| 2462 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 2458 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 2463 | }, | 2459 | }, |
| 2464 | .ptr_embedded_in_code => { | | |
| 2465 | return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | | |
| 2466 | }, | | |
| 2467 | } | 2460 | } |
| 2468 | } | 2461 | } |
| 2469 | | 2462 | |
| ... | @@ -2615,107 +2608,48 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2615,107 +2608,48 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2615 | | 2608 | |
| 2616 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 2609 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2617 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2610 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2618 | | 2611 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2619 | if (self.liveness.isUnused(inst)) | 2612 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2620 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 2613 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2621 | | 2614 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 2622 | const ty = self.air.typeOf(bin_op.lhs); | 2615 | |
| 2623 | | 2616 | var int_buffer: Type.Payload.Bits = undefined; |
| 2624 | if (ty.abiSize(self.target.*) > 8) { | 2617 | const int_ty = switch (lhs_ty.zigTypeTag()) { |
| 2625 | return self.fail("TODO cmp for types with size > 8", .{}); | 2618 | .Vector => return self.fail("TODO AArch64 cmp vectors", .{}), |
| 2626 | } | 2619 | .Enum => lhs_ty.intTagType(&int_buffer), |
| 2627 | | 2620 | .Int => lhs_ty, |
| 2628 | try self.spillCompareFlagsIfOccupied(); | 2621 | .Bool => Type.initTag(.u1), |
| 2629 | self.compare_flags_inst = inst; | 2622 | .Pointer => Type.usize, |
| 2630 | | 2623 | .ErrorSet => Type.initTag(.u16), |
| 2631 | const signedness: std.builtin.Signedness = blk: { | 2624 | .Optional => blk: { |
| 2632 | // by default we tell the operand type is unsigned (i.e. bools and enum values) | 2625 | var opt_buffer: Type.Payload.ElemType = undefined; |
| 2633 | if (ty.zigTypeTag() != .Int) break :blk .unsigned; | 2626 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); |
| 2634 | | 2627 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 2635 | // incase of an actual integer, we emit the correct signedness | 2628 | break :blk Type.initTag(.u1); |
| 2636 | break :blk ty.intInfo(self.target.*).signedness; | 2629 | } else if (lhs_ty.isPtrLikeOptional()) { |
| 2637 | }; | 2630 | break :blk Type.usize; |
| 2638 | | 2631 | } else { |
| 2639 | const lhs = try self.resolveInst(bin_op.lhs); | 2632 | return self.fail("TODO AArch64 cmp non-pointer optionals", .{}); |
| 2640 | const rhs = try self.resolveInst(bin_op.rhs); | 2633 | } |
| 2641 | const result: MCValue = result: { | 2634 | }, |
| 2642 | const lhs_is_register = lhs == .register; | 2635 | .Float => return self.fail("TODO AArch64 cmp floats", .{}), |
| 2643 | const rhs_is_register = rhs == .register; | 2636 | else => unreachable, |
| 2644 | // lhs should always be a register | | |
| 2645 | const rhs_should_be_register = switch (rhs) { | | |
| 2646 | .immediate => |imm| imm < 0 or imm > std.math.maxInt(u12), | | |
| 2647 | else => true, | | |
| 2648 | }; | 2637 | }; |
| 2649 | | 2638 | |
| 2650 | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); | 2639 | const int_info = int_ty.intInfo(self.target.*); |
| 2651 | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); | 2640 | if (int_info.bits <= 64) { |
| 2652 | if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register}); | 2641 | _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty); |
| 2653 | defer if (rhs_is_register) self.register_manager.unfreezeRegs(&.{rhs.register}); | | |
| 2654 | | 2642 | |
| 2655 | var lhs_mcv = lhs; | 2643 | try self.spillCompareFlagsIfOccupied(); |
| 2656 | var rhs_mcv = rhs; | 2644 | self.compare_flags_inst = inst; |
| 2657 | | 2645 | |
| 2658 | // Allocate registers | 2646 | break :result switch (int_info.signedness) { |
| 2659 | if (rhs_should_be_register) { | 2647 | .signed => MCValue{ .compare_flags_signed = op }, |
| 2660 | if (!lhs_is_register and !rhs_is_register) { | 2648 | .unsigned => MCValue{ .compare_flags_unsigned = op }, |
| 2661 | const regs = try self.register_manager.allocRegs(2, .{ | 2649 | }; |
| 2662 | Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?, | | |
| 2663 | }); | | |
| 2664 | lhs_mcv = MCValue{ .register = regs[0] }; | | |
| 2665 | rhs_mcv = MCValue{ .register = regs[1] }; | | |
| 2666 | } else if (!rhs_is_register) { | | |
| 2667 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?) }; | | |
| 2668 | } else if (!lhs_is_register) { | | |
| 2669 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?) }; | | |
| 2670 | } | | |
| 2671 | } else { | 2650 | } else { |
| 2672 | if (!lhs_is_register) { | 2651 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); |
| 2673 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?) }; | | |
| 2674 | } | | |
| 2675 | } | | |
| 2676 | | | |
| 2677 | // Move the operands to the newly allocated registers | | |
| 2678 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | | |
| 2679 | if (lhs_mcv == .register and !lhs_is_register) { | | |
| 2680 | try self.genSetReg(ty, lhs_mcv.register, lhs); | | |
| 2681 | branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.lhs).?, lhs); | | |
| 2682 | } | | |
| 2683 | if (rhs_mcv == .register and !rhs_is_register) { | | |
| 2684 | try self.genSetReg(ty, rhs_mcv.register, rhs); | | |
| 2685 | branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs); | | |
| 2686 | } | 2652 | } |
| 2687 | | | |
| 2688 | // The destination register is not present in the cmp instruction | | |
| 2689 | // The signedness of the integer does not matter for the cmp instruction | | |
| 2690 | switch (rhs_mcv) { | | |
| 2691 | .register => |reg| { | | |
| 2692 | _ = try self.addInst(.{ | | |
| 2693 | .tag = .cmp_shifted_register, | | |
| 2694 | .data = .{ .rrr_imm6_shift = .{ | | |
| 2695 | .rd = .xzr, | | |
| 2696 | .rn = lhs_mcv.register, | | |
| 2697 | .rm = reg, | | |
| 2698 | .imm6 = 0, | | |
| 2699 | .shift = .lsl, | | |
| 2700 | } }, | | |
| 2701 | }); | | |
| 2702 | }, | | |
| 2703 | .immediate => |imm| { | | |
| 2704 | _ = try self.addInst(.{ | | |
| 2705 | .tag = .cmp_immediate, | | |
| 2706 | .data = .{ .r_imm12_sh = .{ | | |
| 2707 | .rn = lhs_mcv.register, | | |
| 2708 | .imm12 = @intCast(u12, imm), | | |
| 2709 | } }, | | |
| 2710 | }); | | |
| 2711 | }, | | |
| 2712 | else => unreachable, | | |
| 2713 | } | | |
| 2714 | | | |
| 2715 | break :result switch (signedness) { | | |
| 2716 | .signed => MCValue{ .compare_flags_signed = op }, | | |
| 2717 | .unsigned => MCValue{ .compare_flags_unsigned = op }, | | |
| 2718 | }; | | |
| 2719 | }; | 2653 | }; |
| 2720 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2654 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2721 | } | 2655 | } |
| ... | @@ -3384,18 +3318,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3384,18 +3318,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3384 | .compare_flags_signed, | 3318 | .compare_flags_signed, |
| 3385 | .immediate, | 3319 | .immediate, |
| 3386 | .ptr_stack_offset, | 3320 | .ptr_stack_offset, |
| 3387 | .ptr_embedded_in_code, | | |
| 3388 | => { | 3321 | => { |
| 3389 | const reg = try self.copyToTmpRegister(ty, mcv); | 3322 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3390 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3323 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3391 | }, | 3324 | }, |
| 3392 | .embedded_in_code => |code_offset| { | | |
| 3393 | _ = code_offset; | | |
| 3394 | return self.fail("TODO implement set stack variable from embedded_in_code", .{}); | | |
| 3395 | }, | | |
| 3396 | .register => |reg| { | 3325 | .register => |reg| { |
| 3397 | const adj_off = stack_offset + abi_size; | | |
| 3398 | | | |
| 3399 | switch (abi_size) { | 3326 | switch (abi_size) { |
| 3400 | 1, 2, 4, 8 => { | 3327 | 1, 2, 4, 8 => { |
| 3401 | const tag: Mir.Inst.Tag = switch (abi_size) { | 3328 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| ... | @@ -3410,7 +3337,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3410,7 +3337,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3410 | .tag = tag, | 3337 | .tag = tag, |
| 3411 | .data = .{ .load_store_stack = .{ | 3338 | .data = .{ .load_store_stack = .{ |
| 3412 | .rt = rt, | 3339 | .rt = rt, |
| 3413 | .offset = @intCast(u32, adj_off), | 3340 | .offset = @intCast(u32, stack_offset), |
| 3414 | } }, | 3341 | } }, |
| 3415 | }); | 3342 | }); |
| 3416 | }, | 3343 | }, |
| ... | @@ -3495,7 +3422,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3495,7 +3422,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3495 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 3422 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3496 | switch (mcv) { | 3423 | switch (mcv) { |
| 3497 | .dead => unreachable, | 3424 | .dead => unreachable, |
| 3498 | .ptr_embedded_in_code => unreachable, | | |
| 3499 | .unreach, .none => return, // Nothing to do. | 3425 | .unreach, .none => return, // Nothing to do. |
| 3500 | .undef => { | 3426 | .undef => { |
| 3501 | if (!self.wantSafety()) | 3427 | if (!self.wantSafety()) |
| ... | @@ -3507,13 +3433,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3507,13 +3433,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3507 | else => unreachable, // unexpected register size | 3433 | else => unreachable, // unexpected register size |
| 3508 | } | 3434 | } |
| 3509 | }, | 3435 | }, |
| 3510 | .ptr_stack_offset => |unadjusted_off| { | 3436 | .ptr_stack_offset => |off| { |
| 3511 | // TODO: maybe addressing from sp instead of fp | 3437 | // TODO: maybe addressing from sp instead of fp |
| 3512 | const elem_ty = ty.childType(); | 3438 | const imm12 = math.cast(u12, off) catch |
| 3513 | const abi_size = elem_ty.abiSize(self.target.*); | | |
| 3514 | const adj_off = unadjusted_off + abi_size; | | |
| 3515 | | | |
| 3516 | const imm12 = math.cast(u12, adj_off) catch | | |
| 3517 | return self.fail("TODO larger stack offsets", .{}); | 3439 | return self.fail("TODO larger stack offsets", .{}); |
| 3518 | | 3440 | |
| 3519 | _ = try self.addInst(.{ | 3441 | _ = try self.addInst(.{ |
| ... | @@ -3603,9 +3525,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3603,9 +3525,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3603 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 3525 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 3604 | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); | 3526 | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); |
| 3605 | }, | 3527 | }, |
| 3606 | .stack_offset => |unadjusted_off| { | 3528 | .stack_offset => |off| { |
| 3607 | const abi_size = ty.abiSize(self.target.*); | 3529 | const abi_size = ty.abiSize(self.target.*); |
| 3608 | const adj_off = unadjusted_off + abi_size; | | |
| 3609 | | 3530 | |
| 3610 | switch (abi_size) { | 3531 | switch (abi_size) { |
| 3611 | 1, 2, 4, 8 => { | 3532 | 1, 2, 4, 8 => { |
| ... | @@ -3625,7 +3546,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3625,7 +3546,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3625 | .tag = tag, | 3546 | .tag = tag, |
| 3626 | .data = .{ .load_store_stack = .{ | 3547 | .data = .{ .load_store_stack = .{ |
| 3627 | .rt = rt, | 3548 | .rt = rt, |
| 3628 | .offset = @intCast(u32, adj_off), | 3549 | .offset = @intCast(u32, off), |
| 3629 | } }, | 3550 | } }, |
| 3630 | }); | 3551 | }); |
| 3631 | }, | 3552 | }, |
| ... | @@ -3633,7 +3554,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3633,7 +3554,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3633 | else => unreachable, | 3554 | else => unreachable, |
| 3634 | } | 3555 | } |
| 3635 | }, | 3556 | }, |
| 3636 | else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}), | | |
| 3637 | } | 3557 | } |
| 3638 | } | 3558 | } |
| 3639 | | 3559 | |
| ... | @@ -3661,8 +3581,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3661,8 +3581,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 3661 | const ptr_bytes = @divExact(ptr_bits, 8); | 3581 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3662 | | 3582 | |
| 3663 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | 3583 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); |
| 3664 | try self.genSetStack(ptr_ty, stack_offset + ptr_bytes, ptr); | 3584 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 3665 | try self.genSetStack(Type.initTag(.usize), stack_offset, .{ .immediate = array_len }); | 3585 | try self.genSetStack(Type.initTag(.usize), stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 3666 | break :result MCValue{ .stack_offset = stack_offset }; | 3586 | break :result MCValue{ .stack_offset = stack_offset }; |
| 3667 | }; | 3587 | }; |
| 3668 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3588 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |