16 #include "mlir/IR/Builders.h"
17 #include "mlir/Transforms/DialectConversion.h"
18 #include "llvm/ADT/TypeSwitch.h"
19 #include "llvm/Support/Debug.h"
21 #define DEBUG_TYPE "ibis-lower-portrefs"
24 using namespace circt;
31 using OpConversionPattern::OpConversionPattern;
35 matchAndRewrite(InputPortOp op, OpAdaptor adaptor,
36 ConversionPatternRewriter &rewriter)
const override {
37 PortRefType innerPortRefType = cast<PortRefType>(op.getType());
38 Type
innerType = innerPortRefType.getPortType();
39 Direction d = innerPortRefType.getDirection();
46 auto portrefUsers = op.getResult().getUsers();
47 size_t nPortrefUsers =
48 std::distance(portrefUsers.begin(), portrefUsers.end());
49 if (nPortrefUsers != 1)
50 return rewriter.notifyMatchFailure(
51 op,
"expected a single ibis.port.read as the only user of the input "
52 "port reference, but found multiple readers - please run CSE "
53 "prior to this pass");
57 PortReadOp portUnwrapper = dyn_cast<PortReadOp>(*portrefUsers.begin());
59 return rewriter.notifyMatchFailure(
60 op,
"expected a single ibis.port.read as the only user of the input "
64 OpBuilder::InsertionGuard g(rewriter);
65 rewriter.setInsertionPoint(op);
68 auto rawOutput = rewriter.create<OutputPortOp>(
69 op.getLoc(), op.getNameAttr(), op.getInnerSym(),
innerType);
72 for (
auto *unwrappedPortUser :
73 llvm::make_early_inc_range(portUnwrapper.getResult().getUsers())) {
74 PortWriteOp portWriter = dyn_cast<PortWriteOp>(unwrappedPortUser);
75 if (!portWriter || portWriter.getPort() != portUnwrapper.getResult())
79 rewriter.replaceOpWithNewOp<PortWriteOp>(portWriter, rawOutput,
80 portWriter.getValue());
84 auto rawInput = rewriter.create<InputPortOp>(
85 op.getLoc(), op.getNameAttr(), op.getInnerSym(),
innerType);
91 portUnwrapper.getResult().replaceAllUsesWith(rawInput);
95 llvm::make_early_inc_range(portUnwrapper.getResult().getUsers())) {
96 PortReadOp portReader = dyn_cast<PortReadOp>(portUser);
97 if (!portReader || portReader.getPort() != portUnwrapper.getResult())
100 rewriter.replaceOpWithNewOp<PortReadOp>(portReader, rawInput);
105 rewriter.eraseOp(portUnwrapper);
106 rewriter.eraseOp(op);
114 using OpConversionPattern::OpConversionPattern;
118 matchAndRewrite(OutputPortOp op, OpAdaptor adaptor,
119 ConversionPatternRewriter &rewriter)
const override {
120 PortRefType innerPortRefType = cast<PortRefType>(op.getType());
121 Type
innerType = innerPortRefType.getPortType();
122 Direction d = innerPortRefType.getDirection();
126 PortWriteOp portWrapper;
127 for (
auto *user : op.getResult().getUsers()) {
128 auto writeOp = dyn_cast<PortWriteOp>(user);
129 if (writeOp && writeOp.getPort() == op.getResult()) {
131 return rewriter.notifyMatchFailure(
132 op,
"expected a single ibis.port.write to wrap the output "
133 "portref, but found multiple");
134 portWrapper = writeOp;
140 return rewriter.notifyMatchFailure(
141 op,
"expected an ibis.port.write to wrap the output portref");
143 OpBuilder::InsertionGuard g(rewriter);
144 rewriter.setInsertionPoint(op);
149 auto rawInput = rewriter.create<InputPortOp>(
150 op.getLoc(), op.getNameAttr(), op.getInnerSym(),
innerType);
151 rewriter.create<PortWriteOp>(
152 op.getLoc(), portWrapper.getValue(),
153 rewriter.create<PortReadOp>(op.getLoc(), rawInput));
157 auto rawOutput = rewriter.create<OutputPortOp>(
158 op.getLoc(), op.getNameAttr(), op.getInnerSym(),
innerType);
159 rewriter.create<PortWriteOp>(
160 op.getLoc(), rawOutput,
161 rewriter.create<PortReadOp>(op.getLoc(), portWrapper.getValue()));
165 rewriter.eraseOp(portWrapper);
166 rewriter.eraseOp(op);
173 using OpConversionPattern::OpConversionPattern;
177 matchAndRewrite(GetPortOp op, OpAdaptor adaptor,
178 ConversionPatternRewriter &rewriter)
const override {
179 PortRefType outerPortRefType = cast<PortRefType>(op.getType());
180 PortRefType innerPortRefType =
181 cast<PortRefType>(outerPortRefType.getPortType());
182 Type
innerType = innerPortRefType.getPortType();
184 Direction outerDirection = outerPortRefType.getDirection();
185 Direction innerDirection = innerPortRefType.getDirection();
187 StringAttr portName = op.getPortSymbolAttr().getAttr();
189 OpBuilder::InsertionGuard g(rewriter);
190 rewriter.setInsertionPoint(op);
195 PortWriteOp getPortWrapper;
196 for (
auto *user : op.getResult().getUsers()) {
197 auto writeOp = dyn_cast<PortWriteOp>(user);
198 if (!writeOp || writeOp.getPort() != op.getResult())
201 getPortWrapper = writeOp;
206 return rewriter.notifyMatchFailure(
207 op,
"expected an ibis.port.write to wrap the get_port result");
208 wrapper = getPortWrapper;
209 LLVM_DEBUG(llvm::dbgs() <<
"Found wrapper: " << *wrapper);
213 rewriter.create<GetPortOp>(op.getLoc(), op.getInstance(), portName,
216 rewriter.create<PortReadOp>(op.getLoc(), newGetPort);
217 rewriter.create<PortWriteOp>(op.getLoc(), getPortWrapper.getValue(),
222 rewriter.create<GetPortOp>(op.getLoc(), op.getInstance(), portName,
225 rewriter.create<PortReadOp>(op.getLoc(), getPortWrapper.getValue());
226 rewriter.create<PortWriteOp>(op.getLoc(), newGetPort, writeValue);
229 PortReadOp getPortUnwrapper;
230 for (
auto *user : op.getResult().getUsers()) {
231 auto readOp = dyn_cast<PortReadOp>(user);
232 if (!readOp || readOp.getPort() != op.getResult())
235 getPortUnwrapper = readOp;
239 if (!getPortUnwrapper)
240 return rewriter.notifyMatchFailure(
241 op,
"expected an ibis.port.read to unwrap the get_port result");
242 wrapper = getPortUnwrapper;
244 LLVM_DEBUG(llvm::dbgs() <<
"Found unwrapper: " << *wrapper);
261 PortWriteOp portDriver;
262 PortWriteOp portForwardingDriver;
263 for (
auto *user : getPortUnwrapper.getResult().getUsers()) {
264 auto writeOp = dyn_cast<PortWriteOp>(user);
268 bool isForwarding = writeOp.getPort() != getPortUnwrapper.getResult();
270 if (portForwardingDriver)
271 return rewriter.notifyMatchFailure(
272 op,
"expected a single ibis.port.write to use the unwrapped "
273 "get_port result, but found multiple");
274 portForwardingDriver = writeOp;
275 LLVM_DEBUG(llvm::dbgs()
276 <<
"Found forwarding driver: " << *portForwardingDriver);
279 return rewriter.notifyMatchFailure(
280 op,
"expected a single ibis.port.write to use the unwrapped "
281 "get_port result, but found multiple");
282 portDriver = writeOp;
283 LLVM_DEBUG(llvm::dbgs() <<
"Found driver: " << *portDriver);
287 if (!portDriver && !portForwardingDriver)
288 return rewriter.notifyMatchFailure(
289 op,
"expected an ibis.port.write to drive the unwrapped get_port "
292 Value portDriverValue;
293 if (portForwardingDriver) {
299 auto fwPortName = rewriter.getStringAttr(portName.strref() +
"_fw");
300 auto forwardedInputPort = rewriter.create<InputPortOp>(
309 getPortUnwrapper.getResult().replaceAllUsesWith(forwardedInputPort);
310 portDriverValue = rewriter.create<PortReadOp>(
311 op.getLoc(), forwardedInputPort.getPort());
315 portDriverValue = portDriver.getValue();
316 rewriter.eraseOp(portDriver);
322 rewriter.create<GetPortOp>(op.getLoc(), op.getInstance(), portName,
324 rewriter.create<PortWriteOp>(op.getLoc(), rawPort, portDriverValue);
339 rewriter.create<GetPortOp>(op.getLoc(), op.getInstance(), portName,
347 getPortUnwrapper.getResult().replaceAllUsesWith(rawPort);
352 rewriter.eraseOp(wrapper);
353 rewriter.eraseOp(op);
359 struct PortrefLoweringPass
360 :
public IbisPortrefLoweringBase<PortrefLoweringPass> {
361 void runOnOperation()
override;
366 void PortrefLoweringPass::runOnOperation() {
367 auto *ctx = &getContext();
368 ConversionTarget target(*ctx);
369 target.addIllegalOp<InputPortOp, OutputPortOp>();
370 target.addLegalDialect<IbisDialect>();
373 target.addDynamicallyLegalOp<InputPortOp, OutputPortOp>([&](
auto op) {
374 PortRefType portType =
375 cast<PortRefType>(cast<PortOpInterface>(op).
getPort().getType());
376 return !isa<PortRefType>(portType.getPortType());
382 target.addDynamicallyLegalOp<GetPortOp>([&](GetPortOp op) {
383 PortRefType portType = cast<PortRefType>(op.getPort().getType());
384 return !isa<PortRefType>(portType.getPortType());
388 patterns.add<InputPortConversionPattern, OutputPortConversionPattern,
389 GetPortConversionPattern>(ctx);
392 applyPartialConversion(getOperation(), target, std::move(
patterns))))
397 return std::make_unique<PortrefLoweringPass>();
static PortInfo getPort(ModuleTy &mod, size_t idx)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction
The direction of a Component or Cell port.
mlir::Type innerType(mlir::Type type)
std::unique_ptr< mlir::Pass > createPortrefLoweringPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.