-
Notifications
You must be signed in to change notification settings - Fork 15.6k
[acc][test] add tests for RegionBranchOpInterface for acc regions #172073
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
Conversation
|
@llvm/pr-subscribers-mlir-openacc Author: Susan Tan (ス-ザン タン) (SusanTan) Changesuse last modified analysis to test if RegionBranchOpInterface is correct on acc regions Full diff: https://github.com/llvm/llvm-project/pull/172073.diff 1 Files Affected:
diff --git a/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
new file mode 100644
index 00000000000000..a97fdb7d78ad15
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
@@ -0,0 +1,145 @@
+// RUN: mlir-opt -test-last-modified %s 2>&1 | FileCheck %s
+
+// Test that RegionBranchOpInterface implementations for OpenACC single-region
+// ops behave reasonably under LastModifiedAnalysis.
+//
+// For acc.parallel / acc.serial, which only have value-based memory effects
+// coming from their bodies, the analysis can track the last writer precisely.
+// For other OpenACC region ops (e.g. acc.kernels, acc.data, acc.host_data),
+// which currently only report resource-only memory effects at the op level,
+// LastModifiedAnalysis cannot attribute a precise last writer and falls back
+// to "<unknown>" after the op for values not directly touched in the region.
+
+
+// CHECK-LABEL: test_tag: acc_parallel_after:
+// CHECK: operand #0
+// CHECK-NEXT: - parallel_region
+// CHECK-LABEL: test_tag: acc_parallel_return:
+// CHECK: operand #0
+// CHECK-NEXT: - parallel_region
+func.func @last_mod_openacc_parallel(%arg0: memref<f32>) -> memref<f32> {
+ %one = arith.constant 1.0 : f32
+
+ // The only store to %arg0 happens inside the acc.parallel region.
+ acc.parallel {
+ memref.store %one, %arg0[] {tag_name = "parallel_region"} : memref<f32>
+ acc.yield
+ }
+
+ // With RegionBranchOpInterface wired up, the last modification at this load
+ // is the store inside the acc.parallel region.
+ memref.load %arg0[] {tag = "acc_parallel_after"} : memref<f32>
+
+ // And the same store should be seen at the function return.
+ return {tag = "acc_parallel_return"} %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_serial_after:
+// CHECK: operand #0
+// CHECK-NEXT: - serial_region
+// CHECK-LABEL: test_tag: acc_serial_return:
+// CHECK: operand #0
+// CHECK-NEXT: - serial_region
+func.func @last_mod_openacc_serial(%arg0: memref<f32>) -> memref<f32> {
+ %one = arith.constant 1.0 : f32
+
+ // The only store to %arg0 happens inside the acc.serial region.
+ acc.serial {
+ memref.store %one, %arg0[] {tag_name = "serial_region"} : memref<f32>
+ acc.yield
+ }
+
+ memref.load %arg0[] {tag = "acc_serial_after"} : memref<f32>
+
+ return {tag = "acc_serial_return"} %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_kernels_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_kernels_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_kernels(%arg0: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_kernels_before"} : memref<f32>
+
+ // The acc.kernels region does not touch %arg0.
+ acc.kernels {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.kernels, LastModifiedAnalysis cannot prove that "pre" still
+ // dominates all paths and therefore reports the last modifier conservatively
+ // as "<unknown>" for this load.
+ memref.load %arg0[] {tag = "acc_kernels_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_data_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_data_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store to %arg0 before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_data_before"} : memref<f32>
+
+ // Map an unrelated buffer into device memory and run an acc.data region that
+ // does not touch %arg0.
+ %create = acc.create varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
+ acc.data dataOperands(%create : memref<f32>) {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.data, LastModifiedAnalysis cannot prove that "pre" still
+ // dominates all paths for %arg0 and reports "<unknown>" for this load.
+ memref.load %arg0[] {tag = "acc_data_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_host_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_host_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_host_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store to %arg0 before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_host_before"} : memref<f32>
+
+ // Map %mapped into device memory and run an acc.host_data region that does
+ // not touch %arg0.
+ %devptr = acc.use_device varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
+ acc.host_data dataOperands(%devptr : memref<f32>) {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.host_data, the analysis cannot prove "pre" still dominates and
+ // reports "<unknown>" for the last writer on %arg0.
+ memref.load %arg0[] {tag = "acc_host_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+
|
|
@llvm/pr-subscribers-openacc Author: Susan Tan (ス-ザン タン) (SusanTan) Changesuse last modified analysis to test if RegionBranchOpInterface is correct on acc regions Full diff: https://github.com/llvm/llvm-project/pull/172073.diff 1 Files Affected:
diff --git a/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
new file mode 100644
index 0000000000000..a97fdb7d78ad1
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
@@ -0,0 +1,145 @@
+// RUN: mlir-opt -test-last-modified %s 2>&1 | FileCheck %s
+
+// Test that RegionBranchOpInterface implementations for OpenACC single-region
+// ops behave reasonably under LastModifiedAnalysis.
+//
+// For acc.parallel / acc.serial, which only have value-based memory effects
+// coming from their bodies, the analysis can track the last writer precisely.
+// For other OpenACC region ops (e.g. acc.kernels, acc.data, acc.host_data),
+// which currently only report resource-only memory effects at the op level,
+// LastModifiedAnalysis cannot attribute a precise last writer and falls back
+// to "<unknown>" after the op for values not directly touched in the region.
+
+
+// CHECK-LABEL: test_tag: acc_parallel_after:
+// CHECK: operand #0
+// CHECK-NEXT: - parallel_region
+// CHECK-LABEL: test_tag: acc_parallel_return:
+// CHECK: operand #0
+// CHECK-NEXT: - parallel_region
+func.func @last_mod_openacc_parallel(%arg0: memref<f32>) -> memref<f32> {
+ %one = arith.constant 1.0 : f32
+
+ // The only store to %arg0 happens inside the acc.parallel region.
+ acc.parallel {
+ memref.store %one, %arg0[] {tag_name = "parallel_region"} : memref<f32>
+ acc.yield
+ }
+
+ // With RegionBranchOpInterface wired up, the last modification at this load
+ // is the store inside the acc.parallel region.
+ memref.load %arg0[] {tag = "acc_parallel_after"} : memref<f32>
+
+ // And the same store should be seen at the function return.
+ return {tag = "acc_parallel_return"} %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_serial_after:
+// CHECK: operand #0
+// CHECK-NEXT: - serial_region
+// CHECK-LABEL: test_tag: acc_serial_return:
+// CHECK: operand #0
+// CHECK-NEXT: - serial_region
+func.func @last_mod_openacc_serial(%arg0: memref<f32>) -> memref<f32> {
+ %one = arith.constant 1.0 : f32
+
+ // The only store to %arg0 happens inside the acc.serial region.
+ acc.serial {
+ memref.store %one, %arg0[] {tag_name = "serial_region"} : memref<f32>
+ acc.yield
+ }
+
+ memref.load %arg0[] {tag = "acc_serial_after"} : memref<f32>
+
+ return {tag = "acc_serial_return"} %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_kernels_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_kernels_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_kernels(%arg0: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_kernels_before"} : memref<f32>
+
+ // The acc.kernels region does not touch %arg0.
+ acc.kernels {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.kernels, LastModifiedAnalysis cannot prove that "pre" still
+ // dominates all paths and therefore reports the last modifier conservatively
+ // as "<unknown>" for this load.
+ memref.load %arg0[] {tag = "acc_kernels_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_data_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_data_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store to %arg0 before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_data_before"} : memref<f32>
+
+ // Map an unrelated buffer into device memory and run an acc.data region that
+ // does not touch %arg0.
+ %create = acc.create varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
+ acc.data dataOperands(%create : memref<f32>) {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.data, LastModifiedAnalysis cannot prove that "pre" still
+ // dominates all paths for %arg0 and reports "<unknown>" for this load.
+ memref.load %arg0[] {tag = "acc_data_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_host_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_host_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_host_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store to %arg0 before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_host_before"} : memref<f32>
+
+ // Map %mapped into device memory and run an acc.host_data region that does
+ // not touch %arg0.
+ %devptr = acc.use_device varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
+ acc.host_data dataOperands(%devptr : memref<f32>) {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.host_data, the analysis cannot prove "pre" still dominates and
+ // reports "<unknown>" for the last writer on %arg0.
+ memref.load %arg0[] {tag = "acc_host_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+
|
|
@llvm/pr-subscribers-mlir Author: Susan Tan (ス-ザン タン) (SusanTan) Changesuse last modified analysis to test if RegionBranchOpInterface is correct on acc regions Full diff: https://github.com/llvm/llvm-project/pull/172073.diff 1 Files Affected:
diff --git a/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
new file mode 100644
index 0000000000000..a97fdb7d78ad1
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
@@ -0,0 +1,145 @@
+// RUN: mlir-opt -test-last-modified %s 2>&1 | FileCheck %s
+
+// Test that RegionBranchOpInterface implementations for OpenACC single-region
+// ops behave reasonably under LastModifiedAnalysis.
+//
+// For acc.parallel / acc.serial, which only have value-based memory effects
+// coming from their bodies, the analysis can track the last writer precisely.
+// For other OpenACC region ops (e.g. acc.kernels, acc.data, acc.host_data),
+// which currently only report resource-only memory effects at the op level,
+// LastModifiedAnalysis cannot attribute a precise last writer and falls back
+// to "<unknown>" after the op for values not directly touched in the region.
+
+
+// CHECK-LABEL: test_tag: acc_parallel_after:
+// CHECK: operand #0
+// CHECK-NEXT: - parallel_region
+// CHECK-LABEL: test_tag: acc_parallel_return:
+// CHECK: operand #0
+// CHECK-NEXT: - parallel_region
+func.func @last_mod_openacc_parallel(%arg0: memref<f32>) -> memref<f32> {
+ %one = arith.constant 1.0 : f32
+
+ // The only store to %arg0 happens inside the acc.parallel region.
+ acc.parallel {
+ memref.store %one, %arg0[] {tag_name = "parallel_region"} : memref<f32>
+ acc.yield
+ }
+
+ // With RegionBranchOpInterface wired up, the last modification at this load
+ // is the store inside the acc.parallel region.
+ memref.load %arg0[] {tag = "acc_parallel_after"} : memref<f32>
+
+ // And the same store should be seen at the function return.
+ return {tag = "acc_parallel_return"} %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_serial_after:
+// CHECK: operand #0
+// CHECK-NEXT: - serial_region
+// CHECK-LABEL: test_tag: acc_serial_return:
+// CHECK: operand #0
+// CHECK-NEXT: - serial_region
+func.func @last_mod_openacc_serial(%arg0: memref<f32>) -> memref<f32> {
+ %one = arith.constant 1.0 : f32
+
+ // The only store to %arg0 happens inside the acc.serial region.
+ acc.serial {
+ memref.store %one, %arg0[] {tag_name = "serial_region"} : memref<f32>
+ acc.yield
+ }
+
+ memref.load %arg0[] {tag = "acc_serial_after"} : memref<f32>
+
+ return {tag = "acc_serial_return"} %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_kernels_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_kernels_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_kernels(%arg0: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_kernels_before"} : memref<f32>
+
+ // The acc.kernels region does not touch %arg0.
+ acc.kernels {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.kernels, LastModifiedAnalysis cannot prove that "pre" still
+ // dominates all paths and therefore reports the last modifier conservatively
+ // as "<unknown>" for this load.
+ memref.load %arg0[] {tag = "acc_kernels_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_data_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_data_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store to %arg0 before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_data_before"} : memref<f32>
+
+ // Map an unrelated buffer into device memory and run an acc.data region that
+ // does not touch %arg0.
+ %create = acc.create varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
+ acc.data dataOperands(%create : memref<f32>) {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.data, LastModifiedAnalysis cannot prove that "pre" still
+ // dominates all paths for %arg0 and reports "<unknown>" for this load.
+ memref.load %arg0[] {tag = "acc_data_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: acc_host_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_host_after:
+// CHECK: operand #0
+// CHECK-NEXT: - <unknown>
+func.func @last_mod_openacc_host_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+
+ // Single store to %arg0 before the region.
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_host_before"} : memref<f32>
+
+ // Map %mapped into device memory and run an acc.host_data region that does
+ // not touch %arg0.
+ %devptr = acc.use_device varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
+ acc.host_data dataOperands(%devptr : memref<f32>) {
+ "test.openacc_dummy_op"() : () -> ()
+ acc.terminator
+ }
+
+ // After acc.host_data, the analysis cannot prove "pre" still dominates and
+ // reports "<unknown>" for the last writer on %arg0.
+ memref.load %arg0[] {tag = "acc_host_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
+
+
|
vzakhari
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you, Susan!
…vm#172073) use last modified analysis to test if RegionBranchOpInterface is correct on acc regions
…vm#172073) use last modified analysis to test if RegionBranchOpInterface is correct on acc regions
…vm#172073) use last modified analysis to test if RegionBranchOpInterface is correct on acc regions
use last modified analysis to test if RegionBranchOpInterface is correct on acc regions