Commit 3051fab97c
Changed files (3)
src
arch
aarch64
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;
}