unsigned OccurrenceCount = 0;
public:
+ std::vector<std::shared_ptr<Candidate>> Candidates;
+
/// The actual outlined function created.
/// This is initialized after we go through and create the actual function.
MachineFunction *MF = nullptr;
/// type of candidate.
///
/// \returns The length of the longest candidate found.
- unsigned findCandidates(SuffixTree &ST, const TargetInstrInfo &TII,
- InstructionMapper &Mapper,
- std::vector<Candidate> &CandidateList,
- std::vector<OutlinedFunction> &FunctionList);
+ unsigned
+ findCandidates(SuffixTree &ST, const TargetInstrInfo &TII,
+ InstructionMapper &Mapper,
+ std::vector<std::shared_ptr<Candidate>> &CandidateList,
+ std::vector<OutlinedFunction> &FunctionList);
/// \brief Replace the sequences of instructions represented by the
/// \p Candidates in \p CandidateList with calls to \p MachineFunctions
/// \param CandidateList A list of candidates to be outlined.
/// \param FunctionList A list of functions to be inserted into the module.
/// \param Mapper Contains the instruction mappings for the module.
- bool outline(Module &M, const ArrayRef<Candidate> &CandidateList,
+ bool outline(Module &M,
+ const ArrayRef<std::shared_ptr<Candidate>> &CandidateList,
std::vector<OutlinedFunction> &FunctionList,
InstructionMapper &Mapper);
/// \param TII TargetInstrInfo for the module.
///
/// \returns The length of the longest candidate found. 0 if there are none.
- unsigned buildCandidateList(std::vector<Candidate> &CandidateList,
- std::vector<OutlinedFunction> &FunctionList,
- SuffixTree &ST, InstructionMapper &Mapper,
- const TargetInstrInfo &TII);
+ unsigned
+ buildCandidateList(std::vector<std::shared_ptr<Candidate>> &CandidateList,
+ std::vector<OutlinedFunction> &FunctionList,
+ SuffixTree &ST, InstructionMapper &Mapper,
+ const TargetInstrInfo &TII);
/// Helper function for pruneOverlaps.
/// Removes \p C from the candidate list, and updates its \p OutlinedFunction.
/// \param Mapper Contains instruction mapping info for outlining.
/// \param MaxCandidateLen The length of the longest candidate.
/// \param TII TargetInstrInfo for the module.
- void pruneOverlaps(std::vector<Candidate> &CandidateList,
+ void pruneOverlaps(std::vector<std::shared_ptr<Candidate>> &CandidateList,
std::vector<OutlinedFunction> &FunctionList,
InstructionMapper &Mapper, unsigned MaxCandidateLen,
const TargetInstrInfo &TII);
INITIALIZE_PASS(MachineOutliner, DEBUG_TYPE, "Machine Function Outliner", false,
false)
-unsigned
-MachineOutliner::findCandidates(SuffixTree &ST, const TargetInstrInfo &TII,
- InstructionMapper &Mapper,
- std::vector<Candidate> &CandidateList,
- std::vector<OutlinedFunction> &FunctionList) {
+unsigned MachineOutliner::findCandidates(
+ SuffixTree &ST, const TargetInstrInfo &TII, InstructionMapper &Mapper,
+ std::vector<std::shared_ptr<Candidate>> &CandidateList,
+ std::vector<OutlinedFunction> &FunctionList) {
CandidateList.clear();
FunctionList.clear();
unsigned MaxLen = 0;
// At this point, the candidate class is seen as beneficial. Set their
// benefit values and save them in the candidate list.
+ std::vector<std::shared_ptr<Candidate>> CandidatesForFn;
for (Candidate &C : CandidatesForRepeatedSeq) {
C.Benefit = Benefit;
C.MInfo = MInfo;
- CandidateList.push_back(C);
+ std::shared_ptr<Candidate> Cptr = std::make_shared<Candidate>(C);
+ CandidateList.push_back(Cptr);
+ CandidatesForFn.push_back(Cptr);
}
FunctionList.push_back(OF);
+ FunctionList.back().Candidates = CandidatesForFn;
// Move to the next function.
Parent.IsInTree = false;
<< "\n";);
}
-void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList,
- std::vector<OutlinedFunction> &FunctionList,
- InstructionMapper &Mapper,
- unsigned MaxCandidateLen,
- const TargetInstrInfo &TII) {
+void MachineOutliner::pruneOverlaps(
+ std::vector<std::shared_ptr<Candidate>> &CandidateList,
+ std::vector<OutlinedFunction> &FunctionList, InstructionMapper &Mapper,
+ unsigned MaxCandidateLen, const TargetInstrInfo &TII) {
// Return true if this candidate became unbeneficial for outlining in a
// previous step.
// This is O(MaxCandidateLen * CandidateList.size()).
for (auto It = CandidateList.begin(), Et = CandidateList.end(); It != Et;
It++) {
- Candidate &C1 = *It;
+ Candidate &C1 = **It;
// If C1 was already pruned, or its function is no longer beneficial for
// outlining, move to the next candidate.
// FarthestPossibleIdx indices away from C1. There are at most
// MaxCandidateLen of these.
for (auto Sit = It + 1; Sit != Et; Sit++) {
- Candidate &C2 = *Sit;
+ Candidate &C2 = **Sit;
// Is this candidate too far away to overlap?
if (C2.getStartIdx() < FarthestPossibleIdx)
}
}
-unsigned
-MachineOutliner::buildCandidateList(std::vector<Candidate> &CandidateList,
- std::vector<OutlinedFunction> &FunctionList,
- SuffixTree &ST, InstructionMapper &Mapper,
- const TargetInstrInfo &TII) {
+unsigned MachineOutliner::buildCandidateList(
+ std::vector<std::shared_ptr<Candidate>> &CandidateList,
+ std::vector<OutlinedFunction> &FunctionList, SuffixTree &ST,
+ InstructionMapper &Mapper, const TargetInstrInfo &TII) {
std::vector<unsigned> CandidateSequence; // Current outlining candidate.
unsigned MaxCandidateLen = 0; // Length of the longest candidate.
// Sort the candidates in decending order. This will simplify the outlining
// process when we have to remove the candidates from the mapping by
// allowing us to cut them out without keeping track of an offset.
- std::stable_sort(CandidateList.begin(), CandidateList.end());
+ std::stable_sort(
+ CandidateList.begin(), CandidateList.end(),
+ [](const std::shared_ptr<Candidate> &LHS,
+ const std::shared_ptr<Candidate> &RHS) { return *LHS < *RHS; });
return MaxCandidateLen;
}
return &MF;
}
-bool MachineOutliner::outline(Module &M,
- const ArrayRef<Candidate> &CandidateList,
- std::vector<OutlinedFunction> &FunctionList,
- InstructionMapper &Mapper) {
+bool MachineOutliner::outline(
+ Module &M, const ArrayRef<std::shared_ptr<Candidate>> &CandidateList,
+ std::vector<OutlinedFunction> &FunctionList, InstructionMapper &Mapper) {
bool OutlinedSomething = false;
// Replace the candidates with calls to their respective outlined functions.
- for (const Candidate &C : CandidateList) {
-
+ for (const std::shared_ptr<Candidate> &Cptr : CandidateList) {
+ Candidate &C = *Cptr;
// Was the candidate removed during pruneOverlaps?
if (!C.InCandidateList)
continue;
// Does this candidate have a function yet?
if (!OF.MF) {
OF.MF = createOutlinedFunction(M, OF, Mapper);
+ MachineBasicBlock *MBB = &*OF.MF->begin();
+
+ // Output a remark telling the user that an outlined function was created,
+ // and explaining where it came from.
+ MachineOptimizationRemarkEmitter MORE(*OF.MF, nullptr);
+ MachineOptimizationRemark R(DEBUG_TYPE, "OutlinedFunction",
+ MBB->findDebugLoc(MBB->begin()), MBB);
+ R << "Saved " << NV("OutliningBenefit", OF.getBenefit())
+ << " instructions by "
+ << "outlining " << NV("Length", OF.Sequence.size()) << " instructions "
+ << "from " << NV("NumOccurrences", OF.getOccurrenceCount())
+ << " locations. "
+ << "(Found at: ";
+
+ // Tell the user the other places the candidate was found.
+ for (size_t i = 0, e = OF.Candidates.size(); i < e; i++) {
+
+ // Skip over things that were pruned.
+ if (!OF.Candidates[i]->InCandidateList)
+ continue;
+
+ R << NV(
+ (Twine("StartLoc") + Twine(i)).str(),
+ Mapper.InstrList[OF.Candidates[i]->getStartIdx()]->getDebugLoc());
+ if (i != e - 1)
+ R << ", ";
+ }
+
+ R << ")";
+
+ MORE.emit(R);
FunctionsCreated++;
}
// Construct a suffix tree, use it to find candidates, and then outline them.
SuffixTree ST(Mapper.UnsignedVec);
- std::vector<Candidate> CandidateList;
+ std::vector<std::shared_ptr<Candidate>> CandidateList;
std::vector<OutlinedFunction> FunctionList;
// Find all of the outlining candidates.
-; RUN: llc %s -enable-machine-outliner -mtriple=aarch64-unknown-unknown -pass-remarks-missed=machine-outliner -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc %s -enable-machine-outliner -mtriple=aarch64-unknown-unknown -pass-remarks=machine-outliner -pass-remarks-missed=machine-outliner -o /dev/null 2>&1 | FileCheck %s
; CHECK: machine-outliner-remarks.ll:5:9:
; CHECK-SAME: Did not outline 2 instructions from 2 locations.
; CHECK-SAME: Instructions from outlining all occurrences (9) >=
; CHECK-SAME: Unoutlined instruction count (4)
; CHECK-SAME: (Also found at: machine-outliner-remarks.ll:13:9)
+; CHECK: remark: <unknown>:0:0: Saved 5 instructions by outlining 7 instructions
+; CHECK-SAME: from 2 locations. (Found at: machine-outliner-remarks.ll:27:9,
+; CHECK-SAME: machine-outliner-remarks.ll:36:1)
; RUN: llc %s -enable-machine-outliner -mtriple=aarch64-unknown-unknown -o /dev/null -pass-remarks-missed=machine-outliner -pass-remarks-output=%t.yaml
; RUN: cat %t.yaml | FileCheck %s -check-prefix=YAML
; YAML: --- !Missed
; YAML-NEXT: - OtherStartLoc1: 'machine-outliner-remarks.ll:13:9'
; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 13, Column: 9 }
; YAML-NEXT: - String: ')'
+; YAML: --- !Passed
+; YAML-NEXT: Pass: machine-outliner
+; YAML-NEXT: Name: OutlinedFunction
+; YAML-NEXT: Function: OUTLINED_FUNCTION_0
+; YAML-NEXT: Args:
+; YAML-NEXT: - String: 'Saved '
+; YAML-NEXT: - OutliningBenefit: '5'
+; YAML-NEXT: - String: ' instructions by '
+; YAML-NEXT: - String: 'outlining '
+; YAML-NEXT: - Length: '7'
+; YAML-NEXT: - String: ' instructions '
+; YAML-NEXT: - String: 'from '
+; YAML-NEXT: - NumOccurrences: '2'
+; YAML-NEXT: - String: ' locations. '
+; YAML-NEXT: - String: '(Found at: '
+; YAML-NEXT: - StartLoc0: 'machine-outliner-remarks.ll:27:9'
+; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 27, Column: 9 }
+; YAML-NEXT: - String: ', '
+; YAML-NEXT: - StartLoc1: 'machine-outliner-remarks.ll:36:1'
+; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 36, Column: 1 }
+; YAML-NEXT: - String: ')'
define void @dog() #0 !dbg !8 {
entry:
%x = alloca i32, align 4
%y = alloca i32, align 4
- store i32 0, i32* %x, align 4, !dbg !11
+ store i32 0, i32* %x, align 4
store i32 1, i32* %y, align 4, !dbg !12
- ret void, !dbg !13
+ ret void
}
define void @cat() #0 !dbg !14 {
entry:
%x = alloca i32, align 4
%y = alloca i32, align 4
- store i32 0, i32* %x, align 4, !dbg !15
+ store i32 0, i32* %x, align 4
store i32 1, i32* %y, align 4, !dbg !16
- ret void, !dbg !17
+ ret void
+}
+
+define void @foo() #0 !dbg !18 {
+ %1 = alloca i32, align 4
+ %2 = alloca i32, align 4
+ %3 = alloca i32, align 4
+ %4 = alloca i32, align 4
+ store i32 0, i32* %1, align 4
+ store i32 1, i32* %2, align 4, !dbg !24
+ store i32 2, i32* %3, align 4
+ store i32 3, i32* %4, align 4, !dbg !26
+ ret void
+}
+
+define void @bar() #0 !dbg !27 {
+ %1 = alloca i32, align 4
+ %2 = alloca i32, align 4
+ %3 = alloca i32, align 4
+ %4 = alloca i32, align 4
+ store i32 0, i32* %1, align 4
+ store i32 1, i32* %2, align 4, !dbg !33
+ store i32 2, i32* %3, align 4
+ store i32 3, i32* %4, align 4, !dbg !35
+ ret void
}
attributes #0 = { noredzone nounwind ssp uwtable "no-frame-pointer-elim"="false" "target-cpu"="cyclone" }
!8 = distinct !DISubprogram(name: "dog", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
!9 = !DISubroutineType(types: !10)
!10 = !{null}
-!11 = !DILocation(line: 4, column: 9, scope: !8)
!12 = !DILocation(line: 5, column: 9, scope: !8)
-!13 = !DILocation(line: 6, column: 1, scope: !8)
!14 = distinct !DISubprogram(name: "cat", scope: !1, file: !1, line: 10, type: !9, isLocal: false, isDefinition: true, scopeLine: 11, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
-!15 = !DILocation(line: 12, column: 9, scope: !14)
!16 = !DILocation(line: 13, column: 9, scope: !14)
-!17 = !DILocation(line: 14, column: 1, scope: !14)
+!18 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 26, type: !9, isLocal: false, isDefinition: true, scopeLine: 26, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!24 = !DILocation(line: 27, column: 9, scope: !18)
+!26 = !DILocation(line: 29, column: 9, scope: !18)
+!27 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 35, type: !9, isLocal: false, isDefinition: true, scopeLine: 35, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!33 = !DILocation(line: 36, column: 1, scope: !27)
+!35 = !DILocation(line: 38, column: 1, scope: !27)
\ No newline at end of file