Commit 3051fab97c

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-10-31 19:50:02
stage2 AArch64: misc fixes, enable printing in test runner
- Fixed missing airRetPtr implementation - Fixed wrong pop_regs order - Fixed wrong source and destination register in store
1 parent 4e07798
Changed files (3)
lib/test_runner.zig
@@ -130,6 +130,7 @@ pub fn main2() anyerror!void {
     }
     if (builtin.zig_backend == .stage2_wasm or
         builtin.zig_backend == .stage2_x86_64 or
+        builtin.zig_backend == .stage2_aarch64 or
         builtin.zig_backend == .stage2_llvm or
         builtin.zig_backend == .stage2_c)
     {
src/arch/aarch64/CodeGen.zig
@@ -1016,8 +1016,27 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
 }
 
 fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
-    const stack_offset = try self.allocMemPtr(inst);
-    return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
+    const result: MCValue = switch (self.ret_mcv) {
+        .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) },
+        .stack_offset => blk: {
+            // self.ret_mcv is an address to where this function
+            // should store its result into
+            const ret_ty = self.fn_type.fnReturnType();
+            var ptr_ty_payload: Type.Payload.ElemType = .{
+                .base = .{ .tag = .single_mut_pointer },
+                .data = ret_ty,
+            };
+            const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
+
+            // addr_reg will contain the address of where to store the
+            // result into
+            const addr_reg = try self.copyToTmpRegister(ptr_ty, self.ret_mcv);
+            break :blk .{ .register = addr_reg };
+        },
+        else => unreachable, // invalid return result
+    };
+
+    return self.finishAir(inst, result, .{ .none, .none, .none });
 }
 
 fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
@@ -3631,6 +3650,7 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type
 }
 
 fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
+    log.debug("store: storing {} to {}", .{ value, ptr });
     const abi_size = value_ty.abiSize(self.target.*);
 
     switch (ptr) {
@@ -3655,6 +3675,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                 .dead => unreachable,
                 .undef => unreachable,
                 .register => |value_reg| {
+                    log.debug("store: register {} to {}", .{ value_reg, addr_reg });
                     try self.genStrRegister(value_reg, addr_reg, value_ty);
                 },
                 else => {
@@ -3673,8 +3694,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                             self.register_manager.unlockReg(reg);
                         };
 
-                        const src_reg = addr_reg;
-                        const dst_reg = regs[0];
+                        const src_reg = regs[0];
+                        const dst_reg = addr_reg;
                         const len_reg = regs[1];
                         const count_reg = regs[2];
                         const tmp_reg = regs[3];
@@ -3684,7 +3705,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                                 // sub src_reg, fp, #off
                                 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
                             },
-                            .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
                             .stack_argument_offset => |off| {
                                 _ = try self.addInst(.{
                                     .tag = .ldr_ptr_stack_argument,
@@ -3694,6 +3714,24 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                                     } },
                                 });
                             },
+                            .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
+                            .linker_load => |load_struct| {
+                                const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
+                                    .got => .load_memory_ptr_got,
+                                    .direct => .load_memory_ptr_direct,
+                                };
+                                const mod = self.bin_file.options.module.?;
+                                _ = try self.addInst(.{
+                                    .tag = tag,
+                                    .data = .{
+                                        .payload = try self.addExtra(Mir.LoadMemoryPie{
+                                            .register = @enumToInt(src_reg),
+                                            .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
+                                            .sym_index = load_struct.sym_index,
+                                        }),
+                                    },
+                                });
+                            },
                             else => return self.fail("TODO store {} to register", .{value}),
                         }
 
@@ -4428,7 +4466,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
             if (else_value == .dead)
                 continue;
             // The instruction is only overridden in the else branch.
