MLIR-AIE 1.4.5.dev
Utils.cpp
Go to the documentation of this file.
1//===- Utils.cpp - Utilities to support AIE vectorization -----------------===//
2//
3// Copyright (C) 2023 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7//
8// This file implements utilities for the AIEVec dialect
9//
10//===----------------------------------------------------------------------===//
11
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"
17#include <numeric>
18
19#define DEBUG_TYPE "aievec-utils"
20
21using namespace mlir;
22
23namespace xilinx::aievec {
24
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());
33 // If it's an iteration argument or the lower bound is an
34 // affine expression.
35 // TODO: Compute the value of the lower bound affine expression
36 // TODO: if it's constant.
37 return std::optional<int64_t>();
38 })
39 .Default([](auto) { return std::optional<int64_t>(); });
40 }
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());
45 })
46 .Case<affine::AffineApplyOp>([](auto applyOp) {
47 if (applyOp.getAffineMap().getNumResults() == 1) {
48 auto affineMap = applyOp.getAffineMap();
49
50 // Check if the map has symbols - if so, try symbol-aware evaluation
51 if (affineMap.getNumSymbols() > 0) {
52 auto operands = applyOp.getMapOperands();
53 unsigned numDims = affineMap.getNumDims();
54
55 SmallVector<int64_t, 4> dimValues;
56 SmallVector<int64_t, 4> symbolValues;
57
58 // Collect dimension values
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));
64 }
65
66 // Collect symbol values
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));
72 }
73
74 // Manually replace and constant fold
75 auto expr = affineMap.getResult(0);
76 auto ctx = affineMap.getContext();
77
78 // Convert int64_t values to AffineConstantExpr
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));
85
86 expr = expr.replaceDimsAndSymbols(dimExprs, symbolExprs);
87 if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
88 return std::optional<int64_t>(constExpr.getValue());
89 }
90
91 // If expression couldn't be constant-folded, return nullopt
92 return std::optional<int64_t>();
93 }
94
95 auto operands = applyOp.getMapOperands();
96 SmallVector<int64_t, 4> srcIndices;
97 for (auto index : operands) {
98 std::optional<int64_t> lbv = getLowerBoundValue(index);
99 // XXX: We assume block arguments to either have well-defined
100 // XXX: compile-time values, or to be aligned.
101 if (!lbv && !isa<BlockArgument>(index))
102 return std::optional<int64_t>();
103 srcIndices.push_back(lbv.value_or(0L));
104 }
105 return std::optional<int64_t>(affineMap.compose(srcIndices)[0]);
106 }
107 return std::optional<int64_t>();
108 })
109 .Default([&](auto) { return std::optional<int64_t>(); });
110}
111
112// Return the offset of a given transfer read operation with regards to the
113// specified vector type. If the read is aligned to the specified alignment
114// parameter (in bits), then the offset is 0. Otherwise, the offset is the
115// number of elements past the immediately preceding aligned vector length.
116template <typename TransferReadLikeOp, typename>
117std::optional<int64_t> getTransferReadAlignmentOffset(TransferReadLikeOp readOp,
118 VectorType vType,
119 int64_t alignment) {
120 // TODO: Add support for cases where the index is not comming from an
121 // TODO: `affine.apply` op or when the affine map has more than one
122 // TODO: dimension. We also need to address the case where the index is an
123 // TODO: induction variable.
124 auto innerMostIndex = readOp.getIndices().back();
125 auto vectorLength = vType.getShape().back();
126 std::optional<int64_t> lbv = getLowerBoundValue(innerMostIndex);
127 if (!lbv)
128 return std::nullopt;
129 int64_t vectorLengthAlignmentOffset = lbv.value() % vectorLength;
130 int64_t absoluteAlignmentOffset = alignment / vType.getElementTypeBitWidth();
131 if (vectorLengthAlignmentOffset % absoluteAlignmentOffset)
132 return vectorLengthAlignmentOffset;
133 return 0;
134}
135
136template std::optional<int64_t>
137getTransferReadAlignmentOffset(vector::TransferReadOp readOp, VectorType vType,
138 int64_t alignment);
139template std::optional<int64_t>
140getTransferReadAlignmentOffset(vector::TransferReadOp::Adaptor readOp,
141 VectorType vType, int64_t alignment);
142
143VectorType getFlattenedVectorType(VectorType vecTy) {
144 if (vecTy.getRank() == 1)
145 return vecTy;
146 auto shape = vecTy.getShape();
147 return VectorType::get(
148 {std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<>())},
149 vecTy.getElementType());
150}
151
152} // namespace xilinx::aievec
mlir::VectorType getFlattenedVectorType(mlir::VectorType vecTy)
std::optional< int64_t > getTransferReadAlignmentOffset(TransferReadLikeOp readOp, mlir::VectorType vType, int64_t alignment)