MLIR-AIE 1.4.5.dev
AIELowerCascadeFlows.cpp
Go to the documentation of this file.
1//===- AIELowerCascadeFlows.cpp ---------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2022 Xilinx, Inc.
4// Copyright (C) 2022-2026 Advanced Micro Devices, Inc.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11
12#include "mlir/IR/Attributes.h"
13#include "mlir/Pass/Pass.h"
14
15#include "llvm/ADT/Twine.h"
16
17namespace xilinx::AIE {
18#define GEN_PASS_DEF_AIELOWERCASCADEFLOWS
19#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
20} // namespace xilinx::AIE
21
22#define DEBUG_TYPE "aie-lower-cascade-flows"
23
24using namespace mlir;
25using namespace xilinx;
26using namespace xilinx::AIE;
27
29 : xilinx::AIE::impl::AIELowerCascadeFlowsBase<AIELowerCascadeFlowsPass> {
30 void getDependentDialects(DialectRegistry &registry) const override {
31 registry.insert<AIEDialect>();
32 }
33 void runOnOperation() override {
34 DeviceOp device = getOperation();
35 const auto &targetModel = device.getTargetModel();
36 OpBuilder builder = OpBuilder::atBlockTerminator(device.getBody());
37
38 DenseSet<TileOp> tilesWithCascadeFlow;
39 DenseMap<TileOp, WireBundle> cascadeInputsPerTile;
40 DenseMap<TileOp, WireBundle> cascadeOutputsPerTile;
41
42 // identify cascade_flows and what ports they use on each tile
43 for (auto cascadeFlow : device.getOps<CascadeFlowOp>()) {
44 // for each cascade flow
45 TileOp src = cascadeFlow.getSourceTileOp();
46 TileOp dst = cascadeFlow.getDestTileOp();
47 tilesWithCascadeFlow.insert(src);
48 tilesWithCascadeFlow.insert(dst);
49
50 if (targetModel.isSouth(src.getCol(), src.getRow(), dst.getCol(),
51 dst.getRow())) {
52 cascadeInputsPerTile[dst] = WireBundle::North;
53 cascadeOutputsPerTile[src] = WireBundle::South;
54 } else if (targetModel.isEast(src.getCol(), src.getRow(), dst.getCol(),
55 dst.getRow())) {
56 cascadeInputsPerTile[dst] = WireBundle::West;
57 cascadeOutputsPerTile[src] = WireBundle::East;
58 } else {
59 // TODO: remove when this pass supports routing
60 cascadeFlow.emitOpError(
61 "source tile must be to the North or West of the destination tile");
62 return signalPassFailure();
63 }
64 }
65
66 // generate configure cascade ops
67 for (TileOp tile : device.getOps<TileOp>()) {
68 if (!tilesWithCascadeFlow.contains(tile))
69 continue;
70 WireBundle inputDir;
71 if (cascadeInputsPerTile.find(tile) != cascadeInputsPerTile.end()) {
72 inputDir = cascadeInputsPerTile[tile];
73 } else {
74 inputDir = WireBundle::North;
75 }
76 WireBundle outputDir;
77 if (cascadeOutputsPerTile.find(tile) != cascadeOutputsPerTile.end()) {
78 outputDir = cascadeOutputsPerTile[tile];
79 } else {
80 outputDir = WireBundle::South;
81 }
82 ConfigureCascadeOp::create(builder, tile.getLoc(), tile,
83 static_cast<CascadeDir>(inputDir),
84 static_cast<CascadeDir>(outputDir));
85 }
86
87 // erase CascadeFlowOps
88 SetVector<Operation *> opsToErase;
89 device.walk([&](Operation *op) {
90 if (isa<CascadeFlowOp>(op))
91 opsToErase.insert(op);
92 });
93 IRRewriter rewriter(&getContext());
94 for (auto it = opsToErase.rbegin(); it != opsToErase.rend(); ++it)
95 (*it)->erase();
96 }
97};
98
99std::unique_ptr<OperationPass<DeviceOp>> AIE::createAIELowerCascadeFlowsPass() {
100 return std::make_unique<AIELowerCascadeFlowsPass>();
101}
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIELowerCascadeFlowsPass()
void getDependentDialects(DialectRegistry &registry) const override