Skip to content

Commit

Permalink
Enable save/restore generation when there is a gap between registers
Browse files Browse the repository at this point in the history
Enable save/restore generation when there is a gap between registers
by inserting the missing ones at the moment when spill slots for
callee-saved registers are assigned.
  • Loading branch information
Nikola Peric authored and Nikola Peric committed Dec 15, 2022
1 parent cf10d7e commit 1af2000
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 9 deletions.
43 changes: 34 additions & 9 deletions llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,22 +935,47 @@ bool MipsSEFrameLowering::assignCalleeSavedSpillSlots(
if (!STI.hasNanoMips())
return false;

static const std::unordered_map<unsigned, unsigned> Regs = {
{Mips::GP_NM, 0}, {Mips::FP_NM, 1}, {Mips::RA_NM, 2}, {Mips::S0_NM, 3},
{Mips::S1_NM, 4}, {Mips::S2_NM, 5}, {Mips::S3_NM, 6}, {Mips::S4_NM, 7},
{Mips::S5_NM, 8}, {Mips::S6_NM, 9}, {Mips::S7_NM, 10},
};

static const std::unordered_map<unsigned, unsigned> CSNumToReg = {
{0, Mips::GP_NM}, {1, Mips::FP_NM}, {2, Mips::RA_NM}, {3, Mips::S0_NM},
{4, Mips::S1_NM}, {5, Mips::S2_NM}, {6, Mips::S3_NM}, {7, Mips::S4_NM},
{8, Mips::S5_NM}, {9, Mips::S6_NM}, {10, Mips::S7_NM},
};

// nanoMIPS save and restore instructions require callee-saved registers to be
// saved in particular order on the stack.
auto SortCalleeSaves = [](CalleeSavedInfo First, CalleeSavedInfo Second) {
std::unordered_map<unsigned, unsigned> Regs{
{Mips::GP_NM, 0}, {Mips::FP_NM, 1}, {Mips::RA_NM, 2}, {Mips::S0_NM, 3},
{Mips::S1_NM, 4}, {Mips::S2_NM, 5}, {Mips::S3_NM, 6}, {Mips::S4_NM, 7},
{Mips::S5_NM, 8}, {Mips::S6_NM, 9}, {Mips::S7_NM, 10},
};

auto CompareCalleeSaves = [](CalleeSavedInfo First, CalleeSavedInfo Second) {
// There should be no callee-saved registers that are not part of the list.
assert(Regs.find(First.getReg()) != Regs.end() &&
Regs.find(Second.getReg()) != Regs.end());

return Regs[First.getReg()] < Regs[Second.getReg()];
return Regs.at(First.getReg()) < Regs.at(Second.getReg());
};
std::sort(CSI.begin(), CSI.end(), SortCalleeSaves);

// If CSI list has less than two callee-saved registers we can
// return from method since no insertions nor sorting is needed
if(CSI.size() < 2)
return false;

SmallBitVector CSNumBitVector(11);
for (CalleeSavedInfo &CS : CSI)
CSNumBitVector.set(Regs.at(CS.getReg()));

int MinCSNum = CSNumBitVector.find_first();
int MaxCSNum = CSNumBitVector.find_last();

// Inserting all of the missing callee-saved registers between min and max
// in order to allow further load-store optimizations
for (int i = MinCSNum + 1; i < MaxCSNum; ++i)
if (!CSNumBitVector.test(i))
CSI.push_back(CalleeSavedInfo(CSNumToReg.at(i)));

std::sort(CSI.begin(), CSI.end(), CompareCalleeSaves);
return false;
}

Expand Down
43 changes: 43 additions & 0 deletions llvm/test/CodeGen/Mips/nanomips/saverestore_with_register_gap.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
; RUN: llc -mtriple=nanomips -asm-show-inst -verify-machineinstrs < %s | FileCheck %s

; Make sure that SAVE/RESTORE instructions are working even though there
; is a gap in the callee-saved register sequence.
define void @test1() {
; CHECK: save 32, $s0, $s1, $s2, $s3, $s4
call void asm sideeffect "", "~{$16},~{$18},~{$20},~{$1}"() ret void
; CHECK: restore.jrc 32, $s0, $s1, $s2, $s3, $s4
}

define void @test2() {
; CHECK: save 48, $fp, $ra, $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7
call void asm sideeffect "", "~{$16},~{$23},~{$30},~{$1}"() ret void
; CHECK: restore.jrc 48, $fp, $ra, $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7
}

; Make sure to generate correct SAVE/RESTOR sp offset in case there was a gap
; in callee-saved register sequence and there are more things to be stored on
; stack after storing values from callee-saved registers. For example values
; from ax registers, used to pass function arguments, can be stored on stack
; after values from callee-saved registers.
define void @test3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {

%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca i32, align 4
%d.addr = alloca i32, align 4
%e.addr = alloca i32, align 4
%f.addr = alloca i32, align 4
%g.addr = alloca i32, align 4
%h.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
store i32 %c, i32* %c.addr, align 4
store i32 %d, i32* %d.addr, align 4
store i32 %e, i32* %e.addr, align 4
store i32 %f, i32* %f.addr, align 4
store i32 %g, i32* %g.addr, align 4
store i32 %h, i32* %h.addr, align 4
; CHECK: save 64, $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7
call void asm sideeffect "", "~{$16},~{$23},~{$1}"() ret void
; CHECK: restore.jrc 64, $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7
}

0 comments on commit 1af2000

Please sign in to comment.