1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00

[llvm-opt-report] Distinguish inlined contexts when optimizations differ

How code is optimized sometimes, perhaps often, depends on the context into
which it was inlined. This change allows llvm-opt-report to track the
differences between the optimizations performed, or not, in different contexts,
and when these differ, display those differences.

For example, this code:

  $ cat /tmp/q.cpp
  void bar();
  void foo(int n) {
    for (int i = 0; i < n; ++i)
      bar();
  }

  void quack() {
    foo(4);
  }

  void quack2() {
    foo(4);
  }

will now produce this report:

  < /home/hfinkel/src/llvm/test/tools/llvm-opt-report/Inputs/q.cpp
   2         | void bar();
   3         | void foo(int n) {
   [[
    > foo(int):
   4         |   for (int i = 0; i < n; ++i)
    > quack(), quack2():
   4  U4     |   for (int i = 0; i < n; ++i)
   ]]
   5         |     bar();
   6         | }
   7         |
   8         | void quack() {
   9 I       |   foo(4);
  10         | }
  11         |
  12         | void quack2() {
  13 I       |   foo(4);
  14         | }
  15         |

Note that the tool has demangled the function names, and grouped the reports
associated with line 4. This shows that the loop on line 4 was unrolled by a
factor of 4 when inlined into the functions quack() and quack2(), but not in
the function foo(int) itself.

llvm-svn: 283402
This commit is contained in:
Hal Finkel 2016-10-05 22:25:33 +00:00
parent 77c7c501d3
commit 989b264cc2
11 changed files with 681 additions and 76 deletions

View File

@ -0,0 +1,14 @@
void bar();
void foo(int n) {
for (int i = 0; i < n; ++i)
bar();
}
void quack() {
foo(4);
}
void quack2() {
foo(4);
}

View File

@ -0,0 +1,14 @@
void bar();
void foo(int n) {
for (int i = 0; i < n; ++i)
bar();
}
void quack() {
foo(4);
}
void quack2() {
foo(4);
}

View File

@ -0,0 +1,98 @@
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: Inputs/q.c, Line: 4, Column: 5 }
Function: foo
Args:
- Callee: bar
- String: ' will not be inlined into '
- Caller: foo
- String: ' because its definition is unavailable'
...
--- !Analysis
Pass: inline
Name: CanBeInlined
DebugLoc: { File: Inputs/q.c, Line: 8, Column: 3 }
Function: quack
Args:
- Callee: foo
- String: ' can be inlined into '
- Caller: quack
- String: ' with cost='
- Cost: '40'
- String: ' (threshold='
- Threshold: '275'
- String: ')'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: Inputs/q.c, Line: 8, Column: 3 }
Function: quack
Args:
- Callee: foo
- String: ' inlined into '
- Caller: quack
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q.c, Line: 3, Column: 3 }
Function: quack
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Analysis
Pass: inline
Name: CanBeInlined
DebugLoc: { File: Inputs/q.c, Line: 12, Column: 3 }
Function: quack2
Args:
- Callee: foo
- String: ' can be inlined into '
- Caller: quack2
- String: ' with cost='
- Cost: '40'
- String: ' (threshold='
- Threshold: '275'
- String: ')'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: Inputs/q.c, Line: 12, Column: 3 }
Function: quack2
Args:
- Callee: foo
- String: ' inlined into '
- Caller: quack2
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q.c, Line: 3, Column: 3 }
Function: quack2
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Analysis
Pass: loop-vectorize
Name: CantVectorizeCall
DebugLoc: { File: Inputs/q.c, Line: 4, Column: 5 }
Function: foo
Args:
- String: 'loop not vectorized: '
- String: call instruction cannot be vectorized
...
--- !Missed
Pass: loop-vectorize
Name: MissedDetails
DebugLoc: { File: Inputs/q.c, Line: 3, Column: 3 }
Function: foo
Args:
- String: 'loop not vectorized: use -Rpass-analysis=loop-vectorize for more info'
...

View File

@ -0,0 +1,14 @@
void bar();
void foo(int n) {
for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
bar();
}
void quack() {
foo(4);
}
void quack2() {
foo(4);
}

