18 #include "mlir/IR/Diagnostics.h"
19 #include "mlir/IR/ImplicitLocOpBuilder.h"
20 #include "mlir/Pass/Pass.h"
24 #define GEN_PASS_DEF_LOWERINTMODULES
25 #include "circt/Dialect/FIRRTL/Passes.h.inc"
29 using namespace circt;
30 using namespace firrtl;
37 struct LowerIntmodulesPass
38 :
public circt::firrtl::impl::LowerIntmodulesBase<LowerIntmodulesPass> {
39 void runOnOperation()
override;
40 using LowerIntmodulesBase::fixupEICGWrapper;
46 return mod.emitError(name)
47 <<
" cannot have annotations since it is an intrinsic";
54 return inst.emitError(name)
55 <<
" instance cannot have annotations since it is an intrinsic";
60 void LowerIntmodulesPass::runOnOperation() {
61 auto &ig = getAnalysis<InstanceGraph>();
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)
162 <<
" on EICG_wrapper is dropped";
165 return signalPassFailure();
167 auto *node = ig.lookup(op);
169 for (
auto *use : llvm::make_early_inc_range(node->uses())) {
170 auto inst = use->getInstance<InstanceOp>();
172 return signalPassFailure();
174 ImplicitLocOpBuilder builder(op.getLoc(), inst);
175 auto replaceResults = [](OpBuilder &b,
auto &&range) {
176 return llvm::map_to_vector(range, [&b](
auto v) {
177 auto w = b.create<WireOp>(v.getLoc(), v.getType()).getResult();
178 v.replaceAllUsesWith(w);
183 auto inputs = replaceResults(builder, inst.getResults().drop_back());
185 if (inputs.size() > 2) {
186 auto port1 = inst.getPortName(1);
187 auto port2 = inst.getPortName(2);
188 if (port1 !=
"test_en") {
189 mlir::emitError(op.getPortLocation(1),
190 "expected port named 'test_en'");
191 return signalPassFailure();
192 }
else if (port2 !=
"en") {
193 mlir::emitError(op.getPortLocation(2),
"expected port named 'en'");
194 return signalPassFailure();
196 std::swap(inputs[1], inputs[2]);
198 auto intop = builder.create<GenericIntrinsicOp>(
199 builder.getType<ClockType>(),
"circt_clock_gate", inputs,
201 inst.getResults().back().replaceAllUsesWith(intop.getResult());
213 markAnalysesPreserved<InstanceGraph>();
216 markAllAnalysesPreserved();
220 std::unique_ptr<mlir::Pass>
222 auto pass = std::make_unique<LowerIntmodulesPass>();
223 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.