1111// ===----------------------------------------------------------------------===//
1212
1313#include " RISCVInstrInfo.h"
14+ #include " MCTargetDesc/RISCVBaseInfo.h"
1415#include " MCTargetDesc/RISCVMatInt.h"
1516#include " RISCV.h"
1617#include " RISCVMachineFunctionInfo.h"
@@ -2927,6 +2928,7 @@ bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
29272928
29282929// Enum values indicating how an outlined call should be constructed.
29292930enum MachineOutlinerConstructionID {
2931+ MachineOutlinerTailCall,
29302932 MachineOutlinerDefault
29312933};
29322934
@@ -2935,46 +2937,118 @@ bool RISCVInstrInfo::shouldOutlineFromFunctionByDefault(
29352937 return MF.getFunction ().hasMinSize ();
29362938}
29372939
2940+ static bool isCandidatePatchable (const MachineBasicBlock &MBB) {
2941+ const MachineFunction *MF = MBB.getParent ();
2942+ const Function &F = MF->getFunction ();
2943+ return F.getFnAttribute (" fentry-call" ).getValueAsBool () ||
2944+ F.hasFnAttribute (" patchable-function-entry" );
2945+ }
2946+
2947+ static bool isMIReadsReg (const MachineInstr &MI, const TargetRegisterInfo *TRI,
2948+ unsigned RegNo) {
2949+ return MI.readsRegister (RegNo, TRI) ||
2950+ MI.getDesc ().hasImplicitUseOfPhysReg (RegNo);
2951+ }
2952+
2953+ static bool isMIModifiesReg (const MachineInstr &MI,
2954+ const TargetRegisterInfo *TRI, unsigned RegNo) {
2955+ return MI.modifiesRegister (RegNo, TRI) ||
2956+ MI.getDesc ().hasImplicitDefOfPhysReg (RegNo);
2957+ }
2958+
2959+ static bool cannotInsertTailCall (const MachineBasicBlock &MBB) {
2960+ if (!MBB.back ().isReturn ())
2961+ return true ;
2962+ if (isCandidatePatchable (MBB))
2963+ return true ;
2964+
2965+ // If the candidate reads the pre-set register
2966+ // that can be used for expanding PseudoTAIL instruction,
2967+ // then we cannot insert tail call.
2968+ const TargetSubtargetInfo &STI = MBB.getParent ()->getSubtarget ();
2969+ unsigned TailExpandUseRegNo =
2970+ RISCVII::getTailExpandUseRegNo (STI.getFeatureBits ());
2971+ for (const MachineInstr &MI : MBB) {
2972+ if (isMIReadsReg (MI, STI.getRegisterInfo (), TailExpandUseRegNo))
2973+ return true ;
2974+ if (isMIModifiesReg (MI, STI.getRegisterInfo (), TailExpandUseRegNo))
2975+ break ;
2976+ }
2977+ return false ;
2978+ }
2979+
2980+ static std::optional<MachineOutlinerConstructionID>
2981+ analyzeCandidate (outliner::Candidate &C) {
2982+ // If last instruction is return then we can rely on
2983+ // the verification already performed in the getOutliningTypeImpl.
2984+ if (C.back ().isReturn ()) {
2985+ assert (!cannotInsertTailCall (*C.getMBB ()) &&
2986+ " The candidate who uses return instruction must be outlined "
2987+ " using tail call" );
2988+ return MachineOutlinerTailCall;
2989+ }
2990+
2991+ auto CandidateUsesX5 = [](outliner::Candidate &C) {
2992+ const TargetRegisterInfo *TRI = C.getMF ()->getSubtarget ().getRegisterInfo ();
2993+ if (std::any_of (C.begin (), C.end (), [TRI](const MachineInstr &MI) {
2994+ return isMIModifiesReg (MI, TRI, RISCV::X5);
2995+ }))
2996+ return true ;
2997+ return !C.isAvailableAcrossAndOutOfSeq (RISCV::X5, *TRI);
2998+ };
2999+
3000+ if (!CandidateUsesX5 (C))
3001+ return MachineOutlinerDefault;
3002+
3003+ return std::nullopt ;
3004+ }
3005+
29383006std::optional<std::unique_ptr<outliner::OutlinedFunction>>
29393007RISCVInstrInfo::getOutliningCandidateInfo (
29403008 const MachineModuleInfo &MMI,
29413009 std::vector<outliner::Candidate> &RepeatedSequenceLocs,
29423010 unsigned MinRepeats) const {
29433011
2944- // First we need to filter out candidates where the X5 register (IE t0) can't
2945- // be used to setup the function call.
2946- auto CannotInsertCall = [](outliner::Candidate &C) {
2947- const TargetRegisterInfo *TRI = C.getMF ()->getSubtarget ().getRegisterInfo ();
2948- return !C.isAvailableAcrossAndOutOfSeq (RISCV::X5, *TRI);
2949- };
2950-
2951- llvm::erase_if (RepeatedSequenceLocs, CannotInsertCall);
3012+ // Each RepeatedSequenceLoc is identical.
3013+ outliner::Candidate &Candidate = RepeatedSequenceLocs[0 ];
3014+ auto CandidateInfo = analyzeCandidate (Candidate);
3015+ if (!CandidateInfo)
3016+ RepeatedSequenceLocs.clear ();
29523017
29533018 // If the sequence doesn't have enough candidates left, then we're done.
29543019 if (RepeatedSequenceLocs.size () < MinRepeats)
29553020 return std::nullopt ;
29563021
2957- unsigned SequenceSize = 0 ;
2958-
2959- for (auto &MI : RepeatedSequenceLocs[0 ])
2960- SequenceSize += getInstSizeInBytes (MI);
3022+ unsigned InstrSizeCExt =
3023+ Candidate.getMF ()->getSubtarget <RISCVSubtarget>().hasStdExtCOrZca () ? 2
3024+ : 4 ;
3025+ unsigned CallOverhead = 0 , FrameOverhead = 0 ;
3026+
3027+ MachineOutlinerConstructionID MOCI = CandidateInfo.value ();
3028+ switch (MOCI) {
3029+ case MachineOutlinerDefault:
3030+ // call t0, function = 8 bytes.
3031+ CallOverhead = 8 ;
3032+ // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled.
3033+ FrameOverhead = InstrSizeCExt;
3034+ break ;
3035+ case MachineOutlinerTailCall:
3036+ // tail call = auipc + jalr in the worst case without linker relaxation.
3037+ CallOverhead = 4 + InstrSizeCExt;
3038+ // Using tail call we move ret instruction from caller to callee.
3039+ FrameOverhead = 0 ;
3040+ break ;
3041+ }
29613042
2962- // call t0, function = 8 bytes.
2963- unsigned CallOverhead = 8 ;
29643043 for (auto &C : RepeatedSequenceLocs)
2965- C.setCallInfo (MachineOutlinerDefault , CallOverhead);
3044+ C.setCallInfo (MOCI , CallOverhead);
29663045
2967- // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled.
2968- unsigned FrameOverhead = 4 ;
2969- if (RepeatedSequenceLocs[0 ]
2970- .getMF ()
2971- ->getSubtarget <RISCVSubtarget>()
2972- .hasStdExtCOrZca ())
2973- FrameOverhead = 2 ;
3046+ unsigned SequenceSize = 0 ;
3047+ for (auto &MI : Candidate)
3048+ SequenceSize += getInstSizeInBytes (MI);
29743049
29753050 return std::make_unique<outliner::OutlinedFunction>(
2976- RepeatedSequenceLocs, SequenceSize, FrameOverhead,
2977- MachineOutlinerDefault);
3051+ RepeatedSequenceLocs, SequenceSize, FrameOverhead, MOCI);
29783052}
29793053
29803054outliner::InstrType
@@ -2995,15 +3069,8 @@ RISCVInstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
29953069 return F.needsUnwindTableEntry () ? outliner::InstrType::Illegal
29963070 : outliner::InstrType::Invisible;
29973071
2998- // We need support for tail calls to outlined functions before return
2999- // statements can be allowed.
3000- if (MI.isReturn ())
3001- return outliner::InstrType::Illegal;
3002-
3003- // Don't allow modifying the X5 register which we use for return addresses for
3004- // these outlined functions.
3005- if (MI.modifiesRegister (RISCV::X5, TRI) ||
3006- MI.getDesc ().hasImplicitDefOfPhysReg (RISCV::X5))
3072+ if (cannotInsertTailCall (*MBB) &&
3073+ (MI.isReturn () || isMIModifiesReg (MI, TRI, RISCV::X5)))
30073074 return outliner::InstrType::Illegal;
30083075
30093076 // Make sure the operands don't reference something unsafe.
@@ -3039,6 +3106,9 @@ void RISCVInstrInfo::buildOutlinedFrame(
30393106 }
30403107 }
30413108
3109+ if (OF.FrameConstructionID == MachineOutlinerTailCall)
3110+ return ;
3111+
30423112 MBB.addLiveIn (RISCV::X5);
30433113
30443114 // Add in a return instruction to the end of the outlined frame.
@@ -3052,6 +3122,13 @@ MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall(
30523122 Module &M, MachineBasicBlock &MBB, MachineBasicBlock::iterator &It,
30533123 MachineFunction &MF, outliner::Candidate &C) const {
30543124
3125+ if (C.CallConstructionID == MachineOutlinerTailCall) {
3126+ It = MBB.insert (It, BuildMI (MF, DebugLoc (), get (RISCV::PseudoTAIL))
3127+ .addGlobalAddress (M.getNamedValue (MF.getName ()),
3128+ /* Offset=*/ 0 , RISCVII::MO_CALL));
3129+ return It;
3130+ }
3131+
30553132 // Add in a call instruction to the outlined function at the given location.
30563133 It = MBB.insert (It,
30573134 BuildMI (MF, DebugLoc (), get (RISCV::PseudoCALLReg), RISCV::X5)
0 commit comments