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 {...@@ -288,6 +288,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
288 /// The key must be canonical register.288 /// The key must be canonical register.
289 registers: std.AutoHashMapUnmanaged(Register, *ir.Inst) = .{},289 registers: std.AutoHashMapUnmanaged(Register, *ir.Inst) = .{},
290 free_registers: FreeRegInt = math.maxInt(FreeRegInt),290 free_registers: FreeRegInt = math.maxInt(FreeRegInt),
291 /// Tracks all registers allocated in the course of this function
292 allocated_registers: FreeRegInt = 0,
291 /// Maps offset to what is stored there.293 /// Maps offset to what is stored there.
292 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},294 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
293295
...@@ -384,7 +386,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -384,7 +386,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
384 const index = reg.allocIndex() orelse return;386 const index = reg.allocIndex() orelse return;
385 const ShiftInt = math.Log2Int(FreeRegInt);387 const ShiftInt = math.Log2Int(FreeRegInt);
386 const shift = @intCast(ShiftInt, index);388 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;
388 }392 }
389393
390 fn markRegFree(self: *Self, reg: Register) void {394 fn markRegFree(self: *Self, reg: Register) void {
...@@ -402,7 +406,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -402,7 +406,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
402 if (free_index >= callee_preserved_regs.len) {406 if (free_index >= callee_preserved_regs.len) {
403 return null;407 return null;
404 }408 }
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;
406 const reg = callee_preserved_regs[free_index];412 const reg = callee_preserved_regs[free_index];
407 self.registers.putAssumeCapacityNoClobber(reg, inst);413 self.registers.putAssumeCapacityNoClobber(reg, inst);
408 log.debug("alloc {} => {*}", .{ reg, inst });414 log.debug("alloc {} => {*}", .{ reg, inst });
...@@ -586,20 +592,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -586,20 +592,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
586 // push {fp, lr}592 // push {fp, lr}
587 // mov fp, sp593 // mov fp, sp
588 // sub sp, sp, #reloc594 // sub sp, sp, #reloc
589 writeInt(u32, try self.code.addManyAsArray(4), Instruction.push(.al, .{ .fp, .lr }).toU32());595 const prologue_reloc = self.code.items.len;
590 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32());596 try self.code.resize(prologue_reloc + 12);
591 const backpatch_reloc = self.code.items.len;597 writeInt(u32, self.code.items[prologue_reloc + 4 ..][0..4], Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32());
592 try self.code.resize(backpatch_reloc + 4);
593598
594 try self.dbgSetPrologueEnd();599 try self.dbgSetPrologueEnd();
595600
596 try self.genBody(self.mod_fn.body);601 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
598 // Backpatch stack offset618 // Backpatch stack offset
599 const stack_end = self.max_end_stack;619 const stack_end = self.max_end_stack;
600 const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);620 const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
601 if (Instruction.Operand.fromU32(@intCast(u32, aligned_stack_end))) |op| {621 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());
603 } else {623 } else {
604 return self.failSymbol("TODO ARM: allow larger stacks", .{});624 return self.failSymbol("TODO ARM: allow larger stacks", .{});
605 }625 }
...@@ -632,10 +652,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -632,10 +652,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
632 }652 }
633 }653 }
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
635 // mov sp, fp659 // mov sp, fp
636 // pop {fp, pc}660 // pop {fp, pc}
637 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());661 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());
639 } else {663 } else {
640 try self.dbgSetPrologueEnd();664 try self.dbgSetPrologueEnd();
641 try self.genBody(self.mod_fn.body);665 try self.genBody(self.mod_fn.body);