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";
60 ValueRange domains = {}) {
61 auto wire = WireOp::create(builder, result.getType(), StringRef{},
62 NameKindEnum::DroppableName,
63 ArrayRef<Attribute>{},
67 result.replaceAllUsesWith(wire);
72 SmallVectorImpl<Value> &inputs) {
73 if (inputs.size() <= 2)
76 auto port1 = inst.getPortName(1);
77 auto port2 = inst.getPortName(2);
78 if (port1 !=
"test_en")
79 return mlir::emitError(op.getPortLocation(1),
80 "expected port named 'test_en'");
82 return mlir::emitError(op.getPortLocation(2),
"expected port named 'en'");
83 std::swap(inputs[1], inputs[2]);
89 ImplicitLocOpBuilder builder(op.getLoc(), inst);
91 SmallVector<Value> inputs;
92 for (
auto result : inst.getResults().drop_back())
99 auto intop = GenericIntrinsicOp::create(builder, builder.getType<ClockType>(),
100 "circt_clock_gate", inputs,
102 inst.getResults().back().replaceAllUsesWith(intop.getResult());
108 ImplicitLocOpBuilder builder(op.getLoc(), inst);
110 auto numPorts = op.getNumPorts();
111 unsigned numDataInputs = numPorts - 3;
112 unsigned outIdx = numDataInputs;
119 SmallVector<Value> inputs;
120 for (
unsigned i = 0; i != numDataInputs; ++i)
128 auto intop = GenericIntrinsicOp::create(builder, builder.getType<ClockType>(),
129 "circt_clock_gate", inputs,
131 auto cast = UnsafeDomainCastOp::create(builder, out.getType(),
132 intop.getResult(), ValueRange{domB})
134 MatchingConnectOp::create(builder, out, cast);
139void LowerIntmodulesPass::runOnOperation() {
140 auto &ig = getAnalysis<InstanceGraph>();
142 bool changed =
false;
143 bool warnEICGwrapperDropsDedupAnno =
false;
147 llvm::make_early_inc_range(getOperation().getOps<FIntModuleOp>())) {
148 auto *node = ig.lookup(op);
152 return signalPassFailure();
154 for (
auto *use :
llvm::make_early_inc_range(node->uses())) {
155 auto inst = use->getInstance<InstanceOp>();
158 assert(inst &&
"intmodule must be instantiated with instance op");
161 return signalPassFailure();
165 ImplicitLocOpBuilder builder(op.getLoc(), inst);
167 SmallVector<Value> inputs;
170 BundleType::BundleElement element;
172 SmallVector<OutputInfo> outputs;
173 for (
auto [idx, result] :
llvm::enumerate(inst.getResults())) {
175 if (inst.getPortDirection(idx) != Direction::Out) {
176 auto w = WireOp::create(builder, result.getLoc(), result.getType())
178 result.replaceAllUsesWith(w);
185 auto ftype = dyn_cast<FIRRTLBaseType>(inst.getType(idx));
187 inst.emitError(
"intrinsic has non-FIRRTL or non-base port type")
188 << inst.getType(idx);
193 OutputInfo{inst.getResult(idx),
194 BundleType::BundleElement(inst.getPortNameAttr(idx),
199 if (outputs.empty()) {
201 GenericIntrinsicOp::create(builder, Type(),
202 op.getIntrinsicAttr(), inputs,
205 }
else if (outputs.size() == 1) {
207 auto resultType = outputs.front().element.type;
208 auto intop = GenericIntrinsicOp::create(builder, resultType,
209 op.getIntrinsicAttr(), inputs,
211 outputs.front().result.replaceAllUsesWith(intop.getResult());
215 auto resultType = builder.getType<BundleType>(llvm::map_to_vector(
216 outputs, [](
const auto &info) {
return info.element; }));
217 auto intop = GenericIntrinsicOp::create(builder, resultType,
218 op.getIntrinsicAttr(), inputs,
220 for (
auto &output : outputs)
221 output.result.replaceAllUsesWith(SubfieldOp::create(
222 builder, intop.getResult(), output.element.name));
239 if (fixupEICGWrapper) {
240 constexpr StringRef eicgName =
"EICG_wrapper";
242 llvm::make_early_inc_range(getOperation().getOps<FExtModuleOp>())) {
243 if (op.getDefname() != eicgName)
250 if (!warnEICGwrapperDropsDedupAnno) {
251 op.emitWarning() <<
"Annotation " << firrtl::dedupGroupAnnoClass
252 <<
" on EICG_wrapper is dropped";
253 warnEICGwrapperDropsDedupAnno =
true;
257 return signalPassFailure();
264 auto numPorts = op.getNumPorts();
265 bool hasDomainPorts =
266 numPorts >= 2 && isa<DomainType>(op.getPortType(numPorts - 1));
268 auto *node = ig.lookup(op);
270 for (
auto *use :
llvm::make_early_inc_range(node->uses())) {
271 auto inst = use->getInstance<InstanceOp>();
273 mlir::emitError(use->getInstance()->getLoc())
274 <<
"EICG_wrapper must be instantiated with instance op, not via '"
275 << use->getInstance().getOperation()->getName() <<
"'";
276 return signalPassFailure();
279 return signalPassFailure();
283 return signalPassFailure();
295 markAnalysesPreserved<InstanceGraph>();
298 markAllAnalysesPreserved();
assert(baseType &&"element must be base type")
static Value replaceResultWithWire(ImplicitLocOpBuilder &builder, Value result, ValueRange domains={})
static LogicalResult checkModForAnnotations(FModuleLike mod, StringRef name)
static LogicalResult lowerDomainEICGWrapperInstance(FExtModuleOp op, InstanceOp inst)
static LogicalResult checkInstForAnnotations(FInstanceLike inst, StringRef name)
static LogicalResult swapEICGEnableInputs(FExtModuleOp op, InstanceOp inst, SmallVectorImpl< Value > &inputs)
static LogicalResult lowerLegacyEICGWrapperInstance(FExtModuleOp op, InstanceOp inst)
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.