#include "llvm/ADT/Optional.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
-#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
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
/// 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; }
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
#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>
/// 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
const DebugLoc &DLoc, const Twine &Msg,
Optional<uint64_t> Hotness = None)
: DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc),
- PassName(PassName), Hotness(Hotness), IsVerbose(false) {
- Args.push_back(Argument(Msg.str()));
- }
-
- DiagnosticInfoOptimizationBase &operator<<(StringRef S);
- DiagnosticInfoOptimizationBase &operator<<(Argument A);
- DiagnosticInfoOptimizationBase &operator<<(setIsVerbose V);
+ PassName(PassName), Msg(Msg), Hotness(Hotness) {}
/// \see DiagnosticInfo::print.
void print(DiagnosticPrinter &DP) const override;
virtual bool isEnabled() const = 0;
const char *getPassName() const { return PassName; }
- std::string getMsg() const;
+ const Twine &getMsg() const { return Msg; }
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 &&
/// be emitted.
const char *PassName;
- /// 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;
+ /// Message to report.
+ const Twine &Msg;
/// 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.
: 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;
}
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
/// 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);
#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"
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,
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());
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();
-}
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;
}
#include "llvm/IR/Metadata.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Dwarf.h"
-#include "llvm/Support/YAMLTraits.h"
#include <vector>
namespace llvm {
void *DiagnosticContext;
bool RespectDiagnosticFilters;
bool DiagnosticHotnessRequested;
- std::unique_ptr<yaml::Output> DiagnosticsOutputFile;
LLVMContext::YieldCallbackTy YieldCallback;
void *YieldOpaqueHandle;
// direct call, so we keep it.
if (Function *Callee = CS.getCalledFunction())
if (Callee->isDeclaration()) {
- ORE.emitOptimizationRemarkAnalysis(
- DEBUG_TYPE, &I, Twine("definition of ") + Callee->getName() +
- " is not available",
+ ORE.emitOptimizationRemarkMissedAndAnalysis(
+ DEBUG_TYPE, &I,
+ Twine(Callee->getName()) + " will not be inlined into " +
+ CS.getCaller()->getName(),
+ 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;
}
+++ /dev/null
-; 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}
#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"
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);
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);
"the compile-twice option\n";
Out->os() << BOS->str();
Out->keep();
- if (YamlFile)
- YamlFile->keep();
return 1;
}
Out->os() << BOS->str();
if (!NoOutput || PrintBreakpoints)
Out->keep();
- if (YamlFile)
- YamlFile->keep();
-
return 0;
}