diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -32,8 +32,8 @@ #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/Module.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker/Linker.h" #include "llvm/Pass.h" @@ -86,15 +86,15 @@ const CodeGenOptions CodeGenOpts) { handleAllErrors( std::move(E), - [&](const RemarkSetupFileError &E) { + [&](const LLVMRemarkSetupFileError &E) { Diags.Report(diag::err_cannot_open_file) << CodeGenOpts.OptRecordFile << E.message(); }, - [&](const RemarkSetupPatternError &E) { + [&](const LLVMRemarkSetupPatternError &E) { Diags.Report(diag::err_drv_optimization_remark_pattern) << E.message() << CodeGenOpts.OptRecordPasses; }, - [&](const RemarkSetupFormatError &E) { + [&](const LLVMRemarkSetupFormatError &E) { Diags.Report(diag::err_drv_optimization_remark_format) << CodeGenOpts.OptRecordFormat; }); @@ -309,7 +309,7 @@ CodeGenOpts, this)); Expected> OptRecordFileOrErr = - setupOptimizationRemarks( + setupLLVMOptimizationRemarks( Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness, CodeGenOpts.DiagnosticsHotnessThreshold); @@ -1150,7 +1150,7 @@ std::make_unique(CodeGenOpts, &Result)); Expected> OptRecordFileOrErr = - setupOptimizationRemarks( + setupLLVMOptimizationRemarks( Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness, CodeGenOpts.DiagnosticsHotnessThreshold); diff --git a/llvm/docs/Remarks.rst b/llvm/docs/Remarks.rst --- a/llvm/docs/Remarks.rst +++ b/llvm/docs/Remarks.rst @@ -612,6 +612,38 @@ bool HasError = LLVMRemarkParserHasError(Parser); LLVMRemarkParserDispose(Parser); +Remark streamers +================ + +The ``RemarkStreamer`` interface is used to unify the serialization +capabilities of remarks across all the components that can generate remarks. + +All remark serialization should go through the main remark streamer, the +``llvm::remarks::RemarkStreamer`` set up in the ``LLVMContext``. The interface +takes remark objects converted to ``llvm::remarks::Remark``, and takes care of +serializing it to the requested format, using the requested type of metadata, +etc. + +Typically, a specialized remark streamer will hold a reference to the one set +up in the ``LLVMContext``, and will operate on its own type of diagnostics. + +For example, LLVM IR passes will emit ``llvm::DiagnosticInfoOptimization*`` +that get converted to ``llvm::remarks::Remark`` objects. Then, clang could set +up its own specialized remark streamer that takes ``clang::Diagnostic`` +objects. This can allow various components of the frontend to emit remarks +using the same techniques as the LLVM remarks. + +This gives us the following advantages: + +* Composition: during the compilation pipeline, multiple components can set up + their specialized remark streamers that all emit remarks through the same + main streamer. +* Re-using the remark infrastructure in ``lib/Remarks``. +* Using the same file and format for the remark emitters created throughout the + compilation. + +at the cost of an extra layer of abstraction. + .. FIXME: add documentation for llvm-opt-report. .. FIXME: add documentation for Passes supporting optimization remarks .. FIXME: add documentation for IR Passes diff --git a/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h b/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h --- a/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h +++ b/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h @@ -77,7 +77,7 @@ // remarks enabled. We can't currently check whether remarks are requested // for the calling pass since that requires actually building the remark. - if (F->getContext().getRemarkStreamer() || + if (F->getContext().getLLVMRemarkStreamer() || F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled()) { auto R = RemarkBuilder(); emit((DiagnosticInfoOptimizationBase &)R); @@ -92,7 +92,7 @@ /// provide more context so that non-trivial false positives can be quickly /// detected by the user. bool allowExtraAnalysis(StringRef PassName) const { - return (F->getContext().getRemarkStreamer() || + return (F->getContext().getLLVMRemarkStreamer() || F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(PassName)); } diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -71,11 +71,14 @@ class Module; class ProfileSummaryInfo; class raw_ostream; -class RemarkStreamer; class StackMaps; class TargetLoweringObjectFile; class TargetMachine; +namespace remarks { +class RemarkStreamer; +}; + /// This class is intended to be used as a driving class for all asm writers. class AsmPrinter : public MachineFunctionPass { public: @@ -337,7 +340,7 @@ void emitStackSizeSection(const MachineFunction &MF); - void emitRemarksSection(RemarkStreamer &RS); + void emitRemarksSection(remarks::RemarkStreamer &RS); enum CFIMoveType { CFI_M_None, CFI_M_EH, CFI_M_Debug }; CFIMoveType needsCFIMoves() const; diff --git a/llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h b/llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h --- a/llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h +++ b/llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h @@ -159,7 +159,7 @@ /// that non-trivial false positives can be quickly detected by the user. bool allowExtraAnalysis(StringRef PassName) const { return ( - MF.getFunction().getContext().getRemarkStreamer() || + MF.getFunction().getContext().getLLVMRemarkStreamer() || MF.getFunction().getContext().getDiagHandlerPtr()->isAnyRemarkEnabled( PassName)); } @@ -172,7 +172,7 @@ // remarks enabled. We can't currently check whether remarks are requested // for the calling pass since that requires actually building the remark. - if (MF.getFunction().getContext().getRemarkStreamer() || + if (MF.getFunction().getContext().getLLVMRemarkStreamer() || MF.getFunction() .getContext() .getDiagHandlerPtr() diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -34,9 +34,13 @@ class SMDiagnostic; class StringRef; class Twine; -class RemarkStreamer; +class LLVMRemarkStreamer; class raw_ostream; +namespace remarks { +class RemarkStreamer; +}; + namespace SyncScope { typedef uint8_t ID; @@ -218,23 +222,27 @@ /// included in optimization diagnostics. void setDiagnosticsHotnessThreshold(uint64_t Threshold); - /// Return the streamer used by the backend to save remark diagnostics. If it - /// does not exist, diagnostics are not saved in a file but only emitted via - /// the diagnostic handler. - RemarkStreamer *getRemarkStreamer(); - const RemarkStreamer *getRemarkStreamer() const; - - /// Set the diagnostics output used for optimization diagnostics. - /// This filename may be embedded in a section for tools to find the - /// diagnostics whenever they're needed. + /// The "main remark streamer" used by all the specialized remark streamers. + /// This streamer keeps generic remark metadata in memory throughout the life + /// of the LLVMContext. This metadata may be emitted in a section in object + /// files depending on the format requirements. /// - /// If a remark streamer is already set, it will be replaced with - /// \p RemarkStreamer. + /// All specialized remark streamers should convert remarks to + /// llvm::remarks::Remark and emit them through this streamer. + remarks::RemarkStreamer *getMainRemarkStreamer(); + const remarks::RemarkStreamer *getMainRemarkStreamer() const; + void setMainRemarkStreamer( + std::unique_ptr LLVMRemarkStreamer); + + /// The "LLVM remark streamer" used by LLVM to serialize remark diagnostics + /// comming from IR and MIR passes. /// - /// By default, 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 setRemarkStreamer(std::unique_ptr RemarkStreamer); + /// If it does not exist, diagnostics are not saved in a file but only emitted + /// via the diagnostic handler. + LLVMRemarkStreamer *getLLVMRemarkStreamer(); + const LLVMRemarkStreamer *getLLVMRemarkStreamer() const; + void + setLLVMRemarkStreamer(std::unique_ptr LLVMRemarkStreamer); /// Get the prefix that should be printed in front of a diagnostic of /// the given \p Severity diff --git a/llvm/include/llvm/IR/LLVMRemarkStreamer.h b/llvm/include/llvm/IR/LLVMRemarkStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/IR/LLVMRemarkStreamer.h @@ -0,0 +1,95 @@ +//===- llvm/IR/LLVMRemarkStreamer.h - Streamer for LLVM remarks--*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the conversion between IR Diagnostics and +// serializable remarks::Remark objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_LLVMREMARKSTREAMER_H +#define LLVM_IR_LLVMREMARKSTREAMER_H + +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/Remarks/RemarkStreamer.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ToolOutputFile.h" +#include +#include + +namespace llvm { +/// Streamer for LLVM remarks which has logic for dealing with DiagnosticInfo +/// objects. +class LLVMRemarkStreamer { + remarks::RemarkStreamer &RS; + /// Convert diagnostics into remark objects. + /// The lifetime of the members of the result is bound to the lifetime of + /// the LLVM diagnostics. + remarks::Remark toRemark(const DiagnosticInfoOptimizationBase &Diag) const; + +public: + LLVMRemarkStreamer(remarks::RemarkStreamer &RS) : RS(RS) {} + /// Emit a diagnostic through the streamer. + void emit(const DiagnosticInfoOptimizationBase &Diag); +}; + +template +struct LLVMRemarkSetupErrorInfo : public ErrorInfo { + std::string Msg; + std::error_code EC; + + LLVMRemarkSetupErrorInfo(Error E) { + handleAllErrors(std::move(E), [&](const ErrorInfoBase &EIB) { + Msg = EIB.message(); + EC = EIB.convertToErrorCode(); + }); + } + + void log(raw_ostream &OS) const override { OS << Msg; } + std::error_code convertToErrorCode() const override { return EC; } +}; + +struct LLVMRemarkSetupFileError + : LLVMRemarkSetupErrorInfo { + static char ID; + using LLVMRemarkSetupErrorInfo< + LLVMRemarkSetupFileError>::LLVMRemarkSetupErrorInfo; +}; + +struct LLVMRemarkSetupPatternError + : LLVMRemarkSetupErrorInfo { + static char ID; + using LLVMRemarkSetupErrorInfo< + LLVMRemarkSetupPatternError>::LLVMRemarkSetupErrorInfo; +}; + +struct LLVMRemarkSetupFormatError + : LLVMRemarkSetupErrorInfo { + static char ID; + using LLVMRemarkSetupErrorInfo< + LLVMRemarkSetupFormatError>::LLVMRemarkSetupErrorInfo; +}; + +/// Setup optimization remarks that output to a file. +Expected> +setupLLVMOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, + StringRef RemarksPasses, StringRef RemarksFormat, + bool RemarksWithHotness, + unsigned RemarksHotnessThreshold = 0); + +/// Setup optimization remarks that output directly to a raw_ostream. +/// \p OS is managed by the caller and should be open for writing as long as \p +/// Context is streaming remarks to it. +Error setupLLVMOptimizationRemarks(LLVMContext &Context, raw_ostream &OS, + StringRef RemarksPasses, + StringRef RemarksFormat, + bool RemarksWithHotness, + unsigned RemarksHotnessThreshold = 0); + +} // end namespace llvm + +#endif // LLVM_IR_LLVMREMARKSTREAMER_H diff --git a/llvm/include/llvm/IR/RemarkStreamer.h b/llvm/include/llvm/IR/RemarkStreamer.h deleted file mode 100644 --- a/llvm/include/llvm/IR/RemarkStreamer.h +++ /dev/null @@ -1,108 +0,0 @@ -//===- llvm/IR/RemarkStreamer.h - Remark Streamer ---------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file declares the main interface for outputting remarks. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_IR_REMARKSTREAMER_H -#define LLVM_IR_REMARKSTREAMER_H - -#include "llvm/IR/DiagnosticInfo.h" -#include "llvm/Remarks/RemarkSerializer.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/Regex.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/raw_ostream.h" -#include -#include - -namespace llvm { -/// Streamer for remarks. -class RemarkStreamer { - /// The regex used to filter remarks based on the passes that emit them. - Optional PassFilter; - /// The object used to serialize the remarks to a specific format. - std::unique_ptr RemarkSerializer; - /// The filename that the remark diagnostics are emitted to. - const Optional Filename; - - /// Convert diagnostics into remark objects. - /// The lifetime of the members of the result is bound to the lifetime of - /// the LLVM diagnostics. - remarks::Remark toRemark(const DiagnosticInfoOptimizationBase &Diag); - -public: - RemarkStreamer(std::unique_ptr RemarkSerializer, - Optional Filename = None); - /// Return the filename that the remark diagnostics are emitted to. - Optional getFilename() const { - return Filename ? Optional(*Filename) : None; - } - /// Return stream that the remark diagnostics are emitted to. - raw_ostream &getStream() { return RemarkSerializer->OS; } - /// Return the serializer used for this stream. - remarks::RemarkSerializer &getSerializer() { return *RemarkSerializer; } - /// 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); - /// Check if the remarks also need to have associated metadata in a section. - bool needsSection() const; -}; - -template -struct RemarkSetupErrorInfo : public ErrorInfo { - std::string Msg; - std::error_code EC; - - RemarkSetupErrorInfo(Error E) { - handleAllErrors(std::move(E), [&](const ErrorInfoBase &EIB) { - Msg = EIB.message(); - EC = EIB.convertToErrorCode(); - }); - } - - void log(raw_ostream &OS) const override { OS << Msg; } - std::error_code convertToErrorCode() const override { return EC; } -}; - -struct RemarkSetupFileError : RemarkSetupErrorInfo { - static char ID; - using RemarkSetupErrorInfo::RemarkSetupErrorInfo; -}; - -struct RemarkSetupPatternError : RemarkSetupErrorInfo { - static char ID; - using RemarkSetupErrorInfo::RemarkSetupErrorInfo; -}; - -struct RemarkSetupFormatError : RemarkSetupErrorInfo { - static char ID; - using RemarkSetupErrorInfo::RemarkSetupErrorInfo; -}; - -/// Setup optimization remarks that output to a file. -Expected> -setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, - StringRef RemarksPasses, StringRef RemarksFormat, - bool RemarksWithHotness, - unsigned RemarksHotnessThreshold = 0); - -/// Setup optimization remarks that output directly to a raw_ostream. -/// \p OS is managed by the caller and should be open for writing as long as \p -/// Context is streaming remarks to it. -Error setupOptimizationRemarks(LLVMContext &Context, raw_ostream &OS, - StringRef RemarksPasses, StringRef RemarksFormat, - bool RemarksWithHotness, - unsigned RemarksHotnessThreshold = 0); - -} // end namespace llvm - -#endif // LLVM_IR_REMARKSTREAMER_H diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -19,8 +19,8 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/ModuleSummaryIndex.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/LTO/Config.h" #include "llvm/Linker/IRMover.h" #include "llvm/Object/IRSymtab.h" @@ -87,9 +87,9 @@ /// Setup optimization remarks. Expected> -setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, - StringRef RemarksPasses, StringRef RemarksFormat, - bool RemarksWithHotness, int Count = -1); +setupLLVMOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, + StringRef RemarksPasses, StringRef RemarksFormat, + bool RemarksWithHotness, int Count = -1); /// Setups the output file for saving statistics. Expected> diff --git a/llvm/include/llvm/Remarks/RemarkStreamer.h b/llvm/include/llvm/Remarks/RemarkStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Remarks/RemarkStreamer.h @@ -0,0 +1,73 @@ +//===- llvm/Remarks/RemarkStreamer.h ----------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the main interface for streaming remarks. +// +// This is used to stream any llvm::remarks::Remark to an open file taking +// advantage of all the serialization capabilities developed for remarks (e.g. +// metadata in a section, bitstream format, etc.). +// +// Typically, a specialized remark emitter should hold a reference to the main +// remark streamer set up in the LLVMContext, and should convert specialized +// diagnostics to llvm::remarks::Remark objects as they get emitted. +// +// Specialized remark emitters can be components like: +// * Remarks from LLVM (M)IR passes +// * Remarks from the frontend +// * Remarks from an intermediate IR +// +// This allows for composition between specialized remark emitters throughout +// the compilation pipeline, that end up in the same file, using the same format +// and serialization techniques. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_REMARKS_REMARKSTREAMER_H +#define LLVM_REMARKS_REMARKSTREAMER_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Remarks/RemarkSerializer.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { +namespace remarks { +class RemarkStreamer final { + /// The regex used to filter remarks based on the passes that emit them. + Optional PassFilter; + /// The object used to serialize the remarks to a specific format. + std::unique_ptr RemarkSerializer; + /// The filename that the remark diagnostics are emitted to. + const Optional Filename; + +public: + RemarkStreamer(std::unique_ptr RemarkSerializer, + Optional Filename = None); + + /// Return the filename that the remark diagnostics are emitted to. + Optional getFilename() const { + return Filename ? Optional(*Filename) : None; + } + /// Return stream that the remark diagnostics are emitted to. + raw_ostream &getStream() { return RemarkSerializer->OS; } + /// Return the serializer used for this stream. + remarks::RemarkSerializer &getSerializer() { return *RemarkSerializer; } + /// Set a pass filter based on a regex \p Filter. + /// Returns an error if the regex is invalid. + Error setFilter(StringRef Filter); + /// Check wether the string matches the filter. + bool matchesFilter(StringRef Str); + /// Check if the remarks also need to have associated metadata in a section. + bool needsSection() const; +}; +} // end namespace remarks +} // end namespace llvm + +#endif // LLVM_REMARKS_REMARKSTREAMER_H diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -81,7 +81,6 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/MC/MCAsmInfo.h" @@ -106,6 +105,7 @@ #include "llvm/Pass.h" #include "llvm/Remarks/Remark.h" #include "llvm/Remarks/RemarkFormat.h" +#include "llvm/Remarks/RemarkStreamer.h" #include "llvm/Remarks/RemarkStringTable.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" @@ -1400,7 +1400,7 @@ } } -void AsmPrinter::emitRemarksSection(RemarkStreamer &RS) { +void AsmPrinter::emitRemarksSection(remarks::RemarkStreamer &RS) { if (!RS.needsSection()) return; @@ -1462,7 +1462,7 @@ // Emit the remarks section contents. // FIXME: Figure out when is the safest time to emit this section. It should // not come after debug info. - if (RemarkStreamer *RS = M.getContext().getRemarkStreamer()) + if (remarks::RemarkStreamer *RS = M.getContext().getMainRemarkStreamer()) emitRemarksSection(*RS); const TargetLoweringObjectFile &TLOF = getObjFileLowering(); diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt --- a/llvm/lib/IR/CMakeLists.txt +++ b/llvm/lib/IR/CMakeLists.txt @@ -30,6 +30,7 @@ IntrinsicInst.cpp LLVMContext.cpp LLVMContextImpl.cpp + LLVMRemarkStreamer.cpp LegacyPassManager.cpp MDBuilder.cpp Mangler.cpp @@ -43,7 +44,6 @@ PassManager.cpp PassRegistry.cpp PassTimingInfo.cpp - RemarkStreamer.cpp SafepointIRVerifier.cpp ProfileSummary.cpp Statepoint.cpp diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -19,9 +19,10 @@ #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" -#include "llvm/IR/RemarkStreamer.h" +#include "llvm/Remarks/RemarkStreamer.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -142,15 +143,26 @@ return pImpl->DiagnosticsHotnessThreshold; } -RemarkStreamer *LLVMContext::getRemarkStreamer() { - return pImpl->RemarkDiagStreamer.get(); +remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() { + return pImpl->MainRemarkStreamer.get(); } -const RemarkStreamer *LLVMContext::getRemarkStreamer() const { - return const_cast(this)->getRemarkStreamer(); +const remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() const { + return const_cast(this)->getMainRemarkStreamer(); } -void LLVMContext::setRemarkStreamer( - std::unique_ptr RemarkStreamer) { - pImpl->RemarkDiagStreamer = std::move(RemarkStreamer); +void LLVMContext::setMainRemarkStreamer( + std::unique_ptr RemarkStreamer) { + pImpl->MainRemarkStreamer = std::move(RemarkStreamer); +} + +LLVMRemarkStreamer *LLVMContext::getLLVMRemarkStreamer() { + return pImpl->LLVMRemarkStreamer.get(); +} +const LLVMRemarkStreamer *LLVMContext::getLLVMRemarkStreamer() const { + return const_cast(this)->getLLVMRemarkStreamer(); +} +void LLVMContext::setLLVMRemarkStreamer( + std::unique_ptr RemarkStreamer) { + pImpl->LLVMRemarkStreamer = std::move(RemarkStreamer); } DiagnosticHandler::DiagnosticHandlerTy @@ -214,7 +226,7 @@ void LLVMContext::diagnose(const DiagnosticInfo &DI) { if (auto *OptDiagBase = dyn_cast(&DI)) - if (RemarkStreamer *RS = getRemarkStreamer()) + if (LLVMRemarkStreamer *RS = getLLVMRemarkStreamer()) RS->emit(*OptDiagBase); // If there is a report handler, use it. diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -35,8 +35,8 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/Metadata.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" @@ -1245,11 +1245,17 @@ LLVMContext::InlineAsmDiagHandlerTy InlineAsmDiagHandler = nullptr; void *InlineAsmDiagContext = nullptr; + /// The main remark streamer used by all the other streamers (e.g. IR, MIR, + /// frontends, etc.). This should only be used by the specific streamers, and + /// never directly. + std::unique_ptr MainRemarkStreamer; + std::unique_ptr DiagHandler; bool RespectDiagnosticFilters = false; bool DiagnosticsHotnessRequested = false; uint64_t DiagnosticsHotnessThreshold = 0; - std::unique_ptr RemarkDiagStreamer; + /// The specialized remark streamer used by LLVM's OptimizationRemarkEmitter. + std::unique_ptr LLVMRemarkStreamer; LLVMContext::YieldCallbackTy YieldCallback = nullptr; void *YieldOpaqueHandle = nullptr; diff --git a/llvm/lib/IR/RemarkStreamer.cpp b/llvm/lib/IR/LLVMRemarkStreamer.cpp rename from llvm/lib/IR/RemarkStreamer.cpp rename to llvm/lib/IR/LLVMRemarkStreamer.cpp --- a/llvm/lib/IR/RemarkStreamer.cpp +++ b/llvm/lib/IR/LLVMRemarkStreamer.cpp @@ -1,4 +1,4 @@ -//===- llvm/IR/RemarkStreamer.cpp - Remark Streamer -*- C++ -------------*-===// +//===- llvm/IR/LLVMRemarkStreamer.cpp - Remark Streamer -*- C++ ---------*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,45 +6,18 @@ // //===----------------------------------------------------------------------===// // -// This file contains the implementation of the remark outputting as part of -// LLVMContext. +// This file contains the implementation of the conversion between IR +// Diagnostics and serializable remarks::Remark objects. // //===----------------------------------------------------------------------===// -#include "llvm/IR/RemarkStreamer.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" -#include "llvm/Remarks/BitstreamRemarkSerializer.h" -#include "llvm/Remarks/RemarkFormat.h" -#include "llvm/Remarks/RemarkSerializer.h" -#include "llvm/Support/CommandLine.h" using namespace llvm; -static cl::opt EnableRemarksSection( - "remarks-section", - cl::desc( - "Emit a section containing remark diagnostics metadata. By default, " - "this is enabled for the following formats: yaml-strtab, bitstream."), - cl::init(cl::BOU_UNSET), cl::Hidden); - -RemarkStreamer::RemarkStreamer( - std::unique_ptr RemarkSerializer, - Optional FilenameIn) - : PassFilter(), RemarkSerializer(std::move(RemarkSerializer)), - Filename(FilenameIn ? Optional(FilenameIn->str()) : None) {} - -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(); -} - /// DiagnosticKind -> remarks::Type static remarks::Type toRemarkType(enum DiagnosticKind Kind) { switch (Kind) { @@ -81,7 +54,7 @@ /// LLVM Diagnostic -> Remark remarks::Remark -RemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) { +LLVMRemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) const { remarks::Remark R; // The result. R.RemarkType = toRemarkType(static_cast(Diag.getKind())); R.PassName = Diag.getPassName(); @@ -101,51 +74,24 @@ return R; } -void RemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) { - if (Optional &Filter = PassFilter) - if (!Filter->match(Diag.getPassName())) +void LLVMRemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) { + if (!RS.matchesFilter(Diag.getPassName())) return; // First, convert the diagnostic to a remark. remarks::Remark R = toRemark(Diag); // Then, emit the remark through the serializer. - RemarkSerializer->emit(R); + RS.getSerializer().emit(R); } -bool RemarkStreamer::needsSection() const { - if (EnableRemarksSection == cl::BOU_TRUE) - return true; - - if (EnableRemarksSection == cl::BOU_FALSE) - return false; +char LLVMRemarkSetupFileError::ID = 0; +char LLVMRemarkSetupPatternError::ID = 0; +char LLVMRemarkSetupFormatError::ID = 0; - assert(EnableRemarksSection == cl::BOU_UNSET); - - // We only need a section if we're in separate mode. - if (RemarkSerializer->Mode != remarks::SerializerMode::Separate) - return false; - - // Only some formats need a section: - // * bitstream - // * yaml-strtab - switch (RemarkSerializer->SerializerFormat) { - case remarks::Format::YAMLStrTab: - case remarks::Format::Bitstream: - return true; - default: - return false; - } -} - -char RemarkSetupFileError::ID = 0; -char RemarkSetupPatternError::ID = 0; -char RemarkSetupFormatError::ID = 0; - -Expected> -llvm::setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, - StringRef RemarksPasses, StringRef RemarksFormat, - bool RemarksWithHotness, - unsigned RemarksHotnessThreshold) { +Expected> llvm::setupLLVMOptimizationRemarks( + LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses, + StringRef RemarksFormat, bool RemarksWithHotness, + unsigned RemarksHotnessThreshold) { if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); @@ -157,7 +103,7 @@ Expected Format = remarks::parseFormat(RemarksFormat); if (Error E = Format.takeError()) - return make_error(std::move(E)); + return make_error(std::move(E)); std::error_code EC; auto Flags = *Format == remarks::Format::YAML ? sys::fs::OF_Text @@ -167,29 +113,34 @@ // We don't use llvm::FileError here because some diagnostics want the file // name separately. if (EC) - return make_error(errorCodeToError(EC)); + return make_error(errorCodeToError(EC)); Expected> RemarkSerializer = remarks::createRemarkSerializer( *Format, remarks::SerializerMode::Separate, RemarksFile->os()); if (Error E = RemarkSerializer.takeError()) - return make_error(std::move(E)); + return make_error(std::move(E)); - Context.setRemarkStreamer(std::make_unique( + // Create the main remark streamer. + Context.setMainRemarkStreamer(std::make_unique( std::move(*RemarkSerializer), RemarksFilename)); + // Create LLVM's optimization remarks streamer. + Context.setLLVMRemarkStreamer( + std::make_unique(*Context.getMainRemarkStreamer())); + if (!RemarksPasses.empty()) - if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) - return make_error(std::move(E)); + if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses)) + return make_error(std::move(E)); return std::move(RemarksFile); } -Error llvm::setupOptimizationRemarks(LLVMContext &Context, raw_ostream &OS, - StringRef RemarksPasses, - StringRef RemarksFormat, - bool RemarksWithHotness, - unsigned RemarksHotnessThreshold) { +Error llvm::setupLLVMOptimizationRemarks(LLVMContext &Context, raw_ostream &OS, + StringRef RemarksPasses, + StringRef RemarksFormat, + bool RemarksWithHotness, + unsigned RemarksHotnessThreshold) { if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); @@ -198,20 +149,25 @@ Expected Format = remarks::parseFormat(RemarksFormat); if (Error E = Format.takeError()) - return make_error(std::move(E)); + return make_error(std::move(E)); Expected> RemarkSerializer = remarks::createRemarkSerializer(*Format, remarks::SerializerMode::Separate, OS); if (Error E = RemarkSerializer.takeError()) - return make_error(std::move(E)); + return make_error(std::move(E)); + + // Create the main remark streamer. + Context.setMainRemarkStreamer( + std::make_unique(std::move(*RemarkSerializer))); - Context.setRemarkStreamer( - std::make_unique(std::move(*RemarkSerializer))); + // Create LLVM's optimization remarks streamer. + Context.setLLVMRemarkStreamer( + std::make_unique(*Context.getMainRemarkStreamer())); if (!RemarksPasses.empty()) - if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) - return make_error(std::move(E)); + if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses)) + return make_error(std::move(E)); return Error::success(); } diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -22,10 +22,10 @@ #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Metadata.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/LTO/LTOBackend.h" #include "llvm/LTO/SummaryBasedOptimizations.h" #include "llvm/Linker/IRMover.h" @@ -951,7 +951,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { // Setup optimization remarks. - auto DiagFileOrErr = lto::setupOptimizationRemarks( + auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks( RegularLTO.CombinedModule->getContext(), Conf.RemarksFilename, Conf.RemarksPasses, Conf.RemarksFormat, Conf.RemarksWithHotness); if (!DiagFileOrErr) @@ -1409,10 +1409,9 @@ return BackendProc->wait(); } -Expected> -lto::setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, - StringRef RemarksPasses, StringRef RemarksFormat, - bool RemarksWithHotness, int Count) { +Expected> lto::setupLLVMOptimizationRemarks( + LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses, + StringRef RemarksFormat, bool RemarksWithHotness, int Count) { std::string Filename = std::string(RemarksFilename); // For ThinLTO, file.opt. becomes // file.opt..thin... @@ -1421,7 +1420,7 @@ (Twine(Filename) + ".thin." + llvm::utostr(Count) + "." + RemarksFormat) .str(); - auto ResultOrErr = llvm::setupOptimizationRemarks( + auto ResultOrErr = llvm::setupLLVMOptimizationRemarks( Context, Filename, RemarksPasses, RemarksFormat, RemarksWithHotness); if (Error E = ResultOrErr.takeError()) return std::move(E); diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -20,9 +20,9 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/PassManager.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/LTO/LTO.h" #include "llvm/MC/SubtargetFeature.h" @@ -503,7 +503,7 @@ std::unique_ptr TM = createTargetMachine(Conf, *TOrErr, Mod); // Setup optimization remarks. - auto DiagFileOrErr = lto::setupOptimizationRemarks( + auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks( Mod.getContext(), Conf.RemarksFilename, Conf.RemarksPasses, Conf.RemarksFormat, Conf.RemarksWithHotness, Task); if (!DiagFileOrErr) diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -29,11 +29,11 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassTimingInfo.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" #include "llvm/LTO/LTO.h" @@ -527,8 +527,8 @@ return false; auto DiagFileOrErr = - lto::setupOptimizationRemarks(Context, RemarksFilename, RemarksPasses, - RemarksFormat, RemarksWithHotness); + lto::setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses, + RemarksFormat, RemarksWithHotness); if (!DiagFileOrErr) { errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; report_fatal_error("Can't get an output file for the remarks"); diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp --- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -27,10 +27,10 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/PassTimingInfo.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/LTO/LTO.h" @@ -1079,7 +1079,7 @@ LLVMContext Context; Context.setDiscardValueNames(LTODiscardValueNames); Context.enableDebugTypeODRUniquing(); - auto DiagFileOrErr = lto::setupOptimizationRemarks( + auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks( Context, RemarksFilename, RemarksPasses, RemarksFormat, RemarksWithHotness, count); if (!DiagFileOrErr) { diff --git a/llvm/lib/Remarks/CMakeLists.txt b/llvm/lib/Remarks/CMakeLists.txt --- a/llvm/lib/Remarks/CMakeLists.txt +++ b/llvm/lib/Remarks/CMakeLists.txt @@ -6,6 +6,7 @@ RemarkLinker.cpp RemarkParser.cpp RemarkSerializer.cpp + RemarkStreamer.cpp RemarkStringTable.cpp YAMLRemarkParser.cpp YAMLRemarkSerializer.cpp diff --git a/llvm/lib/Remarks/RemarkStreamer.cpp b/llvm/lib/Remarks/RemarkStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Remarks/RemarkStreamer.cpp @@ -0,0 +1,72 @@ +//===- llvm/Remarks/RemarkStreamer.cpp - Remark Streamer -*- C++ --------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the main remark streamer. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Remarks/RemarkStreamer.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; +using namespace llvm::remarks; + +static cl::opt EnableRemarksSection( + "remarks-section", + cl::desc( + "Emit a section containing remark diagnostics metadata. By default, " + "this is enabled for the following formats: yaml-strtab, bitstream."), + cl::init(cl::BOU_UNSET), cl::Hidden); + +RemarkStreamer::RemarkStreamer( + std::unique_ptr RemarkSerializer, + Optional FilenameIn) + : PassFilter(), RemarkSerializer(std::move(RemarkSerializer)), + Filename(FilenameIn ? Optional(FilenameIn->str()) : None) {} + +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(); +} + +bool RemarkStreamer::matchesFilter(StringRef Str) { + if (PassFilter) + return PassFilter->match(Str); + // No filter means all strings pass. + return true; +} + +bool RemarkStreamer::needsSection() const { + if (EnableRemarksSection == cl::BOU_TRUE) + return true; + + if (EnableRemarksSection == cl::BOU_FALSE) + return false; + + assert(EnableRemarksSection == cl::BOU_UNSET); + + // We only need a section if we're in separate mode. + if (RemarkSerializer->Mode != remarks::SerializerMode::Separate) + return false; + + // Only some formats need a section: + // * bitstream + // * yaml-strtab + switch (RemarkSerializer->SerializerFormat) { + case remarks::Format::YAMLStrTab: + case remarks::Format::Bitstream: + return true; + default: + return false; + } +} diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -29,9 +29,9 @@ #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/InitializePasses.h" @@ -334,9 +334,9 @@ Context.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, &HasError); Expected> RemarksFileOrErr = - setupOptimizationRemarks(Context, RemarksFilename, RemarksPasses, - RemarksFormat, RemarksWithHotness, - RemarksHotnessThreshold); + setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses, + RemarksFormat, RemarksWithHotness, + RemarksHotnessThreshold); if (Error E = RemarksFileOrErr.takeError()) { WithColor::error(errs(), argv[0]) << toString(std::move(E)) << '\n'; return 1; diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp --- a/llvm/tools/opt/opt.cpp +++ b/llvm/tools/opt/opt.cpp @@ -29,10 +29,10 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" -#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/InitializePasses.h" @@ -583,9 +583,9 @@ Context.enableDebugTypeODRUniquing(); Expected> RemarksFileOrErr = - setupOptimizationRemarks(Context, RemarksFilename, RemarksPasses, - RemarksFormat, RemarksWithHotness, - RemarksHotnessThreshold); + setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses, + RemarksFormat, RemarksWithHotness, + RemarksHotnessThreshold); if (Error E = RemarksFileOrErr.takeError()) { errs() << toString(std::move(E)) << '\n'; return 1;