aboutsummaryrefslogtreecommitdiff
path: root/src/arch/aarch64/Emit.zig
diff options
context:
space:
mode:
authorjoachimschmidt557 <joachim.schmidt557@outlook.com>2022-10-31 19:50:02 +0100
committerjoachimschmidt557 <joachim.schmidt557@outlook.com>2022-11-01 20:44:18 +0100
commit3051fab97cbe89f3be8ec2aab36ca0e60fd953f9 (patch)
treed8599199275f0e61944c94d9f55d37c3f183857d /src/arch/aarch64/Emit.zig
parent4e0779813b5a25755f6a5f12e8ec05304abb2337 (diff)
downloadzig-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.zig69
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;
}