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 = getBufferDescriptorAddressRegisterAddress(
185 target_model, bd_id, tile.getCol(), tile.getRow());
186 if (mlir::BlockArgument buf_arg =
187 llvm::dyn_cast<mlir::BlockArgument>(buf)) {
188 if (!target_model.isShimNOCTile(tile.getCol(), tile.getRow())) {
189 return bd_op->emitOpError("DDR memory (runtime input arguments) can "
190 "only be referred to on shim tiles.");
191 }
192 unsigned arg_idx = buf_arg.getArgNumber();
193 int64_t offset = bd_op.getOffsetInBytes();
194 builder.create<NpuAddressPatchOp>(bd_op.getLoc(), /*addr*/ register_addr,
195 /*arg_idx*/ arg_idx,
196 /*arg_plus*/ offset);
197 } else if (AIE::BufferOp buffer =
198 llvm::dyn_cast<AIE::BufferOp>(buf.getDefiningOp())) {
199 uint64_t buf_addr;
200 if (!buffer.getAddress().has_value()) {
201 return bd_op->emitOpError(
202 "Cannot lower buffer without associated address. Run pass "
203 "--aie-assign-buffer-addresses first or manually assign an "
204 "address.");
205 }
206 buf_addr = *buffer.getAddress();
207 builder.create<NpuWrite32Op>(bd_op.getLoc(), register_addr, buf_addr,
208 nullptr, nullptr, nullptr);
209 } else {
210 return bd_op->emitOpError(
211 "Buffer argument must be either a constant aie.buffer or a runtime "
212 "sequence input argument.");
213 }
214 return success();
215 }
216
217 LogicalResult rewriteSingleBD(OpBuilder &builder, Block &block,
218 AIE::TileOp &tile,
219 AIE::DMAChannelDir channelDir) {
220 AIE::DMABDOp bd_op = getBdForBlock(block);
221 const auto &target_model = AIE::getTargetModel(bd_op);
222 MemRefType buffer_type = bd_op.getBuffer().getType();
223 uint32_t addr_granularity = target_model.getAddressGenGranularity();
224
225 uint32_t bd_id = bd_op.getBdId().value();
226 int64_t offset = bd_op.getOffsetInBytes();
227 uint64_t len = bd_op.getLenInBytes();
228 uint64_t len_addr_granularity = len * 8 / addr_granularity;
229
230 if (offset * 8 % addr_granularity != 0) {
231 return bd_op->emitOpError("Offset must be aligned to ")
232 << (addr_granularity / 8) << " byte boundary.";
233 }
234
235 if (len < addr_granularity / 8) {
236 return bd_op->emitOpError("Transfer size of ")
237 << len << " bytes falls below minimum hardware transfer unit of "
238 << (addr_granularity / 8) << " bytes.";
239 }
240 // Process strides/wraps
241 std::optional<llvm::ArrayRef<AIE::BDDimLayoutAttr>> dims =
242 bd_op.getDimensions();
243 llvm::SmallVector<int64_t, 4> sizes = llvm::SmallVector<int64_t, 4>(4, 0);
244 llvm::SmallVector<int64_t, 4> strides = llvm::SmallVector<int64_t, 4>(4, 0);
245
246 // Padding
247 std::optional<llvm::ArrayRef<AIE::BDPadLayoutAttr>> padDims =
248 bd_op.getPadDimensions();
249 llvm::SmallVector<int64_t, 4> padBefore =
250 llvm::SmallVector<int64_t, 4>(4, 0);
251 llvm::SmallVector<int64_t, 4> padAfter =
252 llvm::SmallVector<int64_t, 4>(4, 0);
253 std::fill(padBefore.begin(), padBefore.end(), 0);
254 std::fill(padAfter.begin(), padAfter.end(), 0);
255
256 auto d0size = 0;
257 auto d0stride = 0;
258 auto d1size = 0;
259 auto d1stride = 0;
260 auto d2size = 0;
261 auto d2stride = 0;
262 auto iteration_size = 0;
263 auto iteration_stride = 0;
264
265 if (dims && dims->size() > 0) {
266 llvm::SmallVector<int64_t, 4> input_sizes =
267 llvm::SmallVector<int64_t, 4>(4, 1);
268 llvm::SmallVector<int64_t, 4> input_strides =
269 llvm::SmallVector<int64_t, 4>(4, 0);
270 if (dims->size() > 4) {
271 return bd_op->emitOpError("At most four data layout transformation "
272 "dimensions may be provided.");
273 }
274
275 for (size_t i = 0; i < dims->size(); i++) {
276 // Pass down dimensions in reverse order; in the MLIR, this allows
277 // us to specify step sizes/wraps in the same order as we would
278 // access a multi-dim C array, with the highest dimension first.
279 int j = dims->size() - i - 1;
280 input_sizes[i] = (*dims)[j].getSize();
281 input_strides[i] = (*dims)[j].getStride();
282 }
283
284 // Do not check input_sizes[3] because a repeat can still be considered a
285 // linear transfer
286 bool isLinearTransfer = (input_sizes[0] >= 1) && (input_sizes[1] == 1) &&
287 (input_sizes[2] == 1);
288
289 if (dims->size() > 2) {
290 d2size = (target_model.isMemTile(tile.getCol(), tile.getRow()))
291 ? (*dims)[2].getSize()
292 : 0;
293 }
294 if (padDims.has_value()) {
295 if (!target_model.isMemTile(tile.getCol(), tile.getRow()))
296 return bd_op->emitOpError()
297 << "Padding is only supported by memtile dma bds.";
298 if (padDims->size() > dims->size())
299 return bd_op->emitOpError()
300 << "Mismatch number of dimensions between padding(s)"
301 << " and wrap(s) and stride(s).";
302 if (channelDir == AIE::DMAChannelDir::MM2S) {
303 for (size_t i = 0; i < padDims->size(); i++) {
304 int j = padDims->size() - i - 1;
305 padBefore[i] = (*padDims)[j].getConstPadBefore();
306 padAfter[i] = (*padDims)[j].getConstPadAfter();
307 }
308 for (size_t i = padDims->size(); i < dims->size(); i++) {
309 padBefore[i] = 0;
310 padAfter[i] = 0;
311 }
312 } else
313 return bd_op->emitOpError()
314 << "supports padding only for MM2S direction on MemTiles.";
315 }
316 getHardwareStridesWraps(target_model, buffer_type, input_sizes,
317 input_strides, sizes, strides);
318
319 if (failed(verifyStridesWraps(bd_op, buffer_type, tile.getCol(),
320 tile.getRow(), input_sizes, input_strides,
321 sizes, strides, isLinearTransfer))) {
322 return failure();
323 }
324
325 iteration_size = sizes[3];
326 iteration_stride = strides[3];
327
328 if (!isLinearTransfer) {
329 // d0_size, d0_stride
330 d0size = sizes[0];
331 d0stride = strides[0];
332
333 // d1_size, d1_stride
334 d1size = sizes[1];
335 d1stride = strides[1];
336
337 // d2_stride
338 d2stride = strides[2];
339 // d2_size set elsewhere
340 }
341 if (input_sizes[3] > 1 && input_strides[3] == 0) {
342 // We allow users to encode the repeat_count as a dimension 3 stride
343 // of 0. This must lower to a iteration wrap of 0, so no stride is
344 // ever added. We then repeat the BD using the repeat_count in
345 // NpuPushQueueOp.
346 iteration_size = 0;
347 iteration_stride = 0;
348 }
349
350 // Ensure the total transfer length and the length expressed in the lowest
351 // three dimensions of strides/wraps agree. (Fourth dimension is
352 // iteration/repeat count and repeats the whole BD, so should not be
353 // incorporated in length of a single BD invocation.)
354 uint64_t len_dims_addr_granularity = 1;
355 for (size_t i = 0; i < 3; i++) {
356 len_dims_addr_granularity *= sizes[i];
357 }
358 if (len_dims_addr_granularity != len_addr_granularity) {
359 auto err =
360 bd_op->emitOpError(
361 "Buffer descriptor length does not match length of transfer "
362 "expressed by lowest three dimensions of data layout "
363 "transformation strides/wraps. ")
364 << "BD length is " << (len_addr_granularity * addr_granularity / 8)
365 << " bytes. "
366 << "Lowest three dimensions of data layout transformation would "
367 "result in transfer of "
368 << (len_dims_addr_granularity * addr_granularity / 8) << " bytes. ";
369 err.attachNote() << "Do not include the highest dimension size in "
370 "transfer length, as this is the BD repeat count.";
371 return failure();
372 }
373 } else {
374 if (padDims && target_model.isMemTile(tile.getCol(), tile.getRow()) &&
375 channelDir == AIE::DMAChannelDir::MM2S) {
376 return bd_op->emitOpError()
377 << "Padding requires n-d data layouts expressed as "
378 << "wrap(s) and stride(s).";
379 } else if (padDims) {
380 return bd_op->emitOpError() << "Padding is supported only on MemTiles.";
381 }
382 }
383 // find next BD ID, if any
384 uint32_t use_next_bd = 0;
385 uint32_t next_bd_id = 0;
386 if (bd_op.getNextBdId().has_value()) {
387 next_bd_id = bd_op.getNextBdId().value();
388 use_next_bd = 1;
389 }
390
391 builder.create<NpuWriteBdOp>(
392 bd_op.getLoc(), tile.getCol(), bd_id, len_addr_granularity, offset, 0,
393 0, 0, 0,
394 /* TODO: Strides/Wraps */
395 /*d0_size=*/d0size, /*d0_stride=*/d0stride,
396 /*d1_size=*/d1size, /*d1_stride=*/d1stride,
397 /*d2_size=*/d2size, /*d2_stride=*/d2stride,
398 /*iteration_current=*/0, /*iteration_size=*/iteration_size,
399 /*iteration_stride=*/iteration_stride,
400 /* TODO: Next BD */
401 /*next_bd=*/next_bd_id,
402 /*row=*/tile.getRow(),
403 /*use_next_bd=*/use_next_bd,
404 /*valid_bd=*/1,
405 /* TODO: Locks */
406 /*lock_rel_val=*/0, /*lock_rel_id=*/0, /*lock_acq_enable=*/0,
407 /*lock_acq_val=*/0, /*lock_ackq_id=*/0, /*d0_zero_before=*/padBefore[0],
408 /*d1_zero_before=*/padBefore[1], /*d2_zero_before=*/padBefore[2],
409 /*d0_zero_after=*/padAfter[0], /*d1_zero_after=*/padAfter[1],
410 /*d2_zero_after=*/padAfter[2],
411 /*burst_length=*/bd_op.getBurstLength());
412 return setAddressForSingleBD(builder, bd_op, tile);
413 }
414
415 LogicalResult hoistNextBdOpsIntoAttrs(DMAConfigureTaskOp op) {
416 Region &body = op.getBody();
417 for (auto it = body.begin(); it != body.end(); ++it) {
418 Block &block = *it;
419 if (shouldSkipBlock(block)) {
420 continue;
421 }
422 AIE::DMABDOp bd_op = getBdForBlock(block);
423 if (AIE::NextBDOp next_bd_op =
424 llvm::dyn_cast<AIE::NextBDOp>(block.getTerminator())) {
425 if (bd_op.getNextBdId().has_value()) {
426 auto error =
427 bd_op.emitOpError("Cannot specify both next_bd_id attribute and "
428 "aie.next_bd operation.");
429 error.attachNote(next_bd_op.getLoc())
430 << "Potentially conflicting next buffer descriptor ID specified "
431 "here.";
432 return failure();
433 }
434 Block &next_bd_block = *next_bd_op.getDest();
435 AIE::DMABDOp next_dma_bd_op = getBdForBlock(next_bd_block);
436 assert(next_dma_bd_op.getBdId()
437 .has_value()); // Next BD should have assigned ID, and this
438 // should have been checked by earlier
439 // verifyBdInBlock() call
440 bd_op.setNextBdId(next_dma_bd_op.getBdId().value());
441 OpBuilder builder(next_bd_op);
442 builder.create<AIE::EndOp>(next_bd_op.getLoc());
443 next_bd_op.erase();
444 }
445 }
446 return success();
447 }
448
449 LogicalResult rewriteSingleDMAConfigureTaskOp(DMAConfigureTaskOp op) {
450 OpBuilder builder(op);
451 AIE::TileOp tile = op.getTileOp();
452
453 if (!op.use_empty()) {
454 auto err = op.emitOpError("Cannot lower while op still has uses.");
455 mlir::Operation::use_range uses = op.getOperation()->getUses();
456 for (auto it = uses.begin(); it != uses.end(); ++it) {
457 err.attachNote(it->getOwner()->getLoc()) << "Used here.";
458 }
459 return failure();
460 }
461
462 Region &body = op.getBody();
463
464 // Verify each BD block first; subsequent functions rely on them being
465 // well-formed
466 for (auto it = body.begin(); it != body.end(); ++it) {
467 if (shouldSkipBlock(*it)) {
468 continue;
469 }
470 if (failed(verifyNoUnsupportedOpsInBlock(*it))) {
471 return failure();
472 }
473 if (failed(verifyBdInBlock(*it))) {
474 return failure();
475 }
476 if (failed(verifyOptionalLocksInBlock(*it))) {
477 return failure();
478 }
479 }
480
481 // Hoist next_bd operations into next_bd_id attribute of the dma_bd
482 if (failed(hoistNextBdOpsIntoAttrs(op))) {
483 return failure();
484 }
485
486 auto channelDir = op.getDirection();
487
488 // Lower all BDs
489 for (auto it = body.begin(); it != body.end(); ++it) {
490 Block &block = *it;
491 if (shouldSkipBlock(block)) {
492 continue;
493 }
494 if (failed(rewriteSingleBD(builder, block, tile, channelDir))) {
495 return failure();
496 }
497 }
498
499 op.erase();
500
501 return success();
502 }
503
504 LogicalResult rewriteDMAConfigureTaskOp(AIE::DeviceOp device) {
505 WalkResult result = device.walk([&](DMAConfigureTaskOp op) {
506 if (failed(rewriteSingleDMAConfigureTaskOp(op))) {
507 return WalkResult::interrupt();
508 }
509 return WalkResult::advance();
510 });
511 if (result.wasInterrupted()) {
512 return failure();
513 }
514 return success();
515 }
516
517 void runOnOperation() override {
518 AIE::DeviceOp device = getOperation();
519
520 // Convert DMAStartBD and DMAAwaitBD ops
521 ConversionTarget target(getContext());
522 target.addLegalDialect<AIEXDialect>();
523 target.addIllegalOp<DMAStartTaskOp>();
524 target.addIllegalOp<DMAAwaitTaskOp>();
525 RewritePatternSet patterns(&getContext());
526 patterns.insert<DMAStartTaskOpPattern>(&getContext());
527 patterns.insert<DMAAwaitTaskOpPattern>(&getContext());
528 if (failed(applyPartialConversion(device, target, std::move(patterns)))) {
529 signalPassFailure();
530 }
531
532 // Lower the configuration for the BDs
533 if (failed(rewriteDMAConfigureTaskOp(device))) {
534 signalPassFailure();
535 }
536 }
537};
538
539std::unique_ptr<OperationPass<AIE::DeviceOp>>
541 return std::make_unique<AIEDMATasksToNPUPass>();
542}
virtual bool isShimNOCTile(int col, int row) const =0
Return true if the given tile is a Shim NOC tile.
void getHardwareStridesWraps(const AIE::AIETargetModel &targetModel, 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)
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEDMATasksToNPUPass()
uint64_t getBufferDescriptorAddressRegisterAddress(const AIE::AIETargetModel &tm, unsigned bd_id, unsigned col, unsigned row)
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