CIRCT 22.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
14#include "mlir/IR/ImplicitLocOpBuilder.h"
15#include "mlir/Pass/Pass.h"
16#include "llvm/Support/Debug.h"
17#include <variant>
18
19#define DEBUG_TYPE "arc-strip-sv"
20
21namespace circt {
22namespace arc {
23#define GEN_PASS_DEF_STRIPSV
24#include "circt/Dialect/Arc/ArcPasses.h.inc"
25} // namespace arc
26} // namespace circt
27
28using namespace circt;
29using namespace arc;
30
31namespace {
32struct StripSVPass : public arc::impl::StripSVBase<StripSVPass> {
33 explicit StripSVPass(bool asyncResetsAsSync) {
34 this->asyncResetsAsSync = asyncResetsAsSync;
35 }
36 void runOnOperation() override;
37 SmallVector<Operation *> opsToDelete;
38 SmallPtrSet<StringAttr, 4> clockGateModuleNames;
39};
40} // namespace
41
42void StripSVPass::runOnOperation() {
43 auto mlirModule = getOperation();
44 opsToDelete.clear();
45 clockGateModuleNames.clear();
46
47 auto expectedClockGateInputs =
48 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(), "in"),
49 StringAttr::get(&getContext(), "test_en"),
50 StringAttr::get(&getContext(), "en")});
51 auto expectedClockGateOutputs =
52 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(), "out")});
53 auto i1Type = IntegerType::get(&getContext(), 1);
54
55 for (auto extModOp : mlirModule.getOps<hw::HWModuleExternOp>()) {
56 if (extModOp.getVerilogModuleName() == "EICG_wrapper") {
57 if (!llvm::equal(extModOp.getInputNames(), expectedClockGateInputs) ||
58 !llvm::equal(extModOp.getOutputNames(), expectedClockGateOutputs)) {
59 extModOp.emitError("clock gate module `")
60 << extModOp.getModuleName() << "` has incompatible port names "
61 << extModOp.getInputNames() << " -> " << extModOp.getOutputNames();
62 return signalPassFailure();
63 }
64 if (!llvm::equal(extModOp.getInputTypes(),
65 ArrayRef<Type>{i1Type, i1Type, i1Type}) ||
66 !llvm::equal(extModOp.getOutputTypes(), ArrayRef<Type>{i1Type})) {
67 extModOp.emitError("clock gate module `")
68 << extModOp.getModuleName() << "` has incompatible port types "
69 << extModOp.getInputTypes() << " -> " << extModOp.getOutputTypes();
70 return signalPassFailure();
71 }
72 clockGateModuleNames.insert(extModOp.getModuleNameAttr());
73 opsToDelete.push_back(extModOp);
74 continue;
75 }
76 }
77 LLVM_DEBUG(llvm::dbgs() << "Found " << clockGateModuleNames.size()
78 << " clock gates\n");
79
80 // Remove `sv.*` operation attributes.
81 mlirModule.walk([](Operation *op) {
82 auto isSVAttr = [](NamedAttribute attr) {
83 return attr.getName().getValue().starts_with("sv.");
84 };
85 if (llvm::any_of(op->getAttrs(), isSVAttr)) {
86 SmallVector<NamedAttribute> newAttrs;
87 newAttrs.reserve(op->getAttrs().size());
88 for (auto attr : op->getAttrs())
89 if (!isSVAttr(attr))
90 newAttrs.push_back(attr);
91 op->setAttrs(newAttrs);
92 }
93 });
94
95 // Remove ifdefs and verbatim.
96 for (auto verb : mlirModule.getOps<sv::VerbatimOp>())
97 opsToDelete.push_back(verb);
98 for (auto verb : mlirModule.getOps<sv::IfDefOp>())
99 opsToDelete.push_back(verb);
100 for (auto verb : mlirModule.getOps<sv::MacroDeclOp>())
101 opsToDelete.push_back(verb);
102
103 for (auto module : mlirModule.getOps<hw::HWModuleOp>()) {
104 for (Operation &op : *module.getBodyBlock()) {
105 // Remove ifdefs and verbatim.
106 if (isa<sv::IfDefOp, sv::CoverOp, sv::CoverConcurrentOp>(&op)) {
107 opsToDelete.push_back(&op);
108 continue;
109 }
110 if (isa<sv::VerbatimOp, sv::AlwaysOp>(&op)) {
111 opsToDelete.push_back(&op);
112 continue;
113 }
114
115 // Remove wires.
116 if (auto assign = dyn_cast<sv::AssignOp>(&op)) {
117 auto wire = assign.getDest().getDefiningOp<sv::WireOp>();
118 if (!wire) {
119 assign.emitOpError("expected wire lhs");
120 return signalPassFailure();
121 }
122 for (Operation *user : wire->getUsers()) {
123 if (user == assign)
124 continue;
125 auto readInout = dyn_cast<sv::ReadInOutOp>(user);
126 if (!readInout) {
127 user->emitOpError("has user that is not `sv.read_inout`");
128 return signalPassFailure();
129 }
130 readInout.replaceAllUsesWith(assign.getSrc());
131 opsToDelete.push_back(readInout);
132 }
133 opsToDelete.push_back(assign);
134 opsToDelete.push_back(wire);
135 continue;
136 }
137
138 // Canonicalize registers.
139 if (auto reg = dyn_cast<seq::FirRegOp>(&op)) {
140 OpBuilder builder(reg);
141
142 if (reg.getIsAsync() && !asyncResetsAsSync) {
143 reg.emitOpError("only synchronous resets are currently supported");
144 return signalPassFailure();
145 }
146
147 Value presetValue;
148 // Materialize initial value, assume zero initialization as default.
149 if (reg.getPreset() && !reg.getPreset()->isZero()) {
150 assert(hw::type_isa<IntegerType>(reg.getType()) &&
151 "cannot lower non integer preset");
153 builder, reg.getLoc(),
154 IntegerAttr::get(reg.getType(), *reg.getPreset()));
155 }
156
157 Value compReg = seq::CompRegOp::create(
158 builder, reg.getLoc(), reg.getType(), reg.getNext(), reg.getClk(),
159 reg.getNameAttr(), reg.getReset(), reg.getResetValue(),
160 /*initialValue*/ presetValue, reg.getInnerSymAttr());
161 reg.replaceAllUsesWith(compReg);
162 opsToDelete.push_back(reg);
163 continue;
164 }
165
166 // Replace clock gate instances with the dedicated `seq.clock_gate` op and
167 // stub out other external modules.
168 if (auto instOp = dyn_cast<hw::InstanceOp>(&op)) {
169 auto modName = instOp.getModuleNameAttr().getAttr();
170 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
171 if (clockGateModuleNames.contains(modName)) {
172 auto gated = seq::ClockGateOp::create(
173 builder, instOp.getOperand(0), instOp.getOperand(1),
174 instOp.getOperand(2), hw::InnerSymAttr{});
175 instOp.replaceAllUsesWith(gated);
176 opsToDelete.push_back(instOp);
177 }
178 continue;
179 }
180 }
181 }
182 for (auto *op : opsToDelete)
183 op->erase();
184}
185
186std::unique_ptr<Pass> arc::createStripSVPass(bool asyncResetsAsSync) {
187 return std::make_unique<StripSVPass>(asyncResetsAsSync);
188}
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
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:1159
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