Skip to content

Commit c723bd4

Browse files
committed
computeSliceParameters: use full slice if affine exprs are non-monotonic
1 parent c6a666f commit c723bd4

File tree

6 files changed

+82
-2
lines changed

6 files changed

+82
-2
lines changed

mlir/include/mlir/IR/AffineExpr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ class AffineExpr {
110110
/// floordiv, ceildiv, and mod is only allowed w.r.t constants.
111111
bool isPureAffine() const;
112112

113+
/// Returns true if this expression is monotonic with respect to the
114+
/// AffineDimExpr, i.e. increasing the value of any AffineDimExpr will never
115+
/// decrease the value of the result.
116+
bool isMonotonic() const;
117+
113118
/// Returns the greatest known integral divisor of this affine expression. The
114119
/// result is always positive.
115120
int64_t getLargestKnownDivisor() const;

mlir/include/mlir/IR/AffineMap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ class AffineMap {
364364
/// Returns true if the AffineMap represents a symbol-less permutation map.
365365
bool isPermutation() const;
366366

367+
// Returns true if every result is monotonic.
368+
bool isMonotonic() const;
369+
367370
/// Returns the map consisting of the `resultPos` subset.
368371
AffineMap getSubMap(ArrayRef<unsigned> resultPos) const;
369372

mlir/lib/Dialect/Linalg/Utils/Utils.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,11 @@ computeSliceParameters(OpBuilder &builder, Location loc, Value valueToTile,
616616
sliceParams.strides.reserve(rank);
617617
for (unsigned r = 0; r < rank; ++r) {
618618
LLVM_DEBUG(llvm::dbgs() << "computeSliceParameters: for dim#" << r);
619-
if (!isTiled(map.getSubMap({r}), tileSizes)) {
619+
auto m = map.getSubMap({r});
620+
// The offset & size computation below only handles the case when
621+
// the map is monotonic, i.e. the min and max values are attained at the
622+
// lower and upper bounds of the iteration domain.
623+
if (!isTiled(m, tileSizes) || !m.isMonotonic()) {
620624
sliceParams.offsets.push_back(builder.getIndexAttr(0));
621625
OpFoldResult dim = createFoldedDimOp(builder, loc, valueToTile, r);
622626
sliceParams.sizes.push_back(dim);
@@ -628,7 +632,6 @@ computeSliceParameters(OpBuilder &builder, Location loc, Value valueToTile,
628632

629633
// Tiling creates a new slice at the proper index, the slice step is 1
630634
// (i.e. the op does not subsample, stepping occurs in the loop).
631-
auto m = map.getSubMap({r});
632635
LLVM_DEBUG(llvm::dbgs() << "computeSliceParameters: submap: " << m << "\n");
633636
IRRewriter rewriter(builder);
634637
OpFoldResult offset = makeComposedFoldedAffineApply(rewriter, loc, m, lbs);

mlir/lib/IR/AffineExpr.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,39 @@ bool AffineExpr::isPureAffine() const {
239239
llvm_unreachable("Unknown AffineExpr");
240240
}
241241

242+
static bool isNonNegativeConstant(AffineExpr expr) {
243+
auto constant = dyn_cast<AffineConstantExpr>(expr);
244+
return constant && constant.getValue() >= 0;
245+
}
246+
247+
bool AffineExpr::isMonotonic() const {
248+
switch (getKind()) {
249+
case AffineExprKind::SymbolId:
250+
case AffineExprKind::DimId:
251+
case AffineExprKind::Constant:
252+
return true;
253+
case AffineExprKind::Add: {
254+
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
255+
return op.getLHS().isMonotonic() && op.getRHS().isMonotonic();
256+
}
257+
case AffineExprKind::Mul: {
258+
// One operand must be a non-negative constant.
259+
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
260+
return op.getLHS().isMonotonic() && op.getRHS().isMonotonic() &&
261+
(isNonNegativeConstant(op.getLHS()) ||
262+
isNonNegativeConstant(op.getRHS()));
263+
}
264+
case AffineExprKind::FloorDiv:
265+
case AffineExprKind::CeilDiv: {
266+
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
267+
return op.getLHS().isMonotonic() && isNonNegativeConstant(op.getRHS());
268+
}
269+
case AffineExprKind::Mod:
270+
return false;
271+
}
272+
llvm_unreachable("Unknown AffineExpr");
273+
}
274+
242275
// Returns the greatest known integral divisor of this affine expression.
243276
int64_t AffineExpr::getLargestKnownDivisor() const {
244277
AffineBinaryOpExpr binExpr(nullptr);

mlir/lib/IR/AffineMap.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,10 @@ bool AffineMap::isPermutation() const {
628628
return isProjectedPermutation();
629629
}
630630

631+
bool AffineMap::isMonotonic() const {
632+
return all_of(getResults(), [](auto expr) { return expr.isMonotonic(); });
633+
}
634+
631635
AffineMap AffineMap::getSubMap(ArrayRef<unsigned> resultPos) const {
632636
SmallVector<AffineExpr, 4> exprs;
633637
exprs.reserve(resultPos.size());

mlir/test/Dialect/Linalg/tile-tensors.mlir

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,35 @@ module attributes {transform.with_named_sequence} {
167167
transform.yield
168168
}
169169
}
170+
171+
// -----
172+
173+
// CHECK-LABEL: func @non_monotonic_affine_expr
174+
// CHECK-SAME: %[[ARG0:[a-zA-Z0-9_]+]]: tensor<?xf32>
175+
func.func @non_monotonic_affine_expr(%arg0 : tensor<?xf32>) -> tensor<?xf32> {
176+
%c0 = arith.constant 0 : index
177+
%0 = tensor.dim %arg0, %c0 : tensor<?xf32>
178+
%empty = tensor.empty(%0) : tensor<?xf32>
179+
180+
// CHECK: scf.for
181+
// CHECK: %[[SIZE:[a-zA-Z0-9_]+]] = tensor.dim %[[ARG0]],
182+
// CHECK: tensor.extract_slice %[[ARG0]][0] [%[[SIZE]]] [1] : tensor<?xf32> to tensor<?xf32>
183+
%generic = linalg.generic
184+
{indexing_maps = [affine_map<(d0) -> (d0 mod 3)>,
185+
affine_map<(d0) -> (d0)>],
186+
iterator_types = ["parallel"]}
187+
ins(%arg0: tensor<?xf32>)
188+
outs(%empty : tensor<?xf32>) {
189+
^bb0(%in : f32, %out: f32):
190+
linalg.yield %in : f32
191+
} -> tensor<?xf32>
192+
return %generic : tensor<?xf32>
193+
}
194+
195+
module attributes {transform.with_named_sequence} {
196+
transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
197+
%0 = transform.structured.match ops{["linalg.generic"]} in %arg1 : (!transform.any_op) -> !transform.any_op
198+
%1, %loop = transform.structured.tile_using_for %0 tile_sizes [100] : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
199+
transform.yield
200+
}
201+
}

0 commit comments

Comments
 (0)