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
This commit is contained in:
joachimschmidt557 2022-10-31 19:50:02 +01:00
parent 4e0779813b
commit 3051fab97c
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
3 changed files with 84 additions and 38 deletions

View File

@ -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)
{

View File

@ -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| {

View File

@ -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;
}