CIRCT 20.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 void runOnOperation() override;
34 SmallVector<Operation *> opsToDelete;
35 SmallPtrSet<StringAttr, 4> clockGateModuleNames;
36};
37} // namespace
38
39void StripSVPass::runOnOperation() {
40 auto mlirModule = getOperation();
41 opsToDelete.clear();
42 clockGateModuleNames.clear();
43
44 auto expectedClockGateInputs =
45 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(), "in"),
46 StringAttr::get(&getContext(), "test_en"),
47 StringAttr::get(&getContext(), "en")});
48 auto expectedClockGateOutputs =
49 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(), "out")});
50 auto i1Type = IntegerType::get(&getContext(), 1);
51
52 for (auto extModOp : mlirModule.getOps<hw::HWModuleExternOp>()) {
53 if (extModOp.getVerilogModuleName() == "EICG_wrapper") {
54 if (!llvm::equal(extModOp.getInputNames(), expectedClockGateInputs) ||
55 !llvm::equal(extModOp.getOutputNames(), expectedClockGateOutputs)) {
56 extModOp.emitError("clock gate module `")
57 << extModOp.getModuleName() << "` has incompatible port names "
58 << extModOp.getInputNames() << " -> " << extModOp.getOutputNames();
59 return signalPassFailure();
60 }
61 if (!llvm::equal(extModOp.getInputTypes(),
62 ArrayRef<Type>{i1Type, i1Type, i1Type}) ||
63 !llvm::equal(extModOp.getOutputTypes(), ArrayRef<Type>{i1Type})) {
64 extModOp.emitError("clock gate module `")
65 << extModOp.getModuleName() << "` has incompatible port types "
66 << extModOp.getInputTypes() << " -> " << extModOp.getOutputTypes();
67 return signalPassFailure();
68 }
69 clockGateModuleNames.insert(extModOp.getModuleNameAttr());
70 opsToDelete.push_back(extModOp);
71 continue;
72 }
73 }
74 LLVM_DEBUG(llvm::dbgs() << "Found " << clockGateModuleNames.size()
75 << " clock gates\n");
76
77 // Remove `sv.*` operation attributes.
78 mlirModule.walk([](Operation *op) {
79 auto isSVAttr = [](NamedAttribute attr) {
80 return attr.getName().getValue().starts_with("sv.");
81 };
82 if (llvm::any_of(op->getAttrs(), isSVAttr)) {
83 SmallVector<NamedAttribute> newAttrs;
84 newAttrs.reserve(op->getAttrs().size());
85 for (auto attr : op->getAttrs())
86 if (!isSVAttr(attr))
87 newAttrs.push_back(attr);
88 op->setAttrs(newAttrs);
89 }
90 });
91
92 // Remove ifdefs and verbatim.
93 for (auto verb : mlirModule.getOps<sv::VerbatimOp>())
94 opsToDelete.push_back(verb);
95 for (auto verb : mlirModule.getOps<sv::IfDefOp>())
96 opsToDelete.push_back(verb);
97 for (auto verb : mlirModule.getOps<sv::MacroDeclOp>())
98 opsToDelete.push_back(verb);
99
100 for (auto module : mlirModule.getOps<hw::HWModuleOp>()) {
101 for (Operation &op : *module.getBodyBlock()) {
102 // Remove ifdefs and verbatim.
103 if (isa<sv::IfDefOp, sv::CoverOp, sv::CoverConcurrentOp>(&op)) {
104 opsToDelete.push_back(&op);
105 continue;
106 }
107 if (isa<sv::VerbatimOp, sv::AlwaysOp>(&op)) {
108 opsToDelete.push_back(&op);
109 continue;
110 }
111
112 // Remove wires.
113 if (auto assign = dyn_cast<sv::AssignOp>(&op)) {
114 auto wire = assign.getDest().getDefiningOp<sv::WireOp>();
115 if (!wire) {
116 assign.emitOpError("expected wire lhs");
117 return signalPassFailure();
118 }
119 for (Operation *user : wire->getUsers()) {
120 if (user == assign)
121 continue;
122 auto readInout = dyn_cast<sv::ReadInOutOp>(user);
123 if (!readInout) {
124 user->emitOpError("has user that is not `sv.read_inout`");
125 return signalPassFailure();
126 }
127 readInout.replaceAllUsesWith(assign.getSrc());
128 opsToDelete.push_back(readInout);
129 }
130 opsToDelete.push_back(assign);
131 opsToDelete.push_back(wire);
132 continue;
133 }
134
135 // Canonicalize registers.
136 if (auto reg = dyn_cast<seq::FirRegOp>(&op)) {
137 OpBuilder builder(reg);
138 Value next;
139 // Note: this register will have an sync reset regardless.
140 if (reg.hasReset())
141 next = builder.create<comb::MuxOp>(reg.getLoc(), reg.getReset(),
142 reg.getResetValue(), reg.getNext(),
143 false);
144 else
145 next = reg.getNext();
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 = builder.create<seq::CompRegOp>(
158 reg.getLoc(), next.getType(), next, reg.getClk(), reg.getNameAttr(),
159 Value{}, Value{}, /*initialValue*/ presetValue,
160 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 = builder.create<seq::ClockGateOp>(
173 instOp.getOperand(0), instOp.getOperand(1), instOp.getOperand(2),
174 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() {
187 return std::make_unique<StripSVPass>();
188}
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
std::unique_ptr< mlir::Pass > createStripSVPass()
Definition StripSV.cpp:186
mlir::TypedValue< seq::ImmutableType > createConstantInitialValue(OpBuilder builder, Location loc, mlir::IntegerAttr attr)
Definition SeqOps.cpp:1065
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