MLIR-AIE
AIEDMATasksToNPU.cpp
Go to the documentation of this file.
1//===- AIEDMATasksToNPU.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
11#include <algorithm>
12#include <iterator>
13
17
18#include "mlir/Pass/Pass.h"
19#include "mlir/Transforms/DialectConversion.h"
20#include "llvm/ADT/TypeSwitch.h"
21
22using namespace mlir;
23using namespace xilinx;
24using namespace xilinx::AIEX;
25
27 using OpConversionPattern::OpConversionPattern;
28
29 LogicalResult
30 matchAndRewrite(DMAStartTaskOp op, OpAdaptor adaptor,
31 ConversionPatternRewriter &rewriter) const override {
32 DMAConfigureTaskOp task_op = op.getTaskOp();
33 if (!task_op) {
34 // Cannot rewrite this; probably points to a DMAStartTaskForOp,
35 // which we will lower once it has been rewritten into a DMAStartTaskOp.
36 return failure();
37 }
38 AIE::TileOp tile = task_op.getTileOp();
39 std::optional<uint32_t> first_bd_id = task_op.getFirstBdId();
40 if (!first_bd_id) {
41 auto err = op.emitOpError(
42 "First buffer descriptor in chain has not been assigned an ID");
43 err.attachNote() << "Run the `aie-assign-runtime-buffer-descriptor-ids` "
44 "pass first or manually assign an ID.";
45 return failure();
46 }
47 rewriter.replaceOpWithNewOp<NpuPushQueueOp>(
48 op, tile.getCol(), tile.getRow(), task_op.getDirection(),
49 task_op.getChannel(), task_op.getIssueToken(), task_op.getRepeatCount(),
50 *first_bd_id);
51 return success();
52 }
53};
54
56 using OpConversionPattern::OpConversionPattern;
57
58 LogicalResult
59 matchAndRewrite(DMAAwaitTaskOp op, OpAdaptor adaptor,
60 ConversionPatternRewriter &rewriter) const override {
61 DMAConfigureTaskOp task_op = op.getTaskOp();
62 if (!task_op) {
63 return failure();
64 }
65 if (!task_op.getIssueToken()) {
66 auto err = op.emitOpError(
67 "Cannot wait on a BD that is not configured to issue a token.");
68 err.attachNote(task_op.getLoc())
69 << "Consider adding attribute `issue_token=true` here.";
70 return err;
71 }
72 AIE::TileOp tile = task_op.getTileOp();
73 rewriter.replaceOpWithNewOp<NpuSyncOp>(op, tile.getCol(), tile.getRow(),
74 (uint32_t)task_op.getDirection(),
75 task_op.getChannel(), 1, 1);
76 return success();
77 }
78};
79
80struct AIEDMATasksToNPUPass : AIEDMATasksToNPUBase<AIEDMATasksToNPUPass> {
81
82 bool shouldSkipBlock(Block &block) {
83 // Allow blocks in the input IR that contain nothing but a next_bd operation
84 // as the entry block. We will skip these blocks and not lower them to
85 // anything.
86 auto it = block.without_terminator();
87 return block.isEntryBlock() && it.begin() == it.end();
88 }
89
90 LogicalResult verifyBdInBlock(Block &block) {
91 auto bd_ops = block.getOps<AIE::DMABDOp>();
92 // Exactly one BD op per block
93 int n_bd_ops = std::distance(bd_ops.begin(), bd_ops.end());
94 if (n_bd_ops < 1) {
95 auto error = block.getTerminator()->emitError(
96 "Block ending in this terminator does not contain a required "
97 "aie.dma_bd operation.");
98 error.attachNote(block.getParentOp()->getLoc())
99 << "Error encountered while lowering this BD configuration.";
100 return failure();
101 } else if (n_bd_ops > 1) {
102 auto error = block.getTerminator()->emitOpError(
103 "This block contains multiple aie.dma_bd operations. Exactly one is "
104 "required.");
105 auto it = bd_ops.begin();
106 ++it;
107 for (; it != bd_ops.end(); ++it) {
108 error.attachNote((*it)->getLoc()) << "Extra aie.dma_bd operation here.";
109 }
110 return failure();
111 }
112 AIE::DMABDOp bd_op = *bd_ops.begin();
113 if (!bd_op.getBdId().has_value()) {
114 auto error = bd_op.emitOpError(
115 "Cannot lower buffer descriptor without assigned ID.");
116 error.attachNote()
117 << "Run the `--aie-assign-runtime-sequence-bd-ids` pass first or "
118 "manually assign an ID to this buffer descriptor.";
119 error.attachNote(block.getParentOp()->getLoc())
120 << "Error encountered while lowering this BD configuration.";
121 return failure();
122 }
123 return success();
124 }
125
126 LogicalResult verifyOptionalLocksInBlock(Block &block) {
127 auto lock_ops = block.getOps<AIE::UseLockOp>();
128 // Exactly 0 or 2 lock ops
129 int n_lock_ops = std::distance(lock_ops.begin(), lock_ops.end());
130 if (n_lock_ops > 0) {
131 // TODO: Not yet implemented
132 AIE::UseLockOp lock_op = *lock_ops.begin();
133 lock_op.emitOpError("Lowering for lock operations in NPU runtime "
134 "configuration is not yet implemented.");
135 return failure();
136 }
137 return success();
138 }
139
140 LogicalResult verifyNoUnsupportedOpsInBlock(Block &block) {
141 WalkResult unsupported_ops = block.walk([&](Operation *inner_op) {
142 return llvm::TypeSwitch<Operation *, WalkResult>(inner_op)
143 .Case<AIE::DMABDOp>(
144 [&](AIE::DMABDOp bd_op) { return WalkResult::advance(); })
145 .Case<AIE::UseLockOp>(
146 [&](AIE::UseLockOp lock_op) { return WalkResult::advance(); })
147 .Case<AIE::NextBDOp>(
148 [&](AIE::NextBDOp lock_op) { return WalkResult::advance(); })
149 .Case<AIE::EndOp>(
150 [&](AIE::EndOp lock_op) { return WalkResult::advance(); })
151 .Default([&](Operation *inner_op) {
152 auto error = block.getParentOp()->emitOpError(
153 "Unsupported operation within BD block.");
154 error.attachNote(inner_op->getLoc())
155 << "No lowering to NPU instructions available for this "
156 "operation.";
157 return WalkResult::interrupt();
158 });
159 });
160 if (unsupported_ops.wasInterrupted()) {
161 return failure();
162 }
163 return success();
164 }
165
166 AIE::DMABDOp getBdForBlock(Block &block) {
167 auto bd_ops = block.getOps<AIE::DMABDOp>();
168 AIE::DMABDOp bd_op = *bd_ops.begin(); // Dereference first (and only, after
169 // previous checks) bd op iterator
170 return bd_op;
171 }
172
173 std::optional<std::pair<AIE::UseLockOp, AIE::UseLockOp>>
175 // auto lock_ops = block.getOps<AIE::UseLockOp>();
176 return std::nullopt; // Not yet implemented
177 }
178
179 LogicalResult setAddressForSingleBD(OpBuilder &builder, AIE::DMABDOp &bd_op,
180 AIE::TileOp &tile) {
181 uint32_t bd_id = bd_op.getBdId().value();
182 const AIE::AIETargetModel &target_model = AIE::getTargetModel(bd_op);
183 auto buf = bd_op.getBuffer();
184 uint64_t register_addr =
185 target_model.getDmaBdAddress(tile.getCol(), tile.getRow(), bd_id) +
186 target_model.getDmaBdAddressOffset(tile.getCol(), tile.getRow());
187 if (mlir::BlockArgument buf_arg =
188 llvm::dyn_cast<mlir::BlockArgument>(buf)) {
189 if (!target_model.isShimNOCTile(tile.getCol(), tile.getRow())) {
190 return bd_op->emitOpError("DDR memory (runtime input arguments) can "
191 "only be referred to on shim tiles.");
192 }
193 unsigned arg_idx = buf_arg.getArgNumber();
194 int64_t offset = bd_op.getOffsetInBytes();
195 builder.create<NpuAddressPatchOp>(bd_op.getLoc(),
196 /*addr*/ register_addr,
197 /*arg_idx*/ arg_idx,
198 /*arg_plus*/ offset);
199 } else if (AIE::BufferOp buffer =
200 llvm::dyn_cast<AIE::BufferOp>(buf.getDefiningOp())) {
201 uint64_t buf_addr;
202 if (!buffer.getAddress().has_value()) {
203 return bd_op->emitOpError(
204 "Cannot lower buffer without associated address. Run pass "
205 "--aie-assign-buffer-addresses first or manually assign an "
206 "address.");
207 }
208 buf_addr = *buffer.getAddress();
209 builder.create<NpuWrite32Op>(bd_op.getLoc(), register_addr, buf_addr,
210 nullptr, nullptr, nullptr);
211 } else {
212 return bd_op->emitOpError("Buffer argument must be either a constant "
213 "aie.buffer or a runtime "
214 "sequence input argument.");
215 }
216 return success();
217 }
218
219 LogicalResult rewriteSingleBD(OpBuilder &builder, Block &block,
220 AIE::TileOp &tile,
221 AIE::DMAChannelDir channelDir) {
222 AIE::DMABDOp bd_op = getBdForBlock(block);
223 const auto &target_model = AIE::getTargetModel(bd_op);
224 MemRefType buffer_type = bd_op.getBuffer().getType();
225 uint32_t addr_granularity = target_model.getAddressGenGranularity();
226
227 uint32_t bd_id = bd_op.getBdId().value();
228 int64_t offset = bd_op.getOffsetInBytes();
229 uint64_t len = bd_op.getLenInBytes();
230 uint64_t len_addr_granularity = len * 8 / addr_granularity;
231
232 if (offset * 8 % addr_granularity != 0) {
233 return bd_op->emitOpError("Offset must be aligned to ")
234 << (addr_granularity / 8) << " byte boundary.";
235 }
236
237 if (len < addr_granularity / 8) {
238 return bd_op->emitOpError("Transfer size of ")
239 << len << " bytes falls below minimum hardware transfer unit of "
240 << (addr_granularity / 8) << " bytes.";
241 }
242 // Process strides/wraps
243 std::optional<llvm::ArrayRef<AIE::BDDimLayoutAttr>> dims =
244 bd_op.getDimensions();
245 llvm::SmallVector<int64_t, 4> sizes = llvm::SmallVector<int64_t, 4>(4, 0);
246 llvm::SmallVector<int64_t, 4> strides = llvm::SmallVector<int64_t, 4>(4, 0);
247
248 // Padding
249 std::optional<llvm::ArrayRef<AIE::BDPadLayoutAttr>> padDims =
250 bd_op.getPadDimensions();
251 llvm::SmallVector<int64_t, 4> padBefore =
252 llvm::SmallVector<int64_t, 4>(4, 0);
253 llvm::SmallVector<int64_t, 4> padAfter =
254 llvm::SmallVector<int64_t, 4>(4, 0);
255 std::fill(padBefore.begin(), padBefore.end(), 0);
256 std::fill(padAfter.begin(), padAfter.end(), 0);
257
258 auto enable_packet = 0;
259 auto out_of_order_id = 0;
260 auto packet_id = 0;
261 auto packet_type = 0;
262 auto d0size = 0;
263 auto d0stride = 0;
264 auto d1size = 0;
265 auto d1stride = 0;
266 auto d2size = 0;
267 auto d2stride = 0;
268 auto iteration_size = 0;
269 auto iteration_stride = 0;
270
271 if (dims && dims->size() > 0) {
272 llvm::SmallVector<int64_t, 4> input_sizes =
273 llvm::SmallVector<int64_t, 4>(4, 1);
274 llvm::SmallVector<int64_t, 4> input_strides =
275 llvm::SmallVector<int64_t, 4>(4, 0);
276 if (dims->size() > 4) {
277 return bd_op->emitOpError("At most four data layout transformation "
278 "dimensions may be provided.");
279 }
280
281 for (size_t i = 0; i < dims->size(); i++) {
282 // Pass down dimensions in reverse order; in the MLIR, this allows
283 // us to specify step sizes/wraps in the same order as we would
284 // access a multi-dim C array, with the highest dimension first.
285 int j = dims->size() - i - 1;
286 input_sizes[i] = (*dims)[j].getSize();
287 input_strides[i] = (*dims)[j].getStride();
288 }
289
290 // Do not check input_sizes[3] because a repeat can still be considered a
291 // linear transfer
292 bool isLinearTransfer = (input_sizes[0] >= 1) && (input_sizes[1] == 1) &&
293 (input_sizes[2] == 1);
294
295 if (dims->size() > 2) {
296 d2size = (target_model.isMemTile(tile.getCol(), tile.getRow()))
297 ? (*dims)[2].getSize()
298 : 0;
299 }
300 if (padDims.has_value()) {
301 if (!target_model.isMemTile(tile.getCol(), tile.getRow()))
302 return bd_op->emitOpError()
303 << "Padding is only supported by memtile dma bds.";
304 if (padDims->size() > dims->size())
305 return bd_op->emitOpError()
306 << "Mismatch number of dimensions between padding(s)"
307 << " and wrap(s) and stride(s).";
308 if (channelDir == AIE::DMAChannelDir::MM2S) {
309 for (size_t i = 0; i < padDims->size(); i++) {
310 int j = padDims->size() - i - 1;
311 padBefore[i] = (*padDims)[j].getConstPadBefore();
312 padAfter[i] = (*padDims)[j].getConstPadAfter();
313 }
314 for (size_t i = padDims->size(); i < dims->size(); i++) {
315 padBefore[i] = 0;
316 padAfter[i] = 0;
317 }
318 } else
319 return bd_op->emitOpError()
320 << "supports padding only for MM2S direction on MemTiles.";
321 }
322 getHardwareStridesWraps(target_model, bd_op, buffer_type, input_sizes,
323 input_strides, sizes, strides);
324
325 if (failed(verifyStridesWraps(bd_op, buffer_type, tile.getCol(),
326 tile.getRow(), input_sizes, input_strides,
327 sizes, strides, isLinearTransfer))) {
328 return failure();
329 }
330
331 iteration_size = sizes[3];
332 iteration_stride = strides[3];
333
334 if (!isLinearTransfer) {
335 // d0_size, d0_stride
336 d0size = sizes[0];
337 d0stride = strides[0];
338
339 // d1_size, d1_stride
340 d1size = sizes[1];
341 d1stride = strides[1];
342
343 // d2_stride
344 d2stride = strides[2];
345 // d2_size set elsewhere
346 }
347 if (input_sizes[3] > 1 && input_strides[3] == 0) {
348 // We allow users to encode the repeat_count as a dimension 3 stride
349 // of 0. This must lower to a iteration wrap of 0, so no stride is
350 // ever added. We then repeat the BD using the repeat_count in
351 // NpuPushQueueOp.
352 iteration_size = 0;
353 iteration_stride = 0;
354 }
355
356 // Ensure the total transfer length and the length expressed in the lowest
357 // three dimensions of strides/wraps agree. (Fourth dimension is
358 // iteration/repeat count and repeats the whole BD, so should not be
359 // incorporated in length of a single BD invocation.)
360 uint64_t len_dims_addr_granularity = 1;
361 for (size_t i = 0; i < 3; i++) {
362 len_dims_addr_granularity *= sizes[i];
363 }
364 if (len_dims_addr_granularity != len_addr_granularity) {
365 auto err =
366 bd_op->emitOpError(
367 "Buffer descriptor length does not match length of transfer "
368 "expressed by lowest three dimensions of data layout "
369 "transformation strides/wraps. ")
370 << "BD length is " << (len_addr_granularity * addr_granularity / 8)
371 << " bytes. "
372 << "Lowest three dimensions of data layout transformation would "
373 "result in transfer of "
374 << (len_dims_addr_granularity * addr_granularity / 8) << " bytes. ";
375 err.attachNote() << "Do not include the highest dimension size in "
376 "transfer length, as this is the BD repeat count.";
377 return failure();
378 }
379 } else {
380 if (padDims && target_model.isMemTile(tile.getCol(), tile.getRow()) &&
381 channelDir == AIE::DMAChannelDir::MM2S) {
382 return bd_op->emitOpError()
383 << "Padding requires n-d data layouts expressed as "
384 << "wrap(s) and stride(s).";
385 } else if (padDims) {
386 return bd_op->emitOpError() << "Padding is supported only on MemTiles.";
387 }
388 }
389 // find next BD ID, if any
390 uint32_t use_next_bd = 0;
391 uint32_t next_bd_id = 0;
392 if (bd_op.getNextBdId().has_value()) {
393 next_bd_id = bd_op.getNextBdId().value();
394 use_next_bd = 1;
395 }
396
397 // enable_packet
398 if (auto packetInfo = bd_op.getPacket()) {
399 enable_packet = 1;
400 packet_type = packetInfo->getPktType();
401 packet_id = packetInfo->getPktId();
402 }
403
404 builder.create<NpuWriteBdOp>(
405 bd_op.getLoc(), tile.getCol(), bd_id, len_addr_granularity, offset,
406 /*enable_packet=*/enable_packet,
407 /*out_of_order_id=*/out_of_order_id,
408 /*packet_id=*/packet_id,
409 /*packet_type=*/packet_type,
410 /* TODO: Strides/Wraps */
411 /*d0_size=*/d0size, /*d0_stride=*/d0stride,
412 /*d1_size=*/d1size, /*d1_stride=*/d1stride,
413 /*d2_size=*/d2size, /*d2_stride=*/d2stride,
414 /*iteration_current=*/0, /*iteration_size=*/iteration_size,
415 /*iteration_stride=*/iteration_stride,
416 /* TODO: Next BD */
417 /*next_bd=*/next_bd_id,
418 /*row=*/tile.getRow(),
419 /*use_next_bd=*/use_next_bd,
420 /*valid_bd=*/1,
421 /* TODO: Locks */
422 /*lock_rel_val=*/0, /*lock_rel_id=*/0, /*lock_acq_enable=*/0,
423 /*lock_acq_val=*/0, /*lock_ackq_id=*/0, /*d0_zero_before=*/padBefore[0],
424 /*d1_zero_before=*/padBefore[1], /*d2_zero_before=*/padBefore[2],
425 /*d0_zero_after=*/padAfter[0], /*d1_zero_after=*/padAfter[1],
426 /*d2_zero_after=*/padAfter[2],
427 /*burst_length=*/bd_op.getBurstLength());
428 return setAddressForSingleBD(builder, bd_op, tile);
429 }
430
431 LogicalResult hoistNextBdOpsIntoAttrs(DMAConfigureTaskOp op) {
432 Region &body = op.getBody();
433 for (auto it = body.begin(); it != body.end(); ++it) {
434 Block &block = *it;
435 if (shouldSkipBlock(block)) {
436 continue;
437 }
438 AIE::DMABDOp bd_op = getBdForBlock(block);
439 if (AIE::NextBDOp next_bd_op =
440 llvm::dyn_cast<AIE::NextBDOp>(block.getTerminator())) {
441 if (bd_op.getNextBdId().has_value()) {
442 auto error =
443 bd_op.emitOpError("Cannot specify both next_bd_id attribute and "
444 "aie.next_bd operation.");
445 error.attachNote(next_bd_op.getLoc())
446 << "Potentially conflicting next buffer descriptor ID specified "
447 "here.";
448 return failure();
449 }
450 Block &next_bd_block = *next_bd_op.getDest();
451 AIE::DMABDOp next_dma_bd_op = getBdForBlock(next_bd_block);
452 assert(next_dma_bd_op.getBdId()
453 .has_value()); // Next BD should have assigned ID, and this
454 // should have been checked by earlier
455 // verifyBdInBlock() call
456 bd_op.setNextBdId(next_dma_bd_op.getBdId().value());
457 OpBuilder builder(next_bd_op);
458 builder.create<AIE::EndOp>(next_bd_op.getLoc());
459 next_bd_op.erase();
460 }
461 }
462 return success();
463 }
464
465 LogicalResult rewriteSingleDMAConfigureTaskOp(DMAConfigureTaskOp op) {
466 OpBuilder builder(op);
467 AIE::TileOp tile = op.getTileOp();
468
469 if (!op.use_empty()) {
470 auto err = op.emitOpError("Cannot lower while op still has uses.");
471 mlir::Operation::use_range uses = op.getOperation()->getUses();
472 for (auto it = uses.begin(); it != uses.end(); ++it) {
473 err.attachNote(it->getOwner()->getLoc()) << "Used here.";
474 }
475 return failure();
476 }
477
478 Region &body = op.getBody();
479
480 // Verify each BD block first; subsequent functions rely on them being
481 // well-formed
482 for (auto it = body.begin(); it != body.end(); ++it) {
483 if (shouldSkipBlock(*it)) {
484 continue;
485 }
486 if (failed(verifyNoUnsupportedOpsInBlock(*it))) {
487 return failure();
488 }
489 if (failed(verifyBdInBlock(*it))) {
490 return failure();
491 }
492 if (failed(verifyOptionalLocksInBlock(*it))) {
493 return failure();
494 }
495 }
496
497 // Hoist next_bd operations into next_bd_id attribute of the dma_bd
498 if (failed(hoistNextBdOpsIntoAttrs(op))) {
499 return failure();
500 }
501
502 auto channelDir = op.getDirection();
503
504 // Lower all BDs
505 for (auto it = body.begin(); it != body.end(); ++it) {
506 Block &block = *it;
507 if (shouldSkipBlock(block)) {
508 continue;
509 }
510 if (failed(rewriteSingleBD(builder, block, tile, channelDir))) {
511 return failure();
512 }
513 }
514
515 op.erase();
516
517 return success();
518 }
519
520 LogicalResult rewriteDMAConfigureTaskOp(AIE::DeviceOp device) {
521 WalkResult result = device.walk([&](DMAConfigureTaskOp op) {
522 if (failed(rewriteSingleDMAConfigureTaskOp(op))) {
523 return WalkResult::interrupt();
524 }
525 return WalkResult::advance();
526 });
527 if (result.wasInterrupted()) {
528 return failure();
529 }
530 return success();
531 }
532
533 void runOnOperation() override {
534 AIE::DeviceOp device = getOperation();
535
536 // Convert DMAStartBD and DMAAwaitBD ops
537 ConversionTarget target(getContext());
538 target.addLegalDialect<AIEXDialect>();
539 target.addIllegalOp<DMAStartTaskOp>();
540 target.addIllegalOp<DMAAwaitTaskOp>();
541 RewritePatternSet patterns(&getContext());
542 patterns.insert<DMAStartTaskOpPattern>(&getContext());
543 patterns.insert<DMAAwaitTaskOpPattern>(&getContext());
544 if (failed(applyPartialConversion(device, target, std::move(patterns)))) {
545 signalPassFailure();
546 }
547
548 // Lower the configuration for the BDs
549 if (failed(rewriteDMAConfigureTaskOp(device))) {
550 signalPassFailure();
551 }
552 }
553};
554
555std::unique_ptr<OperationPass<AIE::DeviceOp>>
557 return std::make_unique<AIEDMATasksToNPUPass>();
558}
virtual uint64_t getDmaBdAddress(int col, int row, uint32_t bd_id, int channel=-1, AIE::DMAChannelDir direction=AIE::DMAChannelDir::MM2S) const =0
Return the array address of the dma buffer descriptor for the given col, row, buffer descriptor id,...
virtual uint32_t getDmaBdAddressOffset(int col, int row) const =0
Return the offset of the base address field within the shim dma buffer descriptor.
virtual bool isShimNOCTile(int col, int row) const =0
Return true if the given tile is a Shim NOC tile.
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEDMATasksToNPUPass()
void getHardwareStridesWraps(const AIE::AIETargetModel &targetModel, mlir::Operation *op, mlir::BaseMemRefType referencedBufType, llvm::SmallVector< int64_t, 4 > inputSizes, llvm::SmallVector< int64_t, 4 > inputStrides, llvm::SmallVector< int64_t, 4 > &sizes, llvm::SmallVector< int64_t, 4 > &strides)
mlir::LogicalResult verifyStridesWraps(mlir::Operation *forOp, mlir::BaseMemRefType referencedBufType, int tileCol, int tileRow, llvm::SmallVector< int64_t, 4 > inputSizes, llvm::SmallVector< int64_t, 4 > inputStrides, llvm::SmallVector< int64_t, 4 > hardwareSizes, llvm::SmallVector< int64_t, 4 > hardwareStrides, bool skipTransformationChecks=false)
const AIETargetModel & getTargetModel(mlir::Operation *op)
void runOnOperation() override
bool shouldSkipBlock(Block &block)
LogicalResult rewriteDMAConfigureTaskOp(AIE::DeviceOp device)
LogicalResult verifyNoUnsupportedOpsInBlock(Block &block)
std::optional< std::pair< AIE::UseLockOp, AIE::UseLockOp > > getOptionalLockOpsForBlock(Block &block)
LogicalResult rewriteSingleBD(OpBuilder &builder, Block &block, AIE::TileOp &tile, AIE::DMAChannelDir channelDir)
AIE::DMABDOp getBdForBlock(Block &block)
LogicalResult hoistNextBdOpsIntoAttrs(DMAConfigureTaskOp op)
LogicalResult verifyBdInBlock(Block &block)
LogicalResult rewriteSingleDMAConfigureTaskOp(DMAConfigureTaskOp op)
LogicalResult setAddressForSingleBD(OpBuilder &builder, AIE::DMABDOp &bd_op, AIE::TileOp &tile)
LogicalResult verifyOptionalLocksInBlock(Block &block)
LogicalResult matchAndRewrite(DMAAwaitTaskOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(DMAStartTaskOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override