mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +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:
parent
cc9ffa76b1
commit
c60e9d2649
@ -149,6 +149,8 @@ private:
|
||||
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;
|
||||
@ -807,10 +809,11 @@ struct MachineOutliner : public ModulePass {
|
||||
/// 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
|
||||
@ -820,7 +823,8 @@ struct MachineOutliner : public ModulePass {
|
||||
/// \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);
|
||||
|
||||
@ -841,10 +845,11 @@ struct MachineOutliner : public ModulePass {
|
||||
/// \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.
|
||||
@ -863,7 +868,7 @@ struct MachineOutliner : public ModulePass {
|
||||
/// \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);
|
||||
@ -887,11 +892,10 @@ ModulePass *createMachineOutlinerPass(bool OutlineFromLinkOnceODRs) {
|
||||
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;
|
||||
@ -1004,13 +1008,17 @@ MachineOutliner::findCandidates(SuffixTree &ST, const TargetInstrInfo &TII,
|
||||
|
||||
// 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;
|
||||
@ -1038,11 +1046,10 @@ void MachineOutliner::prune(Candidate &C,
|
||||
<< "\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.
|
||||
@ -1069,7 +1076,7 @@ void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList,
|
||||
// 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.
|
||||
@ -1088,7 +1095,7 @@ void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList,
|
||||
// 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)
|
||||
@ -1130,11 +1137,10 @@ void MachineOutliner::pruneOverlaps(std::vector<Candidate> &CandidateList,
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@ -1145,7 +1151,10 @@ MachineOutliner::buildCandidateList(std::vector<Candidate> &CandidateList,
|
||||
// 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;
|
||||
}
|
||||
@ -1204,15 +1213,14 @@ MachineOutliner::createOutlinedFunction(Module &M, const OutlinedFunction &OF,
|
||||
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;
|
||||
@ -1240,6 +1248,37 @@ bool MachineOutliner::outline(Module &M,
|
||||
// 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++;
|
||||
}
|
||||
|
||||
@ -1300,7 +1339,7 @@ bool MachineOutliner::runOnModule(Module &M) {
|
||||
|
||||
// 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.
|
||||
|
@ -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-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
|
||||
@ -28,23 +31,68 @@
|
||||
; 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" }
|
||||
@ -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)
|
||||
!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)
|
Loading…
Reference in New Issue
Block a user