MLIR  21.0.0git
Utils.cpp
Go to the documentation of this file.
1 //===- Utils.cpp - Utilities to support the Tensor dialect ----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements utilities for the Tensor dialect.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 
21 
22 using namespace mlir;
23 using namespace mlir::tensor;
24 
25 PadOp mlir::tensor::createPadHighOp(RankedTensorType resType, Value source,
26  Value pad, bool nofold, Location loc,
27  OpBuilder &b,
28  SmallVector<Value> dynOutDims) {
29 
30  // This assumption simplifies the following logic without limiting what's
31  // required _today_. If needed, we can relax it in the future.
32  assert(((resType.getNumDynamicDims() == dynOutDims.size()) ||
33  dynOutDims.empty()) &&
34  "Either none or all output dynamic dims must be specified!");
35 
36  // Init "low" and "high" padding values ("low" is kept as is, "high" is
37  // computed below).
38  SmallVector<OpFoldResult> low(resType.getRank(), b.getIndexAttr(0));
39  SmallVector<OpFoldResult> high(resType.getRank(), b.getIndexAttr(0));
40 
41  size_t outDimIdx = 0;
42 
43  for (const auto [idx, val] : enumerate(resType.getShape())) {
44  bool isDimDynamic = ShapedType::isDynamic(val);
45  bool updatePadHigh = !isDimDynamic || !dynOutDims.empty();
46 
47  // Keep the default padding width (i.e. "0") when the output dim is dynamic
48  // and no actual output sizes have been provided.
49  if (!updatePadHigh)
50  continue;
51 
52  // Compute the padding width: resDim - sourceDim.
53  AffineExpr d0, d1;
54  bindDims(b.getContext(), d0, d1);
55  OpFoldResult sourceDim = tensor::getMixedSize(b, loc, source, idx);
56  OpFoldResult outDim = isDimDynamic ? OpFoldResult(dynOutDims[outDimIdx++])
57  : OpFoldResult(b.getIndexAttr(val));
58 
59  high[idx] = affine::makeComposedFoldedAffineApply(b, loc, d0 - d1,
60  {outDim, sourceDim});
61  }
62  return b.create<PadOp>(loc, resType, source, low, high, pad, nofold);
63 }
64 
66  Location loc,
67  Value rankedTensor) {
68  auto tensorTy = cast<RankedTensorType>(rankedTensor.getType());
69  SmallVector<Value> dynamicDims;
70  for (const auto &en : llvm::enumerate(tensorTy.getShape())) {
71  if (en.value() == ShapedType::kDynamic)
72  dynamicDims.push_back(
73  b.create<tensor::DimOp>(loc, rankedTensor, en.index()));
74  }
75  return dynamicDims;
76 }
77 
78 FailureOr<RankedTensorType>
79 mlir::tensor::computeTransposedType(RankedTensorType rankedTensorType,
80  ArrayRef<int64_t> transposeVector) {
81  if (transposeVector.empty())
82  return rankedTensorType;
83 
84  if (!isPermutationVector(transposeVector) ||
85  transposeVector.size() != static_cast<size_t>(rankedTensorType.getRank()))
86  return failure();
87 
88  SmallVector<int64_t> transposedShape(rankedTensorType.getShape());
89  applyPermutationToVector(transposedShape, transposeVector);
90 
91  using RTTBuilder = RankedTensorType::Builder;
92  RankedTensorType transposedTensorType =
93  RTTBuilder(rankedTensorType).setShape(transposedShape);
94  return transposedTensorType;
95 }
96 
97 bool mlir::tensor::isCastLikeInsertSliceOp(InsertSliceOp op) {
98  llvm::SmallBitVector droppedDims = op.getDroppedDims();
99  int64_t srcDim = 0;
100  RankedTensorType resultType = op.getDestType();
101  // Source dims and destination dims (apart from dropped dims) must have the
102  // same size.
103  for (int64_t resultDim = 0; resultDim < resultType.getRank(); ++resultDim) {
104  if (droppedDims.test(resultDim)) {
105  // InsertSlice may expand unit dimensions that result from inserting a
106  // size-1 slice into a non-size-1 result dimension.
107  if (resultType.getDimSize(resultDim) != 1)
108  return false;
109  continue;
110  }
111  FailureOr<bool> equalDimSize = ValueBoundsConstraintSet::areEqual(
112  {op.getSource(), srcDim}, {op.getResult(), resultDim});
113  if (failed(equalDimSize) || !*equalDimSize)
114  return false;
115  ++srcDim;
116  }
117 
118  return true;
119 }
120 
121 bool mlir::tensor::isCastLikeExtractSliceOp(ExtractSliceOp op) {
122  llvm::SmallBitVector droppedDims = op.getDroppedDims();
123  int64_t resultDim = 0;
124  // Source dims and result dims (apart from dropped dims) must have the same
125  // size.
126  RankedTensorType sourceType = op.getSourceType();
127  for (int64_t dim = 0, e = sourceType.getRank(); dim < e; ++dim) {
128  if (droppedDims.test(dim)) {
129  // ExtractSlice may drop unit dimensions that result from taking a size-1
130  // slice from a non-size-1 source dimension.
131  if (sourceType.getDimSize(dim) != 1)
132  return false;
133  continue;
134  }
135  FailureOr<bool> equalDimSize = ValueBoundsConstraintSet::areEqual(
136  {op.getSource(), dim}, {op.getResult(), resultDim});
137  if (failed(equalDimSize) || !*equalDimSize)
138  return false;
139  ++resultDim;
140  }
141 
142  return true;
143 }
Base type for affine expression.
Definition: AffineExpr.h:68
IntegerAttr getIndexAttr(int64_t value)
Definition: Builders.cpp:104
MLIRContext * getContext() const
Definition: Builders.h:56
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:66
This class helps build Operations.
Definition: Builders.h:205
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:453
This class represents a single result from folding an operation.
Definition: OpDefinition.h:271
This is a builder type that keeps local references to arguments.
Definition: BuiltinTypes.h:214
Builder & setShape(ArrayRef< int64_t > newShape)
Definition: BuiltinTypes.h:225
static FailureOr< bool > areEqual(const Variable &var1, const Variable &var2)
Compute whether the given variables are equal.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:129
OpFoldResult makeComposedFoldedAffineApply(OpBuilder &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > operands)
Constructs an AffineApplyOp that applies map to operands after composing the map with the maps of any...
Definition: AffineOps.cpp:1208
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
PadOp createPadHighOp(RankedTensorType resType, Value source, Value pad, bool nofold, Location loc, OpBuilder &builder, SmallVector< Value > dynOutDims={})
Definition: Utils.cpp:25
SmallVector< Value > createDynamicDimValues(OpBuilder &b, Location loc, Value rankedTensor)
Definition: Utils.cpp:65
bool isCastLikeInsertSliceOp(InsertSliceOp op)
A tensor.insert_slice is a cast-like operation if it merely rank-extends the source tensor or inserts...
Definition: Utils.cpp:97
bool isCastLikeExtractSliceOp(ExtractSliceOp op)
A tensor.extract_slice is a cast-like operation if it merely rank-reduces unit dimensions of the sour...
Definition: Utils.cpp:121
OpFoldResult getMixedSize(OpBuilder &builder, Location loc, Value value, int64_t dim)
Return the dimension of the given tensor value.
Definition: TensorOps.cpp:59
FailureOr< RankedTensorType > computeTransposedType(RankedTensorType rankedTensorType, ArrayRef< int64_t > transposeVector)
Returns the transposed rankedTensorType if transposeVector is non-empty.
Definition: Utils.cpp:79
Include the generated interface declarations.
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
Definition: AffineExpr.h:348
void applyPermutationToVector(SmallVector< T, N > &inVec, ArrayRef< int64_t > permutation)
Apply the permutation defined by permutation to inVec.
bool isPermutationVector(ArrayRef< int64_t > interchange)
Method to check if an interchange vector is a permutation.