View File

@ -0,0 +1,118 @@
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: Inputs/q2.c, Line: 4, Column: 5 }
Function: foo
Args:
- Callee: bar
- String: ' will not be inlined into '
- Caller: foo
- String: ' because its definition is unavailable'
...
--- !Analysis
Pass: inline
Name: CanBeInlined
DebugLoc: { File: Inputs/q2.c, Line: 8, Column: 3 }
Function: quack
Args:
- Callee: foo
- String: ' can be inlined into '
- Caller: quack
- String: ' with cost='
- Cost: '55'
- String: ' (threshold='
- Threshold: '275'
- String: ')'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: Inputs/q2.c, Line: 8, Column: 3 }
Function: quack
Args:
- Callee: foo
- String: ' inlined into '
- Caller: quack
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q2.c, Line: 3, Column: 31 }
Function: quack
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q2.c, Line: 3, Column: 3 }
Function: quack
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Analysis
Pass: inline
Name: CanBeInlined
DebugLoc: { File: Inputs/q2.c, Line: 12, Column: 3 }
Function: quack2
Args:
- Callee: foo
- String: ' can be inlined into '
- Caller: quack2
- String: ' with cost='
- Cost: '55'
- String: ' (threshold='
- Threshold: '275'
- String: ')'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: Inputs/q2.c, Line: 12, Column: 3 }
Function: quack2
Args:
- Callee: foo
- String: ' inlined into '
- Caller: quack2
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q2.c, Line: 3, Column: 31 }
Function: quack2
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q2.c, Line: 3, Column: 3 }
Function: quack2
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Analysis
Pass: loop-vectorize
Name: CantVectorizeCall
DebugLoc: { File: Inputs/q2.c, Line: 4, Column: 5 }
Function: foo
Args:
- String: 'loop not vectorized: '
- String: call instruction cannot be vectorized
...
--- !Missed
Pass: loop-vectorize
Name: MissedDetails
DebugLoc: { File: Inputs/q2.c, Line: 3, Column: 31 }
Function: foo
Args:
- String: 'loop not vectorized: use -Rpass-analysis=loop-vectorize for more info'
...

View File

@ -0,0 +1,98 @@
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: Inputs/q.cpp, Line: 4, Column: 5 }
Function: _Z3fooi
Args:
- Callee: _Z3barv
- String: ' will not be inlined into '
- Caller: _Z3fooi
- String: ' because its definition is unavailable'
...
--- !Analysis
Pass: inline
Name: CanBeInlined
DebugLoc: { File: Inputs/q.cpp, Line: 8, Column: 3 }
Function: _Z5quackv
Args:
- Callee: _Z3fooi
- String: ' can be inlined into '
- Caller: _Z5quackv
- String: ' with cost='
- Cost: '40'
- String: ' (threshold='
- Threshold: '275'
- String: ')'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: Inputs/q.cpp, Line: 8, Column: 3 }
Function: _Z5quackv
Args:
- Callee: _Z3fooi
- String: ' inlined into '
- Caller: _Z5quackv
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q.cpp, Line: 3, Column: 3 }
Function: _Z5quackv
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Analysis
Pass: inline
Name: CanBeInlined
DebugLoc: { File: Inputs/q.cpp, Line: 12, Column: 3 }
Function: _Z6quack2v
Args:
- Callee: _Z3fooi
- String: ' can be inlined into '
- Caller: _Z6quack2v
- String: ' with cost='
- Cost: '40'
- String: ' (threshold='
- Threshold: '275'
- String: ')'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: Inputs/q.cpp, Line: 12, Column: 3 }
Function: _Z6quack2v
Args:
- Callee: _Z3fooi
- String: ' inlined into '
- Caller: _Z6quack2v
...
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: Inputs/q.cpp, Line: 3, Column: 3 }
Function: _Z6quack2v
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '4'
- String: ' iterations'
...
--- !Analysis
Pass: loop-vectorize
Name: CantVectorizeCall
DebugLoc: { File: Inputs/q.cpp, Line: 4, Column: 5 }
Function: _Z3fooi
Args:
- String: 'loop not vectorized: '
- String: call instruction cannot be vectorized
...
--- !Missed
Pass: loop-vectorize
Name: MissedDetails
DebugLoc: { File: Inputs/q.cpp, Line: 3, Column: 3 }
Function: _Z3fooi
Args:
- String: 'loop not vectorized: use -Rpass-analysis=loop-vectorize for more info'
...

