@@ -2925,9 +2925,42 @@ bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
29252925 return TargetInstrInfo::isMBBSafeToOutlineFrom (MBB, Flags);
29262926}
29272927
2928- // Enum values indicating how an outlined call should be constructed.
2928+ // / Constants defining how certain sequences should be outlined.
2929+ // / This encompasses how an outlined function should be called, and what kind of
2930+ // / frame should be emitted for that outlined function.
2931+ // /
2932+ // / \p MachineOutlinerCallViaX5 implies that the function should be called with
2933+ // / using X5 as an alternative link register.
2934+ // /
2935+ // / That is,
2936+ // /
2937+ // / I1 Materialize addr in X5 OUTLINED_FUNCTION:
2938+ // / I2 --> JAL X5 I1
2939+ // / I3 I2
2940+ // / I3
2941+ // / RET X5
2942+ // /
2943+ // / * Call construction overhead: 2 insns
2944+ // / * Frame construction overhead: 1 (ret)
2945+ // / * Requires stack fixups? No
2946+ // /
2947+ // / \p MachineOutlinerTailCall implies that the function is being created from
2948+ // / a sequence of instructions ending in a return.
2949+ // /
2950+ // / That is,
2951+ // /
2952+ // / I1 OUTLINED_FUNCTION:
2953+ // / I2 --> B OUTLINED_FUNCTION I1
2954+ // / RET I2
2955+ // / RET
2956+ // /
2957+ // / * Call construction overhead: 2 insns
2958+ // / * Frame construction overhead: 0 (Return included in sequence)
2959+ // / * Requires stack fixups? No
2960+ // /
29292961enum MachineOutlinerConstructionID {
2930- MachineOutlinerDefault
2962+ MachineOutlinerCallViaX5,
2963+ MachineOutlinerTailCall
29312964};
29322965
29332966bool RISCVInstrInfo::shouldOutlineFromFunctionByDefault (
@@ -2941,14 +2974,33 @@ RISCVInstrInfo::getOutliningCandidateInfo(
29412974 std::vector<outliner::Candidate> &RepeatedSequenceLocs,
29422975 unsigned MinRepeats) const {
29432976
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- };
2977+ // If the last instruction in any candidate is a terminator, then we should
2978+ // tail call all of the candidates.
2979+ bool IsTailCall = RepeatedSequenceLocs[0 ].back ().isTerminator ();
2980+
2981+ if (!IsTailCall) {
2982+ // Filter out candidates where the X5 register (IE t0) can't
2983+ // be used to setup the function call.
2984+ auto CannotInsertCall = [](outliner::Candidate &C) {
2985+ const TargetRegisterInfo *TRI =
2986+ C.getMF ()->getSubtarget ().getRegisterInfo ();
2987+ if (!C.isAvailableAcrossAndOutOfSeq (RISCV::X5, *TRI))
2988+ return true ;
29502989
2951- llvm::erase_if (RepeatedSequenceLocs, CannotInsertCall);
2990+ // Don't allow modifying the X5 register which we use for return addresses
2991+ // for these outlined functions.
2992+ for (const auto &MI : C) {
2993+ // FIXME: Why is this case not handled by isAvailableAcrossAndOutOfSeq
2994+ // above?
2995+ if (MI.modifiesRegister (RISCV::X5, TRI))
2996+ return true ;
2997+ }
2998+
2999+ return false ;
3000+ };
3001+
3002+ llvm::erase_if (RepeatedSequenceLocs, CannotInsertCall);
3003+ }
29523004
29533005 // If the sequence doesn't have enough candidates left, then we're done.
29543006 if (RepeatedSequenceLocs.size () < MinRepeats)
@@ -2961,8 +3013,12 @@ RISCVInstrInfo::getOutliningCandidateInfo(
29613013
29623014 // call t0, function = 8 bytes.
29633015 unsigned CallOverhead = 8 ;
3016+
3017+ MachineOutlinerConstructionID OutlinerType =
3018+ IsTailCall ? MachineOutlinerTailCall : MachineOutlinerCallViaX5;
3019+
29643020 for (auto &C : RepeatedSequenceLocs)
2965- C.setCallInfo (MachineOutlinerDefault , CallOverhead);
3021+ C.setCallInfo (OutlinerType , CallOverhead);
29663022
29673023 // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled.
29683024 unsigned FrameOverhead = 4 ;
@@ -2972,19 +3028,19 @@ RISCVInstrInfo::getOutliningCandidateInfo(
29723028 .hasStdExtCOrZca ())
29733029 FrameOverhead = 2 ;
29743030
3031+ // There is no overhead in the frame when doing a tail call.
3032+ if (IsTailCall)
3033+ FrameOverhead = 0 ;
3034+
29753035 return std::make_unique<outliner::OutlinedFunction>(
2976- RepeatedSequenceLocs, SequenceSize, FrameOverhead,
2977- MachineOutlinerDefault);
3036+ RepeatedSequenceLocs, SequenceSize, FrameOverhead, OutlinerType);
29783037}
29793038
29803039outliner::InstrType
29813040RISCVInstrInfo::getOutliningTypeImpl (const MachineModuleInfo &MMI,
29823041 MachineBasicBlock::iterator &MBBI,
29833042 unsigned Flags) const {
29843043 MachineInstr &MI = *MBBI;
2985- MachineBasicBlock *MBB = MI.getParent ();
2986- const TargetRegisterInfo *TRI =
2987- MBB->getParent ()->getSubtarget ().getRegisterInfo ();
29883044 const auto &F = MI.getMF ()->getFunction ();
29893045
29903046 // We can manually strip out CFI instructions later.
@@ -2995,17 +3051,6 @@ RISCVInstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
29953051 return F.needsUnwindTableEntry () ? outliner::InstrType::Illegal
29963052 : outliner::InstrType::Invisible;
29973053
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))
3007- return outliner::InstrType::Illegal;
3008-
30093054 // Make sure the operands don't reference something unsafe.
30103055 for (const auto &MO : MI.operands ()) {
30113056
@@ -3041,6 +3086,9 @@ void RISCVInstrInfo::buildOutlinedFrame(
30413086
30423087 MBB.addLiveIn (RISCV::X5);
30433088
3089+ if (OF.FrameConstructionID == MachineOutlinerTailCall)
3090+ return ;
3091+
30443092 // Add in a return instruction to the end of the outlined frame.
30453093 MBB.insert (MBB.end (), BuildMI (MF, DebugLoc (), get (RISCV::JALR))
30463094 .addReg (RISCV::X0, RegState::Define)
@@ -3052,6 +3100,13 @@ MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall(
30523100 Module &M, MachineBasicBlock &MBB, MachineBasicBlock::iterator &It,
30533101 MachineFunction &MF, outliner::Candidate &C) const {
30543102
3103+ if (C.CallConstructionID == MachineOutlinerTailCall) {
3104+ It = MBB.insert (It, BuildMI (MF, DebugLoc (), get (RISCV::PseudoTAIL))
3105+ .addGlobalAddress (M.getNamedValue (MF.getName ()), 0 ,
3106+ RISCVII::MO_CALL));
3107+ return It;
3108+ }
3109+
30553110 // Add in a call instruction to the outlined function at the given location.
30563111 It = MBB.insert (It,
30573112 BuildMI (MF, DebugLoc (), get (RISCV::PseudoCALLReg), RISCV::X5)
0 commit comments