aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
blob: 73867fe35f06c33f6abb495a833ea6c326762efe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
//===- 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/ADT/StringRef.h"
#include "llvm/Remarks/Remark.h"
#include "llvm/Remarks/RemarkFormat.h"
#include "llvm/Remarks/RemarkParser.h"
#include "llvm/Remarks/RemarkSerializer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Regex.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::init(Format::Auto),                                        \
      cl::desc("Input remark format to parse"),                                \
      cl::values(                                                              \
          clEnumValN(Format::Auto, "auto", "Automatic detection (default)"),   \
          clEnumValN(Format::YAML, "yaml", "YAML"),                            \
          clEnumValN(Format::Bitstream, "bitstream", "Bitstream")),            \
      cl::sub(SUBOPT));

#define OUTPUT_FORMAT_COMMAND_LINE_OPTIONS(SUBOPT)                             \
  static cl::opt<Format> OutputFormat(                                         \
      "serializer", cl::init(Format::Auto),                                    \
      cl::desc("Output remark format to serialize"),                           \
      cl::values(clEnumValN(Format::Auto, "auto",                              \
                            "Automatic detection based on output file "        \
                            "extension or parser format (default)"),           \
                 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));

#define REMARK_FILTER_COMMAND_LINE_OPTIONS(SUBOPT)                             \
  static cl::opt<std::string> FunctionOpt(                                     \
      "function", cl::sub(SUBOPT), cl::ValueOptional,                          \
      cl::desc("Optional function name to filter collection by."));            \
  static cl::opt<std::string> FunctionOptRE(                                   \
      "rfunction", cl::sub(SUBOPT), cl::ValueOptional,                         \
      cl::desc("Optional function name to filter collection by "               \
               "(accepts regular expressions)."));                             \
  static cl::opt<std::string> RemarkNameOpt(                                   \
      "remark-name",                                                           \
      cl::desc("Optional remark name to filter collection by."),               \
      cl::ValueOptional, cl::sub(SUBOPT));                                     \
  static cl::opt<std::string> RemarkNameOptRE(                                 \
      "rremark-name",                                                          \
      cl::desc("Optional remark name to filter collection by "                 \
               "(accepts regular expressions)."),                              \
      cl::ValueOptional, cl::sub(SUBOPT));                                     \
  static cl::opt<std::string> PassNameOpt(                                     \
      "pass-name", cl::ValueOptional,                                          \
      cl::desc("Optional remark pass name to filter collection by."),          \
      cl::sub(SUBOPT));                                                        \
  static cl::opt<std::string> PassNameOptRE(                                   \
      "rpass-name", cl::ValueOptional,                                         \
      cl::desc("Optional remark pass name to filter collection "               \
               "by (accepts regular expressions)."),                           \
      cl::sub(SUBOPT));                                                        \
  static cl::opt<Type> RemarkTypeOpt(                                          \
      "remark-type",                                                           \
      cl::desc("Optional remark type to filter collection by."),               \
      cl::values(clEnumValN(Type::Unknown, "unknown", "UNKOWN"),               \
                 clEnumValN(Type::Passed, "passed", "PASSED"),                 \
                 clEnumValN(Type::Missed, "missed", "MISSED"),                 \
                 clEnumValN(Type::Analysis, "analysis", "ANALYSIS"),           \
                 clEnumValN(Type::AnalysisFPCommute, "analysis-fp-commute",    \
                            "ANALYSIS_FP_COMMUTE"),                            \
                 clEnumValN(Type::AnalysisAliasing, "analysis-aliasing",       \
                            "ANALYSIS_ALIASING"),                              \
                 clEnumValN(Type::Failure, "failure", "FAILURE")),             \
      cl::sub(SUBOPT));                                                        \
  static cl::opt<std::string> RemarkFilterArgByOpt(                            \
      "filter-arg-by",                                                         \
      cl::desc("Optional remark arg to filter collection by."),                \
      cl::ValueOptional, cl::sub(SUBOPT));                                     \
  static cl::opt<std::string> RemarkArgFilterOptRE(                            \
      "rfilter-arg-by",                                                        \
      cl::desc("Optional remark arg to filter collection by "                  \
               "(accepts regular expressions)."),                              \
      cl::sub(SUBOPT), cl::ValueOptional);

