[llvm] Introduce llvmremark util diff command (PR #85007)
Jessica Paquette via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 24 18:46:55 PDT 2024
================
@@ -0,0 +1,298 @@
+//===- RemarkDiff.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic tool to diff remarks based on properties
+//
+//===----------------------------------------------------------------------===//
+
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+namespace llvm {
+namespace remarks {
+
+enum ReportStyleOptions { human_output, json_output };
+/// copy of Argument class using std::string instead of StringRef.
+struct RemarkArgInfo {
+ std::string Key;
+ std::string Val;
+ RemarkArgInfo(StringRef Key, StringRef Val)
+ : Key(Key.str()), Val(Val.str()) {}
+ void print(raw_ostream &OS) const;
+};
+
+hash_code hash_value(const RemarkArgInfo &Arg) {
+ return hash_combine(Arg.Key, Arg.Val);
+}
+
+/// A wrapper for Remark class that can be used for generating remark diff.
+struct RemarkInfo {
+ std::string RemarkName;
+ std::string FunctionName;
+ std::string PassName;
+ Type RemarkType;
+ SmallVector<RemarkArgInfo, 4> Args;
+ RemarkInfo();
+ RemarkInfo(std::string RemarkName, std::string FunctionName,
+ std::string PassName, Type RemarkType,
+ SmallVector<RemarkArgInfo, 4> &Args)
+ : RemarkName(RemarkName), FunctionName(FunctionName), PassName(PassName),
+ RemarkType(RemarkType), Args(Args) {}
+ RemarkInfo(Remark &Remark)
+ : RemarkName(Remark.RemarkName.str()),
+ FunctionName(Remark.FunctionName.str()),
+ PassName(Remark.PassName.str()), RemarkType(Remark.RemarkType) {
+ for (const auto &Arg : Remark.Args)
+ Args.push_back({Arg.Key.str(), Arg.Val.str()});
+ }
+
+ /// Check if the remark has the same name, function name and pass name as \p
+ /// RHS
+ bool hasSameHeader(const RemarkInfo &RHS) const {
+ return RemarkName == RHS.RemarkName && FunctionName == RHS.FunctionName &&
+ PassName == RHS.PassName;
+ };
+ void print(raw_ostream &OS) const;
+ void printHeader(raw_ostream &OS) const;
+};
+
+inline bool operator<(const RemarkArgInfo &LHS, const RemarkArgInfo &RHS) {
+ return std::make_tuple(LHS.Key, LHS.Val) < std::make_tuple(RHS.Key, RHS.Val);
+}
+
+inline bool operator<(const RemarkInfo &LHS, const RemarkInfo &RHS) {
+ return std::make_tuple(LHS.RemarkType, LHS.PassName, LHS.RemarkName,
+ LHS.FunctionName, LHS.Args) <
+ std::make_tuple(RHS.RemarkType, RHS.PassName, RHS.RemarkName,
+ RHS.FunctionName, RHS.Args);
+}
+
+inline bool operator==(const RemarkArgInfo &LHS, const RemarkArgInfo &RHS) {
+ return LHS.Key == RHS.Key && LHS.Val == RHS.Val;
+}
+
+inline bool operator==(const RemarkInfo &LHS, const RemarkInfo &RHS) {
+ return LHS.RemarkName == RHS.RemarkName &&
+ LHS.FunctionName == RHS.FunctionName && LHS.PassName == RHS.PassName &&
+ LHS.RemarkType == RHS.RemarkType && LHS.Args == RHS.Args;
+}
+
+inline raw_ostream &operator<<(raw_ostream &OS,
+ const RemarkArgInfo &RemarkArgInfo) {
+ RemarkArgInfo.print(OS);
+ return OS;
+}
+
+inline raw_ostream &operator<<(raw_ostream &OS, const RemarkInfo &RemarkInfo) {
+ RemarkInfo.print(OS);
+ return OS;
+}
+
+/// Represents the unique location where the remark was issued which is based on
+/// the debug information attatched to the remark. The debug location conists of
+/// the source file path, function name, line number and column number.
+struct DebugLocation {
+ std::string SourceFilePath;
+ std::string FunctionName;
+ unsigned SourceLine = 0;
+ unsigned SourceColumn = 0;
+ DebugLocation() = default;
+ DebugLocation(StringRef SourceFilePath, StringRef FunctionName,
+ unsigned SourceLine, unsigned SourceColumn)
+ : SourceFilePath(SourceFilePath.str()), FunctionName(FunctionName.str()),
+ SourceLine(SourceLine), SourceColumn(SourceColumn) {}
+ std::string toString() {
+ return "Ln: " + to_string(SourceLine) + " Col: " + to_string(SourceColumn);
+ }
+};
+
+/// Configure the verbosity of the diff by choosing to only show unique remarks
+/// from each version or only consider remarks if they differ in type or
+/// argument. The configurator handles user specified arguments passed by flags.
+struct DiffConfigurator {
+ bool AddRemarksFromA;
+ bool AddRemarksFromB;
+ bool ShowCommonRemarks;
+ bool ShowRemarkTypeDiff;
+ bool ShowArgTypeDiff;
+ DiffConfigurator(bool ShowArgDiffOnly, bool OnlyShowCommonRemarks,
+ bool OnlyShowDifferentRemarks, bool ShowOnlyA,
+ bool ShowOnlyB, bool ShowRemarkTypeDiffOnly) {
+ AddRemarksFromA = !OnlyShowCommonRemarks && (ShowOnlyA || !ShowOnlyB);
+ AddRemarksFromB = !OnlyShowCommonRemarks && (ShowOnlyB || !ShowOnlyA);
+ ShowCommonRemarks = !OnlyShowDifferentRemarks || OnlyShowCommonRemarks;
+ ShowRemarkTypeDiff = !ShowArgDiffOnly || ShowRemarkTypeDiffOnly;
+ ShowArgTypeDiff = !ShowRemarkTypeDiffOnly || ShowArgDiffOnly;
+ }
+};
+
+/// Represent a diff where the remark header information is the same but the
+/// differ in remark type or agruments.
+struct DiffAtRemark {
+ RemarkInfo BaseRemark;
+ std::optional<std::pair<Type, Type>> RemarkTypeDiff;
+ SmallVector<RemarkArgInfo, 4> OnlyA;
+ SmallVector<RemarkArgInfo, 4> OnlyB;
+ SmallVector<RemarkArgInfo, 4> InBoth;
+
+ /// Compute the diff between two remarks \p RA and \p RB which share the same
+ /// header and differ in remark type and arguments.
+ DiffAtRemark(RemarkInfo &RA, RemarkInfo &RB, DiffConfigurator &DiffConfig)
+ : BaseRemark(RA) {
+ if (DiffConfig.ShowArgTypeDiff) {
+ unsigned ArgIdx = 0;
+ // Loop through the remarks in RA and RB in order comparing both.
+ for (; ArgIdx < std::min(RA.Args.size(), RB.Args.size()); ArgIdx++) {
+ if (RA.Args[ArgIdx] == (RB.Args[ArgIdx]))
+ InBoth.push_back(RA.Args[ArgIdx]);
+ else {
+ OnlyA.push_back(RA.Args[ArgIdx]);
+ OnlyB.push_back(RB.Args[ArgIdx]);
+ }
+ }
+
+ // Add the remaining remarks if they exist to OnlyA or OnlyB.
+ SmallVector<RemarkArgInfo, 4> RemainingArgs =
+ RA.Args.size() > RB.Args.size() ? RA.Args : RB.Args;
+ bool IsARemaining = RA.Args.size() > RB.Args.size() ? true : false;
+ for (; ArgIdx < RemainingArgs.size(); ArgIdx++)
+ if (IsARemaining)
+ OnlyA.push_back(RemainingArgs[ArgIdx]);
+ else
+ OnlyB.push_back(RemainingArgs[ArgIdx]);
+ }
+
+ // Compare remark type between RA and RB.
+ if (DiffConfig.ShowRemarkTypeDiff && RA.RemarkType != RB.RemarkType) {
----------------
ornata wrote:
also IMO the "type diff" part should be in a function so it is easier to extend
e.g.
```
if (DiffConfig.ShowRemarkTypeDiff)
showRemarkTypeDiff(RA, RB);
```
https://github.com/llvm/llvm-project/pull/85007
More information about the llvm-commits
mailing list