diff --git a/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp b/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp index 56e27f7e71e947..cc8bf9fcc66e0b 100644 --- a/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp +++ b/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -935,22 +935,47 @@ bool MipsSEFrameLowering::assignCalleeSavedSpillSlots( if (!STI.hasNanoMips()) return false; + static const std::unordered_map 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 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 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; } diff --git a/llvm/test/CodeGen/Mips/nanomips/saverestore_with_register_gap.ll b/llvm/test/CodeGen/Mips/nanomips/saverestore_with_register_gap.ll new file mode 100644 index 00000000000000..01bc748e918ddf --- /dev/null +++ b/llvm/test/CodeGen/Mips/nanomips/saverestore_with_register_gap.ll @@ -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 +} \ No newline at end of file