MLIR-AIE
AIEAssignRuntimeSequenceBDIDs.cpp
Go to the documentation of this file.
1//===- AIEAssignRuntimeSequenceBDIDs.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 Advanced Micro Devices, Inc.
8//
9//===----------------------------------------------------------------------===//
10
15
16#include "mlir/Pass/Pass.h"
17#include "llvm/ADT/TypeSwitch.h"
18
19namespace xilinx::AIEX {
20#define GEN_PASS_DEF_AIEASSIGNRUNTIMESEQUENCEBDIDS
21#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
22} // namespace xilinx::AIEX
23
24using namespace mlir;
25using namespace xilinx;
26using namespace xilinx::AIEX;
27
30 AIEAssignRuntimeSequenceBDIDsPass> {
31
33 getGeneratorForTile(AIE::TileOp tile,
34 std::map<AIE::TileOp, BdIdGenerator> &gens) {
35 const AIETargetModel &targetModel =
36 tile->getParentOfType<AIE::DeviceOp>().getTargetModel();
37 auto genIt = gens.find(tile);
38 if (genIt == gens.end()) {
39 gens.insert(std::pair(
40 tile, BdIdGenerator(tile.getCol(), tile.getRow(), targetModel)));
41 }
42 BdIdGenerator &gen = std::get<1>(*gens.find(tile));
43 return gen;
44 }
45
46 LogicalResult runOnConfigureBDs(DMAConfigureTaskOp op,
47 std::map<AIE::TileOp, BdIdGenerator> &gens) {
48 AIE::TileOp tile = op.getTileOp();
49 BdIdGenerator &gen = getGeneratorForTile(tile, gens);
50
51 // First, honor all the user-specified BD IDs
52 WalkResult result = op.walk<WalkOrder::PreOrder>([&](AIE::DMABDOp bd_op) {
53 if (bd_op.getBdId().has_value()) {
54 if (gen.bdIdAlreadyAssigned(bd_op.getBdId().value())) {
55 op.emitOpError("Specified buffer descriptor ID ")
56 << bd_op.getBdId().value()
57 << " is already in use. Emit an aiex.dma_free_task operation to "
58 "reuse BDs.";
59 return WalkResult::interrupt();
60 }
61 gen.assignBdId(bd_op.getBdId().value());
62 }
63 return WalkResult::advance();
64 });
65 if (result.wasInterrupted()) {
66 return failure();
67 }
68
69 // Now, allocate BD IDs for all unspecified BDs
70 result =
71 op.walk<WalkOrder::PreOrder>([&](AIE::DMABDOp bd_op) {
72 if (bd_op.getBdId().has_value()) {
73 return WalkResult::advance();
74 }
75 // FIXME: use correct channelIndex here
76 std::optional<int32_t> next_id = gen.nextBdId(/*channelIndex=*/0);
77 if (!next_id) {
78 op.emitOpError()
79 << "Allocator exhausted available buffer descriptor IDs.";
80 return WalkResult::interrupt();
81 }
82 bd_op.setBdId(*next_id);
83 return WalkResult::advance();
84 });
85 if (result.wasInterrupted()) {
86 return failure();
87 }
88
89 return success();
90 }
91
92 LogicalResult runOnFreeBDs(DMAFreeTaskOp op,
93 std::map<AIE::TileOp, BdIdGenerator> &gens) {
94 DMAConfigureTaskOp task_op = op.getTaskOp();
95 if (!task_op) {
96 auto err = op.emitOpError(
97 "does not reference a valid configure_task operation.");
98 Operation *task_op = op.getTask().getDefiningOp();
99 if (llvm::isa<DMAStartBdChainOp>(task_op)) {
100 err.attachNote(task_op->getLoc())
101 << "Lower this operation first using the "
102 "--aie-materialize-bd-chains pass.";
103 }
104 if (llvm::isa<DMAConfigureTaskForOp>(task_op)) {
105 err.attachNote(task_op->getLoc())
106 << "Lower this operation first using the "
107 "--aie-substitute-shim-dma-allocations pass.";
108 }
109 return err;
110 }
111
112 AIE::TileOp tile = task_op.getTileOp();
113 BdIdGenerator &gen = getGeneratorForTile(tile, gens);
114
115 // First, honor all the hard-coded BD IDs
116 WalkResult result =
117 task_op.walk<WalkOrder::PreOrder>([&](AIE::DMABDOp bd_op) {
118 if (!bd_op.getBdId().has_value()) {
119 bd_op.emitOpError("Free called on BD chain with unassigned IDs.");
120 return WalkResult::interrupt();
121 }
122 if (!gen.bdIdAlreadyAssigned(bd_op.getBdId().value())) {
123 // Ignore double-frees.
124 return WalkResult::advance();
125 }
126 gen.freeBdId(bd_op.getBdId().value());
127 return WalkResult::advance();
128 });
129 if (result.wasInterrupted()) {
130 return failure();
131 }
132
133 op.erase();
134
135 return success();
136 }
137
138 void runOnOperation() override {
139
140 // This pass currently assigns BD IDs with a simple linear pass. IDs are
141 // assigned in sequence, and issuing an aiex.free_bds or aiex.await_bds op
142 // kills the correspondings IDs use. If in the future we support
143 // branching/jumping in the sequence function, a proper liveness analysis
144 // will become necessary here.
145
146 AIE::DeviceOp device = getOperation();
147 std::map<AIE::TileOp, BdIdGenerator> gens;
148
149 // Insert a free_bds operation for each await_bds
150 // After waiting for BD IDs, they can definitely safely be reused
151 device.walk([&](DMAAwaitTaskOp op) {
152 OpBuilder builder(op);
153 builder.setInsertionPointAfter(op);
154 DMAFreeTaskOp::create(builder, op.getLoc(), op.getTask());
155 });
156
157 // TODO: Only walk the sequence function
158 device.walk([&](Operation *op) {
159 LogicalResult result =
160 llvm::TypeSwitch<Operation *, LogicalResult>(op)
161 .Case<DMAConfigureTaskOp>([&](DMAConfigureTaskOp op) {
162 return runOnConfigureBDs(op, gens);
163 })
164 .Case<DMAFreeTaskOp>(
165 [&](DMAFreeTaskOp op) { return runOnFreeBDs(op, gens); })
166 .Default([](Operation *op) { return success(); });
167 if (failed(result)) {
168 return signalPassFailure();
169 }
170 });
171 }
172};
173
174std::unique_ptr<OperationPass<AIE::DeviceOp>>
176 return std::make_unique<AIEAssignRuntimeSequenceBDIDsPass>();
177}
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEAssignRuntimeSequenceBDIDsPass()
const AIETargetModel & getTargetModel(mlir::Operation *op)
LogicalResult runOnFreeBDs(DMAFreeTaskOp op, std::map< AIE::TileOp, BdIdGenerator > &gens)
LogicalResult runOnConfigureBDs(DMAConfigureTaskOp op, std::map< AIE::TileOp, BdIdGenerator > &gens)
BdIdGenerator & getGeneratorForTile(AIE::TileOp tile, std::map< AIE::TileOp, BdIdGenerator > &gens)
bool bdIdAlreadyAssigned(uint32_t bdId)
void assignBdId(uint32_t bdId)
void freeBdId(uint32_t bdId)
std::optional< uint32_t > nextBdId(int channelIndex)