Loading [MathJax]/extensions/tex2jax.js
CIRCT 22.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LowerIntmodules.cpp
Go to the documentation of this file.
1//===- LowerIntmodules.cpp - Lower intmodules to ops ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the LowerIntmodules pass. This pass processes
10// FIRRTL intmodules and replaces all instances with generic intrinsic ops.
11//
12//===----------------------------------------------------------------------===//
13
18#include "mlir/IR/Diagnostics.h"
19#include "mlir/Pass/Pass.h"
20
21namespace circt {
22namespace firrtl {
23#define GEN_PASS_DEF_LOWERINTMODULES
24#include "circt/Dialect/FIRRTL/Passes.h.inc"
25} // namespace firrtl
26} // namespace circt
27
28using namespace circt;
29using namespace firrtl;
30
31//===----------------------------------------------------------------------===//
32// Pass Infrastructure
33//===----------------------------------------------------------------------===//
34
35namespace {
36struct LowerIntmodulesPass
37 : public circt::firrtl::impl::LowerIntmodulesBase<LowerIntmodulesPass> {
38 using Base::Base;
39
40 void runOnOperation() override;
41};
42} // namespace
43
44static LogicalResult checkModForAnnotations(FModuleLike mod, StringRef name) {
45 if (!AnnotationSet(mod).empty())
46 return mod.emitError(name)
47 << " cannot have annotations since it is an intrinsic";
48 return success();
49}
50
51static LogicalResult checkInstForAnnotations(FInstanceLike inst,
52 StringRef name) {
53 if (!AnnotationSet(inst).empty())
54 return inst.emitError(name)
55 << " instance cannot have annotations since it is an intrinsic";
56 return success();
57}
58
59// This is the main entrypoint for the conversion pass.
60void LowerIntmodulesPass::runOnOperation() {
61 auto &ig = getAnalysis<InstanceGraph>();
62
63 bool changed = false;
64 bool warnEICGwrapperDropsDedupAnno = false;
65
66 // Convert to int ops.
67 for (auto op :
68 llvm::make_early_inc_range(getOperation().getOps<FIntModuleOp>())) {
69 auto *node = ig.lookup(op);
70 changed = true;
71
72 if (failed(checkModForAnnotations(op, op.getIntrinsic())))
73 return signalPassFailure();
74
75 for (auto *use : llvm::make_early_inc_range(node->uses())) {
76 auto inst = use->getInstance<InstanceOp>();
77 if (failed(checkInstForAnnotations(inst, op.getIntrinsic())))
78 return signalPassFailure();
79
80 // Replace the instance of this intmodule with firrtl.int.generic.
81 // Inputs become operands, outputs are the result (if any).
82 ImplicitLocOpBuilder builder(op.getLoc(), inst);
83
84 SmallVector<Value> inputs;
85 struct OutputInfo {
86 Value result;
87 BundleType::BundleElement element;
88 };
89 SmallVector<OutputInfo> outputs;
90 for (auto [idx, result] : llvm::enumerate(inst.getResults())) {
91 // Replace inputs with wires that will be used as operands.
92 if (inst.getPortDirection(idx) != Direction::Out) {
93 auto w = builder.create<WireOp>(result.getLoc(), result.getType())
94 .getResult();
95 result.replaceAllUsesWith(w);
96 inputs.push_back(w);
97 continue;
98 }
99
100 // Gather outputs. This will become a bundle if more than one, but
101 // typically there are zero or one.
102 auto ftype = dyn_cast<FIRRTLBaseType>(inst.getType(idx));
103 if (!ftype) {
104 inst.emitError("intrinsic has non-FIRRTL or non-base port type")
105 << inst.getType(idx);
106 signalPassFailure();
107 return;
108 }
109 outputs.push_back(
110 OutputInfo{inst.getResult(idx),
111 BundleType::BundleElement(inst.getPortName(idx),
112 /*isFlip=*/false, ftype)});
113 }
114
115 // Create the replacement operation.
116 if (outputs.empty()) {
117 // If no outputs, just create the operation.
118 builder.create<GenericIntrinsicOp>(/*result=*/Type(),
119 op.getIntrinsicAttr(), inputs,
120 op.getParameters());
121
122 } else if (outputs.size() == 1) {
123 // For single output, the result is the output.
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());
128 } else {
129 // For multiple outputs, create a bundle with fields for each output
130 // and replace users with subfields.
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));
138 }
139 // Remove instance from IR and instance graph.
140 use->erase();
141 inst.erase();
142 ++numInstances;
143 }
144 // Remove intmodule from IR and instance graph.
145 ig.erase(node);
146 op.erase();
147 ++numIntmodules;
148 }
149
150 // Special handling for magic EICG wrapper extmodule. Deprecate and remove.
151 if (fixupEICGWrapper) {
152 constexpr StringRef eicgName = "EICG_wrapper";
153 for (auto op :
154 llvm::make_early_inc_range(getOperation().getOps<FExtModuleOp>())) {
155 if (op.getDefname() != eicgName)
156 continue;
157
158 // FIXME: Dedup group annotation could be annotated to EICG_wrapper but
159 // it causes an error with `fixupEICGWrapper`. For now drop the
160 // annotation until we fully migrate into EICG intrinsic.
162 if (!warnEICGwrapperDropsDedupAnno) {
163 op.emitWarning() << "Annotation " << firrtl::dedupGroupAnnoClass
164 << " on EICG_wrapper is dropped";
165 warnEICGwrapperDropsDedupAnno = true;
166 }
167
168 if (failed(checkModForAnnotations(op, eicgName)))
169 return signalPassFailure();
170
171 auto *node = ig.lookup(op);
172 changed = true;
173 for (auto *use : llvm::make_early_inc_range(node->uses())) {
174 auto inst = use->getInstance<InstanceOp>();
175 if (failed(checkInstForAnnotations(inst, eicgName)))
176 return signalPassFailure();
177
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);
183 return w;
184 });
185 };
186
187 auto inputs = replaceResults(builder, inst.getResults().drop_back());
188 // en and test_en are swapped between extmodule and intrinsic.
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();
199 } else
200 std::swap(inputs[1], inputs[2]);
201 }
202 auto intop = builder.create<GenericIntrinsicOp>(
203 builder.getType<ClockType>(), "circt_clock_gate", inputs,
204 op.getParameters());
205 inst.getResults().back().replaceAllUsesWith(intop.getResult());
206
207 // Remove instance from IR and instance graph.
208 use->erase();
209 inst.erase();
210 }
211 // Remove extmodule from IR and instance graph.
212 ig.erase(node);
213 op.erase();
214 }
215 }
216
217 markAnalysesPreserved<InstanceGraph>();
218
219 if (!changed)
220 markAllAnalysesPreserved();
221}
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
void info(Twine message)
Definition LSPUtils.cpp:20
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.