MLIR-AIE
AIEObjectFifoRegisterProcess.cpp
Go to the documentation of this file.
1//===- AIEObjectFifoRegisterProcess.cpp ------------------------*- MLIR -*-===//
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 2021 Xilinx Inc.
8//
9// Date: October 18th 2021
10//
11//===----------------------------------------------------------------------===//
12
15
16#include "mlir/Dialect/Arith/IR/Arith.h"
17#include "mlir/Dialect/Func/IR/FuncOps.h"
18#include "mlir/Dialect/SCF/IR/SCF.h"
19#include "mlir/IR/IRMapping.h"
20#include "mlir/IR/PatternMatch.h"
21#include "mlir/Pass/Pass.h"
22#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
23#include "mlir/Transforms/DialectConversion.h"
24
25#include <queue>
26
27namespace xilinx::AIE {
28#define GEN_PASS_DEF_AIEOBJECTFIFOREGISTERPROCESS
29#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
30} // namespace xilinx::AIE
31
32using namespace mlir;
33using namespace xilinx;
34using namespace xilinx::AIE;
35
36#define DEBUG_TYPE "aie-register-objectFifos"
37
38//===----------------------------------------------------------------------===//
39// Register objectFifos Pass
40//===----------------------------------------------------------------------===//
43 AIEObjectFifoRegisterProcessPass> {
44
45 scf::ForOp createForLoop(OpBuilder &builder, int length) {
46 auto lowerBound = arith::ConstantOp::create(
47 builder, builder.getUnknownLoc(), builder.getIndexAttr(0));
48 auto upperBound = arith::ConstantOp::create(
49 builder, builder.getUnknownLoc(), builder.getIndexAttr(length));
50 auto step = arith::ConstantOp::create(builder, builder.getUnknownLoc(),
51 builder.getIndexAttr(1));
52 auto forLoop = scf::ForOp::create(builder, builder.getUnknownLoc(),
53 lowerBound, upperBound, step);
54 return forLoop;
55 }
56
57 void createPattern(OpBuilder &builder, DeviceOp &device,
58 ObjectFifoRegisterProcessOp regOp, MemRefType elementType,
59 IntegerAttr acqNumber, IntegerAttr relNumber, int length) {
60 auto ctx = device->getContext();
61 // create for loop
62 scf::ForOp forLoop;
63 if (length > 1) {
64 forLoop = createForLoop(builder, length);
65 Region &forRegion = forLoop.getRegion();
66 builder.setInsertionPointToStart(&forRegion.back());
67 }
68
69 // acquires
70 if (acqNumber.getInt() > 0) {
71 auto acqType = AIEObjectFifoSubviewType::get(elementType);
72 auto acqOp = ObjectFifoAcquireOp::create(
73 builder, builder.getUnknownLoc(), acqType, regOp.getPortAttr(),
74 SymbolRefAttr::get(ctx, regOp.getObjFifoName()), acqNumber);
75
76 // subview accesses
77 for (int i = 0; i < acqNumber.getInt(); i++)
78 (void)ObjectFifoSubviewAccessOp::create(
79 builder, builder.getUnknownLoc(), elementType, acqOp.getSubview(),
80 builder.getIntegerAttr(builder.getI32Type(), i));
81
82 // apply kernel
83 func::FuncOp func;
84 for (auto funcOp : device.getOps<func::FuncOp>()) {
85 if (funcOp.getSymName() == regOp.getCallee()) {
86 func = funcOp;
87 break;
88 }
89 }
90 func::CallOp::create(builder, builder.getUnknownLoc(),
91 func /*, acc.output()*/);
92 }
93
94 // releases
95 if (relNumber.getInt() > 0) {
96 auto relOp = ObjectFifoReleaseOp::create(
97 builder, builder.getUnknownLoc(), regOp.getPortAttr(),
98 SymbolRefAttr::get(ctx, regOp.getObjFifoName()), relNumber);
99 builder.setInsertionPointAfter(relOp);
100 }
101
102 if (length > 1)
103 builder.setInsertionPointAfter(forLoop);
104 }
105
106 void runOnOperation() override {
107 DeviceOp device = getOperation();
108 OpBuilder builder = OpBuilder::atBlockTerminator(device.getBody());
109 DenseMap<ObjectFifoCreateOp, std::queue<Value>> consumersPerFifo;
110 //===----------------------------------------------------------------------===//
111 // Generate access patterns
112 //===----------------------------------------------------------------------===//
113 for (auto registerOp : device.getOps<ObjectFifoRegisterProcessOp>()) {
114 builder.setInsertionPoint(device.getBody()->getTerminator());
115 ObjectFifoCreateOp objFifo = registerOp.getObjectFifo();
116 auto elementType =
117 llvm::dyn_cast<AIEObjectFifoType>(objFifo.getElemType())
118 .getElementType();
119
120 if (consumersPerFifo.find(objFifo) == consumersPerFifo.end()) {
121 std::queue<Value> consumers;
122 for (auto consumerTile : objFifo.getConsumerTiles())
123 consumers.push(consumerTile);
124 consumersPerFifo[objFifo] = consumers;
125 }
126
127 // identify tile on which to generate the pattern
128 Value tile;
129 if (registerOp.getPort() == ObjectFifoPort::Produce)
130 tile = objFifo.getProducerTile();
131 else if (registerOp.getPort() == ObjectFifoPort::Consume) {
132 assert(!consumersPerFifo[objFifo].empty() &&
133 "No more available consumer tiles for process.");
134 tile = consumersPerFifo[objFifo].front();
135 consumersPerFifo[objFifo].pop();
136 }
137
138 Operation *op = llvm::find_singleton<Operation>(
139 device.getOps<CoreOp>(),
140 [&tile](CoreOp coreOp, bool) {
141 return coreOp.getTile() == tile ? coreOp.getOperation() : nullptr;
142 },
143 /*AllowRepeats=*/false);
144 // retrieve core associated to above tile or create new one
145 if (!op) {
146 CoreOp coreOp = CoreOp::create(builder, builder.getUnknownLoc(),
147 builder.getIndexType(), tile);
148 Region &r = coreOp.getBody();
149 r.push_back(new Block);
150 Block &block = r.back();
151 builder.setInsertionPointToStart(&block);
152 EndOp::create(builder, builder.getUnknownLoc());
153 builder.setInsertionPointToStart(&block);
154 } else {
155 CoreOp coreOp = llvm::dyn_cast<CoreOp>(op);
156 Region &r = coreOp.getBody();
157 Block &endBlock = r.back();
158 builder.setInsertionPointToStart(&endBlock);
159 }
160
161 // analyze pattern
162 auto acqSize = registerOp.getAcquirePattern().size();
163
164 if (auto relSize = registerOp.getReleasePattern().size();
165 acqSize == 1 && relSize == 1) {
166 IntegerAttr acqNumber =
167 registerOp.getAcquirePattern().getValues<IntegerAttr>()[0];
168 IntegerAttr relNumber =
169 registerOp.getReleasePattern().getValues<IntegerAttr>()[0];
170 createPattern(builder, device, registerOp, elementType, acqNumber,
171 relNumber, registerOp.getProcessLength());
172
173 } else {
174 auto acqPattern =
175 registerOp.getAcquirePattern().getValues<IntegerAttr>();
176 std::vector<IntegerAttr> acqVector;
177 for (auto i = acqPattern.begin(); i != acqPattern.end(); ++i)
178 acqVector.push_back(*i);
179
180 auto relPattern =
181 registerOp.getReleasePattern().getValues<IntegerAttr>();
182 std::vector<IntegerAttr> relVector;
183 for (auto i = relPattern.begin(); i != relPattern.end(); ++i)
184 relVector.push_back(*i);
185
186 if (acqSize == 1) {
187 // duplicate acquire pattern
188 IntegerAttr acqNumber =
189 registerOp.getAcquirePattern().getValues<IntegerAttr>()[0];
190 std::vector values(registerOp.getProcessLength(), acqNumber);
191 acqVector = values;
192 acqSize = registerOp.getProcessLength();
193
194 } else if (relSize == 1) {
195 // duplicate release pattern
196 IntegerAttr relNumber =
197 registerOp.getReleasePattern().getValues<IntegerAttr>()[0];
198 std::vector values(registerOp.getProcessLength(), relNumber);
199 relVector = values;
200 }
201
202 int length = 1;
203 for (int i = 0; i < acqSize; i++) {
204 auto currAcq = acqVector[i];
205 auto currRel = relVector[i];
206 if (i < acqSize - 1) {
207 auto nextAcq = acqVector[i + 1];
208 if (auto nextRel = relVector[i + 1];
209 currAcq.getInt() == nextAcq.getInt() &&
210 currRel.getInt() == nextRel.getInt()) {
211 length++;
212 continue;
213 }
214 }
215 createPattern(builder, device, registerOp, elementType, currAcq,
216 currRel, length);
217 length = 1;
218 }
219 }
220 }
221
222 //===----------------------------------------------------------------------===//
223 // Remove old ops
224 //===----------------------------------------------------------------------===//
225 SmallVector<Operation *> opsToErase;
226 device.walk([&](Operation *op) {
227 if (isa<ObjectFifoRegisterProcessOp>(op))
228 opsToErase.push_back(op);
229 });
230 for (auto op : opsToErase)
231 op->erase();
232 }
233};
234
235std::unique_ptr<OperationPass<DeviceOp>>
237 return std::make_unique<AIEObjectFifoRegisterProcessPass>();
238}
Include the generated interface declarations.
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIEObjectFifoRegisterProcessPass()
void createPattern(OpBuilder &builder, DeviceOp &device, ObjectFifoRegisterProcessOp regOp, MemRefType elementType, IntegerAttr acqNumber, IntegerAttr relNumber, int length)
scf::ForOp createForLoop(OpBuilder &builder, int length)