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> {
34 void runOnOperation()
override;
35 SmallVector<Operation *> opsToDelete;
36 SmallPtrSet<StringAttr, 4> clockGateModuleNames;
40void StripSVPass::runOnOperation() {
41 auto mlirModule = getOperation();
43 clockGateModuleNames.clear();
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);
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();
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();
70 clockGateModuleNames.insert(extModOp.getModuleNameAttr());
71 opsToDelete.push_back(extModOp);
75 LLVM_DEBUG(llvm::dbgs() <<
"Found " << clockGateModuleNames.size()
79 mlirModule.walk([](Operation *op) {
80 auto isSVAttr = [](NamedAttribute attr) {
81 return attr.getName().getValue().starts_with(
"sv.");
83 if (llvm::any_of(op->getAttrs(), isSVAttr)) {
84 SmallVector<NamedAttribute> newAttrs;
85 newAttrs.reserve(op->getAttrs().size());
86 for (
auto attr : op->getAttrs())
88 newAttrs.push_back(attr);
89 op->setAttrs(newAttrs);
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);
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_";
107 if (macroRef.getType().isInteger(1) && isConditionMacro) {
108 OpBuilder builder(macroRef);
109 auto trueConst = hw::ConstantOp::create(builder, macroRef.getLoc(),
110 builder.getI1Type(), 1);
112 macroRef.replaceAllUsesWith(trueConst->getResult(0));
113 opsToDelete.push_back(macroRef);
117 for (
auto module : mlirModule.getOps<
hw::HWModuleOp>()) {
120 if (isa<sv::IfDefOp, sv::CoverOp, sv::CoverConcurrentOp>(&op)) {
121 opsToDelete.push_back(&op);
124 if (isa<sv::VerbatimOp, sv::AlwaysOp>(&op)) {
125 opsToDelete.push_back(&op);
130 if (
auto assign = dyn_cast<sv::AssignOp>(&op)) {
131 auto wire = assign.getDest().getDefiningOp<
sv::WireOp>();
133 assign.emitOpError(
"expected wire lhs");
134 return signalPassFailure();
136 for (Operation *user : wire->getUsers()) {
139 auto readInout = dyn_cast<sv::ReadInOutOp>(user);
141 user->emitOpError(
"has user that is not `sv.read_inout`");
142 return signalPassFailure();
144 readInout.replaceAllUsesWith(assign.getSrc());
145 opsToDelete.push_back(readInout);
147 opsToDelete.push_back(assign);
148 opsToDelete.push_back(wire);
153 if (
auto reg = dyn_cast<seq::FirRegOp>(&op)) {
154 OpBuilder builder(reg);
156 if (
reg.getIsAsync() && !asyncResetsAsSync) {
157 reg.emitOpError(
"only synchronous resets are currently supported");
158 return signalPassFailure();
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()));
172 builder,
reg.getLoc(),
reg.getType(),
reg.getNext(),
reg.getClk(),
173 reg.getNameAttr(),
reg.getReset(),
reg.getResetValue(),
174 presetValue,
reg.getInnerSymAttr());
175 reg.replaceAllUsesWith(compReg);
176 opsToDelete.push_back(reg);
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);
196 for (
auto *op : opsToDelete)
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)
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)