1111// ===----------------------------------------------------------------------===//
1212
1313#include " RISCVInstrInfo.h"
14+ #include " MCTargetDesc/RISCVBaseInfo.h"
1415#include " MCTargetDesc/RISCVMatInt.h"
1516#include " RISCV.h"
1617#include " RISCVMachineFunctionInfo.h"
@@ -2938,85 +2939,118 @@ bool RISCVInstrInfo::shouldOutlineFromFunctionByDefault(
29382939 return MF.getFunction ().hasMinSize ();
29392940}
29402941
2941- static bool isCandidatePatchable (const MachineInstr &MI) {
2942- const MachineBasicBlock *MBB = MI.getParent ();
2943- const MachineFunction *MF = MBB->getParent ();
2942+ static bool isCandidatePatchable (const MachineBasicBlock &MBB) {
2943+ const MachineFunction *MF = MBB.getParent ();
29442944 const Function &F = MF->getFunction ();
29452945 return F.getFnAttribute (" fentry-call" ).getValueAsBool () ||
29462946 F.hasFnAttribute (" patchable-function-entry" );
29472947}
29482948
2949- static bool cannotInsertTailCall (const MachineInstr &MI) {
2950- if (MI. isTerminator ())
2951- return isCandidatePatchable (MI);
2952- return true ;
2949+ static bool isMIReadsReg (const MachineInstr &MI, const TargetRegisterInfo *TRI,
2950+ unsigned RegNo) {
2951+ return MI. readsRegister (RegNo, TRI) ||
2952+ MI. getDesc (). hasImplicitUseOfPhysReg (RegNo) ;
29532953}
29542954
2955- static bool isMIUsesX5 (const MachineInstr &MI, const TargetRegisterInfo *TRI) {
2956- return MI.modifiesRegister (RISCV::X5, TRI) ||
2957- MI.getDesc ().hasImplicitDefOfPhysReg (RISCV::X5);
2955+ static bool isMIModifiesReg (const MachineInstr &MI,
2956+ const TargetRegisterInfo *TRI, unsigned RegNo) {
2957+ return MI.modifiesRegister (RegNo, TRI) ||
2958+ MI.getDesc ().hasImplicitDefOfPhysReg (RegNo);
29582959}
29592960
2960- std::optional<std::unique_ptr<outliner::OutlinedFunction>>
2961- RISCVInstrInfo::getOutliningCandidateInfo (
2962- const MachineModuleInfo &MMI,
2963- std::vector<outliner::Candidate> &RepeatedSequenceLocs,
2964- unsigned MinRepeats) const {
2961+ static bool cannotInsertTailCall (const MachineBasicBlock &MBB) {
2962+ if (!MBB.back ().isReturn ())
2963+ return true ;
2964+ if (isCandidatePatchable (MBB))
2965+ return true ;
2966+
2967+ // If the candidate reads the pre-set register
2968+ // that can be used for expanding PseudoTAIL instruction,
2969+ // then we cannot insert tail call.
2970+ const TargetSubtargetInfo &STI = MBB.getParent ()->getSubtarget ();
2971+ unsigned TailExpandUseRegNo =
2972+ RISCVII::getTailExpandUseRegNo (STI.getFeatureBits ());
2973+ for (const MachineInstr &MI : MBB) {
2974+ if (isMIReadsReg (MI, STI.getRegisterInfo (), TailExpandUseRegNo))
2975+ return true ;
2976+ if (isMIModifiesReg (MI, STI.getRegisterInfo (), TailExpandUseRegNo))
2977+ break ;
2978+ }
2979+ return false ;
2980+ }
2981+
2982+ static std::optional<MachineOutlinerConstructionID>
2983+ analyzeCandidate (outliner::Candidate &C) {
2984+ // If last instruction is return then we can rely on
2985+ // the verification already performed in the getOutliningTypeImpl.
2986+ if (C.back ().isReturn ()) {
2987+ assert (!cannotInsertTailCall (*C.getMBB ()) &&
2988+ " The candidate who uses return instruction must be outlined "
2989+ " using tail call" );
2990+ return MachineOutlinerTailCall;
2991+ }
29652992
29662993 auto CandidateUsesX5 = [](outliner::Candidate &C) {
29672994 const TargetRegisterInfo *TRI = C.getMF ()->getSubtarget ().getRegisterInfo ();
2968- for (const MachineInstr &MI : C)
2969- if (isMIUsesX5 (MI, TRI))
2970- return true ;
2995+ if (std::any_of (C.begin (), C.end (), [TRI](const MachineInstr &MI) {
2996+ return isMIModifiesReg (MI, TRI, RISCV::X5);
2997+ }))
2998+ return true ;
29712999 return !C.isAvailableAcrossAndOutOfSeq (RISCV::X5, *TRI);
29723000 };
29733001
2974- auto CannotInsertCall = [CandidateUsesX5](outliner::Candidate &C) {
2975- if (!CandidateUsesX5 (C))
2976- return false ;
2977- if (!cannotInsertTailCall (C.back ()))
2978- return false ;
2979- return true ;
2980- };
3002+ if (!CandidateUsesX5 (C))
3003+ return MachineOutlinerDefault;
3004+
3005+ return std::nullopt ;
3006+ }
3007+
3008+ std::optional<std::unique_ptr<outliner::OutlinedFunction>>
3009+ RISCVInstrInfo::getOutliningCandidateInfo (
3010+ const MachineModuleInfo &MMI,
3011+ std::vector<outliner::Candidate> &RepeatedSequenceLocs,
3012+ unsigned MinRepeats) const {
29813013
2982- llvm::erase_if (RepeatedSequenceLocs, CannotInsertCall);
3014+ // Each RepeatedSequenceLoc is identical.
3015+ outliner::Candidate &Candidate = RepeatedSequenceLocs[0 ];
3016+ auto CandidateInfo = analyzeCandidate (Candidate);
3017+ if (!CandidateInfo)
3018+ RepeatedSequenceLocs.clear ();
29833019
29843020 // If the sequence doesn't have enough candidates left, then we're done.
29853021 if (RepeatedSequenceLocs.size () < MinRepeats)
29863022 return std::nullopt ;
29873023
2988- unsigned SequenceSize = 0 ;
2989-
2990- for (auto &MI : RepeatedSequenceLocs[0 ])
2991- SequenceSize += getInstSizeInBytes (MI);
2992-
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 instruction from caller to calle.
2999- // So, FrameOverhead for this is 0
3000- return std::make_unique<outliner::OutlinedFunction>(
3001- RepeatedSequenceLocs, SequenceSize, 0 , MachineOutlinerTailCall);
3024+ unsigned InstrSizeCExt =
3025+ Candidate.getMF ()->getSubtarget <RISCVSubtarget>().hasStdExtCOrZca () ? 2
3026+ : 4 ;
3027+ unsigned CallOverhead = 0 , FrameOverhead = 0 ;
3028+
3029+ MachineOutlinerConstructionID MOCI = CandidateInfo.value ();
3030+ switch (MOCI) {
3031+ case MachineOutlinerDefault:
3032+ // call t0, function = 8 bytes.
3033+ CallOverhead = 8 ;
3034+ // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled.
3035+ FrameOverhead = InstrSizeCExt;
3036+ break ;
3037+ case MachineOutlinerTailCall:
3038+ // tail call = auipc + jalr in the worst case without linker relaxation.
3039+ CallOverhead = 4 + InstrSizeCExt;
3040+ // Using tail call we move ret instruction from caller to callee.
3041+ FrameOverhead = 0 ;
3042+ break ;
30023043 }
30033044
3004- // call t0, function = 8 bytes.
3005- unsigned CallOverhead = 8 ;
30063045 for (auto &C : RepeatedSequenceLocs)
3007- C.setCallInfo (MachineOutlinerDefault , CallOverhead);
3046+ C.setCallInfo (MOCI , CallOverhead);
30083047
3009- // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled.
3010- unsigned FrameOverhead = 4 ;
3011- if (RepeatedSequenceLocs[0 ]
3012- .getMF ()
3013- ->getSubtarget <RISCVSubtarget>()
3014- .hasStdExtCOrZca ())
3015- FrameOverhead = 2 ;
3048+ unsigned SequenceSize = 0 ;
3049+ for (auto &MI : Candidate)
3050+ SequenceSize += getInstSizeInBytes (MI);
30163051
30173052 return std::make_unique<outliner::OutlinedFunction>(
3018- RepeatedSequenceLocs, SequenceSize, FrameOverhead,
3019- MachineOutlinerDefault);
3053+ RepeatedSequenceLocs, SequenceSize, FrameOverhead, MOCI);
30203054}
30213055
30223056outliner::InstrType
@@ -3037,7 +3071,8 @@ RISCVInstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
30373071 return F.needsUnwindTableEntry () ? outliner::InstrType::Illegal
30383072 : outliner::InstrType::Invisible;
30393073
3040- if (cannotInsertTailCall (MBB->back ()) && isMIUsesX5 (MI, TRI))
3074+ if (cannotInsertTailCall (*MBB) &&
3075+ (MI.isReturn () || isMIModifiesReg (MI, TRI, RISCV::X5)))
30413076 return outliner::InstrType::Illegal;
30423077
30433078 // Make sure the operands don't reference something unsafe.
0 commit comments