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>();
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())) {
92 if (inst.getPortDirection(idx) != Direction::Out) {
93 auto w = WireOp::create(builder, 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 GenericIntrinsicOp::create(builder, Type(),
119 op.getIntrinsicAttr(), inputs,
122 }
else if (outputs.size() == 1) {
124 auto resultType = outputs.front().element.type;
125 auto intop = GenericIntrinsicOp::create(builder, resultType,
126 op.getIntrinsicAttr(), inputs,
128 outputs.front().result.replaceAllUsesWith(intop.getResult());
132 auto resultType = builder.getType<BundleType>(llvm::map_to_vector(
133 outputs, [](
const auto &info) {
return info.element; }));
134 auto intop = GenericIntrinsicOp::create(builder, resultType,
135 op.getIntrinsicAttr(), inputs,
137 for (
auto &output : outputs)
138 output.result.replaceAllUsesWith(SubfieldOp::create(
139 builder, intop.getResult(), output.element.name));
153 if (fixupEICGWrapper) {
154 constexpr StringRef eicgName =
"EICG_wrapper";
156 llvm::make_early_inc_range(getOperation().getOps<FExtModuleOp>())) {
157 if (op.getDefname() != eicgName)
164 if (!warnEICGwrapperDropsDedupAnno) {
166 <<
" on EICG_wrapper is dropped";
167 warnEICGwrapperDropsDedupAnno =
true;
171 return signalPassFailure();
173 auto *node = ig.lookup(op);
175 for (
auto *use :
llvm::make_early_inc_range(node->uses())) {
176 auto inst = use->getInstance<InstanceOp>();
178 return signalPassFailure();
180 ImplicitLocOpBuilder builder(op.getLoc(), inst);
181 auto replaceResults = [](OpBuilder &b,
auto &&range) {
182 return llvm::map_to_vector(range, [&b](
auto v) {
183 auto w = WireOp::create(b, v.getLoc(), v.getType()).getResult();
184 v.replaceAllUsesWith(w);
189 auto inputs = replaceResults(builder, inst.getResults().drop_back());
191 if (inputs.size() > 2) {
192 auto port1 = inst.getPortName(1);
193 auto port2 = inst.getPortName(2);
194 if (port1 !=
"test_en") {
195 mlir::emitError(op.getPortLocation(1),
196 "expected port named 'test_en'");
197 return signalPassFailure();
198 }
else if (port2 !=
"en") {
199 mlir::emitError(op.getPortLocation(2),
"expected port named 'en'");
200 return signalPassFailure();
202 std::swap(inputs[1], inputs[2]);
204 auto intop = GenericIntrinsicOp::create(
205 builder, builder.getType<ClockType>(),
"circt_clock_gate", inputs,
207 inst.getResults().back().replaceAllUsesWith(intop.getResult());
219 markAnalysesPreserved<InstanceGraph>();
222 markAllAnalysesPreserved();
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.
constexpr const char * dedupGroupAnnoClass
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.