547 ObjectFifoCreateOp op,
int share_direction) {
551 std::vector<BufferOp> buffers;
552 auto fifo = llvm::cast<AIEObjectFifoType>(op.getElemType());
553 auto elemType = llvm::cast<MemRefType>(fifo.getElementType());
554 int numElem = op.size();
555 int of_elem_index = 0;
564 auto fifoIn = linkOp->getInputObjectFifos()[0];
565 auto fifoOut = linkOp->getOutputObjectFifos()[0];
569 if (linkOp->isJoin()) {
571 if (op.name() != fifoOut.name())
573 }
else if (linkOp->isDistribute()) {
575 if (op.name() != fifoIn.name())
579 if (fifoOut.getInitValues().has_value()) {
580 if (fifoOut.name() != op.name())
584 auto fifoInType = llvm::cast<AIEObjectFifoType>(fifoIn.getElemType());
585 auto elemInType = llvm::cast<MemRefType>(fifoInType.getElementType());
586 int inSize = elemInType.getNumElements();
589 llvm::cast<AIEObjectFifoType>(fifoOut.getElemType());
591 llvm::cast<MemRefType>(fifoOutType.getElementType());
593 if (
int outSize = elemOutType.getNumElements(); inSize >= outSize) {
594 if (op.name() != fifoIn.name())
597 if (fifoOut.name() != op.name())
604 TileOp creation_tile;
605 if (share_direction == 0 || share_direction == -1)
606 creation_tile = op.getProducerTileOp();
608 auto consumerTileOp =
609 dyn_cast<TileOp>(op.getConsumerTiles()[0].getDefiningOp());
610 creation_tile = consumerTileOp;
614 Operation *t =
nullptr;
615 auto dev = op->getParentOfType<DeviceOp>();
616 for (
auto tile_op : dev.getBody()->getOps<TileOp>()) {
617 t = tile_op.getOperation();
620 builder.setInsertionPointAfter(t);
621 for (
int i = 0; i < numElem; i++) {
623 mlir::ElementsAttr initValues =
nullptr;
624 if (!creation_tile.isShimTile()) {
625 if (op.getInitValues().has_value()) {
627 llvm::cast<mlir::ElementsAttr>(op.getInitValues().value()[i]);
630 auto elementType = elemType.getElementType();
632 DataLayout dataLayout = DataLayout::closest(op.getOperation());
633 int64_t elementBitWidth = dataLayout.getTypeSizeInBits(elementType);
635 auto totalSizeBytes = elemType.getNumElements() * elementBitWidth / 8;
636 auto &targetModel = dev.getTargetModel();
638 int maxDataMemorySize = 0;
639 if (creation_tile.isMemTile())
641 targetModel.getMemTileSize();
645 .getLocalMemorySize();
648 int currentUsedMemory =
652 TileOp current_buf_allocation_tile =
655 if (
static_cast<int>(currentUsedMemory + totalSizeBytes) >
659 std::vector<TileOp> neighborTiles;
660 int currentCol = creation_tile.getCol();
661 int currentRow = creation_tile.getRow();
664 if (currentCol > 0) {
666 currentCol - 1, currentRow);
668 int share_direction = 0;
670 neighborTiles.push_back(leftTile);
675 if (currentCol < (targetModel.columns() - 1)) {
677 currentCol + 1, currentRow);
678 int share_direction = 0;
680 neighborTiles.push_back(rightTile);
685 if (!neighborTiles.empty()) {
686 for (
auto &tile : neighborTiles) {
688 int neighborUsedMemory =
690 if (
static_cast<int>(neighborUsedMemory + totalSizeBytes) <=
694 current_buf_allocation_tile = tile;
700 auto buff = builder.create<BufferOp>(
701 builder.getUnknownLoc(), elemType, current_buf_allocation_tile,
702 builder.getStringAttr(op.name().str() +
"_buff_" +
703 std::to_string(of_elem_index)),
706 buffers.push_back(buff);
712 int joinDistribFactor = 1;
713 if (op.getRepeatCount().has_value())
714 repeatCount = op.getRepeatCount().value();
716 if (linkOp->getRepeatCount().has_value())
717 repeatCount = linkOp->getRepeatCount().value();
718 if (linkOp->isDistribute())
719 joinDistribFactor *= linkOp->getFifoOuts().size();
720 else if (linkOp->isJoin())
721 joinDistribFactor *= linkOp->getFifoIns().size();
724 std::vector<LockOp> locks =
726 joinDistribFactor, creation_tile, repeatCount);
1006 ObjectFifoCreateOp op, DMAChannelDir channelDir,
1007 int channelIndex,
int lockMode,
1008 BDDimLayoutArrayAttr dims,
1009 BDPadLayoutArrayAttr padDimensions) {
1010 size_t numBlocks = op.size();
1014 auto fifo = llvm::cast<AIEObjectFifoType>(op.getElemType());
1015 auto elemType = llvm::cast<MemRefType>(fifo.getElementType());
1016 int lenOut = elemType.getNumElements();
1021 int repeatCount = 1;
1022 if (op.getRepeatCount().has_value())
1023 repeatCount = op.getRepeatCount().value();
1027 ObjectFifoCreateOp target = op;
1028 bool isDistribute =
false;
1029 bool isJoin =
false;
1030 int extraOffset = 0;
1031 int joinDistribFactor = 1;
1032 int joinDistribLockIndex = 0;
1037 auto srcOffsets = linkOp->getSrcOffsets();
1038 auto dstOffsets = linkOp->getDstOffsets();
1040 if (linkOp->getRepeatCount().has_value())
1041 if (linkOp->getInputObjectFifos()[0] == op) {
1042 acqNum *= linkOp->getRepeatCount().value();
1043 relNum *= linkOp->getRepeatCount().value();
1046 if (linkOp->isJoin()) {
1050 joinDistribFactor *= linkOp->getFifoIns().size();
1053 for (
auto fifoIn : linkOp->getInputObjectFifos()) {
1054 if (fifoIn.name() == op.name())
1058 extraOffset = *getConstantIntValue(srcOffsets[i]);
1059 lenOut = linkOp->getJoinTransferLengths()[i];
1060 joinDistribLockIndex = i;
1062 }
else if (linkOp->isDistribute()) {
1064 isDistribute =
true;
1066 joinDistribFactor *= linkOp->getFifoOuts().size();
1069 for (
auto fifoOut : linkOp->getOutputObjectFifos()) {
1070 if (fifoOut.name() == op.name())
1074 extraOffset = *getConstantIntValue(dstOffsets[i]);
1075 lenOut = linkOp->getDistributeTransferLengths()[i];
1076 joinDistribLockIndex = i;
1081 llvm::cast<AIEObjectFifoType>(target.getElemType());
1082 auto targetElemType =
1083 llvm::cast<MemRefType>(targetFifo.getElementType());
1084 lenOut = targetElemType.getNumElements();
1090 numBlocks = target.size();
1096 Operation *producerDMA =
nullptr;
1097 for (
auto dmaOp : device.getOps<MemTileDMAOp>()) {
1098 if (dmaOp.getTile() == target.getProducerTile()) {
1099 producerDMA = dmaOp.getOperation();
1105 TileOp objFifoTileOp = target.getProducerTileOp();
1106 if (producerDMA ==
nullptr) {
1107 OpBuilder::InsertionGuard g(builder);
1108 builder.setInsertionPoint(device.getBody()->getTerminator());
1110 builder.create<MemTileDMAOp>(builder.getUnknownLoc(), objFifoTileOp);
1112 OpBuilder::InsertionGuard g(builder);
1113 builder.setInsertionPointToStart(&newDMAOp.getRegion().emplaceBlock());
1114 builder.create<EndOp>(builder.getUnknownLoc());
1116 producerDMA = newDMAOp.getOperation();
1120 Block *lastDmaBlock = endBlock->getSinglePredecessor();
1121 Block *dmaBlock = builder.createBlock(endBlock);
1122 Block *bdBlock = builder.createBlock(endBlock);
1125 builder.setInsertionPointToStart(dmaBlock);
1126 builder.create<DMAStartOp>(builder.getUnknownLoc(), channelDir,
1127 channelIndex, 0, bdBlock,
1129 if (lastDmaBlock !=
nullptr)
1130 lastDmaBlock->getTerminator()->setSuccessor(dmaBlock, 1);
1134 Block *curr = bdBlock;
1135 size_t elemIndex = 0;
1136 size_t lockIndex = 0;
1137 size_t totalBlocks = 0;
1138 bool distribOrJoin =
false;
1139 for (
size_t i = 0; i < numBlocks; i++) {
1142 for (
int r = 0; r < repeatCount * joinDistribFactor; r++) {
1143 if (totalBlocks == numBlocks * repeatCount * joinDistribFactor - 1) {
1146 succ = builder.createBlock(endBlock);
1149 builder.setInsertionPointToStart(curr);
1151 if (isDistribute || isJoin) {
1152 distribOrJoin =
true;
1155 offset = *getConstantIntValue(linkOp->getDstOffsets()[r]);
1156 lenOut = linkOp->getDistributeTransferLengths()[r];
1158 offset = *getConstantIntValue(linkOp->getSrcOffsets()[r]);
1159 lenOut = linkOp->getJoinTransferLengths()[r];
1161 lockIndex = r % joinDistribFactor;
1163 offset = extraOffset;
1164 lockIndex = joinDistribLockIndex;
1167 lockIndex = elemIndex;
1170 createBdBlock<BufferOp>(builder, target, lockMode, acqNum, relNum,
1172 lenOut, channelDir, lockIndex, succ, dims,
1173 padDimensions, distribOrJoin);
1192 std::set<TileOp> objectFifoTiles) {
1193 for (
auto coreOp : device.getOps<CoreOp>()) {
1194 if (objectFifoTiles.count(coreOp.getTileOp()) > 0) {
1195 std::vector<scf::ForOp> unrolledLoops;
1196 std::map<Operation *, bool> foundMap;
1197 std::map<Operation *, int64_t> remainderMap;
1198 std::map<Operation *, int64_t> tripCountMap;
1199 WalkResult res = coreOp.walk([&](scf::ForOp forLoop) {
1203 foundMap[forLoop.getOperation()] =
false;
1204 std::set<int> objFifoSizes;
1205 Block *body = forLoop.getBody();
1206 remainderMap[forLoop.getOperation()] = 0;
1207 for (
auto acqOp : body->getOps<ObjectFifoAcquireOp>()) {
1208 if (acqOp.getOperation()->getParentOp() == forLoop) {
1209 foundMap[forLoop.getOperation()] =
true;
1210 ObjectFifoCreateOp op = acqOp.getObjectFifo();
1211 objFifoSizes.insert(op.size());
1216 if (!foundMap[forLoop.getOperation()]) {
1217 unrolledLoops.push_back(forLoop);
1218 return WalkResult::advance();
1221 Region *region = forLoop->getParentRegion();
1222 scf::ForOp prevLoop;
1224 tripCountMap[prevLoop.getOperation()] = 0;
1225 while (remainderMap[prevLoop.getOperation()] > 1 ||
1226 foundMap[prevLoop.getOperation()]) {
1227 region->walk([&](scf::ForOp remLoop) {
1228 bool skipLoop =
false;
1229 int64_t tripCount = 0;
1230 if (remLoop.getSingleLowerBound() &&
1231 remLoop.getSingleUpperBound() && remLoop.getSingleStep()) {
1232 tripCount = constantTripCount(*(remLoop.getSingleLowerBound()),
1233 *(remLoop.getSingleUpperBound()),
1234 *(remLoop.getSingleStep()))
1246 if (remainderMap[prevLoop.getOperation()] > 1 &&
1247 foundMap[remLoop.getOperation()] ==
false &&
1248 prevLoop != remLoop) {
1251 if (std::count(unrolledLoops.begin(), unrolledLoops.end(),
1254 tripCountMap[remLoop.getOperation()] = tripCount;
1256 if (tripCountMap[remLoop.getOperation()] < unrollFactor)
1257 unrollFactor = tripCountMap[remLoop.getOperation()];
1259 if (unrollFactor == 0) {
1260 remLoop.emitOpError()
1261 <<
"could not be unrolled with unrollFactor = 0, check "
1264 return WalkResult::interrupt();
1266 remainderMap[remLoop.getOperation()] =
1267 tripCountMap[remLoop.getOperation()] % unrollFactor;
1268 auto step = remLoop.getStep()
1269 .getDefiningOp<arith::ConstantOp>()
1271 int64_t step_value = llvm::dyn_cast<IntegerAttr>(step).getInt();
1273 if (step_value < unrollFactor ||
1274 foundMap[remLoop.getOperation()]) {
1276 if (failed(mlir::loopUnrollByFactor(remLoop, unrollFactor))) {
1277 remLoop.emitOpError()
1278 <<
"could not be unrolled with unrollFactor: "
1279 << unrollFactor <<
"\n";
1280 return WalkResult::interrupt();
1282 unrolledLoops.push_back(remLoop);
1283 foundMap[remLoop.getOperation()] =
false;
1285 remainderMap[remLoop.getOperation()] = 0;
1286 foundMap[remLoop.getOperation()] =
false;
1289 remainderMap[remLoop.getOperation()] = 0;
1290 foundMap[remLoop.getOperation()] =
false;
1293 return WalkResult::advance();
1296 return WalkResult::advance();
1298 if (res.wasInterrupted())
1329 std::set<TileOp> objectFifoTiles) {
1330 for (
auto coreOp : device.getOps<CoreOp>()) {
1331 if (objectFifoTiles.count(coreOp.getTileOp()) <= 0)
1333 if (objectFifoTiles.count(coreOp.getTileOp()) > 0) {
1339 std::map<std::pair<ObjectFifoCreateOp, ObjectFifoPort>,
int> fifoSizes;
1342 std::map<std::pair<ObjectFifoCreateOp, ObjectFifoPort>,
1345 std::map<std::pair<ObjectFifoCreateOp, ObjectFifoPort>,
1350 builder.setInsertionPointToStart(&(coreOp.getBody().front()));
1351 Value initVal = builder.create<arith::ConstantOp>(
1352 builder.getUnknownLoc(), builder.getI32IntegerAttr(0));
1353 coreOp.walk([&](ObjectFifoAcquireOp acqOp) {
1354 ObjectFifoCreateOp op = acqOp.getObjectFifo();
1355 ObjectFifoPort
port = acqOp.getPort();
1356 if (fifoSizes.find({op,
port}) == fifoSizes.end()) {
1357 fifoSizes[{op,
port}] = op.size();
1358 auto indexOp = builder.create<arith::ConstantOp>(
1359 initVal.getLoc(), builder.getIndexAttr(index));
1360 globalIndices[{op,
port}] = indexOp;
1362 auto size = builder.create<arith::ConstantOp>(
1363 indexOp.getLoc(), builder.getI32IntegerAttr(op.size()));
1364 constantSizes[{op,
port}] = size;
1367 builder.setInsertionPoint(coreOp);
1369 MemRefType::get(SmallVector<int64_t>{(int64_t)fifoSizes.size()},
1370 builder.getI32Type());
1371 auto globalNextIndex = builder.create<BufferOp>(
1372 builder.getUnknownLoc(), memrefTy, coreOp.getTile(),
1377 for (
auto i : constantSizes) {
1378 builder.setInsertionPointAfter(i.second);
1379 builder.create<memref::StoreOp>(
1380 builder.getUnknownLoc(), initVal, globalNextIndex,
1381 ValueRange(ArrayRef({globalIndices[i.first].getResult()})));
1390 WalkResult res = coreOp.walk([&](Operation *op) {
1391 if (
auto relOp = dyn_cast<ObjectFifoReleaseOp>(op)) {
1392 ObjectFifoCreateOp createOp = relOp.getObjectFifo();
1393 ObjectFifoPort
port = relOp.getPort();
1394 updateGlobalNextIndex(builder, relOp, globalNextIndex,
1395 globalIndices[{createOp,
port}],
1396 constantSizes[{createOp,
port}]);
1398 if (
auto acqOp = dyn_cast<ObjectFifoAcquireOp>(op)) {
1399 std::vector<ObjectFifoSubviewAccessOp> accessOps;
1400 for (
auto u : acqOp->getUsers())
1401 if (
auto accessOp = dyn_cast<ObjectFifoSubviewAccessOp>(u))
1402 accessOps.push_back(accessOp);
1404 for (
auto accessOp : accessOps) {
1405 ObjectFifoCreateOp createOp = acqOp.getObjectFifo();
1406 ObjectFifoPort
port = acqOp.getPort();
1409 if (fifoSizes[{createOp,
port}] == 1)
1410 return WalkResult::advance();
1413 builder.setInsertionPointAfter(accessOp);
1414 auto switchIndexAsInteger = builder.create<memref::LoadOp>(
1415 builder.getUnknownLoc(), globalNextIndex,
1417 ArrayRef({globalIndices[{createOp,
port}].getResult()})));
1418 auto switchIndex = builder.create<arith::IndexCastOp>(
1419 builder.getUnknownLoc(), builder.getIndexType(),
1420 switchIndexAsInteger);
1421 unsigned caseRegionCounts = fifoSizes[{createOp,
port}];
1422 SmallVector<int64_t, 4> caseValues;
1423 for (
int i = 0; i < fifoSizes[{createOp,
port}]; ++i) {
1424 caseValues.push_back(i);
1427 DenseI64ArrayAttr::get(builder.getContext(), caseValues);
1428 auto switchOp = builder.create<scf::IndexSwitchOp>(
1429 switchIndex.getLoc(),
1430 TypeRange({buffersPerFifo[createOp][0].getType()}),
1431 switchIndex, cases, caseRegionCounts);
1433 builder.createBlock(&switchOp.getDefaultRegion());
1434 auto bufferIndex = (accessOp.getIndex()) % createOp.size();
1435 builder.setInsertionPointToStart(&(switchOp.getDefaultBlock()));
1436 builder.create<scf::YieldOp>(
1437 builder.getUnknownLoc(),
1438 buffersPerFifo[createOp][bufferIndex].getResult());
1439 for (
int i = 0; i < fifoSizes[{createOp,
port}]; ++i) {
1441 builder.createBlock(&switchOp.getCaseRegions()[i]);
1442 builder.setInsertionPoint(&switchOp.getCaseBlock(i),
1443 switchOp.getCaseBlock(i).begin());
1444 int bufferToBeAccesed =
1445 (accessOp.getIndex() + i) % fifoSizes[{createOp,
port}];
1446 builder.create<scf::YieldOp>(
1447 switchOp.getCaseRegions()[i].getLoc(),
1448 buffersPerFifo[createOp][bufferToBeAccesed].getResult());
1453 accessOp.getOutput().replaceAllUsesWith(switchOp.getResult(0));
1456 return WalkResult::advance();
1458 if (res.wasInterrupted())
1699 DeviceOp device = getOperation();
1702 OpBuilder builder = OpBuilder::atBlockTerminator(device.getBody());
1703 auto ctx = device->getContext();
1704 auto producerWireType = WireBundle::DMA;
1705 auto consumerWireType = WireBundle::DMA;
1709 verifyObjectFifoLinks(device);
1717 std::vector<ObjectFifoCreateOp> createFifoOps;
1718 auto range = device.getOps<ObjectFifoCreateOp>();
1719 createFifoOps.insert(createFifoOps.end(), range.begin(), range.end());
1720 for (
auto createOp : createFifoOps) {
1721 std::vector<ObjectFifoCreateOp> splitConsumerFifos;
1722 int consumerIndex = 0;
1723 int consumerDepth = createOp.size();
1724 ArrayRef<BDDimLayoutArrayAttr> consumerDims =
1725 createOp.getDimensionsFromStreamPerConsumer();
1729 if (
int share_direction = 0; !requiresDMAs(createOp, share_direction)) {
1733 for (
auto consumerTile : createOp.getConsumerTiles()) {
1734 auto consumerTileOp = dyn_cast<TileOp>(consumerTile.getDefiningOp());
1736 if (isa<ArrayAttr>(createOp.getElemNumber())) {
1738 consumerDepth = createOp.size(consumerIndex + 1);
1740 consumerDepth = findObjectFifoSize(device, consumerTileOp, createOp);
1743 builder.setInsertionPointAfter(createOp);
1744 auto datatype = llvm::cast<AIEObjectFifoType>(createOp.getElemType());
1745 auto consumerObjFifoSize =
1746 builder.getIntegerAttr(builder.getI32Type(), consumerDepth);
1748 std::string consumerFifoName;
1749 if (createOp.getConsumerTiles().size() > 1) {
1750 consumerFifoName = createOp.name().str() +
"_" +
1751 std::to_string(consumerIndex) +
"_cons";
1753 consumerFifoName = createOp.name().str() +
"_cons";
1755 BDDimLayoutArrayAttr emptyDims =
1756 BDDimLayoutArrayAttr::get(builder.getContext(), {});
1757 BDDimLayoutArrayAttr singletonFromStreamDims =
1758 BDDimLayoutArrayAttr::get(
1759 builder.getContext(),
1760 ArrayRef<BDDimLayoutAttr>{consumerDims[consumerIndex]});
1761 BDDimLayoutArrayArrayAttr fromStreamDims =
1762 BDDimLayoutArrayArrayAttr::get(builder.getContext(),
1763 singletonFromStreamDims);
1765 ObjectFifoCreateOp consumerFifo = createObjectFifo(
1766 builder, datatype, consumerFifoName, consumerTile, consumerTile,
1767 consumerObjFifoSize, emptyDims, fromStreamDims);
1768 if (createOp.getDisableSynchronization())
1769 consumerFifo.setDisableSynchronization(
true);
1770 replaceSplitFifo(createOp, consumerFifo, consumerTileOp);
1773 if (consumerTile.getDefiningOp<TileOp>().isShimTile())
1774 detectExternalBuffers(device, createOp, consumerFifo, consumerTile);
1777 splitConsumerFifos.push_back(consumerFifo);
1780 if (
auto linkOp = getOptionalLinkOp(createOp))
1781 for (ObjectFifoCreateOp fifoIn : linkOp->getInputObjectFifos())
1782 if (fifoIn.name() == createOp.name() &&
1783 consumerTile == *linkOp->getOptionalSharedTile())
1784 if (failed(SymbolTable::replaceAllSymbolUses(
1785 createOp, consumerFifo.name(), linkOp->getOperation())))
1786 llvm::report_fatal_error(
"unable to update all symbol uses");
1791 if (!splitConsumerFifos.empty()) {
1792 splitFifos.emplace_back(createOp, splitConsumerFifos);
1802 for (
auto createOp : device.getOps<ObjectFifoCreateOp>()) {
1804 int share_direction = 0;
1805 bool shared = !requiresDMAs(createOp, share_direction);
1809 objectFifoTiles.insert(createOp.getProducerTileOp());
1810 for (
auto consumerTile : createOp.getConsumerTiles()) {
1811 auto consumerTileOp = dyn_cast<TileOp>(consumerTile.getDefiningOp());
1812 objectFifoTiles.insert(consumerTileOp);
1817 if (createOp.getProducerTileOp().isShimTile())
1818 detectExternalBuffers(device, createOp, createOp,
1819 createOp.getProducerTile());
1824 checkAndApplyViaSharedMemAttribute(createOp, share_direction);
1825 createObjectFifoElements(builder, lockAnalysis, createOp,
1829 if (createOp.getViaSharedMem().has_value())
1830 createOp->emitOpError(
1831 "no access to shared memory module specified by "
1832 "`via_shared_mem`");
1834 if (isa<ArrayAttr>(createOp.getElemNumber()))
1835 createOp.setElemNumberAttr(
1836 builder.getI32IntegerAttr(createOp.size()));
1839 if (!createOp.getInitValues().has_value()) {
1841 int prodMaxAcquire = findObjectFifoSize(
1842 device, createOp.getProducerTileOp(), createOp);
1843 createOp.setElemNumberAttr(
1844 builder.getI32IntegerAttr(prodMaxAcquire));
1847 createObjectFifoElements(builder, lockAnalysis, createOp,
1853 auto crossTileInfos = analyzeCrossTileFIFOBuffers();
1859 std::map<ObjectFifoCreateOp, int> fifo_dma_channel_index;
1862 assignDMAChannelIndices(dmaAnalysis, crossTileInfos, fifo_dma_channel_index,
1866 assignDMAChannelIndices(dmaAnalysis, crossTileInfos, fifo_dma_channel_index,
1874 for (
auto &[producer, consumers] : splitFifos) {
1875 int producerChanIndex = fifo_dma_channel_index[producer];
1876 if (producerChanIndex == -1)
1877 producer.getProducerTileOp().emitOpError(
1878 "number of output DMA channel exceeded!");
1879 DMAChannel producerChan = {DMAChannelDir::MM2S, producerChanIndex};
1880 createDMA(device, builder, producer, producerChan.direction,
1881 producerChan.channel, 0, producer.getDimensionsToStreamAttr(),
1882 producer.getPadDimensionsAttr());
1884 builder.setInsertionPoint(device.getBody()->getTerminator());
1886 if (producer.getProducerTileOp().isShimTile())
1887 createObjectFifoAllocationInfo(
1888 builder, ctx, SymbolRefAttr::get(ctx, producer.getName()),
1889 producer.getProducerTileOp().colIndex(), producerChan.direction,
1890 producerChan.channel, producer.getPlio());
1892 for (
auto consumer : consumers) {
1893 int consumerChanIndex = fifo_dma_channel_index[consumer];
1894 if (consumerChanIndex == -1)
1895 consumer.getProducerTileOp().emitOpError(
1896 "number of input DMA channel exceeded!");
1897 DMAChannel consumerChan = {DMAChannelDir::S2MM, consumerChanIndex};
1898 BDDimLayoutArrayAttr consumerDims =
1899 consumer.getDimensionsFromStreamPerConsumer()[0];
1900 createDMA(device, builder, consumer, consumerChan.direction,
1901 consumerChan.channel, 1, consumerDims,
nullptr);
1903 builder.setInsertionPoint(device.getBody()->getTerminator());
1906 if (producer.getPlio()) {
1907 producerWireType = producer.getProducerTileOp().isShimTile()
1910 consumerWireType = consumer.getProducerTileOp().isShimTile()
1914 producerWireType = WireBundle::DMA;
1915 consumerWireType = WireBundle::DMA;
1918 if (consumer.getProducerTileOp().isShimTile())
1919 createObjectFifoAllocationInfo(
1920 builder, ctx, SymbolRefAttr::get(ctx, producer.getName()),
1921 consumer.getProducerTileOp().colIndex(), consumerChan.direction,
1922 consumerChan.channel, producer.getPlio());
1925 builder.setInsertionPointAfter(producer);
1926 builder.create<FlowOp>(builder.getUnknownLoc(),
1927 producer.getProducerTile(), producerWireType,
1928 producerChan.channel, consumer.getProducerTile(),
1929 consumerWireType, consumerChan.channel);
1936 if (clDynamicObjectFifos) {
1937 if (failed(dynamicGlobalObjectFifos(device, builder, objectFifoTiles)))
1938 signalPassFailure();
1940 std::set<TileOp> dynamicTiles;
1941 std::set<TileOp> unrollTiles;
1942 for (
auto c : device.getOps<CoreOp>()) {
1943 TileOp t = c.getTileOp();
1944 if (objectFifoTiles.count(t) > 0) {
1945 if (c.getDynamicObjfifoLowering().has_value()) {
1946 if (c.getDynamicObjfifoLowering().value())
1947 dynamicTiles.insert(t);
1949 unrollTiles.insert(t);
1951 unrollTiles.insert(t);
1955 if (failed(dynamicGlobalObjectFifos(device, builder, dynamicTiles)))
1956 signalPassFailure();
1957 if (failed(unrollForLoops(device, builder, unrollTiles)))
1958 signalPassFailure();
1964 for (
auto coreOp : device.getOps<CoreOp>()) {
1965 DenseMap<ObjectFifoAcquireOp, std::vector<BufferOp *>>
1968 DenseMap<std::pair<ObjectFifoCreateOp, int>, std::vector<int>>
1972 DenseMap<std::pair<ObjectFifoCreateOp, int>,
1973 std::vector<ObjectFifoReleaseOp>>
1976 DenseMap<std::pair<ObjectFifoCreateOp, int>,
int>
1979 DenseMap<std::pair<ObjectFifoCreateOp, int>,
int>
1986 coreOp.walk([&](ObjectFifoReleaseOp releaseOp) {
1987 builder.setInsertionPointAfter(releaseOp);
1988 ObjectFifoCreateOp op = releaseOp.getObjectFifo();
1989 auto port = releaseOp.getPort();
1990 auto portNum =
port == ObjectFifoPort::Produce ? 0 : 1;
1991 auto core = releaseOp->getParentOfType<CoreOp>();
1993 if (
auto linkOp = getOptionalLinkOp(op)) {
1994 if (core.getTile() == *linkOp->getOptionalSharedTile()) {
1995 releaseOp->emitOpError(
"currently cannot access objectFifo used in "
1996 "ObjectFifoLinkOp");
2002 updateAndReturnIndex(relPerFifo, {op, portNum});
2005 int numLocks = releaseOp.relNumber();
2007 if (op.getRepeatCount().has_value())
2008 numLocks *= op.getRepeatCount().value();
2009 createUseLocks(builder, op,
port, relPerFifo, numLocks,
2010 LockAction::Release);
2013 if (releaseOps.find({op, portNum}) != releaseOps.end()) {
2014 releaseOps[{op, portNum}].push_back(releaseOp);
2016 std::vector release = {releaseOp};
2017 releaseOps[{op, portNum}] = release;
2024 coreOp.walk([&](ObjectFifoAcquireOp acquireOp) {
2025 ObjectFifoCreateOp op = acquireOp.getObjectFifo();
2026 builder.setInsertionPointAfter(acquireOp);
2027 auto port = acquireOp.getPort();
2028 auto portNum =
port == ObjectFifoPort::Produce ? 0 : 1;
2029 auto core = acquireOp->getParentOfType<CoreOp>();
2031 auto linkOp = getOptionalLinkOp(op);
2033 if (core.getTile() == *linkOp->getOptionalSharedTile()) {
2034 acquireOp->emitOpError(
"currently cannot access objectFifo used in "
2035 "ObjectFifoLinkOp");
2041 int start = updateAndReturnIndex(
2042 acqPerFifo, {op, portNum});
2049 for (std::vector<ObjectFifoReleaseOp>::iterator relOp =
2050 releaseOps[{op, portNum}].begin();
2051 relOp != releaseOps[{op, portNum}].end();) {
2052 bool erased =
false;
2053 Operation *acqBlockDefOp = acquireOp.getOperation();
2055 Operation *relBlockDefOp = (*relOp).getOperation();
2057 if (acqBlockDefOp->getBlock() == relBlockDefOp->getBlock()) {
2058 if (relBlockDefOp->isBeforeInBlock(acqBlockDefOp)) {
2059 numRel += (*relOp).relNumber();
2060 relOp = releaseOps[{op, portNum}].erase(relOp);
2067 }
while ((relBlockDefOp = relBlockDefOp->getParentOp()) &&
2068 !isa<DeviceOp>(relBlockDefOp) && !erased);
2069 }
while ((acqBlockDefOp = acqBlockDefOp->getParentOp()) &&
2070 !isa<DeviceOp>(acqBlockDefOp) && !erased);
2076 std::vector<int> acquiredIndices;
2077 if (!acquiresPerFifo[{op, portNum}].empty()) {
2080 acquiredIndices = acquiresPerFifo[{op, portNum}];
2082 if (
static_cast<size_t>(numRel) > acquiredIndices.size()) {
2083 acquireOp->emitOpError(
"cannot release more elements than are "
2084 "already acquired");
2087 for (
int i = 0; i < numRel; i++)
2088 acquiredIndices.erase(acquiredIndices.begin());
2092 int numLocks = acquireOp.acqNumber();
2093 int alreadyAcq = acquiredIndices.size();
2095 if (numLocks > alreadyAcq)
2096 numCreate = numLocks - alreadyAcq;
2101 if (op.getRepeatCount().has_value())
2102 numCreate *= op.getRepeatCount().value();
2104 auto dev = op->getParentOfType<DeviceOp>();
2105 if (
auto &targetArch = dev.getTargetModel();
2106 targetArch.getTargetArch() == AIEArch::AIE1)
2107 createUseLocks(builder, op,
port, acqPerFifo, numCreate,
2108 LockAction::Acquire);
2110 createUseLocks(builder, op,
port, acqPerFifo, numCreate,
2111 LockAction::AcquireGreaterEqual);
2115 ObjectFifoCreateOp target = op;
2117 if (objFifoLinks.find(*linkOp) != objFifoLinks.end())
2118 target = objFifoLinks[*linkOp];
2121 for (
int i = 0; i < numCreate; i++) {
2122 acquiredIndices.push_back(start);
2123 start = (start + 1) % op.size();
2125 std::vector<BufferOp *> subviewRefs;
2126 subviewRefs.reserve(acquiredIndices.size());
2127 for (
auto index : acquiredIndices)
2128 subviewRefs.push_back(&buffersPerFifo[target][index]);
2130 subviews[acquireOp] = subviewRefs;
2131 acquiresPerFifo[{op, portNum}] = acquiredIndices;
2137 coreOp.walk([&](ObjectFifoSubviewAccessOp accessOp) {
2138 auto acqOp = accessOp.getSubview().getDefiningOp<ObjectFifoAcquireOp>();
2139 if (ObjectFifoCreateOp op = acqOp.getObjectFifo()) {
2140 if (
auto linkOp = getOptionalLinkOp(op); linkOp.has_value()) {
2141 if (!linkOp->isDistribute() && !linkOp->isJoin()) {
2142 for (
auto consumerTile : op.getConsumerTiles()) {
2143 if (
auto consumerTileOp =
2144 dyn_cast<TileOp>(consumerTile.getDefiningOp())) {
2145 int share_dir_value = 0;
2146 bool sharing = isSharedMemory(
2147 op.getProducerTileOp(), consumerTileOp, &share_dir_value);
2149 accessOp->emitOpError(
2150 "currently cannot access objectFifo used in "
2151 "ObjectFifoLinkOp if the tiles don't share memory");
2155 accessOp->emitOpError(
2156 "currently cannot access objectFifo used in "
2157 "ObjectFifoLinkOp if it is a distribute or join link");
2160 accessOp.getOutput().replaceAllUsesWith(
2161 subviews[acqOp][accessOp.getIndex()]->getBuffer());
2165 for (
auto createOp : device.getOps<ObjectFifoCreateOp>()) {
2166 builder.setInsertionPointToStart(device.getBody());
2167 auto sym_name = createOp.getName();
2168 createOp->setAttr(SymbolTable::getSymbolAttrName(),
2169 builder.getStringAttr(
"__erase_" + sym_name));
2170 auto memrefType = llvm::cast<AIEObjectFifoType>(createOp.getElemType())
2172 builder.create<memref::GlobalOp>(builder.getUnknownLoc(), sym_name,
2173 builder.getStringAttr(
"public"),
2174 memrefType,
nullptr,
false,
nullptr);
2180 SetVector<Operation *> opsToErase;
2181 device.walk([&](Operation *op) {
2182 if (isa<ObjectFifoCreateOp, ObjectFifoLinkOp,
2183 ObjectFifoRegisterExternalBuffersOp, ObjectFifoAcquireOp,
2184 ObjectFifoSubviewAccessOp, ObjectFifoReleaseOp>(op))
2185 opsToErase.insert(op);
2187 SmallVector<Operation *> sorted{opsToErase.begin(), opsToErase.end()};
2188 computeTopologicalSorting(sorted);
2189 for (
auto *op : llvm::reverse(sorted))