Skip to content

Commit 93b8d07

Browse files
authored
[MachineOutliner][NFC] Refactor (#105398)
This patch prepares the NFC groundwork for global outlining using CGData, which will follow #90074. - The `MinRepeats` parameter is now explicitly passed to the `getOutliningCandidateInfo` function, rather than relying on a default value of 2. For local outlining, the minimum number of repetitions is typically 2, but for the global outlining (mentioned above), we will optimistically create a single `Candidate` for each `OutlinedFunction` if stable hashes match a specific code sequence. This parameter is adjusted accordingly in global outlining scenarios. - I have also implemented `unique_ptr` for `OutlinedFunction` to ensure safe and efficient memory management within `FunctionList`, avoiding unnecessary implicit copies. This depends on #101461. This is a patch for https://discourse.llvm.org/t/rfc-enhanced-machine-outliner-part-2-thinlto-nolto/78753.
1 parent e19c3a7 commit 93b8d07

File tree

10 files changed

+92
-69
lines changed

10 files changed

+92
-69
lines changed

llvm/include/llvm/CodeGen/TargetInstrInfo.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,10 +2094,13 @@ class TargetInstrInfo : public MCInstrInfo {
20942094

20952095
/// Returns a \p outliner::OutlinedFunction struct containing target-specific
20962096
/// information for a set of outlining candidates. Returns std::nullopt if the
2097-
/// candidates are not suitable for outlining.
2098-
virtual std::optional<outliner::OutlinedFunction> getOutliningCandidateInfo(
2097+
/// candidates are not suitable for outlining. \p MinRepeats is the minimum
2098+
/// number of times the instruction sequence must be repeated.
2099+
virtual std::optional<std::unique_ptr<outliner::OutlinedFunction>>
2100+
getOutliningCandidateInfo(
20992101
const MachineModuleInfo &MMI,
2100-
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
2102+
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
2103+
unsigned MinRepeats) const {
21012104
llvm_unreachable(
21022105
"Target didn't implement TargetInstrInfo::getOutliningCandidateInfo!");
21032106
}

llvm/lib/CodeGen/MachineOutliner.cpp

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -456,16 +456,19 @@ struct MachineOutliner : public ModulePass {
456456
/// \param Mapper Contains outlining mapping information.
457457
/// \param[out] FunctionList Filled with a list of \p OutlinedFunctions
458458
/// each type of candidate.
459-
void findCandidates(InstructionMapper &Mapper,
460-
std::vector<OutlinedFunction> &FunctionList);
459+
void
460+
findCandidates(InstructionMapper &Mapper,
461+
std::vector<std::unique_ptr<OutlinedFunction>> &FunctionList);
461462

462463
/// Replace the sequences of instructions represented by \p OutlinedFunctions
463464
/// with calls to functions.
464465
///
465466
/// \param M The module we are outlining from.
466467
/// \param FunctionList A list of functions to be inserted into the module.
467468
/// \param Mapper Contains the instruction mappings for the module.
468-
bool outline(Module &M, std::vector<OutlinedFunction> &FunctionList,
469+
/// \param[out] OutlinedFunctionNum The outlined function number.
470+
bool outline(Module &M,
471+
std::vector<std::unique_ptr<OutlinedFunction>> &FunctionList,
469472
InstructionMapper &Mapper, unsigned &OutlinedFunctionNum);
470473

471474
/// Creates a function for \p OF and inserts it into the module.
@@ -583,7 +586,8 @@ void MachineOutliner::emitOutlinedFunctionRemark(OutlinedFunction &OF) {
583586
}
584587

585588
void MachineOutliner::findCandidates(
586-
InstructionMapper &Mapper, std::vector<OutlinedFunction> &FunctionList) {
589+
InstructionMapper &Mapper,
590+
std::vector<std::unique_ptr<OutlinedFunction>> &FunctionList) {
587591
FunctionList.clear();
588592
SuffixTree ST(Mapper.UnsignedVec, OutlinerLeafDescendants);
589593

@@ -658,33 +662,36 @@ void MachineOutliner::findCandidates(
658662
<< "\n");
659663
LLVM_DEBUG(dbgs() << " Candidates kept: " << NumKept << "\n\n");
660664
#endif
665+
unsigned MinRepeats = 2;
661666

662667
// We've found something we might want to outline.
663668
// Create an OutlinedFunction to store it and check if it'd be beneficial
664669
// to outline.
665-
if (CandidatesForRepeatedSeq.size() < 2)
670+
if (CandidatesForRepeatedSeq.size() < MinRepeats)
666671
continue;
667672

668673
// Arbitrarily choose a TII from the first candidate.
669674
// FIXME: Should getOutliningCandidateInfo move to TargetMachine?
670675
const TargetInstrInfo *TII =
671676
CandidatesForRepeatedSeq[0].getMF()->getSubtarget().getInstrInfo();
672677

673-
std::optional<OutlinedFunction> OF =
674-
TII->getOutliningCandidateInfo(*MMI, CandidatesForRepeatedSeq);
678+
std::optional<std::unique_ptr<OutlinedFunction>> OF =
679+
TII->getOutliningCandidateInfo(*MMI, CandidatesForRepeatedSeq,
680+
MinRepeats);
675681

676682
// If we deleted too many candidates, then there's nothing worth outlining.
677683
// FIXME: This should take target-specified instruction sizes into account.
678-
if (!OF || OF->Candidates.size() < 2)
684+
if (!OF.has_value() || OF.value()->Candidates.size() < MinRepeats)
679685
continue;
680686

681687
// Is it better to outline this candidate than not?
682-
if (OF->getBenefit() < OutlinerBenefitThreshold) {
683-
emitNotOutliningCheaperRemark(StringLen, CandidatesForRepeatedSeq, *OF);
688+
if (OF.value()->getBenefit() < OutlinerBenefitThreshold) {
689+
emitNotOutliningCheaperRemark(StringLen, CandidatesForRepeatedSeq,
690+
*OF.value());
684691
continue;
685692
}
686693

687-
FunctionList.push_back(*OF);
694+
FunctionList.emplace_back(std::move(OF.value()));
688695
}
689696
}
690697

@@ -827,71 +834,70 @@ MachineFunction *MachineOutliner::createOutlinedFunction(
827834
return &MF;
828835
}
829836

830-
bool MachineOutliner::outline(Module &M,
831-
std::vector<OutlinedFunction> &FunctionList,
832-
InstructionMapper &Mapper,
833-
unsigned &OutlinedFunctionNum) {
837+
bool MachineOutliner::outline(
838+
Module &M, std::vector<std::unique_ptr<OutlinedFunction>> &FunctionList,
839+
InstructionMapper &Mapper, unsigned &OutlinedFunctionNum) {
834840
LLVM_DEBUG(dbgs() << "*** Outlining ***\n");
835841
LLVM_DEBUG(dbgs() << "NUMBER OF POTENTIAL FUNCTIONS: " << FunctionList.size()
836842
<< "\n");
837843
bool OutlinedSomething = false;
838844

839845
// Sort by priority where priority := getNotOutlinedCost / getOutliningCost.
840846
// The function with highest priority should be outlined first.
841-
stable_sort(FunctionList,
842-
[](const OutlinedFunction &LHS, const OutlinedFunction &RHS) {
843-
return LHS.getNotOutlinedCost() * RHS.getOutliningCost() >
844-
RHS.getNotOutlinedCost() * LHS.getOutliningCost();
845-
});
847+
stable_sort(FunctionList, [](const std::unique_ptr<OutlinedFunction> &LHS,
848+
const std::unique_ptr<OutlinedFunction> &RHS) {
849+
return LHS->getNotOutlinedCost() * RHS->getOutliningCost() >
850+
RHS->getNotOutlinedCost() * LHS->getOutliningCost();
851+
});
846852

847853
// Walk over each function, outlining them as we go along. Functions are
848854
// outlined greedily, based off the sort above.
849855
auto *UnsignedVecBegin = Mapper.UnsignedVec.begin();
850856
LLVM_DEBUG(dbgs() << "WALKING FUNCTION LIST\n");
851-
for (OutlinedFunction &OF : FunctionList) {
857+
for (auto &OF : FunctionList) {
852858
#ifndef NDEBUG
853-
auto NumCandidatesBefore = OF.Candidates.size();
859+
auto NumCandidatesBefore = OF->Candidates.size();
854860
#endif
855861
// If we outlined something that overlapped with a candidate in a previous
856862
// step, then we can't outline from it.
857-
erase_if(OF.Candidates, [&UnsignedVecBegin](Candidate &C) {
863+
erase_if(OF->Candidates, [&UnsignedVecBegin](Candidate &C) {
858864
return std::any_of(UnsignedVecBegin + C.getStartIdx(),
859865
UnsignedVecBegin + C.getEndIdx() + 1, [](unsigned I) {
860866
return I == static_cast<unsigned>(-1);
861867
});
862868
});
863869

864870
#ifndef NDEBUG
865-
auto NumCandidatesAfter = OF.Candidates.size();
871+
auto NumCandidatesAfter = OF->Candidates.size();
866872
LLVM_DEBUG(dbgs() << "PRUNED: " << NumCandidatesBefore - NumCandidatesAfter
867873
<< "/" << NumCandidatesBefore << " candidates\n");
868874
#endif
869875

870876
// If we made it unbeneficial to outline this function, skip it.
871-
if (OF.getBenefit() < OutlinerBenefitThreshold) {
872-
LLVM_DEBUG(dbgs() << "SKIP: Expected benefit (" << OF.getBenefit()
877+
if (OF->getBenefit() < OutlinerBenefitThreshold) {
878+
LLVM_DEBUG(dbgs() << "SKIP: Expected benefit (" << OF->getBenefit()
873879
<< " B) < threshold (" << OutlinerBenefitThreshold
874880
<< " B)\n");
875881
continue;
876882
}
877883

878-
LLVM_DEBUG(dbgs() << "OUTLINE: Expected benefit (" << OF.getBenefit()
884+
LLVM_DEBUG(dbgs() << "OUTLINE: Expected benefit (" << OF->getBenefit()
879885
<< " B) > threshold (" << OutlinerBenefitThreshold
880886
<< " B)\n");
881887

882888
// It's beneficial. Create the function and outline its sequence's
883889
// occurrences.
884-
OF.MF = createOutlinedFunction(M, OF, Mapper, OutlinedFunctionNum);
885-
emitOutlinedFunctionRemark(OF);
890+
OF->MF = createOutlinedFunction(M, *OF, Mapper, OutlinedFunctionNum);
891+
emitOutlinedFunctionRemark(*OF);
886892
FunctionsCreated++;
887893
OutlinedFunctionNum++; // Created a function, move to the next name.
888-
MachineFunction *MF = OF.MF;
894+
MachineFunction *MF = OF->MF;
889895
const TargetSubtargetInfo &STI = MF->getSubtarget();
890896
const TargetInstrInfo &TII = *STI.getInstrInfo();
891897

892898
// Replace occurrences of the sequence with calls to the new function.
893899
LLVM_DEBUG(dbgs() << "CREATE OUTLINED CALLS\n");
894-
for (Candidate &C : OF.Candidates) {
900+
for (Candidate &C : OF->Candidates) {
895901
MachineBasicBlock &MBB = *C.getMBB();
896902
MachineBasicBlock::iterator StartIt = C.begin();
897903
MachineBasicBlock::iterator EndIt = std::prev(C.end());
@@ -1180,7 +1186,7 @@ bool MachineOutliner::doOutline(Module &M, unsigned &OutlinedFunctionNum) {
11801186

11811187
// Prepare instruction mappings for the suffix tree.
11821188
populateMapper(Mapper, M);
1183-
std::vector<OutlinedFunction> FunctionList;
1189+
std::vector<std::unique_ptr<OutlinedFunction>> FunctionList;
11841190

11851191
// Find all of the outlining candidates.
11861192
findCandidates(Mapper, FunctionList);

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8686,10 +8686,11 @@ static bool outliningCandidatesV8_3OpsConsensus(const outliner::Candidate &a,
86868686
return SubtargetA.hasV8_3aOps() == SubtargetB.hasV8_3aOps();
86878687
}
86888688

8689-
std::optional<outliner::OutlinedFunction>
8689+
std::optional<std::unique_ptr<outliner::OutlinedFunction>>
86908690
AArch64InstrInfo::getOutliningCandidateInfo(
86918691
const MachineModuleInfo &MMI,
8692-
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
8692+
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
8693+
unsigned MinRepeats) const {
86938694
unsigned SequenceSize = 0;
86948695
for (auto &MI : RepeatedSequenceLocs[0])
86958696
SequenceSize += getInstSizeInBytes(MI);
@@ -8803,7 +8804,7 @@ AArch64InstrInfo::getOutliningCandidateInfo(
88038804
llvm::erase_if(RepeatedSequenceLocs, hasIllegalSPModification);
88048805

88058806
// If the sequence doesn't have enough candidates left, then we're done.
8806-
if (RepeatedSequenceLocs.size() < 2)
8807+
if (RepeatedSequenceLocs.size() < MinRepeats)
88078808
return std::nullopt;
88088809
}
88098810

@@ -9050,7 +9051,7 @@ AArch64InstrInfo::getOutliningCandidateInfo(
90509051
}
90519052

90529053
// If we dropped all of the candidates, bail out here.
9053-
if (RepeatedSequenceLocs.size() < 2) {
9054+
if (RepeatedSequenceLocs.size() < MinRepeats) {
90549055
RepeatedSequenceLocs.clear();
90559056
return std::nullopt;
90569057
}
@@ -9093,8 +9094,8 @@ AArch64InstrInfo::getOutliningCandidateInfo(
90939094
if (FrameID != MachineOutlinerTailCall && CFICount > 0)
90949095
return std::nullopt;
90959096

9096-
return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize,
9097-
NumBytesToCreateFrame, FrameID);
9097+
return std::make_unique<outliner::OutlinedFunction>(
9098+
RepeatedSequenceLocs, SequenceSize, NumBytesToCreateFrame, FrameID);
90989099
}
90999100

91009101
void AArch64InstrInfo::mergeOutliningCandidateAttributes(

llvm/lib/Target/AArch64/AArch64InstrInfo.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,11 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
472472

473473
bool isFunctionSafeToOutlineFrom(MachineFunction &MF,
474474
bool OutlineFromLinkOnceODRs) const override;
475-
std::optional<outliner::OutlinedFunction> getOutliningCandidateInfo(
475+
std::optional<std::unique_ptr<outliner::OutlinedFunction>>
476+
getOutliningCandidateInfo(
476477
const MachineModuleInfo &MMI,
477-
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override;
478+
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
479+
unsigned MinRepeats) const override;
478480
void mergeOutliningCandidateAttributes(
479481
Function &F, std::vector<outliner::Candidate> &Candidates) const override;
480482
outliner::InstrType getOutliningTypeImpl(const MachineModuleInfo &MMI,

llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5873,10 +5873,11 @@ static bool isLRAvailable(const TargetRegisterInfo &TRI,
58735873
return !Live;
58745874
}
58755875

5876-
std::optional<outliner::OutlinedFunction>
5876+
std::optional<std::unique_ptr<outliner::OutlinedFunction>>
58775877
ARMBaseInstrInfo::getOutliningCandidateInfo(
58785878
const MachineModuleInfo &MMI,
5879-
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
5879+
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
5880+
unsigned MinRepeats) const {
58805881
unsigned SequenceSize = 0;
58815882
for (auto &MI : RepeatedSequenceLocs[0])
58825883
SequenceSize += getInstSizeInBytes(MI);
@@ -5917,7 +5918,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
59175918
llvm::erase_if(RepeatedSequenceLocs, CantGuaranteeValueAcrossCall);
59185919

59195920
// If the sequence doesn't have enough candidates left, then we're done.
5920-
if (RepeatedSequenceLocs.size() < 2)
5921+
if (RepeatedSequenceLocs.size() < MinRepeats)
59215922
return std::nullopt;
59225923
}
59235924

@@ -5943,7 +5944,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
59435944
else
59445945
RepeatedSequenceLocs.erase(RepeatedSequenceLocs.begin(), NoBTI);
59455946

5946-
if (RepeatedSequenceLocs.size() < 2)
5947+
if (RepeatedSequenceLocs.size() < MinRepeats)
59475948
return std::nullopt;
59485949

59495950
// Likewise, partition the candidates according to PAC-RET enablement.
@@ -5960,7 +5961,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
59605961
else
59615962
RepeatedSequenceLocs.erase(RepeatedSequenceLocs.begin(), NoPAC);
59625963

5963-
if (RepeatedSequenceLocs.size() < 2)
5964+
if (RepeatedSequenceLocs.size() < MinRepeats)
59645965
return std::nullopt;
59655966

59665967
// At this point, we have only "safe" candidates to outline. Figure out
@@ -6064,7 +6065,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
60646065
RepeatedSequenceLocs.size() * Costs.CallDefault) {
60656066
RepeatedSequenceLocs = CandidatesWithoutStackFixups;
60666067
FrameID = MachineOutlinerNoLRSave;
6067-
if (RepeatedSequenceLocs.size() < 2)
6068+
if (RepeatedSequenceLocs.size() < MinRepeats)
60686069
return std::nullopt;
60696070
} else
60706071
SetCandidateCallInfo(MachineOutlinerDefault, Costs.CallDefault);
@@ -6090,8 +6091,8 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
60906091
NumBytesToCreateFrame += Costs.SaveRestoreLROnStack;
60916092
}
60926093

6093-
return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize,
6094-
NumBytesToCreateFrame, FrameID);
6094+
return std::make_unique<outliner::OutlinedFunction>(
6095+
RepeatedSequenceLocs, SequenceSize, NumBytesToCreateFrame, FrameID);
60956096
}
60966097

60976098
bool ARMBaseInstrInfo::checkAndUpdateStackOffset(MachineInstr *MI,

llvm/lib/Target/ARM/ARMBaseInstrInfo.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,11 @@ class ARMBaseInstrInfo : public ARMGenInstrInfo {
356356
/// ARM supports the MachineOutliner.
357357
bool isFunctionSafeToOutlineFrom(MachineFunction &MF,
358358
bool OutlineFromLinkOnceODRs) const override;
359-
std::optional<outliner::OutlinedFunction> getOutliningCandidateInfo(
359+
std::optional<std::unique_ptr<outliner::OutlinedFunction>>
360+
getOutliningCandidateInfo(
360361
const MachineModuleInfo &MMI,
361-
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override;
362+
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
363+
unsigned MinRepeats) const override;
362364
void mergeOutliningCandidateAttributes(
363365
Function &F, std::vector<outliner::Candidate> &Candidates) const override;
364366
outliner::InstrType getOutliningTypeImpl(const MachineModuleInfo &MMI,

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2830,10 +2830,11 @@ bool RISCVInstrInfo::shouldOutlineFromFunctionByDefault(
28302830
return MF.getFunction().hasMinSize();
28312831
}
28322832

2833-
std::optional<outliner::OutlinedFunction>
2833+
std::optional<std::unique_ptr<outliner::OutlinedFunction>>
28342834
RISCVInstrInfo::getOutliningCandidateInfo(
28352835
const MachineModuleInfo &MMI,
2836-
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
2836+
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
2837+
unsigned MinRepeats) const {
28372838

28382839
// First we need to filter out candidates where the X5 register (IE t0) can't
28392840
// be used to setup the function call.
@@ -2845,7 +2846,7 @@ RISCVInstrInfo::getOutliningCandidateInfo(
28452846
llvm::erase_if(RepeatedSequenceLocs, CannotInsertCall);
28462847

28472848
// If the sequence doesn't have enough candidates left, then we're done.
2848-
if (RepeatedSequenceLocs.size() < 2)
2849+
if (RepeatedSequenceLocs.size() < MinRepeats)
28492850
return std::nullopt;
28502851

28512852
unsigned SequenceSize = 0;
@@ -2866,8 +2867,9 @@ RISCVInstrInfo::getOutliningCandidateInfo(
28662867
.hasStdExtCOrZca())
28672868
FrameOverhead = 2;
28682869

2869-
return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize,
2870-
FrameOverhead, MachineOutlinerDefault);
2870+
return std::make_unique<outliner::OutlinedFunction>(
2871+
RepeatedSequenceLocs, SequenceSize, FrameOverhead,
2872+
MachineOutlinerDefault);
28712873
}
28722874

28732875
outliner::InstrType

llvm/lib/Target/RISCV/RISCVInstrInfo.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,11 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
206206
bool shouldOutlineFromFunctionByDefault(MachineFunction &MF) const override;
207207

208208
// Calculate target-specific information for a set of outlining candidates.
209-
std::optional<outliner::OutlinedFunction> getOutliningCandidateInfo(
209+
std::optional<std::unique_ptr<outliner::OutlinedFunction>>
210+
getOutliningCandidateInfo(
210211
const MachineModuleInfo &MMI,
211-
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override;
212+
std::vector<outliner::Candidate> &RepeatedSequenceLocs,
213+
unsigned MinRepeats) const override;
212214

213215
// Return if/how a given MachineInstr should be outlined.
214216
virtual outliner::InstrType

0 commit comments

Comments
 (0)