CIRCT 24.0.0git
Loading...
Searching...
No Matches
StripDomains.cpp
Go to the documentation of this file.
1//===- StripDomains.cpp - Strip FIRRTL domains ----------------------------===//
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
10#include "mlir/IR/Iterators.h"
11#include "mlir/IR/Threading.h"
12#include "llvm/ADT/STLExtras.h"
13#include "llvm/ADT/TypeSwitch.h"
14
15namespace circt {
16namespace firrtl {
17#define GEN_PASS_DEF_STRIPDOMAINS
18#include "circt/Dialect/FIRRTL/Passes.h.inc"
19} // namespace firrtl
20} // namespace circt
21
22using namespace circt;
23using namespace firrtl;
24using llvm::concat;
25using mlir::ReverseIterator;
26
27/// A helper for stripping domains from a module based on a predicate. The
28/// predicate takes a domain name and returns true if that domain should be
29/// stripped.
30static LogicalResult
31stripModuleImpl(FModuleLike op,
32 llvm::function_ref<bool(StringAttr)> shouldStripDomain) {
33 auto shouldStripType = [&](Type type) {
34 if (auto domainType = dyn_cast<DomainType>(type))
35 return shouldStripDomain(domainType.getName().getAttr());
36 return false;
37 };
38 WalkResult result = op->walk<mlir::WalkOrder::PostOrder, ReverseIterator>(
39 [&](Operation *op) -> WalkResult {
40 return TypeSwitch<Operation *, WalkResult>(op)
41 .Case<FModuleLike>([&](FModuleLike op) {
42 BitVector erasures(op.getNumPorts());
43 for (size_t i = 0, e = op.getNumPorts(); i < e; ++i)
44 if (shouldStripType(op.getPortType(i)))
45 erasures.set(i);
46 if (erasures.any())
47 op.erasePorts(erasures);
48 return WalkResult::advance();
49 })
50 .Case<DomainDefineOp>([&](DomainDefineOp op) {
51 if (shouldStripType(op.getDest().getType()) ||
52 shouldStripType(op.getSrc().getType()))
53 op.erase();
54 return WalkResult::advance();
55 })
56 .Case<DomainCreateOp>([&](DomainCreateOp op) {
57 if (shouldStripType(op.getType()))
58 op.erase();
59 return WalkResult::advance();
60 })
61 .Case<DomainCreateAnonOp>([&](DomainCreateAnonOp op) {
62 if (shouldStripType(op.getType()))
63 op.erase();
64 return WalkResult::advance();
65 })
66 .Case<DomainSubfieldOp>([&](DomainSubfieldOp op) {
67 // The subfield's result is a property value; decide
68 // whether to strip based on the domain it reads from.
69 if (shouldStripType(op.getInput().getType())) {
70 if (!op->use_empty()) {
71 OpBuilder builder(op);
72 op.replaceAllUsesWith(
73 UnknownValueOp::create(builder, op.getLoc(), op.getType())
74 .getResult());
75 }
76 op.erase();
77 }
78 return WalkResult::advance();
79 })
80 .Case<UnsafeDomainCastOp>([&](UnsafeDomainCastOp op) {
81 // Strip cast if any of the domains being cast should be
82 // stripped.
83 if (llvm::any_of(op.getDomains(), [&](Value domain) {
84 return shouldStripType(domain.getType());
85 })) {
86 op.replaceAllUsesWith(op.getInput());
87 op.erase();
88 }
89 return WalkResult::advance();
90 })
91 .Case<WireOp>([&](WireOp op) {
92 // Erase wires of DomainType that should be stripped.
93 if (shouldStripType(op.getType(0))) {
94 op->erase();
95 return WalkResult::advance();
96 }
97 BitVector erasures(op.getDomains().size());
98
99 // Erase domain operands from regular wires.
100 for (int i = 0, e = op.getDomains().size(); i < e; ++i)
101 if (shouldStripType(op.getDomains()[i].getType()))
102 erasures.set(i);
103
104 op->eraseOperands(erasures);
105 return WalkResult::advance();
106 })
107 .Case<FInstanceLike>([&](auto op) {
108 auto n = op.getNumPorts();
109 BitVector erasures(n);
110 for (size_t i = 0; i < n; ++i)
111 if (shouldStripType(op->getResult(i).getType()))
112 erasures.set(i);
113 if (erasures.any()) {
114 op.cloneWithErasedPortsAndReplaceUses(erasures);
115 op.erase();
116 }
117 return WalkResult::advance();
118 })
119 .Default([&](Operation *op) {
120 // All operations that can have DomainType are handled
121 // above. If we encounter one here, it's a bug in the IR
122 // or this pass.
123 for (auto type :
124 concat<Type>(op->getOperandTypes(), op->getResultTypes())) {
125 if (isa<DomainType>(type)) {
126 op->emitOpError("cannot be stripped");
127 return WalkResult::interrupt();
128 }
129 }
130 return WalkResult::advance();
131 });
132 });
133 return failure(result.wasInterrupted());
134}
135
137 CircuitOp circuit, llvm::function_ref<bool(StringAttr)> shouldStripDomain) {
138 // Collect modules and erase matching DomainOp declarations.
139 llvm::SmallVector<FModuleLike> modules;
140 for (Operation &op : make_early_inc_range(*circuit.getBodyBlock())) {
141 TypeSwitch<Operation *, void>(&op)
142 .Case<FModuleLike>([&](FModuleLike op) { modules.push_back(op); })
143 .Case<DomainOp>([&](DomainOp op) {
144 // Erase domain declaration if its name should be stripped.
145 if (shouldStripDomain(op.getNameAttr()))
146 op.erase();
147 });
148 }
149
150 // Strip domains from all modules in parallel.
151 return failableParallelForEach(
152 circuit.getContext(), modules, [&](FModuleLike module) {
153 return stripModuleImpl(module, shouldStripDomain);
154 });
155}
156
157namespace {
158struct StripDomainsPass : public impl::StripDomainsBase<StripDomainsPass> {
159 void runOnOperation() override {
160 if (failed(stripDomainsFromCircuit(getOperation(),
161 [](StringAttr) { return true; })))
162 signalPassFailure();
163 }
164};
165} // namespace
static LogicalResult stripModuleImpl(FModuleLike op, llvm::function_ref< bool(StringAttr)> shouldStripDomain)
A helper for stripping domains from a module based on a predicate.
LogicalResult stripDomainsFromCircuit(CircuitOp circuit, llvm::function_ref< bool(StringAttr)> shouldStripDomain)
Strip domains whose names match the predicate from a circuit.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.