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"
29using namespace firrtl;
36struct LowerIntmodulesPass
37 :
public circt::firrtl::impl::LowerIntmodulesBase<LowerIntmodulesPass> {
40 void runOnOperation()
override;
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";
60void 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>();
79 assert(inst &&
"intmodule must be instantiated with instance op");
82 return signalPassFailure();
86 ImplicitLocOpBuilder builder(op.getLoc(), inst);
88 SmallVector<Value> inputs;
91 BundleType::BundleElement element;
93 SmallVector<OutputInfo> outputs;
94 for (
auto [idx, result] :
llvm::enumerate(inst.getResults())) {
96 if (inst.getPortDirection(idx) != Direction::Out) {
97 auto w = WireOp::create(builder, result.getLoc(), result.getType())
99 result.replaceAllUsesWith(w);
106 auto ftype = dyn_cast<FIRRTLBaseType>(inst.getType(idx));
108 inst.emitError(
"intrinsic has non-FIRRTL or non-base port type")
109 << inst.getType(idx);
114 OutputInfo{inst.getResult(idx),
115 BundleType::BundleElement(inst.getPortNameAttr(idx),
120 if (outputs.empty()) {
122 GenericIntrinsicOp::create(builder, Type(),
123 op.getIntrinsicAttr(), inputs,
126 }
else if (outputs.size() == 1) {
128 auto resultType = outputs.front().element.type;
129 auto intop = GenericIntrinsicOp::create(builder, resultType,
130 op.getIntrinsicAttr(), inputs,
132 outputs.front().result.replaceAllUsesWith(intop.getResult());
136 auto resultType = builder.getType<BundleType>(llvm::map_to_vector(
137 outputs, [](
const auto &info) {
return info.element; }));
138 auto intop = GenericIntrinsicOp::create(builder, resultType,
139 op.getIntrinsicAttr(), inputs,
141 for (
auto &output : outputs)
142 output.result.replaceAllUsesWith(SubfieldOp::create(
143 builder, intop.getResult(), output.element.name));
157 if (fixupEICGWrapper) {
158 constexpr StringRef eicgName =
"EICG_wrapper";
160 llvm::make_early_inc_range(getOperation().getOps<FExtModuleOp>())) {
161 if (op.getDefname() != eicgName)
168 if (!warnEICGwrapperDropsDedupAnno) {
169 op.emitWarning() <<
"Annotation " << firrtl::dedupGroupAnnoClass
170 <<
" on EICG_wrapper is dropped";
171 warnEICGwrapperDropsDedupAnno =
true;
175 return signalPassFailure();
177 auto *node = ig.lookup(op);
179 for (
auto *use :
llvm::make_early_inc_range(node->uses())) {
180 auto inst = use->getInstance<InstanceOp>();
182 mlir::emitError(use->getInstance()->getLoc())
183 <<
"EICG_wrapper must be instantiated with instance op, not via '"
184 << use->getInstance().getOperation()->getName() <<
"'";
185 return signalPassFailure();
188 return signalPassFailure();
190 ImplicitLocOpBuilder builder(op.getLoc(), inst);
191 auto replaceResults = [](OpBuilder &b,
auto &&range) {
192 return llvm::map_to_vector(range, [&b](
auto v) {
193 auto w = WireOp::create(b, v.getLoc(), v.getType()).getResult();
194 v.replaceAllUsesWith(w);
199 auto inputs = replaceResults(builder, inst.getResults().drop_back());
201 if (inputs.size() > 2) {
202 auto port1 = inst.getPortName(1);
203 auto port2 = inst.getPortName(2);
204 if (port1 !=
"test_en") {
205 mlir::emitError(op.getPortLocation(1),
206 "expected port named 'test_en'");
207 return signalPassFailure();
208 }
else if (port2 !=
"en") {
209 mlir::emitError(op.getPortLocation(2),
"expected port named 'en'");
210 return signalPassFailure();
212 std::swap(inputs[1], inputs[2]);
214 auto intop = GenericIntrinsicOp::create(
215 builder, builder.getType<ClockType>(),
"circt_clock_gate", inputs,
217 inst.getResults().back().replaceAllUsesWith(intop.getResult());
229 markAnalysesPreserved<InstanceGraph>();
232 markAllAnalysesPreserved();
assert(baseType &&"element must be base type")
static LogicalResult checkModForAnnotations(FModuleLike mod, StringRef name)
static LogicalResult checkInstForAnnotations(FInstanceLike inst, StringRef name)
static InstancePath empty
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.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.