11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#include " RISCVInstrInfo.h"
14
+ #include " MCTargetDesc/RISCVBaseInfo.h"
14
15
#include " MCTargetDesc/RISCVMatInt.h"
15
16
#include " RISCV.h"
16
17
#include " RISCVMachineFunctionInfo.h"
@@ -2927,6 +2928,7 @@ bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
2927
2928
2928
2929
// Enum values indicating how an outlined call should be constructed.
2929
2930
enum MachineOutlinerConstructionID {
2931
+ MachineOutlinerTailCall,
2930
2932
MachineOutlinerDefault
2931
2933
};
2932
2934
@@ -2935,46 +2937,118 @@ bool RISCVInstrInfo::shouldOutlineFromFunctionByDefault(
2935
2937
return MF.getFunction ().hasMinSize ();
2936
2938
}
2937
2939
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
+
2938
3006
std::optional<std::unique_ptr<outliner::OutlinedFunction>>
2939
3007
RISCVInstrInfo::getOutliningCandidateInfo (
2940
3008
const MachineModuleInfo &MMI,
2941
3009
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
2942
3010
unsigned MinRepeats) const {
2943
3011
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 ();
2952
3017
2953
3018
// If the sequence doesn't have enough candidates left, then we're done.
2954
3019
if (RepeatedSequenceLocs.size () < MinRepeats)
2955
3020
return std::nullopt;
2956
3021
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
+ }
2961
3042
2962
- // call t0, function = 8 bytes.
2963
- unsigned CallOverhead = 8 ;
2964
3043
for (auto &C : RepeatedSequenceLocs)
2965
- C.setCallInfo (MachineOutlinerDefault , CallOverhead);
3044
+ C.setCallInfo (MOCI , CallOverhead);
2966
3045
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);
2974
3049
2975
3050
return std::make_unique<outliner::OutlinedFunction>(
2976
- RepeatedSequenceLocs, SequenceSize, FrameOverhead,
2977
- MachineOutlinerDefault);
3051
+ RepeatedSequenceLocs, SequenceSize, FrameOverhead, MOCI);
2978
3052
}
2979
3053
2980
3054
outliner::InstrType
@@ -2995,15 +3069,8 @@ RISCVInstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
2995
3069
return F.needsUnwindTableEntry () ? outliner::InstrType::Illegal
2996
3070
: outliner::InstrType::Invisible;
2997
3071
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)))
3007
3074
return outliner::InstrType::Illegal;
3008
3075
3009
3076
// Make sure the operands don't reference something unsafe.
@@ -3039,6 +3106,9 @@ void RISCVInstrInfo::buildOutlinedFrame(
3039
3106
}
3040
3107
}
3041
3108
3109
+ if (OF.FrameConstructionID == MachineOutlinerTailCall)
3110
+ return ;
3111
+
3042
3112
MBB.addLiveIn (RISCV::X5);
3043
3113
3044
3114
// Add in a return instruction to the end of the outlined frame.
@@ -3052,6 +3122,13 @@ MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall(
3052
3122
Module &M, MachineBasicBlock &MBB, MachineBasicBlock::iterator &It,
3053
3123
MachineFunction &MF, outliner::Candidate &C) const {
3054
3124
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
+
3055
3132
// Add in a call instruction to the outlined function at the given location.
3056
3133
It = MBB.insert (It,
3057
3134
BuildMI (MF, DebugLoc (), get (RISCV::PseudoCALLReg), RISCV::X5)
0 commit comments