11#include "mlir/IR/Attributes.h"
12#include "mlir/Pass/Pass.h"
13#include "llvm/ADT/DenseMap.h"
16#define GEN_PASS_DEF_AIEOBJECTFIFOSPLIT
17#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
29 ObjectFifoPoolOp pool;
30 SmallVector<int32_t> segments;
33std::optional<ObjectFifoLinkOp> getOptionalLinkOp(ObjectFifoCreateOp op) {
34 auto device = op->getParentOfType<DeviceOp>();
35 for (ObjectFifoLinkOp linkOp : device.getOps<ObjectFifoLinkOp>()) {
36 for (ObjectFifoCreateOp in : linkOp.getInputObjectFifos()) {
41 for (ObjectFifoCreateOp out : linkOp.getOutputObjectFifos()) {
52std::optional<ObjectFifoAllocateOp>
53getOptionalAllocateOp(ObjectFifoCreateOp op) {
55 op->getParentOfType<DeviceOp>().getOps<ObjectFifoAllocateOp>()) {
56 if (alloc.getObjFifoName() == op.name().getValue()) {
64bool delegateReachesBothEnds(ObjectFifoCreateOp op, TileOp delegate) {
65 auto consumerTileOp = cast<TileOp>(op.getConsumerTiles()[0].getDefiningOp());
66 auto reachesDelegate = [&](TileOp end) {
69 return shared == SharedMemory::First || shared == SharedMemory::Either;
71 return reachesDelegate(op.getProducerTileOp()) &&
72 reachesDelegate(consumerTileOp);
77std::optional<StringRef> dmaReason(ObjectFifoCreateOp createOp,
79 if (createOp.forcesDMA())
80 return "it asks for a dma transport";
81 if (createOp.getRepeatCount())
82 return "it repeats objects (`repeat_count`)";
83 if (createOp.usesStream())
84 return "an end is a Core stream port";
85 if (createOp.getConsumerElemType())
86 return "its consumer takes a different element type";
88 if (createOp.getConsumerTiles().size() == 1 &&
89 createOp.getDimensionsToStream().empty()) {
91 cast<TileOp>(createOp.getConsumerTiles()[0].getDefiningOp());
92 shared =
sharedMemory(createOp.getProducerTileOp(), consumerTileOp);
96 if (
auto alloc = getOptionalAllocateOp(createOp);
98 delegateReachesBothEnds(createOp, alloc->getDelegateTileOp()))
104 if (createOp.getConsumerTiles().size() > 1)
105 return "it has more than one consumer";
106 if (!createOp.getDimensionsToStream().empty())
107 return "its producer reshapes the data (`dimensionsToStream`)";
108 return "its ends share no memory module";
111 for (BDDimLayoutArrayAttr dims :
112 createOp.getDimensionsFromStreamPerConsumer()) {
114 return "a consumer reshapes the data (`dimensionsFromStream`)";
121 if (getOptionalLinkOp(createOp)) {
122 if (
auto alloc = getOptionalAllocateOp(createOp)) {
123 if (delegateReachesBothEnds(createOp, alloc->getDelegateTileOp()))
126 return "it is linked through a tile's DMAs";
135int objectCountOn(DeviceOp device, Value tile, ObjectFifoCreateOp objFifo) {
136 if (objFifo.size() == 0) {
141 for (
auto coreOp : device.getOps<CoreOp>()) {
142 if (coreOp.getTile() == tile) {
143 coreOp.walk([&](ObjectFifoAcquireOp acqOp) {
144 if (acqOp.getObjectFifo() == objFifo) {
145 maxAcquire = std::max(maxAcquire, acqOp.acqNumber());
151 if (maxAcquire == 0) {
152 return objFifo.size();
154 if (maxAcquire == 1 && objFifo.size() == 1) {
157 return maxAcquire + 1;
162int sharedObjectCount(ObjectFifoCreateOp objFifo) {
163 int depth = objFifo.size();
164 if (
auto depths = dyn_cast<ArrayAttr>(objFifo.getElemNumber())) {
165 for (
int index = 1; index < static_cast<int>(depths.size()); ++index) {
166 depth = std::max(depth, objFifo.size(index));
172bool hasCoreAccess(DeviceOp device, Value tile, ObjectFifoCreateOp objFifo,
173 ObjectFifoPort port) {
174 for (
auto coreOp : device.getOps<CoreOp>()) {
175 if (coreOp.getTile() != tile) {
179 coreOp.walk([&](Operation *op) {
180 if (
auto acq = dyn_cast<ObjectFifoAcquireOp>(op)) {
181 found |= acq.getObjectFifo() == objFifo && acq.getPort() == port;
182 }
else if (
auto rel = dyn_cast<ObjectFifoReleaseOp>(op)) {
183 found |= rel.getObjectFifo() == objFifo && rel.getPort() == port;
193struct AIEObjectFifoSplitPass
194 :
public xilinx::AIE::impl::AIEObjectFifoSplitBase<AIEObjectFifoSplitPass> {
197 OpBuilder builder{
static_cast<MLIRContext *
>(
nullptr)};
200 void createSegments(ObjectFifoPoolOp pool, Location loc,
201 ArrayRef<std::pair<int64_t, int64_t>> extents) {
202 OpBuilder::InsertionGuard guard(builder);
203 builder.createBlock(&pool.getSegments());
204 for (
auto [index, extent] : llvm::enumerate(extents)) {
205 ObjectFifoSegmentOp::create(
206 builder, loc, builder.getStringAttr(
"s" + std::to_string(index)),
207 builder.getI32IntegerAttr(extent.first),
208 builder.getI32IntegerAttr(extent.second),
210 FlatSymbolRefAttr());
215 ArrayAttr selectedSegmentNames(PoolRef ref) {
216 std::vector<ObjectFifoSegmentOp> all = ref.pool.getSegmentOps();
217 if (all.size() <= 1) {
220 SmallVector<Attribute> names;
221 for (int32_t index : ref.segments) {
222 names.push_back(FlatSymbolRefAttr::get(builder.getContext(),
223 all[index].getSymName()));
225 return builder.getArrayAttr(names);
228 ObjectFifoPoolOp createPool(Location loc, StringRef name, Value tile,
229 int depth, MemRefType elemType,
230 ObjectFifoCreateOp from,
231 ArrayRef<std::pair<int64_t, int64_t>> extents,
232 bool holdsInitialContents,
233 std::optional<int> repeatCount,
234 bool disableSynchronization =
false) {
235 auto pool = ObjectFifoPoolOp::create(
236 builder, loc, name, tile, depth, elemType, ArrayAttr(),
238 repeatCount ? builder.getI32IntegerAttr(*repeatCount) : IntegerAttr(),
239 disableSynchronization || from.getDisableSynchronization(),
240 builder.getStringAttr(from.name().getValue()),
241 holdsInitialContents ? from.getInitValuesAttr() : ArrayAttr(),
243 createSegments(pool, loc, extents);
247 ObjectFifoCoreEndpointOp createCoreEndpoint(Location loc, StringRef name,
248 Value tile, PoolRef ref,
249 ObjectFifoRole role) {
250 return ObjectFifoCoreEndpointOp::create(builder, loc, name, tile, role,
251 ref.pool.getSymName(),
252 selectedSegmentNames(ref));
255 ObjectFifoDmaEndpointOp createDmaEndpoint(Location loc, StringRef name,
256 Value tile, PoolRef ref,
258 ObjectFifoCreateOp from,
259 BDDimLayoutArrayAttr dims,
260 std::optional<int> channelIndex) {
264 std::optional<int32_t> iterCount;
265 if (std::optional<int32_t> fifoIterations = from.getIterCount()) {
266 iterCount = role == ObjectFifoRole::Drain
268 : *fifoIterations * from.getRepeatCount().value_or(1);
270 ArrayAttr segments = selectedSegmentNames(ref);
272 BDDimLayoutArrayArrayAttr dimensions;
273 if (dims && !dims.empty()) {
274 SmallVector<BDDimLayoutArrayAttr> perSegment(ref.segments.size(), dims);
276 BDDimLayoutArrayArrayAttr::get(builder.getContext(), perSegment);
279 BDPadLayoutArrayArrayAttr padding;
280 std::optional<ArrayRef<BDPadLayoutAttr>> padDims = from.getPadDimensions();
281 if (role == ObjectFifoRole::Drain && padDims && !padDims->empty()) {
282 SmallVector<BDPadLayoutArrayAttr> perSegment(ref.segments.size(),
283 from.getPadDimensionsAttr());
285 BDPadLayoutArrayArrayAttr::get(builder.getContext(), perSegment);
288 return ObjectFifoDmaEndpointOp::create(
289 builder, loc, builder.getStringAttr(name), tile,
290 ObjectFifoRoleAttr::get(builder.getContext(), role),
291 FlatSymbolRefAttr::get(builder.getContext(), ref.pool.getSymName()),
293 channelIndex ? builder.getI32IntegerAttr(*channelIndex) : IntegerAttr(),
295 from.getPadValue() ? builder.getI32IntegerAttr(from.getPadValue())
297 iterCount ? builder.getI32IntegerAttr(*iterCount) : IntegerAttr(),
299 builder.getStringAttr(from.name().getValue()), ArrayAttr(),
300 ArrayAttr(), ArrayAttr());
305 RouteEndpointOp createRouteEndpoint(Location loc, StringRef name, Value tile,
307 std::optional<int> channelIndex,
308 ObjectFifoCreateOp from) {
309 return RouteEndpointOp::create(
310 builder, loc, builder.getStringAttr(name), tile,
311 WireBundleAttr::get(builder.getContext(), bundle),
312 channelIndex ? builder.getI32IntegerAttr(*channelIndex) : IntegerAttr(),
314 builder.getStringAttr(from.name().getValue()));
319 std::optional<PoolRef> registeredPool(ObjectFifoCreateOp fifo, Value tile,
320 StringRef name, MemRefType elemType) {
321 SmallVector<Attribute> names;
322 for (
auto regOp : device.getOps<ObjectFifoRegisterExternalBuffersOp>()) {
323 if (regOp.getTile() != tile || regOp.getObjectFifo() != fifo) {
326 for (Value buffer : regOp.getExternalBuffers()) {
327 auto external = cast<ExternalBufferOp>(buffer.getDefiningOp());
328 names.push_back(SymbolRefAttr::get(external.getSymNameAttr()));
331 elemType = cast<MemRefType>(external.getType());
338 auto pool = ObjectFifoPoolOp::create(
339 builder, fifo.getLoc(), name, tile, (
int)names.size(), elemType,
340 builder.getArrayAttr(names),
341 ArrayAttr(), IntegerAttr(),
342 fifo.getDisableSynchronization(),
343 builder.getStringAttr(fifo.name().getValue()),
346 createSegments(pool, fifo.getLoc(), {{0, elemType.getNumElements()}});
347 return PoolRef{pool, {0}};
351 void retargetCoreAccesses(ObjectFifoCreateOp fifo, ObjectFifoPort port,
352 Value tile, StringRef endpointName) {
353 auto name = FlatSymbolRefAttr::get(builder.getContext(), endpointName);
357 for (
auto coreOp : device.getOps<CoreOp>()) {
358 if (coreOp.getTile() != tile) {
361 coreOp.walk([&](Operation *op) {
362 if (
auto acq = dyn_cast<ObjectFifoAcquireOp>(op)) {
363 if (acq.getObjectFifo() == fifo && acq.getPort() == port) {
364 acq.setObjFifoNameAttr(name);
365 acq.removePortAttr();
367 }
else if (
auto rel = dyn_cast<ObjectFifoReleaseOp>(op)) {
368 if (rel.getObjectFifo() == fifo && rel.getPort() == port) {
369 rel.setObjFifoNameAttr(name);
370 rel.removePortAttr();
377 void runOnOperation()
override;
380 LogicalResult verifyTilesArePlaced() {
381 for (
auto fifo : device.getOps<ObjectFifoCreateOp>()) {
382 auto placed = [](Value tile) {
383 return isa_and_nonnull<TileOp>(tile.getDefiningOp());
385 if (!placed(fifo.getProducerTile())) {
386 return fifo.emitOpError(
"producer tile is not a placed aie.tile; run "
387 "--aie-place-tiles before this pass");
389 for (Value consumer : fifo.getConsumerTiles()) {
390 if (!placed(consumer)) {
391 return fifo.emitOpError(
"consumer tile is not a placed aie.tile; run "
392 "--aie-place-tiles before this pass");
402 LogicalResult verifyAllocateDelegates() {
403 for (
auto fifo : device.getOps<ObjectFifoCreateOp>()) {
404 if (getOptionalLinkOp(fifo) && !linkPoolOwner.contains(fifo)) {
407 auto alloc = getOptionalAllocateOp(fifo);
408 if (alloc && !delegateReachesBothEnds(fifo, alloc->getDelegateTileOp())) {
409 return alloc->emitOpError(
"objectfifo has no shared memory access to "
410 "delegate tile's memory module");
418 LogicalResult verifyStreamPortAccesses() {
419 auto check = [&](Operation *op, ObjectFifoCreateOp fifo,
420 std::optional<ObjectFifoPort> port, StringRef verb) {
421 if (!fifo || !port || !fifo.usesStream()) {
424 bool onStreamPort = *port == ObjectFifoPort::Produce
425 ? fifo.streamsFromProducer()
426 : fifo.streamsToConsumer(0);
430 return LogicalResult(op->emitOpError(
"cannot ")
431 << verb <<
" objectfifo stream port");
433 for (
auto coreOp : device.getOps<CoreOp>()) {
434 auto result = coreOp.walk([&](Operation *op) {
435 LogicalResult ok = success();
436 if (
auto acq = dyn_cast<ObjectFifoAcquireOp>(op)) {
437 ok = check(op, acq.getObjectFifo(), acq.getPort(),
"acquire from");
438 }
else if (
auto rel = dyn_cast<ObjectFifoReleaseOp>(op)) {
439 ok = check(op, rel.getObjectFifo(), rel.getPort(),
"release from");
441 return failed(ok) ? WalkResult::interrupt() : WalkResult::advance();
443 if (result.wasInterrupted()) {
452 LogicalResult verifyLinkAccesses() {
453 for (
auto linkOp : device.getOps<ObjectFifoLinkOp>()) {
454 auto sharedTile = linkOp.getOptionalSharedTile();
458 auto reject = [&](ObjectFifoCreateOp fifo) {
459 return LogicalResult(
460 linkOp.emitOpError(
"core on the shared tile cannot access '")
461 << fifo.name().getValue() <<
"': a link moves objects by DMA");
463 for (ObjectFifoCreateOp in : linkOp.getInputObjectFifos()) {
464 if (hasCoreAccess(device, *sharedTile, in, ObjectFifoPort::Consume)) {
468 for (ObjectFifoCreateOp out : linkOp.getOutputObjectFifos()) {
469 if (hasCoreAccess(device, *sharedTile, out, ObjectFifoPort::Produce)) {
479 DenseMap<Operation *, PoolRef> linkedProducerEnd;
480 DenseMap<std::pair<Operation *, Value>, SmallVector<PoolRef>>
483 DenseSet<Operation *> linkPoolOwner;
485 DenseMap<Operation *, std::string> shimEndpointName;
488 DenseMap<Operation *, ObjectFifoLinkOp> timeLinkOf;
490 DenseMap<Operation *, ObjectFifoDmaEndpointOp> timeLinkEndpoint;
493 DenseMap<Operation *, SmallVector<Attribute>> mergeSources;
494 DenseMap<Operation *, DenseMap<Operation *, Attribute>> dispatchTurns;
498 ObjectFifoDmaEndpointOp timeLinkEndpointFor(ObjectFifoLinkOp link,
499 Location loc, PoolRef ref,
500 std::optional<int> channel);
501 void createTimeLinkRoutes();
502 LogicalResult createLinkPools();
508LogicalResult AIEObjectFifoSplitPass::createLinkPools() {
509 for (
auto linkOp : device.getOps<ObjectFifoLinkOp>()) {
510 auto sharedTile = linkOp.getOptionalSharedTile();
515 std::vector<ObjectFifoCreateOp> ins = linkOp.getInputObjectFifos();
516 std::vector<ObjectFifoCreateOp> outs = linkOp.getOutputObjectFifos();
517 bool isJoin = linkOp.isJoin();
518 bool isDistribute = linkOp.isDistribute();
520 ObjectFifoCreateOp owner = linkOp.getPoolOwner();
521 if (linkOp.isMerge()) {
522 for (ObjectFifoCreateOp in : ins)
523 timeLinkOf[in] = linkOp;
525 if (linkOp.isDispatch()) {
526 for (ObjectFifoCreateOp out : outs)
527 timeLinkOf[out] = linkOp;
530 auto elemType = cast<MemRefType>(
531 cast<AIEObjectFifoType>(owner.getElemType()).getElementType());
532 builder.setInsertionPoint(owner);
534 SmallVector<std::pair<int64_t, int64_t>> extents = linkOp.getPoolSegments();
536 bool ownerIsOutput = llvm::is_contained(outs, owner);
541 bool window = linkOp.walksStream();
544 if (failed(linkOp.getStreamWindow(walk)))
546 name = (owner.name().getValue() +
"_cons_pool").str();
548 }
else if (ownerIsOutput) {
549 name = (owner.name().getValue() +
"_pool").str();
550 depth = owner.size();
552 auto consumers = owner.getConsumerTiles();
553 size_t earlier = linkedConsumerEnd.lookup({owner, *sharedTile}).size();
555 for (
size_t seen = 0; seen <= earlier;) {
556 assert(
static_cast<size_t>(index + 1) < consumers.size() &&
557 "fewer consumer tiles than already-linked pools for this tile");
558 if (consumers[++index] == *sharedTile)
561 name = (owner.name().getValue() +
562 (consumers.size() > 1 ?
"_" + std::to_string(index) +
"_cons_pool"
565 depth = isa<ArrayAttr>(owner.getElemNumber())
566 ? owner.size(index + 1)
567 : objectCountOn(device, *sharedTile, owner);
572 auto asksToSkipLocks = [](ObjectFifoCreateOp fifo) {
573 return fifo.getDisableSynchronization();
575 bool disableSynchronization = llvm::any_of(ins, asksToSkipLocks) ||
576 llvm::any_of(outs, asksToSkipLocks);
578 auto pool = createPool(linkOp.getLoc(), name, *sharedTile, depth, elemType,
581 linkOp.getRepeatCount(), disableSynchronization);
583 pool.setContiguous(
true);
587 pool.setZeroObjects(SmallVector<int32_t>{
588 static_cast<int32_t
>(walk.
top),
static_cast<int32_t
>(walk.
bottom)});
590 linkPoolOwner.insert(owner);
592 SmallVector<int32_t> allSegments;
593 for (int32_t index = 0; index < (int32_t)extents.size(); ++index) {
594 allSegments.push_back(index);
596 for (
auto [index, in] : llvm::enumerate(ins)) {
597 linkedConsumerEnd[{in, *sharedTile}].push_back(PoolRef{
598 pool, isJoin ? SmallVector<int32_t>{
static_cast<int32_t
>(index)}
601 for (
auto [index, out] : llvm::enumerate(outs)) {
602 linkedProducerEnd[out] = PoolRef{
603 pool, isDistribute ? SmallVector<int32_t>{
static_cast<int32_t
>(index)}
610ObjectFifoDmaEndpointOp
611AIEObjectFifoSplitPass::timeLinkEndpointFor(ObjectFifoLinkOp link, Location loc,
613 std::optional<int> channel) {
614 ObjectFifoDmaEndpointOp &endpoint = timeLinkEndpoint[link];
616 ObjectFifoCreateOp owner = link.isMerge() ? link.getOutputObjectFifos()[0]
617 : link.getInputObjectFifos()[0];
618 endpoint = createDmaEndpoint(
620 (owner.name().getValue() +
621 (link.isMerge() ?
"_merge_dma" :
"_dispatch_dma"))
623 ref.pool.getTile(), ref,
624 link.isMerge() ? ObjectFifoRole::Fill : ObjectFifoRole::Drain, owner,
625 BDDimLayoutArrayAttr(), channel);
632void AIEObjectFifoSplitPass::createTimeLinkRoutes() {
633 for (
auto link : device.getOps<ObjectFifoLinkOp>()) {
634 ObjectFifoDmaEndpointOp endpoint = timeLinkEndpoint.lookup(link);
637 MLIRContext *ctx = builder.getContext();
638 if (link.isMerge()) {
639 PacketInfoAttr header = PacketInfoAttr::get(ctx, 0, std::nullopt);
640 for (ObjectFifoCreateOp in : link.getInputObjectFifos())
641 if (PacketInfoAttr pinned = in.packetHeader();
642 pinned && pinned.isAssigned())
644 builder.setInsertionPoint(link);
645 RouteOp::create(builder, link.getLoc(),
646 builder.getArrayAttr(mergeSources[link]),
647 builder.getArrayAttr(
648 {FlatSymbolRefAttr::get(ctx, endpoint.getSymName())}),
652 SmallVector<Attribute> turns;
653 for (ObjectFifoCreateOp out : link.getOutputObjectFifos())
654 turns.push_back(dispatchTurns[link].lookup(out));
655 endpoint.setDispatchAttr(builder.getArrayAttr(turns));
659void AIEObjectFifoSplitPass::runOnOperation() {
660 device = getOperation();
661 builder = OpBuilder(device.getContext());
662 builder.setInsertionPoint(device.getBody()->getTerminator());
664 SmallVector<ObjectFifoCreateOp> fifos(device.getOps<ObjectFifoCreateOp>());
666 if (failed(verifyTilesArePlaced()) || failed(verifyStreamPortAccesses()) ||
667 failed(verifyLinkAccesses())) {
668 return signalPassFailure();
671 if (failed(createLinkPools()) || failed(verifyAllocateDelegates())) {
672 return signalPassFailure();
675 for (ObjectFifoCreateOp fifo : fifos) {
676 builder.setInsertionPoint(fifo);
677 Location loc = fifo.getLoc();
678 StringRef fifoName = fifo.name().getValue();
679 auto fifoType = cast<AIEObjectFifoType>(fifo.getElemType());
680 auto elemType = cast<MemRefType>(fifoType.getElementType());
681 auto consElemType = cast<MemRefType>(
682 cast<AIEObjectFifoType>(fifo.getConsumerElemTypeOrDefault())
685 auto sharedModule = AIETargetModel::SharedMemory::None;
686 std::optional<StringRef> needsDMAs = dmaReason(fifo, sharedModule);
687 if (needsDMAs && fifo.forcesSharedMemory()) {
688 fifo.emitOpError(
"asks for a shared_mem transport, but ") << *needsDMAs;
689 return signalPassFailure();
691 bool shared = !needsDMAs;
695 if (
auto linked = linkedProducerEnd.find(fifo);
696 linked != linkedProducerEnd.end()) {
697 ref = linked->second;
698 }
else if (
auto linked =
699 linkedConsumerEnd.find({fifo, fifo.getConsumerTiles()[0]});
700 linked != linkedConsumerEnd.end()) {
701 ref = linked->second.front();
703 Value tile = sharedModule == AIETargetModel::SharedMemory::Second
704 ? fifo.getConsumerTiles()[0]
705 : fifo.getProducerTile();
708 if (
auto alloc = getOptionalAllocateOp(fifo)) {
709 if (!delegateReachesBothEnds(fifo, alloc->getDelegateTileOp())) {
710 alloc->emitOpError(
"objectfifo has no shared memory access to "
711 "delegate tile's memory module");
712 return signalPassFailure();
714 tile = alloc->getDelegateTile();
718 ref = PoolRef{createPool(loc, (fifoName +
"_pool").str(), tile,
719 sharedObjectCount(fifo), elemType, fifo,
720 {{0, elemType.getNumElements()}},
722 fifo.getRepeatCount()),
726 if (hasCoreAccess(device, fifo.getProducerTile(), fifo,
727 ObjectFifoPort::Produce)) {
728 auto name = (fifoName +
"_prod").str();
729 createCoreEndpoint(loc, name, fifo.getProducerTile(), ref,
730 ObjectFifoRole::Fill);
731 retargetCoreAccesses(fifo, ObjectFifoPort::Produce,
732 fifo.getProducerTile(), name);
734 if (hasCoreAccess(device, fifo.getConsumerTiles()[0], fifo,
735 ObjectFifoPort::Consume)) {
736 auto name = (fifoName +
"_cons").str();
737 createCoreEndpoint(loc, name, fifo.getConsumerTiles()[0], ref,
738 ObjectFifoRole::Drain);
739 retargetCoreAccesses(fifo, ObjectFifoPort::Consume,
740 fifo.getConsumerTiles()[0], name);
745 Value prodTile = fifo.getProducerTile();
748 ObjectFifoEndPortAttr prodPort = fifo.getProdPortAttr();
749 std::optional<int> prodChannel =
750 prodPort ? prodPort.channelIndex() : std::nullopt;
752 bool prodIsShim = cast<TileOp>(prodTile.getDefiningOp()).isShimTile();
753 std::optional<PoolRef> prodRef;
755 if (
auto linked = linkedProducerEnd.find(fifo);
756 linked != linkedProducerEnd.end()) {
757 prodRef = linked->second;
758 }
else if (prodIsShim) {
759 if (!fifo.getPlio()) {
760 prodRef = registeredPool(fifo, prodTile, (fifoName +
"_pool").str(),
763 }
else if (!fifo.streamsFromProducer()) {
764 int depth = fifo.getInitValues() ? fifo.size()
765 : objectCountOn(device, prodTile, fifo);
767 createPool(loc, (fifoName +
"_pool").str(), prodTile, depth, elemType,
768 fifo, {{0, elemType.getNumElements()}},
769 true, fifo.getRepeatCount());
770 prodRef = PoolRef{pool, {0}};
774 hasCoreAccess(device, prodTile, fifo, ObjectFifoPort::Produce)) {
775 auto name = (fifoName +
"_prod").str();
776 createCoreEndpoint(loc, name, prodTile, *prodRef, ObjectFifoRole::Fill);
777 retargetCoreAccesses(fifo, ObjectFifoPort::Produce, prodTile, name);
780 std::string prodDmaName = (fifoName +
"_prod_dma").str();
781 ObjectFifoLinkOp timeLink = timeLinkOf.lookup(fifo);
782 if (timeLink && timeLink.isDispatch()) {
783 prodDmaName = timeLinkEndpointFor(timeLink, loc, *prodRef, prodChannel)
785 }
else if (prodRef) {
786 createDmaEndpoint(loc, prodDmaName, prodTile, *prodRef,
787 ObjectFifoRole::Drain, fifo,
788 fifo.getDimensionsToStreamAttr(), prodChannel);
790 createRouteEndpoint(loc, prodDmaName, prodTile,
791 fifo.streamsFromProducer() ? WireBundle::Core
792 : fifo.getPlio() ? WireBundle::PLIO
797 shimEndpointName[fifo] = prodDmaName;
800 SmallVector<Attribute> destinations;
801 ArrayRef<BDDimLayoutArrayAttr> consumerDims =
802 fifo.getDimensionsFromStreamPerConsumer();
803 int consumerIndex = 0;
804 DenseMap<Value, unsigned> linkedOn;
805 for (Value consumerTile : fifo.getConsumerTiles()) {
806 std::string suffix = fifo.getConsumerTiles().size() > 1
807 ? (
"_" + std::to_string(consumerIndex) +
"_cons")
809 bool consIsShim = cast<TileOp>(consumerTile.getDefiningOp()).isShimTile();
811 std::optional<PoolRef> consRef;
812 if (
auto linked = linkedConsumerEnd.find({fifo, consumerTile});
813 linked != linkedConsumerEnd.end() &&
814 linkedOn[consumerTile] < linked->second.size()) {
815 consRef = linked->second[linkedOn[consumerTile]++];
816 }
else if (consIsShim) {
817 if (!fifo.getPlio()) {
819 registeredPool(fifo, consumerTile,
820 (fifoName + suffix +
"_pool").str(), consElemType);
822 }
else if (!fifo.streamsToConsumer(consumerIndex)) {
823 int depth = isa<ArrayAttr>(fifo.getElemNumber())
824 ? fifo.size(consumerIndex + 1)
825 : objectCountOn(device, consumerTile, fifo);
826 auto pool = createPool(loc, (fifoName + suffix +
"_pool").str(),
827 consumerTile, depth, consElemType, fifo,
828 {{0, consElemType.getNumElements()}},
831 consRef = PoolRef{pool, {0}};
835 hasCoreAccess(device, consumerTile, fifo, ObjectFifoPort::Consume)) {
836 auto name = (fifoName + suffix).str();
837 createCoreEndpoint(loc, name, consumerTile, *consRef,
838 ObjectFifoRole::Drain);
839 retargetCoreAccesses(fifo, ObjectFifoPort::Consume, consumerTile, name);
842 ObjectFifoEndPortAttr consPort = fifo.getConsumerPort(consumerIndex);
843 std::optional<int> consChannel =
844 consPort ? consPort.channelIndex() : std::nullopt;
846 std::string consDmaName = (fifoName + suffix +
"_dma").str();
847 if (timeLink && timeLink.isMerge()) {
848 consDmaName = timeLinkEndpointFor(timeLink, loc, *consRef, consChannel)
850 }
else if (consRef) {
851 createDmaEndpoint(loc, consDmaName, consumerTile, *consRef,
852 ObjectFifoRole::Fill, fifo,
853 consumerDims.empty() ? BDDimLayoutArrayAttr()
854 : consumerDims[consumerIndex],
857 createRouteEndpoint(loc, consDmaName, consumerTile,
858 fifo.streamsToConsumer(consumerIndex)
860 : fifo.getPlio() ? WireBundle::PLIO
864 destinations.push_back(
865 FlatSymbolRefAttr::get(builder.getContext(), consDmaName));
867 shimEndpointName[fifo] = consDmaName;
872 FlatSymbolRefAttr source =
873 FlatSymbolRefAttr::get(builder.getContext(), prodDmaName);
874 if (timeLink && timeLink.isMerge()) {
875 mergeSources[timeLink].push_back(source);
880 PacketInfoAttr header = fifo.packetHeader();
881 if (timeLink && timeLink.isDispatch()) {
882 dispatchTurns[timeLink][fifo] = destinations.front();
884 header = PacketInfoAttr::get(builder.getContext(), 0, std::nullopt);
886 RouteOp::create(builder, loc, builder.getArrayAttr({source}),
887 builder.getArrayAttr(destinations), header);
890 createTimeLinkRoutes();
892 SmallVector<Operation *> toErase;
893 for (ObjectFifoCreateOp fifo : fifos) {
895 auto shim = shimEndpointName.find(fifo);
896 if (shim != shimEndpointName.end()) {
897 (void)SymbolTable::replaceAllSymbolUses(
898 fifo, builder.getStringAttr(shim->second), device);
900 toErase.push_back(fifo);
902 for (
auto linkOp : device.getOps<ObjectFifoLinkOp>()) {
903 toErase.push_back(linkOp);
905 for (
auto allocOp : device.getOps<ObjectFifoAllocateOp>()) {
906 toErase.push_back(allocOp);
908 for (
auto regOp : device.getOps<ObjectFifoRegisterExternalBuffersOp>()) {
909 toErase.push_back(regOp);
911 for (Operation *op : toErase) {
918std::unique_ptr<OperationPass<DeviceOp>>
920 return std::make_unique<AIEObjectFifoSplitPass>();
SharedMemory
Which of two tiles' memory modules both of them can address.
@ None
Neither tile can address the other's memory module.
AIETargetModel::SharedMemory sharedMemory(TileOp a, TileOp b)
Which of a's and b's memory modules both tiles can address.
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIEObjectFifoSplitPass()