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