CIRCT  19.0.0git
ArcCanonicalizer.cpp
Go to the documentation of this file.
1 //===- ArcCanonicalizer.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //===----------------------------------------------------------------------===//
7 //
8 // Simulation centric canonicalizations for non-arc operations and
9 // canonicalizations that require efficient symbol lookups.
10 //
11 //===----------------------------------------------------------------------===//
12 
16 #include "circt/Dialect/HW/HWOps.h"
19 #include "circt/Support/SymCache.h"
20 #include "mlir/IR/Matchers.h"
21 #include "mlir/IR/PatternMatch.h"
22 #include "mlir/Pass/Pass.h"
23 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
24 #include "llvm/Support/Debug.h"
25 
26 #define DEBUG_TYPE "arc-canonicalizer"
27 
28 namespace circt {
29 namespace arc {
30 #define GEN_PASS_DEF_ARCCANONICALIZER
31 #include "circt/Dialect/Arc/ArcPasses.h.inc"
32 } // namespace arc
33 } // namespace circt
34 
35 using namespace circt;
36 using namespace arc;
37 
38 //===----------------------------------------------------------------------===//
39 // Datastructures
40 //===----------------------------------------------------------------------===//
41 
42 namespace {
43 
44 /// A combination of SymbolCache and SymbolUserMap that also allows to add users
45 /// and remove symbols on-demand.
46 class SymbolHandler : public SymbolCache {
47 public:
48  /// Return the users of the provided symbol operation.
49  ArrayRef<Operation *> getUsers(Operation *symbol) const {
50  auto it = userMap.find(symbol);
51  return it != userMap.end() ? it->second.getArrayRef() : std::nullopt;
52  }
53 
54  /// Return true if the given symbol has no uses.
55  bool useEmpty(Operation *symbol) {
56  return !userMap.count(symbol) || userMap[symbol].empty();
57  }
58 
59  void addUser(Operation *def, Operation *user) {
60  assert(isa<mlir::SymbolOpInterface>(def));
61  if (!symbolCache.contains(cast<mlir::SymbolOpInterface>(def).getNameAttr()))
62  symbolCache.insert(
63  {cast<mlir::SymbolOpInterface>(def).getNameAttr(), def});
64  userMap[def].insert(user);
65  }
66 
67  void removeUser(Operation *def, Operation *user) {
68  assert(isa<mlir::SymbolOpInterface>(def));
69  if (symbolCache.contains(cast<mlir::SymbolOpInterface>(def).getNameAttr()))
70  userMap[def].remove(user);
71  if (userMap[def].empty())
72  userMap.erase(def);
73  }
74 
75  void removeDefinitionAndAllUsers(Operation *def) {
76  assert(isa<mlir::SymbolOpInterface>(def));
77  symbolCache.erase(cast<mlir::SymbolOpInterface>(def).getNameAttr());
78  userMap.erase(def);
79  }
80 
81  void collectAllSymbolUses(Operation *symbolTableOp,
82  SymbolTableCollection &symbolTable) {
83  // NOTE: the following is almost 1-1 taken from the SymbolUserMap
84  // constructor. They made it difficult to extend the implementation by
85  // having a lot of members private and non-virtual methods.
86  SmallVector<Operation *> symbols;
87  auto walkFn = [&](Operation *symbolTableOp, bool allUsesVisible) {
88  for (Operation &nestedOp : symbolTableOp->getRegion(0).getOps()) {
89  auto symbolUses = SymbolTable::getSymbolUses(&nestedOp);
90  assert(symbolUses && "expected uses to be valid");
91 
92  for (const SymbolTable::SymbolUse &use : *symbolUses) {
93  symbols.clear();
94  (void)symbolTable.lookupSymbolIn(symbolTableOp, use.getSymbolRef(),
95  symbols);
96  for (Operation *symbolOp : symbols)
97  userMap[symbolOp].insert(use.getUser());
98  }
99  }
100  };
101  // We just set `allSymUsesVisible` to false here because it isn't necessary
102  // for building the user map.
103  SymbolTable::walkSymbolTables(symbolTableOp, /*allSymUsesVisible=*/false,
104  walkFn);
105  }
106 
107 private:
108  DenseMap<Operation *, SetVector<Operation *>> userMap;
109 };
110 
111 /// A Listener keeping the provided SymbolHandler up-to-date. This is especially
112 /// important for simplifications (e.g. DCE) the rewriter performs automatically
113 /// that we cannot or do not want to turn off.
114 class ArcListener : public mlir::RewriterBase::Listener {
115 public:
116  explicit ArcListener(SymbolHandler *handler) : Listener(), handler(handler) {}
117 
118  void notifyOperationReplaced(Operation *op, Operation *replacement) override {
119  // If, e.g., a DefineOp is replaced with another DefineOp but with the same
120  // symbol, we don't want to drop the list of users.
121  auto symOp = dyn_cast<mlir::SymbolOpInterface>(op);
122  auto symReplacement = dyn_cast<mlir::SymbolOpInterface>(replacement);
123  if (symOp && symReplacement &&
124  symOp.getNameAttr() == symReplacement.getNameAttr())
125  return;
126 
127  remove(op);
128  // TODO: if an operation is inserted that defines a symbol and the symbol
129  // already has uses, those users are not added.
130  add(replacement);
131  }
132 
133  void notifyOperationReplaced(Operation *op, ValueRange replacement) override {
134  remove(op);
135  }
136 
137  void notifyOperationErased(Operation *op) override { remove(op); }
138 
139  void notifyOperationInserted(Operation *op,
140  mlir::IRRewriter::InsertPoint) override {
141  // TODO: if an operation is inserted that defines a symbol and the symbol
142  // already has uses, those users are not added.
143  add(op);
144  }
145 
146 private:
147  FailureOr<Operation *> maybeGetDefinition(Operation *op) {
148  if (auto callOp = dyn_cast<mlir::CallOpInterface>(op)) {
149  auto symAttr =
150  dyn_cast<mlir::SymbolRefAttr>(callOp.getCallableForCallee());
151  if (!symAttr)
152  return failure();
153  if (auto *def = handler->getDefinition(symAttr.getLeafReference()))
154  return def;
155  }
156  return failure();
157  }
158 
159  void remove(Operation *op) {
160  auto maybeDef = maybeGetDefinition(op);
161  if (!failed(maybeDef))
162  handler->removeUser(*maybeDef, op);
163 
164  if (isa<mlir::SymbolOpInterface>(op))
165  handler->removeDefinitionAndAllUsers(op);
166  }
167 
168  void add(Operation *op) {
169  auto maybeDef = maybeGetDefinition(op);
170  if (!failed(maybeDef))
171  handler->addUser(*maybeDef, op);
172 
173  if (auto defOp = dyn_cast<mlir::SymbolOpInterface>(op))
174  handler->addDefinition(defOp.getNameAttr(), op);
175  }
176 
177  SymbolHandler *handler;
178 };
179 
180 struct PatternStatistics {
181  unsigned removeUnusedArcArgumentsPatternNumArgsRemoved = 0;
182 };
183 
184 } // namespace
185 
186 //===----------------------------------------------------------------------===//
187 // Canonicalization patterns
188 //===----------------------------------------------------------------------===//
189 
190 namespace {
191 /// A rewrite pattern that has access to a symbol cache to access and modify the
192 /// symbol-defining op and symbol users as well as a namespace to query new
193 /// names. Each pattern has to make sure that the symbol handler is kept
194 /// up-to-date no matter whether the pattern succeeds of fails.
195 template <typename SourceOp>
196 class SymOpRewritePattern : public OpRewritePattern<SourceOp> {
197 public:
198  SymOpRewritePattern(MLIRContext *ctxt, SymbolHandler &symbolCache,
199  Namespace &names, PatternStatistics &stats,
200  mlir::PatternBenefit benefit = 1,
201  ArrayRef<StringRef> generatedNames = {})
202  : OpRewritePattern<SourceOp>(ctxt, benefit, generatedNames), names(names),
203  symbolCache(symbolCache), statistics(stats) {}
204 
205 protected:
206  Namespace &names;
207  SymbolHandler &symbolCache;
208  PatternStatistics &statistics;
209 };
210 
211 class MemWritePortEnableAndMaskCanonicalizer
212  : public SymOpRewritePattern<MemoryWritePortOp> {
213 public:
214  MemWritePortEnableAndMaskCanonicalizer(
215  MLIRContext *ctxt, SymbolHandler &symbolCache, Namespace &names,
216  PatternStatistics &stats, DenseMap<StringAttr, StringAttr> &arcMapping)
217  : SymOpRewritePattern<MemoryWritePortOp>(ctxt, symbolCache, names, stats),
218  arcMapping(arcMapping) {}
219  LogicalResult matchAndRewrite(MemoryWritePortOp op,
220  PatternRewriter &rewriter) const final;
221 
222 private:
223  DenseMap<StringAttr, StringAttr> &arcMapping;
224 };
225 
226 struct CallPassthroughArc : public SymOpRewritePattern<CallOp> {
227  using SymOpRewritePattern::SymOpRewritePattern;
228  LogicalResult matchAndRewrite(CallOp op,
229  PatternRewriter &rewriter) const final;
230 };
231 
232 struct RemoveUnusedArcs : public SymOpRewritePattern<DefineOp> {
233  using SymOpRewritePattern::SymOpRewritePattern;
234  LogicalResult matchAndRewrite(DefineOp op,
235  PatternRewriter &rewriter) const final;
236 };
237 
238 struct ICMPCanonicalizer : public OpRewritePattern<comb::ICmpOp> {
239  using OpRewritePattern::OpRewritePattern;
240  LogicalResult matchAndRewrite(comb::ICmpOp op,
241  PatternRewriter &rewriter) const final;
242 };
243 
244 struct CompRegCanonicalizer : public OpRewritePattern<seq::CompRegOp> {
245  using OpRewritePattern::OpRewritePattern;
246  LogicalResult matchAndRewrite(seq::CompRegOp op,
247  PatternRewriter &rewriter) const final;
248 };
249 
250 struct RemoveUnusedArcArgumentsPattern : public SymOpRewritePattern<DefineOp> {
251  using SymOpRewritePattern::SymOpRewritePattern;
252  LogicalResult matchAndRewrite(DefineOp op,
253  PatternRewriter &rewriter) const final;
254 };
255 
256 struct SinkArcInputsPattern : public SymOpRewritePattern<DefineOp> {
257  using SymOpRewritePattern::SymOpRewritePattern;
258  LogicalResult matchAndRewrite(DefineOp op,
259  PatternRewriter &rewriter) const final;
260 };
261 
262 } // namespace
263 
264 //===----------------------------------------------------------------------===//
265 // Helpers
266 //===----------------------------------------------------------------------===//
267 
268 LogicalResult canonicalizePassthoughCall(mlir::CallOpInterface callOp,
269  SymbolHandler &symbolCache,
270  PatternRewriter &rewriter) {
271  auto defOp = cast<DefineOp>(symbolCache.getDefinition(
272  callOp.getCallableForCallee().get<SymbolRefAttr>().getLeafReference()));
273  if (defOp.isPassthrough()) {
274  symbolCache.removeUser(defOp, callOp);
275  rewriter.replaceOp(callOp, callOp.getArgOperands());
276  return success();
277  }
278  return failure();
279 }
280 
281 //===----------------------------------------------------------------------===//
282 // Canonicalization pattern implementations
283 //===----------------------------------------------------------------------===//
284 
285 LogicalResult MemWritePortEnableAndMaskCanonicalizer::matchAndRewrite(
286  MemoryWritePortOp op, PatternRewriter &rewriter) const {
287  auto defOp = cast<DefineOp>(symbolCache.getDefinition(op.getArcAttr()));
288  APInt enable;
289 
290  if (op.getEnable() &&
291  mlir::matchPattern(
292  defOp.getBodyBlock().getTerminator()->getOperand(op.getEnableIdx()),
293  mlir::m_ConstantInt(&enable))) {
294  if (enable.isZero()) {
295  symbolCache.removeUser(defOp, op);
296  rewriter.eraseOp(op);
297  if (symbolCache.useEmpty(defOp)) {
298  symbolCache.removeDefinitionAndAllUsers(defOp);
299  rewriter.eraseOp(defOp);
300  }
301  return success();
302  }
303  if (enable.isAllOnes()) {
304  if (arcMapping.count(defOp.getNameAttr())) {
305  auto arcWithoutEnable = arcMapping[defOp.getNameAttr()];
306  // Remove the enable attribute
307  rewriter.modifyOpInPlace(op, [&]() {
308  op.setEnable(false);
309  op.setArc(arcWithoutEnable.getValue());
310  });
311  symbolCache.removeUser(defOp, op);
312  symbolCache.addUser(symbolCache.getDefinition(arcWithoutEnable), op);
313  return success();
314  }
315 
316  auto newName = names.newName(defOp.getName());
317  auto users = SmallVector<Operation *>(symbolCache.getUsers(defOp));
318  symbolCache.removeDefinitionAndAllUsers(defOp);
319 
320  // Remove the enable attribute
321  rewriter.modifyOpInPlace(op, [&]() {
322  op.setEnable(false);
323  op.setArc(newName);
324  });
325 
326  auto newResultTypes = op.getArcResultTypes();
327 
328  // Create a new arc that acts as replacement for other users
329  rewriter.setInsertionPoint(defOp);
330  auto newDefOp = rewriter.cloneWithoutRegions(defOp);
331  auto *block = rewriter.createBlock(
332  &newDefOp.getBody(), newDefOp.getBody().end(),
333  newDefOp.getArgumentTypes(),
334  SmallVector<Location>(newDefOp.getNumArguments(), defOp.getLoc()));
335  auto callOp = rewriter.create<CallOp>(newDefOp.getLoc(), newResultTypes,
336  newName, block->getArguments());
337  SmallVector<Value> results(callOp->getResults());
338  Value constTrue = rewriter.create<hw::ConstantOp>(
339  newDefOp.getLoc(), rewriter.getI1Type(), 1);
340  results.insert(results.begin() + op.getEnableIdx(), constTrue);
341  rewriter.create<OutputOp>(newDefOp.getLoc(), results);
342 
343  // Remove the enable output from the current arc
344  auto *terminator = defOp.getBodyBlock().getTerminator();
345  rewriter.modifyOpInPlace(
346  terminator, [&]() { terminator->eraseOperand(op.getEnableIdx()); });
347  rewriter.modifyOpInPlace(defOp, [&]() {
348  defOp.setName(newName);
349  defOp.setFunctionType(
350  rewriter.getFunctionType(defOp.getArgumentTypes(), newResultTypes));
351  });
352 
353  // Update symbol cache
354  symbolCache.addDefinition(defOp.getNameAttr(), defOp);
355  symbolCache.addDefinition(newDefOp.getNameAttr(), newDefOp);
356  symbolCache.addUser(defOp, callOp);
357  for (auto *user : users)
358  symbolCache.addUser(user == op ? defOp : newDefOp, user);
359 
360  arcMapping[newDefOp.getNameAttr()] = defOp.getNameAttr();
361  return success();
362  }
363  }
364  return failure();
365 }
366 
367 LogicalResult
368 CallPassthroughArc::matchAndRewrite(CallOp op,
369  PatternRewriter &rewriter) const {
370  return canonicalizePassthoughCall(op, symbolCache, rewriter);
371 }
372 
373 LogicalResult
374 RemoveUnusedArcs::matchAndRewrite(DefineOp op,
375  PatternRewriter &rewriter) const {
376  if (symbolCache.useEmpty(op)) {
377  op.getBody().walk([&](mlir::CallOpInterface user) {
378  if (auto symbol = dyn_cast<SymbolRefAttr>(user.getCallableForCallee()))
379  if (auto *defOp = symbolCache.getDefinition(symbol.getLeafReference()))
380  symbolCache.removeUser(defOp, user);
381  });
382  symbolCache.removeDefinitionAndAllUsers(op);
383  rewriter.eraseOp(op);
384  return success();
385  }
386  return failure();
387 }
388 
389 LogicalResult
390 ICMPCanonicalizer::matchAndRewrite(comb::ICmpOp op,
391  PatternRewriter &rewriter) const {
392  auto getConstant = [&](const APInt &constant) -> Value {
393  return rewriter.create<hw::ConstantOp>(op.getLoc(), constant);
394  };
395  auto sameWidthIntegers = [](TypeRange types) -> std::optional<unsigned> {
396  if (llvm::all_equal(types) && !types.empty())
397  if (auto intType = dyn_cast<IntegerType>(*types.begin()))
398  return intType.getWidth();
399  return std::nullopt;
400  };
401  auto negate = [&](Value input) -> Value {
402  auto constTrue = rewriter.create<hw::ConstantOp>(op.getLoc(), APInt(1, 1));
403  return rewriter.create<comb::XorOp>(op.getLoc(), input, constTrue,
404  op.getTwoState());
405  };
406 
407  APInt rhs;
408  if (matchPattern(op.getRhs(), mlir::m_ConstantInt(&rhs))) {
409  if (auto concatOp = op.getLhs().getDefiningOp<comb::ConcatOp>()) {
410  if (auto optionalWidth =
411  sameWidthIntegers(concatOp->getOperands().getTypes())) {
412  if ((op.getPredicate() == comb::ICmpPredicate::eq ||
413  op.getPredicate() == comb::ICmpPredicate::ne) &&
414  rhs.isAllOnes()) {
415  Value andOp = rewriter.create<comb::AndOp>(
416  op.getLoc(), concatOp.getInputs(), op.getTwoState());
417  if (*optionalWidth == 1) {
418  if (op.getPredicate() == comb::ICmpPredicate::ne)
419  andOp = negate(andOp);
420  rewriter.replaceOp(op, andOp);
421  return success();
422  }
423  rewriter.replaceOpWithNewOp<comb::ICmpOp>(
424  op, op.getPredicate(), andOp,
425  getConstant(APInt(*optionalWidth, rhs.getZExtValue())),
426  op.getTwoState());
427  return success();
428  }
429 
430  if ((op.getPredicate() == comb::ICmpPredicate::ne ||
431  op.getPredicate() == comb::ICmpPredicate::eq) &&
432  rhs.isZero()) {
433  Value orOp = rewriter.create<comb::OrOp>(
434  op.getLoc(), concatOp.getInputs(), op.getTwoState());
435  if (*optionalWidth == 1) {
436  if (op.getPredicate() == comb::ICmpPredicate::eq)
437  orOp = negate(orOp);
438  rewriter.replaceOp(op, orOp);
439  return success();
440  }
441  rewriter.replaceOpWithNewOp<comb::ICmpOp>(
442  op, op.getPredicate(), orOp,
443  getConstant(APInt(*optionalWidth, rhs.getZExtValue())),
444  op.getTwoState());
445  return success();
446  }
447  }
448  }
449  }
450  return failure();
451 }
452 
453 LogicalResult RemoveUnusedArcArgumentsPattern::matchAndRewrite(
454  DefineOp op, PatternRewriter &rewriter) const {
455  BitVector toDelete(op.getNumArguments());
456  for (auto [i, arg] : llvm::enumerate(op.getArguments()))
457  if (arg.use_empty())
458  toDelete.set(i);
459 
460  if (toDelete.none())
461  return failure();
462 
463  // Collect the mutable callers in a first iteration. If there is a user that
464  // does not implement the interface, we have to abort the rewrite and have to
465  // make sure that we didn't change anything so far.
466  SmallVector<mlir::CallOpInterface> mutableUsers;
467  for (auto *user : symbolCache.getUsers(op)) {
468  auto callOpMutable = dyn_cast<mlir::CallOpInterface>(user);
469  if (!callOpMutable)
470  return failure();
471  mutableUsers.push_back(callOpMutable);
472  }
473 
474  // Do the actual rewrites.
475  for (auto user : mutableUsers)
476  for (int i = toDelete.size() - 1; i >= 0; --i)
477  if (toDelete[i])
478  user.getArgOperandsMutable().erase(i);
479 
480  op.eraseArguments(toDelete);
481  op.setFunctionType(
482  rewriter.getFunctionType(op.getArgumentTypes(), op.getResultTypes()));
483 
484  statistics.removeUnusedArcArgumentsPatternNumArgsRemoved += toDelete.count();
485  return success();
486 }
487 
488 LogicalResult
489 SinkArcInputsPattern::matchAndRewrite(DefineOp op,
490  PatternRewriter &rewriter) const {
491  // First check that all users implement the interface we need to be able to
492  // modify the users.
493  auto users = symbolCache.getUsers(op);
494  if (llvm::any_of(
495  users, [](auto *user) { return !isa<mlir::CallOpInterface>(user); }))
496  return failure();
497 
498  // Find all arguments that use constant operands only.
499  SmallVector<Operation *> stateConsts(op.getNumArguments());
500  bool first = true;
501  for (auto *user : users) {
502  auto callOp = cast<mlir::CallOpInterface>(user);
503  for (auto [constArg, input] :
504  llvm::zip(stateConsts, callOp.getArgOperands())) {
505  if (auto *constOp = input.getDefiningOp();
506  constOp && constOp->template hasTrait<OpTrait::ConstantLike>()) {
507  if (first) {
508  constArg = constOp;
509  continue;
510  }
511  if (constArg &&
512  constArg->getName() == input.getDefiningOp()->getName() &&
513  constArg->getAttrDictionary() ==
514  input.getDefiningOp()->getAttrDictionary())
515  continue;
516  }
517  constArg = nullptr;
518  }
519  first = false;
520  }
521 
522  // Move the constants into the arc and erase the block arguments.
523  rewriter.setInsertionPointToStart(&op.getBodyBlock());
524  llvm::BitVector toDelete(op.getBodyBlock().getNumArguments());
525  for (auto [constArg, arg] : llvm::zip(stateConsts, op.getArguments())) {
526  if (!constArg)
527  continue;
528  auto *inlinedConst = rewriter.clone(*constArg);
529  rewriter.replaceAllUsesWith(arg, inlinedConst->getResult(0));
530  toDelete.set(arg.getArgNumber());
531  }
532  op.getBodyBlock().eraseArguments(toDelete);
533  op.setType(rewriter.getFunctionType(op.getBodyBlock().getArgumentTypes(),
534  op.getResultTypes()));
535 
536  // Rewrite all arc uses to not pass in the constant anymore.
537  for (auto *user : users) {
538  auto callOp = cast<mlir::CallOpInterface>(user);
539  SmallPtrSet<Value, 4> maybeUnusedValues;
540  SmallVector<Value> newInputs;
541  for (auto [index, value] : llvm::enumerate(callOp.getArgOperands())) {
542  if (toDelete[index])
543  maybeUnusedValues.insert(value);
544  else
545  newInputs.push_back(value);
546  }
547  rewriter.modifyOpInPlace(
548  callOp, [&]() { callOp.getArgOperandsMutable().assign(newInputs); });
549  for (auto value : maybeUnusedValues)
550  if (value.use_empty())
551  rewriter.eraseOp(value.getDefiningOp());
552  }
553 
554  return success(toDelete.any());
555 }
556 
557 LogicalResult
558 CompRegCanonicalizer::matchAndRewrite(seq::CompRegOp op,
559  PatternRewriter &rewriter) const {
560  if (!op.getReset())
561  return failure();
562 
563  // Because Arcilator supports constant zero reset values, skip them.
564  APInt constant;
565  if (mlir::matchPattern(op.getResetValue(), mlir::m_ConstantInt(&constant)))
566  if (constant.isZero())
567  return failure();
568 
569  Value newInput = rewriter.create<comb::MuxOp>(
570  op->getLoc(), op.getReset(), op.getResetValue(), op.getInput());
571  rewriter.modifyOpInPlace(op, [&]() {
572  op.getInputMutable().set(newInput);
573  op.getResetMutable().clear();
574  op.getResetValueMutable().clear();
575  });
576 
577  return success();
578 }
579 
580 //===----------------------------------------------------------------------===//
581 // ArcCanonicalizerPass implementation
582 //===----------------------------------------------------------------------===//
583 
584 namespace {
585 struct ArcCanonicalizerPass
586  : public arc::impl::ArcCanonicalizerBase<ArcCanonicalizerPass> {
587  void runOnOperation() override;
588 };
589 } // namespace
590 
591 void ArcCanonicalizerPass::runOnOperation() {
592  MLIRContext &ctxt = getContext();
593  SymbolTableCollection symbolTable;
594  SymbolHandler cache;
595  cache.addDefinitions(getOperation());
596  cache.collectAllSymbolUses(getOperation(), symbolTable);
597  Namespace names;
598  names.add(cache);
599  DenseMap<StringAttr, StringAttr> arcMapping;
600 
601  mlir::GreedyRewriteConfig config;
602  config.enableRegionSimplification = false;
603  config.maxIterations = 10;
604  config.useTopDownTraversal = true;
605  ArcListener listener(&cache);
606  config.listener = &listener;
607 
608  PatternStatistics statistics;
609  RewritePatternSet symbolPatterns(&getContext());
610  symbolPatterns.add<CallPassthroughArc, RemoveUnusedArcs,
611  RemoveUnusedArcArgumentsPattern, SinkArcInputsPattern>(
612  &getContext(), cache, names, statistics);
613  symbolPatterns.add<MemWritePortEnableAndMaskCanonicalizer>(
614  &getContext(), cache, names, statistics, arcMapping);
615 
616  if (failed(mlir::applyPatternsAndFoldGreedily(
617  getOperation(), std::move(symbolPatterns), config)))
618  return signalPassFailure();
619 
620  numArcArgsRemoved = statistics.removeUnusedArcArgumentsPatternNumArgsRemoved;
621 
622  RewritePatternSet patterns(&ctxt);
623  for (auto *dialect : ctxt.getLoadedDialects())
624  dialect->getCanonicalizationPatterns(patterns);
625  for (mlir::RegisteredOperationName op : ctxt.getRegisteredOperations())
626  op.getCanonicalizationPatterns(patterns, &ctxt);
627  patterns.add<ICMPCanonicalizer, CompRegCanonicalizer>(&getContext());
628 
629  // Don't test for convergence since it is often not reached.
630  (void)mlir::applyPatternsAndFoldGreedily(getOperation(), std::move(patterns),
631  config);
632 }
633 
634 std::unique_ptr<mlir::Pass> arc::createArcCanonicalizerPass() {
635  return std::make_unique<ArcCanonicalizerPass>();
636 }
LogicalResult canonicalizePassthoughCall(mlir::CallOpInterface callOp, SymbolHandler &symbolCache, PatternRewriter &rewriter)
assert(baseType &&"element must be base type")
static std::optional< APSInt > getConstant(Attribute operand)
Determine the value of a constant operand for the sake of constant folding.
static InstancePath empty
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:29
void add(SymbolCache &symCache)
SymbolCache initializer; initialize from every key that is convertible to a StringAttr in the SymbolC...
Definition: Namespace.h:47
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
Definition: SymCache.h:85
SymbolCacheBase::Iterator end() override
Definition: SymCache.h:125
def create(data_type, value)
Definition: hw.py:393
std::unique_ptr< mlir::Pass > createArcCanonicalizerPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21