File: PassManager.cpp

package info (click to toggle)
intel-graphics-compiler 1.0.12504.6-1%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 83,912 kB
  • sloc: cpp: 910,147; lisp: 202,655; ansic: 15,197; python: 4,025; yacc: 2,241; lex: 1,570; pascal: 244; sh: 104; makefile: 25
file content (344 lines) | stat: -rw-r--r-- 11,561 bytes parent folder | download
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/*========================== begin_copyright_notice ============================

Copyright (C) 2021 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

#include "vc/Support/PassManager.h"
#include "vc/Support/PassPrinters.h"

#include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/StringMap.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Analysis/CallGraphSCCPass.h>
#include <llvm/Analysis/LoopPass.h>
#include <llvm/Analysis/RegionPass.h>
#include <llvm/IR/IRPrintingPasses.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/Mutex.h>
#include <llvm/Support/Regex.h>
#include <llvm/Support/raw_ostream.h>

#include "Probe/Assertion.h"

#include <string>
#include <sstream>
#include <utility>

using namespace llvm;

// One can either add extra passes inside vc::PassManager::add or inside
// vc::addPass function. Otherwise pass will be added multiple times.
// This option defines whether addition inside vc::PassManager should take
// place.
static cl::opt<bool> OverridePassManagerOpt(
    "vc-choose-pass-manager-override", cl::init(true), cl::Hidden,
    cl::desc("Take pass manager overrideing over addPass func"));

static cl::opt<bool>
    SplitIRDumps("vc-dump-ir-split", cl::init(false), cl::Hidden,
                 cl::desc("Split IR dumps into separate files"));

namespace {
struct PassNumber {
  int N;
  PassNumber(int n) : N(n) {}
  std::string str() { return N ? (std::string("#") + std::to_string(N)) : ""; }
};

class PassIndexSet {
  SmallVector<int, 1> Indexes;
  int Occurence;
  unsigned i = 0;

public:
  PassIndexSet(int Occ = 0) : Occurence(Occ) {}
  std::pair<bool, PassNumber> isCurrent() {
    ++Occurence;
    if (Indexes.empty())
      return {true, Occurence};
    if ((i < Indexes.size()) && (Occurence == Indexes[i])) {
      ++i;
      return {true, Occurence};
    }
    return {false, Occurence};
  }

  void add(int Val) {
    auto Begin = Indexes.begin();
    auto End = Indexes.end();
    auto Iter = std::lower_bound(Begin, End, Val);
    if (Begin == End || *Iter != Val)
      Indexes.insert(Iter, Val);
  }
};

class PassSet {
  StringMap<PassIndexSet> PassMap;

public:
  void insert(StringRef PassArg, int Index) { PassMap[PassArg].add(Index); }
  void insert(StringRef PassArg) { PassMap[PassArg]; }
  std::pair<bool, PassNumber> includes(StringRef PassArg) {
    auto It = PassMap.find(PassArg);
    auto End = PassMap.end();
    if (It == End) {
      if (PassMap.count("*")) {
        PassMap.insert({PassArg, 1});
        return {true, 1};
      }
      return {false, 0};
    }
    return It->second.isCurrent();
  }
  bool empty() { return PassMap.empty(); }
};

} // namespace

template <>
bool cl::parser<PassSet>::parse(cl::Option &O, StringRef ArgName,
                                StringRef ArgValue, PassSet &Val) {
  static auto RegExp = Regex("\\*|([^#]+)(#([[:digit:]]+))?");
  SmallVector<StringRef, 4> Matches;
  if (RegExp.match(ArgValue, &Matches)) {
    auto &Whole = Matches[0];
    auto &PassArg = Matches[1];
    auto &PassNumber = Matches[3];
    if (PassNumber.size())
      Val.insert(
          std::move(PassArg),
          std::stoi(std::string{std::make_move_iterator(PassNumber.begin()),
                                std::make_move_iterator(PassNumber.end())}));
    else
      Val.insert(std::move(Whole));
    return false;
  }
  return true;
}

namespace {

class PassSetOption {
  cl::opt<PassSet> CLOption;

public:
  template <typename... Mods>
  PassSetOption(const Mods &... Ms)
      : CLOption(Ms..., cl::ZeroOrMore, cl::CommaSeparated) {}
  auto &getValue() { return CLOption.getValue(); }
  bool empty() { return getValue().empty(); }
};

using OutputStreamHandle = std::unique_ptr<llvm::raw_fd_ostream>;
static OutputStreamHandle createOutputStream(const llvm::Twine &Name) {
  // no error handling since this is debug output
  std::error_code EC;
  auto Result = std::make_unique<llvm::raw_fd_ostream>(Name.str(), EC);
  Result->SetUnbuffered();
  return Result;
}

// global (!!!) variable storing output stream handles for IR printer,
// guarded by mutex
static ManagedStatic<std::vector<OutputStreamHandle>> IRDumpStreams;
static ManagedStatic<sys::SmartMutex<true>> IRDumpsLock;

llvm::raw_fd_ostream &getFileStreamForIRDump(const Twine &Name) {
  sys::SmartScopedLock<true> Writer(*IRDumpsLock);
  OutputStreamHandle OS = createOutputStream(Name);
  IRDumpStreams->push_back(std::move(OS));
  return *IRDumpStreams->back();
}

enum class IRDumpType { Before, After };

llvm::raw_ostream &getOutputStreamForIRDump(IRDumpType DumpType,
                                            StringRef PassArg, PassNumber N) {
  static int Id = 0;
  std::stringstream ss;
  ss.fill('0');
  ss.width(3);
  ss << Id++;

  // FIXME: this won't work well for online compilations and multi-theaded
  // compilations. We need extra facilities to ensure that created
  // files are unique for every compilation process
  if (!SplitIRDumps)
    return llvm::errs();

  std::string DumpName = ss.str() + "_" +
      (((DumpType == IRDumpType::Before) ? Twine("before_") : Twine("after_")) +
       PassArg + N.str() + ".ll")
          .str();
  std::replace_if(DumpName.begin(), DumpName.end(),
                  [](unsigned char c) { return !std::isalnum(c) && c != '.'; },
                  '_');
  return getFileStreamForIRDump(DumpName);
}

std::string getIRDumpBanner(StringRef PassName, StringRef PassArg, PassNumber N,
                            IRDumpType Type) {
  return ("; *** " +
          (Type == IRDumpType::Before ? Twine("IR Dump Before ")
                                      : Twine("IR Dump After")) +
          "*** (" + PassArg + N.str() + ")")
      .str();
}

struct ExtraIRDumpBeforePass {
  static PassSetOption option;
  static auto createPass(const PassInfo *PI, PassKind PassKindID,
                         PassNumber N) {
    auto PassArg = PI->getPassArgument();
    return createPrintModulePass(
        getOutputStreamForIRDump(IRDumpType::Before, PassArg, N),
        getIRDumpBanner(PassArg, PassArg, N, IRDumpType::Before));
  }
};
PassSetOption ExtraIRDumpBeforePass::option{
    "vc-dump-ir-before-pass",
    cl::desc("Debug only. Dump IR of the module before the specified pass.")};

struct ExtraVerificationBeforePass {
  static PassSetOption option;
  static auto createPass(const PassInfo *PI, PassKind PassKindID,
                         PassNumber N) {
    errs() << "extra verifier shall be run before <" << PI->getPassArgument()
           << N.str() << ">\n";
    return createVerifierPass();
  }
};
PassSetOption ExtraVerificationBeforePass::option{
    "vc-run-verifier-before-pass",
    cl::desc("Debug only. Run verifier before the specified pass.")};

struct ExtraIRDumpAfterPass {
  static PassSetOption option;
  static auto createPass(const PassInfo *PI, PassKind PassKindID,
                         PassNumber N) {
    auto PassArg = PI->getPassArgument();
    return createPrintModulePass(
        getOutputStreamForIRDump(IRDumpType::After, PassArg, N),
        getIRDumpBanner(PassArg, PassArg, N, IRDumpType::After));
  }
};
PassSetOption ExtraIRDumpAfterPass::option{
    "vc-dump-ir-after-pass",
    cl::desc("Debug only. Dump IR of the module after the specified pass.")};

struct ExtraVerificationAfterPass {
  static PassSetOption option;
  static auto createPass(const PassInfo *PI, PassKind PassKindID,
                         PassNumber N) {
    errs() << "extra verifier shall be run after <" << PI->getPassArgument()
           << N.str() << ">\n";
    return createVerifierPass();
  }
};
PassSetOption ExtraVerificationAfterPass::option{
    "vc-run-verifier-after-pass",
    cl::desc("Debug only. Run verifier after the specified pass.")};

static PassSetOption DisablePass{
    "vc-disable-pass", cl::desc("Debug only. Do not add the specified pass")};

struct ExtraPrinterPassAfterPass {
  static PassSetOption option;
  static Pass *createPass(const PassInfo *PI, PassKind PassKindID,
                          PassNumber N) {
    auto PassName = PI->getPassName();
    auto PassArg = PI->getPassArgument();
    switch (PassKindID) {
    case PT_Region:
      return vc::createRegionPassPrinter(PI, llvm::errs());
    case PT_Loop:
      return vc::createLoopPassPrinter(PI, llvm::errs());
    case PT_Function:
      return vc::createFunctionPassPrinter(PI, llvm::errs());
    case PT_CallGraphSCC:
      return vc::createCallGraphPassPrinter(PI, llvm::errs());
    default:
      return vc::createModulePassPrinter(PI, llvm::errs());
    }
  }
};
PassSetOption ExtraPrinterPassAfterPass::option{
    "vc-analyze", cl::desc("Debug only. Print specified analyses. Behaves like "
                           "-analyze opt option.")};

bool AllOptionsAreEmpty() {
  return ExtraIRDumpBeforePass::option.empty() &&
         ExtraIRDumpAfterPass::option.empty() &&
         ExtraVerificationBeforePass::option.empty() &&
         ExtraVerificationAfterPass::option.empty() &&
         ExtraPrinterPassAfterPass::option.empty() && DisablePass.empty();
}
} // namespace

template <typename PMOption, typename PMT, typename AdderT>
void addExtraPass(PMT &PM, const PassInfo *CurrentPI, PassKind PassKindID,
                  AdderT Adder) {
  auto res = PMOption::option.getValue().includes(CurrentPI->getPassArgument());
  if (res.first)
    Adder(PM, *PMOption::createPass(CurrentPI, PassKindID, res.second));
}

// Adds pass \p P to \p PM plus some additional passes.
// Passes are added by \p Adder functor.
// AdderT: (PMT &, Pass &) -> void
template <typename PMT, typename AdderT>
void addPassImpl(PMT &PM, Pass &P, AdderT Adder) {
  if (AllOptionsAreEmpty())
    return Adder(PM, P);

  const auto *PassInfo = Pass::lookupPassInfo(P.getPassID());
  if (!PassInfo) {
#ifndef NDEBUG
    llvm::errs() << "WARNING: LLVM could not find PassInfo for the <"
                 << P.getPassName() << "> pass! Extra passes "
                 << "won't be injected.\n";
#endif // NDEBUG
    return Adder(PM, P);
  }
  PassKind PassKindID = P.getPassKind();
  // Extra passes are inserted independent on whether or not the pass is ommited
  // to preserve numbering of passes inside them (if '*' is passed to
  // -vc-dump-...-pass, and one occurence of a pass is ommited, the numbering of
  // others would shift if addExtraPasses would not be called).
  addExtraPass<ExtraIRDumpBeforePass>(PM, PassInfo, PassKindID, Adder);
  addExtraPass<ExtraVerificationBeforePass>(PM, PassInfo, PassKindID, Adder);

  auto PassArg = PassInfo->getPassArgument();
  auto res = DisablePass.getValue().includes(PassArg);
  if (res.first)
    errs() << "Pass " << PassArg << res.second.str() << " is ommited\n";
  else
    Adder(PM, P);

  addExtraPass<ExtraIRDumpAfterPass>(PM, PassInfo, PassKindID, Adder);
  addExtraPass<ExtraPrinterPassAfterPass>(PM, PassInfo, PassKindID, Adder);
  addExtraPass<ExtraVerificationAfterPass>(PM, PassInfo, PassKindID, Adder);
}

void vc::PassManager::add(Pass *P) {
  IGC_ASSERT(P);
  auto Adder = [](vc::PassManager &PM, Pass &P) {
    PM.legacy::PassManager::add(&P);
  };
  if (OverridePassManagerOpt.getValue())
    return addPassImpl(*this, *P, Adder);
  Adder(*this, *P);
}

void vc::addPass(legacy::PassManagerBase &PM, Pass *P) {
  IGC_ASSERT(P);
  auto Adder = [](legacy::PassManagerBase &PM, Pass &P) { PM.add(&P); };
  if (OverridePassManagerOpt.getValue())
    return Adder(PM, *P);
  addPassImpl(PM, *P, Adder);
}