| ... | ... | @@ -115,11 +115,6 @@ const MCValue = union(enum) { |
| 115 | 115 | /// A pointer-sized integer that fits in a register. |
| 116 | 116 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 117 | 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 | 118 | /// The value is in a target-specific register. |
| 124 | 119 | register: Register, |
| 125 | 120 | /// The value is in memory at a hard-coded address. |
| ... | ... | @@ -147,7 +142,7 @@ const MCValue = union(enum) { |
| 147 | 142 | |
| 148 | 143 | fn isMemory(mcv: MCValue) bool { |
| 149 | 144 | return switch (mcv) { |
| 150 | | .embedded_in_code, .memory, .stack_offset => true, |
| 145 | .memory, .stack_offset => true, |
| 151 | 146 | else => false, |
| 152 | 147 | }; |
| 153 | 148 | } |
| ... | ... | @@ -166,12 +161,10 @@ const MCValue = union(enum) { |
| 166 | 161 | .dead => unreachable, |
| 167 | 162 | |
| 168 | 163 | .immediate, |
| 169 | | .embedded_in_code, |
| 170 | 164 | .memory, |
| 171 | 165 | .compare_flags_unsigned, |
| 172 | 166 | .compare_flags_signed, |
| 173 | 167 | .ptr_stack_offset, |
| 174 | | .ptr_embedded_in_code, |
| 175 | 168 | .undef, |
| 176 | 169 | => false, |
| 177 | 170 | |
| ... | ... | @@ -816,10 +809,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 816 | 809 | if (abi_align > self.stack_align) |
| 817 | 810 | self.stack_align = abi_align; |
| 818 | 811 | // TODO find a free slot instead of always appending |
| 819 | | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align); |
| 820 | | self.next_stack_offset = offset + abi_size; |
| 821 | | if (self.next_stack_offset > self.max_end_stack) |
| 822 | | self.max_end_stack = self.next_stack_offset; |
| 812 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; |
| 813 | self.next_stack_offset = offset; |
| 814 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 823 | 815 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 824 | 816 | .inst = inst, |
| 825 | 817 | .size = abi_size, |
| ... | ... | @@ -832,9 +824,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 832 | 824 | const elem_ty = self.air.typeOfIndex(inst).elemType(); |
| 833 | 825 | |
| 834 | 826 | if (!elem_ty.hasRuntimeBits()) { |
| 835 | | // As this stack item will never be dereferenced at runtime, |
| 836 | | // return the current stack offset |
| 837 | | return self.next_stack_offset; |
| 827 | // return the stack offset 0. Stack offset 0 will be where all |
| 828 | // zero-sized stack allocations live as non-zero-sized |
| 829 | // allocations will always have an offset > 0. |
| 830 | return @as(u32, 0); |
| 838 | 831 | } |
| 839 | 832 | |
| 840 | 833 | const target = self.target.*; |
| ... | ... | @@ -1058,7 +1051,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1058 | 1051 | |
| 1059 | 1052 | _ = try self.addInst(.{ |
| 1060 | 1053 | .tag = .mvn, |
| 1061 | | .data = .{ .rr_imm6_shift = .{ |
| 1054 | .data = .{ .rr_imm6_logical_shift = .{ |
| 1062 | 1055 | .rd = dest_reg, |
| 1063 | 1056 | .rm = op_reg, |
| 1064 | 1057 | .imm6 = 0, |
| ... | ... | @@ -1104,8 +1097,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1104 | 1097 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 1105 | 1098 | |
| 1106 | 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); |
| 1108 | | try self.genSetStack(len_ty, stack_offset, len); |
| 1100 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1101 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); |
| 1109 | 1102 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1110 | 1103 | }; |
| 1111 | 1104 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -1188,6 +1181,7 @@ fn binOpRegister( |
| 1188 | 1181 | .sub, |
| 1189 | 1182 | .ptr_sub, |
| 1190 | 1183 | => .sub_shifted_register, |
| 1184 | .cmp_eq => .cmp_shifted_register, |
| 1191 | 1185 | .mul => .mul, |
| 1192 | 1186 | .bit_and, |
| 1193 | 1187 | .bool_and, |
| ... | ... | @@ -1219,6 +1213,12 @@ fn binOpRegister( |
| 1219 | 1213 | .imm6 = 0, |
| 1220 | 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 | 1222 | .mul, |
| 1223 | 1223 | .shl, |
| 1224 | 1224 | .shl_exact, |
| ... | ... | @@ -1296,20 +1296,23 @@ fn binOpImmediate( |
| 1296 | 1296 | }; |
| 1297 | 1297 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); |
| 1298 | 1298 | |
| 1299 | | const dest_reg = if (maybe_inst) |inst| blk: { |
| 1300 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1299 | const dest_reg = switch (tag) { |
| 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( |
| 1303 | | inst, |
| 1304 | | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, |
| 1305 | | if (lhs_and_rhs_swapped) 1 else 0, |
| 1306 | | lhs, |
| 1307 | | )) { |
| 1308 | | break :blk lhs_reg; |
| 1309 | | } else { |
| 1310 | | break :blk try self.register_manager.allocReg(inst); |
| 1311 | | } |
| 1312 | | } else try self.register_manager.allocReg(null); |
| 1304 | if (lhs_is_register and self.reuseOperand( |
| 1305 | inst, |
| 1306 | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, |
| 1307 | if (lhs_and_rhs_swapped) 1 else 0, |
| 1308 | lhs, |
| 1309 | )) { |
| 1310 | break :blk lhs_reg; |
| 1311 | } else { |
| 1312 | break :blk try self.register_manager.allocReg(inst); |
| 1313 | } |
| 1314 | } else try self.register_manager.allocReg(null), |
| 1315 | }; |
| 1313 | 1316 | |
| 1314 | 1317 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1315 | 1318 | |
| ... | ... | @@ -1325,6 +1328,7 @@ fn binOpImmediate( |
| 1325 | 1328 | .signed => Mir.Inst.Tag.asr_immediate, |
| 1326 | 1329 | .unsigned => Mir.Inst.Tag.lsr_immediate, |
| 1327 | 1330 | }, |
| 1331 | .cmp_eq => .cmp_immediate, |
| 1328 | 1332 | else => unreachable, |
| 1329 | 1333 | }; |
| 1330 | 1334 | const mir_data: Mir.Inst.Data = switch (tag) { |
| ... | ... | @@ -1344,6 +1348,10 @@ fn binOpImmediate( |
| 1344 | 1348 | .rn = lhs_reg, |
| 1345 | 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 | 1355 | else => unreachable, |
| 1348 | 1356 | }; |
| 1349 | 1357 | |
| ... | ... | @@ -1381,6 +1389,7 @@ fn binOp( |
| 1381 | 1389 | // Arithmetic operations on integers and floats |
| 1382 | 1390 | .add, |
| 1383 | 1391 | .sub, |
| 1392 | .cmp_eq, |
| 1384 | 1393 | => { |
| 1385 | 1394 | switch (lhs_ty.zigTypeTag()) { |
| 1386 | 1395 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| ... | ... | @@ -1394,12 +1403,13 @@ fn binOp( |
| 1394 | 1403 | // operands |
| 1395 | 1404 | const lhs_immediate_ok = switch (tag) { |
| 1396 | 1405 | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 1397 | | .sub => false, |
| 1406 | .sub, .cmp_eq => false, |
| 1398 | 1407 | else => unreachable, |
| 1399 | 1408 | }; |
| 1400 | 1409 | const rhs_immediate_ok = switch (tag) { |
| 1401 | 1410 | .add, |
| 1402 | 1411 | .sub, |
| 1412 | .cmp_eq, |
| 1403 | 1413 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 1404 | 1414 | else => unreachable, |
| 1405 | 1415 | }; |
| ... | ... | @@ -1505,7 +1515,13 @@ fn binOp( |
| 1505 | 1515 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1506 | 1516 | |
| 1507 | 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 | 1525 | } else { |
| 1510 | 1526 | // convert the offset into a byte offset by |
| 1511 | 1527 | // multiplying it with elem_size |
| ... | ... | @@ -1714,14 +1730,12 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1714 | 1730 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1715 | 1731 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1716 | 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 | 1733 | const mcv = try self.resolveInst(ty_op.operand); |
| 1720 | 1734 | switch (mcv) { |
| 1721 | 1735 | .dead, .unreach, .none => unreachable, |
| 1722 | 1736 | .register => unreachable, // a slice doesn't fit in one register |
| 1723 | 1737 | .stack_offset => |off| { |
| 1724 | | break :result MCValue{ .stack_offset = off + ptr_bytes }; |
| 1738 | break :result MCValue{ .stack_offset = off }; |
| 1725 | 1739 | }, |
| 1726 | 1740 | .memory => |addr| { |
| 1727 | 1741 | break :result MCValue{ .memory = addr }; |
| ... | ... | @@ -1742,7 +1756,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1742 | 1756 | .dead, .unreach, .none => unreachable, |
| 1743 | 1757 | .register => unreachable, // a slice doesn't fit in one register |
| 1744 | 1758 | .stack_offset => |off| { |
| 1745 | | break :result MCValue{ .stack_offset = off }; |
| 1759 | break :result MCValue{ .stack_offset = off - ptr_bytes }; |
| 1746 | 1760 | }, |
| 1747 | 1761 | .memory => |addr| { |
| 1748 | 1762 | break :result MCValue{ .memory = addr + ptr_bytes }; |
| ... | ... | @@ -1762,7 +1776,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1762 | 1776 | switch (mcv) { |
| 1763 | 1777 | .dead, .unreach, .none => unreachable, |
| 1764 | 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 | 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 | 1823 | defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register}); |
| 1810 | 1824 | |
| 1811 | 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 | 1827 | else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), |
| 1814 | 1828 | }; |
| 1815 | 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 | 1963 | .compare_flags_signed => unreachable, |
| 1950 | 1964 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1951 | 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 | 1966 | .register => |addr_reg| { |
| 1959 | 1967 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 1960 | 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 | 1971 | .dead => unreachable, |
| 1964 | 1972 | .undef => unreachable, |
| 1965 | 1973 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 1966 | | .embedded_in_code => unreachable, |
| 1967 | 1974 | .register => |dst_reg| { |
| 1968 | 1975 | try self.genLdrRegister(dst_reg, addr_reg, elem_size); |
| 1969 | 1976 | }, |
| ... | ... | @@ -2036,8 +2043,7 @@ fn genInlineMemcpy( |
| 2036 | 2043 | // cmp count, len |
| 2037 | 2044 | _ = try self.addInst(.{ |
| 2038 | 2045 | .tag = .cmp_shifted_register, |
| 2039 | | .data = .{ .rrr_imm6_shift = .{ |
| 2040 | | .rd = .xzr, |
| 2046 | .data = .{ .rr_imm6_shift = .{ |
| 2041 | 2047 | .rn = count, |
| 2042 | 2048 | .rm = len, |
| 2043 | 2049 | .imm6 = 0, |
| ... | ... | @@ -2227,12 +2233,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2227 | 2233 | .ptr_stack_offset => |off| { |
| 2228 | 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 | 2236 | .register => |addr_reg| { |
| 2237 | 2237 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 2238 | 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 | 2297 | const mcv = try self.resolveInst(operand); |
| 2298 | 2298 | const ptr_ty = self.air.typeOf(operand); |
| 2299 | 2299 | const struct_ty = ptr_ty.childType(); |
| 2300 | | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 2301 | 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 | 2301 | switch (mcv) { |
| 2305 | 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 | 2305 | else => { |
| 2309 | 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 | 2442 | .immediate => unreachable, |
| 2446 | 2443 | .unreach => unreachable, |
| 2447 | 2444 | .dead => unreachable, |
| 2448 | | .embedded_in_code => unreachable, |
| 2449 | 2445 | .memory => unreachable, |
| 2450 | 2446 | .compare_flags_signed => unreachable, |
| 2451 | 2447 | .compare_flags_unsigned => unreachable, |
| ... | ... | @@ -2461,9 +2457,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2461 | 2457 | .ptr_stack_offset => { |
| 2462 | 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 | 2608 | |
| 2616 | 2609 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2617 | 2610 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2618 | | |
| 2619 | | if (self.liveness.isUnused(inst)) |
| 2620 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2621 | | |
| 2622 | | const ty = self.air.typeOf(bin_op.lhs); |
| 2623 | | |
| 2624 | | if (ty.abiSize(self.target.*) > 8) { |
| 2625 | | return self.fail("TODO cmp for types with size > 8", .{}); |
| 2626 | | } |
| 2627 | | |
| 2628 | | try self.spillCompareFlagsIfOccupied(); |
| 2629 | | self.compare_flags_inst = inst; |
| 2630 | | |
| 2631 | | const signedness: std.builtin.Signedness = blk: { |
| 2632 | | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 2633 | | if (ty.zigTypeTag() != .Int) break :blk .unsigned; |
| 2634 | | |
| 2635 | | // incase of an actual integer, we emit the correct signedness |
| 2636 | | break :blk ty.intInfo(self.target.*).signedness; |
| 2637 | | }; |
| 2638 | | |
| 2639 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 2640 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 2641 | | const result: MCValue = result: { |
| 2642 | | const lhs_is_register = lhs == .register; |
| 2643 | | const rhs_is_register = rhs == .register; |
| 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, |
| 2611 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2612 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2613 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2614 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 2615 | |
| 2616 | var int_buffer: Type.Payload.Bits = undefined; |
| 2617 | const int_ty = switch (lhs_ty.zigTypeTag()) { |
| 2618 | .Vector => return self.fail("TODO AArch64 cmp vectors", .{}), |
| 2619 | .Enum => lhs_ty.intTagType(&int_buffer), |
| 2620 | .Int => lhs_ty, |
| 2621 | .Bool => Type.initTag(.u1), |
| 2622 | .Pointer => Type.usize, |
| 2623 | .ErrorSet => Type.initTag(.u16), |
| 2624 | .Optional => blk: { |
| 2625 | var opt_buffer: Type.Payload.ElemType = undefined; |
| 2626 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); |
| 2627 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 2628 | break :blk Type.initTag(.u1); |
| 2629 | } else if (lhs_ty.isPtrLikeOptional()) { |
| 2630 | break :blk Type.usize; |
| 2631 | } else { |
| 2632 | return self.fail("TODO AArch64 cmp non-pointer optionals", .{}); |
| 2633 | } |
| 2634 | }, |
| 2635 | .Float => return self.fail("TODO AArch64 cmp floats", .{}), |
| 2636 | else => unreachable, |
| 2648 | 2637 | }; |
| 2649 | 2638 | |
| 2650 | | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); |
| 2651 | | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); |
| 2652 | | if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register}); |
| 2653 | | defer if (rhs_is_register) self.register_manager.unfreezeRegs(&.{rhs.register}); |
| 2639 | const int_info = int_ty.intInfo(self.target.*); |
| 2640 | if (int_info.bits <= 64) { |
| 2641 | _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty); |
| 2654 | 2642 | |
| 2655 | | var lhs_mcv = lhs; |
| 2656 | | var rhs_mcv = rhs; |
| 2643 | try self.spillCompareFlagsIfOccupied(); |
| 2644 | self.compare_flags_inst = inst; |
| 2657 | 2645 | |
| 2658 | | // Allocate registers |
| 2659 | | if (rhs_should_be_register) { |
| 2660 | | if (!lhs_is_register and !rhs_is_register) { |
| 2661 | | const regs = try self.register_manager.allocRegs(2, .{ |
| 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 | | } |
| 2646 | break :result switch (int_info.signedness) { |
| 2647 | .signed => MCValue{ .compare_flags_signed = op }, |
| 2648 | .unsigned => MCValue{ .compare_flags_unsigned = op }, |
| 2649 | }; |
| 2671 | 2650 | } else { |
| 2672 | | if (!lhs_is_register) { |
| 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); |
| 2651 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); |
| 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 | 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 | 3318 | .compare_flags_signed, |
| 3385 | 3319 | .immediate, |
| 3386 | 3320 | .ptr_stack_offset, |
| 3387 | | .ptr_embedded_in_code, |
| 3388 | 3321 | => { |
| 3389 | 3322 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3390 | 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 | 3325 | .register => |reg| { |
| 3397 | | const adj_off = stack_offset + abi_size; |
| 3398 | | |
| 3399 | 3326 | switch (abi_size) { |
| 3400 | 3327 | 1, 2, 4, 8 => { |
| 3401 | 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 | 3337 | .tag = tag, |
| 3411 | 3338 | .data = .{ .load_store_stack = .{ |
| 3412 | 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 | 3422 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3496 | 3423 | switch (mcv) { |
| 3497 | 3424 | .dead => unreachable, |
| 3498 | | .ptr_embedded_in_code => unreachable, |
| 3499 | 3425 | .unreach, .none => return, // Nothing to do. |
| 3500 | 3426 | .undef => { |
| 3501 | 3427 | if (!self.wantSafety()) |
| ... | ... | @@ -3507,13 +3433,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3507 | 3433 | else => unreachable, // unexpected register size |
| 3508 | 3434 | } |
| 3509 | 3435 | }, |
| 3510 | | .ptr_stack_offset => |unadjusted_off| { |
| 3436 | .ptr_stack_offset => |off| { |
| 3511 | 3437 | // TODO: maybe addressing from sp instead of fp |
| 3512 | | const elem_ty = ty.childType(); |
| 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 |
| 3438 | const imm12 = math.cast(u12, off) catch |
| 3517 | 3439 | return self.fail("TODO larger stack offsets", .{}); |
| 3518 | 3440 | |
| 3519 | 3441 | _ = try self.addInst(.{ |
| ... | ... | @@ -3603,9 +3525,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3603 | 3525 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 3604 | 3526 | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); |
| 3605 | 3527 | }, |
| 3606 | | .stack_offset => |unadjusted_off| { |
| 3528 | .stack_offset => |off| { |
| 3607 | 3529 | const abi_size = ty.abiSize(self.target.*); |
| 3608 | | const adj_off = unadjusted_off + abi_size; |
| 3609 | 3530 | |
| 3610 | 3531 | switch (abi_size) { |
| 3611 | 3532 | 1, 2, 4, 8 => { |
| ... | ... | @@ -3625,7 +3546,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3625 | 3546 | .tag = tag, |
| 3626 | 3547 | .data = .{ .load_store_stack = .{ |
| 3627 | 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 | 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 | 3581 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3662 | 3582 | |
| 3663 | 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); |
| 3665 | | try self.genSetStack(Type.initTag(.usize), stack_offset, .{ .immediate = array_len }); |
| 3584 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 3585 | try self.genSetStack(Type.initTag(.usize), stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 3666 | 3586 | break :result MCValue{ .stack_offset = stack_offset }; |
| 3667 | 3587 | }; |
| 3668 | 3588 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |