16#include "mlir/Dialect/Arith/IR/Arith.h"
17#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
18#include "mlir/Dialect/MemRef/IR/MemRef.h"
19#include "mlir/Dialect/SCF/IR/SCF.h"
20#include "mlir/Pass/Pass.h"
21#include "mlir/Transforms/DialectConversion.h"
26#define GEN_PASS_DEF_AIEDMATONPU
27#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
36struct Write32SymToAddr : OpConversionPattern<NpuWrite32Op> {
37 using OpConversionPattern::OpConversionPattern;
39 Write32SymToAddr(MLIRContext *context,
const AIE::NamedOpTable &names)
40 : OpConversionPattern(context), names(names) {}
42 const AIE::NamedOpTable &names;
45 matchAndRewrite(NpuWrite32Op op, OpAdaptor adaptor,
46 ConversionPatternRewriter &rewriter)
const override {
51 std::optional<uint32_t> address = op.getAbsoluteAddress(&names);
52 if (!address.has_value()) {
57 rewriter.replaceOpWithNewOp<NpuWrite32Op>(
58 op, addressVal, adaptor.getValue(),
nullptr,
nullptr,
nullptr);
63struct BlockWriteSymToAddr : OpConversionPattern<NpuBlockWriteOp> {
64 using OpConversionPattern::OpConversionPattern;
66 BlockWriteSymToAddr(MLIRContext *context,
const AIE::NamedOpTable &names)
67 : OpConversionPattern(context), names(names) {}
69 const AIE::NamedOpTable &names;
72 matchAndRewrite(NpuBlockWriteOp op, OpAdaptor adaptor,
73 ConversionPatternRewriter &rewriter)
const override {
78 std::optional<uint32_t> address = op.getAbsoluteAddress(&names);
79 if (!address.has_value()) {
82 rewriter.replaceOpWithNewOp<NpuBlockWriteOp>(op, *address, op.getData(),
83 nullptr,
nullptr,
nullptr);
88struct MaskWrite32SymToAddr : OpConversionPattern<NpuMaskWrite32Op> {
89 using OpConversionPattern::OpConversionPattern;
91 MaskWrite32SymToAddr(MLIRContext *context,
const AIE::NamedOpTable &names)
92 : OpConversionPattern(context), names(names) {}
94 const AIE::NamedOpTable &names;
97 matchAndRewrite(NpuMaskWrite32Op op, OpAdaptor adaptor,
98 ConversionPatternRewriter &rewriter)
const override {
103 std::optional<uint32_t> absoluteAddress = op.getAbsoluteAddress(&names);
104 if (!absoluteAddress.has_value()) {
110 rewriter.replaceOpWithNewOp<NpuMaskWrite32Op>(
111 op, addressVal, adaptor.getValue(), adaptor.getMask(),
nullptr,
nullptr,
117struct MaskPollSymToAddr : OpConversionPattern<NpuMaskPollOp> {
118 using OpConversionPattern::OpConversionPattern;
120 MaskPollSymToAddr(MLIRContext *context,
const AIE::NamedOpTable &names)
121 : OpConversionPattern(context), names(names) {}
123 const AIE::NamedOpTable &names;
126 matchAndRewrite(NpuMaskPollOp op, OpAdaptor adaptor,
127 ConversionPatternRewriter &rewriter)
const override {
131 std::optional<uint32_t> absoluteAddress = op.getAbsoluteAddress(&names);
132 if (!absoluteAddress)
137 rewriter.replaceOpWithNewOp<NpuMaskPollOp>(
138 op, addressVal, adaptor.getValue(), adaptor.getMask(),
nullptr,
nullptr,
144struct RtpToWrite32Pattern : OpConversionPattern<NpuWriteRTPOp> {
145 using OpConversionPattern::OpConversionPattern;
147 RtpToWrite32Pattern(MLIRContext *context,
const AIE::NamedOpTable &names)
148 : OpConversionPattern(context), names(names) {}
150 const AIE::NamedOpTable &names;
153 matchAndRewrite(NpuWriteRTPOp op, OpAdaptor adaptor,
154 ConversionPatternRewriter &rewriter)
const override {
156 auto buffer = names.lookup<AIE::BufferOp>(op.getBufferAttr().getAttr());
158 op->emitError(
"buffer '" + op.getBuffer() +
"' not found in device");
162 auto bufferAddress = buffer.getAddress();
163 if (!bufferAddress) {
164 op->emitError(
"buffer must have address assigned");
167 AIE::TileOp tile = buffer.getTileOp();
169 uint32_t idx = op.getIndex() *
sizeof(uint32_t);
170 uint32_t address = *bufferAddress + idx;
172 NpuWrite32Op::create(rewriter, op->getLoc(),
174 adaptor.getValue(),
nullptr,
175 rewriter.getI32IntegerAttr(tile.getCol()),
176 rewriter.getI32IntegerAttr(tile.getRow()));
178 rewriter.eraseOp(op);
183struct PushQueuetoWrite32Pattern : OpConversionPattern<NpuPushQueueOp> {
186 using OpConversionPattern::OpConversionPattern;
188 PushQueuetoWrite32Pattern(MLIRContext *context, PatternBenefit benefit = 1)
189 : OpConversionPattern(context, benefit) {}
192 matchAndRewrite(NpuPushQueueOp op, OpAdaptor adaptor,
193 ConversionPatternRewriter &rewriter)
const override {
196 uint32_t ctrl_offset = tm.getDmaControlAddress(
197 op.getColumn(), op.getRow(), op.getChannel(), op.getDirection());
200 if (op.getIssueToken()) {
203 AIE::TileOp shimTile = AIE::TileOp::getOrCreate(
204 rewriter, op->getParentOfType<AIE::DeviceOp>(), op.getColumn(),
206 if (shimTile->hasAttr(
"controller_id")) {
207 AIE::PacketInfoAttr controller_id_attr =
208 shimTile->getAttrOfType<AIE::PacketInfoAttr>(
"controller_id");
209 uint32_t data = controller_id_attr.assignedId() << 8;
210 uint32_t mask = 0x00001F00;
211 NpuMaskWrite32Op::create(
212 rewriter, op->getLoc(),
221 uint32_t queue_offset = ctrl_offset + 0x4;
229 Location loc = op->getLoc();
230 auto i32ty = rewriter.getIntegerType(32);
232 tm.isMemTile(op.getColumn(), op.getRow()) ? 0x3Fu : 0xFu;
234 std::optional<uint64_t> repeat_cnt =
236 uint32_t issueBit = op.getIssueToken() ? 0x80000000 : 0;
242 if (IntegerAttr idx = op.getRepeatStateTableIdxAttr()) {
243 NpuUpdateFromScratchpadOp::create(
244 rewriter, loc,
static_cast<uint8_t
>(idx.getUInt()),
245 StateTableFunc::Incr,
247 (*bd_id & bdIdMask) | issueBit,
248 queue_offset,
nullptr,
nullptr,
250 rewriter.eraseOp(op);
255 if (bd_id && repeat_cnt) {
257 (*bd_id & bdIdMask) |
258 ((*repeat_cnt & 0xFF) << 16) | issueBit);
271 getAsI64(rewriter, loc, OpFoldResult(op.getRepeatCount()));
274 uint32_t maxRepeat = tm.getMaxRepeatCount();
275 Value inRange = arith::CmpIOp::create(
276 rewriter, loc, arith::CmpIPredicate::ule, repeat64,
277 arith::ConstantOp::create(rewriter, loc,
278 rewriter.getI64IntegerAttr(maxRepeat)));
280 rewriter, loc, inRange,
281 "a runtime DMA repeat count exceeds the task queue's [0:" +
282 Twine(maxRepeat) +
"] range (at most " +
283 Twine(maxRepeat + 1) +
" executions)")))
285 repeat = rewriter.createOrFold<arith::TruncIOp>(loc, i32ty, repeat64);
288 Value bdField = rewriter.createOrFold<arith::AndIOp>(
289 loc,
getAsValue(rewriter, loc, op.getBdId(), i32ty),
291 cmd = rewriter.createOrFold<arith::OrIOp>(loc, cmd, bdField);
292 Value masked = rewriter.createOrFold<arith::AndIOp>(
294 Value shifted = rewriter.createOrFold<arith::ShLIOp>(
296 cmdVal = rewriter.createOrFold<arith::OrIOp>(loc, cmd, shifted);
299 NpuWrite32Op::create(
300 rewriter, op->getLoc(),
302 nullptr,
nullptr,
nullptr);
303 rewriter.eraseOp(op);
308struct DmaToNpuPattern : OpConversionPattern<NpuDmaMemcpyNdOp> {
309 using OpConversionPattern::OpConversionPattern;
312 DmaToNpuPattern(MLIRContext *context, PatternBenefit benefit = 1)
313 : OpConversionPattern(context, benefit) {}
316 matchAndRewrite(NpuDmaMemcpyNdOp op, OpAdaptor adaptor,
317 ConversionPatternRewriter &rewriter)
const override {
322 bool allOffsetsConstant =
323 llvm::all_of(op.getMixedOffsets(),
324 [](OpFoldResult s) { return getConstantIntValue(s); });
325 bool allSizesConstant =
326 llvm::all_of(op.getMixedSizes(),
327 [](OpFoldResult s) { return getConstantIntValue(s); });
328 bool allStridesConstant =
329 llvm::all_of(op.getMixedStrides(),
330 [](OpFoldResult s) { return getConstantIntValue(s); });
331 if (!allOffsetsConstant || !allSizesConstant || !allStridesConstant)
332 return lowerDynamic(op, adaptor, rewriter);
335 BaseMemRefType bufferType = op.getMemref().getType();
336 auto *ctx = op->getContext();
337 auto i32ty = IntegerType::get(ctx, 32);
338 auto zero = IntegerAttr::get(i32ty, 0);
340 auto dev = op->getParentOfType<AIE::DeviceOp>();
344 auto infoOp = AIE::ShimDMAAllocationOp::getForSymbol(
345 dev, op.getMetadata().getRootReference());
347 return op->emitOpError(
"couldn't find shim_dma_allocation op.");
350 AIE::TileOp shimTile = infoOp.getTileOp();
352 return op->emitOpError(
353 "shim_dma_allocation op must reference a valid TileOp.");
356 auto channelDir = infoOp.getChannelDir();
357 bool isMM2S = channelDir == AIE::DMAChannelDir::MM2S;
358 int tileCol = shimTile.getCol();
359 int tileRow = shimTile.getRow();
364 auto buffer_length = zero;
365 auto buffer_offset = zero;
366 auto enable_packet = zero;
367 auto out_of_order_id = zero;
368 auto packet_id = zero;
369 auto packet_type = zero;
371 auto d0_stride = zero;
373 auto d1_stride = zero;
375 auto d2_stride = zero;
376 auto iteration_current = zero;
377 auto iteration_size = zero;
378 auto iteration_stride = zero;
381 auto use_next_bd = zero;
382 auto valid_bd = zero;
383 auto lock_rel_val = zero;
384 auto lock_rel_id = zero;
385 auto lock_acq_enable = zero;
386 auto lock_acq_val = zero;
387 auto lock_acq_id = zero;
388 auto d0_zero_before = zero;
389 auto d1_zero_before = zero;
390 auto d2_zero_before = zero;
391 auto d0_zero_after = zero;
392 auto d1_zero_after = zero;
393 auto d2_zero_after = zero;
394 auto burst_length = zero;
397 auto issue_token = BoolAttr::get(ctx,
false);
398 auto repeat_count = zero;
399 llvm::SmallVector<int64_t, 4> inputSizes = llvm::map_to_vector(
400 llvm::reverse(op.getMixedSizes()),
401 [](OpFoldResult s) { return getConstantIntValue(s).value(); });
402 llvm::SmallVector<int64_t, 4> inputStrides = llvm::map_to_vector(
403 llvm::reverse(op.getMixedStrides()),
404 [](OpFoldResult s) { return getConstantIntValue(s).value(); });
410 inputSizes, inputStrides);
411 if (!isLinear && op.getLengthStateTableIdxAttr())
413 llvm::SmallVector<int64_t, 4> sizes(4);
414 llvm::SmallVector<int64_t, 4> strides(4);
416 inputStrides, sizes, strides);
419 column = IntegerAttr::get(i32ty, tileCol);
422 row = IntegerAttr::get(i32ty, tileRow);
425 op, [&] {
return op->emitOpError(); }, bufferType, tileCol, tileRow,
426 inputSizes, inputStrides, sizes, strides, isLinear))) {
431 bd_id = IntegerAttr::get(i32ty, op.getId());
434 uint64_t buffer_length_val = inputSizes[0] * op.getElementTypeBitwidth() /
435 targetModel.getAddressGenGranularity();
436 if (inputSizes.size() > 1) {
437 for (
size_t i = 1; i < std::min(inputSizes.size(), (
size_t)3); i++) {
438 buffer_length_val *= inputSizes[i];
441 buffer_length = IntegerAttr::get(i32ty, buffer_length_val);
444 buffer_offset = IntegerAttr::get(i32ty, 0);
447 if (
auto packetInfo =
448 op.getPacket() ? op.getPacket() : infoOp.getPacket()) {
449 enable_packet = IntegerAttr::get(i32ty, 1);
450 packet_type = IntegerAttr::get(i32ty, packetInfo->getPktType());
451 packet_id = IntegerAttr::get(i32ty, packetInfo->assignedId());
459 d0_size = IntegerAttr::get(i32ty, sizes[0]);
460 d0_stride = IntegerAttr::get(i32ty, strides[0]);
463 d1_size = IntegerAttr::get(i32ty, sizes[1]);
464 d1_stride = IntegerAttr::get(i32ty, strides[1]);
467 d2_stride = IntegerAttr::get(i32ty, strides[2]);
470 if (targetModel.isMemTile(tileCol, 0))
471 d2_size = IntegerAttr::get(i32ty, sizes[2]);
473 d2_size = IntegerAttr::get(i32ty, 0);
476 if (inputSizes[3] > 1) {
477 if (inputStrides[3] > 0) {
478 iteration_size = IntegerAttr::get(i32ty, sizes[3]);
479 iteration_stride = IntegerAttr::get(i32ty, strides[3]);
485 iteration_size = zero;
486 iteration_stride = zero;
489 repeat_count = IntegerAttr::get(i32ty, sizes[3]);
496 valid_bd = IntegerAttr::get(i32ty, 1);
509 d0_zero_before = IntegerAttr::get(i32ty, op.getD0ZeroBefore());
512 d1_zero_before = IntegerAttr::get(i32ty, op.getD1ZeroBefore());
515 d2_zero_before = IntegerAttr::get(i32ty, op.getD2ZeroBefore());
518 d0_zero_after = IntegerAttr::get(i32ty, op.getD0ZeroAfter());
521 d1_zero_after = IntegerAttr::get(i32ty, op.getD1ZeroAfter());
524 d2_zero_after = IntegerAttr::get(i32ty, op.getD2ZeroAfter());
527 burst_length = IntegerAttr::get(i32ty, op.getBurstLength());
531 if (targetModel.isShimNOCTile(tileCol, tileRow))
532 axcache = IntegerAttr::get(i32ty, op.getAxcacheOrDefault());
534 axcache = IntegerAttr();
537 issue_token = BoolAttr::get(ctx, op.getIssueToken());
541 issue_token = BoolAttr::get(ctx,
true);
543 if (targetModel.isMemTile(tileCol, tileRow) && (!isMM2S) &&
544 (op.getD0ZeroBefore() != 0 || op.getD0ZeroAfter() != 0 ||
545 op.getD1ZeroBefore() != 0 || op.getD1ZeroAfter() != 0 ||
546 op.getD2ZeroBefore() != 0 || op.getD2ZeroAfter() != 0)) {
547 op->emitOpError(
"MemTile supports zero padding only on MM2S direction");
552 NpuWriteBdOp::create(
553 rewriter, op->getLoc(), column, bd_id, buffer_length, buffer_offset,
554 enable_packet, out_of_order_id, packet_id, packet_type, d0_size,
555 d0_stride, d1_size, d1_stride, d2_size, d2_stride, iteration_current,
556 iteration_size, iteration_stride, next_bd, row, use_next_bd, valid_bd,
557 lock_rel_val, lock_rel_id, lock_acq_enable, lock_acq_val, lock_acq_id,
558 d0_zero_before, d1_zero_before, d2_zero_before, d0_zero_after,
559 d1_zero_after, d2_zero_after, burst_length, axcache);
564 if (failed(emitBufferAddressPatch(op, adaptor, rewriter, tileCol, tileRow,
571 auto lengthUnit = op.getLengthUnit();
572 if (op.getLengthStateTableIdxAttr() && lengthUnit) {
574 *lengthUnit, targetModel,
575 tileCol, tileRow, op.getId())))
581 NpuPushQueueOp::create(
582 rewriter, op->getLoc(), column, row, infoOp.getChannelDirAttr(),
583 infoOp.getChannelIndexAttr(), issue_token,
585 static_cast<uint32_t
>(repeat_count.getInt())),
587 static_cast<uint32_t
>(bd_id.getInt())),
590 rewriter.eraseOp(op);
601 LogicalResult emitBufferAddressPatch(NpuDmaMemcpyNdOp op, OpAdaptor adaptor,
602 ConversionPatternRewriter &rewriter,
603 int tileCol,
int tileRow,
605 AIE::RuntimeSequenceOp seqOp =
606 op->getParentOfType<AIE::RuntimeSequenceOp>();
608 return op->emitOpError(
"NpuDmaMemcpyNdOps must have RuntimeSequenceOp "
609 "parent at time of lowering.");
612 return op->emitOpError(
613 "memref must be a block argument or subview/cast/reinterpret_cast of "
614 "a block argument with static offsets, sizes, and strides");
615 std::optional<unsigned> hostIdx =
617 if (!hostIdx || traceResult->rootArg.getOwner() != &seqOp.getBody().front())
619 argIdx =
static_cast<int>(*hostIdx);
623 targetModel.getDmaBdAddress(tileCol, tileRow, op.getId()) +
624 targetModel.getDmaBdAddressOffset(tileCol, tileRow);
630 SmallVector<OpFoldResult> offsets = op.getMixedOffsets();
631 SmallVector<OpFoldResult> strides = op.getMixedStrides();
632 int64_t elemBytes = op.getElementTypeBitwidth() / 8;
633 SmallVector<OpFoldResult> sizes = op.getMixedSizes();
635 llvm::any_of(llvm::concat<OpFoldResult>(offsets, sizes, strides),
636 [](OpFoldResult v) {
return !getConstantIntValue(v); });
638 rewriter, op->getLoc(),
639 cast<BaseMemRefType>(traceResult->rootArg.getType()),
640 traceResult->offsetInBytes, elemBytes, offsets,
641 strides, sizes, strides)))
644 rewriter, op->getLoc(), offsets, strides, elemBytes,
645 traceResult->offsetInBytes, targetModel.getAddressGenGranularity() / 8);
648 NpuAddressPatchOp::create(rewriter, op->getLoc(), patchAddr,
649 Value(), argIdx, argPlus);
654 if (op.getOffsetStateTableIdxAttr()) {
655 auto bufType = cast<BaseMemRefType>(op.getMemref().getType());
667 LogicalResult lowerDynamic(NpuDmaMemcpyNdOp op, OpAdaptor adaptor,
668 ConversionPatternRewriter &rewriter)
const {
670 auto *ctx = op->getContext();
671 auto i32ty = IntegerType::get(ctx, 32);
672 Location loc = op->getLoc();
674 auto dev = op->getParentOfType<AIE::DeviceOp>();
677 auto infoOp = AIE::ShimDMAAllocationOp::getForSymbol(
678 dev, op.getMetadata().getRootReference());
680 return op->emitOpError(
"couldn't find shim_dma_allocation op.");
681 AIE::TileOp shimTile = infoOp.getTileOp();
683 return op->emitOpError(
684 "shim_dma_allocation op must reference a valid TileOp.");
685 auto channelDir = infoOp.getChannelDir();
686 bool isMM2S = channelDir == AIE::DMAChannelDir::MM2S;
687 int tileCol = shimTile.getCol();
688 int tileRow = shimTile.getRow();
691 auto column = IntegerAttr::get(i32ty, tileCol);
692 auto row = IntegerAttr::get(i32ty, tileRow);
693 BdTemplateFields fields;
694 if (
auto packetInfo =
695 op.getPacket() ? op.getPacket() : infoOp.getPacket()) {
698 fields.
packet_id = packetInfo->assignedId();
700 auto issue_token = BoolAttr::get(ctx, op.getIssueToken());
702 issue_token = BoolAttr::get(ctx,
true);
706 SmallVector<Value> words;
708 if (failed(
buildBdWords(rewriter, loc, targetModel, tileCol, tileRow,
709 fields, op.getMixedSizes(), op.getMixedStrides(),
710 op.getElementTypeBitwidth(), op.getBurstLength(),
711 op.getAxcacheOrDefault(),
712 OpFoldResult(), repeatCount, words)))
716 rewriter.getI32IntegerAttr(op.getId()));
717 NpuBlockWriteValuesOp::create(rewriter, loc, bdBase, words);
722 if (failed(emitBufferAddressPatch(op, adaptor, rewriter, tileCol, tileRow,
726 NpuPushQueueOp::create(
727 rewriter, loc, column, row, infoOp.getChannelDirAttr(),
728 infoOp.getChannelIndexAttr(), issue_token, repeatCount,
732 rewriter.eraseOp(op);
740struct DmaWaitToSyncPattern : OpConversionPattern<NpuDmaWaitOp> {
743 using OpConversionPattern::OpConversionPattern;
745 DmaWaitToSyncPattern(MLIRContext *context, PatternBenefit benefit = 1)
746 : OpConversionPattern(context, benefit) {}
749 matchAndRewrite(NpuDmaWaitOp op, OpAdaptor adaptor,
750 ConversionPatternRewriter &rewriter)
const override {
751 AIE::DeviceOp dev = op->getParentOfType<AIE::DeviceOp>();
753 return op->emitError(
"couldn't find parent of type DeviceOp");
755 AIE::ShimDMAAllocationOp shimDmaAllocOp =
756 AIE::ShimDMAAllocationOp::getForSymbol(dev, op.getSymbol());
757 if (!shimDmaAllocOp) {
758 return op->emitError(
"couldn't find shim_dma_allocation op");
761 AIE::TileOp shimTile = shimDmaAllocOp.getTileOp();
763 return op->emitError(
764 "shim_dma_allocation op must reference a valid TileOp");
769 Location loc = op->getLoc();
770 (void)rewriter.replaceOpWithNewOp<NpuSyncOp>(
775 static_cast<uint32_t
>(shimDmaAllocOp.getChannelDir())),
784struct WriteBdToBlockWritePattern : OpConversionPattern<NpuWriteBdOp> {
785 using OpConversionPattern::OpConversionPattern;
788 WriteBdToBlockWritePattern(MLIRContext *context,
789 BlockwriteData &blockwriteData,
790 PatternBenefit benefit = 1)
791 : OpConversionPattern(context, benefit), blockwriteData(blockwriteData) {}
793 BlockwriteData &blockwriteData;
796 matchAndRewrite(NpuWriteBdOp op, OpAdaptor adaptor,
797 ConversionPatternRewriter &rewriter)
const override {
799 AIE::DeviceOp dev = op->getParentOfType<AIE::DeviceOp>();
800 const AIE::AIETargetModel &tm = dev.getTargetModel();
801 int col = op.getColumn();
802 int row = op.getRow();
804 const AIE::DmaBdLayout *layout = tm.getDmaBdLayout(col, row);
806 return op->emitOpError(
"has no buffer descriptor layout on this tile");
807 if (!tm.isMemTile(col, row) &&
808 (op.getD0ZeroBefore() || op.getD1ZeroBefore() || op.getD2ZeroBefore() ||
809 op.getD0ZeroAfter() || op.getD1ZeroAfter() || op.getD2ZeroAfter()))
810 return op->emitOpError(
"Zero padding is only available on MemTile");
812 std::vector<uint32_t> words(layout->
numWords, 0);
813 auto set = [&](
const AIE::DmaBdField &field, uint64_t value) {
817 uint64_t bufferOffset = op.getBufferOffset();
818 if (tm.isCoreTile(col, row))
824 set(layout->
packetId, op.getPacketId());
826 set(layout->
d0Size, op.getD0Size());
827 set(layout->
d0Stride, op.getD0Stride());
828 set(layout->
d1Size, op.getD1Size());
829 set(layout->
d1Stride, op.getD1Stride());
830 set(layout->
d2Stride, op.getD2Stride());
843 set(layout->
axcache, op.getAxcacheOrDefault());
844 set(layout->
nextBd, op.getNextBd());
845 set(layout->
useNextBd, op.getUseNextBd());
846 set(layout->
validBd, op.getValidBd());
848 set(layout->
lockRelId, op.getLockRelId());
851 set(layout->
lockAcqId, op.getLockAcqId());
853 uint32_t bd_id = op.getBdId();
854 uint64_t bd_addr = tm.getDmaBdAddress(col, row, bd_id);
856 memref::GlobalOp global =
nullptr;
858 OpBuilder::InsertionGuard guard(rewriter);
859 rewriter.setInsertionPoint(op->getParentOfType<AIE::RuntimeSequenceOp>());
860 global = blockwriteData.getOrCreate(rewriter, op.getLoc(), words);
862 auto memref = memref::GetGlobalOp::create(
863 rewriter, op.getLoc(), global.getType(), global.getName());
865 (void)rewriter.replaceOpWithNewOp<NpuBlockWriteOp>(
866 op, rewriter.getUI32IntegerAttr(bd_addr), memref.getResult(),
nullptr,
875static void checkQueueDepth(AIE::DeviceOp device,
bool enforceQueueDepth) {
877 auto effectOf = [&](Operation *op) ->
QueueEffect {
878 if (
auto push = dyn_cast<NpuPushQueueOp>(op))
880 static_cast<int>(push.getRow()),
881 static_cast<int>(push.getDirection()),
882 static_cast<int>(push.getChannel())},
883 push.getIssueToken());
884 if (
auto sync = dyn_cast<NpuSyncOp>(op))
885 if (std::optional<DmaQueueModel::ChannelKey> key =
syncChannelKey(sync))
890 device.walk([&](AIE::RuntimeSequenceOp seq) {
899struct AIEDmaToNpuPass : xilinx::AIEX::impl::AIEDmaToNpuBase<AIEDmaToNpuPass> {
900 using Base = xilinx::AIEX::impl::AIEDmaToNpuBase<AIEDmaToNpuPass>;
901 AIEDmaToNpuPass() =
default;
902 AIEDmaToNpuPass(
const AIEDmaToNpuOptions &options) : Base(options) {}
904 void runOnOperation()
override {
906 AIE::DeviceOp device = getOperation();
908 ConversionTarget target(getContext());
909 target.addLegalDialect<AIEXDialect>();
910 target.addLegalDialect<memref::MemRefDialect>();
911 target.addLegalDialect<arith::ArithDialect>();
912 target.addLegalOp<cf::AssertOp>();
913 target.addLegalOp<AIE::BufferOp>();
914 target.addLegalOp<AIE::ShimDMAAllocationOp>();
915 target.addLegalOp<AIE::TileOp>();
917 target.addIllegalOp<NpuDmaMemcpyNdOp>();
918 target.addIllegalOp<NpuDmaWaitOp>();
919 target.addIllegalOp<NpuWriteRTPOp>();
920 target.addIllegalOp<NpuWriteBdOp>();
921 target.addDynamicallyLegalOp<NpuWrite32Op>(
922 [&](NpuWrite32Op op) {
return !op.getBuffer(); });
923 target.addDynamicallyLegalOp<NpuBlockWriteOp>(
924 [&](NpuBlockWriteOp op) {
return !op.getBuffer(); });
925 target.addDynamicallyLegalOp<NpuMaskWrite32Op>(
926 [&](NpuMaskWrite32Op op) {
return !op.getBuffer(); });
927 target.addDynamicallyLegalOp<NpuMaskPollOp>(
928 [&](NpuMaskPollOp op) {
return !op.getBuffer(); });
930 BlockwriteData blockwriteData(device,
"blockwrite_data_");
931 AIE::NamedOpTable names(device);
933 RewritePatternSet patterns(&getContext());
934 patterns.insert<BlockWriteSymToAddr>(&getContext(), names);
935 patterns.insert<DmaToNpuPattern>(&getContext());
936 patterns.insert<DmaWaitToSyncPattern>(&getContext());
937 patterns.insert<MaskWrite32SymToAddr>(&getContext(), names);
938 patterns.insert<MaskPollSymToAddr>(&getContext(), names);
939 patterns.insert<RtpToWrite32Pattern>(&getContext(), names);
940 patterns.insert<Write32SymToAddr>(&getContext(), names);
941 patterns.insert<WriteBdToBlockWritePattern>(&getContext(), blockwriteData);
945 SmallVector<Operation *> illegal;
946 device.walk([&](Operation *op) {
947 if (target.isIllegal(op))
948 illegal.push_back(op);
950 ConversionConfig config;
951 config.foldingMode = DialectConversionFoldingMode::Never;
952 config.allowPatternRollback =
false;
953 if (failed(applyPartialConversion(illegal, target, std::move(patterns),
959 checkQueueDepth(device, enforceQueueDepth);
961 target.addIllegalOp<NpuPushQueueOp>();
962 RewritePatternSet pushPatterns(&getContext());
963 pushPatterns.insert<PushQueuetoWrite32Pattern>(&getContext());
964 SmallVector<Operation *> pushes;
965 device.walk([&](NpuPushQueueOp op) { pushes.push_back(op); });
966 if (failed(applyPartialConversion(pushes, target, std::move(pushPatterns),
977 return std::make_unique<AIEDmaToNpuPass>();
980std::unique_ptr<OperationPass<AIE::DeviceOp>>
982 return std::make_unique<AIEDmaToNpuPass>(options);
Tracks, per DMA channel, the pushes not yet known to have completed along one execution path.
mlir::LogicalResult verifyStridesWraps(mlir::Operation *forOp, llvm::function_ref< mlir::InFlightDiagnostic()> emitError, mlir::BaseMemRefType referencedBufType, int tileCol, int tileRow, llvm::SmallVector< int64_t, 4 > inputSizes, llvm::SmallVector< int64_t, 4 > inputStrides, llvm::SmallVector< int64_t, 4 > hardwareSizes, llvm::SmallVector< int64_t, 4 > hardwareStrides, bool skipTransformationChecks=false)
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEDmaToNpuPass()
std::optional< SubviewTraceResult > traceSubviewToBlockArgument(Value value)
constexpr llvm::StringLiteral queueDiagnosedAttr
mlir::Value buildArgPlusValue(mlir::OpBuilder &builder, mlir::Location loc, llvm::ArrayRef< mlir::OpFoldResult > elementOffsets, llvm::ArrayRef< mlir::OpFoldResult > strides, int64_t elemWidthBytes, int64_t baseByteOffset, uint32_t granuleBytes)
std::optional< uint64_t > getConstantInt64Operand(mlir::Value v)
mlir::Value getAsValue(mlir::OpBuilder &builder, mlir::Location loc, mlir::OpFoldResult ofr, mlir::Type intType)
std::optional< DmaQueueModel::ChannelKey > syncChannelKey(NpuSyncOp sync)
The channel an aiex.npu.sync retires on, or nullopt when it cannot be pinned down.
mlir::LogicalResult guardWithinHostBuffer(mlir::OpBuilder &builder, mlir::Location loc, mlir::BaseMemRefType hostBufferType, int64_t baseByteOffset, int64_t elemWidthBytes, llvm::ArrayRef< mlir::OpFoldResult > offsets, llvm::ArrayRef< mlir::OpFoldResult > offsetStrides, llvm::ArrayRef< mlir::OpFoldResult > sizes, llvm::ArrayRef< mlir::OpFoldResult > strides)
mlir::LogicalResult buildBdWords(mlir::OpBuilder &builder, mlir::Location loc, const xilinx::AIE::AIETargetModel &targetModel, int tileCol, int tileRow, const BdTemplateFields &fields, llvm::ArrayRef< mlir::OpFoldResult > mixedSizes, llvm::ArrayRef< mlir::OpFoldResult > mixedStrides, uint64_t elemWidth, uint32_t burstLength, uint32_t axcache, mlir::OpFoldResult lenElems, mlir::Value &repeatCountOut, llvm::SmallVectorImpl< mlir::Value > &wordsOut)
std::optional< uint32_t > getConstantIntOperand(mlir::Value v)
mlir::Value getAsI64(mlir::OpBuilder &builder, mlir::Location loc, mlir::OpFoldResult ofr)
void eraseDeadArith(mlir::Operation *root)
void guardSequenceQueueDepth(mlir::Region &body, DmaQueueModel &queue, const AIE::AIETargetModel &tm, bool enforce, bool warnUnsafeBdReuse, EffectFn effectOf)
Guard every push in a runtime sequence that can land on a full queue, and (when warnUnsafeBdReuse) wa...
void getHardwareStridesWraps(const AIE::AIETargetModel &targetModel, mlir::Operation *op, mlir::BaseMemRefType referencedBufType, llvm::SmallVector< int64_t, 4 > inputSizes, llvm::SmallVector< int64_t, 4 > inputStrides, llvm::SmallVector< int64_t, 4 > &sizes, llvm::SmallVector< int64_t, 4 > &strides)
bool isLinearModeTransfer(const AIE::AIETargetModel &targetModel, int col, int row, llvm::ArrayRef< int64_t > sizes, llvm::ArrayRef< int64_t > strides)
mlir::Value getBdRegisterBase(mlir::OpBuilder &builder, mlir::Location loc, const xilinx::AIE::AIETargetModel &targetModel, int tileCol, int tileRow, mlir::OpFoldResult bdId)
mlir::LogicalResult emitRuntimeCheck(mlir::OpBuilder &builder, mlir::Location loc, mlir::Value cond, const llvm::Twine &message)
LogicalResult emitUpdateBdAddressFromOffsetParameter(OpBuilder &builder, Operation *bdOp, BaseMemRefType bufType, uint64_t registerAddr)
LogicalResult emitUpdateBdLengthFromParameter(OpBuilder &builder, Operation *bdOp, BaseMemRefType bufType, int64_t lengthUnit, const AIE::AIETargetModel &targetModel, int col, int row, int bdId)
std::optional< unsigned > getHostBufferArgIndex(BlockArgument arg)
mlir::Value createConstantI32(mlir::OpBuilder &builder, mlir::Location loc, uint32_t value)
uint32_t getShimBurstLengthEncoding(const AIE::AIETargetModel &tm, uint32_t burstLength)
const AIETargetModel & getTargetModel(mlir::Operation *op)
void placeRuntimeLengthDimension(llvm::MutableArrayRef< int64_t > sizes, llvm::MutableArrayRef< int64_t > strides)
What one op in a loop body does to a channel queue.
static QueueEffect await(DmaQueueModel::ChannelKey key)
static QueueEffect push(DmaQueueModel::ChannelKey key, bool issuesToken, mlir::Value task={})
uint32_t place(uint64_t value) const
DmaBdField iterationCurrent
DmaBdField iterationStride