View File

@ -0,0 +1,49 @@
RUN: llvm-opt-report -r %p %p/Inputs/q2.yaml | FileCheck -strict-whitespace %s
RUN: llvm-opt-report -s -r %p %p/Inputs/q2.yaml | FileCheck -strict-whitespace -check-prefix=CHECK-SUCCINCT %s
; CHECK: < {{.*}}/Inputs/q2.c
; CHECK-NEXT: 2 | void bar();
; CHECK-NEXT: 3 | void foo(int n) {
; CHECK-NEXT: {{\[\[}}
; CHECK-NEXT: > quack, quack2:
; CHECK-NEXT: 4 | for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
; CHECK-NEXT: U4 | ^
; CHECK-NEXT: U4 | ^
; CHECK-NEXT: > foo:
; CHECK-NEXT: 4 | for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
; CHECK-NEXT: {{\]\]}}
; CHECK-NEXT: 5 | bar();
; CHECK-NEXT: 6 | }
; CHECK-NEXT: 7 |
; CHECK-NEXT: 8 | void quack() {
; CHECK-NEXT: 9 I | foo(4);
; CHECK-NEXT: 10 | }
; CHECK-NEXT: 11 |
; CHECK-NEXT: 12 | void quack2() {
; CHECK-NEXT: 13 I | foo(4);
; CHECK-NEXT: 14 | }
; CHECK-NEXT: 15 |
; CHECK-SUCCINCT: < {{.*}}/Inputs/q2.c
; CHECK-SUCCINCT-NEXT: 2 | void bar();
; CHECK-SUCCINCT-NEXT: 3 | void foo(int n) {
; CHECK-SUCCINCT-NEXT: {{\[\[}}
; CHECK-SUCCINCT-NEXT: > quack, quack2:
; CHECK-SUCCINCT-NEXT: 4 | for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
; CHECK-SUCCINCT-NEXT: U | ^
; CHECK-SUCCINCT-NEXT: U | ^
; CHECK-SUCCINCT-NEXT: > foo:
; CHECK-SUCCINCT-NEXT: 4 | for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
; CHECK-SUCCINCT-NEXT: {{\]\]}}
; CHECK-SUCCINCT-NEXT: 5 | bar();
; CHECK-SUCCINCT-NEXT: 6 | }
; CHECK-SUCCINCT-NEXT: 7 |
; CHECK-SUCCINCT-NEXT: 8 | void quack() {
; CHECK-SUCCINCT-NEXT: 9 I | foo(4);
; CHECK-SUCCINCT-NEXT: 10 | }
; CHECK-SUCCINCT-NEXT: 11 |
; CHECK-SUCCINCT-NEXT: 12 | void quack2() {
; CHECK-SUCCINCT-NEXT: 13 I | foo(4);
; CHECK-SUCCINCT-NEXT: 14 | }
; CHECK-SUCCINCT-NEXT: 15 |

View File

