18#include "llvm/Support/Debug.h"
24#define DEBUG_TYPE "aie-reuse"
28bool IntervalReuse::sameEnclosingLoops(
29 Operation *op, mlir::DenseMap<Block *, SmallVector<Operation *, 8>>
30 &blockToEnclosingLoops) {
32 assert(!extentMap.empty() &&
33 "interval must have at least one read operation");
36 Operation *ref = extentMap.begin()->first;
40 assert(blockToEnclosingLoops.count(op->getBlock()) &&
41 "block to enclosing loop mapping not computed");
42 assert(blockToEnclosingLoops.count(ref->getBlock()) &&
43 "block to enclosing loop mapping not computed");
45 return blockToEnclosingLoops[op->getBlock()] ==
46 blockToEnclosingLoops[ref->getBlock()];
51size_t IntervalReuse::getIntervalIndex(Operation *op) {
56 auto lb = std::lower_bound(intervals.begin(), intervals.end(), bound);
60 if (lb != intervals.begin()) {
61 auto prev = std::prev(lb);
62 if (prev->first <= bound.first && prev->second >= bound.second)
65 assert(lb != intervals.end() &&
66 "Failed to find correct interval for read operation");
68 assert(lb->first <= bound.first && lb->second >= bound.second &&
69 "Failed to find correct interval for read operation");
70 size_t pos = std::distance(intervals.begin(), lb);
77 assert(extentMap.find(op) != extentMap.end() &&
78 "Could not find the bounds of operator in map");
85 std::pair<int32_t, int32_t> &extent) {
86 assert(extentMap.find(op) != extentMap.end() &&
87 "operation does not belong to this reuse interval");
88 extentMap[op] = extent;
94 size_t pos = getIntervalIndex(op);
95 return intervals[pos];
103 if (vecIsLHSOperand.empty())
104 vecIsLHSOperand.resize(intervals.size(),
false);
106 size_t pos = getIntervalIndex(op);
107 assert(pos < vecIsLHSOperand.size());
109 vecIsLHSOperand[pos] =
true;
117 return interval.second - interval.first;
125 vector::TransferReadOp readOp, AffineExpr invariantBase,
126 mlir::DenseMap<Block *, SmallVector<Operation *, 8>>
127 &blockToEnclosingLoops) {
128 return sameMemRef(readOp.getBase()) && sameInvariantIndices(invariantBase) &&
129 sameEnclosingLoops(readOp, blockToEnclosingLoops);
137static std::pair<int32_t, int32_t>
138computeAccessExtent(vector::TransferReadOp readOp, int32_t offset,
139 int32_t loopStepSize,
bool isSplat,
unsigned minVecSize) {
140 VectorType vType = cast<VectorType>(readOp.getResult().getType());
144 int32_t vecSizeInBits = std::max(minVecSize, vecSize * elementSizeInBits);
147 "Current support is only for power-of-two vector sizes");
151 int32_t lb = (offset * elementSizeInBits) & ~(vecSizeInBits - 1);
152 int32_t ub = (isSplat ? (offset & ~(vecSize - 1)) + vecSize
153 : offset + loopStepSize * vecSize) *
156 ub = (ub + vecSizeInBits - 1) & ~(vecSizeInBits - 1);
158 return std::make_pair(lb, ub);
166 vector::TransferReadOp readOp,
167 mlir::DenseMap<Operation *, IntervalReuse *> &opToIntervalMap,
168 int32_t offset, int32_t loopStepSize,
bool isSplat,
unsigned minVecSize) {
170 std::pair<int32_t, int32_t> bound =
171 computeAccessExtent(readOp, offset, loopStepSize, isSplat, minVecSize);
174 extentMap[readOp] = bound;
176 opToIntervalMap[readOp] =
this;
178 LLVM_DEBUG(llvm::dbgs() <<
"\n\nInserting access extent [" << bound.first
179 <<
"," << bound.second <<
"] for read op " << readOp);
182 if (std::find(intervals.begin(), intervals.end(), bound) != intervals.end()) {
185 <<
"\n\tPre-existing interval already subsumes the access extent");
190 int32_t lb = bound.first, ub = bound.second;
191 SmallVector<std::pair<int32_t, int32_t>, 8> mergedIntervals;
192 bool inserted =
false;
199 for (
auto iv : intervals) {
202 mergedIntervals.push_back(iv);
203 else if (iv.first >= ub) {
206 mergedIntervals.push_back(std::make_pair(lb, ub));
209 mergedIntervals.push_back(iv);
212 lb = std::min(lb, iv.first);
213 ub = std::max(ub, iv.second);
217 mergedIntervals.push_back(std::make_pair(lb, ub));
220 intervals = std::move(mergedIntervals);
224 for (
auto iv : intervals) {
225 int32_t width = iv.second - iv.first;
227 printf(
"Vector width > 1024 currently not supported");
235 LLVM_DEBUG(llvm::dbgs() <<
"\n\tAfter inserting access extent, intervals: ");
237 for (
auto iv : intervals)
238 LLVM_DEBUG(llvm::dbgs() <<
"[" << iv.first <<
"," << iv.second <<
"] ");
250 if (vecIsLHSOperand.empty())
255 bool canCoalesce =
false;
256 for (
size_t i = 0, e = intervals.size(); i < e; ++i) {
258 vecIsLHSOperand[i] && intervals[i].second - intervals[i].first <= 256;
264 SmallVector<std::pair<int32_t, int32_t>, 8> coalescedIntervals;
265 for (
size_t i = 0, e = intervals.size(); i < e;) {
267 if (vecIsLHSOperand[i] && i < intervals.size() - 1 &&
268 vecIsLHSOperand[i + 1]) {
270 int32_t v1size = intervals[i].second - intervals[i].first;
271 int32_t v2size = intervals[i + 1].second - intervals[i + 1].first;
274 if (v1size <= 256 && v2size <= 256) {
275 coalescedIntervals.push_back(
276 std::make_pair(intervals[i].first, intervals[i + 1].second));
281 coalescedIntervals.push_back(intervals[i]);
285 vecIsLHSOperand.clear();
288 intervals = std::move(coalescedIntervals);
291 LLVM_DEBUG(llvm::dbgs() <<
"\n\nAfter coalescing for "
292 <<
"i8xi8 scheme, intervals: ");
294 for (
auto iv : intervals)
295 LLVM_DEBUG(llvm::dbgs() <<
"[" << iv.first <<
"," << iv.second <<
"] ");
void insertInterval(mlir::vector::TransferReadOp readOp, llvm::DenseMap< mlir::Operation *, IntervalReuse * > &dataAccessToIntervalMap, int32_t offset, int32_t forLoopStepSize, bool isSplat=false, unsigned minVecSize=128)
void setAccessExtent(mlir::Operation *op, std::pair< int32_t, int32_t > &extent)
bool potentialReuse(mlir::vector::TransferReadOp readOp, mlir::AffineExpr invariantBase, llvm::DenseMap< mlir::Block *, llvm::SmallVector< mlir::Operation *, 8 > > &blockToEnclosingLoops)
int32_t getIntervalWidth(mlir::Operation *op)
std::pair< int32_t, int32_t > getAccessExtent(mlir::Operation *op)
std::pair< int32_t, int32_t > getInterval(mlir::Operation *op)
void markLHSOperandVec(mlir::Operation *op)
bool isPowerOfTwo(int32_t n)
unsigned getVectorLaneSize(mlir::VectorType type)
int32_t getElementSizeInBits(mlir::VectorType type)