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) {
115115 /// A pointer-sized integer that fits in a register.
116116 /// If the type is a pointer, this is the pointer address in virtual address space.
117117 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,
123118 /// The value is in a target-specific register.
124119 register: Register,
125120 /// The value is in memory at a hard-coded address.
......@@ -147,7 +142,7 @@ const MCValue = union(enum) {
147142
148143 fn isMemory(mcv: MCValue) bool {
149144 return switch (mcv) {
150 .embedded_in_code, .memory, .stack_offset => true,
145 .memory, .stack_offset => true,
151146 else => false,
152147 };
153148 }
......@@ -166,12 +161,10 @@ const MCValue = union(enum) {
166161 .dead => unreachable,
167162
168163 .immediate,
169 .embedded_in_code,
170164 .memory,
171165 .compare_flags_unsigned,
172166 .compare_flags_signed,
173167 .ptr_stack_offset,
174 .ptr_embedded_in_code,
175168 .undef,
176169 => false,
177170
......@@ -816,10 +809,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
816809 if (abi_align > self.stack_align)
817810 self.stack_align = abi_align;
818811 // 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);
823815 try self.stack.putNoClobber(self.gpa, offset, .{
824816 .inst = inst,
825817 .size = abi_size,
......@@ -832,9 +824,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
832824 const elem_ty = self.air.typeOfIndex(inst).elemType();
833825
834826 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);
838831 }
839832
840833 const target = self.target.*;
......@@ -1058,7 +1051,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
10581051
10591052 _ = try self.addInst(.{
10601053 .tag = .mvn,
1061 .data = .{ .rr_imm6_shift = .{
1054 .data = .{ .rr_imm6_logical_shift = .{
10621055 .rd = dest_reg,
10631056 .rm = op_reg,
10641057 .imm6 = 0,
......@@ -1104,8 +1097,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
11041097 const ptr_bytes = @divExact(ptr_bits, 8);
11051098
11061099 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);
11091102 break :result MCValue{ .stack_offset = stack_offset };
11101103 };
11111104 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -1188,6 +1181,7 @@ fn binOpRegister(
11881181 .sub,
11891182 .ptr_sub,
11901183 => .sub_shifted_register,
1184 .cmp_eq => .cmp_shifted_register,
11911185 .mul => .mul,
11921186 .bit_and,
11931187 .bool_and,
......@@ -1219,6 +1213,12 @@ fn binOpRegister(
12191213 .imm6 = 0,
12201214 .shift = .lsl,
12211215 } },
1216 .cmp_eq => .{ .rr_imm6_shift = .{
1217 .rn = lhs_reg,
1218 .rm = rhs_reg,
1219 .imm6 = 0,
1220 .shift = .lsl,
1221 } },
12221222 .mul,
12231223 .shl,
12241224 .shl_exact,
......@@ -1296,20 +1296,23 @@ fn binOpImmediate(
12961296 };
12971297 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
12981298
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;
13011303
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 };
13131316
13141317 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
13151318
......@@ -1325,6 +1328,7 @@ fn binOpImmediate(
13251328 .signed => Mir.Inst.Tag.asr_immediate,
13261329 .unsigned => Mir.Inst.Tag.lsr_immediate,
13271330 },
1331 .cmp_eq => .cmp_immediate,
13281332 else => unreachable,
13291333 };
13301334 const mir_data: Mir.Inst.Data = switch (tag) {
......@@ -1344,6 +1348,10 @@ fn binOpImmediate(
13441348 .rn = lhs_reg,
13451349 .shift = @intCast(u6, rhs.immediate),
13461350 } },
1351 .cmp_eq => .{ .r_imm12_sh = .{
1352 .rn = lhs_reg,
1353 .imm12 = @intCast(u12, rhs.immediate),
1354 } },
13471355 else => unreachable,
13481356 };
13491357
......@@ -1381,6 +1389,7 @@ fn binOp(
13811389 // Arithmetic operations on integers and floats
13821390 .add,
13831391 .sub,
1392 .cmp_eq,
13841393 => {
13851394 switch (lhs_ty.zigTypeTag()) {
13861395 .Float => return self.fail("TODO binary operations on floats", .{}),
......@@ -1394,12 +1403,13 @@ fn binOp(
13941403 // operands
13951404 const lhs_immediate_ok = switch (tag) {
13961405 .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12),
1397 .sub => false,
1406 .sub, .cmp_eq => false,
13981407 else => unreachable,
13991408 };
14001409 const rhs_immediate_ok = switch (tag) {
14011410 .add,
14021411 .sub,
1412 .cmp_eq,
14031413 => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12),
14041414 else => unreachable,
14051415 };
......@@ -1505,7 +1515,13 @@ fn binOp(
15051515 const elem_size = elem_ty.abiSize(self.target.*);
15061516
15071517 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);
15091525 } else {
15101526 // convert the offset into a byte offset by
15111527 // multiplying it with elem_size
......@@ -1714,14 +1730,12 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
17141730fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
17151731 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
17161732 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);
17191733 const mcv = try self.resolveInst(ty_op.operand);
17201734 switch (mcv) {
17211735 .dead, .unreach, .none => unreachable,
17221736 .register => unreachable, // a slice doesn't fit in one register
17231737 .stack_offset => |off| {
1724 break :result MCValue{ .stack_offset = off + ptr_bytes };
1738 break :result MCValue{ .stack_offset = off };
17251739 },
17261740 .memory => |addr| {
17271741 break :result MCValue{ .memory = addr };
......@@ -1742,7 +1756,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
17421756 .dead, .unreach, .none => unreachable,
17431757 .register => unreachable, // a slice doesn't fit in one register
17441758 .stack_offset => |off| {
1745 break :result MCValue{ .stack_offset = off };
1759 break :result MCValue{ .stack_offset = off - ptr_bytes };
17461760 },
17471761 .memory => |addr| {
17481762 break :result MCValue{ .memory = addr + ptr_bytes };
......@@ -1762,7 +1776,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
17621776 switch (mcv) {
17631777 .dead, .unreach, .none => unreachable,
17641778 .ptr_stack_offset => |off| {
1765 break :result MCValue{ .ptr_stack_offset = off + ptr_bytes };
1779 break :result MCValue{ .ptr_stack_offset = off - ptr_bytes };
17661780 },
17671781 else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}),
17681782 }
......@@ -1809,7 +1823,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
18091823 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});
18101824
18111825 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 }) },
18131827 else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}),
18141828 };
18151829 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
19491963 .compare_flags_signed => unreachable,
19501964 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
19511965 .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 },
19581966 .register => |addr_reg| {
19591967 self.register_manager.freezeRegs(&.{addr_reg});
19601968 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
19631971 .dead => unreachable,
19641972 .undef => unreachable,
19651973 .compare_flags_signed, .compare_flags_unsigned => unreachable,
1966 .embedded_in_code => unreachable,
19671974 .register => |dst_reg| {
19681975 try self.genLdrRegister(dst_reg, addr_reg, elem_size);
19691976 },
......@@ -2036,8 +2043,7 @@ fn genInlineMemcpy(
20362043 // cmp count, len
20372044 _ = try self.addInst(.{
20382045 .tag = .cmp_shifted_register,
2039 .data = .{ .rrr_imm6_shift = .{
2040 .rd = .xzr,
2046 .data = .{ .rr_imm6_shift = .{
20412047 .rn = count,
20422048 .rm = len,
20432049 .imm6 = 0,
......@@ -2227,12 +2233,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
22272233 .ptr_stack_offset => |off| {
22282234 try self.genSetStack(value_ty, off, value);
22292235 },
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 },
22362236 .register => |addr_reg| {
22372237 self.register_manager.freezeRegs(&.{addr_reg});
22382238 defer self.register_manager.unfreezeRegs(&.{addr_reg});
......@@ -2297,13 +2297,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
22972297 const mcv = try self.resolveInst(operand);
22982298 const ptr_ty = self.air.typeOf(operand);
22992299 const struct_ty = ptr_ty.childType();
2300 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
23012300 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.*));
23042301 switch (mcv) {
23052302 .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 };
23072304 },
23082305 else => {
23092306 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
......@@ -2445,7 +2442,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
24452442 .immediate => unreachable,
24462443 .unreach => unreachable,
24472444 .dead => unreachable,
2448 .embedded_in_code => unreachable,
24492445 .memory => unreachable,
24502446 .compare_flags_signed => unreachable,
24512447 .compare_flags_unsigned => unreachable,
......@@ -2461,9 +2457,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
24612457 .ptr_stack_offset => {
24622458 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
24632459 },
2464 .ptr_embedded_in_code => {
2465 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2466 },
24672460 }
24682461 }
24692462
......@@ -2615,107 +2608,48 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
26152608
26162609fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
26172610 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,
26482637 };
26492638
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);
26542642
2655 var lhs_mcv = lhs;
2656 var rhs_mcv = rhs;
2643 try self.spillCompareFlagsIfOccupied();
2644 self.compare_flags_inst = inst;
26572645
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 };
26712650 } 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", .{});
26862652 }
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 };
27192653 };
27202654 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
27212655}
......@@ -3384,18 +3318,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
33843318 .compare_flags_signed,
33853319 .immediate,
33863320 .ptr_stack_offset,
3387 .ptr_embedded_in_code,
33883321 => {
33893322 const reg = try self.copyToTmpRegister(ty, mcv);
33903323 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
33913324 },
3392 .embedded_in_code => |code_offset| {
3393 _ = code_offset;
3394 return self.fail("TODO implement set stack variable from embedded_in_code", .{});
3395 },
33963325 .register => |reg| {
3397 const adj_off = stack_offset + abi_size;
3398
33993326 switch (abi_size) {
34003327 1, 2, 4, 8 => {
34013328 const tag: Mir.Inst.Tag = switch (abi_size) {
......@@ -3410,7 +3337,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
34103337 .tag = tag,
34113338 .data = .{ .load_store_stack = .{
34123339 .rt = rt,
3413 .offset = @intCast(u32, adj_off),
3340 .offset = @intCast(u32, stack_offset),
34143341 } },
34153342 });
34163343 },
......@@ -3495,7 +3422,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
34953422fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
34963423 switch (mcv) {
34973424 .dead => unreachable,
3498 .ptr_embedded_in_code => unreachable,
34993425 .unreach, .none => return, // Nothing to do.
35003426 .undef => {
35013427 if (!self.wantSafety())
......@@ -3507,13 +3433,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
35073433 else => unreachable, // unexpected register size
35083434 }
35093435 },
3510 .ptr_stack_offset => |unadjusted_off| {
3436 .ptr_stack_offset => |off| {
35113437 // 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
35173439 return self.fail("TODO larger stack offsets", .{});
35183440
35193441 _ = try self.addInst(.{
......@@ -3603,9 +3525,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
36033525 try self.genSetReg(ty, reg, .{ .immediate = addr });
36043526 try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*));
36053527 },
3606 .stack_offset => |unadjusted_off| {
3528 .stack_offset => |off| {
36073529 const abi_size = ty.abiSize(self.target.*);
3608 const adj_off = unadjusted_off + abi_size;
36093530
36103531 switch (abi_size) {
36113532 1, 2, 4, 8 => {
......@@ -3625,7 +3546,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
36253546 .tag = tag,
36263547 .data = .{ .load_store_stack = .{
36273548 .rt = rt,
3628 .offset = @intCast(u32, adj_off),
3549 .offset = @intCast(u32, off),
36293550 } },
36303551 });
36313552 },
......@@ -3633,7 +3554,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
36333554 else => unreachable,
36343555 }
36353556 },
3636 else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}),
36373557 }
36383558}
36393559
......@@ -3661,8 +3581,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
36613581 const ptr_bytes = @divExact(ptr_bits, 8);
36623582
36633583 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 });
36663586 break :result MCValue{ .stack_offset = stack_offset };
36673587 };
36683588 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 {
650650
651651fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
652652 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
660653 switch (tag) {
661 .add_shifted_register => try emit.writeInstruction(Instruction.addShiftedRegister(rd, rn, rm, shift, imm6)),
662 .cmp_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(rd, rn, rm, shift, imm6)),
663 .sub_shifted_register => try emit.writeInstruction(Instruction.subShiftedRegister(rd, rn, rm, shift, imm6)),
654 .add_shifted_register,
655 .sub_shifted_register,
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 },
664679 else => unreachable,
665680 }
666681}
......@@ -896,8 +911,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
896911 try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false));
897912 },
898913 .mvn => {
899 const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift;
900 try emit.writeInstruction(Instruction.ornShiftedRegister(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, rr_imm6_shift.shift, rr_imm6_shift.imm6));
914 const rr_imm6_logical_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_logical_shift;
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));
901921 },
902922 else => unreachable,
903923 }
src/arch/aarch64/Mir.zig+11-2
......@@ -249,11 +249,20 @@ pub const Inst = struct {
249249 imm12: u12,
250250 sh: u1 = 0,
251251 },
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 },
252261 /// Two registers and a shift (logical instruction version)
253262 /// (shift type and 6-bit amount)
254263 ///
255264 /// Used by e.g. mvn
256 rr_imm6_shift: struct {
265 rr_imm6_logical_shift: struct {
257266 rd: Register,
258267 rm: Register,
259268 imm6: u6,
......@@ -287,7 +296,7 @@ pub const Inst = struct {
287296 },
288297 /// Three registers and a shift (shift type and 6-bit amount)
289298 ///
290 /// Used by e.g. cmp_shifted_register
299 /// Used by e.g. add_shifted_register
291300 rrr_imm6_shift: struct {
292301 rd: Register,
293302 rn: Register,
test/behavior/optional.zig+2
......@@ -33,6 +33,8 @@ test "optional pointer to size zero struct" {
3333}
3434
3535test "equality compare optional pointers" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
37
3638 try testNullPtrsEql();
3739 comptime try testNullPtrsEql();
3840}