MLIR  18.0.0git
IndependenceTransforms.cpp
Go to the documentation of this file.
1 //===- IndependenceTransforms.cpp - Make ops independent of values --------===//
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 
10 
16 
17 using namespace mlir;
18 using namespace mlir::tensor;
19 
20 /// Make the given OpFoldResult independent of all independencies.
22  OpFoldResult ofr,
23  ValueRange independencies) {
24  if (ofr.is<Attribute>())
25  return ofr;
26  Value value = ofr.get<Value>();
27  AffineMap boundMap;
28  ValueDimList mapOperands;
30  boundMap, mapOperands, presburger::BoundType::UB, value,
31  /*dim=*/std::nullopt, independencies, /*closedUB=*/true)))
32  return failure();
33  return mlir::affine::materializeComputedBound(b, loc, boundMap, mapOperands);
34 }
35 
37  ValueRange independencies) {
39  b.setInsertionPoint(padOp);
40  Location loc = padOp.getLoc();
41 
42  // Non-constant padding not supported.
43  Value constantPadding = padOp.getConstantPaddingValue();
44  if (!constantPadding)
45  return failure();
46 
47  SmallVector<OpFoldResult> newMixedLow, newMixedHigh;
48  for (OpFoldResult ofr : padOp.getMixedLowPad()) {
49  auto ub = makeIndependent(b, loc, ofr, independencies);
50  if (failed(ub))
51  return failure();
52  newMixedLow.push_back(*ub);
53  }
54  for (OpFoldResult ofr : padOp.getMixedHighPad()) {
55  auto ub = makeIndependent(b, loc, ofr, independencies);
56  if (failed(ub))
57  return failure();
58  newMixedHigh.push_back(*ub);
59  }
60 
61  // Return existing tensor::PadOp if nothing has changed.
62  if (llvm::equal(padOp.getMixedLowPad(), newMixedLow) &&
63  llvm::equal(padOp.getMixedHighPad(), newMixedHigh))
64  return padOp.getResult();
65 
66  // Create a new tensor::PadOp.
67  auto newPadOp = b.create<PadOp>(
68  loc, padOp.getResultType(), padOp.getSource(), newMixedLow, newMixedHigh,
69  constantPadding, padOp.getNofold(), /*attrs=*/ArrayRef<NamedAttribute>{});
70 
71  // Create a tensor::ExtractSliceOp.
72  // Reify the result sizes of the old tensor::PadOp.
73  ReifiedRankedShapedTypeDims reifiedSizes;
74  ReifyRankedShapedTypeOpInterface reifyShapedTypeInterface =
75  dyn_cast<ReifyRankedShapedTypeOpInterface>(padOp.getOperation());
76  if (failed(reifyShapedTypeInterface.reifyResultShapes(b, reifiedSizes)))
77  return failure();
78  SmallVector<OpFoldResult> offsets, sizes, strides;
79  for (int64_t i = 0, e = padOp.getResultType().getRank(); i < e; ++i) {
80  // offset = ub(low_padding) - low_padding
81  OpFoldResult prevLow = padOp.getMixedLowPad()[i];
82  if (prevLow.is<Attribute>()) {
83  offsets.push_back(b.getIndexAttr(0));
84  } else {
85  offsets.push_back(
86  b.create<affine::AffineApplyOp>(
87  loc, b.getAffineDimExpr(0) - b.getAffineDimExpr(1),
88  std::initializer_list<Value>{newMixedLow[i].get<Value>(),
89  prevLow.get<Value>()})
90  .getResult());
91  }
92  // size = reified result size
93  if (!padOp.getResultType().isDynamicDim(i)) {
94  sizes.push_back(b.getIndexAttr(padOp.getResultType().getDimSize(i)));
95  } else {
96  sizes.push_back(reifiedSizes[0][i]);
97  }
98  // stride = 1
99  strides.push_back(b.getIndexAttr(1));
100  }
101 
102  return b.create<ExtractSliceOp>(loc, newPadOp, offsets, sizes, strides)
103  .getResult();
104 }
105 
107  tensor::EmptyOp emptyOp,
108  ValueRange independencies) {
110  b.setInsertionPoint(emptyOp);
111  Location loc = emptyOp.getLoc();
112 
113  SmallVector<OpFoldResult> newSizes;
114  for (OpFoldResult ofr : emptyOp.getMixedSizes()) {
115  auto ub = makeIndependent(b, loc, ofr, independencies);
116  if (failed(ub))
117  return failure();
118  newSizes.push_back(*ub);
119  }
120 
121  // Return existing tensor::EmptyOp if nothing has changed.
122  if (llvm::equal(emptyOp.getMixedSizes(), newSizes))
123  return emptyOp.getResult();
124 
125  // Create a new tensor::EmptyOp.
126  Value newEmptyOp =
127  b.create<EmptyOp>(loc, newSizes, emptyOp.getType().getElementType());
128 
129  // Create a tensor::ExtractSliceOp.
130  SmallVector<OpFoldResult> offsets(newSizes.size(), b.getIndexAttr(0));
131  SmallVector<OpFoldResult> strides(newSizes.size(), b.getIndexAttr(1));
132  return b
133  .create<ExtractSliceOp>(loc, newEmptyOp, offsets, emptyOp.getMixedSizes(),
134  strides)
135  .getResult();
136 }
static FailureOr< OpFoldResult > makeIndependent(OpBuilder &b, Location loc, OpFoldResult ofr, ValueRange independencies)
Make the given OpFoldResult independent of all independencies.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:47
Attributes are known-constant values of operations.
Definition: Attributes.h:25
IntegerAttr getIndexAttr(int64_t value)
Definition: Builders.cpp:124
AffineExpr getAffineDimExpr(unsigned position)
Definition: Builders.cpp:353
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
RAII guard to reset the insertion point of the builder when destroyed.
Definition: Builders.h:333
This class helps build Operations.
Definition: Builders.h:206
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition: Builders.h:383
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:446
This class represents a single result from folding an operation.
Definition: OpDefinition.h:266
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:402
static LogicalResult computeIndependentBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, Value value, std::optional< int64_t > dim, ValueRange independencies, bool closedUB=false)
Compute a bound in that is independent of all values in independencies.
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:378
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
OpFoldResult materializeComputedBound(OpBuilder &b, Location loc, AffineMap boundMap, ArrayRef< std::pair< Value, std::optional< int64_t >>> mapOperands)
Materialize an already computed bound with Affine dialect ops.
FailureOr< Value > buildIndependentOp(OpBuilder &b, tensor::PadOp padOp, ValueRange independencies)
Build a new tensor::PadOp with low/high padding that is independent of all given independencies.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72