20#include "mlir/IR/IRMapping.h"
21#include "mlir/IR/Matchers.h"
22#include "mlir/IR/PatternMatch.h"
23#include "mlir/Pass/Pass.h"
24#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
25#include "llvm/Support/Debug.h"
27#define DEBUG_TYPE "arc-canonicalizer"
31#define GEN_PASS_DEF_ARCCANONICALIZER
32#include "circt/Dialect/Arc/ArcPasses.h.inc"
50 ArrayRef<Operation *> getUsers(Operation *symbol)
const {
51 auto it = userMap.find(symbol);
52 return it != userMap.
end() ? it->second.getArrayRef()
53 : ArrayRef<Operation *>();
57 bool useEmpty(Operation *symbol) {
58 return !userMap.count(symbol) || userMap[symbol].empty();
61 void addUser(Operation *def, Operation *user) {
62 assert(isa<mlir::SymbolOpInterface>(def));
63 if (!symbolCache.contains(cast<mlir::SymbolOpInterface>(def).getNameAttr()))
65 {cast<mlir::SymbolOpInterface>(def).getNameAttr(), def});
66 userMap[def].insert(user);
69 void removeUser(Operation *def, Operation *user) {
70 assert(isa<mlir::SymbolOpInterface>(def));
71 if (symbolCache.contains(cast<mlir::SymbolOpInterface>(def).getNameAttr()))
72 userMap[def].remove(user);
73 if (userMap[def].
empty())
77 void removeDefinitionAndAllUsers(Operation *def) {
78 assert(isa<mlir::SymbolOpInterface>(def));
79 symbolCache.erase(cast<mlir::SymbolOpInterface>(def).getNameAttr());
83 void collectAllSymbolUses(Operation *symbolTableOp,
84 SymbolTableCollection &symbolTable) {
88 SmallVector<Operation *> symbols;
89 auto walkFn = [&](Operation *symbolTableOp,
bool allUsesVisible) {
90 for (Operation &nestedOp : symbolTableOp->getRegion(0).getOps()) {
91 auto symbolUses = SymbolTable::getSymbolUses(&nestedOp);
92 assert(symbolUses &&
"expected uses to be valid");
94 for (
const SymbolTable::SymbolUse &use : *symbolUses) {
96 (void)symbolTable.lookupSymbolIn(symbolTableOp, use.getSymbolRef(),
98 for (Operation *symbolOp : symbols)
99 userMap[symbolOp].insert(use.getUser());
105 SymbolTable::walkSymbolTables(symbolTableOp,
false,
110 DenseMap<Operation *, SetVector<Operation *>> userMap;
116class ArcListener :
public mlir::RewriterBase::Listener {
118 explicit ArcListener(SymbolHandler *handler) : Listener(), handler(handler) {}
120 void notifyOperationReplaced(Operation *op, Operation *replacement)
override {
123 auto symOp = dyn_cast<mlir::SymbolOpInterface>(op);
124 auto symReplacement = dyn_cast<mlir::SymbolOpInterface>(replacement);
125 if (symOp && symReplacement &&
126 symOp.getNameAttr() == symReplacement.getNameAttr())
135 void notifyOperationReplaced(Operation *op, ValueRange replacement)
override {
139 void notifyOperationErased(Operation *op)
override { remove(op); }
141 void notifyOperationInserted(Operation *op,
142 mlir::IRRewriter::InsertPoint)
override {
149 FailureOr<Operation *> maybeGetDefinition(Operation *op) {
150 if (
auto callOp = dyn_cast<mlir::CallOpInterface>(op)) {
152 dyn_cast<mlir::SymbolRefAttr>(callOp.getCallableForCallee());
155 if (
auto *def = handler->getDefinition(symAttr.getLeafReference()))
161 void remove(Operation *op) {
162 auto maybeDef = maybeGetDefinition(op);
163 if (!failed(maybeDef))
164 handler->removeUser(*maybeDef, op);
166 if (isa<mlir::SymbolOpInterface>(op))
167 handler->removeDefinitionAndAllUsers(op);
170 void add(Operation *op) {
171 auto maybeDef = maybeGetDefinition(op);
172 if (!failed(maybeDef))
173 handler->addUser(*maybeDef, op);
175 if (
auto defOp = dyn_cast<mlir::SymbolOpInterface>(op))
176 handler->addDefinition(defOp.getNameAttr(), op);
179 SymbolHandler *handler;
182struct PatternStatistics {
183 unsigned removeUnusedArcArgumentsPatternNumArgsRemoved = 0;
197template <
typename SourceOp>
200 SymOpRewritePattern(MLIRContext *ctxt, SymbolHandler &symbolCache,
201 Namespace &names, PatternStatistics &stats,
202 mlir::PatternBenefit benefit = 1,
203 ArrayRef<StringRef> generatedNames = {})
205 symbolCache(symbolCache), statistics(stats) {}
209 SymbolHandler &symbolCache;
210 PatternStatistics &statistics;
213class MemWritePortEnableAndMaskCanonicalizer
214 :
public SymOpRewritePattern<MemoryWritePortOp> {
216 MemWritePortEnableAndMaskCanonicalizer(
217 MLIRContext *ctxt, SymbolHandler &symbolCache,
Namespace &names,
218 PatternStatistics &stats, DenseMap<StringAttr, StringAttr> &arcMapping)
219 : SymOpRewritePattern<MemoryWritePortOp>(
ctxt, symbolCache, names, stats),
220 arcMapping(arcMapping) {}
221 LogicalResult matchAndRewrite(MemoryWritePortOp op,
222 PatternRewriter &rewriter)
const final;
225 DenseMap<StringAttr, StringAttr> &arcMapping;
228struct CallPassthroughArc :
public SymOpRewritePattern<CallOp> {
229 using SymOpRewritePattern::SymOpRewritePattern;
230 LogicalResult matchAndRewrite(CallOp op,
231 PatternRewriter &rewriter)
const final;
234struct RemoveUnusedArcs :
public SymOpRewritePattern<DefineOp> {
235 using SymOpRewritePattern::SymOpRewritePattern;
236 LogicalResult matchAndRewrite(DefineOp op,
237 PatternRewriter &rewriter)
const final;
241 using OpRewritePattern::OpRewritePattern;
242 LogicalResult matchAndRewrite(comb::ICmpOp op,
243 PatternRewriter &rewriter)
const final;
247 using OpRewritePattern::OpRewritePattern;
249 PatternRewriter &rewriter)
const final;
252struct RemoveUnusedArcArgumentsPattern :
public SymOpRewritePattern<DefineOp> {
253 using SymOpRewritePattern::SymOpRewritePattern;
254 LogicalResult matchAndRewrite(DefineOp op,
255 PatternRewriter &rewriter)
const final;
258struct SinkArcInputsPattern :
public SymOpRewritePattern<DefineOp> {
259 using SymOpRewritePattern::SymOpRewritePattern;
260 LogicalResult matchAndRewrite(DefineOp op,
261 PatternRewriter &rewriter)
const final;
265 using OpRewritePattern::OpRewritePattern;
266 LogicalResult matchAndRewrite(VectorizeOp op,
267 PatternRewriter &rewriter)
const final;
271 using OpRewritePattern::OpRewritePattern;
272 LogicalResult matchAndRewrite(VectorizeOp op,
273 PatternRewriter &rewriter)
const final;
283 SymbolHandler &symbolCache,
284 PatternRewriter &rewriter) {
285 auto defOp = cast<DefineOp>(symbolCache.getDefinition(
286 llvm::cast<SymbolRefAttr>(callOp.getCallableForCallee())
287 .getLeafReference()));
288 if (defOp.isPassthrough()) {
289 symbolCache.removeUser(defOp, callOp);
290 rewriter.replaceOp(callOp, callOp.getArgOperands());
297 const SmallVector<Value> &newOperands) {
299 unsigned groupSize = vecOp.getResults().size();
300 unsigned numOfGroups = newOperands.size() / groupSize;
301 SmallVector<int32_t> newAttr(numOfGroups, groupSize);
302 vecOp.setInputOperandSegments(newAttr);
303 vecOp.getOperation()->setOperands(ValueRange(newOperands));
311LogicalResult MemWritePortEnableAndMaskCanonicalizer::matchAndRewrite(
312 MemoryWritePortOp op, PatternRewriter &rewriter)
const {
313 auto defOp = cast<DefineOp>(symbolCache.getDefinition(op.getArcAttr()));
316 if (op.getEnable() &&
318 defOp.getBodyBlock().getTerminator()->getOperand(op.getEnableIdx()),
319 mlir::m_ConstantInt(&enable))) {
320 if (enable.isZero()) {
321 symbolCache.removeUser(defOp, op);
322 rewriter.eraseOp(op);
323 if (symbolCache.useEmpty(defOp)) {
324 symbolCache.removeDefinitionAndAllUsers(defOp);
325 rewriter.eraseOp(defOp);
329 if (enable.isAllOnes()) {
330 if (arcMapping.count(defOp.getNameAttr())) {
331 auto arcWithoutEnable = arcMapping[defOp.getNameAttr()];
333 rewriter.modifyOpInPlace(op, [&]() {
335 op.setArc(arcWithoutEnable.getValue());
337 symbolCache.removeUser(defOp, op);
338 symbolCache.addUser(symbolCache.getDefinition(arcWithoutEnable), op);
342 auto newName = names.newName(defOp.getName());
343 auto users = SmallVector<Operation *>(symbolCache.getUsers(defOp));
344 symbolCache.removeDefinitionAndAllUsers(defOp);
347 rewriter.modifyOpInPlace(op, [&]() {
352 auto newResultTypes = op.getArcResultTypes();
355 rewriter.setInsertionPoint(defOp);
356 auto newDefOp = rewriter.cloneWithoutRegions(defOp);
357 auto *block = rewriter.createBlock(
358 &newDefOp.getBody(), newDefOp.getBody().end(),
359 newDefOp.getArgumentTypes(),
360 SmallVector<Location>(newDefOp.getNumArguments(), defOp.getLoc()));
361 auto callOp = rewriter.create<CallOp>(newDefOp.getLoc(), newResultTypes,
362 newName, block->getArguments());
363 SmallVector<Value> results(callOp->getResults());
365 newDefOp.getLoc(), rewriter.getI1Type(), 1);
366 results.insert(results.begin() + op.getEnableIdx(), constTrue);
367 rewriter.
create<OutputOp>(newDefOp.getLoc(), results);
370 auto *terminator = defOp.getBodyBlock().getTerminator();
371 rewriter.modifyOpInPlace(
372 terminator, [&]() { terminator->eraseOperand(op.getEnableIdx()); });
373 rewriter.modifyOpInPlace(defOp, [&]() {
374 defOp.setName(newName);
375 defOp.setFunctionType(
376 rewriter.getFunctionType(defOp.getArgumentTypes(), newResultTypes));
380 symbolCache.addDefinition(defOp.getNameAttr(), defOp);
381 symbolCache.addDefinition(newDefOp.getNameAttr(), newDefOp);
382 symbolCache.addUser(defOp, callOp);
383 for (
auto *user : users)
384 symbolCache.addUser(user == op ? defOp : newDefOp, user);
386 arcMapping[newDefOp.getNameAttr()] = defOp.getNameAttr();
394CallPassthroughArc::matchAndRewrite(CallOp op,
395 PatternRewriter &rewriter)
const {
400RemoveUnusedArcs::matchAndRewrite(DefineOp op,
401 PatternRewriter &rewriter)
const {
402 if (symbolCache.useEmpty(op)) {
403 op.getBody().walk([&](mlir::CallOpInterface user) {
404 if (
auto symbol = dyn_cast<SymbolRefAttr>(user.getCallableForCallee()))
405 if (
auto *defOp = symbolCache.getDefinition(symbol.getLeafReference()))
406 symbolCache.removeUser(defOp, user);
408 symbolCache.removeDefinitionAndAllUsers(op);
409 rewriter.eraseOp(op);
416ICMPCanonicalizer::matchAndRewrite(comb::ICmpOp op,
417 PatternRewriter &rewriter)
const {
418 auto getConstant = [&](
const APInt &constant) -> Value {
421 auto sameWidthIntegers = [](TypeRange types) -> std::optional<unsigned> {
422 if (llvm::all_equal(types) && !types.empty())
423 if (
auto intType = dyn_cast<IntegerType>(*types.begin()))
424 return intType.getWidth();
427 auto negate = [&](Value input) -> Value {
434 if (matchPattern(op.getRhs(), mlir::m_ConstantInt(&rhs))) {
435 if (
auto concatOp = op.getLhs().getDefiningOp<
comb::ConcatOp>()) {
436 if (
auto optionalWidth =
437 sameWidthIntegers(concatOp->getOperands().getTypes())) {
438 if ((op.getPredicate() == comb::ICmpPredicate::eq ||
439 op.getPredicate() == comb::ICmpPredicate::ne) &&
442 op.getLoc(), concatOp.getInputs(), op.getTwoState());
443 if (*optionalWidth == 1) {
444 if (op.getPredicate() == comb::ICmpPredicate::ne)
445 andOp = negate(andOp);
446 rewriter.replaceOp(op, andOp);
449 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
450 op, op.getPredicate(), andOp,
451 getConstant(APInt(*optionalWidth, rhs.getZExtValue(),
457 if ((op.getPredicate() == comb::ICmpPredicate::ne ||
458 op.getPredicate() == comb::ICmpPredicate::eq) &&
461 op.getLoc(), concatOp.getInputs(), op.getTwoState());
462 if (*optionalWidth == 1) {
463 if (op.getPredicate() == comb::ICmpPredicate::eq)
465 rewriter.replaceOp(op, orOp);
468 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
469 op, op.getPredicate(), orOp,
470 getConstant(APInt(*optionalWidth, rhs.getZExtValue(),
481LogicalResult RemoveUnusedArcArgumentsPattern::matchAndRewrite(
482 DefineOp op, PatternRewriter &rewriter)
const {
483 BitVector toDelete(op.getNumArguments());
484 for (
auto [i, arg] :
llvm::enumerate(op.getArguments()))
494 SmallVector<mlir::CallOpInterface> mutableUsers;
495 for (
auto *user : symbolCache.getUsers(op)) {
496 auto callOpMutable = dyn_cast<mlir::CallOpInterface>(user);
499 mutableUsers.push_back(callOpMutable);
503 for (
auto user : mutableUsers)
504 for (int i = toDelete.size() - 1; i >= 0; --i)
506 user.getArgOperandsMutable().erase(i);
508 if (failed(op.eraseArguments(toDelete)))
511 rewriter.getFunctionType(op.getArgumentTypes(), op.getResultTypes()));
513 statistics.removeUnusedArcArgumentsPatternNumArgsRemoved += toDelete.count();
518SinkArcInputsPattern::matchAndRewrite(DefineOp op,
519 PatternRewriter &rewriter)
const {
522 auto users = symbolCache.getUsers(op);
524 users, [](
auto *user) {
return !isa<mlir::CallOpInterface>(user); }))
528 SmallVector<Operation *> stateConsts(op.getNumArguments());
530 for (
auto *user : users) {
531 auto callOp = cast<mlir::CallOpInterface>(user);
532 for (
auto [constArg, input] :
533 llvm::zip(stateConsts, callOp.getArgOperands())) {
534 if (
auto *constOp = input.getDefiningOp();
535 constOp && constOp->template hasTrait<OpTrait::ConstantLike>()) {
541 constArg->getName() == input.getDefiningOp()->getName() &&
542 constArg->getAttrDictionary() ==
543 input.getDefiningOp()->getAttrDictionary())
552 rewriter.setInsertionPointToStart(&op.getBodyBlock());
553 llvm::BitVector toDelete(op.getBodyBlock().getNumArguments());
554 for (
auto [constArg, arg] :
llvm::zip(stateConsts, op.getArguments())) {
557 auto *inlinedConst = rewriter.clone(*constArg);
558 rewriter.replaceAllUsesWith(arg, inlinedConst->getResult(0));
559 toDelete.set(arg.getArgNumber());
561 op.getBodyBlock().eraseArguments(toDelete);
562 op.setType(rewriter.getFunctionType(op.getBodyBlock().getArgumentTypes(),
563 op.getResultTypes()));
566 for (
auto *user : users) {
567 auto callOp = cast<mlir::CallOpInterface>(user);
568 SmallPtrSet<Value, 4> maybeUnusedValues;
569 SmallVector<Value> newInputs;
570 for (
auto [index, value] :
llvm::enumerate(callOp.getArgOperands())) {
572 maybeUnusedValues.insert(value);
574 newInputs.push_back(value);
576 rewriter.modifyOpInPlace(
577 callOp, [&]() { callOp.getArgOperandsMutable().assign(newInputs); });
578 for (
auto value : maybeUnusedValues)
579 if (value.use_empty())
580 rewriter.eraseOp(value.getDefiningOp());
583 return success(toDelete.any());
588 PatternRewriter &rewriter)
const {
594 if (mlir::matchPattern(op.getResetValue(), mlir::m_ConstantInt(&constant)))
595 if (constant.isZero())
599 op->getLoc(), op.getReset(), op.getResetValue(), op.getInput());
600 rewriter.modifyOpInPlace(op, [&]() {
601 op.getInputMutable().set(newInput);
602 op.getResetMutable().clear();
603 op.getResetValueMutable().clear();
610MergeVectorizeOps::matchAndRewrite(VectorizeOp vecOp,
611 PatternRewriter &rewriter)
const {
612 auto ¤tBlock = vecOp.getBody().front();
613 IRMapping argMapping;
614 SmallVector<Value> newOperands;
615 SmallVector<VectorizeOp> vecOpsToRemove;
616 bool canBeMerged =
false;
618 unsigned paddedBy = 0;
620 for (
unsigned argIdx = 0, numArgs = vecOp.getInputs().size();
621 argIdx < numArgs; ++argIdx) {
622 auto inputVec = vecOp.getInputs()[argIdx];
626 auto otherVecOp = inputVec[0].getDefiningOp<VectorizeOp>();
627 if (!otherVecOp || otherVecOp == vecOp ||
628 !llvm::all_of(otherVecOp.getResults(),
629 [](
auto result) {
return result.hasOneUse(); }) ||
630 !llvm::all_of(inputVec, [&](
auto result) {
631 return result.template getDefiningOp<VectorizeOp>() == otherVecOp;
633 newOperands.insert(newOperands.end(), inputVec.begin(), inputVec.end());
640 DenseMap<Value, size_t> resultIdxMap;
641 for (
auto [resultIdx, result] :
llvm::enumerate(otherVecOp.getResults()))
642 resultIdxMap[result] = resultIdx;
644 SmallVector<Value> tempVec(inputVec.begin(), inputVec.end());
645 llvm::sort(tempVec, [&](Value a, Value b) {
646 return resultIdxMap[a] < resultIdxMap[b];
650 if (tempVec != SmallVector<Value>(otherVecOp.getResults().begin(),
651 otherVecOp.getResults().end())) {
652 newOperands.insert(newOperands.end(), inputVec.begin(), inputVec.end());
656 DenseMap<size_t, size_t> fromRealIdxToSortedIdx;
657 for (
auto [inIdx, in] :
llvm::enumerate(inputVec))
658 fromRealIdxToSortedIdx[inIdx] = resultIdxMap[in];
665 if (inputVec != otherVecOp.getResults()) {
666 for (
auto otherVecOpInputVec : otherVecOp.getInputs()) {
668 tempVec = SmallVector<Value>(inputVec.size());
669 for (
auto [realIdx, opernad] :
llvm::enumerate(otherVecOpInputVec))
671 otherVecOpInputVec[fromRealIdxToSortedIdx[realIdx]];
673 newOperands.insert(newOperands.end(), tempVec.begin(), tempVec.end());
677 newOperands.insert(newOperands.end(), otherVecOp.getOperands().begin(),
678 otherVecOp.getOperands().end());
680 auto &otherBlock = otherVecOp.getBody().front();
681 for (
auto &otherArg : otherBlock.getArguments()) {
682 auto newArg = currentBlock.insertArgument(
683 argIdx + paddedBy, otherArg.getType(), otherArg.getLoc());
684 argMapping.map(otherArg, newArg);
688 rewriter.setInsertionPointToStart(¤tBlock);
689 for (
auto &op : otherBlock.without_terminator())
690 rewriter.clone(op, argMapping);
692 unsigned argNewPos = paddedBy + argIdx;
695 auto retOp = cast<VectorizeReturnOp>(otherBlock.getTerminator());
696 rewriter.replaceAllUsesWith(currentBlock.getArgument(argNewPos),
697 argMapping.lookupOrDefault(retOp.getValue()));
698 currentBlock.eraseArgument(argNewPos);
699 vecOpsToRemove.push_back(otherVecOp);
711 for (
auto deadOp : vecOpsToRemove)
712 rewriter.eraseOp(deadOp);
718static unsigned hashValue(
const SmallVector<Value> &inputs) {
720 for (
auto input : inputs)
721 hash = hash_combine(hash, input);
718static unsigned hashValue(
const SmallVector<Value> &inputs) {
…}
728 return SmallVector<Value>();
732 return SmallVector<Value>();
739 static bool isEqual(
const SmallVector<Value> &lhs,
740 const SmallVector<Value> &rhs) {
739 static bool isEqual(
const SmallVector<Value> &lhs, {
…}
746LogicalResult KeepOneVecOp::matchAndRewrite(VectorizeOp vecOp,
747 PatternRewriter &rewriter)
const {
748 DenseMap<SmallVector<Value>,
unsigned> inExists;
749 auto ¤tBlock = vecOp.getBody().front();
750 SmallVector<Value> newOperands;
751 BitVector argsToRemove(vecOp.getInputs().size(),
false);
752 for (
size_t argIdx = 0; argIdx < vecOp.getInputs().size(); ++argIdx) {
753 auto input = SmallVector<Value>(vecOp.getInputs()[argIdx].begin(),
754 vecOp.getInputs()[argIdx].end());
755 if (
auto in = inExists.find(input); in != inExists.end()) {
756 rewriter.replaceAllUsesWith(currentBlock.getArgument(argIdx),
757 currentBlock.getArgument(in->second));
758 argsToRemove.set(argIdx);
761 inExists[input] = argIdx;
762 newOperands.insert(newOperands.end(), input.begin(), input.end());
765 if (argsToRemove.none())
768 currentBlock.eraseArguments(argsToRemove);
777struct ArcCanonicalizerPass
778 :
public arc::impl::ArcCanonicalizerBase<ArcCanonicalizerPass> {
779 void runOnOperation()
override;
783void ArcCanonicalizerPass::runOnOperation() {
784 MLIRContext &
ctxt = getContext();
785 SymbolTableCollection symbolTable;
787 cache.addDefinitions(getOperation());
788 cache.collectAllSymbolUses(getOperation(), symbolTable);
791 DenseMap<StringAttr, StringAttr> arcMapping;
793 mlir::GreedyRewriteConfig config;
794 config.setRegionSimplificationLevel(
795 mlir::GreedySimplifyRegionLevel::Disabled);
796 config.setMaxIterations(10);
797 config.setUseTopDownTraversal(
true);
798 ArcListener listener(&cache);
799 config.setListener(&listener);
801 PatternStatistics statistics;
802 RewritePatternSet symbolPatterns(&getContext());
803 symbolPatterns.add<CallPassthroughArc, RemoveUnusedArcs,
804 RemoveUnusedArcArgumentsPattern, SinkArcInputsPattern>(
805 &getContext(), cache, names, statistics);
806 symbolPatterns.add<MemWritePortEnableAndMaskCanonicalizer>(
807 &getContext(), cache, names, statistics, arcMapping);
809 if (failed(mlir::applyPatternsGreedily(getOperation(),
810 std::move(symbolPatterns), config)))
811 return signalPassFailure();
813 numArcArgsRemoved = statistics.removeUnusedArcArgumentsPatternNumArgsRemoved;
816 for (
auto *dialect :
ctxt.getLoadedDialects())
817 dialect->getCanonicalizationPatterns(
patterns);
818 for (mlir::RegisteredOperationName op :
ctxt.getRegisteredOperations())
820 patterns.add<ICMPCanonicalizer, CompRegCanonicalizer, MergeVectorizeOps,
821 KeepOneVecOp>(&getContext());
824 (void)mlir::applyPatternsGreedily(getOperation(), std::move(
patterns),
829 return std::make_unique<ArcCanonicalizerPass>();
LogicalResult canonicalizePassthoughCall(mlir::CallOpInterface callOp, SymbolHandler &symbolCache, PatternRewriter &rewriter)
LogicalResult updateInputOperands(VectorizeOp &vecOp, const SmallVector< Value > &newOperands)
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.
void add(mlir::ModuleOp module)
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
SymbolCacheBase::Iterator end() override
std::unique_ptr< mlir::Pass > createArcCanonicalizerPass()
static llvm::hash_code hash_value(const ModulePort &port)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
static unsigned hashValue(const SmallVector< Value > &inputs)
static SmallVector< Value > getTombstoneKey()
static SmallVector< Value > getEmptyKey()
static bool isEqual(const SmallVector< Value > &lhs, const SmallVector< Value > &rhs)
static unsigned getHashValue(const SmallVector< Value > &inputs)