MLIR-AIE
AIELowerCascadeFlows.cpp
Go to the documentation of this file.
1//===- AIELowerCascadeFlows.cpp ---------------------------------*- C++ -*-===//
2//
3// This file is licensed 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// (c) Copyright 2024 Xilinx Inc.
8//
9//===----------------------------------------------------------------------===//
10
13
14#include "mlir/IR/Attributes.h"
15#include "mlir/Pass/Pass.h"
16
17#include "llvm/ADT/Twine.h"
18
19namespace xilinx::AIE {
20#define GEN_PASS_DEF_AIELOWERCASCADEFLOWS
21#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
22} // namespace xilinx::AIE
23
24#define DEBUG_TYPE "aie-lower-cascade-flows"
25
26using namespace mlir;
27using namespace xilinx;
28using namespace xilinx::AIE;
29
31 : xilinx::AIE::impl::AIELowerCascadeFlowsBase<AIELowerCascadeFlowsPass> {
32 void getDependentDialects(DialectRegistry &registry) const override {
33 registry.insert<AIEDialect>();
34 }
35 void runOnOperation() override {
36 DeviceOp device = getOperation();
37 const auto &targetModel = device.getTargetModel();
38 OpBuilder builder = OpBuilder::atBlockTerminator(device.getBody());
39
40 std::set<TileOp> tilesWithCascadeFlow;
41 DenseMap<TileOp, WireBundle> cascadeInputsPerTile;
42 DenseMap<TileOp, WireBundle> cascadeOutputsPerTile;
43
44 // identify cascade_flows and what ports they use on each tile
45 for (auto cascadeFlow : device.getOps<CascadeFlowOp>()) {
46 // for each cascade flow
47 TileOp src = cascadeFlow.getSourceTileOp();
48 TileOp dst = cascadeFlow.getDestTileOp();
49 tilesWithCascadeFlow.insert(src);
50 tilesWithCascadeFlow.insert(dst);
51
52 if (targetModel.isSouth(src.getCol(), src.getRow(), dst.getCol(),
53 dst.getRow())) {
54 cascadeInputsPerTile[dst] = WireBundle::North;
55 cascadeOutputsPerTile[src] = WireBundle::South;
56 } else if (targetModel.isEast(src.getCol(), src.getRow(), dst.getCol(),
57 dst.getRow())) {
58 cascadeInputsPerTile[dst] = WireBundle::West;
59 cascadeOutputsPerTile[src] = WireBundle::East;
60 } else {
61 // TODO: remove when this pass supports routing
62 cascadeFlow.emitOpError(
63 "source tile must be to the North or West of the destination tile");
64 return signalPassFailure();
65 }
66 }
67
68 // generate configure cascade ops
69 for (TileOp tile : tilesWithCascadeFlow) {
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, builder.getUnknownLoc(), 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}
Include the generated interface declarations.
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIELowerCascadeFlowsPass()
PathEndPoint src
void getDependentDialects(DialectRegistry &registry) const override