From 3051fab97cbe89f3be8ec2aab36ca0e60fd953f9 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Mon, 31 Oct 2022 19:50:02 +0100 Subject: [PATCH] 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 --- lib/test_runner.zig | 1 + src/arch/aarch64/CodeGen.zig | 52 +++++++++++++++++++++++---- src/arch/aarch64/Emit.zig | 69 ++++++++++++++++++++---------------- 3 files changed, 84 insertions(+), 38 deletions(-) diff --git a/lib/test_runner.zig b/lib/test_runner.zig index 83ac378daf..7c3d4d493f 100644 --- a/lib/test_runner.zig +++ b/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) { diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index bf79ecf29e..d9f94fdc71 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/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| { diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index d9f10d5103..8794890e9e 100644 --- a/src/arch/aarch64/Emit.zig +++ b/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; }