| ... | @@ -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) = .{}, |
| 293 | | 295 | |
| ... | @@ -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 | } |
| 389 | | 393 | |
| 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, sp | 593 | // mov fp, sp |
| 588 | // sub sp, sp, #reloc | 594 | // 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); | | |
| 593 | | 598 | |
| 594 | try self.dbgSetPrologueEnd(); | 599 | try self.dbgSetPrologueEnd(); |
| 595 | | 600 | |
| 596 | try self.genBody(self.mod_fn.body); | 601 | try self.genBody(self.mod_fn.body); |
| 597 | | 602 | |
| | 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 offset | 618 | // 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 | } |
| 634 | | 654 | |
| | 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, fp | 659 | // 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); |