[llvm] 30d8e08 - [RemarkUtil] Refactor remarkutil tool to use a command registry.
Zain Jaffal via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 28 01:21:47 PDT 2023
Author: Zain Jaffal
Date: 2023-07-28T09:21:29+01:00
New Revision: 30d8e0837d68a11430cc4c0f24cd743e14219a7d
URL: https://github.com/llvm/llvm-project/commit/30d8e0837d68a11430cc4c0f24cd743e14219a7d
DIFF: https://github.com/llvm/llvm-project/commit/30d8e0837d68a11430cc4c0f24cd743e14219a7d.diff
LOG: [RemarkUtil] Refactor remarkutil tool to use a command registry.
In preperation to move all remark utilities into one tool. We use
command registry to breakdown each utility into a separate file.
For now we have 3 utilities for remarks
1. Convert: which is responsible for converting yaml remarks to
bitstream and vice-versa
2. Count: Analyse remarks and report count. This currently only supports
asm-remarks and annotation-summary remarks.
3. Diff remarks: Currently we only have a diff for size remarks using
`llvm-remark-size-diff`
The first two utilites have been simplified and seperated into two
files. The following commit will move `llvm-remark-size-diff` and fold
it to be inside `llvm-remarkutil` as a subcommand
Differential Revision: https://reviews.llvm.org/D156416
Added:
llvm/tools/llvm-remarkutil/RemarkConvert.cpp
llvm/tools/llvm-remarkutil/RemarkCount.cpp
llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
llvm/tools/llvm-remarkutil/RemarkUtilRegistry.h
Modified:
llvm/tools/llvm-remarkutil/CMakeLists.txt
llvm/tools/llvm-remarkutil/RemarkUtil.cpp
Removed:
################################################################################
diff --git a/llvm/tools/llvm-remarkutil/CMakeLists.txt b/llvm/tools/llvm-remarkutil/CMakeLists.txt
index bf044d248fb785..85c920dfd3b838 100644
--- a/llvm/tools/llvm-remarkutil/CMakeLists.txt
+++ b/llvm/tools/llvm-remarkutil/CMakeLists.txt
@@ -5,5 +5,9 @@ set(LLVM_LINK_COMPONENTS
)
add_llvm_tool(llvm-remarkutil
+ RemarkConvert.cpp
+ RemarkCount.cpp
RemarkUtil.cpp
+ RemarkUtilHelpers.cpp
+ RemarkUtilRegistry.cpp
)
diff --git a/llvm/tools/llvm-remarkutil/RemarkConvert.cpp b/llvm/tools/llvm-remarkutil/RemarkConvert.cpp
new file mode 100644
index 00000000000000..35d8dcd99b4a9c
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkConvert.cpp
@@ -0,0 +1,143 @@
+//===- RemarkConvert.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Convert remarks from bitstream to yaml and the other way around.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+extern ExitOnError ExitOnErr;
+static cl::SubCommand
+ YAML2Bitstream("yaml2bitstream",
+ "Convert YAML remarks to bitstream remarks");
+static cl::SubCommand
+ Bitstream2YAML("bitstream2yaml",
+ "Convert bitstream remarks to YAML remarks");
+
+namespace yaml2bitstream {
+/// Remark format to parse.
+static constexpr Format InputFormat = Format::YAML;
+/// Remark format to output.
+static constexpr Format OutputFormat = Format::Bitstream;
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(YAML2Bitstream)
+} // namespace yaml2bitstream
+
+namespace bitstream2yaml {
+/// Remark format to parse.
+static constexpr Format InputFormat = Format::Bitstream;
+/// Remark format to output.
+static constexpr Format OutputFormat = Format::YAML;
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(Bitstream2YAML)
+} // namespace bitstream2yaml
+
+namespace yaml2bitstream {
+/// Parses all remarks in the input YAML file.
+/// \p [out] ParsedRemarks - Filled with remarks parsed from the input file.
+/// \p [out] StrTab - A string table populated for later remark serialization.
+/// \returns Error::success() if all remarks were successfully parsed, and an
+/// Error otherwise.
+static Error
+tryParseRemarksFromYAMLFile(std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
+ StringTable &StrTab) {
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ StrTab.internalize(**MaybeRemark);
+ ParsedRemarks.push_back(std::move(*MaybeRemark));
+ }
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ return Error::success();
+}
+
+/// Reserialize a list of parsed YAML remarks into bitstream remarks.
+/// \p ParsedRemarks - A list of remarks.
+/// \p StrTab - The string table for the remarks.
+/// \returns Error::success() on success.
+static Error tryReserializeYAML2Bitstream(
+ const std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
+ StringTable &StrTab) {
+ auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ auto MaybeSerializer = createRemarkSerializer(
+ OutputFormat, SerializerMode::Standalone, OF->os(), std::move(StrTab));
+ if (!MaybeSerializer)
+ return MaybeSerializer.takeError();
+ auto Serializer = std::move(*MaybeSerializer);
+ for (const auto &Remark : ParsedRemarks)
+ Serializer->emit(*Remark);
+ OF->keep();
+ return Error::success();
+}
+
+/// Parse YAML remarks and reserialize as bitstream remarks.
+/// \returns Error::success() on success, and an Error otherwise.
+static Error tryYAML2Bitstream() {
+ StringTable StrTab;
+ std::vector<std::unique_ptr<Remark>> ParsedRemarks;
+ ExitOnErr(tryParseRemarksFromYAMLFile(ParsedRemarks, StrTab));
+ return tryReserializeYAML2Bitstream(ParsedRemarks, StrTab);
+}
+} // namespace yaml2bitstream
+
+namespace bitstream2yaml {
+/// Parse bitstream remarks and reserialize as YAML remarks.
+/// \returns An Error if reserialization fails, or Error::success() on success.
+static Error tryBitstream2YAML() {
+ // Create the serializer.
+ auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ auto MaybeSerializer = createRemarkSerializer(
+ OutputFormat, SerializerMode::Standalone, OF->os());
+ if (!MaybeSerializer)
+ return MaybeSerializer.takeError();
+
+ // Create the parser.
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto Serializer = std::move(*MaybeSerializer);
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ auto &Parser = **MaybeParser;
+
+ // Parse + reserialize all remarks.
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next())
+ Serializer->emit(**MaybeRemark);
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ return Error::success();
+}
+} // namespace bitstream2yaml
+
+static CommandRegistration Bitstream2YamlReg(&Bitstream2YAML,
+ bitstream2yaml::tryBitstream2YAML);
+static CommandRegistration Yaml2Bitstream(&YAML2Bitstream,
+ yaml2bitstream::tryYAML2Bitstream);
diff --git a/llvm/tools/llvm-remarkutil/RemarkCount.cpp b/llvm/tools/llvm-remarkutil/RemarkCount.cpp
new file mode 100644
index 00000000000000..d08f47ff352796
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkCount.cpp
@@ -0,0 +1,159 @@
+//===- RemarkCount.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Count remarks using `instruction-count` for asm-printer remarks and
+// `annotation-count` for annotation-remarks
+//
+//===----------------------------------------------------------------------===//
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+static cl::SubCommand InstructionCount(
+ "instruction-count",
+ "Function instruction count information (requires asm-printer remarks)");
+static cl::SubCommand
+ AnnotationCount("annotation-count",
+ "Collect count information from annotation remarks (uses "
+ "AnnotationRemarksPass)");
+
+namespace instructioncount {
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionCount)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionCount)
+DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(InstructionCount)
+} // namespace instructioncount
+
+namespace annotationcount {
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(AnnotationCount)
+static cl::opt<std::string> AnnotationTypeToCollect(
+ "annotation-type", cl::desc("annotation-type remark to collect count for"),
+ cl::sub(AnnotationCount));
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(AnnotationCount)
+DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(AnnotationCount)
+} // namespace annotationcount
+
+static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) {
+ return UseDebugLoc && !Remark.Loc.has_value();
+}
+
+namespace instructioncount {
+/// Outputs all instruction count remarks in the file as a CSV.
+/// \returns Error::success() on success, and an Error otherwise.
+static Error tryInstructionCount() {
+ // Create the output buffer.
+ auto MaybeOF = getOutputFileWithFlags(OutputFileName,
+ /*Flags = */ sys::fs::OF_TextWithCRLF);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ // Create a parser for the user-specified input format.
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ // Emit CSV header.
+ if (UseDebugLoc)
+ OF->os() << "Source,";
+ OF->os() << "Function,InstructionCount\n";
+ // Parse all remarks. Whenever we see an instruction count remark, output
+ // the file name and the number of instructions.
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ auto &Remark = **MaybeRemark;
+ if (Remark.RemarkName != "InstructionCount")
+ continue;
+ if (shouldSkipRemark(UseDebugLoc, Remark))
+ continue;
+ auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) {
+ return Arg.Key == "NumInstructions";
+ });
+ assert(InstrCountArg != Remark.Args.end() &&
+ "Expected instruction count remarks to have a NumInstructions key?");
+ if (UseDebugLoc) {
+ std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
+ std::to_string(Remark.Loc->SourceLine) + +":" +
+ std::to_string(Remark.Loc->SourceColumn);
+ OF->os() << Loc << ",";
+ }
+ OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n";
+ }
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ OF->keep();
+ return Error::success();
+}
+} // namespace instructioncount
+
+namespace annotationcount {
+static Error tryAnnotationCount() {
+ // Create the output buffer.
+ auto MaybeOF = getOutputFileWithFlags(OutputFileName,
+ /*Flags = */ sys::fs::OF_TextWithCRLF);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ // Create a parser for the user-specified input format.
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ // Emit CSV header.
+ if (UseDebugLoc)
+ OF->os() << "Source,";
+ OF->os() << "Function,Count\n";
+ // Parse all remarks. When we see the specified remark collect the count
+ // information.
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ auto &Remark = **MaybeRemark;
+ if (Remark.RemarkName != "AnnotationSummary")
+ continue;
+ if (shouldSkipRemark(UseDebugLoc, Remark))
+ continue;
+ auto *RemarkNameArg = find_if(Remark.Args, [](const Argument &Arg) {
+ return Arg.Key == "type" && Arg.Val == AnnotationTypeToCollect;
+ });
+ if (RemarkNameArg == Remark.Args.end())
+ continue;
+ auto *CountArg = find_if(
+ Remark.Args, [](const Argument &Arg) { return Arg.Key == "count"; });
+ assert(CountArg != Remark.Args.end() &&
+ "Expected annotation-type remark to have a count key?");
+ if (UseDebugLoc) {
+ std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
+ std::to_string(Remark.Loc->SourceLine) + +":" +
+ std::to_string(Remark.Loc->SourceColumn);
+ OF->os() << Loc << ",";
+ }
+ OF->os() << Remark.FunctionName << "," << CountArg->Val << "\n";
+ }
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ OF->keep();
+ return Error::success();
+}
+} // namespace annotationcount
+
+static CommandRegistration
+ InstructionCountReg(&InstructionCount,
+ instructioncount::tryInstructionCount);
+static CommandRegistration Yaml2Bitstream(&AnnotationCount,
+ annotationcount::tryAnnotationCount);
diff --git a/llvm/tools/llvm-remarkutil/RemarkUtil.cpp b/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
index 14af5d2842cf80..8ab3fbba4311d1 100644
--- a/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
@@ -1,4 +1,4 @@
-//===--------- llvm-remarkutil/RemarkUtil.cpp -----------===//
+//===--------- llvm-remarkutil/RemarkUtil.cpp -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -8,370 +8,34 @@
/// Utility for remark files.
//===----------------------------------------------------------------------===//
-#include "llvm-c/Remarks.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Remarks/Remark.h"
-#include "llvm/Remarks/RemarkFormat.h"
-#include "llvm/Remarks/RemarkParser.h"
-#include "llvm/Remarks/YAMLRemarkSerializer.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileSystem.h"
+#include "RemarkUtilRegistry.h"
#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/WithColor.h"
using namespace llvm;
-using namespace remarks;
-
-static ExitOnError ExitOnErr;
-static cl::OptionCategory RemarkUtilCategory("llvm-remarkutil options");
-namespace subopts {
-static cl::SubCommand
- YAML2Bitstream("yaml2bitstream",
- "Convert YAML remarks to bitstream remarks");
-static cl::SubCommand
- Bitstream2YAML("bitstream2yaml",
- "Convert bitstream remarks to YAML remarks");
-static cl::SubCommand InstructionCount(
- "instruction-count",
- "Function instruction count information (requires asm-printer remarks)");
-static cl::SubCommand
- AnnotationCount("annotation-count",
- "Collect count information from annotation remarks (uses "
- "AnnotationRemarksPass)");
-} // namespace subopts
-
-// Keep input + output help + names consistent across the various modes via a
-// hideous macro.
-#define INPUT_OUTPUT_COMMAND_LINE_OPTIONS(SUBOPT) \
- static cl::opt<std::string> InputFileName( \
- cl::Positional, cl::cat(RemarkUtilCategory), cl::init("-"), \
- cl::desc("<input file>"), cl::sub(SUBOPT)); \
- static cl::opt<std::string> OutputFileName( \
- "o", cl::init("-"), cl::cat(RemarkUtilCategory), cl::desc("Output"), \
- cl::value_desc("filename"), cl::sub(SUBOPT));
-
-// Keep Input format and names consistent accross the modes via a macro.
-#define INPUT_FORMAT_COMMAND_LINE_OPTIONS(SUBOPT) \
- static cl::opt<Format> InputFormat( \
- "parser", cl::desc("Input remark format to parse"), \
- cl::values(clEnumValN(Format::YAML, "yaml", "YAML"), \
- clEnumValN(Format::Bitstream, "bitstream", "Bitstream")), \
- cl::sub(SUBOPT));
-
-#define DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(SUBOPT) \
- static cl::opt<bool> UseDebugLoc( \
- "use-debug-loc", \
- cl::desc( \
- "Add debug loc information when generating tables for " \
- "functions. The loc is represented as (path:line number:column " \
- "number)"), \
- cl::init(false), cl::sub(SUBOPT));
-namespace yaml2bitstream {
-/// Remark format to parse.
-static constexpr Format InputFormat = Format::YAML;
-/// Remark format to output.
-static constexpr Format OutputFormat = Format::Bitstream;
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::YAML2Bitstream)
-} // namespace yaml2bitstream
-
-namespace bitstream2yaml {
-/// Remark format to parse.
-static constexpr Format InputFormat = Format::Bitstream;
-/// Remark format to output.
-static constexpr Format OutputFormat = Format::YAML;
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::Bitstream2YAML)
-} // namespace bitstream2yaml
-
-namespace instructioncount {
-INPUT_FORMAT_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
-DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
-} // namespace instructioncount
-
-namespace annotationcount {
-INPUT_FORMAT_COMMAND_LINE_OPTIONS(subopts::AnnotationCount)
-static cl::opt<std::string> AnnotationTypeToCollect(
- "annotation-type", cl::desc("annotation-type remark to collect count for"),
- cl::sub(subopts::AnnotationCount));
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::AnnotationCount)
-DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(subopts::AnnotationCount)
-} // namespace annotationcount
-
-/// \returns A MemoryBuffer for the input file on success, and an Error
-/// otherwise.
-static Expected<std::unique_ptr<MemoryBuffer>>
-getInputMemoryBuffer(StringRef InputFileName) {
- auto MaybeBuf = MemoryBuffer::getFileOrSTDIN(InputFileName);
- if (auto ErrorCode = MaybeBuf.getError())
- return createStringError(ErrorCode,
- Twine("Cannot open file '" + InputFileName +
- "': " + ErrorCode.message()));
- return std::move(*MaybeBuf);
-}
-
-/// \returns A ToolOutputFile which can be used for outputting the results of
-/// some tool mode.
-/// \p OutputFileName is the desired destination.
-/// \p Flags controls whether or not the file is opened for writing in text
-/// mode, as a binary, etc. See sys::fs::OpenFlags for more detail.
-static Expected<std::unique_ptr<ToolOutputFile>>
-getOutputFileWithFlags(StringRef OutputFileName, sys::fs::OpenFlags Flags) {
- if (OutputFileName == "")
- OutputFileName = "-";
- std::error_code ErrorCode;
- auto OF = std::make_unique<ToolOutputFile>(OutputFileName, ErrorCode, Flags);
- if (ErrorCode)
- return errorCodeToError(ErrorCode);
- return std::move(OF);
-}
-
-/// \returns A ToolOutputFile which can be used for writing remarks on success,
-/// and an Error otherwise.
-/// \p OutputFileName is the desired destination.
-/// \p OutputFormat
-static Expected<std::unique_ptr<ToolOutputFile>>
-getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat) {
- assert((OutputFormat == Format::YAML || OutputFormat == Format::Bitstream) &&
- "Expected one of YAML or Bitstream!");
- return getOutputFileWithFlags(OutputFileName, OutputFormat == Format::YAML
- ? sys::fs::OF_TextWithCRLF
- : sys::fs::OF_None);
-}
-
-static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) {
- return UseDebugLoc && !Remark.Loc.has_value();
-}
-
-namespace yaml2bitstream {
-/// Parses all remarks in the input YAML file.
-/// \p [out] ParsedRemarks - Filled with remarks parsed from the input file.
-/// \p [out] StrTab - A string table populated for later remark serialization.
-/// \returns Error::success() if all remarks were successfully parsed, and an
-/// Error otherwise.
-static Error
-tryParseRemarksFromYAMLFile(std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
- StringTable &StrTab) {
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- auto &Parser = **MaybeParser;
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next()) {
- StrTab.internalize(**MaybeRemark);
- ParsedRemarks.push_back(std::move(*MaybeRemark));
- }
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- return Error::success();
-}
-
-/// Reserialize a list of parsed YAML remarks into bitstream remarks.
-/// \p ParsedRemarks - A list of remarks.
-/// \p StrTab - The string table for the remarks.
-/// \returns Error::success() on success.
-static Error tryReserializeYAML2Bitstream(
- const std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
- StringTable &StrTab) {
- auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- auto MaybeSerializer = createRemarkSerializer(
- OutputFormat, SerializerMode::Standalone, OF->os(), std::move(StrTab));
- if (!MaybeSerializer)
- return MaybeSerializer.takeError();
- auto Serializer = std::move(*MaybeSerializer);
- for (const auto &Remark : ParsedRemarks)
- Serializer->emit(*Remark);
- OF->keep();
- return Error::success();
-}
-
-/// Parse YAML remarks and reserialize as bitstream remarks.
-/// \returns Error::success() on success, and an Error otherwise.
-static Error tryYAML2Bitstream() {
- StringTable StrTab;
- std::vector<std::unique_ptr<Remark>> ParsedRemarks;
- ExitOnErr(tryParseRemarksFromYAMLFile(ParsedRemarks, StrTab));
- return tryReserializeYAML2Bitstream(ParsedRemarks, StrTab);
-}
-} // namespace yaml2bitstream
-
-namespace bitstream2yaml {
-/// Parse bitstream remarks and reserialize as YAML remarks.
-/// \returns An Error if reserialization fails, or Error::success() on success.
-static Error tryBitstream2YAML() {
- // Create the serializer.
- auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- auto MaybeSerializer = createRemarkSerializer(
- OutputFormat, SerializerMode::Standalone, OF->os());
- if (!MaybeSerializer)
- return MaybeSerializer.takeError();
-
- // Create the parser.
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto Serializer = std::move(*MaybeSerializer);
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- auto &Parser = **MaybeParser;
-
- // Parse + reserialize all remarks.
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next())
- Serializer->emit(**MaybeRemark);
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- return Error::success();
-}
-} // namespace bitstream2yaml
-
-namespace instructioncount {
-/// Outputs all instruction count remarks in the file as a CSV.
-/// \returns Error::success() on success, and an Error otherwise.
-static Error tryInstructionCount() {
- // Create the output buffer.
- auto MaybeOF = getOutputFileWithFlags(OutputFileName,
- /*Flags = */ sys::fs::OF_TextWithCRLF);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- // Create a parser for the user-specified input format.
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- // Emit CSV header.
- if (UseDebugLoc)
- OF->os() << "Source,";
- OF->os() << "Function,InstructionCount\n";
- // Parse all remarks. Whenever we see an instruction count remark, output
- // the file name and the number of instructions.
- auto &Parser = **MaybeParser;
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next()) {
- auto &Remark = **MaybeRemark;
- if (Remark.RemarkName != "InstructionCount")
- continue;
- if (shouldSkipRemark(UseDebugLoc, Remark))
- continue;
- auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) {
- return Arg.Key == "NumInstructions";
- });
- assert(InstrCountArg != Remark.Args.end() &&
- "Expected instruction count remarks to have a NumInstructions key?");
- if (UseDebugLoc) {
- std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
- std::to_string(Remark.Loc->SourceLine) + +":" +
- std::to_string(Remark.Loc->SourceColumn);
- OF->os() << Loc << ",";
- }
- OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n";
- }
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- OF->keep();
- return Error::success();
-}
-} // namespace instructioncount
-
-namespace annotationcount {
-static Error tryAnnotationCount() {
- // Create the output buffer.
- auto MaybeOF = getOutputFileWithFlags(OutputFileName,
- /*Flags = */ sys::fs::OF_TextWithCRLF);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- // Create a parser for the user-specified input format.
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- // Emit CSV header.
- if (UseDebugLoc)
- OF->os() << "Source,";
- OF->os() << "Function,Count\n";
- // Parse all remarks. When we see the specified remark collect the count
- // information.
- auto &Parser = **MaybeParser;
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next()) {
- auto &Remark = **MaybeRemark;
- if (Remark.RemarkName != "AnnotationSummary")
- continue;
- if (shouldSkipRemark(UseDebugLoc, Remark))
- continue;
- auto *RemarkNameArg = find_if(Remark.Args, [](const Argument &Arg) {
- return Arg.Key == "type" && Arg.Val == AnnotationTypeToCollect;
- });
- if (RemarkNameArg == Remark.Args.end())
- continue;
- auto *CountArg = find_if(
- Remark.Args, [](const Argument &Arg) { return Arg.Key == "count"; });
- assert(CountArg != Remark.Args.end() &&
- "Expected annotation-type remark to have a count key?");
- if (UseDebugLoc) {
- std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
- std::to_string(Remark.Loc->SourceLine) + +":" +
- std::to_string(Remark.Loc->SourceColumn);
- OF->os() << Loc << ",";
+using namespace llvm::remarkutil;
+ExitOnError ExitOnErr;
+
+static Error handleSubOptions() {
+ for (auto *SC : cl::getRegisteredSubcommands()) {
+ if (*SC) {
+ // If no subcommand was provided, we need to explicitly check if this is
+ // the top-level subcommand.
+ if (SC == &cl::SubCommand::getTopLevel())
+ break;
+ if (auto C = dispatch(SC)) {
+ return C();
+ }
}
- OF->os() << Remark.FunctionName << "," << CountArg->Val << "\n";
}
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- OF->keep();
- return Error::success();
-}
-
-} // namespace annotationcount
-/// Handle user-specified suboptions (e.g. yaml2bitstream, bitstream2yaml).
-/// \returns An Error if the specified suboption fails or if no suboption was
-/// specified. Otherwise, Error::success().
-static Error handleSuboptions() {
- if (subopts::Bitstream2YAML)
- return bitstream2yaml::tryBitstream2YAML();
- if (subopts::YAML2Bitstream)
- return yaml2bitstream::tryYAML2Bitstream();
- if (subopts::InstructionCount)
- return instructioncount::tryInstructionCount();
- if (subopts::AnnotationCount)
- return annotationcount::tryAnnotationCount();
return make_error<StringError>(
"Please specify a subcommand. (See -help for options)",
inconvertibleErrorCode());
}
-int main(int argc, const char **argv) {
+int main(int argc, char *argv[]) {
InitLLVM X(argc, argv);
- cl::HideUnrelatedOptions(RemarkUtilCategory);
cl::ParseCommandLineOptions(argc, argv, "Remark file utilities\n");
ExitOnErr.setBanner(std::string(argv[0]) + ": error: ");
- ExitOnErr(handleSuboptions());
+ ExitOnErr(handleSubOptions());
}
diff --git a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
new file mode 100644
index 00000000000000..c0357161c4f984
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
@@ -0,0 +1,57 @@
+//===- RemarkUtilHelpers.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers for remark utilites
+//
+//===----------------------------------------------------------------------===//
+#include "RemarkUtilHelpers.h"
+
+namespace llvm {
+namespace remarks {
+/// \returns A MemoryBuffer for the input file on success, and an Error
+/// otherwise.
+Expected<std::unique_ptr<MemoryBuffer>>
+getInputMemoryBuffer(StringRef InputFileName) {
+ auto MaybeBuf = MemoryBuffer::getFileOrSTDIN(InputFileName);
+ if (auto ErrorCode = MaybeBuf.getError())
+ return createStringError(ErrorCode,
+ Twine("Cannot open file '" + InputFileName +
+ "': " + ErrorCode.message()));
+ return std::move(*MaybeBuf);
+}
+
+/// \returns A ToolOutputFile which can be used for outputting the results of
+/// some tool mode.
+/// \p OutputFileName is the desired destination.
+/// \p Flags controls whether or not the file is opened for writing in text
+/// mode, as a binary, etc. See sys::fs::OpenFlags for more detail.
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileWithFlags(StringRef OutputFileName, sys::fs::OpenFlags Flags) {
+ if (OutputFileName == "")
+ OutputFileName = "-";
+ std::error_code ErrorCode;
+ auto OF = std::make_unique<ToolOutputFile>(OutputFileName, ErrorCode, Flags);
+ if (ErrorCode)
+ return errorCodeToError(ErrorCode);
+ return std::move(OF);
+}
+
+/// \returns A ToolOutputFile which can be used for writing remarks on success,
+/// and an Error otherwise.
+/// \p OutputFileName is the desired destination.
+/// \p OutputFormat
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat) {
+ assert((OutputFormat == Format::YAML || OutputFormat == Format::Bitstream) &&
+ "Expected one of YAML or Bitstream!");
+ return getOutputFileWithFlags(OutputFileName, OutputFormat == Format::YAML
+ ? sys::fs::OF_TextWithCRLF
+ : sys::fs::OF_None);
+}
+} // namespace remarks
+} // namespace llvm
diff --git a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
new file mode 100644
index 00000000000000..5d2335224d4c2f
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
@@ -0,0 +1,59 @@
+//===- RemarkUtilHelpers.h ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers for remark utilites
+//
+//===----------------------------------------------------------------------===//
+#include "llvm-c/Remarks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Remarks/Remark.h"
+#include "llvm/Remarks/RemarkFormat.h"
+#include "llvm/Remarks/RemarkParser.h"
+#include "llvm/Remarks/YAMLRemarkSerializer.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ToolOutputFile.h"
+
+// Keep input + output help + names consistent across the various modes via a
+// hideous macro.
+#define INPUT_OUTPUT_COMMAND_LINE_OPTIONS(SUBOPT) \
+ static cl::opt<std::string> InputFileName(cl::Positional, cl::init("-"), \
+ cl::desc("<input file>"), \
+ cl::sub(SUBOPT)); \
+ static cl::opt<std::string> OutputFileName( \
+ "o", cl::init("-"), cl::desc("Output"), cl::value_desc("filename"), \
+ cl::sub(SUBOPT));
+
+// Keep Input format and names consistent accross the modes via a macro.
+#define INPUT_FORMAT_COMMAND_LINE_OPTIONS(SUBOPT) \
+ static cl::opt<Format> InputFormat( \
+ "parser", cl::desc("Input remark format to parse"), \
+ cl::values(clEnumValN(Format::YAML, "yaml", "YAML"), \
+ clEnumValN(Format::Bitstream, "bitstream", "Bitstream")), \
+ cl::sub(SUBOPT));
+
+#define DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(SUBOPT) \
+ static cl::opt<bool> UseDebugLoc( \
+ "use-debug-loc", \
+ cl::desc( \
+ "Add debug loc information when generating tables for " \
+ "functions. The loc is represented as (path:line number:column " \
+ "number)"), \
+ cl::init(false), cl::sub(SUBOPT));
+
+namespace llvm {
+namespace remarks {
+Expected<std::unique_ptr<MemoryBuffer>>
+getInputMemoryBuffer(StringRef InputFileName);
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileWithFlags(StringRef OutputFileName, sys::fs::OpenFlags Flags);
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat);
+} // namespace remarks
+} // namespace llvm
diff --git a/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp b/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
new file mode 100644
index 00000000000000..244a16d51805b6
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
@@ -0,0 +1,41 @@
+//===- RemarkUtilRegistry.cpp: Implement a command registry. --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement a simple subcommand registry.
+//
+//===----------------------------------------------------------------------===//
+#include "RemarkUtilRegistry.h"
+#include <unordered_map>
+
+namespace llvm {
+namespace remarkutil {
+
+using HandlerType = std::function<Error()>;
+
+static std::unordered_map<cl::SubCommand *, HandlerType> &getCommands() {
+ static std::unordered_map<cl::SubCommand *, HandlerType> Commands;
+ return Commands;
+}
+
+CommandRegistration::CommandRegistration(cl::SubCommand *SC,
+ HandlerType Command) {
+ assert(getCommands().count(SC) == 0 &&
+ "Attempting to overwrite a command handler");
+ assert(Command && "Attempting to register an empty std::function<Error()>");
+ getCommands()[SC] = Command;
+}
+
+HandlerType dispatch(cl::SubCommand *SC) {
+ auto It = getCommands().find(SC);
+ assert(It != getCommands().end() &&
+ "Attempting to dispatch on un-registered SubCommand.");
+ return It->second;
+}
+
+} // namespace remarkutil
+} // namespace llvm
diff --git a/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.h b/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.h
new file mode 100644
index 00000000000000..2dd3a53cb047d9
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.h
@@ -0,0 +1,40 @@
+//===- RemarkUtilRegistry.h: Implement a command registry. ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement a simple subcommand registry.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TOOLS_LLVM_REMARKUTIL_REGISTRY_H
+#define TOOLS_LLVM_REMARKUTIL_REGISTRY_H
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace remarkutil {
+
+// Use |CommandRegistration| as a global initialiser that registers a function
+// and associates it with |SC|. This requires that a command has not been
+// registered to a given |SC|.
+//
+// Usage:
+//
+// // At namespace scope.
+// static CommandRegistration Unused(&MySubCommand, [] { ... });
+//
+struct CommandRegistration {
+ CommandRegistration(cl::SubCommand *SC, std::function<Error()> Command);
+};
+
+// Requires that |SC| is not null and has an associated function to it.
+std::function<Error()> dispatch(cl::SubCommand *SC);
+
+} // namespace remarkutil
+} // namespace llvm
+
+#endif // TOOLS_LLVM_REMARKUTIL_REGISTRY_H
More information about the llvm-commits
mailing list