13#include "mlir/Dialect/Affine/IR/AffineOps.h"
14#include "mlir/Dialect/Arith/IR/Arith.h"
15#include "mlir/Dialect/Vector/IR/VectorOps.h"
16#include "llvm/ADT/TypeSwitch.h"
19#define DEBUG_TYPE "aievec-utils"
25static std::optional<int64_t> getLowerBoundValue(Value idx) {
26 if (
auto blkArg = dyn_cast<BlockArgument>(idx)) {
27 auto *parentOp = blkArg.getOwner()->getParentOp();
28 return TypeSwitch<Operation *, std::optional<int64_t>>(parentOp)
29 .Case<affine::AffineForOp>([&blkArg](affine::AffineForOp forOp) {
30 if (forOp.getInductionVar() == blkArg &&
31 forOp.hasConstantLowerBound())
32 return std::optional<int64_t>(forOp.getConstantLowerBound());
37 return std::optional<int64_t>();
39 .Default([](
auto) {
return std::optional<int64_t>(); });
41 return TypeSwitch<Operation *, std::optional<int64_t>>(idx.getDefiningOp())
42 .Case<arith::ConstantOp>([](
auto constantOp) {
43 return std::optional<int64_t>(
44 cast<IntegerAttr>(constantOp.getValue()).getInt());
46 .Case<affine::AffineApplyOp>([](
auto applyOp) {
47 if (applyOp.getAffineMap().getNumResults() == 1) {
48 auto affineMap = applyOp.getAffineMap();
51 if (affineMap.getNumSymbols() > 0) {
52 auto operands = applyOp.getMapOperands();
53 unsigned numDims = affineMap.getNumDims();
55 SmallVector<int64_t, 4> dimValues;
56 SmallVector<int64_t, 4> symbolValues;
59 for (
unsigned i = 0; i < numDims; i++) {
60 std::optional<int64_t> lbv = getLowerBoundValue(operands[i]);
61 if (!lbv && !isa<BlockArgument>(operands[i]))
62 return std::optional<int64_t>();
63 dimValues.push_back(lbv.value_or(0L));
67 for (
unsigned i = numDims; i < operands.size(); i++) {
68 std::optional<int64_t> lbv = getLowerBoundValue(operands[i]);
69 if (!lbv && !isa<BlockArgument>(operands[i]))
70 return std::optional<int64_t>();
71 symbolValues.push_back(lbv.value_or(0L));
75 auto expr = affineMap.getResult(0);
76 auto ctx = affineMap.getContext();
79 SmallVector<AffineExpr, 4> dimExprs;
80 SmallVector<AffineExpr, 4> symbolExprs;
81 for (
auto val : dimValues)
82 dimExprs.push_back(getAffineConstantExpr(val, ctx));
83 for (
auto val : symbolValues)
84 symbolExprs.push_back(getAffineConstantExpr(val, ctx));
86 expr = expr.replaceDimsAndSymbols(dimExprs, symbolExprs);
87 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
88 return std::optional<int64_t>(constExpr.getValue());
92 return std::optional<int64_t>();
95 auto operands = applyOp.getMapOperands();
96 SmallVector<int64_t, 4> srcIndices;
97 for (
auto index : operands) {
98 std::optional<int64_t> lbv = getLowerBoundValue(index);
101 if (!lbv && !isa<BlockArgument>(index))
102 return std::optional<int64_t>();
103 srcIndices.push_back(lbv.value_or(0L));
105 return std::optional<int64_t>(affineMap.compose(srcIndices)[0]);
107 return std::optional<int64_t>();
109 .Default([&](
auto) {
return std::optional<int64_t>(); });
116template <
typename TransferReadLikeOp,
typename>
124 auto innerMostIndex = readOp.getIndices().back();
125 auto vectorLength = vType.getShape().back();
126 std::optional<int64_t> lbv = getLowerBoundValue(innerMostIndex);
129 int64_t vectorLengthAlignmentOffset = lbv.value() % vectorLength;
130 int64_t absoluteAlignmentOffset = alignment / vType.getElementTypeBitWidth();
131 if (vectorLengthAlignmentOffset % absoluteAlignmentOffset)
132 return vectorLengthAlignmentOffset;
136template std::optional<int64_t>
139template std::optional<int64_t>
141 VectorType vType, int64_t alignment);
144 if (vecTy.getRank() == 1)
146 auto shape = vecTy.getShape();
147 return VectorType::get(
148 {std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<>())},
149 vecTy.getElementType());
mlir::VectorType getFlattenedVectorType(mlir::VectorType vecTy)
std::optional< int64_t > getTransferReadAlignmentOffset(TransferReadLikeOp readOp, mlir::VectorType vType, int64_t alignment)