aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llvm-profdata/llvm-profdata.cpp7
-rw-r--r--llvm/tools/llvm-remarkutil/CMakeLists.txt1
-rw-r--r--llvm/tools/llvm-remarkutil/RemarkCounter.cpp6
-rw-r--r--llvm/tools/llvm-remarkutil/RemarkSummary.cpp254
-rw-r--r--llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h51
5 files changed, 316 insertions, 3 deletions
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index a356bcd..9b853e2 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -778,6 +779,12 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
// we have more non-fatal errors from InstrProfReader in the future. How
// should this interact with different -failure-mode?
std::optional<std::pair<Error, std::string>> ReaderWarning;
+ auto ReaderWarningScope = llvm::make_scope_exit([&] {
+ // If we hit a different error we may still have an error in ReaderWarning.
+ // Consume it now to avoid an assert
+ if (ReaderWarning)
+ consumeError(std::move(ReaderWarning->first));
+ });
auto Warn = [&](Error E) {
if (ReaderWarning) {
consumeError(std::move(E));
diff --git a/llvm/tools/llvm-remarkutil/CMakeLists.txt b/llvm/tools/llvm-remarkutil/CMakeLists.txt
index c6e9334..3f0a436 100644
--- a/llvm/tools/llvm-remarkutil/CMakeLists.txt
+++ b/llvm/tools/llvm-remarkutil/CMakeLists.txt
@@ -11,6 +11,7 @@ add_llvm_tool(llvm-remarkutil
RemarkFilter.cpp
RemarkInstructionMix.cpp
RemarkSizeDiff.cpp
+ RemarkSummary.cpp
RemarkUtil.cpp
RemarkUtilHelpers.cpp
RemarkUtilRegistry.cpp
diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
index 2e842c8..4e429b7 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
@@ -70,11 +70,11 @@ static cl::opt<GroupBy> GroupByOpt(
/// integer value or 0 if it is has no integer value.
static unsigned getValForKey(StringRef Key, const Remark &Remark) {
auto *RemarkArg = find_if(Remark.Args, [&Key](const Argument &Arg) {
- return Arg.Key == Key && Arg.isValInt();
+ return Arg.Key == Key && Arg.getValAsInt<unsigned>();
});
if (RemarkArg == Remark.Args.end())
return 0;
- return *RemarkArg->getValAsInt();
+ return *RemarkArg->getValAsInt<unsigned>();
}
Error ArgumentCounter::getAllMatchingArgumentsInRemark(
@@ -91,7 +91,7 @@ Error ArgumentCounter::getAllMatchingArgumentsInRemark(
continue;
for (auto &Key : Arguments) {
for (Argument Arg : Remark.Args)
- if (Key.match(Arg.Key) && Arg.isValInt())
+ if (Key.match(Arg.Key) && Arg.getValAsInt<unsigned>())
ArgumentSetIdxMap.insert({Arg.Key, ArgumentSetIdxMap.size()});
}
}
diff --git a/llvm/tools/llvm-remarkutil/RemarkSummary.cpp b/llvm/tools/llvm-remarkutil/RemarkSummary.cpp
new file mode 100644
index 0000000..124bd51
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkSummary.cpp
@@ -0,0 +1,254 @@
+//===- RemarkSummary.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Specialized tool to summarize remarks
+//
+//===----------------------------------------------------------------------===//
+
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/WithColor.h"
+#include <memory>
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+namespace summary {
+
+static cl::SubCommand
+ SummarySub("summary", "Summarize remarks using different strategies.");
+
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(SummarySub)
+OUTPUT_FORMAT_COMMAND_LINE_OPTIONS(SummarySub)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(SummarySub)
+
+static cl::OptionCategory SummaryStrategyCat("Strategy options");
+
+enum class KeepMode { None, Used, All };
+
+static cl::opt<KeepMode> KeepInputOpt(
+ "keep", cl::desc("Keep input remarks in output"), cl::init(KeepMode::None),
+ cl::values(clEnumValN(KeepMode::None, "none",
+ "Don't keep input remarks (default)"),
+ clEnumValN(KeepMode::Used, "used",
+ "Keep only remarks used for summary"),
+ clEnumValN(KeepMode::All, "all", "Keep all input remarks")),
+ cl::sub(SummarySub));
+
+static cl::opt<bool>
+ IgnoreMalformedOpt("ignore-malformed",
+ cl::desc("Ignore remarks that fail to process"),
+ cl::init(false), cl::Hidden, cl::sub(SummarySub));
+
+// Use one cl::opt per Strategy, because future strategies might need to take
+// per-strategy parameters.
+static cl::opt<bool> EnableInlineSummaryOpt(
+ "inline-callees", cl::desc("Summarize per-callee inling statistics"),
+ cl::cat(SummaryStrategyCat), cl::init(false), cl::sub(SummarySub));
+
+/// An interface to implement different strategies for creating remark
+/// summaries. Override this class to develop new strategies.
+class SummaryStrategy {
+public:
+ virtual ~SummaryStrategy() = default;
+
+ /// Strategy should return true if it wants to process the remark \p R.
+ virtual bool filter(Remark &R) = 0;
+
+ /// Hook to process the remark \p R (i.e. collect the necessary data for
+ /// producing summary remarks). This will only be called with remarks
+ /// accepted by filter(). Can return an error if \p R is malformed or
+ /// unexpected.
+ virtual Error process(Remark &R) = 0;
+
+ /// Hook to emit new remarks based on the collected data.
+ virtual void emit(RemarkSerializer &Serializer) = 0;
+};
+
+/// Check if any summary strategy options are explicitly enabled.
+static bool isAnyStrategyRequested() {
+ StringMap<cl::Option *> Opts = cl::getRegisteredOptions(SummarySub);
+ for (auto &[_, Opt] : Opts) {
+ if (!is_contained(Opt->Categories, &SummaryStrategyCat))
+ continue;
+ if (!Opt->getNumOccurrences())
+ continue;
+ return true;
+ }
+ return false;
+}
+
+class InlineCalleeSummary : public SummaryStrategy {
+ struct CallsiteCost {
+ int Cost = 0;
+ int Threshold = 0;
+ std::optional<RemarkLocation> Loc;
+
+ int getProfit() const { return Threshold - Cost; }
+
+ friend bool operator==(const CallsiteCost &A, const CallsiteCost &B) {
+ return A.Cost == B.Cost && A.Threshold == B.Threshold && A.Loc == B.Loc;
+ }
+
+ friend bool operator!=(const CallsiteCost &A, const CallsiteCost &B) {
+ return !(A == B);
+ }
+ };
+
+ struct CalleeSummary {
+ SmallDenseMap<StringRef, size_t> Stats;
+ std::optional<RemarkLocation> Loc;
+ std::optional<CallsiteCost> LeastProfit;
+ std::optional<CallsiteCost> MostProfit;
+
+ void updateCost(CallsiteCost NewCost) {
+ if (!LeastProfit || NewCost.getProfit() < LeastProfit->getProfit())
+ LeastProfit = NewCost;
+ if (!MostProfit || NewCost.getProfit() > MostProfit->getProfit())
+ MostProfit = NewCost;
+ }
+ };
+
+ DenseMap<StringRef, CalleeSummary> Callees;
+
+ Error malformed() { return createStringError("Malformed inline remark."); }
+
+ bool filter(Remark &R) override {
+ return R.PassName == "inline" && R.RemarkName != "Summary";
+ }
+
+ Error process(Remark &R) override {
+ auto *CalleeArg = R.getArgByKey("Callee");
+ if (!CalleeArg)
+ return Error::success();
+ auto &Callee = Callees[CalleeArg->Val];
+ ++Callee.Stats[R.RemarkName];
+ if (!Callee.Loc)
+ Callee.Loc = CalleeArg->Loc;
+
+ Argument *CostArg = R.getArgByKey("Cost");
+ Argument *ThresholdArg = R.getArgByKey("Threshold");
+ if (!CostArg || !ThresholdArg)
+ return Error::success();
+ auto CostVal = CostArg->getValAsInt<int>();
+ auto ThresholdVal = ThresholdArg->getValAsInt<int>();
+ if (!CostVal || !ThresholdVal)
+ return malformed();
+ Callee.updateCost({*CostVal, *ThresholdVal, R.Loc});
+ return Error::success();
+ }
+
+ void emit(RemarkSerializer &Serializer) override {
+ SmallVector<StringRef> SortedKeys(Callees.keys());
+ llvm::sort(SortedKeys);
+ for (StringRef K : SortedKeys) {
+ auto &V = Callees[K];
+ RemarkBuilder RB(Type::Analysis, "inline", "Summary", K);
+ if (V.Stats.empty())
+ continue;
+ RB.R.Loc = V.Loc;
+ RB << "Incoming Calls (";
+ SmallVector<StringRef> StatKeys(V.Stats.keys());
+ llvm::sort(StatKeys);
+ bool First = true;
+ for (StringRef StatK : StatKeys) {
+ if (!First)
+ RB << ", ";
+ RB << StatK << ": " << NV(StatK, V.Stats[StatK]);
+ First = false;
+ }
+ RB << ")";
+ if (V.LeastProfit && V.MostProfit != V.LeastProfit) {
+ RB << "\nLeast profitable (cost="
+ << NV("LeastProfitCost", V.LeastProfit->Cost, V.LeastProfit->Loc)
+ << ", threshold="
+ << NV("LeastProfitThreshold", V.LeastProfit->Threshold) << ")";
+ }
+ if (V.MostProfit) {
+ RB << "\nMost profitable (cost="
+ << NV("MostProfitCost", V.MostProfit->Cost, V.MostProfit->Loc)
+ << ", threshold="
+ << NV("MostProfitThreshold", V.MostProfit->Threshold) << ")";
+ }
+ Serializer.emit(RB.R);
+ }
+ }
+};
+
+static Error trySummary() {
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ auto &Parser = **MaybeParser;
+
+ Format SerializerFormat =
+ getSerializerFormat(OutputFileName, OutputFormat, Parser.ParserFormat);
+
+ auto MaybeOF = getOutputFileForRemarks(OutputFileName, SerializerFormat);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+
+ auto MaybeSerializer = createRemarkSerializer(SerializerFormat, OF->os());
+ if (!MaybeSerializer)
+ return MaybeSerializer.takeError();
+ auto &Serializer = **MaybeSerializer;
+
+ bool UseDefaultStrategies = !isAnyStrategyRequested();
+ SmallVector<std::unique_ptr<SummaryStrategy>> Strategies;
+ if (EnableInlineSummaryOpt || UseDefaultStrategies)
+ Strategies.push_back(std::make_unique<InlineCalleeSummary>());
+
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ Remark &Remark = **MaybeRemark;
+ bool UsedRemark = false;
+ for (auto &Strategy : Strategies) {
+ if (!Strategy->filter(Remark))
+ continue;
+ UsedRemark = true;
+ if (auto E = Strategy->process(Remark)) {
+ if (IgnoreMalformedOpt) {
+ WithColor::warning() << "Ignored error: " << E << "\n";
+ consumeError(std::move(E));
+ continue;
+ }
+ return E;
+ }
+ }
+ if (KeepInputOpt == KeepMode::All ||
+ (KeepInputOpt == KeepMode::Used && UsedRemark))
+ Serializer.emit(Remark);
+ }
+
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+
+ for (auto &Strategy : Strategies)
+ Strategy->emit(Serializer);
+
+ OF->keep();
+ return Error::success();
+}
+
+static CommandRegistration SummaryReg(&SummarySub, trySummary);
+
+} // namespace summary
diff --git a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
index 73867fe..39e7b42 100644
--- a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
@@ -9,6 +9,7 @@
// Helpers for remark utilites
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Remarks/Remark.h"
#include "llvm/Remarks/RemarkFormat.h"
@@ -19,6 +20,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Regex.h"
+#include "llvm/Support/StringSaver.h"
#include "llvm/Support/ToolOutputFile.h"
// Keep input + output help + names consistent across the various modes via a
@@ -205,5 +207,54 @@ struct Filters {
bool filterRemark(const Remark &Remark);
};
+/// Helper to construct Remarks using an API similar to DiagnosticInfo.
+/// Once this is more fully featured, consider implementing DiagnosticInfo using
+/// RemarkBuilder.
+class RemarkBuilder {
+ BumpPtrAllocator Alloc;
+ UniqueStringSaver Strs;
+
+public:
+ Remark R;
+ struct Argument {
+ std::string Key;
+ std::string Val;
+ std::optional<RemarkLocation> Loc;
+ Argument(StringRef Key, StringRef Val,
+ std::optional<RemarkLocation> Loc = std::nullopt)
+ : Key(Key), Val(Val), Loc(Loc) {}
+ Argument(StringRef Key, int Val,
+ std::optional<RemarkLocation> Loc = std::nullopt)
+ : Key(Key), Val(itostr(Val)), Loc(Loc) {}
+ };
+
+ RemarkBuilder(Type RemarkType, StringRef PassName, StringRef RemarkName,
+ StringRef FunctionName)
+ : Strs(Alloc) {
+ R.RemarkType = RemarkType;
+ R.PassName = Strs.save(PassName);
+ R.RemarkName = Strs.save(RemarkName);
+ R.FunctionName = Strs.save(FunctionName);
+ }
+
+ RemarkBuilder &operator<<(Argument &&Arg) {
+ auto &RArg = R.Args.emplace_back(Strs.save(Arg.Key), Strs.save(Arg.Val));
+ RArg.Loc = Arg.Loc;
+ return *this;
+ }
+
+ RemarkBuilder &operator<<(const char *Str) {
+ R.Args.emplace_back("String", Str);
+ return *this;
+ }
+
+ RemarkBuilder &operator<<(StringRef Str) {
+ R.Args.emplace_back("String", Strs.save(Str));
+ return *this;
+ }
+};
+
+using NV = RemarkBuilder::Argument;
+
} // namespace remarks
} // namespace llvm