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<DomainAnyRefCastOp>([&](DomainAnyRefCastOp op) {
81 if (shouldStripType(op.getInput().getType())) {
82 if (!op->use_empty()) {
83 OpBuilder builder(op);
84 op.replaceAllUsesWith(
85 UnknownValueOp::create(builder, op.getLoc(), op.getType())
86 .getResult());
87 }
88 op.erase();
89 }
90 return WalkResult::advance();
91 })
92 .Case<UnsafeDomainCastOp>([&](UnsafeDomainCastOp op) {
93 // Strip cast if any of the domains being cast should be
94 // stripped.
95 if (llvm::any_of(op.getDomains(), [&](Value domain) {
96 return shouldStripType(domain.getType());
97 })) {
98 op.replaceAllUsesWith(op.getInput());
99 op.erase();
100 }
101 return WalkResult::advance();
102 })
103 .Case<WireOp>([&](WireOp op) {
104 // Erase wires of DomainType that should be stripped.
105 if (shouldStripType(op.getType(0))) {
106 op->erase();
107 return WalkResult::advance();
108 }
109 BitVector erasures(op.getDomains().size());
110
111 // Erase domain operands from regular wires.
112 for (int i = 0, e = op.getDomains().size(); i < e; ++i)
113 if (shouldStripType(op.getDomains()[i].getType()))
114 erasures.set(i);
115
116 op->eraseOperands(erasures);
117 return WalkResult::advance();
118 })
119 .Case<FInstanceLike>([&](auto op) {
120 auto n = op.getNumPorts();
121 BitVector erasures(n);
122 for (size_t i = 0; i < n; ++i)
123 if (shouldStripType(op->getResult(i).getType()))
124 erasures.set(i);
125 if (erasures.any()) {
126 op.cloneWithErasedPortsAndReplaceUses(erasures);
127 op.erase();
128 }
129 return WalkResult::advance();
130 })
131 .Default([&](Operation *op) {
132 // All operations that can have DomainType are handled
133 // above. If we encounter one here, it's a bug in the IR
134 // or this pass.
135 for (auto type :
136 concat<Type>(op->getOperandTypes(), op->getResultTypes())) {
137 if (isa<DomainType>(type)) {
138 op->emitOpError("cannot be stripped");
139 return WalkResult::interrupt();
140 }
141 }
142 return WalkResult::advance();
143 });
144 });
145 return failure(result.wasInterrupted());
146}
147
149 CircuitOp circuit, llvm::function_ref<bool(StringAttr)> shouldStripDomain) {
150 // Collect modules and erase matching DomainOp declarations.
151 llvm::SmallVector<FModuleLike> modules;
152 for (Operation &op : make_early_inc_range(*circuit.getBodyBlock())) {
153 TypeSwitch<Operation *, void>(&op)
154 .Case<FModuleLike>([&](FModuleLike op) { modules.push_back(op); })
155 .Case<DomainOp>([&](DomainOp op) {
156 // Erase domain declaration if its name should be stripped.
157 if (shouldStripDomain(op.getNameAttr()))
158 op.erase();
159 });
160 }
161
162 // Strip domains from all modules in parallel.
163 return failableParallelForEach(
164 circuit.getContext(), modules, [&](FModuleLike module) {
165 return stripModuleImpl(module, shouldStripDomain);
166 });
167}
168
169namespace {
170struct StripDomainsPass : public impl::StripDomainsBase<StripDomainsPass> {
171 void runOnOperation() override {
172 if (failed(stripDomainsFromCircuit(getOperation(),
173 [](StringAttr) { return true; })))
174 signalPassFailure();
175 }
176};
177} // namespace
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
Definition CalyxOps.cpp:555
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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.