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.getSource()) &&
129 sameInvariantIndices(invariantBase) &&
130 sameEnclosingLoops(readOp, blockToEnclosingLoops);
138static std::pair<int32_t, int32_t>
139computeAccessExtent(vector::TransferReadOp readOp, int32_t offset,
140 int32_t loopStepSize,
bool isSplat,
unsigned minVecSize) {
141 VectorType vType = cast<VectorType>(readOp.getResult().getType());
145 int32_t vecSizeInBits = std::max(minVecSize, vecSize * elementSizeInBits);
148 "Current support is only for power-of-two vector sizes");
152 int32_t lb = (offset * elementSizeInBits) & ~(vecSizeInBits - 1);
153 int32_t ub = (isSplat ? (offset & ~(vecSize - 1)) + vecSize
154 : offset + loopStepSize * vecSize) *
157 ub = (ub + vecSizeInBits - 1) & ~(vecSizeInBits - 1);
159 return std::make_pair(lb, ub);
167 vector::TransferReadOp readOp,
168 mlir::DenseMap<Operation *, IntervalReuse *> &opToIntervalMap,
169 int32_t offset, int32_t loopStepSize,
bool isSplat,
unsigned minVecSize) {
171 std::pair<int32_t, int32_t> bound =
172 computeAccessExtent(readOp, offset, loopStepSize, isSplat, minVecSize);
175 extentMap[readOp] = bound;
177 opToIntervalMap[readOp] =
this;
179 LLVM_DEBUG(llvm::dbgs() <<
"\n\nInserting access extent [" << bound.first
180 <<
"," << bound.second <<
"] for read op " << readOp);
183 if (std::find(intervals.begin(), intervals.end(), bound) != intervals.end()) {
186 <<
"\n\tPre-existing interval already subsumes the access extent");
191 int32_t lb = bound.first, ub = bound.second;
192 SmallVector<std::pair<int32_t, int32_t>, 8> mergedIntervals;
193 bool inserted =
false;
200 for (
auto iv : intervals) {
203 mergedIntervals.push_back(iv);
204 else if (iv.first >= ub) {
207 mergedIntervals.push_back(std::make_pair(lb, ub));
210 mergedIntervals.push_back(iv);
213 lb = std::min(lb, iv.first);
214 ub = std::max(ub, iv.second);
218 mergedIntervals.push_back(std::make_pair(lb, ub));
221 intervals = std::move(mergedIntervals);
225 for (
auto iv : intervals) {
226 int32_t width = iv.second - iv.first;
228 printf(
"Vector width > 1024 currently not supported");
236 LLVM_DEBUG(llvm::dbgs() <<
"\n\tAfter inserting access extent, intervals: ");
238 for (
auto iv : intervals)
239 LLVM_DEBUG(llvm::dbgs() <<
"[" << iv.first <<
"," << iv.second <<
"] ");
251 if (vecIsLHSOperand.empty())
256 bool canCoalesce =
false;
257 for (
size_t i = 0, e = intervals.size(); i < e; ++i) {
259 vecIsLHSOperand[i] && intervals[i].second - intervals[i].first <= 256;
265 SmallVector<std::pair<int32_t, int32_t>, 8> coalescedIntervals;
266 for (
size_t i = 0, e = intervals.size(); i < e;) {
268 if (vecIsLHSOperand[i] && i < intervals.size() - 1 &&
269 vecIsLHSOperand[i + 1]) {
271 int32_t v1size = intervals[i].second - intervals[i].first;
272 int32_t v2size = intervals[i + 1].second - intervals[i + 1].first;
275 if (v1size <= 256 && v2size <= 256) {
276 coalescedIntervals.push_back(
277 std::make_pair(intervals[i].first, intervals[i + 1].second));
282 coalescedIntervals.push_back(intervals[i]);
286 vecIsLHSOperand.clear();
289 intervals = std::move(coalescedIntervals);
292 LLVM_DEBUG(llvm::dbgs() <<
"\n\nAfter coalescing for "
293 <<
"i8xi8 scheme, intervals: ");
295 for (
auto iv : intervals)
296 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)