18 #include "mlir/IR/Diagnostics.h"
19 #include "mlir/Pass/Pass.h"
23 #define GEN_PASS_DEF_LOWERINTMODULES
24 #include "circt/Dialect/FIRRTL/Passes.h.inc"
28 using namespace circt;
29 using namespace firrtl;
36 struct LowerIntmodulesPass
37 :
public circt::firrtl::impl::LowerIntmodulesBase<LowerIntmodulesPass> {
38 void runOnOperation()
override;
39 using LowerIntmodulesBase::fixupEICGWrapper;
45 return mod.emitError(name)
46 <<
" cannot have annotations since it is an intrinsic";
53 return inst.emitError(name)
54 <<
" instance cannot have annotations since it is an intrinsic";
59 void LowerIntmodulesPass::runOnOperation() {
60 auto &ig = getAnalysis<InstanceGraph>();
63 bool warnEICGwrapperDropsDedupAnno =
false;
67 llvm::make_early_inc_range(getOperation().getOps<FIntModuleOp>())) {
68 auto *node = ig.lookup(op);
72 return signalPassFailure();
74 for (
auto *use : llvm::make_early_inc_range(node->uses())) {
75 auto inst = use->getInstance<InstanceOp>();
77 return signalPassFailure();
81 ImplicitLocOpBuilder builder(op.getLoc(), inst);
83 SmallVector<Value> inputs;
86 BundleType::BundleElement element;
88 SmallVector<OutputInfo> outputs;
89 for (
auto [idx, result] : llvm::enumerate(inst.getResults())) {
92 auto w = builder.create<WireOp>(result.getLoc(), result.getType())
94 result.replaceAllUsesWith(w);
101 auto ftype = dyn_cast<FIRRTLBaseType>(inst.getType(idx));
103 inst.emitError(
"intrinsic has non-FIRRTL or non-base port type")
104 << inst.getType(idx);
109 OutputInfo{inst.getResult(idx),
110 BundleType::BundleElement(inst.getPortName(idx),
115 if (outputs.empty()) {
117 builder.create<GenericIntrinsicOp>(Type(),
118 op.getIntrinsicAttr(), inputs,
121 }
else if (outputs.size() == 1) {
123 auto resultType = outputs.front().element.type;
124 auto intop = builder.create<GenericIntrinsicOp>(
125 resultType, op.getIntrinsicAttr(), inputs, op.getParameters());
126 outputs.front().result.replaceAllUsesWith(intop.getResult());
130 auto resultType = builder.getType<BundleType>(llvm::map_to_vector(
131 outputs, [](
const auto &info) {
return info.element; }));
132 auto intop = builder.create<GenericIntrinsicOp>(
133 resultType, op.getIntrinsicAttr(), inputs, op.getParameters());
134 for (
auto &output : outputs)
135 output.result.replaceAllUsesWith(builder.create<SubfieldOp>(
136 intop.getResult(), output.element.name));
150 if (fixupEICGWrapper) {
151 constexpr StringRef eicgName =
"EICG_wrapper";
153 llvm::make_early_inc_range(getOperation().getOps<FExtModuleOp>())) {
154 if (op.getDefname() != eicgName)
161 if (!warnEICGwrapperDropsDedupAnno) {
163 <<
" on EICG_wrapper is dropped";
164 warnEICGwrapperDropsDedupAnno =
true;
168 return signalPassFailure();
170 auto *node = ig.lookup(op);
172 for (
auto *use : llvm::make_early_inc_range(node->uses())) {
173 auto inst = use->getInstance<InstanceOp>();
175 return signalPassFailure();
177 ImplicitLocOpBuilder builder(op.getLoc(), inst);
178 auto replaceResults = [](OpBuilder &b,
auto &&range) {
179 return llvm::map_to_vector(range, [&b](
auto v) {
180 auto w = b.create<WireOp>(v.getLoc(), v.getType()).getResult();
181 v.replaceAllUsesWith(w);
186 auto inputs = replaceResults(builder, inst.getResults().drop_back());
188 if (inputs.size() > 2) {
189 auto port1 = inst.getPortName(1);
190 auto port2 = inst.getPortName(2);
191 if (port1 !=
"test_en") {
192 mlir::emitError(op.getPortLocation(1),
193 "expected port named 'test_en'");
194 return signalPassFailure();
195 }
else if (port2 !=
"en") {
196 mlir::emitError(op.getPortLocation(2),
"expected port named 'en'");
197 return signalPassFailure();
199 std::swap(inputs[1], inputs[2]);
201 auto intop = builder.create<GenericIntrinsicOp>(
202 builder.getType<ClockType>(),
"circt_clock_gate", inputs,
204 inst.getResults().back().replaceAllUsesWith(intop.getResult());
216 markAnalysesPreserved<InstanceGraph>();
219 markAllAnalysesPreserved();
223 std::unique_ptr<mlir::Pass>
225 auto pass = std::make_unique<LowerIntmodulesPass>();
226 pass->fixupEICGWrapper = fixupEICGWrapper;
static InstancePath empty
static LogicalResult checkModForAnnotations(FModuleLike mod, StringRef name)
static LogicalResult checkInstForAnnotations(FInstanceLike inst, StringRef name)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
std::unique_ptr< mlir::Pass > createLowerIntmodulesPass(bool fixupEICGWrapper=false)
This is the pass constructor.
constexpr const char * dedupGroupAnnoClass
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.