Skip to content

Commit 573742a

Browse files
authored
Merge pull request #407 from Xilinx/matthias.fix_non_monotonic_slice_params
computeSliceParameters: use full slice if affine exprs are non-monotonic
2 parents 1bf1742 + 79ef42a commit 573742a

File tree

6 files changed

+87
-2
lines changed

6 files changed

+87
-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 monotonicically increasing with respect
114+
/// to the AffineDimExprs, i.e. increasing the value of any AffineDimExpr will
115+
/// never decrease the value of the result.
116+
bool isMonotonicallyIncreasing() 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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ 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 monotonically increasing.
368+
// See AffineExpr::isMonotonicallyIncreasing().
369+
bool isComponentWiseMonotonicallyIncreasing() const;
370+
367371
/// Returns the map consisting of the `resultPos` subset.
368372
AffineMap getSubMap(ArrayRef<unsigned> resultPos) const;
369373

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 monotonically increasing, i.e. the min and max values are
622+
// attained at the lower and upper bounds of the iteration domain.
623+
if (!isTiled(m, tileSizes) || !m.isComponentWiseMonotonicallyIncreasing()) {
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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,42 @@ 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::isMonotonicallyIncreasing() 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().isMonotonicallyIncreasing() &&
256+
op.getRHS().isMonotonicallyIncreasing();
257+
}
258+
case AffineExprKind::Mul: {
259+
// One operand must be a non-negative constant.
260+
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
261+
return op.getLHS().isMonotonicallyIncreasing() &&
262+
op.getRHS().isMonotonicallyIncreasing() &&
263+
(isNonNegativeConstant(op.getLHS()) ||
264+
isNonNegativeConstant(op.getRHS()));
265+
}
266+
case AffineExprKind::FloorDiv:
267+
case AffineExprKind::CeilDiv: {
268+
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
269+
return op.getLHS().isMonotonicallyIncreasing() &&
270+
isNonNegativeConstant(op.getRHS());
271+
}
272+
case AffineExprKind::Mod:
273+
return false;
274+
}
275+
llvm_unreachable("Unknown AffineExpr");
276+
}
277+
242278
// Returns the greatest known integral divisor of this affine expression.
243279
int64_t AffineExpr::getLargestKnownDivisor() const {
244280
AffineBinaryOpExpr binExpr(nullptr);

mlir/lib/IR/AffineMap.cpp

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

631+
bool AffineMap::isComponentWiseMonotonicallyIncreasing() const {
632+
return all_of(getResults(),
633+
[](auto expr) { return expr.isMonotonicallyIncreasing(); });
634+
}
635+
631636
AffineMap AffineMap::getSubMap(ArrayRef<unsigned> resultPos) const {
632637
SmallVector<AffineExpr, 4> exprs;
633638
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)