#define REMARK_FILTER_SETUP_FUNC()                                             \
  static Expected<Filters> getRemarkFilters() {                                \
    auto MaybeFunctionFilter =                                                 \
        FilterMatcher::createExactOrRE(FunctionOpt, FunctionOptRE);            \
    if (!MaybeFunctionFilter)                                                  \
      return MaybeFunctionFilter.takeError();                                  \
                                                                               \
    auto MaybeRemarkNameFilter =                                               \
        FilterMatcher::createExactOrRE(RemarkNameOpt, RemarkNameOptRE);        \
    if (!MaybeRemarkNameFilter)                                                \
      return MaybeRemarkNameFilter.takeError();                                \
                                                                               \
    auto MaybePassNameFilter =                                                 \
        FilterMatcher::createExactOrRE(PassNameOpt, PassNameOptRE);            \
    if (!MaybePassNameFilter)                                                  \
      return MaybePassNameFilter.takeError();                                  \
                                                                               \
    auto MaybeRemarkArgFilter = FilterMatcher::createExactOrRE(                \
        RemarkFilterArgByOpt, RemarkArgFilterOptRE);                           \
    if (!MaybeRemarkArgFilter)                                                 \
      return MaybeRemarkArgFilter.takeError();                                 \
                                                                               \
    std::optional<Type> TypeFilter;                                            \
    if (RemarkTypeOpt.getNumOccurrences())                                     \
      TypeFilter = RemarkTypeOpt.getValue();                                   \
                                                                               \
    return Filters{std::move(*MaybeFunctionFilter),                            \
                   std::move(*MaybeRemarkNameFilter),                          \
                   std::move(*MaybePassNameFilter),                            \
                   std::move(*MaybeRemarkArgFilter), TypeFilter};              \
  }

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);

/// Choose the serializer format. If \p SelectedFormat is Format::Auto, try to
/// detect the format based on the extension of \p OutputFileName or fall back
/// to \p DefaultFormat.
Format getSerializerFormat(StringRef OutputFileName, Format SelectedFormat,
                           Format DefaultFormat);

/// Filter object which can be either a string or a regex to match with the
/// remark properties.
class FilterMatcher {
  Regex FilterRE;
  std::string FilterStr;
  bool IsRegex;

  FilterMatcher(StringRef Filter, bool IsRegex)
      : FilterRE(Filter), FilterStr(Filter), IsRegex(IsRegex) {}

  static Expected<FilterMatcher> createRE(StringRef Arg, StringRef Value);

public:
  static FilterMatcher createExact(StringRef Filter) { return {Filter, false}; }

  static Expected<FilterMatcher>
  createRE(const llvm::cl::opt<std::string> &Arg);

  static Expected<FilterMatcher> createRE(StringRef Filter,
                                          const cl::list<std::string> &Arg);

  static Expected<std::optional<FilterMatcher>>
  createExactOrRE(const llvm::cl::opt<std::string> &ExactArg,
                  const llvm::cl::opt<std::string> &REArg);

  static FilterMatcher createAny() { return {".*", true}; }

  bool match(StringRef StringToMatch) const {
    if (IsRegex)
      return FilterRE.match(StringToMatch);
    return FilterStr == StringToMatch.trim().str();
  }
};

/// Filter out remarks based on remark properties (function, remark name, pass
/// name, argument values and type).
struct Filters {
  std::optional<FilterMatcher> FunctionFilter;
  std::optional<FilterMatcher> RemarkNameFilter;
  std::optional<FilterMatcher> PassNameFilter;
  std::optional<FilterMatcher> ArgFilter;
  std::optional<Type> RemarkTypeFilter;

  /// Returns true if \p Remark satisfies all the provided filters.
  bool filterRemark(const Remark &Remark);
};

} // namespace remarks
} // namespace llvm