20#include "mlir/Dialect/MemRef/IR/MemRef.h"
21#include "mlir/Dialect/SCF/IR/SCF.h"
22#include "mlir/Dialect/Utils/StaticValueUtils.h"
23#include "mlir/IR/PatternMatch.h"
24#include "mlir/Interfaces/SideEffectInterfaces.h"
25#include "mlir/Pass/Pass.h"
26#include "llvm/ADT/DenseSet.h"
27#include "llvm/ADT/SetVector.h"
28#include "llvm/Support/raw_ostream.h"
36#define GEN_PASS_DEF_AIEDECOMPOSELARGEDMABD
37#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
48static std::optional<NdDmaPattern> constantPattern(NpuDmaMemcpyNdOp op) {
49 std::optional<SmallVector<int64_t>> offsets =
50 getConstantIntValues(op.getMixedOffsets());
51 std::optional<SmallVector<int64_t>> sizes =
52 getConstantIntValues(op.getMixedSizes());
53 std::optional<SmallVector<int64_t>> strides =
54 getConstantIntValues(op.getMixedStrides());
55 if (!offsets || !sizes || !strides)
58 pattern.
offsets.assign(offsets->rbegin(), offsets->rend());
59 pattern.
sizes.assign(sizes->rbegin(), sizes->rend());
60 pattern.
strides.assign(strides->rbegin(), strides->rend());
64static SmallVector<int64_t, 4> toOuter(ArrayRef<int64_t> inner) {
65 return llvm::map_to_vector(llvm::reverse(inner), [](int64_t v) {
return v; });
68static int64_t flatOffsetFromPattern(int64_t baseFlatOffset,
70 int64_t flat = baseFlatOffset + pattern.
baseOffset;
71 for (
unsigned k = 0; k < 4; ++k)
76static int64_t lenFromInnermost3(ArrayRef<int64_t> sizesInnermostFirst) {
78 for (
unsigned i = 0; i < 3; ++i)
79 len *= sizesInnermostFirst[i];
83static AIE::BDDimLayoutArrayAttr outerDimsAttr(MLIRContext *ctx,
84 ArrayRef<int64_t> outerSizes,
85 ArrayRef<int64_t> outerStrides) {
86 SmallVector<AIE::BDDimLayoutAttr> dims;
87 dims.reserve(outerSizes.size());
88 for (
auto [s, t] : llvm::zip(outerSizes, outerStrides))
89 dims.push_back(AIE::BDDimLayoutAttr::get(ctx,
static_cast<uint32_t
>(s),
90 static_cast<uint32_t
>(t)));
91 return AIE::BDDimLayoutArrayAttr::get(ctx, dims);
94static void updateTaskBdInPlace(AIE::DMABDOp bd, int32_t offset, int32_t len,
95 ArrayRef<int64_t> outerSizes,
96 ArrayRef<int64_t> outerStrides) {
97 bd.getOffsetMutable().clear();
98 bd.setStaticOffset(offset);
99 bd.getLenMutable().clear();
100 bd.setStaticLen(len);
101 bd.getSizesMutable().clear();
102 bd.getStridesMutable().clear();
103 bd.setStaticSizes(DenseI64ArrayAttr::get(bd.getContext(), outerSizes));
104 bd.setStaticStrides(DenseI64ArrayAttr::get(bd.getContext(), outerStrides));
107static AIE::DMABDOp createTaskBd(RewriterBase &rewriter, Location loc,
108 AIE::DMABDOp tmpl, int32_t offset, int32_t len,
109 ArrayRef<int64_t> outerSizes,
110 ArrayRef<int64_t> outerStrides) {
111 auto dims = outerDimsAttr(rewriter.getContext(), outerSizes, outerStrides);
113 AIE::DMABDOp::create(rewriter, loc, tmpl.getBuffer(), offset, len, dims);
114 if (tmpl.getPacketAttr())
115 bd.setPacketAttr(tmpl.getPacketAttr());
116 if (tmpl.getBurstLengthAttr())
117 bd.setBurstLengthAttr(tmpl.getBurstLengthAttr());
118 if (tmpl.getAxcacheAttr())
119 bd.setAxcacheAttr(tmpl.getAxcacheAttr());
120 if (tmpl.getOffsetParameterAttr())
121 bd.setOffsetParameterAttr(tmpl.getOffsetParameterAttr());
128static int64_t iterationCount(
const NdDmaPattern &pattern) {
130 for (int64_t size : llvm::drop_begin(pattern.
sizes, 3))
140struct IterationScale {
144 bool isOne()
const {
return num == den; }
147 bool divides(int64_t runs)
const {
return runs % den == 0; }
148 int64_t apply(int64_t runs)
const {
return runs / den * num; }
149 std::string str()
const {
150 return den == 1 ? std::to_string(num)
151 : std::to_string(num) +
"/" + std::to_string(den);
155static IterationScale iterationScale(int64_t iterations,
157 int64_t common = std::gcd(after.
sizes[3], iterations);
158 return {after.
sizes[3] / common, iterations / common};
161static unsigned countTaskBds(DMAConfigureTaskLike taskOp) {
163 taskOp->walk([&](AIE::DMABDOp) { ++n; });
167static bool isUnderRuntimeControlFlow(AIE::DMABDOp op) {
168 auto seq = op->getParentOfType<AIE::RuntimeSequenceOp>();
171 for (Operation *parent = op->getParentOp(); parent && parent != seq;
172 parent = parent->getParentOp()) {
173 if (isa<scf::ForOp, scf::WhileOp, scf::IfOp>(parent))
179static std::optional<std::pair<AIE::TileOp, DMAConfigureTaskLike>>
180resolveTaskAndTile(AIE::DMABDOp op) {
181 if (
auto cfg = op->getParentOfType<DMAConfigureTaskOp>()) {
184 AIE::TileOp tile = cfg.tryGetTileOp();
187 return std::make_pair(tile, cast<DMAConfigureTaskLike>(*cfg));
189 if (
auto cfgFor = op->getParentOfType<DMAConfigureTaskForOp>()) {
190 AIE::DeviceOp dev = op->getParentOfType<AIE::DeviceOp>();
193 auto allocOp = AIE::ShimDMAAllocationOp::getForSymbol(
194 dev, cfgFor.getAlloc().getRootReference());
197 AIE::TileOp tile = allocOp.getTileOp();
200 return std::make_pair(tile, cast<DMAConfigureTaskLike>(*cfgFor));
205static NpuDmaMemcpyNdOp createDecomposedOp(RewriterBase &rewriter,
208 int64_t
id,
bool issueToken) {
210 "a memcpy pattern has no peeled dimensions");
211 auto newOp = NpuDmaMemcpyNdOp::create(
212 rewriter, op.getLoc(), op, toOuter(pattern.
offsets),
214 newOp.setIdAttr(rewriter.getI64IntegerAttr(
id));
215 newOp.setIssueTokenAttr(rewriter.getBoolAttr(issueToken));
219static int64_t allocateNextId(NpuDmaMemcpyNdOp op, int64_t startId,
220 llvm::DenseSet<int64_t> &usedIds) {
221 int64_t
id = startId;
222 while (usedIds.contains(
id))
231 int64_t group, index, count;
233 llvm::DenseMap<Operation *, Start> starts;
236 llvm::DenseSet<Operation *> lateTasks;
237 llvm::SetVector<Block *> blocks;
238 int64_t nextGroup = 0;
246static std::optional<std::string>
247whyNotSeparateTasks(AIE::DMABDOp bd, DMAConfigureTaskLike taskOp,
248 int64_t iterations) {
250 llvm::raw_string_ostream os(why);
251 if (bd.getBdIdVal()) {
252 os <<
"the descriptor's bd_id is a runtime value";
255 if (taskOp.getRepeatCountVal()) {
256 os <<
"the task's repeat count is a runtime value";
259 for (Operation *user : taskOp->getResult(0).getUsers()) {
260 if (!isa<DMAStartTaskOp, DMAAwaitTaskOp, DMAFreeTaskOp>(user)) {
261 os <<
"the task is used by '" << user->getName() <<
"'";
264 if (user->getBlock() != taskOp->getBlock()) {
265 os <<
"the task is used outside the block that configures it";
268 auto start = dyn_cast<DMAStartTaskOp>(user);
271 if (start.getRepeatCountVal()) {
272 os <<
"a start's repeat count is a runtime value";
275 if (start.hasRepeatParameter()) {
276 os <<
"a start's repeat count is a scratchpad parameter";
279 std::optional<uint32_t> rc = start.getRepeatCount();
280 int64_t runs =
static_cast<int64_t
>(rc ? *rc : taskOp.getRepeatCount());
282 if (runs % iterations != 0) {
283 os <<
"a start runs it " << runs
284 <<
" times, not a whole number of passes over its " << iterations
285 <<
"-long iteration dimension";
299static void splitIntoTasks(RewriterBase &rewriter, AIE::DMABDOp bd,
300 DMAConfigureTaskLike taskOp,
301 ArrayRef<NdDmaPattern> slices,
302 int64_t baseFlatOffset, int64_t iterations,
304 bool token = taskOp.getIssueToken();
305 int64_t taskRuns =
static_cast<int64_t
>(taskOp.getRepeatCount()) + 1;
306 SmallVector<Operation *> users(taskOp->getResult(0).getUsers());
308 SmallVector<DMAConfigureTaskLike> tasks{taskOp};
309 rewriter.setInsertionPointAfter(taskOp);
310 for (
size_t i = 1; i < slices.size(); ++i) {
311 tasks.push_back(cast<DMAConfigureTaskLike>(rewriter.clone(*taskOp)));
312 state.lateTasks.insert(tasks.back());
315 for (
auto it : llvm::enumerate(slices)) {
316 size_t i = it.index();
318 DMAConfigureTaskLike task = tasks[i];
319 AIE::DMABDOp sliceBd = bd;
321 task->walk([&](AIE::DMABDOp b) { sliceBd = b; });
322 int64_t flatOffset = flatOffsetFromPattern(baseFlatOffset, sub);
323 int32_t len =
static_cast<int32_t
>(lenFromInnermost3(sub.
sizes));
324 rewriter.modifyOpInPlace(sliceBd, [&]() {
325 updateTaskBdInPlace(sliceBd,
static_cast<int32_t
>(flatOffset), len,
329 sliceBd.removeBdIdAttr();
331 rewriter.modifyOpInPlace(task, [&]() {
334 task.setRepeatCount(
static_cast<uint32_t
>(sub.
sizes[3] - 1));
335 task.setIssueToken(token && i + 1 == slices.size());
339 for (Operation *user : users) {
340 if (
auto await = dyn_cast<DMAAwaitTaskOp>(user)) {
341 rewriter.modifyOpInPlace(await, [&]() {
342 await.getTaskMutable().assign(tasks.back()->getResult(0));
346 if (
auto free = dyn_cast<DMAFreeTaskOp>(user)) {
347 rewriter.setInsertionPointAfter(free);
348 for (DMAConfigureTaskLike task : llvm::drop_begin(tasks))
349 DMAFreeTaskOp::create(rewriter, free.getLoc(), task->getResult(0));
352 auto start = cast<DMAStartTaskOp>(user);
353 std::optional<uint32_t> rc = start.getRepeatCount();
354 int64_t runs = rc ?
static_cast<int64_t
>(*rc) + 1 : taskRuns;
355 int64_t count = runs / iterations *
static_cast<int64_t
>(slices.size());
356 int64_t group = state.nextGroup++;
359 bool startToken = token && !start.getNoToken();
360 auto mark = [&](DMAStartTaskOp s, int64_t index) {
361 state.starts[s] = {group, index, count};
363 rewriter.modifyOpInPlace(start, [&]() { start.removeRepeatCountAttr(); });
365 state.blocks.insert(start->getBlock());
366 rewriter.setInsertionPointAfter(start);
367 for (int64_t k = 1; k < count; ++k) {
368 size_t i =
static_cast<size_t>(k) % slices.size();
370 token && i + 1 == slices.size() && (!startToken || k + 1 != count);
371 auto s = DMAStartTaskOp::create(
372 rewriter, start.getLoc(), tasks[i]->getResult(0),
374 withholds ? rewriter.getUnitAttr() :
nullptr,
385static std::optional<ChannelKey> channelOf(DMAStartTaskOp start) {
386 Operation *def = start.getTask().getDefiningOp();
387 if (
auto cfg = dyn_cast_or_null<DMAConfigureTaskOp>(def)) {
388 if (AIE::TileOp tile = cfg.tryGetTileOp())
392 auto cfgFor = dyn_cast_or_null<DMAConfigureTaskForOp>(def);
395 auto dev = cfgFor->getParentOfType<AIE::DeviceOp>();
396 auto alloc = dev ? AIE::ShimDMAAllocationOp::getForSymbol(
397 dev, cfgFor.getAlloc().getRootReference())
398 :
AIE::ShimDMAAllocationOp();
399 AIE::TileOp tile = alloc ? alloc.getTileOp() : AIE::TileOp();
403 alloc.getChannelIndex());
417static void orderSlices(Block &block, Slices &state) {
419 DMAStartTaskOp start;
420 int64_t index, count, head;
422 SmallVector<Pending> pending;
423 llvm::DenseSet<Value> pendingTasks;
424 std::set<ChannelKey> round;
425 llvm::DenseMap<int64_t, int64_t> headOfGroup;
426 Operation *anchor =
nullptr;
430 llvm::stable_sort(pending, [](
const Pending &a,
const Pending &b) {
431 int64_t lhs = a.index * b.count;
432 int64_t rhs = b.index * a.count;
433 return lhs != rhs ? lhs < rhs : a.head < b.head;
435 Operation *after = anchor;
436 for (Pending &p : pending) {
437 p.start->moveAfter(after);
442 Operation *task = p.start.getTask().getDefiningOp();
443 if (task && state.lateTasks.erase(task))
444 task->moveBefore(p.start);
447 pendingTasks.clear();
453 for (Operation &op : llvm::make_early_inc_range(block)) {
454 if (
auto start = dyn_cast<DMAStartTaskOp>(op)) {
455 std::optional<ChannelKey> channel = channelOf(start);
456 auto it = state.starts.find(start);
457 std::optional<Slices::Start> slice;
458 if (it != state.starts.end())
460 if (channel && slice && slice->index > 0) {
461 auto head = headOfGroup.find(slice->group);
462 if (head != headOfGroup.end()) {
463 pending.push_back({start, slice->index, slice->count, head->second});
464 pendingTasks.insert(start.getTask());
468 if (!channel || round.count(*channel))
472 round.insert(*channel);
474 headOfGroup[slice->group] = heads;
479 if (
auto free = dyn_cast<DMAFreeTaskOp>(op)) {
480 if (pendingTasks.contains(free.getTask()))
484 if (isa<DMAConfigureTaskOp, DMAConfigureTaskForOp, NpuWriteRTPOp,
486 isMemoryEffectFree(&op))
493static void decomposeMemcpy(RewriterBase &rewriter, NpuDmaMemcpyNdOp op) {
494 std::optional<NdDmaPattern> constant = constantPattern(op);
498 if (op.getLengthParameterAttr() || op.getLengthStateTableIdxAttr())
505 AIE::DeviceOp dev = op->getParentOfType<AIE::DeviceOp>();
509 auto allocOp = AIE::ShimDMAAllocationOp::getForSymbol(
510 dev, op.getMetadata().getRootReference());
514 AIE::TileOp tile = allocOp.getTileOp();
518 int col = tile.getCol();
519 int row = tile.getRow();
521 auto bufferType = cast<BaseMemRefType>(op.getMemref().getType());
531 if (failed(decomposed) ||
536 SmallVector<NdDmaPattern> &bds =
538 if (bds.size() > targetModel.
getNumBDs(col, row))
541 rewriter.setInsertionPoint(op);
542 if (bds.size() == 1) {
543 rewriter.replaceOpWithNewOp<NpuDmaMemcpyNdOp>(
544 op, op, toOuter(bds.front().offsets), toOuter(bds.front().sizes),
545 toOuter(bds.front().strides));
549 llvm::DenseSet<int64_t> usedIds;
550 if (
auto seq = op->getParentOfType<AIE::RuntimeSequenceOp>()) {
551 seq.walk([&](NpuDmaMemcpyNdOp other) {
554 if (other.getMetadata() == op.getMetadata())
555 usedIds.insert(other.getId());
559 int64_t nextId = op.getId();
560 for (
auto [idx, subPattern] : llvm::enumerate(bds)) {
561 bool last = idx + 1 == bds.size();
562 int64_t
id = allocateNextId(op, nextId, usedIds);
564 createDecomposedOp(rewriter, op, subPattern,
id,
565 last && op.getIssueToken());
567 rewriter.eraseOp(op);
572static LogicalResult decomposeTaskBd(RewriterBase &rewriter, AIE::DMABDOp op,
574 auto taskAndTile = resolveTaskAndTile(op);
578 AIE::TileOp tile = taskAndTile->first;
579 DMAConfigureTaskLike taskOp = taskAndTile->second;
583 bool tooManyDims = op.getMixedSizes().size() > kNdDmaDims;
584 auto cannotReduce = [&]() {
585 return op.emitOpError()
586 <<
"has " << op.getMixedSizes().size()
587 <<
" dimensions, and a buffer descriptor holds " << kNdDmaDims
588 <<
"; the extra ones can only be split off ";
590 int col = tile.getCol();
591 int row = tile.getRow();
593 FailureOr<TaskBdDecomposition> plan =
597 return cannotReduce()
598 <<
"a descriptor whose offset, length, sizes and strides are "
599 "all constant and that has no padding";
602 if (countTaskBds(taskOp) != 1) {
604 return cannotReduce() <<
"a task's only descriptor";
609 bool takesLocks =
false;
610 taskOp->walk([&](AIE::UseLockOp) { takesLocks =
true; });
613 return cannotReduce() <<
"a descriptor that takes no locks";
617 if (op.getLengthParameterAttr() || op.getLengthStateTableIdxAttr())
625 if (op.getIteration())
626 return op.emitOpError()
627 <<
"buffer descriptor with the iteration attribute is too large "
628 "to lower and cannot be decomposed";
632 iterationCount(plan->pass);
635 SmallVector<NdDmaPattern> &bds =
639 return op.emitOpError()
640 <<
"has " << op.getMixedSizes().size()
641 <<
" dimensions, and no split into at most " << kMaxNdDmaPieces
642 <<
" descriptors of " << kNdDmaDims <<
" fits this tile";
646 int64_t baseFlatOffset = op.getConstantOffset().value_or(0);
648 if (bds.size() == 1) {
650 int64_t flatOffset = flatOffsetFromPattern(baseFlatOffset, sub);
651 auto outerSizes = toOuter(sub.
sizes);
652 auto outerStrides = toOuter(sub.
strides);
658 int32_t len =
static_cast<int32_t
>(lenFromInnermost3(sub.
sizes));
660 IterationScale scale = iterationScale(iterations, sub);
662 if (!scale.isOne()) {
663 if (taskOp.getRepeatCountVal())
664 return op.emitOpError()
665 <<
"cannot decompose a buffer descriptor whose repeat count "
666 "is a runtime value: decomposition needs to scale it by "
673 auto check = [&](Operation *at, int64_t repeat, StringRef runner,
674 StringRef count) -> LogicalResult {
675 int64_t before = repeat + 1;
676 if (!scale.divides(before))
677 return at->emitOpError()
678 <<
"cannot decompose: it merges every " << scale.den
679 <<
" executions of the buffer descriptor into " << scale.num
680 <<
", and " << runner <<
" runs it " << before <<
" times";
681 int64_t after = scale.apply(before);
682 if (after - 1 > std::numeric_limits<int32_t>::max())
683 return at->emitOpError()
684 <<
"decomposition scales " << count <<
" by " << scale.str()
685 <<
" to " << (after - 1) <<
", beyond a 32-bit repeat_count";
688 runs = taskOp.getRepeatCount() + int64_t{1};
689 if (failed(check(op, runs - 1,
"the task",
"the repeat count")))
693 for (Operation *user : taskOp->getResult(0).getUsers()) {
694 auto start = dyn_cast<DMAStartTaskOp>(user);
697 if (start.getRepeatCountVal() || start.hasRepeatParameter())
698 return start.emitOpError()
699 <<
"cannot decompose a buffer descriptor this start repeats "
700 "a runtime number of times: decomposition needs to scale "
703 if (IntegerAttr rc = start.getRepeatCountAttr())
704 if (failed(check(start, rc.getInt(),
"this start",
705 "this start's repeat count")))
708 runs = scale.apply(runs);
711 rewriter.modifyOpInPlace(op, [&]() {
712 updateTaskBdInPlace(op,
static_cast<int32_t
>(flatOffset), len, outerSizes,
715 if (!scale.isOne()) {
716 rewriter.modifyOpInPlace(taskOp, [&]() {
717 taskOp.setRepeatCount(
static_cast<uint32_t
>(runs - 1));
719 for (Operation *user : taskOp->getResult(0).getUsers())
720 if (
auto start = dyn_cast<DMAStartTaskOp>(user))
721 if (IntegerAttr rc = start.getRepeatCountAttr())
722 rewriter.modifyOpInPlace(start, [&]() {
723 start.setRepeatCountAttr(
724 rewriter.getI32IntegerAttr(scale.apply(rc.getInt() + 1) - 1));
732 if (op.getOutOfOrderId().has_value())
733 return op.emitOpError() <<
"splitting an out-of-order buffer descriptor "
734 "into multiple descriptors is not implemented";
743 bool sharedRepeat = llvm::all_of(bds, [&](
const NdDmaPattern &sub) {
744 return iterationScale(iterations, sub).isOne();
747 sharedRepeat && bds.size() <= targetModel.
getNumBDs(col, row);
749 if (!chainFits || (depth > 0 && bds.size() > depth)) {
752 if (isUnderRuntimeControlFlow(op)) {
754 return cannotReduce()
755 <<
"outside runtime control flow, since its " << bds.size()
756 <<
" pieces have to be separate tasks";
757 op.emitRemark() <<
"deferring decomposition into " << bds.size()
758 <<
" separate tasks under runtime control flow";
761 std::optional<std::string> why =
762 whyNotSeparateTasks(op, taskOp, iterations);
764 splitIntoTasks(rewriter, op, taskOp, bds, baseFlatOffset, iterations,
769 return op.emitOpError()
770 <<
"cannot split this buffer descriptor: its slices need "
771 "per-descriptor repeat counts, which a chain shares, and "
772 "they cannot be separate tasks because "
775 return op.emitOpError()
776 <<
"cannot split this buffer descriptor: its " << bds.size()
777 <<
" slices outnumber the tile's "
779 <<
" buffer descriptors, and they cannot be separate tasks "
784 Region *body = &taskOp.getBody();
788 SmallVector<Block *> blocks;
789 blocks.push_back(op->getBlock());
790 for (
unsigned i = 1; i < bds.size(); ++i)
791 blocks.push_back(rewriter.createBlock(body));
793 for (
auto [idx, subPattern] : llvm::enumerate(bds)) {
794 Block *block = blocks[idx];
795 int64_t flatOffset = flatOffsetFromPattern(baseFlatOffset, subPattern);
796 auto outerSizes = toOuter(subPattern.sizes);
797 auto outerStrides = toOuter(subPattern.strides);
798 int32_t len =
static_cast<int32_t
>(lenFromInnermost3(subPattern.sizes));
801 rewriter.modifyOpInPlace(op, [&]() {
802 updateTaskBdInPlace(op,
static_cast<int32_t
>(flatOffset), len,
803 outerSizes, outerStrides);
805 Operation *oldTerm = block->getTerminator();
806 rewriter.setInsertionPoint(oldTerm);
807 if (idx + 1 < bds.size())
808 AIE::NextBDOp::create(rewriter, op.getLoc(), blocks[idx + 1]);
810 AIE::EndOp::create(rewriter, op.getLoc());
811 rewriter.eraseOp(oldTerm);
813 rewriter.setInsertionPointToStart(block);
814 createTaskBd(rewriter, op.getLoc(), op,
static_cast<int32_t
>(flatOffset),
815 len, outerSizes, outerStrides);
816 rewriter.setInsertionPointToEnd(block);
817 if (idx + 1 < bds.size())
818 AIE::NextBDOp::create(rewriter, op.getLoc(), blocks[idx + 1]);
820 AIE::EndOp::create(rewriter, op.getLoc());
827struct AIEDecomposeLargeDmaBdPass
828 : xilinx::AIEX::impl::AIEDecomposeLargeDmaBdBase<
829 AIEDecomposeLargeDmaBdPass> {
830 void runOnOperation()
override {
831 AIE::DeviceOp device = getOperation();
832 IRRewriter rewriter(&getContext());
833 SmallVector<NpuDmaMemcpyNdOp> memcpys;
834 SmallVector<AIE::DMABDOp> bds;
835 device.walk([&](Operation *op) {
836 if (
auto memcpy = dyn_cast<NpuDmaMemcpyNdOp>(op))
837 memcpys.push_back(memcpy);
838 else if (
auto bd = dyn_cast<AIE::DMABDOp>(op))
841 for (NpuDmaMemcpyNdOp memcpy : memcpys)
842 decomposeMemcpy(rewriter, memcpy);
845 for (AIE::DMABDOp bd : bds)
846 failed |= mlir::failed(decomposeTaskBd(rewriter, bd, slices));
848 return signalPassFailure();
849 for (Block *block : slices.blocks)
850 orderSlices(*block, slices);
856std::unique_ptr<OperationPass<AIE::DeviceOp>>
858 return std::make_unique<AIEDecomposeLargeDmaBdPass>();
std::array< int, 4 > ChannelKey
{col, row, direction, channel}.
static ChannelKey keyOf(AIE::TileOp tile, AIE::DMAChannelDir direction, int64_t channel)
virtual uint32_t getDmaTaskQueueDepth() const =0
Return how many DMA tasks a single channel's task queue holds (unsupported = 0).
virtual uint32_t getNumBDs(AIETileType tileType) const =0
Return the number of buffer descriptors for a given tile type.
bool isContiguousTransfer(llvm::ArrayRef< int64_t > sizes, llvm::ArrayRef< int64_t > strides)
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEDecomposeLargeDmaBdPass()
mlir::FailureOr< llvm::SmallVector< NdDmaPattern > > decomposeNdDmaPattern(mlir::Operation *forOp, mlir::BaseMemRefType referencedBufType, const NdDmaPattern &pattern, const xilinx::AIE::AIETargetModel &targetModel, int tileCol, int tileRow)
Decompose an illegal pattern into one or more legal sub-patterns that move the same data.
mlir::FailureOr< TaskBdDecomposition > decomposeTaskBdPattern(xilinx::AIE::DMABDOp bd, const xilinx::AIE::AIETargetModel &targetModel, int tileCol, int tileRow)
Plan the split of bd, a runtime task's descriptor, on tile (tileCol, tileRow).
bool patternPassesVerification(mlir::Operation *forOp, mlir::BaseMemRefType referencedBufType, const xilinx::AIE::AIETargetModel &tm, int tileCol, int tileRow, const NdDmaPattern &pattern, bool skipTransformationChecks=false)
Returns true when the pattern passes verifyStridesWraps for the given tile and memref element type.
const AIETargetModel & getTargetModel(mlir::Operation *op)
Innermost-first ND access pattern (d0..d3 / repeat), matching the convention used by verifyStridesWra...
llvm::SmallVector< int64_t, kNdDmaDims > sizes
int64_t baseOffset
Elements added to the address the offsets give.
llvm::SmallVector< int64_t, kNdDmaDims > offsets
llvm::SmallVector< int64_t, kNdDmaDims > strides