@ -0,0 +1,45 @@
RUN: llvm-opt-report -r %p %p/Inputs/qx.yaml | FileCheck -strict-whitespace %s
RUN: llvm-opt-report -s -r %p %p/Inputs/qx.yaml | FileCheck -strict-whitespace -check-prefix=CHECK-SUCCINCT %s
; CHECK: < {{.*}}/Inputs/q.cpp
; CHECK-NEXT: 2 | void bar();
; CHECK-NEXT: 3 | void foo(int n) {
; CHECK-NEXT: {{\[\[}}
; CHECK-NEXT: > foo(int):
; CHECK-NEXT: 4 | for (int i = 0; i < n; ++i)
; CHECK-NEXT: > quack(), quack2():
; CHECK-NEXT: 4 U4 | for (int i = 0; i < n; ++i)
; CHECK-NEXT: {{\]\]}}
; CHECK-NEXT: 5 | bar();
; CHECK-NEXT: 6 | }
; CHECK-NEXT: 7 |
; CHECK-NEXT: 8 | void quack() {
; CHECK-NEXT: 9 I | foo(4);
; CHECK-NEXT: 10 | }
; CHECK-NEXT: 11 |
; CHECK-NEXT: 12 | void quack2() {
; CHECK-NEXT: 13 I | foo(4);
; CHECK-NEXT: 14 | }
; CHECK-NEXT: 15 |
; CHECK-SUCCINCT: < {{.*}}/Inputs/q.cpp
; CHECK-SUCCINCT-NEXT: 2 | void bar();
; CHECK-SUCCINCT-NEXT: 3 | void foo(int n) {
; CHECK-SUCCINCT-NEXT: {{\[\[}}
; CHECK-SUCCINCT-NEXT: > foo(int):
; CHECK-SUCCINCT-NEXT: 4 | for (int i = 0; i < n; ++i)
; CHECK-SUCCINCT-NEXT: > quack(), quack2():
; CHECK-SUCCINCT-NEXT: 4 U | for (int i = 0; i < n; ++i)
; CHECK-SUCCINCT-NEXT: {{\]\]}}
; CHECK-SUCCINCT-NEXT: 5 | bar();
; CHECK-SUCCINCT-NEXT: 6 | }
; CHECK-SUCCINCT-NEXT: 7 |
; CHECK-SUCCINCT-NEXT: 8 | void quack() {
; CHECK-SUCCINCT-NEXT: 9 I | foo(4);
; CHECK-SUCCINCT-NEXT: 10 | }
; CHECK-SUCCINCT-NEXT: 11 |
; CHECK-SUCCINCT-NEXT: 12 | void quack2() {
; CHECK-SUCCINCT-NEXT: 13 I | foo(4);
; CHECK-SUCCINCT-NEXT: 14 | }
; CHECK-SUCCINCT-NEXT: 15 |

View File

@ -0,0 +1,45 @@
RUN: llvm-opt-report -r %p %p/Inputs/q.yaml | FileCheck -strict-whitespace %s
RUN: llvm-opt-report -s -r %p %p/Inputs/q.yaml | FileCheck -strict-whitespace -check-prefix=CHECK-SUCCINCT %s
; CHECK: < {{.*}}/Inputs/q.c
; CHECK-NEXT: 2 | void bar();
; CHECK-NEXT: 3 | void foo(int n) {
; CHECK-NEXT: {{\[\[}}
; CHECK-NEXT: > foo:
; CHECK-NEXT: 4 | for (int i = 0; i < n; ++i)
; CHECK-NEXT: > quack, quack2:
; CHECK-NEXT: 4 U4 | for (int i = 0; i < n; ++i)
; CHECK-NEXT: {{\]\]}}
; CHECK-NEXT: 5 | bar();
; CHECK-NEXT: 6 | }
; CHECK-NEXT: 7 |
; CHECK-NEXT: 8 | void quack() {
; CHECK-NEXT: 9 I | foo(4);
; CHECK-NEXT: 10 | }
; CHECK-NEXT: 11 |
; CHECK-NEXT: 12 | void quack2() {
; CHECK-NEXT: 13 I | foo(4);
; CHECK-NEXT: 14 | }
; CHECK-NEXT: 15 |
; CHECK-SUCCINCT: < {{.*}}/Inputs/q.c
; CHECK-SUCCINCT-NEXT: 2 | void bar();
; CHECK-SUCCINCT-NEXT: 3 | void foo(int n) {
; CHECK-SUCCINCT-NEXT: {{\[\[}}
; CHECK-SUCCINCT-NEXT: > foo:
; CHECK-SUCCINCT-NEXT: 4 | for (int i = 0; i < n; ++i)
; CHECK-SUCCINCT-NEXT: > quack, quack2:
; CHECK-SUCCINCT-NEXT: 4 U | for (int i = 0; i < n; ++i)
; CHECK-SUCCINCT-NEXT: {{\]\]}}
; CHECK-SUCCINCT-NEXT: 5 | bar();
; CHECK-SUCCINCT-NEXT: 6 | }
; CHECK-SUCCINCT-NEXT: 7 |
; CHECK-SUCCINCT-NEXT: 8 | void quack() {
; CHECK-SUCCINCT-NEXT: 9 I | foo(4);
; CHECK-SUCCINCT-NEXT: 10 | }
; CHECK-SUCCINCT-NEXT: 11 |
; CHECK-SUCCINCT-NEXT: 12 | void quack2() {
; CHECK-SUCCINCT-NEXT: 13 I | foo(4);
; CHECK-SUCCINCT-NEXT: 14 | }
; CHECK-SUCCINCT-NEXT: 15 |

