mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
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:
parent
4e0779813b
commit
3051fab97c
@ -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)
|
||||
{
|
||||
|
||||
@ -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| {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user