-            var i: usize = self.branch_stack.items.len - 2;
+            var i: usize = self.branch_stack.items.len - 1;
             while (true) {
                 i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?
                 if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| {
@@ -4455,7 +4493,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
         if (then_value == .dead)
             continue;
         const parent_mcv = blk: {
-            var i: usize = self.branch_stack.items.len - 2;
+            var i: usize = self.branch_stack.items.len - 1;
             while (true) {
                 i -= 1;
                 if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| {
src/arch/aarch64/Emit.zig
@@ -1191,42 +1191,50 @@ fn mirNop(emit: *Emit) !void {
     try emit.writeInstruction(Instruction.nop());
 }
 
+fn regListIsSet(reg_list: u32, reg: Register) bool {
+    return reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0;
+}
+
 fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
     const tag = emit.mir.instructions.items(.tag)[inst];
     const reg_list = emit.mir.instructions.items(.data)[inst].reg_list;
 
-    if (reg_list & @as(u32, 1) << 31 != 0) return emit.fail("xzr is not a valid register for {}", .{tag});
+    if (regListIsSet(reg_list, .xzr)) return emit.fail("xzr is not a valid register for {}", .{tag});
 
     // sp must be aligned at all times, so we only use stp and ldp
-    // instructions for minimal instruction count. However, if we do
-    // not have an even number of registers, we use str and ldr
+    // instructions for minimal instruction count.
+    //
+    // However, if we have an odd number of registers, for pop_regs we
+    // use one ldr instruction followed by zero or more ldp
+    // instructions; for push_regs we use zero or more stp
+    // instructions followed by one str instruction.
     const number_of_regs = @popCount(reg_list);
+    const odd_number_of_regs = number_of_regs % 2 != 0;
 
     switch (tag) {
         .pop_regs => {
             var i: u6 = 32;
             var count: u6 = 0;
-            var other_reg: Register = undefined;
+            var other_reg: ?Register = null;
             while (i > 0) : (i -= 1) {
                 const reg = @intToEnum(Register, i - 1);
-                if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) {
-                    if (count % 2 == 0) {
-                        if (count == number_of_regs - 1) {
-                            try emit.writeInstruction(Instruction.ldr(
-                                reg,
-                                .sp,
-                                Instruction.LoadStoreOffset.imm_post_index(16),
-                            ));
-                        } else {
-                            other_reg = reg;
-                        }
-                    } else {
+                if (regListIsSet(reg_list, reg)) {
+                    if (count == 0 and odd_number_of_regs) {
+                        try emit.writeInstruction(Instruction.ldr(
+                            reg,
+                            .sp,
+                            Instruction.LoadStoreOffset.imm_post_index(16),
+                        ));
+                    } else if (other_reg) |r| {
                         try emit.writeInstruction(Instruction.ldp(
                             reg,
-                            other_reg,
+                            r,
                             .sp,
                             Instruction.LoadStorePairOffset.post_index(16),
                         ));
+                        other_reg = null;
+                    } else {
+                        other_reg = reg;
                     }
                     count += 1;
                 }
@@ -1236,27 +1244,26 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
         .push_regs => {
             var i: u6 = 0;
             var count: u6 = 0;
-            var other_reg: Register = undefined;
+            var other_reg: ?Register = null;
             while (i < 32) : (i += 1) {
                 const reg = @intToEnum(Register, i);
-                if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) {
-                    if (count % 2 == 0) {
-                        if (count == number_of_regs - 1) {
-                            try emit.writeInstruction(Instruction.str(
-                                reg,
-                                .sp,
-                                Instruction.LoadStoreOffset.imm_pre_index(-16),
-                            ));
-                        } else {
-                            other_reg = reg;
-                        }
-                    } else {
+                if (regListIsSet(reg_list, reg)) {
+                    if (count == number_of_regs - 1 and odd_number_of_regs) {
+                        try emit.writeInstruction(Instruction.str(
+                            reg,
+                            .sp,
+                            Instruction.LoadStoreOffset.imm_pre_index(-16),
+                        ));
+                    } else if (other_reg) |r| {
                         try emit.writeInstruction(Instruction.stp(
-                            other_reg,
+                            r,
                             reg,
                             .sp,
                             Instruction.LoadStorePairOffset.pre_index(-16),
                         ));
+                        other_reg = null;
+                    } else {
+                        other_reg = reg;
                     }
                     count += 1;
                 }