54#include "mlir/IR/BuiltinAttributes.h"
55#include "mlir/IR/BuiltinOps.h"
56#include "mlir/Pass/Pass.h"
58#include "llvm/ADT/DenseMap.h"
59#include "llvm/ADT/DenseSet.h"
60#include "llvm/ADT/SmallVector.h"
61#include "llvm/ADT/StringMap.h"
62#include "llvm/ADT/StringRef.h"
71#define GEN_PASS_DEF_AIEOBJECTFIFOLIVENESS
72#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
75#define DEBUG_TYPE "aie-objectfifo-liveness"
86static StringRef nameBase(StringRef name) {
87 size_t us = name.rfind(
'_');
88 if (us == StringRef::npos || us + 1 >= name.size())
90 StringRef suffix = name.substr(us + 1);
92 if (c <
'0' || c >
'9')
94 return name.substr(0, us);
97struct AIEObjectFifoLivenessPass
98 : xilinx::AIE::impl::AIEObjectFifoLivenessBase<AIEObjectFifoLivenessPass> {
99 void runOnOperation()
override {
100 DeviceOp mod = getOperation();
106 SmallVector<mlir::Value> cons;
111 SmallVector<F> fifos;
113 mod.walk([&](xilinx::AIE::ObjectFifoCreateOp ofo) {
117 auto depthInt = dyn_cast<IntegerAttr>(ofo.getElemNumber());
122 f.name = ofo.getSymName();
123 f.depth = depthInt.getInt();
124 f.prod = ofo.getProducerTile();
125 for (mlir::Value c : ofo.getConsumerTiles())
128 if (
auto rc = ofo.getRepeatCount())
130 f.elemTy = ofo.getElemType();
134 unsigned n = fifos.size();
139 mlir::DenseMap<mlir::Value, SmallVector<unsigned>> consumes, produces;
140 for (
unsigned i = 0; i < n; ++i) {
141 produces[fifos[i].prod].push_back(i);
142 for (mlir::Value c : fifos[i].cons)
143 consumes[c].push_back(i);
145 std::vector<std::set<unsigned>> adj(n);
146 mlir::DenseSet<mlir::Value> tiles;
147 for (
auto &kv : consumes)
148 tiles.insert(kv.first);
149 for (
auto &kv : produces)
150 tiles.insert(kv.first);
151 for (mlir::Value tile : tiles) {
152 auto &ins = consumes[tile];
153 auto &outs = produces[tile];
154 for (
unsigned o : outs)
155 for (
unsigned i : ins) {
167 SmallVector<int> uf(n);
168 for (
unsigned i = 0; i < n; ++i)
170 std::function<int(
int)> find = [&](
int x) {
177 for (
unsigned v = 0; v < n; ++v)
178 for (
unsigned w : adj[v])
179 uf[find(v)] = find(w);
180 SmallVector<int> compSize(n, 0);
181 for (
unsigned i = 0; i < n; ++i)
183 SmallVector<int> sccId(n, -1);
184 for (
unsigned i = 0; i < n; ++i)
185 if (compSize[find(i)] > 1)
209 long fan = 0, depth = 0;
215 llvm::DenseSet<mlir::Value> cons;
218 SmallVector<Group> groupList;
219 llvm::StringMap<unsigned>
221 for (
unsigned i = 0; i < n; ++i) {
222 if (sccId[i] < 0 || fifos[i].cons.size() <= 1)
224 StringRef base = nameBase(fifos[i].name);
226 auto it = groupIdx.find(base);
227 if (it != groupIdx.end()) {
228 Group &cand = groupList[it->second];
229 bool consistent = cand.elemTy == fifos[i].elemTy &&
230 cand.sigDepth == fifos[i].depth &&
231 cand.sigRepeat == fifos[i].repeat;
232 for (mlir::Value c : fifos[i].cons)
233 if (consistent && cand.cons.contains(c))
245 g.elemTy = fifos[i].elemTy;
246 g.sigDepth = fifos[i].depth;
247 g.sigRepeat = fifos[i].repeat;
248 g.depth = fifos[i].depth;
249 groupList.push_back(std::move(g));
250 slot = (int)groupList.size() - 1;
251 if (it == groupIdx.end())
252 groupIdx[base] = slot;
254 groupList[slot].depth = std::min(groupList[slot].depth, fifos[i].depth);
256 Group &g = groupList[slot];
257 g.fan += (long)fifos[i].cons.size();
258 for (mlir::Value c : fifos[i].cons)
260 g.sccs.insert(sccId[i]);
270 for (Group &g : groupList) {
272 for (
unsigned i = 0; i < n; ++i)
273 if (sccId[i] >= 0 && g.sccs.count(sccId[i]))
274 T = std::max(T, fifos[i].repeat);
275 long demand = g.fan * T;
276 long slack = 2 * g.depth;
277 if (g.depth <= 0 || T < 2 || demand <= slack)
279 long reqDepth = (demand + 1) / 2;
280 fifos[g.rep].op->emitError()
281 <<
"objectFIFO @" << g.name
282 <<
" in a cyclic dependency requires depth >= " << reqDepth
283 <<
" for deadlock-free execution; allocated depth = " << g.depth
284 <<
". (Coupled broadcast fan-out " << g.fan <<
" x trip-count " << T
286 <<
" outstanding tokens exceeds round-trip slack 2*depth = " << slack
287 <<
"; raise depth or reduce coupled consumers / output tiles.)";
296std::unique_ptr<OperationPass<DeviceOp>>
298 return std::make_unique<AIEObjectFifoLivenessPass>();
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIEObjectFifoLivenessPass()