authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-02-19 10:23:36+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-25 22:27:19+02:00
log297eabd4accbcae42bfe821078a79e4af06a2dde
tree93aef82dce14373b5f0ff6ebb055acebec73d728
parent3c0238e731d3ec0514dc4a563817d6a27fed272e

stage2 ARM: Save callee-saved registers

Add a new allocated_registers bitmap to keep track of all callee-saved registers allocated during generation of this function. Function(.arm).gen uses this data to generate instructions in the function prologue and epilogue to push and pop these registers respectively.

1 files changed, 32 insertions(+), 8 deletions(-)

src/codegen.zig+32-8
......@@ -288,6 +288,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
288288 /// The key must be canonical register.
289289 registers: std.AutoHashMapUnmanaged(Register, *ir.Inst) = .{},
290290 free_registers: FreeRegInt = math.maxInt(FreeRegInt),
291 /// Tracks all registers allocated in the course of this function
292 allocated_registers: FreeRegInt = 0,
291293 /// Maps offset to what is stored there.
292294 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
293295
......@@ -384,7 +386,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
384386 const index = reg.allocIndex() orelse return;
385387 const ShiftInt = math.Log2Int(FreeRegInt);
386388 const shift = @intCast(ShiftInt, index);
387 self.free_registers &= ~(@as(FreeRegInt, 1) << shift);
389 const mask = @as(FreeRegInt, 1) << shift;
390 self.free_registers &= ~mask;
391 self.allocated_registers |= mask;
388392 }
389393
390394 fn markRegFree(self: *Self, reg: Register) void {
......@@ -402,7 +406,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
402406 if (free_index >= callee_preserved_regs.len) {
403407 return null;
404408 }
405 self.free_registers &= ~(@as(FreeRegInt, 1) << free_index);
409 const mask = @as(FreeRegInt, 1) << free_index;
410 self.free_registers &= ~mask;
411 self.allocated_registers |= mask;
406412 const reg = callee_preserved_regs[free_index];
407413 self.registers.putAssumeCapacityNoClobber(reg, inst);
408414 log.debug("alloc {} => {*}", .{ reg, inst });
......@@ -586,20 +592,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
586592 // push {fp, lr}
587593 // mov fp, sp
588594 // sub sp, sp, #reloc
589 writeInt(u32, try self.code.addManyAsArray(4), Instruction.push(.al, .{ .fp, .lr }).toU32());
590 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32());
591 const backpatch_reloc = self.code.items.len;
592 try self.code.resize(backpatch_reloc + 4);
595 const prologue_reloc = self.code.items.len;
596 try self.code.resize(prologue_reloc + 12);
597 writeInt(u32, self.code.items[prologue_reloc + 4 ..][0..4], Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32());
593598
594599 try self.dbgSetPrologueEnd();
595600
596601 try self.genBody(self.mod_fn.body);
597602
603 // Backpatch push callee saved regs
604 var saved_regs = Instruction.RegisterList{
605 .r11 = true, // fp
606 .r14 = true, // lr
607 };
608 inline for (callee_preserved_regs) |reg, i| {
609 const ShiftInt = math.Log2Int(FreeRegInt);
610 const shift = @intCast(ShiftInt, i);
611 const mask = @as(FreeRegInt, 1) << shift;
612 if (self.allocated_registers & mask != 0) {
613 @field(saved_regs, @tagName(reg)) = true;
614 }
615 }
616 writeInt(u32, self.code.items[prologue_reloc..][0..4], Instruction.stmdb(.al, .sp, true, saved_regs).toU32());
617
598618 // Backpatch stack offset
599619 const stack_end = self.max_end_stack;
600620 const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
601621 if (Instruction.Operand.fromU32(@intCast(u32, aligned_stack_end))) |op| {
602 writeInt(u32, self.code.items[backpatch_reloc..][0..4], Instruction.sub(.al, .sp, .sp, op).toU32());
622 writeInt(u32, self.code.items[prologue_reloc + 8 ..][0..4], Instruction.sub(.al, .sp, .sp, op).toU32());
603623 } else {
604624 return self.failSymbol("TODO ARM: allow larger stacks", .{});
605625 }
......@@ -632,10 +652,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
632652 }
633653 }
634654
655 // Epilogue: pop callee saved registers (swap lr with pc in saved_regs)
656 saved_regs.r14 = false; // lr
657 saved_regs.r15 = true; // pc
658
635659 // mov sp, fp
636660 // pop {fp, pc}
637661 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
638 writeInt(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
662 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldm(.al, .sp, true, saved_regs).toU32());
639663 } else {
640664 try self.dbgSetPrologueEnd();
641665 try self.genBody(self.mod_fn.body);