@@ -2929,6 +2929,7 @@ bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
29292929
29302930// Enum values indicating how an outlined call should be constructed.
29312931enum MachineOutlinerConstructionID {
2932+ MachineOutlinerTailCall,
29322933 MachineOutlinerDefault
29332934};
29342935
@@ -2937,19 +2938,47 @@ bool RISCVInstrInfo::shouldOutlineFromFunctionByDefault(
29372938 return MF.getFunction ().hasMinSize ();
29382939}
29392940
2941+ static bool IsCandidatePatchable (const MachineInstr &MI) {
2942+ const MachineBasicBlock *MBB = MI.getParent ();
2943+ const MachineFunction *MF = MBB->getParent ();
2944+ const Function &F = MF->getFunction ();
2945+ return F.getFnAttribute (" fentry-call" ).getValueAsBool () ||
2946+ F.hasFnAttribute (" patchable-function-entry" );
2947+ }
2948+
2949+ static bool CannotInsertTailCall (const MachineInstr &MI) {
2950+ if (MI.isTerminator ())
2951+ return IsCandidatePatchable (MI);
2952+ return true ;
2953+ }
2954+
2955+ static bool MIUseX5 (const MachineInstr &MI, const TargetRegisterInfo *TRI) {
2956+ return MI.modifiesRegister (RISCV::X5, TRI) ||
2957+ MI.getDesc ().hasImplicitDefOfPhysReg (RISCV::X5);
2958+ }
2959+
29402960std::optional<std::unique_ptr<outliner::OutlinedFunction>>
29412961RISCVInstrInfo::getOutliningCandidateInfo (
29422962 const MachineModuleInfo &MMI,
29432963 std::vector<outliner::Candidate> &RepeatedSequenceLocs,
29442964 unsigned MinRepeats) const {
29452965
2946- // First we need to filter out candidates where the X5 register (IE t0) can't
2947- // be used to setup the function call.
2948- auto CannotInsertCall = [](outliner::Candidate &C) {
2966+ auto CandidateUseX5 = [](outliner::Candidate &C) {
29492967 const TargetRegisterInfo *TRI = C.getMF ()->getSubtarget ().getRegisterInfo ();
2968+ for (const MachineInstr &MI : C)
2969+ if (MIUseX5 (MI, TRI))
2970+ return true ;
29502971 return !C.isAvailableAcrossAndOutOfSeq (RISCV::X5, *TRI);
29512972 };
29522973
2974+ auto CannotInsertCall = [CandidateUseX5](outliner::Candidate &C) {
2975+ if (!CandidateUseX5 (C))
2976+ return false ;
2977+ if (!CannotInsertTailCall (C.back ()))
2978+ return false ;
2979+ return true ;
2980+ };
2981+
29532982 llvm::erase_if (RepeatedSequenceLocs, CannotInsertCall);
29542983
29552984 // If the sequence doesn't have enough candidates left, then we're done.
@@ -2961,6 +2990,17 @@ RISCVInstrInfo::getOutliningCandidateInfo(
29612990 for (auto &MI : RepeatedSequenceLocs[0 ])
29622991 SequenceSize += getInstSizeInBytes (MI);
29632992
2993+ if (!CannotInsertTailCall (RepeatedSequenceLocs[0 ].back ())) {
2994+ // tail function = 8 bytes. Can't be compressed
2995+ for (auto &C : RepeatedSequenceLocs)
2996+ C.setCallInfo (MachineOutlinerTailCall, 8 );
2997+
2998+ // Using tail call we move ret instrunction from caller to calee.
2999+ // So, FrameOverhead for this is 0
3000+ return std::make_unique<outliner::OutlinedFunction>(
3001+ RepeatedSequenceLocs, SequenceSize, 0 , MachineOutlinerTailCall);
3002+ }
3003+
29643004 // call t0, function = 8 bytes.
29653005 unsigned CallOverhead = 8 ;
29663006 for (auto &C : RepeatedSequenceLocs)
@@ -2997,15 +3037,7 @@ RISCVInstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
29973037 return F.needsUnwindTableEntry () ? outliner::InstrType::Illegal
29983038 : outliner::InstrType::Invisible;
29993039
3000- // We need support for tail calls to outlined functions before return
3001- // statements can be allowed.
3002- if (MI.isReturn ())
3003- return outliner::InstrType::Illegal;
3004-
3005- // Don't allow modifying the X5 register which we use for return addresses for
3006- // these outlined functions.
3007- if (MI.modifiesRegister (RISCV::X5, TRI) ||
3008- MI.getDesc ().hasImplicitDefOfPhysReg (RISCV::X5))
3040+ if (CannotInsertTailCall (MBB->back ()) && MIUseX5 (MI, TRI))
30093041 return outliner::InstrType::Illegal;
30103042
30113043 // Make sure the operands don't reference something unsafe.
@@ -3041,19 +3073,29 @@ void RISCVInstrInfo::buildOutlinedFrame(
30413073 }
30423074 }
30433075
3076+ if (OF.FrameConstructionID == MachineOutlinerTailCall)
3077+ return ;
3078+
30443079 MBB.addLiveIn (RISCV::X5);
30453080
30463081 // Add in a return instruction to the end of the outlined frame.
30473082 MBB.insert (MBB.end (), BuildMI (MF, DebugLoc (), get (RISCV::JALR))
3048- .addReg (RISCV::X0, RegState::Define)
3049- .addReg (RISCV::X5)
3050- .addImm (0 ));
3083+ .addReg (RISCV::X0, RegState::Define)
3084+ .addReg (RISCV::X5)
3085+ .addImm (0 ));
30513086}
30523087
30533088MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall (
30543089 Module &M, MachineBasicBlock &MBB, MachineBasicBlock::iterator &It,
30553090 MachineFunction &MF, outliner::Candidate &C) const {
30563091
3092+ if (C.CallConstructionID == MachineOutlinerTailCall) {
3093+ It = MBB.insert (It, BuildMI (MF, DebugLoc (), get (RISCV::PseudoTAIL))
3094+ .addGlobalAddress (M.getNamedValue (MF.getName ()),
3095+ /* Offset=*/ 0 , RISCVII::MO_CALL));
3096+ return It;
3097+ }
3098+
30573099 // Add in a call instruction to the outlined function at the given location.
30583100 It = MBB.insert (It,
30593101 BuildMI (MF, DebugLoc (), get (RISCV::PseudoCALLReg), RISCV::X5)
0 commit comments