authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-25 22:22:47-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-25 22:22:47-04:00
logbcd7eb012ac3d4a6365eea0b69aa89b0aef57243
tree102e961e3ac86d8dc0d6b0669b29f3017c1c0b23
parentc1098e90367c8965fbf0c65e4967d938986af8b0
parentf7da4b9bc802b66d409413596204df355604fc67
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11304 from joachimschmidt557/stage2-aarch64

stage2 AArch64: remove MCValue.embedded_in_code

4 files changed, 143 insertions(+), 192 deletions(-)

src/arch/aarch64/CodeGen.zig+98-178
...@@ -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) {
147142
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,
167162
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,
177170
...@@ -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 appending811 // 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();
833825
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 offset828 // 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 }
839832
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 {
10581051
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);
11051098
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});
12981298
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;
13011303
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 };
13131316
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);
13151318
...@@ -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 };
13491357
...@@ -1381,6 +1389,7 @@ fn binOp(...@@ -1381,6 +1389,7 @@ fn binOp(
1381 // Arithmetic operations on integers and floats1389 // 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 // operands1403 // 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.*);
15061516
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 by1526 // convert the offset into a byte offset by
1511 // multiplying it with elem_size1527 // 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 {
1714fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {1730fn 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 register1736 .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 register1757 .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});
18101824
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, len2043 // 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 }
24692462
...@@ -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 {
26152608
2616fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {2609fn 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;
26182611 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);
26212614 const lhs_ty = self.air.typeOf(bin_op.lhs);
2622 const ty = self.air.typeOf(bin_op.lhs);2615
26232616 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),
26272620 .Int => lhs_ty,
2628 try self.spillCompareFlagsIfOccupied();2621 .Bool => Type.initTag(.u1),
2629 self.compare_flags_inst = inst;2622 .Pointer => Type.usize,
26302623 .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);
26342627 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2635 // incase of an actual integer, we emit the correct signedness2628 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;
26382631 } 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 };
26492638
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});
26542642
2655 var lhs_mcv = lhs;2643 try self.spillCompareFlagsIfOccupied();
2656 var rhs_mcv = rhs;2644 self.compare_flags_inst = inst;
26572645
2658 // Allocate registers2646 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
3495fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {3422fn 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 size3433 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 fp3437 // 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", .{});
35183440
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;
36093530
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}
36393559
...@@ -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);
36623582
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 });
src/arch/aarch64/Emit.zig+32-12
...@@ -650,17 +650,32 @@ fn mirLogicalImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -650,17 +650,32 @@ fn mirLogicalImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
650650
651fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {651fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
652 const tag = emit.mir.instructions.items(.tag)[inst];652 const tag = emit.mir.instructions.items(.tag)[inst];
653 const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift;
654 const rd = rrr_imm6_shift.rd;
655 const rn = rrr_imm6_shift.rn;
656 const rm = rrr_imm6_shift.rm;
657 const shift = rrr_imm6_shift.shift;
658 const imm6 = rrr_imm6_shift.imm6;
659
660 switch (tag) {653 switch (tag) {
661 .add_shifted_register => try emit.writeInstruction(Instruction.addShiftedRegister(rd, rn, rm, shift, imm6)),654 .add_shifted_register,
662 .cmp_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(rd, rn, rm, shift, imm6)),655 .sub_shifted_register,
663 .sub_shifted_register => try emit.writeInstruction(Instruction.subShiftedRegister(rd, rn, rm, shift, imm6)),656 => {
657 const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift;
658 const rd = rrr_imm6_shift.rd;
659 const rn = rrr_imm6_shift.rn;
660 const rm = rrr_imm6_shift.rm;
661 const shift = rrr_imm6_shift.shift;
662 const imm6 = rrr_imm6_shift.imm6;
663
664 switch (tag) {
665 .add_shifted_register => try emit.writeInstruction(Instruction.addShiftedRegister(rd, rn, rm, shift, imm6)),
666 .sub_shifted_register => try emit.writeInstruction(Instruction.subShiftedRegister(rd, rn, rm, shift, imm6)),
667 else => unreachable,
668 }
669 },
670 .cmp_shifted_register => {
671 const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift;
672 const rn = rr_imm6_shift.rn;
673 const rm = rr_imm6_shift.rm;
674 const shift = rr_imm6_shift.shift;
675 const imm6 = rr_imm6_shift.imm6;
676
677 try emit.writeInstruction(Instruction.subsShiftedRegister(.xzr, rn, rm, shift, imm6));
678 },
664 else => unreachable,679 else => unreachable,
665 }680 }
666}681}
...@@ -896,8 +911,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -896,8 +911,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
896 try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false));911 try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false));
897 },912 },
898 .mvn => {913 .mvn => {
899 const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift;914 const rr_imm6_logical_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_logical_shift;
900 try emit.writeInstruction(Instruction.ornShiftedRegister(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, rr_imm6_shift.shift, rr_imm6_shift.imm6));915 const rd = rr_imm6_logical_shift.rd;
916 const rm = rr_imm6_logical_shift.rm;
917 const shift = rr_imm6_logical_shift.shift;
918 const imm6 = rr_imm6_logical_shift.imm6;
919
920 try emit.writeInstruction(Instruction.ornShiftedRegister(rd, .xzr, rm, shift, imm6));
901 },921 },
902 else => unreachable,922 else => unreachable,
903 }923 }
src/arch/aarch64/Mir.zig+11-2
...@@ -249,11 +249,20 @@ pub const Inst = struct {...@@ -249,11 +249,20 @@ pub const Inst = struct {
249 imm12: u12,249 imm12: u12,
250 sh: u1 = 0,250 sh: u1 = 0,
251 },251 },
252 /// Two registers and a shift (shift type and 6-bit amount)
253 ///
254 /// Used by e.g. cmp_shifted_register
255 rr_imm6_shift: struct {
256 rn: Register,
257 rm: Register,
258 imm6: u6,
259 shift: bits.Instruction.AddSubtractShiftedRegisterShift,
260 },
252 /// Two registers and a shift (logical instruction version)261 /// Two registers and a shift (logical instruction version)
253 /// (shift type and 6-bit amount)262 /// (shift type and 6-bit amount)
254 ///263 ///
255 /// Used by e.g. mvn264 /// Used by e.g. mvn
256 rr_imm6_shift: struct {265 rr_imm6_logical_shift: struct {
257 rd: Register,266 rd: Register,
258 rm: Register,267 rm: Register,
259 imm6: u6,268 imm6: u6,
...@@ -287,7 +296,7 @@ pub const Inst = struct {...@@ -287,7 +296,7 @@ pub const Inst = struct {
287 },296 },
288 /// Three registers and a shift (shift type and 6-bit amount)297 /// Three registers and a shift (shift type and 6-bit amount)
289 ///298 ///
290 /// Used by e.g. cmp_shifted_register299 /// Used by e.g. add_shifted_register
291 rrr_imm6_shift: struct {300 rrr_imm6_shift: struct {
292 rd: Register,301 rd: Register,
293 rn: Register,302 rn: Register,
test/behavior/optional.zig+2
...@@ -33,6 +33,8 @@ test "optional pointer to size zero struct" {...@@ -33,6 +33,8 @@ test "optional pointer to size zero struct" {
33}33}
3434
35test "equality compare optional pointers" {35test "equality compare optional pointers" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
37
36 try testNullPtrsEql();38 try testNullPtrsEql();
37 comptime try testNullPtrsEql();39 comptime try testNullPtrsEql();
38}40}