View File

@ -1,4 +1,4 @@
set(LLVM_LINK_COMPONENTS Core Object Support)
set(LLVM_LINK_COMPONENTS Core Demangle Object Support)
add_llvm_tool(llvm-opt-report
OptReport.cpp

View File

@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/CommandLine.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
@ -27,6 +28,9 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/YAMLTraits.h"
#include <cstdlib>
#include <map>
#include <set>
using namespace llvm;
using namespace llvm::yaml;
@ -54,6 +58,10 @@ static cl::opt<bool>
Succinct("s", cl::desc("Don't include vectorization factors, etc."),
cl::init(false), cl::cat(OptReportCategory));
static cl::opt<bool>
Demangle("demangle", cl::desc("Demangle function names"), cl::init(true),
cl::cat(OptReportCategory));
namespace {
// For each location in the source file, the common per-transformation state
// collected.
@ -68,6 +76,16 @@ struct OptReportLocationItemInfo {
return *this;
}
bool operator < (const OptReportLocationItemInfo &RHS) const {
if (Analyzed < RHS.Analyzed)
return true;
else if (Analyzed > RHS.Analyzed)
return false;
else if (Transformed < RHS.Transformed)
return true;
return false;
}
};
// The per-location information collected for producing an optimization report.
@ -92,10 +110,36 @@ struct OptReportLocationInfo {
return *this;
}
bool operator < (const OptReportLocationInfo &RHS) const {
if (Inlined < RHS.Inlined)
return true;
else if (RHS.Inlined < Inlined)
return false;
else if (Unrolled < RHS.Unrolled)
return true;
else if (RHS.Unrolled < Unrolled)
return false;
else if (Vectorized < RHS.Vectorized)
return true;
else if (RHS.Vectorized < Vectorized || Succinct)
return false;
else if (VectorizationFactor < RHS.VectorizationFactor)
return true;
else if (VectorizationFactor > RHS.VectorizationFactor)
return false;
else if (InterleaveCount < RHS.InterleaveCount)
return true;
else if (InterleaveCount > RHS.InterleaveCount)
return false;
else if (InterleaveCount < RHS.InterleaveCount)
return true;
return false;
}
};
typedef std::map<std::string, std::map<int, std::map<int,
OptReportLocationInfo>>> LocationInfoTy;
typedef std::map<std::string, std::map<int, std::map<std::string, std::map<int,
OptReportLocationInfo>>>> LocationInfoTy;
} // anonymous namespace
static void collectLocationInfo(yaml::Stream &Stream,
@ -115,7 +159,7 @@ static void collectLocationInfo(yaml::Stream &Stream,
continue;
bool Transformed = Root->getRawTag() == "!Passed";
std::string Pass, File;
std::string Pass, File, Function;
int Line = 0, Column = 1;
int VectorizationFactor = 1;
@ -132,6 +176,11 @@ static void collectLocationInfo(yaml::Stream &Stream,
if (!Value)
continue;
Pass = Value->getValue(Tmp);
} else if (KeyName == "Function") {
auto *Value = dyn_cast<yaml::ScalarNode>(RootChild.getValue());
if (!Value)
continue;
Function = Value->getValue(Tmp);
} else if (KeyName == "DebugLoc") {
auto *DebugLoc = dyn_cast<yaml::MappingNode>(RootChild.getValue());
if (!DebugLoc)
@ -214,13 +263,13 @@ static void collectLocationInfo(yaml::Stream &Stream,
};
if (Pass == "inline") {
auto &LI = LocationInfo[File][Line][Column];
auto &LI = LocationInfo[File][Line][Function][Column];
UpdateLLII(LI, LI.Inlined);
} else if (Pass == "loop-unroll") {
auto &LI = LocationInfo[File][Line][Column];
auto &LI = LocationInfo[File][Line][Function][Column];
UpdateLLII(LI, LI.Unrolled);
} else if (Pass == "loop-vectorize") {
auto &LI = LocationInfo[File][Line][Column];
auto &LI = LocationInfo[File][Line][Function][Column];
UpdateLLII(LI, LI.Vectorized);
}
}
@ -283,7 +332,8 @@ static bool writeReport(LocationInfoTy &LocationInfo) {
// Figure out how many characters we need for the vectorization factors
// and similar.
OptReportLocationInfo MaxLI;
for (auto &FI : FileInfo)
for (auto &FLI : FileInfo)
for (auto &FI : FLI.second)
for (auto &LI : FI.second)
MaxLI |= LI.second;
@ -300,16 +350,19 @@ static bool writeReport(LocationInfoTy &LocationInfo) {
for (line_iterator LI(*Buf.get(), false); LI != line_iterator(); ++LI) {
int64_t L = LI.line_number();
auto LII = FileInfo.find(L);
auto PrintLine = [&](bool PrintFuncName,
const std::set<std::string> &FuncNameSet) {
OptReportLocationInfo LLI;
std::map<int, OptReportLocationInfo> ColsInfo;
unsigned InlinedCols = 0, UnrolledCols = 0, VectorizedCols = 0;
auto LII = FileInfo.find(L);
if (LII != FileInfo.end()) {
const auto &LineInfo = LII->second;
for (auto &CI : LineInfo) {
for (auto &CI : LineInfo.find(*FuncNameSet.begin())->second) {
int Col = CI.first;
ColsInfo[Col] = CI.second;
InlinedCols += CI.second.Inlined.Analyzed;
@ -319,6 +372,37 @@ static bool writeReport(LocationInfoTy &LocationInfo) {
}
}
if (PrintFuncName) {
OS << " > ";
bool FirstFunc = true;
for (const auto &FuncName : FuncNameSet) {
if (FirstFunc)
FirstFunc = false;
else
OS << ", ";
bool Printed = false;
if (Demangle) {
int Status = 0;
char *Demangled =
itaniumDemangle(FuncName.c_str(), nullptr, nullptr, &Status);
if (Demangled && Status == 0) {
OS << Demangled;
Printed = true;
}
if (Demangled)
std::free(Demangled);
}
if (!Printed)
OS << FuncName;
}
OS << ":\n";
}
// We try to keep the output as concise as possible. If only one thing on
// a given line could have been inlined, vectorized, etc. then we can put
// the marker on the source line itself. If there are multiple options
@ -372,6 +456,32 @@ static bool writeReport(LocationInfoTy &LocationInfo) {
OS << " | " << std::string(J.first - 1, ' ') << "^\n";
}
}
};
// We need to figure out if the optimizations for this line were the same
// in each function context. If not, then we want to group the similar
// function contexts together and display each group separately. If
// they're all the same, then we only display the line once without any
// additional markings.
std::map<std::map<int, OptReportLocationInfo>,
std::set<std::string>> UniqueLIs;
if (LII != FileInfo.end()) {
const auto &FuncLineInfo = LII->second;
for (const auto &FLII : FuncLineInfo)
UniqueLIs[FLII.second].insert(FLII.first);
}
if (UniqueLIs.size() > 1) {
OS << " [[\n";
for (const auto &FSLI : UniqueLIs)
PrintLine(true, FSLI.second);
OS << " ]]\n";
} else if (UniqueLIs.size() == 1) {
PrintLine(false, UniqueLIs.begin()->second);
} else {
PrintLine(false, std::set<std::string>());
}
}
}