diff options
| author | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-10-31 19:50:02 +0100 |
|---|---|---|
| committer | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-11-01 20:44:18 +0100 |
| commit | 3051fab97cbe89f3be8ec2aab36ca0e60fd953f9 (patch) | |
| tree | d8599199275f0e61944c94d9f55d37c3f183857d /src/arch/aarch64/Emit.zig | |
| parent | 4e0779813b5a25755f6a5f12e8ec05304abb2337 (diff) | |
| download | zig-3051fab97cbe89f3be8ec2aab36ca0e60fd953f9.tar.gz zig-3051fab97cbe89f3be8ec2aab36ca0e60fd953f9.zip | |
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
Diffstat (limited to 'src/arch/aarch64/Emit.zig')
| -rw-r--r-- | src/arch/aarch64/Emit.zig | 69 |
1 files changed, 38 insertions, 31 deletions
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; } |
