[Remarks] Restructure bitstream remarks to be fully standalone (#156715)

Currently there are two serialization modes for bitstream Remarks:
standalone and separate. The separate mode splits remark metadata (e.g.
the string table) from actual remark data. The metadata is written into
the object file by the AsmPrinter, while the remark data is stored in a
separate remarks file. This means we can't use bitstream remarks with
tools like opt that don't generate an object file. Also, it is confusing
to post-process bitstream remarks files, because only the standalone
files can be read by llvm-remarkutil. We always need to use dsymutil
to convert the separate files to standalone files, which only works for
MachO. It is not possible for clang/opt to directly emit bitstream
remark files in standalone mode, because the string table can only be
serialized after all remarks were emitted.

Therefore, this change completely removes the separate serialization
mode. Instead, the remark string table is now always written to the end
of the remarks file. This requires us to tell the serializer when to
finalize remark serialization. This automatically happens when the
serializer goes out of scope. However, often the remark file goes out of
scope before the serializer is destroyed. To diagnose this, I have added
an assert to alert users that they need to explicitly call
finalizeLLVMOptimizationRemarks.

This change paves the way for further improvements to the remark
infrastructure, including more tooling (e.g. #159784), size optimizations
for bitstream remarks, and more.

Pull Request: https://github.com/llvm/llvm-project/pull/156715
This commit is contained in:
Tobias Stadler
2025-09-22 16:41:39 +01:00
committed by GitHub
parent eede47656b
commit dfbd76bda0
83 changed files with 1275 additions and 763 deletions

View File

@@ -29,6 +29,7 @@
#include "llvm/Frontend/Driver/CodeGenOptions.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSummaryIndex.h"
@@ -1384,6 +1385,10 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex,
Conf.CGFileType = getCodeGenFileType(Action);
break;
}
// FIXME: Both ExecuteAction and thinBackend set up optimization remarks for
// the same context.
finalizeLLVMOptimizationRemarks(M->getContext());
if (Error E =
thinBackend(Conf, -1, AddStream, *M, *CombinedIndex, ImportList,
ModuleToDefinedGVSummaries[M->getModuleIdentifier()],

View File

@@ -29,6 +29,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/Demangle/Demangle.h"
@@ -259,19 +260,18 @@ void BackendConsumer::HandleTranslationUnit(ASTContext &C) {
Ctx.setDefaultTargetCPU(TargetOpts.CPU);
Ctx.setDefaultTargetFeatures(llvm::join(TargetOpts.Features, ","));
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
setupLLVMOptimizationRemarks(
Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
CodeGenOpts.DiagnosticsHotnessThreshold);
Expected<LLVMRemarkFileHandle> OptRecordFileOrErr =
setupLLVMOptimizationRemarks(
Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
CodeGenOpts.DiagnosticsHotnessThreshold);
if (Error E = OptRecordFileOrErr.takeError()) {
reportOptRecordError(std::move(E), Diags, CodeGenOpts);
return;
}
std::unique_ptr<llvm::ToolOutputFile> OptRecordFile =
std::move(*OptRecordFileOrErr);
LLVMRemarkFileHandle OptRecordFile = std::move(*OptRecordFileOrErr);
if (OptRecordFile && CodeGenOpts.getProfileUse() !=
llvm::driver::ProfileInstrKind::ProfileNone)
@@ -1173,7 +1173,7 @@ void CodeGenAction::ExecuteAction() {
Ctx.setDefaultTargetCPU(TargetOpts.CPU);
Ctx.setDefaultTargetFeatures(llvm::join(TargetOpts.Features, ","));
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
Expected<LLVMRemarkFileHandle> OptRecordFileOrErr =
setupLLVMOptimizationRemarks(
Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
@@ -1183,8 +1183,7 @@ void CodeGenAction::ExecuteAction() {
reportOptRecordError(std::move(E), Diagnostics, CodeGenOpts);
return;
}
std::unique_ptr<llvm::ToolOutputFile> OptRecordFile =
std::move(*OptRecordFileOrErr);
LLVMRemarkFileHandle OptRecordFile = std::move(*OptRecordFileOrErr);
emitBackendOutput(CI, CI.getCodeGenOpts(),
CI.getTarget().getDataLayoutString(), TheModule.get(), BA,

View File

@@ -1352,7 +1352,7 @@ void CodeGenAction::executeAction() {
std::make_unique<BackendRemarkConsumer>(remarkConsumer));
// write optimization-record
llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr =
llvm::Expected<llvm::LLVMRemarkFileHandle> optRecordFileOrErr =
setupLLVMOptimizationRemarks(
llvmModule->getContext(), codeGenOpts.OptRecordFile,
codeGenOpts.OptRecordPasses, codeGenOpts.OptRecordFormat,
@@ -1364,8 +1364,7 @@ void CodeGenAction::executeAction() {
return;
}
std::unique_ptr<llvm::ToolOutputFile> optRecordFile =
std::move(*optRecordFileOrErr);
llvm::LLVMRemarkFileHandle optRecordFile = std::move(*optRecordFileOrErr);
if (optRecordFile) {
optRecordFile->keep();

View File

@@ -152,26 +152,6 @@ Other tools that support remarks:
.. option:: -opt-remarks-format=<format>
.. option:: -opt-remarks-with-hotness
Serialization modes
===================
There are two modes available for serializing remarks:
``Separate``
In this mode, the remarks and the metadata are serialized separately. The
client is responsible for parsing the metadata first, then use the metadata
to correctly parse the remarks.
``Standalone``
In this mode, the remarks and the metadata are serialized to the same
stream. The metadata will always come before the remarks.
The compiler does not support emitting standalone remarks. This mode is
more suited for post-processing tools like linkers, that can merge the
remarks for one whole project.
.. _yamlremarks:
YAML remarks
@@ -374,27 +354,11 @@ This block can contain the following records:
The remark container
--------------------
Bitstream remarks are designed to be used in two different modes:
The bitstream remark container supports multiple types:
``The separate mode``
.. _bitstreamremarksfileexternal:
The separate mode is the mode that is typically used during compilation. It
provides a way to serialize the remark entries to a stream while some
metadata is kept in memory to be emitted in the product of the compilation
(typically, an object file).
``The standalone mode``
The standalone mode is typically stored and used after the distribution of
a program. It contains all the information that allows the parsing of all
the remarks without having any external dependencies.
In order to support multiple modes, the format introduces the concept of a
bitstream remark container type.
.. _bitstreamremarksseparateremarksmeta:
``SeparateRemarksMeta: the metadata emitted separately``
``RemarksFileExternal: a link to an external remarks file``
This container type expects only a :ref:`META_BLOCK <bitstreamremarksmetablock>` containing only:
@@ -406,84 +370,33 @@ bitstream remark container type.
clients to retrieve remarks and their associated metadata directly from
intermediate products.
``SeparateRemarksFile: the remark entries emitted separately``
The container versions of the external separate container should match in order to
have a well-formed file.
This container type expects only a :ref:`META_BLOCK <bitstreamremarksmetablock>` containing only:
.. _bitstreamremarksfile:
``RemarksFile: a standalone remarks file``
This container type expects a :ref:`META_BLOCK <bitstreamremarksmetablock>` containing only:
* :ref:`RECORD_META_CONTAINER_INFO <bitstreamremarksrecordmetacontainerinfo>`
* :ref:`RECORD_META_REMARK_VERSION <bitstreamremarksrecordmetaremarkversion>`
This container type expects 0 or more :ref:`REMARK_BLOCK <bitstreamremarksremarkblock>`.
Then, this container type expects 1 or more :ref:`REMARK_BLOCK <bitstreamremarksremarkblock>`.
If no remarks are emitted, the meta blocks are also not emitted, so the file is empty.
Typically, this is emitted in a side-file alongside an object file, and is
made to be able to stream to without increasing the memory consumption of
the compiler. This is referenced by the :ref:`RECORD_META_EXTERNAL_FILE
<bitstreamremarksrecordmetaexternalfile>` entry in the
:ref:`SeparateRemarksMeta <bitstreamremarksseparateremarksmeta>` container.
When the parser tries to parse a container that contains the metadata for the
separate remarks, it should parse the version and type, then keep the string
table in memory while opening the external file, validating its metadata and
parsing the remark entries.
The container versions from the separate container should match in order to
have a well-formed file.
``Standalone: the metadata and the remark entries emitted together``
This container type expects only a :ref:`META_BLOCK <bitstreamremarksmetablock>` containing only:
* :ref:`RECORD_META_CONTAINER_INFO <bitstreamremarksrecordmetacontainerinfo>`
* :ref:`RECORD_META_REMARK_VERSION <bitstreamremarksrecordmetaremarkversion>`
After the remark blocks, another :ref:`META_BLOCK <bitstreamremarksmetablock>` is emitted, containing:
* :ref:`RECORD_META_STRTAB <bitstreamremarksrecordmetastrtab>`
This container type expects 0 or more :ref:`REMARK_BLOCK <bitstreamremarksremarkblock>`.
When the parser reads this container type, it jumps to the end of the file
to read the string table before parsing the individual remarks.
A complete output of :program:`llvm-bcanalyzer` on the different container types:
Standalone remarks files can be referenced by the
:ref:`RECORD_META_EXTERNAL_FILE <bitstreamremarksrecordmetaexternalfile>`
entry in the :ref:`RemarksFileExternal
<bitstreamremarksfileexternal>` container.
``SeparateRemarksMeta``
.. code-block:: none
<BLOCKINFO_BLOCK/>
<Meta BlockID=8 NumWords=13 BlockCodeSize=3>
<Container info codeid=1 abbrevid=4 op0=5 op1=0/>
<String table codeid=3 abbrevid=5/> blob data = 'pass\\x00key\\x00value\\x00'
<External File codeid=4 abbrevid=6/> blob data = '/path/to/file/name'
</Meta>
``SeparateRemarksFile``
.. code-block:: none
<BLOCKINFO_BLOCK/>
<Meta BlockID=8 NumWords=3 BlockCodeSize=3>
<Container info codeid=1 abbrevid=4 op0=0 op1=1/>
<Remark version codeid=2 abbrevid=5 op0=0/>
</Meta>
<Remark BlockID=9 NumWords=8 BlockCodeSize=4>
<Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>
<Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>
<Remark hotness codeid=7 abbrevid=6 op0=999999999/>
<Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 op3=11 op4=66/>
</Remark>
``Standalone``
.. code-block:: none
<BLOCKINFO_BLOCK/>
<Meta BlockID=8 NumWords=15 BlockCodeSize=3>
<Container info codeid=1 abbrevid=4 op0=5 op1=2/>
<Remark version codeid=2 abbrevid=5 op0=30/>
<String table codeid=3 abbrevid=6/> blob data = 'pass\\x00remark\\x00function\\x00path\\x00key\\x00value\\x00argpath\\x00'
</Meta>
<Remark BlockID=9 NumWords=8 BlockCodeSize=4>
<Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>
<Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>
<Remark hotness codeid=7 abbrevid=6 op0=999999999/>
<Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 op3=11 op4=66/>
</Remark>
.. FIXME: Add complete output of :program:`llvm-bcanalyzer` on the different container types (once format changes are completed)
opt-viewer
==========

View File

@@ -17,6 +17,7 @@
#include "llvm/Remarks/Remark.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ToolOutputFile.h"
#include <memory>
#include <optional>
#include <string>
@@ -82,20 +83,81 @@ struct LLVMRemarkSetupFormatError
LLVMRemarkSetupFormatError>::LLVMRemarkSetupErrorInfo;
};
/// Setup optimization remarks that output to a file.
LLVM_ABI Expected<std::unique_ptr<ToolOutputFile>> setupLLVMOptimizationRemarks(
/// RAII handle that manages the lifetime of the ToolOutputFile used to output
/// remarks. On destruction (or when calling releaseFile()), this handle ensures
/// that the optimization remarks are finalized and the RemarkStreamer is
/// correctly deregistered from the LLVMContext.
class LLVMRemarkFileHandle final {
struct Finalizer {
LLVMContext *Context;
Finalizer(LLVMContext *Ctx) : Context(Ctx) {}
Finalizer(const Finalizer &) = delete;
Finalizer &operator=(const Finalizer &) = delete;
Finalizer(Finalizer &&Other) : Context(Other.Context) {
Other.Context = nullptr;
}
Finalizer &operator=(Finalizer &&Other) {
std::swap(Context, Other.Context);
return *this;
}
~Finalizer() { finalize(); }
LLVM_ABI void finalize();
};
std::unique_ptr<ToolOutputFile> OutputFile;
Finalizer Finalize;
public:
LLVMRemarkFileHandle() : OutputFile(nullptr), Finalize(nullptr) {}
LLVMRemarkFileHandle(std::unique_ptr<ToolOutputFile> OutputFile,
LLVMContext &Ctx)
: OutputFile(std::move(OutputFile)), Finalize(&Ctx) {}
ToolOutputFile *get() { return OutputFile.get(); }
explicit operator bool() { return bool(OutputFile); }
/// Finalize remark emission and release the underlying ToolOutputFile.
std::unique_ptr<ToolOutputFile> releaseFile() {
finalize();
return std::move(OutputFile);
}
void finalize() { Finalize.finalize(); }
ToolOutputFile &operator*() { return *OutputFile; }
ToolOutputFile *operator->() { return &*OutputFile; }
};
/// Set up optimization remarks that output to a file. The LLVMRemarkFileHandle
/// manages the lifetime of the underlying ToolOutputFile to ensure \ref
/// finalizeLLVMOptimizationRemarks() is called before the file is destroyed or
/// released from the handle. The handle must be kept alive until all remarks
/// were emitted through the remark streamer.
LLVM_ABI Expected<LLVMRemarkFileHandle> setupLLVMOptimizationRemarks(
LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses,
StringRef RemarksFormat, bool RemarksWithHotness,
std::optional<uint64_t> 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.
/// Set up optimization remarks that output directly to a raw_ostream.
/// \p OS is managed by the caller and must be open for writing until
/// \ref finalizeLLVMOptimizationRemarks() is called.
LLVM_ABI Error setupLLVMOptimizationRemarks(
LLVMContext &Context, raw_ostream &OS, StringRef RemarksPasses,
StringRef RemarksFormat, bool RemarksWithHotness,
std::optional<uint64_t> RemarksHotnessThreshold = 0);
/// Finalize optimization remarks and deregister the RemarkStreamer from the \p
/// Context. This must be called before closing the (file) stream that was used
/// to set up the remarks.
LLVM_ABI void finalizeLLVMOptimizationRemarks(LLVMContext &Context);
} // end namespace llvm
#endif // LLVM_IR_LLVMREMARKSTREAMER_H

View File

@@ -15,6 +15,7 @@
#ifndef LLVM_LTO_LTO_H
#define LLVM_LTO_LTO_H
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/Support/Compiler.h"
#include <memory>
@@ -91,7 +92,7 @@ LLVM_ABI std::string getThinLTOOutputFile(StringRef Path, StringRef OldPrefix,
StringRef NewPrefix);
/// Setup optimization remarks.
LLVM_ABI Expected<std::unique_ptr<ToolOutputFile>> setupLLVMOptimizationRemarks(
LLVM_ABI Expected<LLVMRemarkFileHandle> setupLLVMOptimizationRemarks(
LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses,
StringRef RemarksFormat, bool RemarksWithHotness,
std::optional<uint64_t> RemarksHotnessThreshold = 0, int Count = -1);
@@ -579,7 +580,7 @@ private:
DenseSet<GlobalValue::GUID> DynamicExportSymbols;
// Diagnostic optimization remarks file
std::unique_ptr<ToolOutputFile> DiagnosticOutputFile;
LLVMRemarkFileHandle DiagnosticOutputFile;
};
/// The resolution for a symbol. The linker must provide a SymbolResolution for

View File

@@ -65,8 +65,7 @@ thinBackend(const Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
AddStreamFn IRAddStream = nullptr,
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
LLVM_ABI Error
finalizeOptimizationRemarks(std::unique_ptr<ToolOutputFile> DiagOutputFile);
LLVM_ABI Error finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile);
/// Returns the BitcodeModule that is ThinLTO.
LLVM_ABI BitcodeModule *findThinLTOModule(MutableArrayRef<BitcodeModule> BMs);

View File

@@ -244,7 +244,7 @@ private:
bool ShouldInternalize = EnableLTOInternalization;
bool ShouldEmbedUselists = false;
bool ShouldRestoreGlobalsLinkage = false;
std::unique_ptr<ToolOutputFile> DiagnosticOutputFile;
LLVMRemarkFileHandle DiagnosticOutputFile;
std::unique_ptr<ToolOutputFile> StatsFile = nullptr;
std::string SaveIRBeforeOptPath;

View File

@@ -23,35 +23,35 @@ namespace remarks {
/// The current version of the remark container.
/// Note: this is different from the version of the remark entry.
constexpr uint64_t CurrentContainerVersion = 0;
constexpr uint64_t CurrentContainerVersion = 1;
/// The magic number used for identifying remark blocks.
constexpr StringLiteral ContainerMagic("RMRK");
/// Type of the remark container.
/// The remark container has two modes:
/// * separate: the metadata is separate from the remarks and points to the
/// auxiliary file that contains the remarks.
/// * standalone: the metadata and the remarks are emitted together.
enum class BitstreamRemarkContainerType {
/// The metadata emitted separately.
/// This will contain the following:
/// * Container version and type
/// * String table
/// * External file
SeparateRemarksMeta,
/// The remarks emitted separately.
/// This will contain the following:
/// * Container version and type
/// * Remark version
SeparateRemarksFile,
/// Everything is emitted together.
/// This will contain the following:
/// * Container version and type
/// * Remark version
/// * String table
Standalone,
First = SeparateRemarksMeta,
Last = Standalone,
/// Emit a link to an external remarks file
/// (usually as a section of the object file, to enable discovery of all
/// remarks files from the final linked object file)
/// RemarksFileExternal:
/// | Meta:
/// | | Container info
/// | | External file
RemarksFileExternal,
/// Emit metadata and remarks into a file
/// RemarksFile:
/// | Meta:
/// | | Container info
/// | | Remark version
/// | Remarks:
/// | | Remark0
/// | | Remark1
/// | | Remark2
/// | | ...
/// | Late Meta:
/// | | String table
RemarksFile,
First = RemarksFileExternal,
Last = RemarksFile
};
/// The possible blocks that will be encountered in a bitstream remark

View File

@@ -27,31 +27,7 @@ struct Remarks;
/// Serialize the remarks to LLVM bitstream.
/// This class provides ways to emit remarks in the LLVM bitstream format and
/// its associated metadata.
///
/// * The separate model:
/// Separate meta: | Container info
/// | String table
/// | External file
///
/// Separate remarks: | Container info
/// | Remark version
/// | Remark0
/// | Remark1
/// | Remark2
/// | ...
///
/// * The standalone model: | Container info
/// | String table
/// | Remark version
/// | Remark0
/// | Remark1
/// | Remark2
/// | ...
///
struct BitstreamRemarkSerializerHelper {
/// Buffer used for encoding the bitstream before writing it to the final
/// stream.
SmallVector<char, 1024> Encoded;
/// Buffer used to construct records and pass to the bitstream writer.
SmallVector<uint64_t, 64> R;
/// The Bitstream writer.
@@ -73,7 +49,8 @@ struct BitstreamRemarkSerializerHelper {
uint64_t RecordRemarkArgWithDebugLocAbbrevID = 0;
uint64_t RecordRemarkArgWithoutDebugLocAbbrevID = 0;
BitstreamRemarkSerializerHelper(BitstreamRemarkContainerType ContainerType);
BitstreamRemarkSerializerHelper(BitstreamRemarkContainerType ContainerType,
raw_ostream &OS);
// Disable copy and move: Bitstream points to Encoded, which needs special
// handling during copy/move, but moving the vectors is probably useless
@@ -104,20 +81,15 @@ struct BitstreamRemarkSerializerHelper {
/// The block info for the remarks block.
void setupRemarkBlockInfo();
/// Emit the metadata for the remarks.
void emitMetaBlock(uint64_t ContainerVersion,
std::optional<uint64_t> RemarkVersion,
std::optional<const StringTable *> StrTab = std::nullopt,
std::optional<StringRef> Filename = std::nullopt);
/// Emit the main metadata at the beginning of the file
void emitMetaBlock(std::optional<StringRef> Filename = std::nullopt);
/// Emit the remaining metadata at the end of the file. Here we emit metadata
/// that is only known once all remarks were emitted.
void emitLateMetaBlock(const StringTable &StrTab);
/// Emit a remark block. The string table is required.
void emitRemarkBlock(const Remark &Remark, StringTable &StrTab);
/// Finalize the writing to \p OS.
void flushToStream(raw_ostream &OS);
/// Finalize the writing to a buffer.
/// The contents of the buffer remain valid for the lifetime of the object.
/// Any call to any other function in this class will invalidate the buffer.
StringRef getBuffer();
void emitRemark(const Remark &Remark, StringTable &StrTab);
};
/// Implementation of the remark serializer using LLVM bitstream.
@@ -127,68 +99,57 @@ struct BitstreamRemarkSerializer : public RemarkSerializer {
/// 2) The metadata block that contains various information about the remarks
/// in the file.
/// 3) A number of remark blocks.
/// 4) Another metadata block for metadata that is only finalized once all
/// remarks were emitted (e.g. StrTab)
/// We need to set up 1) and 2) first, so that we can emit 3) after. This flag
/// is used to emit the first two blocks only once.
bool DidSetUp = false;
/// The helper to emit bitstream.
BitstreamRemarkSerializerHelper Helper;
/// The helper to emit bitstream. This is nullopt when the Serializer has not
/// been setup yet.
std::optional<BitstreamRemarkSerializerHelper> Helper;
/// Construct a serializer that will create its own string table.
BitstreamRemarkSerializer(raw_ostream &OS, SerializerMode Mode);
BitstreamRemarkSerializer(raw_ostream &OS);
/// Construct a serializer with a pre-filled string table.
BitstreamRemarkSerializer(raw_ostream &OS, SerializerMode Mode,
StringTable StrTab);
BitstreamRemarkSerializer(raw_ostream &OS, StringTable StrTab);
~BitstreamRemarkSerializer() override;
/// Emit a remark to the stream. This also emits the metadata associated to
/// the remarks based on the SerializerMode specified at construction.
/// This writes the serialized output to the provided stream.
/// the remarks. This writes the serialized output to the provided stream.
void emit(const Remark &Remark) override;
/// Finalize emission of remarks. This emits the late metadata block and
/// flushes internal buffers. It is safe to call this function multiple times,
/// and it is automatically executed on destruction of the Serializer.
void finalize() override;
/// The metadata serializer associated to this remark serializer. Based on the
/// container type of the current serializer, the container type of the
/// metadata serializer will change.
std::unique_ptr<MetaSerializer> metaSerializer(
raw_ostream &OS,
std::optional<StringRef> ExternalFilename = std::nullopt) override;
std::unique_ptr<MetaSerializer>
metaSerializer(raw_ostream &OS, StringRef ExternalFilename) override;
static bool classof(const RemarkSerializer *S) {
return S->SerializerFormat == Format::Bitstream;
}
private:
void setup();
};
/// Serializer of metadata for bitstream remarks.
struct BitstreamMetaSerializer : public MetaSerializer {
/// This class can be used with [1] a pre-constructed
/// BitstreamRemarkSerializerHelper, or with [2] one that is owned by the meta
/// serializer. In case of [1], we need to be able to store a reference to the
/// object, while in case of [2] we need to store the whole object.
std::optional<BitstreamRemarkSerializerHelper> TmpHelper;
/// The actual helper, that can point to \p TmpHelper or to an external helper
/// object.
BitstreamRemarkSerializerHelper *Helper = nullptr;
std::optional<BitstreamRemarkSerializerHelper> Helper;
std::optional<const StringTable *> StrTab;
std::optional<StringRef> ExternalFilename;
StringRef ExternalFilename;
/// Create a new meta serializer based on \p ContainerType.
BitstreamMetaSerializer(
raw_ostream &OS, BitstreamRemarkContainerType ContainerType,
std::optional<const StringTable *> StrTab = std::nullopt,
std::optional<StringRef> ExternalFilename = std::nullopt)
: MetaSerializer(OS), TmpHelper(std::nullopt), Helper(nullptr),
StrTab(StrTab), ExternalFilename(ExternalFilename) {
TmpHelper.emplace(ContainerType);
Helper = &*TmpHelper;
BitstreamMetaSerializer(raw_ostream &OS,
BitstreamRemarkContainerType ContainerType,
StringRef ExternalFilename)
: MetaSerializer(OS), ExternalFilename(ExternalFilename) {
Helper.emplace(ContainerType, OS);
}
/// Create a new meta serializer based on a previously built \p Helper.
BitstreamMetaSerializer(
raw_ostream &OS, BitstreamRemarkSerializerHelper &Helper,
std::optional<const StringTable *> StrTab = std::nullopt,
std::optional<StringRef> ExternalFilename = std::nullopt)
: MetaSerializer(OS), TmpHelper(std::nullopt), Helper(&Helper),
StrTab(StrTab), ExternalFilename(ExternalFilename) {}
void emit() override;
};

View File

@@ -26,16 +26,6 @@ namespace remarks {
struct Remark;
enum class SerializerMode {
Separate, // A mode where the metadata is serialized separately from the
// remarks. Typically, this is used when the remarks need to be
// streamed to a side file and the metadata is embedded into the
// final result of the compilation.
Standalone // A mode where everything can be retrieved in the same
// file/buffer. Typically, this is used for storing remarks for
// later use.
};
struct MetaSerializer;
/// This is the base class for a remark serializer.
@@ -45,24 +35,27 @@ struct RemarkSerializer {
Format SerializerFormat;
/// The open raw_ostream that the remark diagnostics are emitted to.
raw_ostream &OS;
/// The serialization mode.
SerializerMode Mode;
/// The string table containing all the unique strings used in the output.
/// The table can be serialized to be consumed after the compilation.
std::optional<StringTable> StrTab;
RemarkSerializer(Format SerializerFormat, raw_ostream &OS,
SerializerMode Mode)
: SerializerFormat(SerializerFormat), OS(OS), Mode(Mode) {}
RemarkSerializer(Format SerializerFormat, raw_ostream &OS)
: SerializerFormat(SerializerFormat), OS(OS) {}
/// This is just an interface.
virtual ~RemarkSerializer() = default;
/// Finalize remark emission (e.g. finish writing metadata, flush internal
/// buffers). It is safe to call this function multiple times, and it should
/// have the same behavior as destructing the RemarkSerializer.
/// After finalizing, the behavior of emit is unspecified.
virtual void finalize() {}
/// Emit a remark to the stream.
virtual void emit(const Remark &Remark) = 0;
/// Return the corresponding metadata serializer.
virtual std::unique_ptr<MetaSerializer>
metaSerializer(raw_ostream &OS,
std::optional<StringRef> ExternalFilename = std::nullopt) = 0;
metaSerializer(raw_ostream &OS, StringRef ExternalFilename) = 0;
};
/// This is the base class for a remark metadata serializer.
@@ -79,13 +72,12 @@ struct MetaSerializer {
/// Create a remark serializer.
LLVM_ABI Expected<std::unique_ptr<RemarkSerializer>>
createRemarkSerializer(Format RemarksFormat, SerializerMode Mode,
raw_ostream &OS);
createRemarkSerializer(Format RemarksFormat, raw_ostream &OS);
/// Create a remark serializer that uses a pre-filled string table.
LLVM_ABI Expected<std::unique_ptr<RemarkSerializer>>
createRemarkSerializer(Format RemarksFormat, SerializerMode Mode,
raw_ostream &OS, remarks::StringTable StrTab);
createRemarkSerializer(Format RemarksFormat, raw_ostream &OS,
remarks::StringTable StrTab);
} // end namespace remarks
} // end namespace llvm

View File

@@ -52,6 +52,7 @@ class RemarkStreamer final {
public:
RemarkStreamer(std::unique_ptr<remarks::RemarkSerializer> RemarkSerializer,
std::optional<StringRef> Filename = std::nullopt);
~RemarkStreamer();
/// Return the filename that the remark diagnostics are emitted to.
std::optional<StringRef> getFilename() const {
@@ -61,6 +62,14 @@ public:
raw_ostream &getStream() { return RemarkSerializer->OS; }
/// Return the serializer used for this stream.
remarks::RemarkSerializer &getSerializer() { return *RemarkSerializer; }
/// Release the underlying RemarkSerializer. Destructing the RemarkStreamer
/// will assert that the RemarkStreamer has been released, to ensure that the
/// remarks were properly finalized.
std::unique_ptr<remarks::RemarkSerializer> releaseSerializer() {
return std::move(RemarkSerializer);
}
/// Set a pass filter based on a regex \p Filter.
/// Returns an error if the regex is invalid.
Error setFilter(StringRef Filter);

View File

@@ -36,28 +36,22 @@ struct LLVM_ABI YAMLRemarkSerializer : public RemarkSerializer {
/// The YAML streamer.
yaml::Output YAMLOutput;
YAMLRemarkSerializer(raw_ostream &OS, SerializerMode Mode,
std::optional<StringTable> StrTab = std::nullopt);
YAMLRemarkSerializer(raw_ostream &OS);
YAMLRemarkSerializer(raw_ostream &OS, StringTable StrTabIn);
void emit(const Remark &Remark) override;
std::unique_ptr<MetaSerializer> metaSerializer(
raw_ostream &OS,
std::optional<StringRef> ExternalFilename = std::nullopt) override;
std::unique_ptr<MetaSerializer>
metaSerializer(raw_ostream &OS, StringRef ExternalFilename) override;
static bool classof(const RemarkSerializer *S) {
return S->SerializerFormat == Format::YAML;
}
protected:
YAMLRemarkSerializer(Format SerializerFormat, raw_ostream &OS,
SerializerMode Mode,
std::optional<StringTable> StrTab = std::nullopt);
};
struct LLVM_ABI YAMLMetaSerializer : public MetaSerializer {
std::optional<StringRef> ExternalFilename;
StringRef ExternalFilename;
YAMLMetaSerializer(raw_ostream &OS, std::optional<StringRef> ExternalFilename)
YAMLMetaSerializer(raw_ostream &OS, StringRef ExternalFilename)
: MetaSerializer(OS), ExternalFilename(ExternalFilename) {}
void emit() override;

View File

@@ -78,6 +78,7 @@
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
@@ -2508,6 +2509,8 @@ void AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
void AsmPrinter::emitRemarksSection(remarks::RemarkStreamer &RS) {
if (!RS.needsSection())
return;
if (!RS.getFilename())
return;
MCSection *RemarksSection =
OutContext.getObjectFileInfo()->getRemarksSection();
@@ -2518,20 +2521,16 @@ void AsmPrinter::emitRemarksSection(remarks::RemarkStreamer &RS) {
return;
}
remarks::RemarkSerializer &RemarkSerializer = RS.getSerializer();
std::optional<SmallString<128>> Filename;
if (std::optional<StringRef> FilenameRef = RS.getFilename()) {
Filename = *FilenameRef;
sys::fs::make_absolute(*Filename);
assert(!Filename->empty() && "The filename can't be empty.");
}
SmallString<128> Filename = *RS.getFilename();
sys::fs::make_absolute(Filename);
assert(!Filename.empty() && "The filename can't be empty.");
std::string Buf;
raw_string_ostream OS(Buf);
remarks::RemarkSerializer &RemarkSerializer = RS.getSerializer();
std::unique_ptr<remarks::MetaSerializer> MetaSerializer =
Filename ? RemarkSerializer.metaSerializer(OS, Filename->str())
: RemarkSerializer.metaSerializer(OS);
RemarkSerializer.metaSerializer(OS, Filename);
MetaSerializer->emit();
// Switch to the remarks section.

View File

@@ -92,7 +92,7 @@ char LLVMRemarkSetupFileError::ID = 0;
char LLVMRemarkSetupPatternError::ID = 0;
char LLVMRemarkSetupFormatError::ID = 0;
Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks(
Expected<LLVMRemarkFileHandle> llvm::setupLLVMOptimizationRemarks(
LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses,
StringRef RemarksFormat, bool RemarksWithHotness,
std::optional<uint64_t> RemarksHotnessThreshold) {
@@ -102,7 +102,7 @@ Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks(
Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
if (RemarksFilename.empty())
return nullptr;
return LLVMRemarkFileHandle();
Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat);
if (Error E = Format.takeError())
@@ -119,24 +119,35 @@ Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks(
return make_error<LLVMRemarkSetupFileError>(errorCodeToError(EC));
Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer =
remarks::createRemarkSerializer(
*Format, remarks::SerializerMode::Separate, RemarksFile->os());
remarks::createRemarkSerializer(*Format, RemarksFile->os());
if (Error E = RemarkSerializer.takeError())
return make_error<LLVMRemarkSetupFormatError>(std::move(E));
// Create the main remark streamer.
Context.setMainRemarkStreamer(std::make_unique<remarks::RemarkStreamer>(
std::move(*RemarkSerializer), RemarksFilename));
auto RS = std::make_unique<remarks::RemarkStreamer>(
std::move(*RemarkSerializer), RemarksFilename);
if (!RemarksPasses.empty())
if (Error E = RS->setFilter(RemarksPasses)) {
RS->releaseSerializer();
return make_error<LLVMRemarkSetupPatternError>(std::move(E));
}
// Install the main remark streamer. Only install this after setting the
// filter, because this might fail.
Context.setMainRemarkStreamer(std::move(RS));
// Create LLVM's optimization remarks streamer.
Context.setLLVMRemarkStreamer(
std::make_unique<LLVMRemarkStreamer>(*Context.getMainRemarkStreamer()));
if (!RemarksPasses.empty())
if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses))
return make_error<LLVMRemarkSetupPatternError>(std::move(E));
return LLVMRemarkFileHandle{std::move(RemarksFile), Context};
}
return std::move(RemarksFile);
void LLVMRemarkFileHandle::Finalizer::finalize() {
if (!Context)
return;
finalizeLLVMOptimizationRemarks(*Context);
Context = nullptr;
}
Error llvm::setupLLVMOptimizationRemarks(
@@ -153,22 +164,34 @@ Error llvm::setupLLVMOptimizationRemarks(
return make_error<LLVMRemarkSetupFormatError>(std::move(E));
Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer =
remarks::createRemarkSerializer(*Format,
remarks::SerializerMode::Separate, OS);
remarks::createRemarkSerializer(*Format, OS);
if (Error E = RemarkSerializer.takeError())
return make_error<LLVMRemarkSetupFormatError>(std::move(E));
// Create the main remark streamer.
Context.setMainRemarkStreamer(
std::make_unique<remarks::RemarkStreamer>(std::move(*RemarkSerializer)));
auto RS =
std::make_unique<remarks::RemarkStreamer>(std::move(*RemarkSerializer));
if (!RemarksPasses.empty())
if (Error E = RS->setFilter(RemarksPasses)) {
RS->releaseSerializer();
return make_error<LLVMRemarkSetupPatternError>(std::move(E));
}
// Install the main remark streamer. Only install this after setting the
// filter, because this might fail.
Context.setMainRemarkStreamer(std::move(RS));
// Create LLVM's optimization remarks streamer.
Context.setLLVMRemarkStreamer(
std::make_unique<LLVMRemarkStreamer>(*Context.getMainRemarkStreamer()));
if (!RemarksPasses.empty())
if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses))
return make_error<LLVMRemarkSetupPatternError>(std::move(E));
return Error::success();
}
void llvm::finalizeLLVMOptimizationRemarks(LLVMContext &Context) {
Context.setLLVMRemarkStreamer(nullptr);
if (auto *RS = Context.getMainRemarkStreamer()) {
RS->releaseSerializer();
Context.setMainRemarkStreamer(nullptr);
}
}

View File

@@ -1290,11 +1290,11 @@ void lto::updateMemProfAttributes(Module &Mod,
Error LTO::runRegularLTO(AddStreamFn AddStream) {
llvm::TimeTraceScope timeScope("Run regular LTO");
LLVMContext &CombinedCtx = RegularLTO.CombinedModule->getContext();
// Setup optimization remarks.
auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(
RegularLTO.CombinedModule->getContext(), Conf.RemarksFilename,
Conf.RemarksPasses, Conf.RemarksFormat, Conf.RemarksWithHotness,
Conf.RemarksHotnessThreshold);
CombinedCtx, Conf.RemarksFilename, Conf.RemarksPasses, Conf.RemarksFormat,
Conf.RemarksWithHotness, Conf.RemarksHotnessThreshold);
LLVM_DEBUG(dbgs() << "Running regular LTO\n");
if (!DiagFileOrErr)
return DiagFileOrErr.takeError();
@@ -2177,7 +2177,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
return RunBackends(SecondRoundLTO.get());
}
Expected<std::unique_ptr<ToolOutputFile>> lto::setupLLVMOptimizationRemarks(
Expected<LLVMRemarkFileHandle> lto::setupLLVMOptimizationRemarks(
LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses,
StringRef RemarksFormat, bool RemarksWithHotness,
std::optional<uint64_t> RemarksHotnessThreshold, int Count) {

View File

@@ -540,12 +540,12 @@ static Expected<const Target *> initAndLookupTarget(const Config &C,
return T;
}
Error lto::finalizeOptimizationRemarks(
std::unique_ptr<ToolOutputFile> DiagOutputFile) {
Error lto::finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile) {
// Make sure we flush the diagnostic remarks file in case the linker doesn't
// call the global destructors before exiting.
if (!DiagOutputFile)
return Error::success();
DiagOutputFile.finalize();
DiagOutputFile->keep();
DiagOutputFile->os().flush();
return Error::success();
@@ -640,7 +640,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
auto OptimizeAndCodegen =
[&](Module &Mod, TargetMachine *TM,
std::unique_ptr<ToolOutputFile> DiagnosticOutputFile) {
LLVMRemarkFileHandle DiagnosticOutputFile) {
// Perform optimization and code generation for ThinLTO.
if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true,
/*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex,

View File

@@ -545,6 +545,7 @@ void LTOCodeGenerator::finishOptimizationRemarks() {
if (DiagnosticOutputFile) {
DiagnosticOutputFile->keep();
// FIXME: LTOCodeGenerator dtor is not invoked on Darwin
DiagnosticOutputFile.finalize();
DiagnosticOutputFile->os().flush();
}
}

View File

@@ -197,14 +197,9 @@ Error BitstreamRemarkParserHelper::parseNext() {
Loc.reset();
Args.clear();
if (Error E = expectBlock())
return E;
return parseBlock();
}
BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer)
: Stream(Buffer) {}
Error BitstreamParserHelper::expectMagic() {
std::array<char, 4> Result;
for (unsigned I = 0; I < 4; ++I)
@@ -244,14 +239,57 @@ Error BitstreamParserHelper::parseBlockInfoBlock() {
return Error::success();
}
Error BitstreamParserHelper::advanceToMetaBlock() {
Error BitstreamParserHelper::parseMeta() {
if (Error E = expectMagic())
return E;
if (Error E = parseBlockInfoBlock())
return E;
// Parse early meta block.
if (Error E = MetaHelper.expectBlock())
return E;
if (Error E = MetaHelper.parseBlock())
return E;
// Skip all Remarks blocks.
while (!Stream.AtEndOfStream()) {
auto MaybeBlockID = expectSubBlock(Stream);
if (!MaybeBlockID)
return MaybeBlockID.takeError();
if (*MaybeBlockID == META_BLOCK_ID)
break;
if (*MaybeBlockID != REMARK_BLOCK_ID)
return error("Unexpected block between meta blocks.");
// Remember first remark block.
if (!RemarkStartBitPos)
RemarkStartBitPos = Stream.GetCurrentBitNo();
if (Error E = Stream.SkipBlock())
return E;
}
// Late meta block is optional if there are no remarks.
if (Stream.AtEndOfStream())
return Error::success();
// Parse late meta block.
if (Error E = MetaHelper.parseBlock())
return E;
return Error::success();
}
Error BitstreamParserHelper::parseRemark() {
if (RemarkStartBitPos) {
RemarkStartBitPos.reset();
} else {
auto MaybeBlockID = expectSubBlock(Stream);
if (!MaybeBlockID)
return MaybeBlockID.takeError();
if (*MaybeBlockID != REMARK_BLOCK_ID)
return make_error<EndOfFileError>();
}
return RemarksHelper->parseNext();
}
Expected<std::unique_ptr<BitstreamRemarkParser>>
remarks::createBitstreamParserFromMeta(
StringRef Buf, std::optional<StringRef> ExternalFilePrependPath) {
@@ -263,45 +301,52 @@ remarks::createBitstreamParserFromMeta(
return std::move(Parser);
}
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
if (ParserHelper.atEndOfStream())
return make_error<EndOfFileError>();
BitstreamRemarkParser::BitstreamRemarkParser(StringRef Buf)
: RemarkParser(Format::Bitstream), ParserHelper(Buf) {}
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
if (!IsMetaReady) {
// Container is completely empty.
if (ParserHelper->Stream.AtEndOfStream())
return make_error<EndOfFileError>();
if (!ReadyToParseRemarks) {
if (Error E = parseMeta())
return std::move(E);
ReadyToParseRemarks = true;
IsMetaReady = true;
// Container has meta, but no remarks blocks.
if (!ParserHelper->RemarkStartBitPos)
return error(
"Container is non-empty, but does not contain any remarks blocks.");
if (Error E =
ParserHelper->Stream.JumpToBit(*ParserHelper->RemarkStartBitPos))
return std::move(E);
ParserHelper->RemarksHelper.emplace(ParserHelper->Stream);
}
return parseRemark();
if (Error E = ParserHelper->parseRemark())
return std::move(E);
return processRemark();
}
Error BitstreamRemarkParser::parseMeta() {
if (Error E = ParserHelper.advanceToMetaBlock())
if (Error E = ParserHelper->parseMeta())
return E;
BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream);
if (Error E = MetaHelper.expectBlock())
return E;
if (Error E = MetaHelper.parseBlock())
return E;
if (Error E = processCommonMeta(MetaHelper))
if (Error E = processCommonMeta())
return E;
switch (ContainerType) {
case BitstreamRemarkContainerType::Standalone:
return processStandaloneMeta(MetaHelper);
case BitstreamRemarkContainerType::SeparateRemarksFile:
return processSeparateRemarksFileMeta(MetaHelper);
case BitstreamRemarkContainerType::SeparateRemarksMeta:
return processSeparateRemarksMetaMeta(MetaHelper);
case BitstreamRemarkContainerType::RemarksFileExternal:
return processExternalFilePath();
case BitstreamRemarkContainerType::RemarksFile:
return processFileContainerMeta();
}
llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
}
Error BitstreamRemarkParser::processCommonMeta(
BitstreamMetaParserHelper &Helper) {
Error BitstreamRemarkParser::processCommonMeta() {
auto &Helper = ParserHelper->MetaHelper;
if (!Helper.Container)
return Helper.error("Missing container info.");
auto &Container = *Helper.Container;
@@ -313,7 +358,16 @@ Error BitstreamRemarkParser::processCommonMeta(
return Error::success();
}
Error BitstreamRemarkParser::processStrTab(BitstreamMetaParserHelper &Helper) {
Error BitstreamRemarkParser::processFileContainerMeta() {
if (Error E = processRemarkVersion())
return E;
if (Error E = processStrTab())
return E;
return Error::success();
}
Error BitstreamRemarkParser::processStrTab() {
auto &Helper = ParserHelper->MetaHelper;
if (!Helper.StrTabBuf)
return Helper.error("Missing string table.");
// Parse and assign the string table.
@@ -321,26 +375,25 @@ Error BitstreamRemarkParser::processStrTab(BitstreamMetaParserHelper &Helper) {
return Error::success();
}
Error BitstreamRemarkParser::processRemarkVersion(
BitstreamMetaParserHelper &Helper) {
Error BitstreamRemarkParser::processRemarkVersion() {
auto &Helper = ParserHelper->MetaHelper;
if (!Helper.RemarkVersion)
return Helper.error("Missing remark version.");
RemarkVersion = *Helper.RemarkVersion;
return Error::success();
}
Error BitstreamRemarkParser::processExternalFilePath(
BitstreamMetaParserHelper &Helper) {
Error BitstreamRemarkParser::processExternalFilePath() {
auto &Helper = ParserHelper->MetaHelper;
if (!Helper.ExternalFilePath)
return Helper.error("Missing external file path.");
StringRef ExternalFilePath = *Helper.ExternalFilePath;
SmallString<80> FullPath(ExternalFilePrependPath);
sys::path::append(FullPath, ExternalFilePath);
sys::path::append(FullPath, *Helper.ExternalFilePath);
// External file: open the external file, parse it, check if its metadata
// matches the one from the separate metadata, then replace the current parser
// with the one parsing the remarks.
// matches the one from the separate metadata, then replace the current
// parser with the one parsing the remarks.
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
MemoryBuffer::getFile(FullPath);
if (std::error_code EC = BufferOrErr.getError())
@@ -353,58 +406,19 @@ Error BitstreamRemarkParser::processExternalFilePath(
return make_error<EndOfFileError>();
// Create a separate parser used for parsing the separate file.
ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer());
// Advance and check until we can parse the meta block.
if (Error E = ParserHelper.advanceToMetaBlock())
return E;
// Parse the meta from the separate file.
// Note: here we overwrite the BlockInfo with the one from the file. This will
// be used to parse the rest of the file.
BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream);
if (Error E = SeparateMetaHelper.expectBlock())
return E;
if (Error E = SeparateMetaHelper.parseBlock())
ParserHelper.emplace(TmpRemarkBuffer->getBuffer());
if (Error E = parseMeta())
return E;
if (Error E = processCommonMeta(SeparateMetaHelper))
return E;
if (ContainerType != BitstreamRemarkContainerType::RemarksFile)
return ParserHelper->MetaHelper.error(
"Wrong container type in external file.");
if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile)
return SeparateMetaHelper.error("Wrong container type in external file.");
// Process the meta from the separate file.
return processSeparateRemarksFileMeta(SeparateMetaHelper);
return Error::success();
}
Error BitstreamRemarkParser::processStandaloneMeta(
BitstreamMetaParserHelper &Helper) {
if (Error E = processStrTab(Helper))
return E;
return processRemarkVersion(Helper);
}
Error BitstreamRemarkParser::processSeparateRemarksFileMeta(
BitstreamMetaParserHelper &Helper) {
return processRemarkVersion(Helper);
}
Error BitstreamRemarkParser::processSeparateRemarksMetaMeta(
BitstreamMetaParserHelper &Helper) {
if (Error E = processStrTab(Helper))
return E;
return processExternalFilePath(Helper);
}
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() {
BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream);
if (Error E = RemarkHelper.parseNext())
return std::move(E);
return processRemark(RemarkHelper);
}
Expected<std::unique_ptr<Remark>>
BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::processRemark() {
auto &Helper = *ParserHelper->RemarksHelper;
std::unique_ptr<Remark> Result = std::make_unique<Remark>();
Remark &R = *Result;
@@ -491,5 +505,3 @@ BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
return std::move(Result);
}
llvm::remarks::BitstreamRemarkParser::BitstreamRemarkParser(StringRef Buf)
: RemarkParser(Format::Bitstream), ParserHelper(Buf) {}

View File

@@ -187,35 +187,49 @@ struct BitstreamParserHelper {
BitstreamCursor Stream;
/// The block info block.
BitstreamBlockInfo BlockInfo;
/// Helper to parse the metadata blocks in this bitstream.
BitstreamMetaParserHelper MetaHelper;
/// Helper to parse the remark blocks in this bitstream. Only needed
/// for ContainerType RemarksFile.
std::optional<BitstreamRemarkParserHelper> RemarksHelper;
/// The position of the first remark block we encounter after
/// the initial metadata block.
std::optional<uint64_t> RemarkStartBitPos;
/// Start parsing at \p Buffer.
BitstreamParserHelper(StringRef Buffer);
BitstreamParserHelper(StringRef Buffer)
: Stream(Buffer), MetaHelper(Stream), RemarksHelper(Stream) {}
/// Parse and validate the magic number.
Error expectMagic();
/// Advance to the meta block
Error advanceToMetaBlock();
/// Parse the block info block containing all the abbrevs.
/// This needs to be called before calling any other parsing function.
Error parseBlockInfoBlock();
/// Return true if the parser reached the end of the stream.
bool atEndOfStream() { return Stream.AtEndOfStream(); }
/// Parse all metadata blocks in the file. This populates the meta helper.
Error parseMeta();
/// Parse the next remark. This populates the remark helper data.
Error parseRemark();
};
/// Parses and holds the state of the latest parsed remark.
struct BitstreamRemarkParser : public RemarkParser {
/// The buffer to parse.
BitstreamParserHelper ParserHelper;
std::optional<BitstreamParserHelper> ParserHelper;
/// The string table used for parsing strings.
std::optional<ParsedStringTable> StrTab;
/// Temporary remark buffer used when the remarks are stored separately.
std::unique_ptr<MemoryBuffer> TmpRemarkBuffer;
/// Whether the metadata has already been parsed, so we can continue parsing
/// remarks.
bool IsMetaReady = false;
/// The common metadata used to decide how to parse the buffer.
/// This is filled when parsing the metadata block.
uint64_t ContainerVersion = 0;
uint64_t RemarkVersion = 0;
BitstreamRemarkContainerType ContainerType =
BitstreamRemarkContainerType::Standalone;
/// Wether the parser is ready to parse remarks.
bool ReadyToParseRemarks = false;
BitstreamRemarkContainerType::RemarksFile;
/// Create a parser that expects to find a string table embedded in the
/// stream.
@@ -230,20 +244,15 @@ struct BitstreamRemarkParser : public RemarkParser {
/// Parse and process the metadata of the buffer.
Error parseMeta();
/// Parse a Bitstream remark.
Expected<std::unique_ptr<Remark>> parseRemark();
private:
Error processCommonMeta(BitstreamMetaParserHelper &Helper);
Error processStandaloneMeta(BitstreamMetaParserHelper &Helper);
Error processSeparateRemarksFileMeta(BitstreamMetaParserHelper &Helper);
Error processSeparateRemarksMetaMeta(BitstreamMetaParserHelper &Helper);
Error processExternalFilePath(BitstreamMetaParserHelper &Helper);
Error processStrTab(BitstreamMetaParserHelper &Helper);
Error processRemarkVersion(BitstreamMetaParserHelper &Helper);
Error processCommonMeta();
Error processFileContainerMeta();
Error processExternalFilePath();
Expected<std::unique_ptr<Remark>>
processRemark(BitstreamRemarkParserHelper &Helper);
Expected<std::unique_ptr<Remark>> processRemark();
Error processStrTab();
Error processRemarkVersion();
};
Expected<std::unique_ptr<BitstreamRemarkParser>> createBitstreamParserFromMeta(

View File

@@ -12,25 +12,23 @@
//===----------------------------------------------------------------------===//
#include "llvm/Remarks/BitstreamRemarkSerializer.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Remarks/Remark.h"
#include <cassert>
#include <optional>
using namespace llvm;
using namespace llvm::remarks;
BitstreamRemarkSerializerHelper::BitstreamRemarkSerializerHelper(
BitstreamRemarkContainerType ContainerType)
: Bitstream(Encoded), ContainerType(ContainerType) {}
static void push(SmallVectorImpl<uint64_t> &R, StringRef Str) {
append_range(R, Str);
}
BitstreamRemarkContainerType ContainerType, raw_ostream &OS)
: Bitstream(OS), ContainerType(ContainerType) {}
static void setRecordName(unsigned RecordID, BitstreamWriter &Bitstream,
SmallVectorImpl<uint64_t> &R, StringRef Str) {
R.clear();
R.push_back(RecordID);
push(R, Str);
append_range(R, Str);
Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, R);
}
@@ -41,7 +39,7 @@ static void initBlock(unsigned BlockID, BitstreamWriter &Bitstream,
Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, R);
R.clear();
push(R, Str);
append_range(R, Str);
Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, R);
}
@@ -200,75 +198,64 @@ void BitstreamRemarkSerializerHelper::setupBlockInfo() {
Bitstream.Emit(static_cast<unsigned>(C), 8);
Bitstream.EnterBlockInfoBlock();
auto ExitBlock = make_scope_exit([&] { Bitstream.ExitBlock(); });
// Setup the main metadata. Depending on the container type, we'll setup the
// required records next.
setupMetaBlockInfo();
switch (ContainerType) {
case BitstreamRemarkContainerType::SeparateRemarksMeta:
// Needs a string table that the separate remark file is using.
setupMetaStrTab();
case BitstreamRemarkContainerType::RemarksFileExternal:
// Needs to know where the external remarks file is.
setupMetaExternalFile();
break;
case BitstreamRemarkContainerType::SeparateRemarksFile:
// Contains remarks: emit the version.
setupMetaRemarkVersion();
// Contains remarks: emit the remark abbrevs.
setupRemarkBlockInfo();
break;
case BitstreamRemarkContainerType::Standalone:
return;
case BitstreamRemarkContainerType::RemarksFile:
// Contains remarks: emit the version.
setupMetaRemarkVersion();
// Needs a string table.
setupMetaStrTab();
// Contains remarks: emit the remark abbrevs.
setupRemarkBlockInfo();
break;
return;
}
Bitstream.ExitBlock();
llvm_unreachable("Unexpected BitstreamRemarkContainerType");
}
void BitstreamRemarkSerializerHelper::emitMetaBlock(
uint64_t ContainerVersion, std::optional<uint64_t> RemarkVersion,
std::optional<const StringTable *> StrTab,
std::optional<StringRef> Filename) {
// Emit the meta block
Bitstream.EnterSubblock(META_BLOCK_ID, 3);
auto ExitBlock = make_scope_exit([&] { Bitstream.ExitBlock(); });
// The container version and type.
R.clear();
R.push_back(RECORD_META_CONTAINER_INFO);
R.push_back(ContainerVersion);
R.push_back(CurrentContainerVersion);
R.push_back(static_cast<uint64_t>(ContainerType));
Bitstream.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID, R);
switch (ContainerType) {
case BitstreamRemarkContainerType::SeparateRemarksMeta:
assert(StrTab != std::nullopt && *StrTab != nullptr);
emitMetaStrTab(**StrTab);
case BitstreamRemarkContainerType::RemarksFileExternal:
assert(Filename != std::nullopt);
emitMetaExternalFile(*Filename);
break;
case BitstreamRemarkContainerType::SeparateRemarksFile:
assert(RemarkVersion != std::nullopt);
emitMetaRemarkVersion(*RemarkVersion);
break;
case BitstreamRemarkContainerType::Standalone:
assert(RemarkVersion != std::nullopt);
emitMetaRemarkVersion(*RemarkVersion);
assert(StrTab != std::nullopt && *StrTab != nullptr);
emitMetaStrTab(**StrTab);
break;
return;
case BitstreamRemarkContainerType::RemarksFile:
emitMetaRemarkVersion(CurrentRemarkVersion);
return;
}
llvm_unreachable("Unexpected BitstreamRemarkContainerType");
}
void BitstreamRemarkSerializerHelper::emitLateMetaBlock(
const StringTable &StrTab) {
// Emit the late meta block (after all remarks are serialized)
Bitstream.EnterSubblock(META_BLOCK_ID, 3);
emitMetaStrTab(StrTab);
Bitstream.ExitBlock();
}
void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark &Remark,
StringTable &StrTab) {
void BitstreamRemarkSerializerHelper::emitRemark(const Remark &Remark,
StringTable &StrTab) {
Bitstream.EnterSubblock(REMARK_BLOCK_ID, 4);
R.clear();
@@ -317,73 +304,49 @@ void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark &Remark,
Bitstream.ExitBlock();
}
void BitstreamRemarkSerializerHelper::flushToStream(raw_ostream &OS) {
OS.write(Encoded.data(), Encoded.size());
Encoded.clear();
}
StringRef BitstreamRemarkSerializerHelper::getBuffer() {
return StringRef(Encoded.data(), Encoded.size());
}
BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,
SerializerMode Mode)
: RemarkSerializer(Format::Bitstream, OS, Mode),
Helper(BitstreamRemarkContainerType::SeparateRemarksFile) {
assert(Mode == SerializerMode::Separate &&
"For SerializerMode::Standalone, a pre-filled string table needs to "
"be provided.");
// We always use a string table with bitstream.
BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS)
: RemarkSerializer(Format::Bitstream, OS) {
StrTab.emplace();
}
BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,
SerializerMode Mode,
StringTable StrTabIn)
: RemarkSerializer(Format::Bitstream, OS, Mode),
Helper(Mode == SerializerMode::Separate
? BitstreamRemarkContainerType::SeparateRemarksFile
: BitstreamRemarkContainerType::Standalone) {
: RemarkSerializer(Format::Bitstream, OS) {
StrTab = std::move(StrTabIn);
}
void BitstreamRemarkSerializer::emit(const Remark &Remark) {
if (!DidSetUp) {
// Emit the metadata that is embedded in the remark file.
// If we're in standalone mode, serialize the string table as well.
bool IsStandalone =
Helper.ContainerType == BitstreamRemarkContainerType::Standalone;
BitstreamMetaSerializer MetaSerializer(
OS, Helper,
IsStandalone ? &*StrTab
: std::optional<const StringTable *>(std::nullopt));
MetaSerializer.emit();
DidSetUp = true;
}
BitstreamRemarkSerializer::~BitstreamRemarkSerializer() { finalize(); }
assert(DidSetUp &&
"The Block info block and the meta block were not emitted yet.");
Helper.emitRemarkBlock(Remark, *StrTab);
Helper.flushToStream(OS);
void BitstreamRemarkSerializer::setup() {
if (Helper)
return;
Helper.emplace(BitstreamRemarkContainerType::RemarksFile, OS);
Helper->setupBlockInfo();
Helper->emitMetaBlock();
}
std::unique_ptr<MetaSerializer> BitstreamRemarkSerializer::metaSerializer(
raw_ostream &OS, std::optional<StringRef> ExternalFilename) {
assert(Helper.ContainerType !=
BitstreamRemarkContainerType::SeparateRemarksMeta);
bool IsStandalone =
Helper.ContainerType == BitstreamRemarkContainerType::Standalone;
void BitstreamRemarkSerializer::finalize() {
if (!Helper)
return;
Helper->emitLateMetaBlock(*StrTab);
Helper = std::nullopt;
}
void BitstreamRemarkSerializer::emit(const Remark &Remark) {
setup();
Helper->emitRemark(Remark, *StrTab);
}
std::unique_ptr<MetaSerializer>
BitstreamRemarkSerializer::metaSerializer(raw_ostream &OS,
StringRef ExternalFilename) {
return std::make_unique<BitstreamMetaSerializer>(
OS,
IsStandalone ? BitstreamRemarkContainerType::Standalone
: BitstreamRemarkContainerType::SeparateRemarksMeta,
&*StrTab, ExternalFilename);
OS, BitstreamRemarkContainerType::RemarksFileExternal, ExternalFilename);
}
void BitstreamMetaSerializer::emit() {
assert(Helper && "BitstreamMetaSerializer emitted multiple times");
Helper->setupBlockInfo();
Helper->emitMetaBlock(CurrentContainerVersion, CurrentRemarkVersion, StrTab,
ExternalFilename);
Helper->flushToStream(OS);
Helper->emitMetaBlock(ExternalFilename);
Helper = std::nullopt;
}

View File

@@ -108,7 +108,7 @@ Error RemarkLinker::link(const object::ObjectFile &Obj, Format RemarkFormat) {
Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const {
Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer =
createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS,
createRemarkSerializer(RemarksFormat, OS,
std::move(const_cast<StringTable &>(StrTab)));
if (!MaybeSerializer)
return MaybeSerializer.takeError();

View File

@@ -18,34 +18,32 @@ using namespace llvm;
using namespace llvm::remarks;
Expected<std::unique_ptr<RemarkSerializer>>
remarks::createRemarkSerializer(Format RemarksFormat, SerializerMode Mode,
raw_ostream &OS) {
remarks::createRemarkSerializer(Format RemarksFormat, raw_ostream &OS) {
switch (RemarksFormat) {
case Format::Unknown:
case Format::Auto:
return createStringError(std::errc::invalid_argument,
"Invalid remark serializer format.");
case Format::YAML:
return std::make_unique<YAMLRemarkSerializer>(OS, Mode);
return std::make_unique<YAMLRemarkSerializer>(OS);
case Format::Bitstream:
return std::make_unique<BitstreamRemarkSerializer>(OS, Mode);
return std::make_unique<BitstreamRemarkSerializer>(OS);
}
llvm_unreachable("Unknown remarks::Format enum");
}
Expected<std::unique_ptr<RemarkSerializer>>
remarks::createRemarkSerializer(Format RemarksFormat, SerializerMode Mode,
raw_ostream &OS, remarks::StringTable StrTab) {
remarks::createRemarkSerializer(Format RemarksFormat, raw_ostream &OS,
remarks::StringTable StrTab) {
switch (RemarksFormat) {
case Format::Unknown:
case Format::Auto:
return createStringError(std::errc::invalid_argument,
"Invalid remark serializer format.");
case Format::YAML:
return std::make_unique<YAMLRemarkSerializer>(OS, Mode, std::move(StrTab));
return std::make_unique<YAMLRemarkSerializer>(OS, std::move(StrTab));
case Format::Bitstream:
return std::make_unique<BitstreamRemarkSerializer>(OS, Mode,
std::move(StrTab));
return std::make_unique<BitstreamRemarkSerializer>(OS, std::move(StrTab));
}
llvm_unreachable("Unknown remarks::Format enum");
}

View File

@@ -12,6 +12,7 @@
#include "llvm/Remarks/RemarkStreamer.h"
#include "llvm/Support/CommandLine.h"
#include <cassert>
#include <optional>
using namespace llvm;
@@ -31,6 +32,14 @@ RemarkStreamer::RemarkStreamer(
Filename(FilenameIn ? std::optional<std::string>(FilenameIn->str())
: std::nullopt) {}
RemarkStreamer::~RemarkStreamer() {
// Ensure that llvm::finalizeOptimizationRemarks was called before the
// RemarkStreamer is destroyed.
assert(!RemarkSerializer &&
"RemarkSerializer must be released before RemarkStreamer is "
"destroyed. Ensure llvm::finalizeOptimizationRemarks is called.");
}
Error RemarkStreamer::setFilter(StringRef Filter) {
Regex R = Regex(Filter);
std::string RegexError;
@@ -57,16 +66,7 @@ bool RemarkStreamer::needsSection() const {
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
switch (RemarkSerializer->SerializerFormat) {
case remarks::Format::Bitstream:
return true;
default:
return false;
}
// Enable remark sections by default for bitstream remarks (so dsymutil can
// find all remarks for a linked binary)
return RemarkSerializer->SerializerFormat == Format::Bitstream;
}

View File

@@ -385,7 +385,11 @@ Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) {
if (!ValueStr)
return error("argument value is missing.", *ArgMap);
return Argument{*KeyStr, *ValueStr, Loc};
Argument Arg;
Arg.Key = *KeyStr;
Arg.Val = *ValueStr;
Arg.Loc = Loc;
return Arg;
}
Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() {

View File

@@ -19,8 +19,6 @@
using namespace llvm;
using namespace llvm::remarks;
// Use the same keys whether we use a string table or not (respectively, T is an
// unsigned or a StringRef).
static void
mapRemarkHeader(yaml::IO &io, StringRef PassName, StringRef RemarkName,
std::optional<RemarkLocation> RL, StringRef FunctionName,
@@ -131,10 +129,13 @@ template <> struct MappingTraits<Argument> {
LLVM_YAML_IS_SEQUENCE_VECTOR(Argument)
YAMLRemarkSerializer::YAMLRemarkSerializer(raw_ostream &OS, SerializerMode Mode,
std::optional<StringTable> StrTabIn)
: RemarkSerializer(Format::YAML, OS, Mode),
YAMLOutput(OS, reinterpret_cast<void *>(this)) {
YAMLRemarkSerializer::YAMLRemarkSerializer(raw_ostream &OS)
: RemarkSerializer(Format::YAML, OS),
YAMLOutput(OS, reinterpret_cast<void *>(this)) {}
YAMLRemarkSerializer::YAMLRemarkSerializer(raw_ostream &OS,
StringTable StrTabIn)
: YAMLRemarkSerializer(OS) {
StrTab = std::move(StrTabIn);
}
@@ -145,8 +146,9 @@ void YAMLRemarkSerializer::emit(const Remark &Remark) {
YAMLOutput << R;
}
std::unique_ptr<MetaSerializer> YAMLRemarkSerializer::metaSerializer(
raw_ostream &OS, std::optional<StringRef> ExternalFilename) {
std::unique_ptr<MetaSerializer>
YAMLRemarkSerializer::metaSerializer(raw_ostream &OS,
StringRef ExternalFilename) {
return std::make_unique<YAMLMetaSerializer>(OS, ExternalFilename);
}
@@ -186,6 +188,5 @@ void YAMLMetaSerializer::emit() {
support::endian::write64le(StrTabSizeBuf.data(), StrTabSize);
OS.write(StrTabSizeBuf.data(), StrTabSizeBuf.size());
if (ExternalFilename)
emitExternalFile(OS, *ExternalFilename);
emitExternalFile(OS, ExternalFilename);
}

View File

@@ -8,6 +8,11 @@
; RUN: -pass-remarks-with-hotness 2>&1 | FileCheck %s
; RUN: cat %t | FileCheck -check-prefixes=YAML,YAML-NO-ANNOTATE %s
; RUN: opt < %s -S -passes=inline -pass-remarks-output=%t.bitstream -pass-remarks=inline \
; RUN: -pass-remarks-missed=inline -pass-remarks-analysis=inline \
; RUN: -pass-remarks-with-hotness -pass-remarks-format=bitstream 2>&1 | FileCheck %s
; RUN: llvm-remarkutil bitstream2yaml %t.bitstream | FileCheck -check-prefixes=YAML,YAML-NO-ANNOTATE %s
; RUN: opt < %s -S -passes=inliner-wrapper -pass-remarks-output=%t -pass-remarks=inline \
; RUN: -pass-remarks-missed=inline -pass-remarks-analysis=inline \
; RUN: -annotate-inline-phase=false \

View File

@@ -0,0 +1,13 @@
RUN: rm -rf %t
RUN: mkdir -p %t
RUN: cat %p/../Inputs/remarks/basic.macho.remarks.empty.arm64 > %t/basic.macho.remarks.empty.arm64
RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.empty.arm64
Check that the remark file in the bundle does not exist:
RUN: not cat %t/basic.macho.remarks.empty.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 2>&1
RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.empty.arm64
Check that the remark file in the bundle does not exist:
RUN: not cat %t/basic.macho.remarks.empty.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.empty.arm64 2>&1

View File

@@ -0,0 +1,81 @@
RUN: rm -rf %t
RUN: mkdir -p %t/private/tmp/remarks
RUN: cat %p/../Inputs/remarks/basic.macho.remarks.arm64> %t/basic.macho.remarks.arm64
RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml -o %t/private/tmp/remarks/basic1.macho.remarks.arm64.opt.bitstream
RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.yaml -o %t/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream
RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml -o %t/private/tmp/remarks/basic3.macho.remarks.arm64.opt.bitstream
RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64
Check that the remark file in the bundle exists and is sane:
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s
RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64
Check that the remark file in the bundle exists and is sane:
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s
Now emit it in a different format: YAML.
RUN: dsymutil -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64
RUN: cat %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s --check-prefix=CHECK-YAML
RUN: dsymutil --linker parallel -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64
RUN: cat %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s --check-prefix=CHECK-YAML
CHECK: <Meta
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK-NOT: <Remark Num
CHECK: <Meta
CHECK-YAML:--- !Passed
CHECK-YAML:--- !Passed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-NOT: --- !

View File

@@ -22,9 +22,9 @@
Remarks compilation:
for FILE in basic1.c basic2.c basic3.c; do
clang -gline-tables-only -c $FILE -fsave-optimization-record=bitstream -foptimization-record-file=/remarks/${FILE%.c}.macho.remarks.x86_64.opt.bitstream -o ${FILE%.c}.macho.remarks.x86_64.o
clang -gline-tables-only -c $FILE -fsave-optimization-record=bitstream -foptimization-record-file=${FILE%.c}.macho.remarks.arm64.opt.bitstream -o ${FILE%.c}.macho.remarks.arm64.o
done
clang basic1.macho.remarks.x86_64.o basic2.macho.remarks.x86_64.o basic3.macho.remarks.x86_64.o -o basic.macho.remarks.x86_64 -Wl,-dead_strip
clang basic1.macho.remarks.arm64.o basic2.macho.remarks.arm64.o basic3.macho.remarks.arm64.o -o basic.macho.remarks.arm64 -Wl,-dead_strip
Remarks archive compilation (after remarks compilation):
ar -q libbasic.a basic1.macho.x86_64.o basic2.macho.x86_64.o basic3.macho.x86_64.o

View File

@@ -0,0 +1,47 @@
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: basic1.c, Line: 38, Column: 10 }
Function: main
Args:
- Callee: foo
DebugLoc: { File: basic1.c, Line: 0, Column: 0 }
- String: ' will not be inlined into '
- Caller: main
DebugLoc: { File: basic1.c, Line: 37, Column: 0 }
- String: ' because its definition is unavailable'
...
--- !Analysis
Pass: prologepilog
Name: StackSize
DebugLoc: { File: basic1.c, Line: 37, Column: 0 }
Function: main
Args:
- NumStackBytes: '0'
- String: ' stack bytes in function '''
- Function: main
- String: ''''
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
DebugLoc: { File: basic1.c, Line: 38, Column: 10 }
Function: main
Args:
- String: 'BasicBlock: '
- BasicBlock: entry
- String: "\n"
- String: TCRETURNdi
- String: ': '
- INST_TCRETURNdi: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionCount
DebugLoc: { File: basic1.c, Line: 37, Column: 0 }
Function: main
Args:
- NumInstructions: '1'
- String: ' instructions in function'
...

View File

@@ -0,0 +1,194 @@
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: basic2.c, Line: 11, Column: 3 }
Function: unused1
Args:
- Callee: bar
DebugLoc: { File: basic2.c, Line: 0, Column: 0 }
- String: ' will not be inlined into '
- Caller: unused1
DebugLoc: { File: basic2.c, Line: 10, Column: 0 }
- String: ' because its definition is unavailable'
...
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: basic2.c, Line: 20, Column: 10 }
Function: foo
Args:
- Callee: bar
DebugLoc: { File: basic2.c, Line: 0, Column: 0 }
- String: ' will not be inlined into '
- Caller: foo
DebugLoc: { File: basic2.c, Line: 19, Column: 0 }
- String: ' because its definition is unavailable'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: basic2.c, Line: 20, Column: 25 }
Function: foo
Args:
- String: ''''
- Callee: inc
DebugLoc: { File: basic2.c, Line: 14, Column: 0 }
- String: ''' inlined into '''
- Caller: foo
DebugLoc: { File: basic2.c, Line: 19, Column: 0 }
- String: ''''
- String: ' with '
- String: '(cost='
- Cost: '-15015'
- String: ', threshold='
- Threshold: '75'
- String: ')'
- String: ' at callsite '
- String: foo
- String: ':'
- Line: '1'
- String: ':'
- Column: '25'
- String: ';'
...
--- !Missed
Pass: gvn
Name: LoadClobbered
DebugLoc: { File: basic2.c, Line: 15, Column: 10 }
Function: foo
Args:
- String: 'load of type '
- Type: i32
- String: ' not eliminated'
- String: ' because it is clobbered by '
- ClobberedBy: call
DebugLoc: { File: basic2.c, Line: 20, Column: 10 }
...
--- !Missed
Pass: gvn
Name: LoadClobbered
DebugLoc: { File: basic2.c, Line: 20, Column: 36 }
Function: foo
Args:
- String: 'load of type '
- Type: i32
- String: ' not eliminated'
- String: ' because it is clobbered by '
- ClobberedBy: call
DebugLoc: { File: basic2.c, Line: 20, Column: 10 }
...
--- !Analysis
Pass: prologepilog
Name: StackSize
DebugLoc: { File: basic2.c, Line: 10, Column: 0 }
Function: unused1
Args:
- NumStackBytes: '0'
- String: ' stack bytes in function '''
- Function: unused1
- String: ''''
...
--- !Analysis
Pass: prologepilog
Name: StackSize
DebugLoc: { File: basic2.c, Line: 19, Column: 0 }
Function: foo
Args:
- NumStackBytes: '16'
- String: ' stack bytes in function '''
- Function: foo
- String: ''''
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
DebugLoc: { File: basic2.c, Line: 11, Column: 7 }
Function: unused1
Args:
- String: 'BasicBlock: '
- BasicBlock: entry
- String: "\n"
- String: ADRP
- String: ': '
- INST_ADRP: '1'
- String: "\n"
- String: LDRWui
- String: ': '
- INST_LDRWui: '1'
- String: "\n"
- String: TCRETURNdi
- String: ': '
- INST_TCRETURNdi: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionCount
DebugLoc: { File: basic2.c, Line: 10, Column: 0 }
Function: unused1
Args:
- NumInstructions: '3'
- String: ' instructions in function'
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
Function: foo
Args:
- String: 'BasicBlock: '
- BasicBlock: entry
- String: "\n"
- String: ADDWrs
- String: ': '
- INST_ADDWrs: '3'
- String: "\n"
- String: ADRP
- String: ': '
- INST_ADRP: '3'
- String: "\n"
- String: LDRWui
- String: ': '
- INST_LDRWui: '3'
- String: "\n"
- String: ADDWri
- String: ': '
- INST_ADDWri: '2'
- String: "\n"
- String: STRWui
- String: ': '
- INST_STRWui: '2'
- String: "\n"
- String: ADDXri
- String: ': '
- INST_ADDXri: '1'
- String: "\n"
- String: BL
- String: ': '
- INST_BL: '1'
- String: "\n"
- String: LDPXpost
- String: ': '
- INST_LDPXpost: '1'
- String: "\n"
- String: LDRXui
- String: ': '
- INST_LDRXui: '1'
- String: "\n"
- String: RET
- String: ': '
- INST_RET: '1'
- String: "\n"
- String: STPXpre
- String: ': '
- INST_STPXpre: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionCount
DebugLoc: { File: basic2.c, Line: 19, Column: 0 }
Function: foo
Args:
- NumInstructions: '19'
- String: ' instructions in function'
...

View File

@@ -0,0 +1,181 @@
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: basic3.c, Line: 8, Column: 10 }
Function: unused2
Args:
- Callee: foo
DebugLoc: { File: basic3.c, Line: 0, Column: 0 }
- String: ' will not be inlined into '
- Caller: unused2
DebugLoc: { File: basic3.c, Line: 7, Column: 0 }
- String: ' because its definition is unavailable'
...
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: basic3.c, Line: 19, Column: 10 }
Function: bar
Args:
- Callee: foo
DebugLoc: { File: basic3.c, Line: 0, Column: 0 }
- String: ' will not be inlined into '
- Caller: bar
DebugLoc: { File: basic3.c, Line: 16, Column: 0 }
- String: ' because its definition is unavailable'
...
--- !Passed
Pass: inline
Name: Inlined
DebugLoc: { File: basic3.c, Line: 18, Column: 12 }
Function: bar
Args:
- String: ''''
- Callee: inc
DebugLoc: { File: basic3.c, Line: 11, Column: 0 }
- String: ''' inlined into '''
- Caller: bar
DebugLoc: { File: basic3.c, Line: 16, Column: 0 }
- String: ''''
- String: ' with '
- String: '(cost='
- Cost: '-15015'
- String: ', threshold='
- Threshold: '75'
- String: ')'
- String: ' at callsite '
- String: bar
- String: ':'
- Line: '2'
- String: ':'
- Column: '12'
- String: ';'
...
--- !Analysis
Pass: prologepilog
Name: StackSize
DebugLoc: { File: basic3.c, Line: 7, Column: 0 }
Function: unused2
Args:
- NumStackBytes: '0'
- String: ' stack bytes in function '''
- Function: unused2
- String: ''''
...
--- !Analysis
Pass: prologepilog
Name: StackSize
DebugLoc: { File: basic3.c, Line: 16, Column: 0 }
Function: bar
Args:
- NumStackBytes: '0'
- String: ' stack bytes in function '''
- Function: bar
- String: ''''
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
DebugLoc: { File: basic3.c, Line: 8, Column: 14 }
Function: unused2
Args:
- String: 'BasicBlock: '
- BasicBlock: entry
- String: "\n"
- String: ADRP
- String: ': '
- INST_ADRP: '1'
- String: "\n"
- String: LDRWui
- String: ': '
- INST_LDRWui: '1'
- String: "\n"
- String: TCRETURNdi
- String: ': '
- INST_TCRETURNdi: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionCount
DebugLoc: { File: basic3.c, Line: 7, Column: 0 }
Function: unused2
Args:
- NumInstructions: '3'
- String: ' instructions in function'
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
DebugLoc: { File: basic3.c, Line: 0, Column: 0 }
Function: bar
Args:
- String: 'BasicBlock: '
- BasicBlock: entry
- String: "\n"
- String: ADRP
- String: ': '
- INST_ADRP: '1'
- String: "\n"
- String: Bcc
- String: ': '
- INST_Bcc: '1'
- String: "\n"
- String: LDRWui
- String: ': '
- INST_LDRWui: '1'
- String: "\n"
- String: SUBSWri
- String: ': '
- INST_SUBSWri: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
DebugLoc: { File: basic3.c, Line: 12, Column: 10 }
Function: bar
Args:
- String: 'BasicBlock: '
- BasicBlock: if.then
- String: "\n"
- String: ADDWri
- String: ': '
- INST_ADDWri: '1'
- String: "\n"
- String: RET
- String: ': '
- INST_RET: '1'
- String: "\n"
- String: STRWui
- String: ': '
- INST_STRWui: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
DebugLoc: { File: basic3.c, Line: 19, Column: 18 }
Function: bar
Args:
- String: 'BasicBlock: '
- BasicBlock: if.end
- String: "\n"
- String: ADDWrs
- String: ': '
- INST_ADDWrs: '1'
- String: "\n"
- String: TCRETURNdi
- String: ': '
- INST_TCRETURNdi: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionCount
DebugLoc: { File: basic3.c, Line: 16, Column: 0 }
Function: bar
Args:
- NumInstructions: '9'
- String: ' instructions in function'
...

View File

@@ -0,0 +1,53 @@
--- !Analysis
Pass: prologepilog
Name: StackSize
DebugLoc: { File: fat.macho.remarks.x86.c, Line: 14, Column: 0 }
Function: main
Args:
- NumStackBytes: '8'
- String: ' stack bytes in function '''
- Function: main
- String: ''''
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
Function: main
Args:
- String: 'BasicBlock: '
- BasicBlock: entry
- String: "\n"
- String: MOV32mi
- String: ': '
- INST_MOV32mi: '1'
- String: "\n"
- String: MOV64rr
- String: ': '
- INST_MOV64rr: '1'
- String: "\n"
- String: POP64r
- String: ': '
- INST_POP64r: '1'
- String: "\n"
- String: PUSH64r
- String: ': '
- INST_PUSH64r: '1'
- String: "\n"
- String: RET64
- String: ': '
- INST_RET64: '1'
- String: "\n"
- String: XOR32rr
- String: ': '
- INST_XOR32rr: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionCount
DebugLoc: { File: fat.macho.remarks.x86.c, Line: 14, Column: 0 }
Function: main
Args:
- NumInstructions: '6'
- String: ' instructions in function'
...

View File

@@ -0,0 +1,53 @@
--- !Analysis
Pass: prologepilog
Name: StackSize
DebugLoc: { File: fat.macho.remarks.x86.c, Line: 14, Column: 0 }
Function: main
Args:
- NumStackBytes: '8'
- String: ' stack bytes in function '''
- Function: main
- String: ''''
...
--- !Analysis
Pass: asm-printer
Name: InstructionMix
Function: main
Args:
- String: 'BasicBlock: '
- BasicBlock: entry
- String: "\n"
- String: MOV32mi
- String: ': '
- INST_MOV32mi: '1'
- String: "\n"
- String: MOV64rr
- String: ': '
- INST_MOV64rr: '1'
- String: "\n"
- String: POP64r
- String: ': '
- INST_POP64r: '1'
- String: "\n"
- String: PUSH64r
- String: ': '
- INST_PUSH64r: '1'
- String: "\n"
- String: RET64
- String: ': '
- INST_RET64: '1'
- String: "\n"
- String: XOR32rr
- String: ': '
- INST_XOR32rr: '1'
- String: "\n"
...
--- !Analysis
Pass: asm-printer
Name: InstructionCount
DebugLoc: { File: fat.macho.remarks.x86.c, Line: 14, Column: 0 }
Function: main
Args:
- NumInstructions: '6'
- String: ' instructions in function'
...

View File

@@ -4,11 +4,11 @@
* - fat.macho.remarks.x86
*/
/* for ARCH in x86_64 x86_64h i386
/* for ARCH in x86_64 x86_64h
* do
* clang -gline-tables-only -c fat.macho.remarks.x86.c -fsave-optimization-record=bitstream -foptimization-record-file=fat.macho.remarks."$ARCH".opt.bitstream -mllvm -remarks-section -arch "$ARCH"
* done
* lipo -create -output fat.macho.remarks.x86.o fat.macho.remarks.x86_64.o fat.macho.remarks.x86_64h.o fat.macho.remarks.i386.o
* clang -gline-tables-only fat.macho.remarks.x86.o -arch x86_64 -arch x86_64h -arch i386 -o fat.macho.remarks.x86
* lipo -create -output fat.macho.remarks.x86.o fat.macho.remarks.x86_64.o fat.macho.remarks.x86_64h.o
* clang -gline-tables-only fat.macho.remarks.x86.o -arch x86_64 -arch x86_64h -o fat.macho.remarks.x86
*/
int main(void) { return 0; }

View File

@@ -1,13 +0,0 @@
RUN: rm -rf %t
RUN: mkdir -p %t
RUN: cat %p/../Inputs/remarks/basic.macho.remarks.empty.x86_64 > %t/basic.macho.remarks.empty.x86_64
RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.empty.x86_64
Check that the remark file in the bundle does not exist:
RUN: not cat %t/basic.macho.remarks.empty.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.empty.x86_64 2>&1
RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.empty.x86_64
Check that the remark file in the bundle does not exist:
RUN: not cat %t/basic.macho.remarks.empty.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.empty.x86_64 2>&1

View File

@@ -1,67 +0,0 @@
RUN: rm -rf %t
RUN: mkdir -p %t
RUN: cat %p/../Inputs/remarks/basic.macho.remarks.x86_64 > %t/basic.macho.remarks.x86_64
RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.x86_64
Check that the remark file in the bundle exists and is sane:
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s
RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.x86_64
Check that the remark file in the bundle exists and is sane:
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s
Now emit it in a different format: YAML.
RUN: dsymutil -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.x86_64
RUN: cat %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s --check-prefix=CHECK-YAML
RUN: dsymutil --linker parallel -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.x86_64
RUN: cat %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s --check-prefix=CHECK-YAML
CHECK: <Meta
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK: <Remark Num
CHECK-NOT: <Remark Num
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Missed
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-YAML:--- !Analysis
CHECK-NOT: --- !

View File

@@ -1,25 +1,26 @@
REQUIRES: system-darwin
RUN: rm -rf %t
RUN: mkdir -p %t
RUN: mkdir -p %t/private/tmp/remarks
RUN: cat %p/../Inputs/remarks/fat.macho.remarks.x86 > %t/fat.macho.remarks.x86
RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.yaml -o %t/private/tmp/remarks/fat.macho.remarks.x86_64.opt.bitstream
RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.yaml -o %t/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.bitstream
RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/fat.macho.remarks.x86
RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/fat.macho.remarks.x86
Check that the remark files in the bundle exist and are all sane:
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64h | FileCheck %s
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64 | FileCheck %s
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-i386 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-i386
RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/fat.macho.remarks.x86
RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/fat.macho.remarks.x86
Check that the remark files in the bundle exist and are all sane:
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64h | FileCheck %s
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64 | FileCheck %s
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-i386 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-i386
CHECK: <Meta
CHECK: <Remark Num
CHECK: <Remark Num
CHECK-i386: <Remark Num
CHECK: <Remark Num
CHECK-NOT: <Remark Num
CHECK: <Meta

View File

@@ -1,8 +1,11 @@
RUN: llvm-remarkutil bitstream2yaml %p/Inputs/two-remarks.bitstream -o %t.yaml
RUN: FileCheck %s -strict-whitespace < %t.yaml
RUN: not llvm-remarkutil bitstream2yaml %p/Inputs/two-remarks.v0.bitstream 2>&1 -o - | FileCheck %s --check-prefix=ERR
RUN: llvm-remarkutil yaml2bitstream %p/Inputs/two-remarks.yaml -o %t.bitstream
RUN: llvm-remarkutil bitstream2yaml %t.bitstream -o - | FileCheck %s -strict-whitespace
; ERR: error: Unsupported remark container version (expected: 1, read: 0). Please upgrade/downgrade your toolchain to read this container.
; CHECK: --- !Analysis
; CHECK-NEXT: Pass: prologepilog
; CHECK-NEXT: Name: StackSize

View File

@@ -291,6 +291,7 @@ ErrorOr<std::unique_ptr<DWARFFile>> DwarfLinkerForBinary::loadObject(
[&](StringRef FileName) { BinHolder.eraseObjectEntry(FileName); });
Error E = RL.link(*ErrorOrObj);
// FIXME: Remark parsing errors are not propagated to the user.
if (Error NewE = handleErrors(
std::move(E), [&](std::unique_ptr<FileError> EC) -> Error {
return remarksErrorHandler(Obj, *this, std::move(EC));

View File

@@ -387,13 +387,13 @@ int main(int argc, char **argv) {
// Set a diagnostic handler that doesn't exit on the first error
Context.setDiagnosticHandler(std::make_unique<LLCDiagnosticHandler>());
Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr =
Expected<LLVMRemarkFileHandle> RemarksFileOrErr =
setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
RemarksFormat, RemarksWithHotness,
RemarksHotnessThreshold);
if (Error E = RemarksFileOrErr.takeError())
reportError(std::move(E), RemarksFilename);
std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr);
LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr);
if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir")
reportError("input language must be '', 'IR' or 'MIR'");

View File

@@ -80,8 +80,8 @@ static Error tryReserializeYAML2Bitstream(
if (!MaybeOF)
return MaybeOF.takeError();
auto OF = std::move(*MaybeOF);
auto MaybeSerializer = createRemarkSerializer(
OutputFormat, SerializerMode::Standalone, OF->os(), std::move(StrTab));
auto MaybeSerializer =
createRemarkSerializer(OutputFormat, OF->os(), std::move(StrTab));
if (!MaybeSerializer)
return MaybeSerializer.takeError();
auto Serializer = std::move(*MaybeSerializer);
@@ -110,8 +110,7 @@ static Error tryBitstream2YAML() {
if (!MaybeOF)
return MaybeOF.takeError();
auto OF = std::move(*MaybeOF);
auto MaybeSerializer = createRemarkSerializer(
OutputFormat, SerializerMode::Standalone, OF->os());
auto MaybeSerializer = createRemarkSerializer(OutputFormat, OF->os());
if (!MaybeSerializer)
return MaybeSerializer.takeError();

View File

@@ -510,7 +510,7 @@ extern "C" int optMain(
if (!DisableDITypeMap)
Context.enableDebugTypeODRUniquing();
Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr =
Expected<LLVMRemarkFileHandle> RemarksFileOrErr =
setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
RemarksFormat, RemarksWithHotness,
RemarksHotnessThreshold);
@@ -518,7 +518,7 @@ extern "C" int optMain(
errs() << toString(std::move(E)) << '\n';
return 1;
}
std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr);
LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr);
// Load the input module...
auto SetDataLayout = [&](StringRef IRTriple,

View File

@@ -21,7 +21,7 @@ TEST(BitstreamRemarksFormat, Magic) {
// This should be updated whenever any of the tests below are modified.
TEST(BitstreamRemarksFormat, ContainerVersion) {
EXPECT_EQ(remarks::CurrentContainerVersion, 0UL);
EXPECT_EQ(remarks::CurrentContainerVersion, 1UL);
}
// The values of the current blocks should not change over time.

View File

@@ -14,7 +14,7 @@
using namespace llvm;
template <size_t N> void parseGood(const char (&Buf)[N]) {
template <size_t N> static void parseGood(const char (&Buf)[N]) {
// 1. Parse the YAML remark -> FromYAMLRemark
// 2. Serialize it to bitstream -> BSStream
// 3. Parse it back -> FromBSRemark
@@ -48,11 +48,11 @@ template <size_t N> void parseGood(const char (&Buf)[N]) {
std::string BSBuf;
raw_string_ostream BSStream(BSBuf);
Expected<std::unique_ptr<remarks::RemarkSerializer>> BSSerializer =
remarks::createRemarkSerializer(remarks::Format::Bitstream,
remarks::SerializerMode::Standalone,
BSStream, std::move(BSStrTab));
remarks::createRemarkSerializer(remarks::Format::Bitstream, BSStream,
std::move(BSStrTab));
EXPECT_FALSE(errorToBool(BSSerializer.takeError()));
(*BSSerializer)->emit(*FromYAMLRemark);
(*BSSerializer)->finalize();
// 3.
Expected<std::unique_ptr<remarks::RemarkParser>> MaybeBSParser =
@@ -256,11 +256,11 @@ TEST(BitstreamRemarks, ContentsCAPI) {
std::string BSBuf;
raw_string_ostream BSStream(BSBuf);
Expected<std::unique_ptr<remarks::RemarkSerializer>> BSSerializer =
remarks::createRemarkSerializer(remarks::Format::Bitstream,
remarks::SerializerMode::Standalone,
BSStream, std::move(BSStrTab));
remarks::createRemarkSerializer(remarks::Format::Bitstream, BSStream,
std::move(BSStrTab));
EXPECT_FALSE(errorToBool(BSSerializer.takeError()));
(*BSSerializer)->emit(ToSerializeRemark);
(*BSSerializer)->finalize();
StringRef Buf = BSStream.str();
LLVMRemarkParserRef Parser =

View File

@@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Bitcode/BitcodeAnalyzer.h"
#include "llvm/Remarks/BitstreamRemarkSerializer.h"
#include "llvm/Remarks/Remark.h"
#include "llvm/Remarks/RemarkSerializer.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <optional>
@@ -34,23 +34,24 @@ static void checkAnalyze(StringRef Input, StringRef Expected) {
EXPECT_EQ(OutputOS.str(), Expected);
}
static void check(remarks::SerializerMode Mode, const remarks::Remark &R,
StringRef ExpectedR, std::optional<StringRef> ExpectedMeta,
std::optional<remarks::StringTable> StrTab) {
static void check(const remarks::Remark &R, StringRef ExpectedR,
std::optional<StringRef> ExpectedMeta = std::nullopt,
std::optional<remarks::StringTable> StrTab = std::nullopt) {
// Emit the remark.
std::string InputBuf;
raw_string_ostream InputOS(InputBuf);
Expected<std::unique_ptr<remarks::RemarkSerializer>> MaybeSerializer = [&] {
if (StrTab)
return createRemarkSerializer(remarks::Format::Bitstream, Mode, InputOS,
return createRemarkSerializer(remarks::Format::Bitstream, InputOS,
std::move(*StrTab));
else
return createRemarkSerializer(remarks::Format::Bitstream, Mode, InputOS);
return createRemarkSerializer(remarks::Format::Bitstream, InputOS);
}();
EXPECT_FALSE(errorToBool(MaybeSerializer.takeError()));
std::unique_ptr<remarks::RemarkSerializer> Serializer =
std::move(*MaybeSerializer);
Serializer->emit(R);
Serializer->finalize();
// Analyze the serialized remark.
checkAnalyze(InputOS.str(), ExpectedR);
@@ -66,20 +67,6 @@ static void check(remarks::SerializerMode Mode, const remarks::Remark &R,
}
}
static void check(const remarks::Remark &R, StringRef ExpectedR,
StringRef ExpectedMeta,
std::optional<remarks::StringTable> StrTab = std::nullopt) {
return check(remarks::SerializerMode::Separate, R, ExpectedR, ExpectedMeta,
std::move(StrTab));
}
static void
checkStandalone(const remarks::Remark &R, StringRef ExpectedR,
std::optional<remarks::StringTable> StrTab = std::nullopt) {
return check(remarks::SerializerMode::Standalone, R, ExpectedR,
/*ExpectedMeta=*/std::nullopt, std::move(StrTab));
}
TEST(BitstreamRemarkSerializer, SeparateRemarkFileNoOptionals) {
remarks::Remark R;
R.RemarkType = remarks::Type::Missed;
@@ -89,19 +76,21 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileNoOptionals) {
check(R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
"</Remark>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
" <String table codeid=3 abbrevid=5/> blob data = "
"</Remark>\n"
"<Meta BlockID=8 NumWords=8 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'remark\\x00pass\\x00function\\x00'\n"
" <External File codeid=4 abbrevid=6/> blob data = "
"'" EXTERNALFILETESTPATH"'\n"
"</Meta>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=7 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=0/>\n"
" <External File codeid=4 abbrevid=5/> blob data = "
"'" EXTERNALFILETESTPATH "'\n"
"</Meta>\n");
}
@@ -118,19 +107,21 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileNoOptionalsSeparateStrTab) {
check(R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=2 op2=1 op3=0/>\n"
"</Remark>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
" <String table codeid=3 abbrevid=5/> blob data = "
"</Remark>\n"
"<Meta BlockID=8 NumWords=8 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'function\\x00pass\\x00remark\\x00'\n"
" <External File codeid=4 abbrevid=6/> blob data = "
"'" EXTERNALFILETESTPATH"'\n"
"</Meta>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=7 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=0/>\n"
" <External File codeid=4 abbrevid=5/> blob data = "
"'" EXTERNALFILETESTPATH "'\n"
"</Meta>\n",
std::move(StrTab));
}
@@ -148,20 +139,22 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileDebugLoc) {
check(R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>\n"
"</Remark>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=15 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
" <String table codeid=3 abbrevid=5/> blob data = "
"</Remark>\n"
"<Meta BlockID=8 NumWords=9 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'remark\\x00pass\\x00function\\x00path\\x00'\n"
" <External File codeid=4 abbrevid=6/> blob data = "
"'" EXTERNALFILETESTPATH"'\n"
"</Meta>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=7 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=0/>\n"
" <External File codeid=4 abbrevid=5/> blob data = "
"'" EXTERNALFILETESTPATH "'\n"
"</Meta>\n");
}
@@ -175,20 +168,22 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileHotness) {
check(R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=3 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
" <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n"
"</Remark>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=14 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
" <String table codeid=3 abbrevid=5/> blob data = "
"</Remark>\n"
"<Meta BlockID=8 NumWords=8 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'remark\\x00pass\\x00function\\x00'\n"
" <External File codeid=4 abbrevid=6/> blob data = "
"'" EXTERNALFILETESTPATH"'\n"
"</Meta>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=7 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=0/>\n"
" <External File codeid=4 abbrevid=5/> blob data = "
"'" EXTERNALFILETESTPATH "'\n"
"</Meta>\n");
}
@@ -204,20 +199,22 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileArgNoDebugLoc) {
check(R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=2 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
" <Argument codeid=9 abbrevid=8 op0=3 op1=4/>\n"
"</Remark>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=16 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
" <String table codeid=3 abbrevid=5/> blob data = "
"</Remark>\n"
"<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'remark\\x00pass\\x00function\\x00key\\x00value\\x00'\n"
" <External File codeid=4 abbrevid=6/> blob data = "
"'" EXTERNALFILETESTPATH"'\n"
"</Meta>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=7 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=0/>\n"
" <External File codeid=4 abbrevid=5/> blob data = "
"'" EXTERNALFILETESTPATH "'\n"
"</Meta>\n");
}
@@ -237,21 +234,23 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileArgDebugLoc) {
check(R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>\n"
" <Argument with debug location codeid=8 abbrevid=7 op0=3 op1=4 op2=5 "
"op3=99 op4=55/>\n"
"</Remark>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=17 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
" <String table codeid=3 abbrevid=5/> blob data = "
"</Remark>\n"
"<Meta BlockID=8 NumWords=11 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'remark\\x00pass\\x00function\\x00key\\x00value\\x00path\\x00'\n"
" <External File codeid=4 abbrevid=6/> blob data = "
"'" EXTERNALFILETESTPATH"'\n"
"</Meta>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=7 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=0/>\n"
" <External File codeid=4 abbrevid=5/> blob data = "
"'" EXTERNALFILETESTPATH "'\n"
"</Meta>\n");
}
@@ -276,7 +275,7 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileAll) {
check(R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=1/>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=8 BlockCodeSize=4>\n"
@@ -285,14 +284,17 @@ TEST(BitstreamRemarkSerializer, SeparateRemarkFileAll) {
" <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n"
" <Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 "
"op3=11 op4=66/>\n"
"</Remark>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=19 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=0/>\n"
" <String table codeid=3 abbrevid=5/> blob data = "
"</Remark>\n"
"<Meta BlockID=8 NumWords=13 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'remark\\x00pass\\x00function\\x00path\\x00key\\x00value\\x00argpa"
"th\\x00'\n <External File codeid=4 abbrevid=6/> blob data = "
"'" EXTERNALFILETESTPATH"'\n"
"th\\x00'\n"
"</Meta>\n",
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=7 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=0/>\n"
" <External File codeid=4 abbrevid=5/> blob data = "
"'" EXTERNALFILETESTPATH "'\n"
"</Meta>\n");
}
@@ -323,15 +325,12 @@ TEST(BitstreamRemarkSerializer, Standalone) {
R.Args.back().Loc->SourceFilePath = "argpath";
R.Args.back().Loc->SourceLine = 11;
R.Args.back().Loc->SourceColumn = 66;
checkStandalone(
check(
R,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=15 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'pass\\x00remark\\x00function\\x00path\\x00key\\x00value\\x00argpath\\x0"
"0'\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=8 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
@@ -339,6 +338,11 @@ TEST(BitstreamRemarkSerializer, Standalone) {
" <Remark hotness codeid=7 abbrevid=6 op0=999999999/>\n"
" <Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 "
"op3=11 op4=66/>\n"
"</Remark>\n",
std::move(StrTab));
"</Remark>\n"
"<Meta BlockID=8 NumWords=13 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'pass\\x00remark\\x00function\\x00path\\x00key\\x00value\\x00argpath\\x0"
"0'\n"
"</Meta>\n",
std::nullopt, std::move(StrTab));
}

View File

@@ -133,16 +133,18 @@ TEST(Remarks, LinkingGoodBitstream) {
"...\n",
remarks::Format::Bitstream,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
"</Remark>\n");
"</Remark>\n"
"<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
"</Meta>\n");
// Check that we keep remarks without debug info.
check(remarks::Format::YAML,
@@ -153,15 +155,17 @@ TEST(Remarks, LinkingGoodBitstream) {
"...\n",
remarks::Format::Bitstream,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00'\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
"</Remark>\n");
"</Remark>\n"
"<Meta BlockID=8 NumWords=8 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00'\n"
"</Meta>\n");
// Check that we deduplicate remarks.
check(remarks::Format::YAML,
@@ -179,16 +183,18 @@ TEST(Remarks, LinkingGoodBitstream) {
"...\n",
remarks::Format::Bitstream,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
"</Remark>\n");
"</Remark>\n"
"<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
"</Meta>\n");
}
TEST(Remarks, LinkingGoodStrTab) {
@@ -209,11 +215,9 @@ TEST(Remarks, LinkingGoodStrTab) {
"...\n",
remarks::Format::Bitstream,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=13 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
"<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00Ok\\x00'\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=1 op1=4 op2=0 op3=2/>\n"
@@ -222,7 +226,11 @@ TEST(Remarks, LinkingGoodStrTab) {
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
"</Remark>\n");
"</Remark>\n"
"<Meta BlockID=8 NumWords=11 BlockCodeSize=3>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00Ok\\x00'\n"
"</Meta>\n");
}
// Check that we propagate parsing errors.

View File

@@ -23,23 +23,23 @@
using namespace llvm;
static void check(remarks::Format SerializerFormat,
remarks::SerializerMode Mode, ArrayRef<remarks::Remark> Rs,
StringRef ExpectedR, std::optional<StringRef> ExpectedMeta,
ArrayRef<remarks::Remark> Rs, StringRef ExpectedR,
std::optional<StringRef> ExpectedMeta,
std::optional<remarks::StringTable> StrTab = std::nullopt) {
std::string Buf;
raw_string_ostream OS(Buf);
Expected<std::unique_ptr<remarks::RemarkSerializer>> MaybeS = [&] {
if (StrTab)
return createRemarkSerializer(SerializerFormat, Mode, OS,
std::move(*StrTab));
return createRemarkSerializer(SerializerFormat, OS, std::move(*StrTab));
else
return createRemarkSerializer(SerializerFormat, Mode, OS);
return createRemarkSerializer(SerializerFormat, OS);
}();
EXPECT_FALSE(errorToBool(MaybeS.takeError()));
std::unique_ptr<remarks::RemarkSerializer> S = std::move(*MaybeS);
for (const remarks::Remark &R : Rs)
S->emit(R);
S->finalize();
EXPECT_EQ(OS.str(), ExpectedR);
if (ExpectedMeta) {
@@ -54,8 +54,7 @@ static void check(remarks::Format SerializerFormat,
static void check(remarks::Format SerializerFormat, const remarks::Remark &R,
StringRef ExpectedR, StringRef ExpectedMeta,
std::optional<remarks::StringTable> StrTab = std::nullopt) {
return check(SerializerFormat, remarks::SerializerMode::Separate,
ArrayRef(&R, &R + 1), ExpectedR, ExpectedMeta,
return check(SerializerFormat, ArrayRef(&R, &R + 1), ExpectedR, ExpectedMeta,
std::move(StrTab));
}
@@ -63,8 +62,7 @@ static void
checkStandalone(remarks::Format SerializerFormat, const remarks::Remark &R,
StringRef ExpectedR,
std::optional<remarks::StringTable> StrTab = std::nullopt) {
return check(SerializerFormat, remarks::SerializerMode::Standalone,
ArrayRef(&R, &R + 1), ExpectedR,
return check(SerializerFormat, ArrayRef(&R, &R + 1), ExpectedR,
/*ExpectedMeta=*/std::nullopt, std::move(StrTab));
}

View File

@@ -26,14 +26,15 @@ public:
createToFile(llvm::StringRef path, llvm::remarks::Format fmt);
void streamOptimizationRemark(const Remark &remark) override;
void finalize() override {}
void finalize() override;
~LLVMRemarkStreamer() override;
private:
LLVMRemarkStreamer() = default;
std::unique_ptr<class llvm::remarks::RemarkStreamer> remarkStreamer;
std::unique_ptr<class llvm::ToolOutputFile> file;
// RemarkStreamer must be destructed before file is destroyed!
std::unique_ptr<class llvm::remarks::RemarkStreamer> remarkStreamer;
};
} // namespace mlir::remark::detail

View File

@@ -20,8 +20,7 @@ LLVMRemarkStreamer::createToFile(llvm::StringRef path,
if (ec)
return failure();
auto serOr = llvm::remarks::createRemarkSerializer(
fmt, llvm::remarks::SerializerMode::Separate, f->os());
auto serOr = llvm::remarks::createRemarkSerializer(fmt, f->os());
if (!serOr) {
llvm::consumeError(serOr.takeError());
return failure();
@@ -50,6 +49,12 @@ LLVMRemarkStreamer::~LLVMRemarkStreamer() {
if (file && remarkStreamer)
file->keep();
}
void LLVMRemarkStreamer::finalize() {
if (!remarkStreamer)
return;
remarkStreamer->releaseSerializer();
}
} // namespace mlir::remark::detail
namespace mlir::remark {

View File

@@ -180,9 +180,10 @@ Expected<std::unique_ptr<MemoryBuffer>>
JITEngine::backend(Module &M, const std::string &ComputeUnitKind,
unsigned OptLevel) {
auto RemarksFileOrErr = setupLLVMOptimizationRemarks(
M.getContext(), /*RemarksFilename=*/"", /*RemarksPasses=*/"",
/*RemarksFormat=*/"", /*RemarksWithHotness=*/false);
Expected<LLVMRemarkFileHandle> RemarksFileOrErr =
setupLLVMOptimizationRemarks(
M.getContext(), /*RemarksFilename=*/"", /*RemarksPasses=*/"",
/*RemarksFormat=*/"", /*RemarksWithHotness=*/false);
if (Error E = RemarksFileOrErr.takeError())
return std::move(E);
if (*RemarksFileOrErr)