1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
//===- IndexingUtils.cpp - Helpers related to index computations ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/Utils/IndexingUtils.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include <numeric>
#include <optional>
using namespace mlir;
SmallVector<int64_t> mlir::computeStrides(ArrayRef<int64_t> sizes) {
SmallVector<int64_t> strides(sizes.size(), 1);
for (int64_t r = strides.size() - 2; r >= 0; --r)
strides[r] = strides[r + 1] * sizes[r + 1];
return strides;
}
SmallVector<int64_t> mlir::computeElementwiseMul(ArrayRef<int64_t> v1,
ArrayRef<int64_t> v2) {
SmallVector<int64_t> result;
for (auto it : llvm::zip(v1, v2))
result.push_back(std::get<0>(it) * std::get<1>(it));
return result;
}
std::optional<SmallVector<int64_t>>
mlir::computeShapeRatio(ArrayRef<int64_t> shape, ArrayRef<int64_t> subShape) {
if (shape.size() < subShape.size())
return std::nullopt;
assert(llvm::all_of(shape, [](int64_t s) { return s > 0; }) &&
"shape must be nonnegative");
assert(llvm::all_of(subShape, [](int64_t s) { return s > 0; }) &&
"subShape must be nonnegative");
// Starting from the end, compute the integer divisors.
std::vector<int64_t> result;
result.reserve(shape.size());
for (auto [size, subSize] :
llvm::zip(llvm::reverse(shape), llvm::reverse(subShape))) {
// If integral division does not occur, return and let the caller decide.
if (size % subSize != 0)
return std::nullopt;
result.push_back(size / subSize);
}
// At this point we computed the ratio (in reverse) for the common size.
// Fill with the remaining entries from the shape (still in reverse).
int commonSize = subShape.size();
std::copy(shape.rbegin() + commonSize, shape.rend(),
std::back_inserter(result));
// Reverse again to get it back in the proper order and return.
return SmallVector<int64_t>{result.rbegin(), result.rend()};
}
int64_t mlir::linearize(ArrayRef<int64_t> offsets, ArrayRef<int64_t> basis) {
assert(offsets.size() == basis.size());
int64_t linearIndex = 0;
for (unsigned idx = 0, e = basis.size(); idx < e; ++idx)
linearIndex += offsets[idx] * basis[idx];
return linearIndex;
}
llvm::SmallVector<int64_t> mlir::delinearize(ArrayRef<int64_t> sliceStrides,
int64_t index) {
int64_t rank = sliceStrides.size();
SmallVector<int64_t> vectorOffsets(rank);
for (int64_t r = 0; r < rank; ++r) {
assert(sliceStrides[r] > 0);
vectorOffsets[r] = index / sliceStrides[r];
index %= sliceStrides[r];
}
return vectorOffsets;
}
int64_t mlir::computeMaxLinearIndex(ArrayRef<int64_t> basis) {
if (basis.empty())
return 0;
return std::accumulate(basis.begin(), basis.end(), 1,
std::multiplies<int64_t>());
}
llvm::SmallVector<int64_t>
mlir::invertPermutationVector(ArrayRef<int64_t> permutation) {
SmallVector<int64_t> inversion(permutation.size());
for (const auto &pos : llvm::enumerate(permutation)) {
inversion[pos.value()] = pos.index();
}
return inversion;
}
bool mlir::isPermutationVector(ArrayRef<int64_t> interchange) {
llvm::SmallDenseSet<int64_t, 4> seenVals;
for (auto val : interchange) {
if (seenVals.count(val))
return false;
seenVals.insert(val);
}
return seenVals.size() == interchange.size();
}
llvm::SmallVector<int64_t> mlir::getI64SubArray(ArrayAttr arrayAttr,
unsigned dropFront,
unsigned dropBack) {
assert(arrayAttr.size() > dropFront + dropBack && "Out of bounds");
auto range = arrayAttr.getAsRange<IntegerAttr>();
SmallVector<int64_t> res;
res.reserve(arrayAttr.size() - dropFront - dropBack);
for (auto it = range.begin() + dropFront, eit = range.end() - dropBack;
it != eit; ++it)
res.push_back((*it).getValue().getSExtValue());
return res;
}
mlir::AffineExpr mlir::getLinearAffineExpr(ArrayRef<int64_t> basis,
mlir::Builder &b) {
AffineExpr resultExpr = b.getAffineDimExpr(0);
resultExpr = resultExpr * basis[0];
for (unsigned i = 1; i < basis.size(); i++)
resultExpr = resultExpr + b.getAffineDimExpr(i) * basis[i];
return resultExpr;
}
llvm::SmallVector<mlir::AffineExpr>
mlir::getDelinearizedAffineExpr(mlir::ArrayRef<int64_t> strides, Builder &b) {
AffineExpr resultExpr = b.getAffineDimExpr(0);
int64_t rank = strides.size();
SmallVector<AffineExpr> vectorOffsets(rank);
vectorOffsets[0] = resultExpr.floorDiv(strides[0]);
resultExpr = resultExpr % strides[0];
for (unsigned i = 1; i < rank; i++) {
vectorOffsets[i] = resultExpr.floorDiv(strides[i]);
resultExpr = resultExpr % strides[i];
}
return vectorOffsets;
}
|