CIRCT 23.0.0git
Loading...
Searching...
No Matches
StripSV.cpp
Go to the documentation of this file.
1//===- StripSV.cpp --------------------------------------------------------===//
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
15#include "mlir/IR/ImplicitLocOpBuilder.h"
16#include "mlir/Pass/Pass.h"
17#include "llvm/Support/Debug.h"
18#include <variant>
19
20#define DEBUG_TYPE "arc-strip-sv"
21
22namespace circt {
23namespace arc {
24#define GEN_PASS_DEF_STRIPSV
25#include "circt/Dialect/Arc/ArcPasses.h.inc"
26} // namespace arc
27} // namespace circt
28
29using namespace circt;
30using namespace arc;
31
32namespace {
33struct StripSVPass : public arc::impl::StripSVBase<StripSVPass> {
34 using Base::Base;
35 void runOnOperation() override;
36 SmallVector<Operation *> opsToDelete;
37 SmallPtrSet<StringAttr, 4> clockGateModuleNames;
38};
39} // namespace
40
41void StripSVPass::runOnOperation() {
42 auto mlirModule = getOperation();
43 opsToDelete.clear();
44 clockGateModuleNames.clear();
45
46 auto expectedClockGateInputs =
47 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(), "in"),
48 StringAttr::get(&getContext(), "test_en"),
49 StringAttr::get(&getContext(), "en")});
50 auto expectedClockGateOutputs =
51 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(), "out")});
52 auto i1Type = IntegerType::get(&getContext(), 1);
53
54 for (auto extModOp : mlirModule.getOps<hw::HWModuleExternOp>()) {
55 if (extModOp.getVerilogModuleName() == "EICG_wrapper") {
56 if (!llvm::equal(extModOp.getInputNames(), expectedClockGateInputs) ||
57 !llvm::equal(extModOp.getOutputNames(), expectedClockGateOutputs)) {
58 extModOp.emitError("clock gate module `")
59 << extModOp.getModuleName() << "` has incompatible port names "
60 << extModOp.getInputNames() << " -> " << extModOp.getOutputNames();
61 return signalPassFailure();
62 }
63 if (!llvm::equal(extModOp.getInputTypes(),
64 ArrayRef<Type>{i1Type, i1Type, i1Type}) ||
65 !llvm::equal(extModOp.getOutputTypes(), ArrayRef<Type>{i1Type})) {
66 extModOp.emitError("clock gate module `")
67 << extModOp.getModuleName() << "` has incompatible port types "
68 << extModOp.getInputTypes() << " -> " << extModOp.getOutputTypes();
69 return signalPassFailure();
70 }
71 clockGateModuleNames.insert(extModOp.getModuleNameAttr());
72 opsToDelete.push_back(extModOp);
73 continue;
74 }
75 }
76 LLVM_DEBUG(llvm::dbgs() << "Found " << clockGateModuleNames.size()
77 << " clock gates\n");
78
79 // Remove `sv.*` operation attributes.
80 mlirModule.walk([](Operation *op) {
81 auto isSVAttr = [](NamedAttribute attr) {
82 return attr.getName().getValue().starts_with("sv.");
83 };
84 if (llvm::any_of(op->getAttrs(), isSVAttr)) {
85 SmallVector<NamedAttribute> newAttrs;
86 newAttrs.reserve(op->getAttrs().size());
87 for (auto attr : op->getAttrs())
88 if (!isSVAttr(attr))
89 newAttrs.push_back(attr);
90 op->setAttrs(newAttrs);
91 }
92 });
93
94 // Remove ifdefs and verbatim.
95 for (auto verb : mlirModule.getOps<sv::VerbatimOp>())
96 opsToDelete.push_back(verb);
97 for (auto verb : mlirModule.getOps<sv::IfDefOp>())
98 opsToDelete.push_back(verb);
99 for (auto verb : mlirModule.getOps<sv::MacroDeclOp>())
100 opsToDelete.push_back(verb);
101
102 mlirModule.walk([&](sv::MacroRefExprOp macroRef) {
103 StringRef macroName = macroRef.getMacroName();
104 bool isConditionMacro = macroName == "STOP_COND_" ||
105 macroName == "PRINTF_COND_" ||
106 macroName == "ASSERT_VERBOSE_COND_";
107
108 if (macroRef.getType().isInteger(1) && isConditionMacro) {
109 OpBuilder builder(macroRef);
110 auto trueConst = hw::ConstantOp::create(builder, macroRef.getLoc(),
111 builder.getI1Type(), 1);
112
113 macroRef.replaceAllUsesWith(trueConst->getResult(0));
114 opsToDelete.push_back(macroRef);
115 }
116 });
117
118 for (auto module : mlirModule.getOps<hw::HWModuleOp>()) {
119 for (Operation &op : *module.getBodyBlock()) {
120 // Remove ifdefs and verbatim.
121 if (isa<sv::IfDefOp, sv::CoverOp, sv::CoverConcurrentOp>(&op)) {
122 opsToDelete.push_back(&op);
123 continue;
124 }
125 if (isa<sv::VerbatimOp, sv::AlwaysOp>(&op)) {
126 opsToDelete.push_back(&op);
127 continue;
128 }
129
130 // Remove wires.
131 if (auto assign = dyn_cast<sv::AssignOp>(&op)) {
132 auto wire = assign.getDest().getDefiningOp<sv::WireOp>();
133 if (!wire) {
134 assign.emitOpError("expected wire lhs");
135 return signalPassFailure();
136 }
137 for (Operation *user : wire->getUsers()) {
138 if (user == assign)
139 continue;
140 auto readInout = dyn_cast<sv::ReadInOutOp>(user);
141 if (!readInout) {
142 user->emitOpError("has user that is not `sv.read_inout`");
143 return signalPassFailure();
144 }
145 readInout.replaceAllUsesWith(assign.getSrc());
146 opsToDelete.push_back(readInout);
147 }
148 opsToDelete.push_back(assign);
149 opsToDelete.push_back(wire);
150 continue;
151 }
152
153 // Canonicalize registers.
154 if (auto reg = dyn_cast<seq::FirRegOp>(&op)) {
155 OpBuilder builder(reg);
156
157 if (reg.getIsAsync() && !asyncResetsAsSync) {
158 reg.emitOpError("only synchronous resets are currently supported");
159 return signalPassFailure();
160 }
161
162 Value presetValue;
163 // Materialize initial value, assume zero initialization as default.
164 if (reg.getPreset() && !reg.getPreset()->isZero()) {
165 assert(hw::type_isa<IntegerType>(reg.getType()) &&
166 "cannot lower non integer preset");
168 builder, reg.getLoc(),
169 IntegerAttr::get(reg.getType(), *reg.getPreset()));
170 }
171
172 Value compReg = seq::CompRegOp::create(
173 builder, reg.getLoc(), reg.getType(), reg.getNext(), reg.getClk(),
174 reg.getNameAttr(), reg.getReset(), reg.getResetValue(),
175 /*initialValue*/ presetValue, reg.getInnerSymAttr());
176 reg.replaceAllUsesWith(compReg);
177 opsToDelete.push_back(reg);
178 continue;
179 }
180
181 // Replace clock gate instances with the dedicated `seq.clock_gate` op and
182 // stub out other external modules.
183 if (auto instOp = dyn_cast<hw::InstanceOp>(&op)) {
184 auto modName = instOp.getModuleNameAttr().getAttr();
185 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
186 if (clockGateModuleNames.contains(modName)) {
187 auto gated = seq::ClockGateOp::create(
188 builder, instOp.getOperand(0), instOp.getOperand(1),
189 instOp.getOperand(2), hw::InnerSymAttr{});
190 instOp.replaceAllUsesWith(gated);
191 opsToDelete.push_back(instOp);
192 }
193 continue;
194 }
195
196 // Canonicalize has-been-reset indicators.
197 if (auto hbr = dyn_cast<verif::HasBeenResetOp>(&op)) {
198 OpBuilder builder(hbr);
199
200 if (hbr.getAsync() && !asyncResetsAsSync) {
201 hbr.emitOpError("has async reset, but only sync resets supported");
202 return signalPassFailure();
203 }
204
205 auto clock =
206 seq::ToClockOp::create(builder, hbr.getLoc(), hbr.getClock());
208 builder, hbr.getLoc(), builder.getBoolAttr(false));
209 auto one =
210 hw::ConstantOp::create(builder, hbr.getLoc(), hbr.getType(), 1);
211 auto reg = seq::CompRegOp::create(builder, hbr.getLoc(), one, clock,
212 StringAttr{}, hbr.getReset(), one,
213 initial, hw::InnerSymAttr{});
214 reg.getInputMutable().assign(reg);
215 auto notReset =
216 comb::createOrFoldNot(builder, hbr.getLoc(), hbr.getReset());
217 auto masked =
218 comb::AndOp::create(builder, hbr.getLoc(), reg, notReset, true);
219 hbr.getResult().replaceAllUsesWith(masked);
220 opsToDelete.push_back(hbr);
221 continue;
222 }
223 }
224 }
225 for (auto *op : opsToDelete)
226 op->erase();
227}
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
create(data_type, value)
Definition hw.py:433
create(cls, result_type, reset=None, reset_value=None, name=None, sym_name=None, **kwargs)
Definition seq.py:157
Definition arc.py:1
mlir::TypedValue< seq::ImmutableType > createConstantInitialValue(OpBuilder builder, Location loc, mlir::IntegerAttr attr)
Definition SeqOps.cpp:1188
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition seq.py:21
Definition sv.py:1