16#include "mlir/Dialect/Affine/IR/AffineOps.h"
17#include "mlir/Dialect/Arith/IR/Arith.h"
18#include "mlir/Dialect/Vector/IR/VectorOps.h"
19#include "llvm/ADT/TypeSwitch.h"
22#define DEBUG_TYPE "aievec-utils"
28static std::optional<int64_t> getLowerBoundValue(Value idx) {
29 if (
auto blkArg = dyn_cast<BlockArgument>(idx)) {
30 auto parentOp = blkArg.getOwner()->getParentOp();
31 return TypeSwitch<Operation *, std::optional<int64_t>>(parentOp)
32 .Case<affine::AffineForOp>([&blkArg](affine::AffineForOp forOp) {
33 if (forOp.getInductionVar() == blkArg &&
34 forOp.hasConstantLowerBound())
35 return std::optional<int64_t>(forOp.getConstantLowerBound());
40 return std::optional<int64_t>();
42 .Default([](
auto) {
return std::optional<int64_t>(); });
44 return TypeSwitch<Operation *, std::optional<int64_t>>(idx.getDefiningOp())
45 .Case<arith::ConstantOp>([](
auto constantOp) {
46 return std::optional<int64_t>(
47 cast<IntegerAttr>(constantOp.getValue()).getInt());
49 .Case<affine::AffineApplyOp>([](
auto applyOp) {
50 if (applyOp.getAffineMap().getNumResults() == 1) {
51 auto affineMap = applyOp.getAffineMap();
54 if (affineMap.getNumSymbols() > 0) {
55 auto operands = applyOp.getMapOperands();
56 unsigned numDims = affineMap.getNumDims();
58 SmallVector<int64_t, 4> dimValues;
59 SmallVector<int64_t, 4> symbolValues;
62 for (
unsigned i = 0; i < numDims; i++) {
63 std::optional<int64_t> lbv = getLowerBoundValue(operands[i]);
64 if (!lbv && !isa<BlockArgument>(operands[i]))
65 return std::optional<int64_t>();
66 dimValues.push_back(lbv.value_or(0L));
70 for (
unsigned i = numDims; i < operands.size(); i++) {
71 std::optional<int64_t> lbv = getLowerBoundValue(operands[i]);
72 if (!lbv && !isa<BlockArgument>(operands[i]))
73 return std::optional<int64_t>();
74 symbolValues.push_back(lbv.value_or(0L));
78 auto expr = affineMap.getResult(0);
79 auto ctx = affineMap.getContext();
82 SmallVector<AffineExpr, 4> dimExprs;
83 SmallVector<AffineExpr, 4> symbolExprs;
84 for (
auto val : dimValues)
85 dimExprs.push_back(getAffineConstantExpr(val, ctx));
86 for (
auto val : symbolValues)
87 symbolExprs.push_back(getAffineConstantExpr(val, ctx));
89 expr = expr.replaceDimsAndSymbols(dimExprs, symbolExprs);
90 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
91 return std::optional<int64_t>(constExpr.getValue());
95 return std::optional<int64_t>();
98 auto operands = applyOp.getMapOperands();
99 SmallVector<int64_t, 4> srcIndices;
100 for (
auto index : operands) {
101 std::optional<int64_t> lbv = getLowerBoundValue(index);
104 if (!lbv && !isa<BlockArgument>(index))
105 return std::optional<int64_t>();
106 srcIndices.push_back(lbv.value_or(0L));
108 return std::optional<int64_t>(affineMap.compose(srcIndices)[0]);
110 return std::optional<int64_t>();
112 .Default([&](
auto) {
return std::optional<int64_t>(); });
119template <
typename TransferReadLikeOp,
typename>
127 auto innerMostIndex = readOp.getIndices().back();
128 auto vectorLength = vType.getShape().back();
129 std::optional<int64_t> lbv = getLowerBoundValue(innerMostIndex);
132 int64_t vectorLengthAlignmentOffset = lbv.value() % vectorLength;
133 int64_t absoluteAlignmentOffset = alignment / vType.getElementTypeBitWidth();
134 if (vectorLengthAlignmentOffset % absoluteAlignmentOffset)
135 return vectorLengthAlignmentOffset;
139template std::optional<int64_t>
142template std::optional<int64_t>
144 VectorType vType, int64_t alignment);
147 if (vecTy.getRank() == 1)
149 auto shape = vecTy.getShape();
150 return VectorType::get(
151 {std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<>())},
152 vecTy.getElementType());
mlir::VectorType getFlattenedVectorType(mlir::VectorType vecTy)
std::optional< int64_t > getTransferReadAlignmentOffset(TransferReadLikeOp readOp, mlir::VectorType vType, int64_t alignment)