MLIR-AIE
AIELowerMemcpy.cpp
Go to the documentation of this file.
1//===- AIELowerMemcpy.cpp ---------------------------------------*- C++ -*-===//
2//
3// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7// (c) Copyright 2019 Xilinx Inc.
8//
9//===----------------------------------------------------------------------===//
10
15
16#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
17#include "mlir/Dialect/Func/IR/FuncOps.h"
18#include "mlir/IR/Attributes.h"
19#include "mlir/IR/IRMapping.h"
20#include "mlir/IR/Location.h"
21#include "mlir/IR/PatternMatch.h"
22#include "mlir/Pass/Pass.h"
23#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
24#include "mlir/Transforms/DialectConversion.h"
25
26using namespace mlir;
27using namespace xilinx;
28using namespace xilinx::AIE;
29using namespace xilinx::AIEX;
30
31static TileOp srcTileOp(xilinx::AIEX::MemcpyOp op) {
32 return llvm::dyn_cast<xilinx::AIE::TileOp>(op.getSrcTile().getDefiningOp());
33}
34static TileOp dstTileOp(xilinx::AIEX::MemcpyOp op) {
35 return llvm::dyn_cast<xilinx::AIE::TileOp>(op.getDstTile().getDefiningOp());
36}
37
38struct LowerAIEMemcpy : public OpConversionPattern<MemcpyOp> {
40
41 LowerAIEMemcpy(MLIRContext *context, PatternBenefit benefit = 1)
42 : OpConversionPattern<MemcpyOp>(context, benefit) {}
43
44 void createDMABlocksAndOps(MemOp &mem, StringRef tokenName, int acquireTknVal,
45 int releaseTknVal, Value buf, int offset, int len,
46 DMAChannelDir dmaDir, int channelIndex,
47 ConversionPatternRewriter &rewriter) const {
48
49 Region &r = mem.getBody();
50 Block &endBlock = r.back();
51 Block *dmaBlock = rewriter.createBlock(&endBlock);
52 Block *bdBlock = rewriter.createBlock(&endBlock);
53
54 rewriter.setInsertionPointToStart(dmaBlock);
55 rewriter.create<DMAStartOp>(rewriter.getUnknownLoc(), dmaDir, channelIndex,
56 /*repeatCount*/ 0, bdBlock, &endBlock);
57
58 // Setup bd Block
59 // It should contain locking operations (lock or token) as well as DMABD op
60 // for specifying DMA Block description (which buffer type (A/B), transfer
61 // length/address, etc.)
62 rewriter.setInsertionPointToStart(bdBlock);
63 rewriter.create<UseTokenOp>(rewriter.getUnknownLoc(), tokenName,
64 acquireTknVal, LockAction::Acquire);
65 rewriter.create<DMABDOp>(rewriter.getUnknownLoc(), buf, offset, len);
66 rewriter.create<UseTokenOp>(rewriter.getUnknownLoc(), tokenName,
67 releaseTknVal, LockAction::Release);
68 rewriter.create<NextBDOp>(rewriter.getUnknownLoc(), &endBlock);
69 }
70
71 LogicalResult
72 matchAndRewrite(MemcpyOp op, OpAdaptor adaptor,
73 ConversionPatternRewriter &rewriter) const override {
74 Value srcBuf = op.getSrcBuf();
75 Value dstBuf = op.getDstBuf();
76
77 StringRef tokenName = op.getTokenName();
78 int acquireTknVal = op.getAcquireTokenValue();
79 int releaseTknVal = op.getReleaseTokenValue();
80 int srcOffset = op.getSrcOffsetValue();
81 int dstOffset = op.getDstOffsetValue();
82 int srcLen = op.getSrcLenValue();
83 int dstLen = op.getDstLenValue();
84
85 MemOp srcMem = srcTileOp(op).getMemOp();
86 MemOp dstMem = dstTileOp(op).getMemOp();
87
88 createDMABlocksAndOps(srcMem, tokenName, acquireTknVal, releaseTknVal,
89 srcBuf, srcOffset, srcLen, DMAChannelDir::MM2S, 0,
90 rewriter);
91 createDMABlocksAndOps(dstMem, tokenName, acquireTknVal, releaseTknVal,
92 dstBuf, dstOffset, dstLen, DMAChannelDir::S2MM, 0,
93 rewriter);
94
95 rewriter.eraseOp(op);
96 return success();
97 }
98};
99
100struct AIELowerMemcpyPass : public AIELowerMemcpyBase<AIELowerMemcpyPass> {
101 void runOnOperation() override {
102
103 DeviceOp device = getOperation();
104 OpBuilder builder = OpBuilder::atBlockTerminator(device.getBody());
105
106 // Setup FlowOps
107 // Since memcpy moves data from one memory module to another, we use
108 // WireBundle::DMA for both the source and the destination In addition, we
109 // only have two DMA ports per each direction (MM2S/S2MM), and in a
110 // circuit-switch mode, dest port/channel sharing is not possible.
111 // Therefore, we will generate error if the number of logical flows
112 // (streams) targeting the same destination (S2MM) is more than 2
113 DenseMap<Value, int> destChannel;
114 for (auto op : device.getOps<MemcpyOp>()) {
115 builder.setInsertionPoint(op);
116 TileOp srcTile = dyn_cast<TileOp>(op.getSrcTile().getDefiningOp());
117 TileOp dstTile = dyn_cast<TileOp>(op.getDstTile().getDefiningOp());
118 // TODO: perhaps a better approach is to not assert here, but rather have
119 // a subsequent pass that legally relocates the ports
120 assert(destChannel[op.getDstTile()] <= 2 &&
121 "Could not allocate more than two dest. channel when creating "
122 "FlowOp");
123 builder.create<FlowOp>(builder.getUnknownLoc(), srcTile, WireBundle::DMA,
124 0, dstTile, WireBundle::DMA,
125 destChannel[op.getDstTile()]);
126 destChannel[op.getDstTile()]++;
127 }
128
129 ConversionTarget target(getContext());
130 RewritePatternSet patterns(&getContext());
131 target.addLegalOp<DMAStartOp>();
132 target.addLegalOp<DMABDOp>();
133 target.addLegalOp<UseTokenOp>();
134 target.addLegalOp<NextBDOp>();
135
136 patterns.insert<LowerAIEMemcpy>(&getContext());
137
138 if (failed(applyPartialConversion(device, target, std::move(patterns))))
139 signalPassFailure();
140 }
141};
142
143std::unique_ptr<OperationPass<AIE::DeviceOp>>
145 return std::make_unique<AIELowerMemcpyPass>();
146}
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIELowerMemcpyPass()
Include the generated interface declarations.
void runOnOperation() override
LowerAIEMemcpy(MLIRContext *context, PatternBenefit benefit=1)
LogicalResult matchAndRewrite(MemcpyOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
void createDMABlocksAndOps(MemOp &mem, StringRef tokenName, int acquireTknVal, int releaseTknVal, Value buf, int offset, int len, DMAChannelDir dmaDir, int channelIndex, ConversionPatternRewriter &rewriter) const