From 14e47fc8be178caff3b66aeb6a820e7599f097cb Mon Sep 17 00:00:00 2001 From: Francis Visoiu Mistrih Date: Tue, 12 Mar 2019 21:22:27 +0000 Subject: [PATCH] Reland "[Remarks] Add -foptimization-record-passes to filter remark emission" Currently we have -Rpass for filtering the remarks that are displayed as diagnostics, but when using -fsave-optimization-record, there is no way to filter the remarks while generating them. This adds support for filtering remarks by passes using a regex. Ex: `clang -fsave-optimization-record -foptimization-record-passes=inline` will only emit the remarks coming from the pass `inline`. This adds: * `-fsave-optimization-record` to the driver * `-opt-record-passes` to cc1 * `-lto-pass-remarks-filter` to the LTOCodeGenerator * `--opt-remarks-passes` to lld * `-pass-remarks-filter` to llc, opt, llvm-lto, llvm-lto2 * `-opt-remarks-passes` to gold-plugin Differential Revision: https://reviews.llvm.org/D59268 Original llvm-svn: 355964 llvm-svn: 355984 --- include/llvm/IR/RemarkStreamer.h | 7 +++++++ include/llvm/LTO/Config.h | 3 +++ include/llvm/LTO/LTO.h | 1 + lib/IR/RemarkStreamer.cpp | 14 ++++++++++++++ lib/LTO/LTO.cpp | 6 ++++++ lib/LTO/LTOBackend.cpp | 8 +++++--- lib/LTO/LTOCodeGenerator.cpp | 8 +++++++- lib/LTO/ThinLTOCodeGenerator.cpp | 4 +++- .../Resolution/X86/diagnostic-handler-remarks.ll | 2 ++ test/ThinLTO/X86/diagnostic-handler-remarks.ll | 1 + tools/gold/gold-plugin.cpp | 6 +++++- tools/llc/llc.cpp | 12 ++++++++++++ tools/llvm-lto2/llvm-lto2.cpp | 7 +++++++ tools/opt/opt.cpp | 12 ++++++++++++ 14 files changed, 85 insertions(+), 6 deletions(-) diff --git a/include/llvm/IR/RemarkStreamer.h b/include/llvm/IR/RemarkStreamer.h index 38baa2b3b4b..64de27e3726 100644 --- a/include/llvm/IR/RemarkStreamer.h +++ b/include/llvm/IR/RemarkStreamer.h @@ -14,8 +14,10 @@ #define LLVM_IR_REMARKSTREAMER_H #include "llvm/IR/DiagnosticInfo.h" +#include "llvm/Support/Error.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Regex.h" #include #include @@ -26,6 +28,8 @@ class RemarkStreamer { const std::string Filename; /// The open raw_ostream that the remark diagnostics are emitted to. raw_ostream &OS; + /// The regex used to filter remarks based on the passes that emit them. + Optional PassFilter; /// The YAML streamer. yaml::Output YAMLOutput; @@ -36,6 +40,9 @@ public: StringRef getFilename() const { return Filename; } /// Return stream that the remark diagnostics are emitted to. raw_ostream &getStream() { return OS; } + /// Set a pass filter based on a regex \p Filter. + /// Returns an error if the regex is invalid. + Error setFilter(StringRef Filter); /// Emit a diagnostic through the streamer. void emit(const DiagnosticInfoOptimizationBase &Diag); }; diff --git a/include/llvm/LTO/Config.h b/include/llvm/LTO/Config.h index bf8cc98ac4d..1e2eeab11c0 100644 --- a/include/llvm/LTO/Config.h +++ b/include/llvm/LTO/Config.h @@ -96,6 +96,9 @@ struct Config { /// Optimization remarks file path. std::string RemarksFilename = ""; + /// Optimization remarks pass filter. + std::string RemarksPasses = ""; + /// Whether to emit optimization remarks with hotness informations. bool RemarksWithHotness = false; diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h index ab4d874b55e..be37dbd0c59 100644 --- a/include/llvm/LTO/LTO.h +++ b/include/llvm/LTO/LTO.h @@ -84,6 +84,7 @@ std::string getThinLTOOutputFile(const std::string &Path, /// Setup optimization remarks. Expected> setupOptimizationRemarks(LLVMContext &Context, StringRef LTORemarksFilename, + StringRef LTORemarksPasses, bool LTOPassRemarksWithHotness, int Count = -1); class LTO; diff --git a/lib/IR/RemarkStreamer.cpp b/lib/IR/RemarkStreamer.cpp index 0b983408e46..022c17d6722 100644 --- a/lib/IR/RemarkStreamer.cpp +++ b/lib/IR/RemarkStreamer.cpp @@ -21,7 +21,21 @@ RemarkStreamer::RemarkStreamer(StringRef Filename, raw_ostream &OS) assert(!Filename.empty() && "This needs to be a real filename."); } +Error RemarkStreamer::setFilter(StringRef Filter) { + Regex R = Regex(Filter); + std::string RegexError; + if (!R.isValid(RegexError)) + return createStringError(std::make_error_code(std::errc::invalid_argument), + RegexError.data()); + PassFilter = std::move(R); + return Error::success(); +} + void RemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) { + if (Optional &Filter = PassFilter) + if (!Filter->match(Diag.getPassName())) + return; + DiagnosticInfoOptimizationBase *DiagPtr = const_cast(&Diag); YAMLOutput << DiagPtr; diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index f6e34c5d061..99318c19a89 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -1312,6 +1312,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) { Expected> lto::setupOptimizationRemarks(LLVMContext &Context, StringRef LTORemarksFilename, + StringRef LTORemarksPasses, bool LTOPassRemarksWithHotness, int Count) { if (LTOPassRemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); @@ -1329,6 +1330,11 @@ lto::setupOptimizationRemarks(LLVMContext &Context, return errorCodeToError(EC); Context.setRemarkStreamer( llvm::make_unique(Filename, DiagnosticFile->os())); + + if (!LTORemarksPasses.empty()) + if (Error E = Context.getRemarkStreamer()->setFilter(LTORemarksPasses)) + return std::move(E); + DiagnosticFile->keep(); return std::move(DiagnosticFile); } diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp index 0595771bd00..64c596931fa 100644 --- a/lib/LTO/LTOBackend.cpp +++ b/lib/LTO/LTOBackend.cpp @@ -429,8 +429,9 @@ Error lto::backend(Config &C, AddStreamFn AddStream, std::unique_ptr TM = createTargetMachine(C, *TOrErr, *Mod); // Setup optimization remarks. - auto DiagFileOrErr = lto::setupOptimizationRemarks( - Mod->getContext(), C.RemarksFilename, C.RemarksWithHotness); + auto DiagFileOrErr = + lto::setupOptimizationRemarks(Mod->getContext(), C.RemarksFilename, + C.RemarksPasses, C.RemarksWithHotness); if (!DiagFileOrErr) return DiagFileOrErr.takeError(); auto DiagnosticOutputFile = std::move(*DiagFileOrErr); @@ -484,7 +485,8 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, // Setup optimization remarks. auto DiagFileOrErr = lto::setupOptimizationRemarks( - Mod.getContext(), Conf.RemarksFilename, Conf.RemarksWithHotness, Task); + Mod.getContext(), Conf.RemarksFilename, Conf.RemarksPasses, + Conf.RemarksWithHotness, Task); if (!DiagFileOrErr) return DiagFileOrErr.takeError(); auto DiagnosticOutputFile = std::move(*DiagFileOrErr); diff --git a/lib/LTO/LTOCodeGenerator.cpp b/lib/LTO/LTOCodeGenerator.cpp index 1b1de2ba187..f02907f7a86 100644 --- a/lib/LTO/LTOCodeGenerator.cpp +++ b/lib/LTO/LTOCodeGenerator.cpp @@ -85,6 +85,12 @@ cl::opt cl::desc("Output filename for pass remarks"), cl::value_desc("filename")); +cl::opt + LTORemarksPasses("lto-pass-remarks-filter", + cl::desc("Only record optimization remarks from passes " + "whose names match the given regular expression"), + cl::value_desc("regex")); + cl::opt LTOPassRemarksWithHotness( "lto-pass-remarks-with-hotness", cl::desc("With PGO, include profile count in optimization remarks"), @@ -505,7 +511,7 @@ bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline, return false; auto DiagFileOrErr = lto::setupOptimizationRemarks( - Context, LTORemarksFilename, LTOPassRemarksWithHotness); + Context, LTORemarksFilename, LTORemarksPasses, LTOPassRemarksWithHotness); if (!DiagFileOrErr) { errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; report_fatal_error("Can't get an output file for the remarks"); diff --git a/lib/LTO/ThinLTOCodeGenerator.cpp b/lib/LTO/ThinLTOCodeGenerator.cpp index 557afd6c360..d4ee66a53e0 100644 --- a/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/lib/LTO/ThinLTOCodeGenerator.cpp @@ -70,6 +70,7 @@ namespace llvm { // Flags -discard-value-names, defined in LTOCodeGenerator.cpp extern cl::opt LTODiscardValueNames; extern cl::opt LTORemarksFilename; +extern cl::opt LTORemarksPasses; extern cl::opt LTOPassRemarksWithHotness; } @@ -972,7 +973,8 @@ void ThinLTOCodeGenerator::run() { Context.setDiscardValueNames(LTODiscardValueNames); Context.enableDebugTypeODRUniquing(); auto DiagFileOrErr = lto::setupOptimizationRemarks( - Context, LTORemarksFilename, LTOPassRemarksWithHotness, count); + Context, LTORemarksFilename, LTORemarksPasses, + LTOPassRemarksWithHotness, count); if (!DiagFileOrErr) { errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; report_fatal_error("ThinLTO: Can't get an output file for the " diff --git a/test/LTO/Resolution/X86/diagnostic-handler-remarks.ll b/test/LTO/Resolution/X86/diagnostic-handler-remarks.ll index 03db4a722b5..beb0f4fa49b 100644 --- a/test/LTO/Resolution/X86/diagnostic-handler-remarks.ll +++ b/test/LTO/Resolution/X86/diagnostic-handler-remarks.ll @@ -4,6 +4,7 @@ ; RUN: llvm-as < %s >%t.bc ; RUN: rm -f %t.yaml ; RUN: llvm-lto2 run -pass-remarks-output=%t.yaml \ +; RUN: -pass-remarks-filter=inline \ ; RUN: -r %t.bc,tinkywinky,p \ ; RUN: -r %t.bc,patatino,px \ ; RUN: -r %t.bc,main,px -o %t.o %t.bc @@ -13,6 +14,7 @@ ; RUN: opt -module-summary %s -o %t.bc ; RUN: rm -f %t.thin.1.yaml ; RUN: llvm-lto2 run -pass-remarks-output=%t \ +; RUN: -pass-remarks-filter=inline \ ; RUN: -r %t.bc,tinkywinky,p \ ; RUN: -r %t.bc,patatino,px \ ; RUN: -r %t.bc,main,px -o %t.o %t.bc diff --git a/test/ThinLTO/X86/diagnostic-handler-remarks.ll b/test/ThinLTO/X86/diagnostic-handler-remarks.ll index d4606ba999d..4c13fe804d6 100644 --- a/test/ThinLTO/X86/diagnostic-handler-remarks.ll +++ b/test/ThinLTO/X86/diagnostic-handler-remarks.ll @@ -5,6 +5,7 @@ ; RUN: rm -f %t.yaml.thin.0.yaml %t.yaml.thin.1.yaml ; RUN: llvm-lto -thinlto-action=run \ ; RUN: -lto-pass-remarks-output=%t.yaml \ +; RUN: -lto-pass-remarks-filter=inline \ ; RUN: -exported-symbol _func2 \ ; RUN: -exported-symbol _main %t1.bc %t2.bc 2>&1 | \ ; RUN: FileCheck %s -allow-empty diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index fbf78b02551..dc61ff925ce 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -205,8 +205,9 @@ namespace options { /// Statistics output filename. static std::string stats_file; - // Optimization remarks filename and hotness options + // Optimization remarks filename, accepted passes and hotness options static std::string OptRemarksFilename; + static std::string OptRemarksFilter; static bool OptRemarksWithHotness = false; // Context sensitive PGO options. @@ -285,6 +286,8 @@ namespace options { dwo_dir = opt.substr(strlen("dwo_dir=")); } else if (opt.startswith("opt-remarks-filename=")) { OptRemarksFilename = opt.substr(strlen("opt-remarks-filename=")); + } else if (opt.startswith("opt-remarks-passes=")) { + OptRemarksFilter = opt.substr(strlen("opt-remarks-passes=")); } else if (opt == "opt-remarks-with-hotness") { OptRemarksWithHotness = true; } else if (opt.startswith("stats-file=")) { @@ -908,6 +911,7 @@ static std::unique_ptr createLTO(IndexWriteCallback OnIndexWrite, // Set up optimization remarks handling. Conf.RemarksFilename = options::OptRemarksFilename; + Conf.RemarksPasses = options::OptRemarksFilter; Conf.RemarksWithHotness = options::OptRemarksWithHotness; // Use new pass manager if set in driver diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index a566d15cd81..be103845e97 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -148,6 +148,12 @@ static cl::opt cl::desc("YAML output filename for pass remarks"), cl::value_desc("filename")); +static cl::opt + RemarksPasses("pass-remarks-filter", + cl::desc("Only record optimization remarks from passes whose " + "names match the given regular expression"), + cl::value_desc("regex")); + namespace { static ManagedStatic> RunPassNames; @@ -336,6 +342,12 @@ int main(int argc, char **argv) { } Context.setRemarkStreamer( llvm::make_unique(RemarksFilename, YamlFile->os())); + + if (!RemarksPasses.empty()) + if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) { + WithColor::error(errs(), argv[0]) << E << '\n'; + return 1; + } } if (InputLanguage != "" && InputLanguage != "ir" && diff --git a/tools/llvm-lto2/llvm-lto2.cpp b/tools/llvm-lto2/llvm-lto2.cpp index 6cceb8e4cf8..df51921396a 100644 --- a/tools/llvm-lto2/llvm-lto2.cpp +++ b/tools/llvm-lto2/llvm-lto2.cpp @@ -100,6 +100,12 @@ static cl::opt OptRemarksWithHotness( cl::desc("Whether to include hotness informations in the remarks.\n" "Has effect only if -pass-remarks-output is specified.")); +static cl::opt + OptRemarksPasses("pass-remarks-filter", + cl::desc("Only record optimization remarks from passes " + "whose names match the given regular expression"), + cl::value_desc("regex")); + static cl::opt SamplePGOFile("lto-sample-profile-file", cl::desc("Specify a SamplePGO profile file")); @@ -220,6 +226,7 @@ static int run(int argc, char **argv) { // Optimization remarks. Conf.RemarksFilename = OptRemarksOutput; + Conf.RemarksPasses = OptRemarksPasses; Conf.RemarksWithHotness = OptRemarksWithHotness; Conf.SampleProfile = SamplePGOFile; diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 06745b0cca0..b4c39e2fca8 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -275,6 +275,12 @@ static cl::opt cl::desc("YAML output filename for pass remarks"), cl::value_desc("filename")); +static cl::opt + RemarksPasses("pass-remarks-filter", + cl::desc("Only record optimization remarks from passes whose " + "names match the given regular expression"), + cl::value_desc("regex")); + cl::opt PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden, cl::desc("The kind of profile guided optimization"), @@ -566,6 +572,12 @@ int main(int argc, char **argv) { } Context.setRemarkStreamer(llvm::make_unique( RemarksFilename, OptRemarkFile->os())); + + if (!RemarksPasses.empty()) + if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) { + errs() << E << '\n'; + return 1; + } } // Load the input module...