[Mlir-commits] [mlir] dc44acc - [MLIR] Fix/check for aliases for escaping memrefs in affine fusion
Uday Bondhugula
llvmlistbot at llvm.org
Wed Dec 14 09:24:07 PST 2022
Author: Uday Bondhugula
Date: 2022-12-14T22:53:29+05:30
New Revision: dc44acc9654116701159a6ebdd6ccf62211fd35a
URL: https://github.com/llvm/llvm-project/commit/dc44acc9654116701159a6ebdd6ccf62211fd35a
DIFF: https://github.com/llvm/llvm-project/commit/dc44acc9654116701159a6ebdd6ccf62211fd35a.diff
LOG: [MLIR] Fix/check for aliases for escaping memrefs in affine fusion
Check for aliases for escaping memrefs check in affine fusion pass. Fix
`isEscapingMemRef` to handle unknown defining ops for the memref.
Reviewed By: dcaballe
Differential Revision: https://reviews.llvm.org/D139268
Added:
Modified:
mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp
mlir/test/Transforms/loop-fusion-3.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp b/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp
index df6b30ee91f92..e30079b6e3745 100644
--- a/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp
+++ b/mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp
@@ -711,17 +711,28 @@ gatherProducerConsumerMemrefs(unsigned srcId, unsigned dstId,
}
/// A memref escapes the function if either:
-/// 1. it is a function argument, or
-/// 2. it is used by a non-affine op (e.g., std load/store, std
-/// call, etc.)
-/// FIXME: Support alias creating ops like memref view ops.
+/// 1. it (or its alias) is a block argument, or
+/// 2. created by an op not known to guarantee alias freedom,
+/// 3. it (or its alias) is used by a non-affine op (e.g., call op, memref
+/// load/store ops, alias creating ops, unknown ops, etc.); such ops
+/// do not deference the memref in an affine way.
static bool isEscapingMemref(Value memref) {
- // Check if 'memref' escapes because it's a block argument.
- if (memref.isa<BlockArgument>())
+ Operation *defOp = memref.getDefiningOp();
+ // Check if 'memref' is a block argument.
+ if (!defOp)
return true;
- // Check if 'memref' escapes through a non-affine op (e.g., std load/store,
- // call op, etc.). This already covers aliases created from this.
+ // Check if this is defined to be an alias of another memref.
+ if (auto viewOp = dyn_cast<mlir::ViewLikeOpInterface>(defOp))
+ if (isEscapingMemref(viewOp.getViewSource()))
+ return true;
+
+ // Any op besides allocating ops wouldn't guarantee alias freedom
+ if (!hasSingleEffect<mlir::MemoryEffects::Allocate>(defOp, memref))
+ return true;
+
+ // Check if 'memref' is used by a non-deferencing op (including unknown ones)
+ // (e.g., call ops, alias creating ops, etc.).
for (Operation *user : memref.getUsers())
if (!isa<AffineMapAccessInterface>(*user))
return true;
@@ -729,7 +740,7 @@ static bool isEscapingMemref(Value memref) {
}
/// Returns in 'escapingMemRefs' the memrefs from affine store ops in node 'id'
-/// that escape the function.
+/// that escape the function or are accessed by non-affine ops.
void gatherEscapingMemrefs(unsigned id, MemRefDependenceGraph *mdg,
DenseSet<Value> &escapingMemRefs) {
auto *node = mdg->getNode(id);
diff --git a/mlir/test/Transforms/loop-fusion-3.mlir b/mlir/test/Transforms/loop-fusion-3.mlir
index 2628c19609634..54457a17a2a5e 100644
--- a/mlir/test/Transforms/loop-fusion-3.mlir
+++ b/mlir/test/Transforms/loop-fusion-3.mlir
@@ -1076,4 +1076,52 @@ func.func @fuse_large_number_of_loops(%arg0: memref<20x10xf32, 1>, %arg1: memref
// CHECK: affine.for
// CHECK-NOT: affine.for
+// CHECK-LABEL: func @alias_escaping_memref
+func.func @alias_escaping_memref(%a : memref<2x5xf32>) {
+ %cst = arith.constant 0.000000e+00 : f32
+ %alias = memref.reinterpret_cast %a to offset: [0], sizes: [10], strides: [1] : memref<2x5xf32> to memref<10xf32>
+ affine.for %i0 = 0 to 10 {
+ affine.store %cst, %alias[%i0] : memref<10xf32>
+ }
+
+ affine.for %i1 = 0 to 10 {
+ %0 = affine.load %alias[%i1] : memref<10xf32>
+ }
+ // Fusion happens, but memref isn't privatized since %alias is an alias of a
+ // function argument.
+ // CHECK: memref.reinterpret_cast
+ // CHECK-NEXT: affine.for
+ // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>
+ // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>
+ // CHECK-NEXT: }
+ // CHECK-NOT: affine.for
+
+ return
+}
+
+// CHECK-LABEL: func @unknown_memref_def_op
+func.func @unknown_memref_def_op() {
+ %cst = arith.constant 0.000000e+00 : f32
+ %may_alias = call @bar() : () -> memref<10xf32>
+ affine.for %i0 = 0 to 10 {
+ affine.store %cst, %may_alias[%i0] : memref<10xf32>
+ }
+
+ affine.for %i1 = 0 to 10 {
+ %0 = affine.load %may_alias[%i1] : memref<10xf32>
+ }
+ // Fusion happens, but memref isn't privatized since %may_alias's origin is
+ // unknown.
+ // CHECK: call
+ // CHECK-NEXT: affine.for
+ // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>
+ // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>
+ // CHECK-NEXT: }
+ // CHECK-NOT: affine.for
+
+ return
+}
+func.func private @bar() -> memref<10xf32>
+
+
// Add further tests in mlir/test/Transforms/loop-fusion-4.mlir
More information about the Mlir-commits
mailing list