Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

computeSliceParameters: use full slice if affine exprs are non-monotonic #407

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions mlir/include/mlir/IR/AffineExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ class AffineExpr {
/// floordiv, ceildiv, and mod is only allowed w.r.t constants.
bool isPureAffine() const;

/// Returns true if this expression is monotonic with respect to the
/// AffineDimExpr, i.e. increasing the value of any AffineDimExpr will never
/// decrease the value of the result.
bool isMonotonic() const;

/// Returns the greatest known integral divisor of this affine expression. The
/// result is always positive.
int64_t getLargestKnownDivisor() const;
Expand Down
3 changes: 3 additions & 0 deletions mlir/include/mlir/IR/AffineMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ class AffineMap {
/// Returns true if the AffineMap represents a symbol-less permutation map.
bool isPermutation() const;

// Returns true if every result is monotonic.
bool isMonotonic() const;

/// Returns the map consisting of the `resultPos` subset.
AffineMap getSubMap(ArrayRef<unsigned> resultPos) const;

Expand Down
7 changes: 5 additions & 2 deletions mlir/lib/Dialect/Linalg/Utils/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,11 @@ computeSliceParameters(OpBuilder &builder, Location loc, Value valueToTile,
sliceParams.strides.reserve(rank);
for (unsigned r = 0; r < rank; ++r) {
LLVM_DEBUG(llvm::dbgs() << "computeSliceParameters: for dim#" << r);
if (!isTiled(map.getSubMap({r}), tileSizes)) {
auto m = map.getSubMap({r});
// The offset & size computation below only handles the case when
// the map is monotonic, i.e. the min and max values are attained at the
mgehre-amd marked this conversation as resolved.
Show resolved Hide resolved
// lower and upper bounds of the iteration domain.
if (!isTiled(m, tileSizes) || !m.isMonotonic()) {
sliceParams.offsets.push_back(builder.getIndexAttr(0));
OpFoldResult dim = createFoldedDimOp(builder, loc, valueToTile, r);
sliceParams.sizes.push_back(dim);
Expand All @@ -628,7 +632,6 @@ computeSliceParameters(OpBuilder &builder, Location loc, Value valueToTile,

// Tiling creates a new slice at the proper index, the slice step is 1
// (i.e. the op does not subsample, stepping occurs in the loop).
auto m = map.getSubMap({r});
LLVM_DEBUG(llvm::dbgs() << "computeSliceParameters: submap: " << m << "\n");
IRRewriter rewriter(builder);
OpFoldResult offset = makeComposedFoldedAffineApply(rewriter, loc, m, lbs);
Expand Down
33 changes: 33 additions & 0 deletions mlir/lib/IR/AffineExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,39 @@ bool AffineExpr::isPureAffine() const {
llvm_unreachable("Unknown AffineExpr");
}

static bool isNonNegativeConstant(AffineExpr expr) {
auto constant = dyn_cast<AffineConstantExpr>(expr);
return constant && constant.getValue() >= 0;
}

bool AffineExpr::isMonotonic() const {
mgehre-amd marked this conversation as resolved.
Show resolved Hide resolved
switch (getKind()) {
case AffineExprKind::SymbolId:
case AffineExprKind::DimId:
case AffineExprKind::Constant:
return true;
case AffineExprKind::Add: {
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
return op.getLHS().isMonotonic() && op.getRHS().isMonotonic();
}
case AffineExprKind::Mul: {
// One operand must be a non-negative constant.
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
return op.getLHS().isMonotonic() && op.getRHS().isMonotonic() &&
(isNonNegativeConstant(op.getLHS()) ||
isNonNegativeConstant(op.getRHS()));
mgehre-amd marked this conversation as resolved.
Show resolved Hide resolved
}
case AffineExprKind::FloorDiv:
case AffineExprKind::CeilDiv: {
auto op = llvm::cast<AffineBinaryOpExpr>(*this);
return op.getLHS().isMonotonic() && isNonNegativeConstant(op.getRHS());
}
case AffineExprKind::Mod:
return false;
}
llvm_unreachable("Unknown AffineExpr");
}

// Returns the greatest known integral divisor of this affine expression.
int64_t AffineExpr::getLargestKnownDivisor() const {
AffineBinaryOpExpr binExpr(nullptr);
Expand Down
4 changes: 4 additions & 0 deletions mlir/lib/IR/AffineMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,10 @@ bool AffineMap::isPermutation() const {
return isProjectedPermutation();
}

bool AffineMap::isMonotonic() const {
mgehre-amd marked this conversation as resolved.
Show resolved Hide resolved
return all_of(getResults(), [](auto expr) { return expr.isMonotonic(); });
}

AffineMap AffineMap::getSubMap(ArrayRef<unsigned> resultPos) const {
SmallVector<AffineExpr, 4> exprs;
exprs.reserve(resultPos.size());
Expand Down
32 changes: 32 additions & 0 deletions mlir/test/Dialect/Linalg/tile-tensors.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,35 @@ module attributes {transform.with_named_sequence} {
transform.yield
}
}

// -----

// CHECK-LABEL: func @non_monotonic_affine_expr
// CHECK-SAME: %[[ARG0:[a-zA-Z0-9_]+]]: tensor<?xf32>
func.func @non_monotonic_affine_expr(%arg0 : tensor<?xf32>) -> tensor<?xf32> {
%c0 = arith.constant 0 : index
%0 = tensor.dim %arg0, %c0 : tensor<?xf32>
%empty = tensor.empty(%0) : tensor<?xf32>

// CHECK: scf.for
// CHECK: %[[SIZE:[a-zA-Z0-9_]+]] = tensor.dim %[[ARG0]],
// CHECK: tensor.extract_slice %[[ARG0]][0] [%[[SIZE]]] [1] : tensor<?xf32> to tensor<?xf32>
%generic = linalg.generic
{indexing_maps = [affine_map<(d0) -> (d0 mod 3)>,
affine_map<(d0) -> (d0)>],
iterator_types = ["parallel"]}
ins(%arg0: tensor<?xf32>)
outs(%empty : tensor<?xf32>) {
^bb0(%in : f32, %out: f32):
linalg.yield %in : f32
} -> tensor<?xf32>
return %generic : tensor<?xf32>
}

mgehre-amd marked this conversation as resolved.
Show resolved Hide resolved
module attributes {transform.with_named_sequence} {
transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
%0 = transform.structured.match ops{["linalg.generic"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1, %loop = transform.structured.tile_using_for %0 tile_sizes [100] : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
transform.yield
}
}
Loading