summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h17
-rw-r--r--llvm/include/llvm/IR/DiagnosticInfo.h74
-rw-r--r--llvm/include/llvm/IR/LLVMContext.h14
-rw-r--r--llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp80
-rw-r--r--llvm/lib/IR/DiagnosticInfo.cpp33
-rw-r--r--llvm/lib/IR/LLVMContext.cpp8
-rw-r--r--llvm/lib/IR/LLVMContextImpl.h2
-rw-r--r--llvm/lib/Transforms/IPO/Inliner.cpp14
-rw-r--r--llvm/test/Transforms/Inline/optimization-remarks-yaml.ll76
-rw-r--r--llvm/tools/opt/opt.cpp23
10 files changed, 331 insertions, 10 deletions
diff --git a/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h b/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h
index 5890ad7a032..9a88fea48b5 100644
--- a/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h
+++ b/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
@@ -62,6 +63,9 @@ public:
return *this;
}
+ /// The new interface to emit remarks.
+ void emit(DiagnosticInfoOptimizationBase &OptDiag);
+
/// Emit an optimization-applied message.
///
/// \p PassName is the name of the pass emitting the message. If -Rpass= is
@@ -198,8 +202,13 @@ private:
/// If we generate BFI on demand, we need to free it when ORE is freed.
std::unique_ptr<BlockFrequencyInfo> OwnedBFI;
+ /// Compute hotness from IR value (currently assumed to be a block) if PGO is
+ /// available.
Optional<uint64_t> computeHotness(const Value *V);
+ /// Similar but use value from \p OptDiag and update hotness there.
+ void computeHotness(DiagnosticInfoOptimizationBase &OptDiag);
+
/// \brief Only allow verbose messages if we know we're filtering by hotness
/// (BFI is only set in this case).
bool shouldEmitVerbose() { return BFI != nullptr; }
@@ -208,6 +217,14 @@ private:
void operator=(const OptimizationRemarkEmitter &) = delete;
};
+/// \brief Add a small namespace to avoid name clashes with the classes used in
+/// the streaming interface. We want these to be short for better
+/// write/readability.
+namespace ore {
+using NV = DiagnosticInfoOptimizationBase::Argument;
+using setIsVerbose = DiagnosticInfoOptimizationBase::setIsVerbose;
+}
+
/// OptimizationRemarkEmitter legacy analysis pass
///
/// Note that this pass shouldn't generally be marked as preserved by other
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index b8516ba163d..4275fdb8f09 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -17,10 +17,12 @@
#include "llvm-c/Types.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Support/YAMLTraits.h"
#include <functional>
#include <string>
@@ -375,6 +377,38 @@ private:
/// Common features for diagnostics dealing with optimization remarks.
class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithDebugLocBase {
public:
+ /// \brief Used to set IsVerbose via the stream interface.
+ struct setIsVerbose {};
+
+ /// \brief Used in the streaming interface as the general argument type. It
+ /// internally converts everything into a key-value pair.
+ struct Argument {
+ StringRef Key;
+ std::string Val;
+
+ explicit Argument(StringRef Str = "") : Key("String"), Val(Str) {}
+ explicit Argument(StringRef Key, Value *V) : Key(Key), Val(V->getName()) {}
+ explicit Argument(StringRef Key, int N)
+ : Key(Key), Val(std::to_string(N)) {}
+ };
+
+ /// \p PassName is the name of the pass emitting this diagnostic. \p
+ /// RemarkName is a textual identifier for the remark. \p Fn is the function
+ /// where the diagnostic is being emitted. \p DLoc is the location information
+ /// to use in the diagnostic. If line table information is available, the
+ /// diagnostic will include the source code location. \p CodeRegion is IR
+ /// value (currently basic block) that the optimization operates on. This is
+ /// currently used to provide run-time hotness information with PGO.
+ DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind,
+ enum DiagnosticSeverity Severity,
+ const char *PassName, StringRef RemarkName,
+ const Function &Fn, const DebugLoc &DLoc,
+ Value *CodeRegion = nullptr)
+ : DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc),
+ PassName(PassName), RemarkName(RemarkName), CodeRegion(CodeRegion),
+ IsVerbose(false) {}
+
+ /// Legacy interface.
/// \p PassName is the name of the pass emitting this diagnostic.
/// \p Fn is the function where the diagnostic is being emitted. \p DLoc is
/// the location information to use in the diagnostic. If line table
@@ -388,7 +422,13 @@ public:
const DebugLoc &DLoc, const Twine &Msg,
Optional<uint64_t> Hotness = None)
: DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc),
- PassName(PassName), Msg(Msg), Hotness(Hotness) {}
+ PassName(PassName), Hotness(Hotness), IsVerbose(false) {
+ Args.push_back(Argument(Msg.str()));
+ }
+
+ DiagnosticInfoOptimizationBase &operator<<(StringRef S);
+ DiagnosticInfoOptimizationBase &operator<<(Argument A);
+ DiagnosticInfoOptimizationBase &operator<<(setIsVerbose V);
/// \see DiagnosticInfo::print.
void print(DiagnosticPrinter &DP) const override;
@@ -401,8 +441,13 @@ public:
virtual bool isEnabled() const = 0;
const char *getPassName() const { return PassName; }
- const Twine &getMsg() const { return Msg; }
+ std::string getMsg() const;
Optional<uint64_t> getHotness() const { return Hotness; }
+ void setHotness(Optional<uint64_t> H) { Hotness = H; }
+
+ Value *getCodeRegion() const { return CodeRegion; }
+
+ bool isVerbose() const { return IsVerbose; }
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() >= DK_FirstRemark &&
@@ -415,12 +460,25 @@ private:
/// be emitted.
const char *PassName;
- /// Message to report.
- const Twine &Msg;
+ /// Textual identifier for the remark. Can be used by external tools reading
+ /// the YAML output file for optimization remarks to identify the remark.
+ StringRef RemarkName;
/// If profile information is available, this is the number of times the
/// corresponding code was executed in a profile instrumentation run.
Optional<uint64_t> Hotness;
+
+ /// The IR value (currently basic block) that the optimization operates on.
+ /// This is currently used to provide run-time hotness information with PGO.
+ Value *CodeRegion;
+
+ /// Arguments collected via the streaming interface.
+ SmallVector<Argument, 4> Args;
+
+ /// The remark is expected to be noisy.
+ bool IsVerbose;
+
+ friend struct yaml::MappingTraits<DiagnosticInfoOptimizationBase *>;
};
/// Diagnostic information for applied optimization remarks.
@@ -467,6 +525,14 @@ public:
: DiagnosticInfoOptimizationBase(DK_OptimizationRemarkMissed, DS_Remark,
PassName, Fn, DLoc, Msg, Hotness) {}
+ /// \p PassName is the name of the pass emitting this diagnostic. If this name
+ /// matches the regular expression given in -Rpass-missed=, then the
+ /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
+ /// remark. \p Inst is the instruction that the optimization operates on.
+ DiagnosticInfoOptimizationRemarkMissed(const char *PassName,
+ StringRef RemarkName,
+ Instruction *Inst);
+
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_OptimizationRemarkMissed;
}
diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h
index dbf2b456233..df9368904a6 100644
--- a/llvm/include/llvm/IR/LLVMContext.h
+++ b/llvm/include/llvm/IR/LLVMContext.h
@@ -34,6 +34,9 @@ template <typename T> class SmallVectorImpl;
class Function;
class DebugLoc;
class OptBisect;
+namespace yaml {
+class Output;
+}
/// This is an important class for using LLVM in a threaded context. It
/// (opaquely) owns and manages the core "global" data of LLVM's core
@@ -181,6 +184,17 @@ public:
/// diagnostics.
void setDiagnosticHotnessRequested(bool Requested);
+ /// \brief Return the YAML file used by the backend to save optimization
+ /// diagnostics. If null, diagnostics are not saved in a file but only
+ /// emitted via the diagnostic handler.
+ yaml::Output *getDiagnosticsOutputFile();
+ /// Set the diagnostics output file used for optimization diagnostics.
+ ///
+ /// By default or if invoked with null, diagnostics are not saved in a file
+ /// but only emitted via the diagnostic handler. Even if an output file is
+ /// set, the handler is invoked for each diagnostic message.
+ void setDiagnosticsOutputFile(yaml::Output *F);
+
/// \brief Get the prefix that should be printed in front of a diagnostic of
/// the given \p Severity
static const char *getDiagnosticMessagePrefix(DiagnosticSeverity Severity);
diff --git a/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp b/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp
index 09a4ce51472..864308f62ed 100644
--- a/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp
+++ b/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp
@@ -16,6 +16,7 @@
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/LLVMContext.h"
@@ -51,6 +52,85 @@ Optional<uint64_t> OptimizationRemarkEmitter::computeHotness(const Value *V) {
return BFI->getBlockProfileCount(cast<BasicBlock>(V));
}
+template <> struct yaml::MappingTraits<DiagnosticInfoOptimizationBase *> {
+ static void mapping(IO &io, DiagnosticInfoOptimizationBase *&OptDiag) {
+ assert(io.outputting() && "input not yet implemented");
+
+ if (io.mapTag("!Missed", OptDiag->getKind() == DK_OptimizationRemarkMissed))
+ ;
+ else
+ llvm_unreachable("todo");
+
+ // These are read-only for now.
+ DebugLoc DL = OptDiag->getDebugLoc();
+ StringRef FN = 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);
+ }
+};
+
+template <> struct yaml::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;
+};
+
+template <>
+struct yaml::ScalarTraits<DiagnosticInfoOptimizationBase::Argument> {
+ static void output(const DiagnosticInfoOptimizationBase::Argument &Arg,
+ void *, llvm::raw_ostream &out) {
+ out << Arg.Key << ": " << Arg.Val;
+ }
+
+ static StringRef input(StringRef scalar, void *,
+ DiagnosticInfoOptimizationBase::Argument &Arg) {
+ llvm_unreachable("input not yet implemented");
+ }
+
+ static bool mustQuote(StringRef) { return false; }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(DiagnosticInfoOptimizationBase::Argument)
+
+void OptimizationRemarkEmitter::computeHotness(
+ DiagnosticInfoOptimizationBase &OptDiag) {
+ Value *V = OptDiag.getCodeRegion();
+ if (V)
+ OptDiag.setHotness(computeHotness(V));
+}
+
+void OptimizationRemarkEmitter::emit(DiagnosticInfoOptimizationBase &OptDiag) {
+ computeHotness(OptDiag);
+
+ yaml::Output *Out = F->getContext().getDiagnosticsOutputFile();
+ if (Out && OptDiag.isEnabled()) {
+ auto *P = &const_cast<DiagnosticInfoOptimizationBase &>(OptDiag);
+ *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);
+}
+
void OptimizationRemarkEmitter::emitOptimizationRemark(const char *PassName,
const DebugLoc &DLoc,
const Value *V,
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index 7dd4cab734d..e11aeafd01f 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -181,6 +181,13 @@ bool DiagnosticInfoOptimizationRemark::isEnabled() const {
PassRemarksOptLoc.Pattern->match(getPassName());
}
+DiagnosticInfoOptimizationRemarkMissed::DiagnosticInfoOptimizationRemarkMissed(
+ const char *PassName, StringRef RemarkName, Instruction *Inst)
+ : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkMissed, DS_Remark,
+ PassName, RemarkName,
+ *Inst->getParent()->getParent(),
+ Inst->getDebugLoc(), Inst->getParent()) {}
+
bool DiagnosticInfoOptimizationRemarkMissed::isEnabled() const {
return PassRemarksMissedOptLoc.Pattern &&
PassRemarksMissedOptLoc.Pattern->match(getPassName());
@@ -266,3 +273,29 @@ void llvm::emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn,
void DiagnosticInfoISelFallback::print(DiagnosticPrinter &DP) const {
DP << "Instruction selection used fallback path for " << getFunction();
}
+
+DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase::
+operator<<(StringRef S) {
+ Args.emplace_back(S);
+ return *this;
+}
+
+DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase::
+operator<<(Argument A) {
+ Args.push_back(std::move(A));
+ return *this;
+}
+
+DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase::
+operator<<(setIsVerbose V) {
+ IsVerbose = true;
+ return *this;
+}
+
+std::string DiagnosticInfoOptimizationBase::getMsg() const {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ for (const DiagnosticInfoOptimizationBase::Argument &Arg : Args)
+ OS << Arg.Val;
+ return OS.str();
+}
diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
index d27fcfb1b7a..c97228fd51a 100644
--- a/llvm/lib/IR/LLVMContext.cpp
+++ b/llvm/lib/IR/LLVMContext.cpp
@@ -203,6 +203,14 @@ bool LLVMContext::getDiagnosticHotnessRequested() const {
return pImpl->DiagnosticHotnessRequested;
}
+yaml::Output *LLVMContext::getDiagnosticsOutputFile() {
+ return pImpl->DiagnosticsOutputFile.get();
+}
+
+void LLVMContext::setDiagnosticsOutputFile(yaml::Output *F) {
+ pImpl->DiagnosticsOutputFile.reset(F);
+}
+
LLVMContext::DiagnosticHandlerTy LLVMContext::getDiagnosticHandler() const {
return pImpl->DiagnosticHandler;
}
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 40935d9331e..49a35a4d375 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -33,6 +33,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/YAMLTraits.h"
#include <vector>
namespace llvm {
@@ -1043,6 +1044,7 @@ public:
void *DiagnosticContext;
bool RespectDiagnosticFilters;
bool DiagnosticHotnessRequested;
+ std::unique_ptr<yaml::Output> DiagnosticsOutputFile;
LLVMContext::YieldCallbackTy YieldCallback;
void *YieldOpaqueHandle;
diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp
index befadb63db5..f1475cd434c 100644
--- a/llvm/lib/Transforms/IPO/Inliner.cpp
+++ b/llvm/lib/Transforms/IPO/Inliner.cpp
@@ -469,13 +469,15 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
// direct call, so we keep it.
if (Function *Callee = CS.getCalledFunction())
if (Callee->isDeclaration()) {
- ORE.emitOptimizationRemarkMissedAndAnalysis(
- DEBUG_TYPE, &I,
- Twine(Callee->getName()) + " will not be inlined into " +
- CS.getCaller()->getName(),
- Twine("definition of ") + Callee->getName() +
- " is not available",
+ ORE.emitOptimizationRemarkAnalysis(
+ DEBUG_TYPE, &I, Twine("definition of ") + Callee->getName() +
+ " is not available",
/*Verbose=*/true);
+ using namespace ore;
+ ORE.emit(DiagnosticInfoOptimizationRemarkMissed(DEBUG_TYPE,
+ "NotInlined", &I)
+ << NV("Callee", Callee) << " will not be inlined into "
+ << NV("Caller", CS.getCaller()) << setIsVerbose());
continue;
}
diff --git a/llvm/test/Transforms/Inline/optimization-remarks-yaml.ll b/llvm/test/Transforms/Inline/optimization-remarks-yaml.ll
new file mode 100644
index 00000000000..45ed78d6592
--- /dev/null
+++ b/llvm/test/Transforms/Inline/optimization-remarks-yaml.ll
@@ -0,0 +1,76 @@
+; RUN: opt < %s -inline -pass-remarks-missed=inline -pass-remarks-with-hotness \
+; RUN: -pass-remarks-output=%t 2>&1 | FileCheck %s
+; RUN: cat %t | FileCheck -check-prefix=YAML %s
+
+; Check the YAML file generated for inliner remarks for this program:
+;
+; 1 int foo();
+; 2 int bar();
+; 3
+; 4 int baz() {
+; 5 return foo() + bar();
+; 6 }
+
+; CHECK: remark: /tmp/s.c:5:10: foo will not be inlined into baz (hotness: 30)
+; CHECK-NEXT: remark: /tmp/s.c:5:18: bar will not be inlined into baz (hotness: 30)
+
+; YAML: --- !Missed
+; YAML-NEXT: Pass: inline
+; YAML-NEXT: Name: NotInlined
+; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 5, Column: 10 }
+; YAML-NEXT: Function: baz
+; YAML-NEXT: Hotness: 30
+; YAML-NEXT: Args:
+; YAML-NEXT: - Callee: foo
+; YAML-NEXT: - String: will not be inlined into
+; YAML-NEXT: - Caller: baz
+; YAML-NEXT: ...
+; YAML-NEXT: --- !Missed
+; YAML-NEXT: Pass: inline
+; YAML-NEXT: Name: NotInlined
+; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 5, Column: 18 }
+; YAML-NEXT: Function: baz
+; YAML-NEXT: Hotness: 30
+; YAML-NEXT: Args:
+; YAML-NEXT: - Callee: bar
+; YAML-NEXT: - String: will not be inlined into
+; YAML-NEXT: - Caller: baz
+; YAML-NEXT: ...
+
+; ModuleID = '/tmp/s.c'
+source_filename = "/tmp/s.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @baz() !dbg !7 !prof !14 {
+entry:
+ %call = call i32 (...) @foo(), !dbg !9
+ %call1 = call i32 (...) @bar(), !dbg !10
+ %add = add nsw i32 %call, %call1, !dbg !12
+ ret i32 %add, !dbg !13
+}
+
+declare i32 @foo(...)
+
+declare i32 @bar(...)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 281293) (llvm/trunk 281290)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2)
+!1 = !DIFile(filename: "/tmp/s.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"PIC Level", i32 2}
+!6 = !{!"clang version 4.0.0 (trunk 281293) (llvm/trunk 281290)"}
+!7 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 4, type: !8, isLocal: false, isDefinition: true, scopeLine: 4, isOptimized: true, unit: !0, variables: !2)
+!8 = !DISubroutineType(types: !2)
+!9 = !DILocation(line: 5, column: 10, scope: !7)
+!10 = !DILocation(line: 5, column: 18, scope: !11)
+!11 = !DILexicalBlockFile(scope: !7, file: !1, discriminator: 1)
+!12 = !DILocation(line: 5, column: 16, scope: !7)
+!13 = !DILocation(line: 5, column: 3, scope: !7)
+!14 = !{!"function_entry_count", i64 30}
diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp
index 8ae18df3cc4..ef4f975fb79 100644
--- a/llvm/tools/opt/opt.cpp
+++ b/llvm/tools/opt/opt.cpp
@@ -49,6 +49,7 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/YAMLTraits.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Coroutines.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
@@ -231,6 +232,11 @@ static cl::opt<bool> PassRemarksWithHotness(
cl::desc("With PGO, include profile count in optimization remarks"),
cl::Hidden);
+static cl::opt<std::string>
+ RemarksFilename("pass-remarks-output",
+ cl::desc("YAML output filename for pass remarks"),
+ cl::value_desc("filename"));
+
static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
// Add the pass to the pass manager...
PM.add(P);
@@ -408,6 +414,18 @@ int main(int argc, char **argv) {
if (PassRemarksWithHotness)
Context.setDiagnosticHotnessRequested(true);
+ std::unique_ptr<tool_output_file> YamlFile;
+ if (RemarksFilename != "") {
+ std::error_code EC;
+ YamlFile = llvm::make_unique<tool_output_file>(RemarksFilename, EC,
+ sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
+ return 1;
+ }
+ Context.setDiagnosticsOutputFile(new yaml::Output(YamlFile->os()));
+ }
+
// Load the input module...
std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
@@ -716,6 +734,8 @@ int main(int argc, char **argv) {
"the compile-twice option\n";
Out->os() << BOS->str();
Out->keep();
+ if (YamlFile)
+ YamlFile->keep();
return 1;
}
Out->os() << BOS->str();
@@ -725,5 +745,8 @@ int main(int argc, char **argv) {
if (!NoOutput || PrintBreakpoints)
Out->keep();
+ if (YamlFile)
+ YamlFile->keep();
+
return 0;
}
OpenPOWER on IntegriCloud