| ... | ... | @@ -288,6 +288,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 288 | 288 | /// The key must be canonical register. |
| 289 | 289 | registers: std.AutoHashMapUnmanaged(Register, *ir.Inst) = .{}, |
| 290 | 290 | free_registers: FreeRegInt = math.maxInt(FreeRegInt), |
| 291 | /// Tracks all registers allocated in the course of this function |
| 292 | allocated_registers: FreeRegInt = 0, |
| 291 | 293 | /// Maps offset to what is stored there. |
| 292 | 294 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 293 | 295 | |
| ... | ... | @@ -384,7 +386,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 384 | 386 | const index = reg.allocIndex() orelse return; |
| 385 | 387 | const ShiftInt = math.Log2Int(FreeRegInt); |
| 386 | 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 | 394 | fn markRegFree(self: *Self, reg: Register) void { |
| ... | ... | @@ -402,7 +406,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 402 | 406 | if (free_index >= callee_preserved_regs.len) { |
| 403 | 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 | 412 | const reg = callee_preserved_regs[free_index]; |
| 407 | 413 | self.registers.putAssumeCapacityNoClobber(reg, inst); |
| 408 | 414 | log.debug("alloc {} => {*}", .{ reg, inst }); |
| ... | ... | @@ -586,20 +592,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 586 | 592 | // push {fp, lr} |
| 587 | 593 | // mov fp, sp |
| 588 | 594 | // 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()); |
| 593 | 598 | |
| 594 | 599 | try self.dbgSetPrologueEnd(); |
| 595 | 600 | |
| 596 | 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 | 618 | // Backpatch stack offset |
| 599 | 619 | const stack_end = self.max_end_stack; |
| 600 | 620 | const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); |
| 601 | 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 | 623 | } else { |
| 604 | 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 | 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 | 659 | // mov sp, fp |
| 636 | 660 | // pop {fp, pc} |
| 637 | 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 | 663 | } else { |
| 640 | 664 | try self.dbgSetPrologueEnd(); |
| 641 | 665 | try self.genBody(self.mod_fn.body); |