Index: llvm/lib/Target/Sparc/SparcFrameLowering.h =================================================================== --- llvm/lib/Target/Sparc/SparcFrameLowering.h +++ llvm/lib/Target/Sparc/SparcFrameLowering.h @@ -49,7 +49,7 @@ private: // Remap input registers to output registers for leaf procedure. - void remapRegsForLeafProc(MachineFunction &MF) const; + bool remapRegsForLeafProc(MachineFunction &MF) const; // Returns true if MF is a leaf procedure. bool isLeafProc(MachineFunction &MF) const; Index: llvm/lib/Target/Sparc/SparcFrameLowering.cpp =================================================================== --- llvm/lib/Target/Sparc/SparcFrameLowering.cpp +++ llvm/lib/Target/Sparc/SparcFrameLowering.cpp @@ -322,40 +322,58 @@ || hasFP(MF)); // need %fp } -void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const { +bool SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const { MachineRegisterInfo &MRI = MF.getRegInfo(); + + // Registers to remap. + const Register InRegs[7] = { + SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5, SP::I7, + }; + + auto PairReg = [](Register R) -> Register { + return (R - SP::I0) / 2 + SP::I0_I1; + }; + auto OutReg = [](Register R, bool Pair = false) -> Register { + if (Pair) + return (R - SP::I0) / 2 + SP::O0_O1; + return R - SP::I0 + SP::O0; + }; + + // Remap every use of %iN to %oN, but only if the destination register is + // free. We could handle that case by remapping the occupied output registers + // into some free %gN ones, but here we simply give up instead. + for (Register Reg : InRegs) { + if (MRI.isPhysRegUsed(Reg) && MRI.isPhysRegUsed(OutReg(Reg))) + return false; + } + // Remap %i[0-7] to %o[0-7]. - for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) { - if (!MRI.isPhysRegUsed(reg)) + for (Register Reg : InRegs) { + if (!MRI.isPhysRegUsed(Reg)) continue; - unsigned mapped_reg = reg - SP::I0 + SP::O0; - // Replace I register with O register. - MRI.replaceRegWith(reg, mapped_reg); + MRI.replaceRegWith(Reg, OutReg(Reg)); // Also replace register pair super-registers. - if ((reg - SP::I0) % 2 == 0) { - unsigned preg = (reg - SP::I0) / 2 + SP::I0_I1; - unsigned mapped_preg = preg - SP::I0_I1 + SP::O0_O1; - MRI.replaceRegWith(preg, mapped_preg); + if ((Reg - SP::I0) % 2 == 0) { + MRI.replaceRegWith(PairReg(Reg), OutReg(Reg, true)); } } // Rewrite MBB's Live-ins. - for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); - MBB != E; ++MBB) { - for (unsigned reg = SP::I0_I1; reg <= SP::I6_I7; ++reg) { - if (!MBB->isLiveIn(reg)) + for (MachineBasicBlock &MBB : MF) { + for (unsigned Reg = SP::I0_I1; Reg <= SP::I6_I7; ++Reg) { + if (!MBB.isLiveIn(Reg)) continue; - MBB->removeLiveIn(reg); - MBB->addLiveIn(reg - SP::I0_I1 + SP::O0_O1); + MBB.removeLiveIn(Reg); + MBB.addLiveIn(OutReg(Reg, true)); } - for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) { - if (!MBB->isLiveIn(reg)) + for (unsigned Reg = SP::I0; Reg <= SP::I7; ++Reg) { + if (!MBB.isLiveIn(Reg)) continue; - MBB->removeLiveIn(reg); - MBB->addLiveIn(reg - SP::I0 + SP::O0); + MBB.removeLiveIn(Reg); + MBB.addLiveIn(OutReg(Reg)); } } @@ -363,6 +381,8 @@ #ifdef EXPENSIVE_CHECKS MF.verify(0, "After LeafProc Remapping"); #endif + + return true; } void SparcFrameLowering::determineCalleeSaves(MachineFunction &MF, @@ -370,10 +390,9 @@ RegScavenger *RS) const { TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); if (!DisableLeafProc && isLeafProc(MF)) { - SparcMachineFunctionInfo *MFI = MF.getInfo(); - MFI->setLeafProc(true); - - remapRegsForLeafProc(MF); + if (remapRegsForLeafProc(MF)) { + SparcMachineFunctionInfo *MFI = MF.getInfo(); + MFI->setLeafProc(true); + } } - } Index: llvm/test/CodeGen/SPARC/leafproc.ll =================================================================== --- llvm/test/CodeGen/SPARC/leafproc.ll +++ llvm/test/CodeGen/SPARC/leafproc.ll @@ -78,3 +78,26 @@ %4 = load i32, i32* %3, align 4 ret i32 %4 } + +; Here we have a leaf function where all the in and out registers are used and +; where the register allocator is loading the sixth argument into %o5, making +; the register renumbering fail. +; As a result the function is not marked as being a leaf one. + +; CHECK-LABEL: leaf_proc_give_up +; CHECK: save %sp, -96, %sp +; CHECK: ld [%fp+92], %o5 +; CHECK: mov %i0, %g1 +; CHECK: mov %i1, %o0 +; CHECK: mov %i2, %o1 +; CHECK: mov %i3, %o2 +; CHECK: mov %i4, %o3 +; CHECK: mov %i5, %o4 +; CHECK: ret +; CHECK-NEXT: restore %g0, %o0, %o0 + +define i32 @leaf_proc_give_up(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) { +Entry: + %g = call i32 asm sideeffect "", "={o0},{g1},{o0},{o1},{o2},{o3},{o4},{o5}"(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) + ret i32 %g +}