[flang-commits] [flang] [mlir] [flang][acc] Register fir::ConvertOp with OutlineRematerializationOpInterface (PR #184218)
via flang-commits
flang-commits at lists.llvm.org
Mon Mar 2 12:53:25 PST 2026
https://github.com/khaki3 updated https://github.com/llvm/llvm-project/pull/184218
>From 16395d600c3b5c89f2d0ca9839422e3d8930b005 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 2 Mar 2026 12:16:48 -0800
Subject: [PATCH 1/4] [acc] Rematerialize view-like ops with
OutlineRematerializationOpInterface
Check OutlineRematerializationOpInterface on the direct defining op
before tracing through ViewLikeOpInterface in
OffloadLiveInValueCanonicalization. An op may implement both interfaces
(e.g. fir.convert), and tracing first would reach a block argument,
missing the rematerialization.
Also register fir::ConvertOp with OutlineRematerializationOpInterface
so that CSE merging fir.convert across ACC region boundaries does not
prevent ACCImplicitData from mapping the original pointer.
Made-with: Cursor
---
.../Support/RegisterOpenACCExtensions.cpp | 2 +
.../offload-livein-value-canonicalization.fir | 42 +++++++++++++++++++
.../OffloadLiveInValueCanonicalization.cpp | 11 +++++
3 files changed, 55 insertions(+)
diff --git a/flang/lib/Optimizer/OpenACC/Support/RegisterOpenACCExtensions.cpp b/flang/lib/Optimizer/OpenACC/Support/RegisterOpenACCExtensions.cpp
index c0be247a47729..ed0b5707a0b90 100644
--- a/flang/lib/Optimizer/OpenACC/Support/RegisterOpenACCExtensions.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/RegisterOpenACCExtensions.cpp
@@ -77,6 +77,8 @@ void registerOpenACCExtensions(mlir::DialectRegistry ®istry) {
*ctx);
fir::FieldIndexOp::attachInterface<
OutlineRematerializationModel<fir::FieldIndexOp>>(*ctx);
+ fir::ConvertOp::attachInterface<
+ OutlineRematerializationModel<fir::ConvertOp>>(*ctx);
});
// Register HLFIR operation interfaces
diff --git a/flang/test/Fir/OpenACC/offload-livein-value-canonicalization.fir b/flang/test/Fir/OpenACC/offload-livein-value-canonicalization.fir
index 6ecccde39d3fb..d9313a1f933bd 100644
--- a/flang/test/Fir/OpenACC/offload-livein-value-canonicalization.fir
+++ b/flang/test/Fir/OpenACC/offload-livein-value-canonicalization.fir
@@ -253,3 +253,45 @@ func.func @test_accbounds_rematerialize_fir() {
// CHECK: acc.bounds
// CHECK: acc.serial {
// CHECK: acc.bounds
+
+// -----
+
+// Test fir.convert rematerialization (ViewLikeOpInterface +
+// OutlineRematerializationOpInterface).
+func.func private @use_i64(i64) -> ()
+
+func.func @test_convert_rematerialize(%arg0: !fir.ref<i32>) {
+ %0 = fir.convert %arg0 : (!fir.ref<i32>) -> i64
+ fir.call @use_i64(%0) : (i64) -> ()
+ acc.parallel {
+ fir.call @use_i64(%0) : (i64) -> ()
+ acc.yield
+ }
+ return
+}
+
+// CHECK-LABEL: @test_convert_rematerialize
+// CHECK: %[[CVT_OUTER:.*]] = fir.convert
+// CHECK: fir.call @use_i64(%[[CVT_OUTER]])
+// CHECK: acc.parallel {
+// CHECK: %[[CVT_INNER:.*]] = fir.convert
+// CHECK: fir.call @use_i64(%[[CVT_INNER]])
+
+// -----
+
+// Test fir.convert sinking (only used inside region).
+func.func private @use_i64(i64) -> ()
+
+func.func @test_convert_sink(%arg0: !fir.ref<i32>) {
+ %0 = fir.convert %arg0 : (!fir.ref<i32>) -> i64
+ acc.parallel {
+ fir.call @use_i64(%0) : (i64) -> ()
+ acc.yield
+ }
+ return
+}
+
+// CHECK-LABEL: @test_convert_sink
+// CHECK: acc.parallel {
+// CHECK: %[[CVT:.*]] = fir.convert
+// CHECK: fir.call @use_i64(%[[CVT]])
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
index ea7ee715189e3..851096b755f80 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
@@ -132,6 +132,17 @@ static Value getOriginalValue(Value val) {
/// to find the original defining operation before making the determination.
static bool isRematerializationCandidate(Value val,
acc::OpenACCSupport &accSupport) {
+ // Check before tracing through view-like ops: an op may implement both
+ // ViewLikeOpInterface and OutlineRematerializationOpInterface.
+ if (Operation *directDefOp = val.getDefiningOp()) {
+ if (isa<acc::OutlineRematerializationOpInterface>(directDefOp)) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "\tDirect OutlineRematerializationOpInterface: "
+ << *directDefOp << "\n");
+ return true;
+ }
+ }
+
// Trace through view-like operations to find the original value.
Value origVal = getOriginalValue(val);
Operation *definingOp = origVal.getDefiningOp();
>From d12233255c907548f755901729a68e6a06d45a78 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 2 Mar 2026 12:27:49 -0800
Subject: [PATCH 2/4] Remove redundant OutlineRematerializationOpInterface
check
Made-with: Cursor
---
.../Transforms/OffloadLiveInValueCanonicalization.cpp | 6 ------
1 file changed, 6 deletions(-)
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
index 851096b755f80..426f63f7508b3 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
@@ -157,12 +157,6 @@ static bool isRematerializationCandidate(Value val,
return true;
}
- // Operations implementing OutlineRematerializationOpInterface are candidates.
- if (isa<acc::OutlineRematerializationOpInterface>(definingOp)) {
- LLVM_DEBUG(llvm::dbgs() << "\t\t-> OutlineRematerializationOpInterface\n");
- return true;
- }
-
// Address-of operations referencing globals that are valid in GPU regions
// or referencing constant globals should be rematerialized.
if (auto addrOfOp = dyn_cast<acc::AddressOfGlobalOpInterface>(definingOp)) {
>From eb84ba06b51676bf6b4800cd88b6f8cddde1ea86 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 2 Mar 2026 12:52:19 -0800
Subject: [PATCH 3/4] Fallback to direct defining op when traced original is a
block argument
Made-with: Cursor
---
.../OffloadLiveInValueCanonicalization.cpp | 23 ++++++++++---------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
index 426f63f7508b3..4fc7a49b04950 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
@@ -111,6 +111,10 @@ static Value getOriginalValue(Value val) {
Value prev;
while (val && val != prev) {
prev = val;
+ // Stop tracing if the op is a rematerialization candidate itself.
+ if (isa_and_nonnull<acc::OutlineRematerializationOpInterface>(
+ val.getDefiningOp()))
+ break;
if (auto viewLikeOp = val.getDefiningOp<ViewLikeOpInterface>())
val = viewLikeOp.getViewSource();
if (auto partialAccess =
@@ -132,20 +136,11 @@ static Value getOriginalValue(Value val) {
/// to find the original defining operation before making the determination.
static bool isRematerializationCandidate(Value val,
acc::OpenACCSupport &accSupport) {
- // Check before tracing through view-like ops: an op may implement both
- // ViewLikeOpInterface and OutlineRematerializationOpInterface.
- if (Operation *directDefOp = val.getDefiningOp()) {
- if (isa<acc::OutlineRematerializationOpInterface>(directDefOp)) {
- LLVM_DEBUG(llvm::dbgs()
- << "\tDirect OutlineRematerializationOpInterface: "
- << *directDefOp << "\n");
- return true;
- }
- }
-
// Trace through view-like operations to find the original value.
Value origVal = getOriginalValue(val);
Operation *definingOp = origVal.getDefiningOp();
+ if (!definingOp)
+ definingOp = val.getDefiningOp();
if (!definingOp)
return false;
@@ -157,6 +152,12 @@ static bool isRematerializationCandidate(Value val,
return true;
}
+ // Operations implementing OutlineRematerializationOpInterface are candidates.
+ if (isa<acc::OutlineRematerializationOpInterface>(definingOp)) {
+ LLVM_DEBUG(llvm::dbgs() << "\t\t-> OutlineRematerializationOpInterface\n");
+ return true;
+ }
+
// Address-of operations referencing globals that are valid in GPU regions
// or referencing constant globals should be rematerialized.
if (auto addrOfOp = dyn_cast<acc::AddressOfGlobalOpInterface>(definingOp)) {
>From 8410c4ecdbd7771fa97107c6e3339211aca84ea8 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 2 Mar 2026 12:53:09 -0800
Subject: [PATCH 4/4] Remove unnecessary getOriginalValue break
Made-with: Cursor
---
.../OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp | 4 ----
1 file changed, 4 deletions(-)
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
index 4fc7a49b04950..b1f3191bdb68b 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/OffloadLiveInValueCanonicalization.cpp
@@ -111,10 +111,6 @@ static Value getOriginalValue(Value val) {
Value prev;
while (val && val != prev) {
prev = val;
- // Stop tracing if the op is a rematerialization candidate itself.
- if (isa_and_nonnull<acc::OutlineRematerializationOpInterface>(
- val.getDefiningOp()))
- break;
if (auto viewLikeOp = val.getDefiningOp<ViewLikeOpInterface>())
val = viewLikeOp.getViewSource();
if (auto partialAccess =
More information about the flang-commits
mailing list