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>();
64 bool warnEICGwrapperDropsDedupAnno =
false;
68 llvm::make_early_inc_range(getOperation().getOps<FIntModuleOp>())) {
69 auto *node = ig.lookup(op);
73 return signalPassFailure();
75 for (
auto *use : llvm::make_early_inc_range(node->uses())) {
76 auto inst = use->getInstance<InstanceOp>();
78 return signalPassFailure();
82 ImplicitLocOpBuilder builder(op.getLoc(), inst);
84 SmallVector<Value> inputs;
87 BundleType::BundleElement element;
89 SmallVector<OutputInfo> outputs;
90 for (
auto [idx, result] : llvm::enumerate(inst.getResults())) {
93 auto w = builder.create<WireOp>(result.getLoc(), result.getType())
95 result.replaceAllUsesWith(w);
102 auto ftype = dyn_cast<FIRRTLBaseType>(inst.getType(idx));
104 inst.emitError(
"intrinsic has non-FIRRTL or non-base port type")
105 << inst.getType(idx);
110 OutputInfo{inst.getResult(idx),
111 BundleType::BundleElement(inst.getPortName(idx),
116 if (outputs.empty()) {
118 builder.create<GenericIntrinsicOp>(Type(),
119 op.getIntrinsicAttr(), inputs,
122 }
else if (outputs.size() == 1) {
124 auto resultType = outputs.front().element.type;
125 auto intop = builder.create<GenericIntrinsicOp>(
126 resultType, op.getIntrinsicAttr(), inputs, op.getParameters());
127 outputs.front().result.replaceAllUsesWith(intop.getResult());
131 auto resultType = builder.getType<BundleType>(llvm::map_to_vector(
132 outputs, [](
const auto &info) {
return info.element; }));
133 auto intop = builder.create<GenericIntrinsicOp>(
134 resultType, op.getIntrinsicAttr(), inputs, op.getParameters());
135 for (
auto &output : outputs)
136 output.result.replaceAllUsesWith(builder.create<SubfieldOp>(
137 intop.getResult(), output.element.name));
151 if (fixupEICGWrapper) {
152 constexpr StringRef eicgName =
"EICG_wrapper";
154 llvm::make_early_inc_range(getOperation().getOps<FExtModuleOp>())) {
155 if (op.getDefname() != eicgName)
162 if (!warnEICGwrapperDropsDedupAnno) {
164 <<
" on EICG_wrapper is dropped";
165 warnEICGwrapperDropsDedupAnno =
true;
169 return signalPassFailure();
171 auto *node = ig.lookup(op);
173 for (
auto *use : llvm::make_early_inc_range(node->uses())) {
174 auto inst = use->getInstance<InstanceOp>();
176 return signalPassFailure();
178 ImplicitLocOpBuilder builder(op.getLoc(), inst);
179 auto replaceResults = [](OpBuilder &b,
auto &&range) {
180 return llvm::map_to_vector(range, [&b](
auto v) {
181 auto w = b.create<WireOp>(v.getLoc(), v.getType()).getResult();
182 v.replaceAllUsesWith(w);
187 auto inputs = replaceResults(builder, inst.getResults().drop_back());
189 if (inputs.size() > 2) {
190 auto port1 = inst.getPortName(1);
191 auto port2 = inst.getPortName(2);
192 if (port1 !=
"test_en") {
193 mlir::emitError(op.getPortLocation(1),
194 "expected port named 'test_en'");
195 return signalPassFailure();
196 }
else if (port2 !=
"en") {
197 mlir::emitError(op.getPortLocation(2),
"expected port named 'en'");
198 return signalPassFailure();
200 std::swap(inputs[1], inputs[2]);
202 auto intop = builder.create<GenericIntrinsicOp>(
203 builder.getType<ClockType>(),
"circt_clock_gate", inputs,
205 inst.getResults().back().replaceAllUsesWith(intop.getResult());
217 markAnalysesPreserved<InstanceGraph>();
220 markAllAnalysesPreserved();
224 std::unique_ptr<mlir::Pass>
226 auto pass = std::make_unique<LowerIntmodulesPass>();
227 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.