14#include "mlir/IR/ImplicitLocOpBuilder.h"
15#include "mlir/Pass/Pass.h"
16#include "llvm/Support/Debug.h"
19#define DEBUG_TYPE "arc-strip-sv"
23#define GEN_PASS_DEF_STRIPSV
24#include "circt/Dialect/Arc/ArcPasses.h.inc"
32struct StripSVPass :
public arc::impl::StripSVBase<StripSVPass> {
33 void runOnOperation()
override;
34 SmallVector<Operation *> opsToDelete;
35 SmallPtrSet<StringAttr, 4> clockGateModuleNames;
39void StripSVPass::runOnOperation() {
40 auto mlirModule = getOperation();
42 clockGateModuleNames.clear();
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);
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();
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();
69 clockGateModuleNames.insert(extModOp.getModuleNameAttr());
70 opsToDelete.push_back(extModOp);
74 LLVM_DEBUG(llvm::dbgs() <<
"Found " << clockGateModuleNames.size()
78 mlirModule.walk([](Operation *op) {
79 auto isSVAttr = [](NamedAttribute attr) {
80 return attr.getName().getValue().starts_with(
"sv.");
82 if (llvm::any_of(op->getAttrs(), isSVAttr)) {
83 SmallVector<NamedAttribute> newAttrs;
84 newAttrs.reserve(op->getAttrs().size());
85 for (
auto attr : op->getAttrs())
87 newAttrs.push_back(attr);
88 op->setAttrs(newAttrs);
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);
100 for (
auto module : mlirModule.getOps<
hw::HWModuleOp>()) {
103 if (isa<sv::IfDefOp, sv::CoverOp, sv::CoverConcurrentOp>(&op)) {
104 opsToDelete.push_back(&op);
107 if (isa<sv::VerbatimOp, sv::AlwaysOp>(&op)) {
108 opsToDelete.push_back(&op);
113 if (
auto assign = dyn_cast<sv::AssignOp>(&op)) {
114 auto wire = assign.getDest().getDefiningOp<
sv::WireOp>();
116 assign.emitOpError(
"expected wire lhs");
117 return signalPassFailure();
119 for (Operation *user : wire->getUsers()) {
122 auto readInout = dyn_cast<sv::ReadInOutOp>(user);
124 user->emitOpError(
"has user that is not `sv.read_inout`");
125 return signalPassFailure();
127 readInout.replaceAllUsesWith(assign.getSrc());
128 opsToDelete.push_back(readInout);
130 opsToDelete.push_back(assign);
131 opsToDelete.push_back(wire);
136 if (
auto reg = dyn_cast<seq::FirRegOp>(&op)) {
137 OpBuilder builder(reg);
142 reg.getResetValue(),
reg.getNext(),
145 next =
reg.getNext();
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()));
158 reg.getLoc(), next.getType(), next,
reg.getClk(),
reg.getNameAttr(),
159 Value{}, Value{}, presetValue,
160 reg.getInnerSymAttr());
161 reg.replaceAllUsesWith(compReg);
162 opsToDelete.push_back(reg);
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),
175 instOp.replaceAllUsesWith(gated);
176 opsToDelete.push_back(instOp);
182 for (
auto *op : opsToDelete)
187 return std::make_unique<StripSVPass>();
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
std::unique_ptr< mlir::Pass > createStripSVPass()
mlir::TypedValue< seq::ImmutableType > createConstantInitialValue(OpBuilder builder, Location loc, mlir::IntegerAttr attr)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)