2017-10-10 07:19:02 +08:00
|
|
|
//===- OptimizationRemarkEmitter.cpp - Optimization Diagnostic --*- C++ -*-===//
|
2016-07-16 01:23:20 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2016-07-16 01:23:20 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-10-10 07:19:02 +08:00
|
|
|
#include "llvm/Analysis/OptimizationRemarkEmitter.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"
|
|
|
|
#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;
|
|
|
|
|
2017-02-22 15:38:17 +08:00
|
|
|
OptimizationRemarkEmitter::OptimizationRemarkEmitter(const Function *F)
|
2016-08-10 08:44:44 +08:00
|
|
|
: F(F), BFI(nullptr) {
|
[ORE] Unify spelling as "diagnostics hotness"
Summary:
To enable profile hotness information in diagnostics output, Clang takes
the option `-fdiagnostics-show-hotness` -- that's "diagnostics", with an
"s" at the end. Clang also defines `CodeGenOptions::DiagnosticsWithHotness`.
LLVM, on the other hand, defines
`LLVMContext::getDiagnosticHotnessRequested` -- that's "diagnostic", not
"diagnostics". It's a small difference, but it's confusing, typo-inducing, and
frustrating.
Add a new method with the spelling "diagnostics", and "deprecate" the
old spelling.
Reviewers: anemet, davidxl
Reviewed By: anemet
Subscribers: llvm-commits, mehdi_amini
Differential Revision: https://reviews.llvm.org/D34864
llvm-svn: 306848
2017-07-01 02:13:59 +08:00
|
|
|
if (!F->getContext().getDiagnosticsHotnessRequested())
|
2016-08-10 08:44:44 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// First create a dominator tree.
|
|
|
|
DominatorTree DT;
|
2017-02-22 15:38:17 +08:00
|
|
|
DT.recalculate(*const_cast<Function *>(F));
|
2016-08-10 08:44:44 +08:00
|
|
|
|
|
|
|
// Generate LoopInfo from it.
|
|
|
|
LoopInfo LI;
|
|
|
|
LI.analyze(DT);
|
|
|
|
|
|
|
|
// Then compute BranchProbabilityInfo.
|
|
|
|
BranchProbabilityInfo BPI;
|
|
|
|
BPI.calculate(*F, LI);
|
|
|
|
|
|
|
|
// Finally compute BFI.
|
2019-08-15 23:54:37 +08:00
|
|
|
OwnedBFI = std::make_unique<BlockFrequencyInfo>(*F, BPI, LI);
|
2016-08-10 08:44:44 +08:00
|
|
|
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
|
|
|
void OptimizationRemarkEmitter::computeHotness(
|
2017-01-26 07:20:25 +08:00
|
|
|
DiagnosticInfoIROptimization &OptDiag) {
|
2017-02-22 15:38:17 +08:00
|
|
|
const Value *V = OptDiag.getCodeRegion();
|
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
|
|
|
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);
|
2017-12-02 04:41:38 +08:00
|
|
|
|
|
|
|
// Only emit it if its hotness meets the threshold.
|
|
|
|
if (OptDiag.getHotness().getValueOr(0) <
|
|
|
|
F->getContext().getDiagnosticsHotnessThreshold()) {
|
2017-07-01 07:14:53 +08:00
|
|
|
return;
|
|
|
|
}
|
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
|
|
|
|
2017-10-04 12:26:23 +08:00
|
|
|
F->getContext().diagnose(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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
[ORE] Unify spelling as "diagnostics hotness"
Summary:
To enable profile hotness information in diagnostics output, Clang takes
the option `-fdiagnostics-show-hotness` -- that's "diagnostics", with an
"s" at the end. Clang also defines `CodeGenOptions::DiagnosticsWithHotness`.
LLVM, on the other hand, defines
`LLVMContext::getDiagnosticHotnessRequested` -- that's "diagnostic", not
"diagnostics". It's a small difference, but it's confusing, typo-inducing, and
frustrating.
Add a new method with the spelling "diagnostics", and "deprecate" the
old spelling.
Reviewers: anemet, davidxl
Reviewed By: anemet
Subscribers: llvm-commits, mehdi_amini
Differential Revision: https://reviews.llvm.org/D34864
llvm-svn: 306848
2017-07-01 02:13:59 +08:00
|
|
|
if (Fn.getContext().getDiagnosticsHotnessRequested())
|
2016-07-16 01:23:20 +08:00
|
|
|
BFI = &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
|
|
|
|
else
|
|
|
|
BFI = nullptr;
|
|
|
|
|
2019-08-15 23:54:37 +08:00
|
|
|
ORE = std::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;
|
|
|
|
|
[ORE] Unify spelling as "diagnostics hotness"
Summary:
To enable profile hotness information in diagnostics output, Clang takes
the option `-fdiagnostics-show-hotness` -- that's "diagnostics", with an
"s" at the end. Clang also defines `CodeGenOptions::DiagnosticsWithHotness`.
LLVM, on the other hand, defines
`LLVMContext::getDiagnosticHotnessRequested` -- that's "diagnostic", not
"diagnostics". It's a small difference, but it's confusing, typo-inducing, and
frustrating.
Add a new method with the spelling "diagnostics", and "deprecate" the
old spelling.
Reviewers: anemet, davidxl
Reviewed By: anemet
Subscribers: llvm-commits, mehdi_amini
Differential Revision: https://reviews.llvm.org/D34864
llvm-svn: 306848
2017-07-01 02:13:59 +08:00
|
|
|
if (F.getContext().getDiagnosticsHotnessRequested())
|
2016-07-19 00:29:21 +08:00
|
|
|
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)
|