11#include "mlir/IR/Attributes.h"
12#include "mlir/Pass/Pass.h"
19#define GEN_PASS_DEF_AIEOBJECTFIFOLOWERDMAS
20#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
31 BDDimLayoutArrayAttr dimensions;
32 BDPadLayoutArrayAttr padding;
33 FlatSymbolRefAttr acquireLock;
34 FlatSymbolRefAttr releaseLock;
39 std::optional<int64_t> acquireValue = std::nullopt;
40 std::optional<int64_t> releaseValue = std::nullopt;
43 BDIterationAttr iteration =
nullptr;
46Block *findEndOpBlock(Region ®ion) {
47 Block *endBlock =
nullptr;
48 for (Block &block : region) {
49 if (!block.getOps<EndOp>().empty()) {
56struct AIEObjectFifoLowerDMAsPass
57 :
public xilinx::AIE::impl::AIEObjectFifoLowerDMAsBase<
58 AIEObjectFifoLowerDMAsPass> {
61 OpBuilder builder{
static_cast<MLIRContext *
>(
nullptr)};
64 DmaBody dmaProgramFor(TileLike tile, Location loc) {
65 Value wanted = tile->getResult(0);
66 for (
auto program : device.getOps<DmaBody>()) {
67 if (program.getTile() == wanted) {
72 OpBuilder::InsertionGuard g(builder);
73 builder.setInsertionPoint(device.getBody()->getTerminator());
75 if (tile.isShimTile()) {
76 program = ShimDMAOp::create(builder, loc, builder.getIndexType(), wanted);
77 }
else if (tile.isMemTile()) {
78 program = MemTileDMAOp::create(builder, loc, wanted);
80 program = MemOp::create(builder, loc, wanted);
83 builder.setInsertionPointToStart(&program.getDmaBody().emplaceBlock());
84 EndOp::create(builder, loc);
89 SmallVector<Value> buffersOf(ObjectFifoPoolOp pool) {
90 SmallVector<Value> buffers;
91 for (BufferLike buffer : pool.getBufferOps()) {
92 buffers.push_back(buffer.getBuffer());
101 SmallVector<Descriptor>
102 contiguousDescriptors(ObjectFifoDmaEndpointOp endpoint, Value buffer,
104 ObjectFifoPoolOp pool = endpoint.getPoolOp();
105 ObjectFifoSegmentOp segment = endpoint.getSelectedSegments().front();
106 FlatSymbolRefAttr take =
107 drains ? segment.getConsumeLockAttr() : segment.getProduceLockAttr();
108 FlatSymbolRefAttr give =
109 drains ? segment.getProduceLockAttr() : segment.getConsumeLockAttr();
110 MLIRContext *context = builder.getContext();
111 if (!endpoint.walksStream()) {
112 BDDimLayoutArrayAttr dims;
113 if (
auto all = endpoint.getDimensions(); all && !all->empty())
115 int64_t
object = pool.getObjectSize();
117 if (
auto zeros = pool.getZeroObjects())
118 first = (*zeros)[0] * object;
119 int64_t walkers = endpoint.getNumDescriptors();
120 SmallVector<Descriptor> descriptors;
121 for (int64_t j = 0; j < walkers; j++)
122 descriptors.push_back(
123 {buffer, first + j * object + segment.getOffset(),
124 segment.getSize(), dims, BDPadLayoutArrayAttr(), take, give, j,
125 std::nullopt, std::nullopt,
126 BDIterationAttr::get(context, pool.getDepth() / walkers,
127 walkers * object, 0)});
132 if (failed(endpoint.getStreamWindow(window)))
134 BDDimLayoutArrayAttr dims =
135 BDDimLayoutArrayAttr::get(context, window.
inner);
136 SmallVector<Descriptor> descriptors;
138 descriptors.push_back({buffer, step.first * window.
objectSize,
139 window.
transfer(), dims, BDPadLayoutArrayAttr(),
140 take, give, 0, step.acquire, step.release,
147 SmallVector<Descriptor> descriptorsFor(ObjectFifoDmaEndpointOp endpoint,
148 ArrayRef<Value> buffers,
bool drains) {
149 if (endpoint.getPoolOp().getContiguous())
150 return contiguousDescriptors(endpoint, buffers.front(), drains);
151 std::vector<ObjectFifoSegmentOp> segments = endpoint.getSelectedSegments();
152 SmallVector<BDDimLayoutArrayAttr> dimensions;
153 if (
auto allDimensions = endpoint.getDimensions()) {
154 llvm::append_range(dimensions, *allDimensions);
156 SmallVector<BDPadLayoutArrayAttr> padding;
157 if (
auto allPadding = endpoint.getPadDimensions()) {
158 llvm::append_range(padding, *allPadding);
161 SmallVector<Descriptor> descriptors;
162 for (
auto [index, buffer] : llvm::enumerate(buffers)) {
163 for (
auto [position, segment] : llvm::enumerate(segments)) {
164 descriptors.push_back(
165 {buffer, segment.getOffset(), segment.getSize(),
166 position < dimensions.size() ? dimensions[position]
167 : BDDimLayoutArrayAttr(),
168 position < padding.size() ? padding[position]
169 : BDPadLayoutArrayAttr(),
170 drains ? segment.getConsumeLockAttr()
171 : segment.getProduceLockAttr(),
172 drains ? segment.getProduceLockAttr()
173 : segment.getConsumeLockAttr(),
174 static_cast<int64_t
>(index)});
180 void emitDescriptor(ObjectFifoDmaEndpointOp endpoint, ObjectFifoPoolOp pool,
181 Descriptor &descriptor, PacketInfoAttr packet,
182 Block *successor,
bool binaryLocks,
bool drains) {
183 Location loc = endpoint.getLoc();
184 int count = drains ? 1 : pool.getRepeatCount().value_or(1);
186 LockOp acquireLock, releaseLock;
187 int acquireValue = count, releaseValue = count;
188 auto action = LockAction::AcquireGreaterEqual;
191 SmallVector<LockOp> locks = pool.getLockOps();
192 if (descriptor.object < (int64_t)locks.size()) {
193 acquireLock = releaseLock = locks[descriptor.object];
194 acquireValue = drains ? 1 : 0;
195 releaseValue = drains ? 0 : 1;
196 action = LockAction::Acquire;
198 }
else if (descriptor.acquireLock) {
205 if (descriptor.acquireValue)
206 acquireValue = *descriptor.acquireValue;
207 if (descriptor.releaseValue)
208 releaseValue = *descriptor.releaseValue;
210 UseLockOp::create(builder, loc, acquireLock, action, acquireValue);
213 DMABDPACKETOp::create(builder, loc, packet.getPktType(),
214 packet.assignedId());
218 if (descriptor.dimensions && drains && descriptor.padding) {
219 bd = DMABDOp::create(builder, loc, descriptor.buffer, descriptor.offset,
220 paddedSize(descriptor.dimensions, descriptor.padding,
222 descriptor.dimensions, descriptor.padding);
223 }
else if (descriptor.dimensions) {
224 bd = DMABDOp::create(builder, loc, descriptor.buffer, descriptor.offset,
225 descriptor.size, descriptor.dimensions);
227 bd = DMABDOp::create(builder, loc, descriptor.buffer, descriptor.offset,
230 if (descriptor.iteration && descriptor.iteration.getSize() > 1)
231 bd.setIterationAttr(descriptor.iteration);
234 UseLockOp::create(builder, loc, releaseLock, LockAction::Release,
237 NextBDOp::create(builder, loc, successor);
242 std::pair<Block *, Block *> startChain(ObjectFifoDmaEndpointOp endpoint,
243 int channel,
int taskCount) {
244 Location loc = endpoint.getLoc();
245 DmaBody program = dmaProgramFor(endpoint.getTileLike(), loc);
246 Block *endBlock = findEndOpBlock(program.getDmaBody());
247 Block *lastDmaBlock = endBlock->getSinglePredecessor();
248 Block *dmaBlock = builder.createBlock(endBlock);
249 Block *bdBlock = builder.createBlock(endBlock);
251 builder.setInsertionPointToStart(dmaBlock);
252 DMAStartOp::create(builder, loc, endpoint.getRouteDirection(), channel,
253 taskCount, endpoint.getPadValue(),
254 false, bdBlock, endBlock);
256 lastDmaBlock->getTerminator()->setSuccessor(dmaBlock, 1);
258 return {bdBlock, endBlock};
263 LogicalResult lowerTurns(ObjectFifoDmaEndpointOp first,
int channel) {
264 SmallVector<ObjectFifoDmaEndpointOp> ends =
turnEndpoints(first);
265 SmallVector<SmallVector<Descriptor>> descriptors;
266 for (ObjectFifoDmaEndpointOp end : ends) {
267 descriptors.push_back(
268 descriptorsFor(end, buffersOf(end.getPoolOp()), end.drains()));
269 if (
static_cast<int64_t
>(descriptors.back().size()) !=
270 end.getNumDescriptors() ||
271 descriptors.back().empty())
272 return end.emitOpError(
"takes turns, but lowers to ")
273 << descriptors.back().size() <<
" descriptors per pass for "
274 << end.getNumDescriptors();
276 SmallVector<unsigned> turns;
277 for (
auto name : first.getTurnsAttr().getAsRange<FlatSymbolRefAttr>())
278 turns.push_back(llvm::find_if(ends,
279 [&](ObjectFifoDmaEndpointOp end) {
280 return end.getSymNameAttr() ==
285 auto [bdBlock, endBlock] = startChain(first, channel, 0);
286 bool binaryLocks = !device.getTargetModel().hasProperty(
288 SmallVector<size_t> next(ends.size(), 0);
289 int64_t total = first.getNumBDs();
290 Block *current = bdBlock;
291 for (int64_t k = 0; k < total; k++) {
292 unsigned i = turns[k % turns.size()];
294 k + 1 < total ? builder.createBlock(endBlock) : bdBlock;
295 builder.setInsertionPointToStart(current);
296 emitDescriptor(ends[i], ends[i].getPoolOp(), descriptors[i][next[i]],
297 PacketInfoAttr(), successor, binaryLocks,
299 next[i] = (next[i] + 1) % descriptors[i].size();
305 LogicalResult lowerEndpoint(ObjectFifoDmaEndpointOp endpoint,
int channel) {
306 bool drains = endpoint.drains();
307 ObjectFifoPoolOp pool = endpoint.getPoolOp();
308 SmallVector<Value> buffers = buffersOf(pool);
309 if (buffers.empty()) {
313 SmallVector<Descriptor> descriptors =
314 descriptorsFor(endpoint, buffers, drains);
315 if (descriptors.empty()) {
319 if (
static_cast<int64_t
>(descriptors.size()) !=
320 endpoint.getNumDescriptors())
321 return endpoint.emitOpError()
322 <<
"lowers to " << descriptors.size()
323 <<
" descriptors per pass, but its channel was allocated for "
324 << endpoint.getNumDescriptors();
326 Location loc = endpoint.getLoc();
328 int64_t repeat = endpoint.getRepeat();
329 std::optional<int32_t> iterCount = endpoint.getIterCount();
331 bool repeatInHardware = endpoint.repeatsInHardware();
334 int64_t passes = endpoint.getDispatchPasses();
335 int taskCount = iterCount ? *iterCount / passes - 1
336 : (repeatInHardware ? repeat - 1 : 0);
337 int64_t copies = repeatInHardware ? 1 : repeat;
338 SmallVector<PacketInfoAttr> turns;
339 if (std::optional<ArrayAttr> headers = endpoint.getDispatchPackets()) {
340 llvm::append_range(turns, headers->getAsRange<PacketInfoAttr>());
341 }
else if (endpoint.getDispatch()) {
342 return endpoint.emitOpError(
343 "has no dispatchPackets; run --aie-objectfifo-allocate");
347 if (!turns.empty() && pool.getContiguous())
348 return endpoint.emitOpError(
349 "dispatches from a contiguous pool, which has no per-object BDs");
350 int64_t depth = pool.getDepth();
352 auto [bdBlock, endBlock] = startChain(endpoint, channel, taskCount);
353 bool binaryLocks = !device.getTargetModel().hasProperty(
355 size_t total = descriptors.size() * copies * passes;
357 Block *current = bdBlock;
358 for (int64_t pass = 0; pass < passes; pass++) {
359 for (Descriptor &descriptor : descriptors) {
360 PacketInfoAttr packet = endpoint.getPacketAttr();
362 packet = turns[(pass * depth + descriptor.object) % turns.size()];
363 for (int64_t copy = 0; copy < copies; copy++) {
365 if (emitted + 1 < total) {
366 successor = builder.createBlock(endBlock);
367 }
else if (iterCount) {
369 successor = builder.createBlock(endBlock);
370 builder.setInsertionPointToStart(successor);
371 EndOp::create(builder, loc);
375 builder.setInsertionPointToStart(current);
376 emitDescriptor(endpoint, pool, descriptor, packet, successor,
377 binaryLocks, drains);
386 void runOnOperation()
override {
387 device = getOperation();
388 builder = OpBuilder(device.getContext());
390 SmallVector<ObjectFifoDmaEndpointOp> endpoints(
391 device.getOps<ObjectFifoDmaEndpointOp>());
394 DenseMap<Value, size_t> tileOrder;
395 for (ObjectFifoDmaEndpointOp endpoint : endpoints)
396 tileOrder.try_emplace(endpoint.getTile(), tileOrder.size());
398 endpoints, [&](ObjectFifoDmaEndpointOp a, ObjectFifoDmaEndpointOp b) {
399 return std::make_tuple(tileOrder.lookup(a.getTile()),
400 a.getRouteDirection(),
401 a.getChannelIndex().value_or(-1)) <
402 std::make_tuple(tileOrder.lookup(b.getTile()),
403 b.getRouteDirection(),
404 b.getChannelIndex().value_or(-1));
406 for (ObjectFifoDmaEndpointOp endpoint : endpoints) {
407 std::optional<int> channel = endpoint.getChannelIndex();
409 endpoint.emitOpError(
"has no channel; run --aie-objectfifo-allocate");
410 return signalPassFailure();
412 SmallVector<ObjectFifoDmaEndpointOp> turns =
turnEndpoints(endpoint);
413 if (turns.empty() ? failed(lowerEndpoint(endpoint, *channel))
414 : turns.front() == endpoint &&
415 failed(lowerTurns(endpoint, *channel)))
416 return signalPassFailure();
418 for (ObjectFifoDmaEndpointOp endpoint : endpoints)
424 llvm::make_early_inc_range(device.getOps<RouteEndpointOp>())) {
432std::unique_ptr<OperationPass<DeviceOp>>
434 return std::make_unique<AIEObjectFifoLowerDMAsPass>();
llvm::SmallVector< ObjectFifoDmaEndpointOp > turnEndpoints(ObjectFifoDmaEndpointOp end)
llvm::SmallVector< StreamWindowStep > streamWindowSteps(const StreamWindow &w)
mlir::Operation * lookupNamedOp(mlir::Operation *from, mlir::StringAttr name)
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIEObjectFifoLowerDMAsPass()
int64_t paddedSize(llvm::ArrayRef< BDDimLayoutAttr > dims, llvm::ArrayRef< BDPadLayoutAttr > pads, int64_t fallback)
llvm::SmallVector< BDDimLayoutAttr > inner