2016-07-16 01:23:20 +08:00
|
|
|
//===- OptimizationDiagnosticInfo.cpp - Optimization Diagnostic -*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Optimization diagnostic interfaces. It's packaged as an analysis pass so
|
|
|
|
// that by using this service passes become dependent on BFI as well. BFI is
|
|
|
|
// used to compute the "hotness" of the diagnostic message.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
|
2016-08-10 08:44:44 +08:00
|
|
|
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
2016-07-16 01:23:20 +08:00
|
|
|
#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
|
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-28 04:55:07 +08:00
|
|
|
#include "llvm/IR/DebugInfo.h"
|
2016-07-16 01:23:20 +08:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
2016-08-10 08:44:44 +08:00
|
|
|
#include "llvm/IR/Dominators.h"
|
2016-07-16 01:23:20 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2016-08-10 08:44:44 +08:00
|
|
|
OptimizationRemarkEmitter::OptimizationRemarkEmitter(Function *F)
|
|
|
|
: F(F), BFI(nullptr) {
|
|
|
|
if (!F->getContext().getDiagnosticHotnessRequested())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// First create a dominator tree.
|
|
|
|
DominatorTree DT;
|
|
|
|
DT.recalculate(*F);
|
|
|
|
|
|
|
|
// Generate LoopInfo from it.
|
|
|
|
LoopInfo LI;
|
|
|
|
LI.analyze(DT);
|
|
|
|
|
|
|
|
// Then compute BranchProbabilityInfo.
|
|
|
|
BranchProbabilityInfo BPI;
|
|
|
|
BPI.calculate(*F, LI);
|
|
|
|
|
|
|
|
// Finally compute BFI.
|
|
|
|
OwnedBFI = llvm::make_unique<BlockFrequencyInfo>(*F, BPI, LI);
|
|
|
|
BFI = OwnedBFI.get();
|
|
|
|
}
|
|
|
|
|
2017-01-15 16:20:50 +08:00
|
|
|
bool OptimizationRemarkEmitter::invalidate(
|
|
|
|
Function &F, const PreservedAnalyses &PA,
|
|
|
|
FunctionAnalysisManager::Invalidator &Inv) {
|
|
|
|
// This analysis has no state and so can be trivially preserved but it needs
|
|
|
|
// a fresh view of BFI if it was constructed with one.
|
|
|
|
if (BFI && Inv.invalidate<BlockFrequencyAnalysis>(F, PA))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Otherwise this analysis result remains valid.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-21 05:44:22 +08:00
|
|
|
Optional<uint64_t> OptimizationRemarkEmitter::computeHotness(const Value *V) {
|
2016-07-16 01:23:20 +08:00
|
|
|
if (!BFI)
|
|
|
|
return None;
|
|
|
|
|
|
|
|
return BFI->getBlockProfileCount(cast<BasicBlock>(V));
|
|
|
|
}
|
|
|
|
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-28 04:55:07 +08:00
|
|
|
namespace llvm {
|
|
|
|
namespace yaml {
|
|
|
|
|
2017-01-26 07:20:33 +08:00
|
|
|
void MappingTraits<DiagnosticInfoOptimizationBase *>::mapping(
|
|
|
|
IO &io, DiagnosticInfoOptimizationBase *&OptDiag) {
|
|
|
|
assert(io.outputting() && "input not yet implemented");
|
|
|
|
|
|
|
|
if (io.mapTag("!Passed", OptDiag->getKind() == DK_OptimizationRemark))
|
|
|
|
;
|
|
|
|
else if (io.mapTag("!Missed",
|
|
|
|
OptDiag->getKind() == DK_OptimizationRemarkMissed))
|
|
|
|
;
|
|
|
|
else if (io.mapTag("!Analysis",
|
|
|
|
OptDiag->getKind() == DK_OptimizationRemarkAnalysis))
|
|
|
|
;
|
|
|
|
else if (io.mapTag("!AnalysisFPCommute",
|
|
|
|
OptDiag->getKind() ==
|
|
|
|
DK_OptimizationRemarkAnalysisFPCommute))
|
|
|
|
;
|
|
|
|
else if (io.mapTag("!AnalysisAliasing",
|
|
|
|
OptDiag->getKind() ==
|
|
|
|
DK_OptimizationRemarkAnalysisAliasing))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
llvm_unreachable("todo");
|
|
|
|
|
|
|
|
// These are read-only for now.
|
|
|
|
DebugLoc DL = OptDiag->getDebugLoc();
|
|
|
|
StringRef FN =
|
|
|
|
GlobalValue::getRealLinkageName(OptDiag->getFunction().getName());
|
|
|
|
|
|
|
|
StringRef PassName(OptDiag->PassName);
|
|
|
|
io.mapRequired("Pass", PassName);
|
|
|
|
io.mapRequired("Name", OptDiag->RemarkName);
|
|
|
|
if (!io.outputting() || DL)
|
|
|
|
io.mapOptional("DebugLoc", DL);
|
|
|
|
io.mapRequired("Function", FN);
|
|
|
|
io.mapOptional("Hotness", OptDiag->Hotness);
|
|
|
|
io.mapOptional("Args", OptDiag->Args);
|
|
|
|
}
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-28 04:55:07 +08:00
|
|
|
|
|
|
|
template <> struct MappingTraits<DebugLoc> {
|
|
|
|
static void mapping(IO &io, DebugLoc &DL) {
|
|
|
|
assert(io.outputting() && "input not yet implemented");
|
|
|
|
|
|
|
|
auto *Scope = cast<DIScope>(DL.getScope());
|
|
|
|
StringRef File = Scope->getFilename();
|
|
|
|
unsigned Line = DL.getLine();
|
|
|
|
unsigned Col = DL.getCol();
|
|
|
|
|
|
|
|
io.mapRequired("File", File);
|
|
|
|
io.mapRequired("Line", Line);
|
|
|
|
io.mapRequired("Column", Col);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const bool flow = true;
|
|
|
|
};
|
|
|
|
|
2016-10-05 01:05:04 +08:00
|
|
|
// Implement this as a mapping for now to get proper quotation for the value.
|
|
|
|
template <> struct MappingTraits<DiagnosticInfoOptimizationBase::Argument> {
|
|
|
|
static void mapping(IO &io, DiagnosticInfoOptimizationBase::Argument &A) {
|
|
|
|
assert(io.outputting() && "input not yet implemented");
|
|
|
|
io.mapRequired(A.Key.data(), A.Val);
|
2016-11-08 06:41:13 +08:00
|
|
|
if (A.DLoc)
|
|
|
|
io.mapOptional("DebugLoc", A.DLoc);
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-28 04:55:07 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end namespace yaml
|
|
|
|
} // end namespace llvm
|
|
|
|
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(DiagnosticInfoOptimizationBase::Argument)
|
|
|
|
|
|
|
|
void OptimizationRemarkEmitter::computeHotness(
|
2017-01-26 07:20:25 +08:00
|
|
|
DiagnosticInfoIROptimization &OptDiag) {
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-28 04:55:07 +08:00
|
|
|
Value *V = OptDiag.getCodeRegion();
|
|
|
|
if (V)
|
|
|
|
OptDiag.setHotness(computeHotness(V));
|
|
|
|
}
|
|
|
|
|
2017-01-26 07:20:25 +08:00
|
|
|
void OptimizationRemarkEmitter::emit(
|
|
|
|
DiagnosticInfoOptimizationBase &OptDiagBase) {
|
|
|
|
auto &OptDiag = cast<DiagnosticInfoIROptimization>(OptDiagBase);
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-28 04:55:07 +08:00
|
|
|
computeHotness(OptDiag);
|
|
|
|
|
|
|
|
yaml::Output *Out = F->getContext().getDiagnosticsOutputFile();
|
2016-10-05 02:13:45 +08:00
|
|
|
if (Out) {
|
2017-01-26 07:20:25 +08:00
|
|
|
auto *P = const_cast<DiagnosticInfoOptimizationBase *>(&OptDiagBase);
|
Output optimization remarks in YAML
(Re-committed after moving the template specialization under the yaml
namespace. GCC was complaining about this.)
This allows various presentation of this data using an external tool.
This was first recommended here[1].
As an example, consider this module:
1 int foo();
2 int bar();
3
4 int baz() {
5 return foo() + bar();
6 }
The inliner generates these missed-optimization remarks today (the
hotness information is pulled from PGO):
remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
Now with -pass-remarks-output=<yaml-file>, we generate this YAML file:
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
Function: baz
Hotness: 30
Args:
- Callee: foo
- String: will not be inlined into
- Caller: baz
...
--- !Missed
Pass: inline
Name: NotInlined
DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
Function: baz
Hotness: 30
Args:
- Callee: bar
- String: will not be inlined into
- Caller: baz
...
This is a summary of the high-level decisions:
* There is a new streaming interface to emit optimization remarks.
E.g. for the inliner remark above:
ORE.emit(DiagnosticInfoOptimizationRemarkMissed(
DEBUG_TYPE, "NotInlined", &I)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", CS.getCaller()) << setIsVerbose());
NV stands for named value and allows the YAML client to process a remark
using its name (NotInlined) and the named arguments (Callee and Caller)
without parsing the text of the message.
Subsequent patches will update ORE users to use the new streaming API.
* I am using YAML I/O for writing the YAML file. YAML I/O requires you
to specify reading and writing at once but reading is highly non-trivial
for some of the more complex LLVM types. Since it's not clear that we
(ever) want to use LLVM to parse this YAML file, the code supports and
asserts that we're writing only.
On the other hand, I did experiment that the class hierarchy starting at
DiagnosticInfoOptimizationBase can be mapped back from YAML generated
here (see D24479).
* The YAML stream is stored in the LLVM context.
* In the example, we can probably further specify the IR value used,
i.e. print "Function" rather than "Value".
* As before hotness is computed in the analysis pass instead of
DiganosticInfo. This avoids the layering problem since BFI is in
Analysis while DiagnosticInfo is in IR.
[1] https://reviews.llvm.org/D19678#419445
Differential Revision: https://reviews.llvm.org/D24587
llvm-svn: 282539
2016-09-28 04:55:07 +08:00
|
|
|
*Out << P;
|
|
|
|
}
|
|
|
|
// FIXME: now that IsVerbose is part of DI, filtering for this will be moved
|
|
|
|
// from here to clang.
|
|
|
|
if (!OptDiag.isVerbose() || shouldEmitVerbose())
|
|
|
|
F->getContext().diagnose(OptDiag);
|
|
|
|
}
|
|
|
|
|
2016-07-21 09:07:13 +08:00
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemark(const char *PassName,
|
|
|
|
const DebugLoc &DLoc,
|
|
|
|
const Value *V,
|
|
|
|
const Twine &Msg) {
|
|
|
|
LLVMContext &Ctx = F->getContext();
|
2016-09-28 06:19:23 +08:00
|
|
|
Ctx.diagnose(OptimizationRemark(PassName, *F, DLoc, Msg, computeHotness(V)));
|
2016-07-21 09:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemark(const char *PassName,
|
|
|
|
Loop *L,
|
|
|
|
const Twine &Msg) {
|
|
|
|
emitOptimizationRemark(PassName, L->getStartLoc(), L->getHeader(), Msg);
|
|
|
|
}
|
|
|
|
|
2016-07-16 01:23:20 +08:00
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemarkMissed(
|
2016-07-21 05:44:22 +08:00
|
|
|
const char *PassName, const DebugLoc &DLoc, const Value *V,
|
2016-08-27 04:21:05 +08:00
|
|
|
const Twine &Msg, bool IsVerbose) {
|
2016-07-16 01:23:20 +08:00
|
|
|
LLVMContext &Ctx = F->getContext();
|
2016-08-27 04:21:05 +08:00
|
|
|
if (!IsVerbose || shouldEmitVerbose())
|
2016-09-28 06:19:23 +08:00
|
|
|
Ctx.diagnose(
|
|
|
|
OptimizationRemarkMissed(PassName, *F, DLoc, Msg, computeHotness(V)));
|
2016-07-16 01:23:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemarkMissed(
|
2016-08-27 04:21:05 +08:00
|
|
|
const char *PassName, Loop *L, const Twine &Msg, bool IsVerbose) {
|
|
|
|
emitOptimizationRemarkMissed(PassName, L->getStartLoc(), L->getHeader(), Msg,
|
|
|
|
IsVerbose);
|
2016-07-16 01:23:20 +08:00
|
|
|
}
|
|
|
|
|
2016-07-21 05:44:26 +08:00
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysis(
|
|
|
|
const char *PassName, const DebugLoc &DLoc, const Value *V,
|
2016-08-27 04:21:05 +08:00
|
|
|
const Twine &Msg, bool IsVerbose) {
|
2016-07-21 05:44:26 +08:00
|
|
|
LLVMContext &Ctx = F->getContext();
|
2016-08-27 04:21:05 +08:00
|
|
|
if (!IsVerbose || shouldEmitVerbose())
|
2016-09-28 06:19:23 +08:00
|
|
|
Ctx.diagnose(
|
|
|
|
OptimizationRemarkAnalysis(PassName, *F, DLoc, Msg, computeHotness(V)));
|
2016-07-21 05:44:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysis(
|
2016-08-27 04:21:05 +08:00
|
|
|
const char *PassName, Loop *L, const Twine &Msg, bool IsVerbose) {
|
2016-07-21 05:44:26 +08:00
|
|
|
emitOptimizationRemarkAnalysis(PassName, L->getStartLoc(), L->getHeader(),
|
2016-08-27 04:21:05 +08:00
|
|
|
Msg, IsVerbose);
|
2016-07-21 05:44:26 +08:00
|
|
|
}
|
|
|
|
|
2016-07-21 07:50:32 +08:00
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysisFPCommute(
|
2016-07-21 09:11:12 +08:00
|
|
|
const char *PassName, const DebugLoc &DLoc, const Value *V,
|
|
|
|
const Twine &Msg) {
|
2016-07-21 07:50:32 +08:00
|
|
|
LLVMContext &Ctx = F->getContext();
|
2016-09-28 06:19:23 +08:00
|
|
|
Ctx.diagnose(OptimizationRemarkAnalysisFPCommute(PassName, *F, DLoc, Msg,
|
|
|
|
computeHotness(V)));
|
2016-07-21 07:50:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysisAliasing(
|
2016-07-21 09:11:12 +08:00
|
|
|
const char *PassName, const DebugLoc &DLoc, const Value *V,
|
|
|
|
const Twine &Msg) {
|
2016-07-21 07:50:32 +08:00
|
|
|
LLVMContext &Ctx = F->getContext();
|
2016-09-28 06:19:23 +08:00
|
|
|
Ctx.diagnose(OptimizationRemarkAnalysisAliasing(PassName, *F, DLoc, Msg,
|
|
|
|
computeHotness(V)));
|
2016-07-21 07:50:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysisAliasing(
|
|
|
|
const char *PassName, Loop *L, const Twine &Msg) {
|
|
|
|
emitOptimizationRemarkAnalysisAliasing(PassName, L->getStartLoc(),
|
|
|
|
L->getHeader(), Msg);
|
|
|
|
}
|
|
|
|
|
2016-07-19 00:29:21 +08:00
|
|
|
OptimizationRemarkEmitterWrapperPass::OptimizationRemarkEmitterWrapperPass()
|
|
|
|
: FunctionPass(ID) {
|
|
|
|
initializeOptimizationRemarkEmitterWrapperPassPass(
|
|
|
|
*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OptimizationRemarkEmitterWrapperPass::runOnFunction(Function &Fn) {
|
|
|
|
BlockFrequencyInfo *BFI;
|
2016-07-16 01:23:20 +08:00
|
|
|
|
|
|
|
if (Fn.getContext().getDiagnosticHotnessRequested())
|
|
|
|
BFI = &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
|
|
|
|
else
|
|
|
|
BFI = nullptr;
|
|
|
|
|
2016-07-19 00:29:21 +08:00
|
|
|
ORE = llvm::make_unique<OptimizationRemarkEmitter>(&Fn, BFI);
|
2016-07-16 01:23:20 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-19 00:29:21 +08:00
|
|
|
void OptimizationRemarkEmitterWrapperPass::getAnalysisUsage(
|
|
|
|
AnalysisUsage &AU) const {
|
2016-07-16 01:23:20 +08:00
|
|
|
LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
|
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
|
2016-11-24 01:53:26 +08:00
|
|
|
AnalysisKey OptimizationRemarkEmitterAnalysis::Key;
|
2016-07-19 00:29:21 +08:00
|
|
|
|
|
|
|
OptimizationRemarkEmitter
|
2016-07-21 05:44:18 +08:00
|
|
|
OptimizationRemarkEmitterAnalysis::run(Function &F,
|
2016-08-09 08:28:15 +08:00
|
|
|
FunctionAnalysisManager &AM) {
|
2016-07-19 00:29:21 +08:00
|
|
|
BlockFrequencyInfo *BFI;
|
|
|
|
|
|
|
|
if (F.getContext().getDiagnosticHotnessRequested())
|
|
|
|
BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
|
|
|
|
else
|
|
|
|
BFI = nullptr;
|
|
|
|
|
|
|
|
return OptimizationRemarkEmitter(&F, BFI);
|
|
|
|
}
|
|
|
|
|
|
|
|
char OptimizationRemarkEmitterWrapperPass::ID = 0;
|
2016-07-16 01:23:20 +08:00
|
|
|
static const char ore_name[] = "Optimization Remark Emitter";
|
|
|
|
#define ORE_NAME "opt-remark-emitter"
|
|
|
|
|
2016-07-19 00:29:21 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
|
|
|
|
false, true)
|
2016-07-16 01:23:20 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(LazyBFIPass)
|
2016-07-19 00:29:21 +08:00
|
|
|
INITIALIZE_PASS_END(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
|
|
|
|
false, true)
|