MLIR-AIE 1.4.5.dev
AIEShimSharing.cpp
Go to the documentation of this file.
1//===- AIEShimSharing.cpp ---------------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2026 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
10
11#include "mlir/Interfaces/LoopLikeInterface.h"
12#include "llvm/ADT/STLExtras.h"
13
14using namespace mlir;
15using namespace xilinx;
16using namespace xilinx::AIE;
17
19 DeviceOp device, function_ref<std::optional<End>(StringAttr)> endOf) {
20 for (auto sequence : device.getOps<RuntimeSequenceOp>()) {
21 DenseMap<Operation *, int64_t> position, end;
22 int64_t next = 0;
23 std::function<void(Operation *)> number = [&](Operation *op) {
24 position[op] = next++;
25 for (Region &region : op->getRegions())
26 for (Block &block : region)
27 for (Operation &nested : block)
28 number(&nested);
29 end[op] = next - 1;
30 };
31 number(sequence);
32
33 auto &byFifo = spans.emplace_back();
34 DenseMap<Value, AIEX::DMAConfigureTaskForOp> tasks;
35 auto note = [&](Operation *op, StringAttr symbol, bool issues) {
36 std::optional<End> shimEnd = endOf(symbol);
37 if (!shimEnd)
38 return;
39 int64_t from = position[op], to = position[op];
40 for (Operation *parent = op->getParentOp(); parent != sequence;
41 parent = parent->getParentOp())
42 if (isa<LoopLikeOpInterface>(parent)) {
43 from = position[parent];
44 to = end[parent];
45 }
46 Span &span = byFifo[shimEnd->fifo];
47 span.sends |= shimEnd->sends;
48 span.first = std::min(span.first, from);
49 span.last = std::max(span.last, to);
50 int64_t &mark = issues ? span.lastIssue : span.lastDone;
51 mark = std::max(mark, to);
52 };
53 auto noteTask = [&](Operation *op, Value task, bool issues) {
54 if (auto configure = tasks.lookup(task))
55 note(op, configure.getAlloc().getRootReference(), issues);
56 };
57 sequence.walk([&](Operation *op) {
58 if (auto memcpy = dyn_cast<AIEX::NpuDmaMemcpyNdOp>(op))
59 note(op, memcpy.getMetadata().getRootReference(), true);
60 else if (auto wait = dyn_cast<AIEX::NpuDmaWaitOp>(op))
61 note(op, wait.getSymbolAttr().getAttr(), false);
62 else if (auto configure = dyn_cast<AIEX::DMAConfigureTaskForOp>(op))
63 tasks[configure.getResult()] = configure;
64 else if (auto start = dyn_cast<AIEX::DMAStartTaskOp>(op))
65 noteTask(op, start.getTask(), true);
66 else if (auto await = dyn_cast<AIEX::DMAAwaitTaskOp>(op))
67 noteTask(op, await.getTask(), false);
68 // Freeing a task lets its BD ids be reused, which is only safe once its
69 // transfers are done.
70 else if (auto free = dyn_cast<AIEX::DMAFreeTaskOp>(op))
71 noteTask(op, free.getTask(), false);
72 });
73 }
74}
75
76bool ShimTransferSpans::apart(StringAttr a, StringAttr b) const {
77 if (a == b)
78 return false;
79 // An end no sequence names is driven some other way, so nothing is known
80 // about when it is in flight.
81 bool aUsed = false, bUsed = false;
82 for (auto &byFifo : spans) {
83 auto sa = byFifo.find(a), sb = byFifo.find(b);
84 aUsed |= sa != byFifo.end();
85 bUsed |= sb != byFifo.end();
86 if (sa == byFifo.end() || sb == byFifo.end())
87 continue;
88 auto before = [](const Span &x, const Span &y) {
89 return !x.sends && x.last < y.first && x.lastDone > x.lastIssue;
90 };
91 if (!before(sa->second, sb->second) && !before(sb->second, sa->second))
92 return false;
93 }
94 return aUsed && bUsed;
95}
96
97SmallVector<SmallVector<unsigned>>
98ShimTransferSpans::groups(ArrayRef<StringAttr> ends) const {
99 auto order = llvm::to_vector(llvm::seq<unsigned>(0, ends.size()));
100 llvm::stable_sort(order, [&](unsigned x, unsigned y) {
101 return ends[x].getValue() < ends[y].getValue();
102 });
103 SmallVector<SmallVector<unsigned>> result;
104 for (unsigned end : order) {
105 auto *group = llvm::find_if(result, [&](ArrayRef<unsigned> members) {
106 return llvm::all_of(
107 members, [&](unsigned m) { return apart(ends[m], ends[end]); });
108 });
109 if (group == result.end())
110 result.push_back({end});
111 else
112 group->push_back(end);
113 }
114 return result;
115}
ShimTransferSpans(DeviceOp device, llvm::function_ref< std::optional< End >(mlir::StringAttr)> endOf)
endOf maps a symbol a runtime sequence transfers through to the objectFIFO end it belongs to,...
bool apart(mlir::StringAttr a, mlir::StringAttr b) const
Whether the ends of a and b are never in flight together.
llvm::SmallVector< llvm::SmallVector< unsigned > > groups(llvm::ArrayRef< mlir::StringAttr > ends) const
Splits ends into groups whose members are pairwise apart, each group taking one channel: first fit,...