1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 11:42:57 +01:00

[MachineOutliner] Add optimisation remarks for successful outlining

This commit adds optimisation remarks for outlining which fire when a function
is successfully outlined.

To do this, OutlinedFunctions must now contain references to their Candidates.
Since the Candidates must still be sorted and worked on separately, this is
done by working on everything in terms of shared_ptrs to Candidates. This is
good; it means that we can easily move everything to outlining in terms of
the OutlinedFunctions rather than the individual Candidates. This is far more
intuitive than what's currently there!

(Remarks are output when a function is created for some group of Candidates.
In a later commit, all of the outlining logic should be rewritten so that we
loop over OutlinedFunctions rather than over Candidates.)
 

llvm-svn: 316396
This commit is contained in:
Jessica Paquette 2017-10-23 23:36:46 +00:00
parent cc9ffa76b1
commit c60e9d2649
2 changed files with 134 additions and 45 deletions

View File

@ -149,6 +149,8 @@ private:
unsigned OccurrenceCount = 0; unsigned OccurrenceCount = 0;
public: public:
std::vector<std::shared_ptr<Candidate>> Candidates;
/// The actual outlined function created. /// The actual outlined function created.
/// This is initialized after we go through and create the actual function. /// This is initialized after we go through and create the actual function.
MachineFunction *MF = nullptr; MachineFunction *MF = nullptr;
@ -807,10 +809,11 @@ struct MachineOutliner : public ModulePass {
/// type of candidate. /// type of candidate.
/// ///
/// \returns The length of the longest candidate found. /// \returns The length of the longest candidate found.
unsigned findCandidates(SuffixTree &ST, const TargetInstrInfo &TII, unsigned
InstructionMapper &Mapper, findCandidates(SuffixTree &ST, const TargetInstrInfo &TII,
std::vector<Candidate> &CandidateList, InstructionMapper &Mapper,
std::vector<OutlinedFunction> &FunctionList); std::vector<std::shared_ptr<Candidate>> &CandidateList,
std::vector<OutlinedFunction> &FunctionList);
/// \brief Replace the sequences of instructions represented by the /// \brief Replace the sequences of instructions represented by the
/// \p Candidates in \p CandidateList with calls to \p MachineFunctions /// \p Candidates in \p CandidateList with calls to \p MachineFunctions
@ -820,7 +823,8 @@ struct MachineOutliner : public ModulePass {
/// \param CandidateList A list of candidates to be outlined. /// \param CandidateList A list of candidates to be outlined.
/// \param FunctionList A list of functions to be inserted into the module. /// \param FunctionList A list of functions to be inserted into the module.
/// \param Mapper Contains the instruction mappings for 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, std::vector<OutlinedFunction> &FunctionList,
InstructionMapper &Mapper); InstructionMapper &Mapper);
@ -841,10 +845,11 @@ struct MachineOutliner : public ModulePass {
/// \param TII TargetInstrInfo for the module. /// \param TII TargetInstrInfo for the module.
/// ///
/// \returns The length of the longest candidate found. 0 if there are none. /// \returns The length of the longest candidate found. 0 if there are none.
unsigned buildCandidateList(std::vector<Candidate> &CandidateList, unsigned
std::vector<OutlinedFunction> &FunctionList, buildCandidateList(std::vector<std::shared_ptr<Candidate>> &CandidateList,
SuffixTree &ST, InstructionMapper &Mapper, std::vector<OutlinedFunction> &FunctionList,
const TargetInstrInfo &TII); SuffixTree &ST, InstructionMapper &Mapper,
const TargetInstrInfo &TII);
/// Helper function for pruneOverlaps. /// Helper function for pruneOverlaps.
/// Removes \p C from the candidate list, and updates its \p OutlinedFunction. /// Removes \p C from the candidate list, and updates its \p OutlinedFunction.
@ -863,7 +868,7 @@ struct MachineOutliner : public ModulePass {
/// \param Mapper Contains instruction mapping info for outlining. /// \param Mapper Contains instruction mapping info for outlining.
/// \param MaxCandidateLen The length of the longest candidate. /// \param MaxCandidateLen The length of the longest candidate.
/// \param TII TargetInstrInfo for the module. /// \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, std::vector<OutlinedFunction> &FunctionList,
InstructionMapper &Mapper, unsigned MaxCandidateLen, InstructionMapper &Mapper, unsigned MaxCandidateLen,
const TargetInstrInfo &TII); const TargetInstrInfo &TII);
@ -887,11 +892,10 @@ ModulePass *createMachineOutlinerPass(bool OutlineFromLinkOnceODRs) {
INITIALIZE_PASS(MachineOutliner, DEBUG_TYPE, "Machine Function Outliner", false, INITIALIZE_PASS(MachineOutliner, DEBUG_TYPE, "Machine Function Outliner", false,
false) false)
unsigned unsigned MachineOutliner::findCandidates(
MachineOutliner::findCandidates(SuffixTree &ST, const TargetInstrInfo &TII, SuffixTree &ST, const TargetInstrInfo &TII, InstructionMapper &Mapper,
InstructionMapper &Mapper, std::vector<std::shared_ptr<Candidate>> &CandidateList,
std::vector<Candidate> &CandidateList, std::vector<OutlinedFunction> &FunctionList) {
std::vector<OutlinedFunction> &FunctionList) {
CandidateList.clear(); CandidateList.clear();
FunctionList.clear(); FunctionList.clear();
unsigned MaxLen = 0; unsigned MaxLen = 0;
@ -1004,13 +1008,17 @@ MachineOutliner::findCandidates(SuffixTree &ST, const TargetInstrInfo &TII,
// At this point, the candidate class is seen as beneficial. Set their // At this point, the candidate class is seen as beneficial. Set their
// benefit values and save them in the candidate list. // benefit values and save them in the candidate list.
std::vector<std::shared_ptr<Candidate>> CandidatesForFn;
for (Candidate &C : CandidatesForRepeatedSeq) { for (Candidate &C : CandidatesForRepeatedSeq) {
C.Benefit = Benefit; C.Benefit = Benefit;
C.MInfo = MInfo; 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.push_back(OF);
FunctionList.back().Candidates = CandidatesForFn;
// Move to the next function. // Move to the next function.
Parent.IsInTree = false; Parent.IsInTree = false;
@ -1038,11 +1046,10 @@ void MachineOutliner::prune(Candidate &C,
<< "\n";); << "\n";);
} }
void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList, void MachineOutliner::pruneOverlaps(
std::vector<OutlinedFunction> &FunctionList, std::vector<std::shared_ptr<Candidate>> &CandidateList,
InstructionMapper &Mapper, std::vector<OutlinedFunction> &FunctionList, InstructionMapper &Mapper,
unsigned MaxCandidateLen, unsigned MaxCandidateLen, const TargetInstrInfo &TII) {
const TargetInstrInfo &TII) {
// Return true if this candidate became unbeneficial for outlining in a // Return true if this candidate became unbeneficial for outlining in a
// previous step. // previous step.
@ -1069,7 +1076,7 @@ void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList,
// This is O(MaxCandidateLen * CandidateList.size()). // This is O(MaxCandidateLen * CandidateList.size()).
for (auto It = CandidateList.begin(), Et = CandidateList.end(); It != Et; for (auto It = CandidateList.begin(), Et = CandidateList.end(); It != Et;
It++) { It++) {
Candidate &C1 = *It; Candidate &C1 = **It;
// If C1 was already pruned, or its function is no longer beneficial for // If C1 was already pruned, or its function is no longer beneficial for
// outlining, move to the next candidate. // outlining, move to the next candidate.
@ -1088,7 +1095,7 @@ void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList,
// FarthestPossibleIdx indices away from C1. There are at most // FarthestPossibleIdx indices away from C1. There are at most
// MaxCandidateLen of these. // MaxCandidateLen of these.
for (auto Sit = It + 1; Sit != Et; Sit++) { for (auto Sit = It + 1; Sit != Et; Sit++) {
Candidate &C2 = *Sit; Candidate &C2 = **Sit;
// Is this candidate too far away to overlap? // Is this candidate too far away to overlap?
if (C2.getStartIdx() < FarthestPossibleIdx) if (C2.getStartIdx() < FarthestPossibleIdx)
@ -1130,11 +1137,10 @@ void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList,
} }
} }
unsigned unsigned MachineOutliner::buildCandidateList(
MachineOutliner::buildCandidateList(std::vector<Candidate> &CandidateList, std::vector<std::shared_ptr<Candidate>> &CandidateList,
std::vector<OutlinedFunction> &FunctionList, std::vector<OutlinedFunction> &FunctionList, SuffixTree &ST,
SuffixTree &ST, InstructionMapper &Mapper, InstructionMapper &Mapper, const TargetInstrInfo &TII) {
const TargetInstrInfo &TII) {
std::vector<unsigned> CandidateSequence; // Current outlining candidate. std::vector<unsigned> CandidateSequence; // Current outlining candidate.
unsigned MaxCandidateLen = 0; // Length of the longest candidate. unsigned MaxCandidateLen = 0; // Length of the longest candidate.
@ -1145,7 +1151,10 @@ MachineOutliner::buildCandidateList(std::vector<Candidate> &CandidateList,
// Sort the candidates in decending order. This will simplify the outlining // Sort the candidates in decending order. This will simplify the outlining
// process when we have to remove the candidates from the mapping by // process when we have to remove the candidates from the mapping by
// allowing us to cut them out without keeping track of an offset. // 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 MaxCandidateLen;
} }
@ -1204,15 +1213,14 @@ MachineOutliner::createOutlinedFunction(Module &M, const OutlinedFunction &OF,
return &MF; return &MF;
} }
bool MachineOutliner::outline(Module &M, bool MachineOutliner::outline(
const ArrayRef<Candidate> &CandidateList, Module &M, const ArrayRef<std::shared_ptr<Candidate>> &CandidateList,
std::vector<OutlinedFunction> &FunctionList, std::vector<OutlinedFunction> &FunctionList, InstructionMapper &Mapper) {
InstructionMapper &Mapper) {
bool OutlinedSomething = false; bool OutlinedSomething = false;
// Replace the candidates with calls to their respective outlined functions. // 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? // Was the candidate removed during pruneOverlaps?
if (!C.InCandidateList) if (!C.InCandidateList)
continue; continue;
@ -1240,6 +1248,37 @@ bool MachineOutliner::outline(Module &M,
// Does this candidate have a function yet? // Does this candidate have a function yet?
if (!OF.MF) { if (!OF.MF) {
OF.MF = createOutlinedFunction(M, OF, Mapper); 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++; FunctionsCreated++;
} }
@ -1300,7 +1339,7 @@ bool MachineOutliner::runOnModule(Module &M) {
// Construct a suffix tree, use it to find candidates, and then outline them. // Construct a suffix tree, use it to find candidates, and then outline them.
SuffixTree ST(Mapper.UnsignedVec); SuffixTree ST(Mapper.UnsignedVec);
std::vector<Candidate> CandidateList; std::vector<std::shared_ptr<Candidate>> CandidateList;
std::vector<OutlinedFunction> FunctionList; std::vector<OutlinedFunction> FunctionList;
// Find all of the outlining candidates. // Find all of the outlining candidates.

View File

@ -1,9 +1,12 @@
; 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: machine-outliner-remarks.ll:5:9:
; CHECK-SAME: Did not outline 2 instructions from 2 locations. ; CHECK-SAME: Did not outline 2 instructions from 2 locations.
; CHECK-SAME: Instructions from outlining all occurrences (9) >= ; CHECK-SAME: Instructions from outlining all occurrences (9) >=
; CHECK-SAME: Unoutlined instruction count (4) ; CHECK-SAME: Unoutlined instruction count (4)
; CHECK-SAME: (Also found at: machine-outliner-remarks.ll:13:9) ; 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: 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 ; RUN: cat %t.yaml | FileCheck %s -check-prefix=YAML
; YAML: --- !Missed ; YAML: --- !Missed
@ -28,23 +31,68 @@
; YAML-NEXT: - OtherStartLoc1: 'machine-outliner-remarks.ll:13:9' ; YAML-NEXT: - OtherStartLoc1: 'machine-outliner-remarks.ll:13:9'
; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 13, Column: 9 } ; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 13, Column: 9 }
; YAML-NEXT: - String: ')' ; 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 { define void @dog() #0 !dbg !8 {
entry: entry:
%x = alloca i32, align 4 %x = alloca i32, align 4
%y = 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 store i32 1, i32* %y, align 4, !dbg !12
ret void, !dbg !13 ret void
} }
define void @cat() #0 !dbg !14 { define void @cat() #0 !dbg !14 {
entry: entry:
%x = alloca i32, align 4 %x = alloca i32, align 4
%y = 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 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" } attributes #0 = { noredzone nounwind ssp uwtable "no-frame-pointer-elim"="false" "target-cpu"="cyclone" }
@ -64,10 +112,12 @@ attributes #0 = { noredzone nounwind ssp uwtable "no-frame-pointer-elim"="false"
!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) !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) !9 = !DISubroutineType(types: !10)
!10 = !{null} !10 = !{null}
!11 = !DILocation(line: 4, column: 9, scope: !8)
!12 = !DILocation(line: 5, 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) !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) !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)