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