Skip to content

Commit 47b4c6a

Browse files
authored
[acc][test] add tests for RegionBranchOpInterface for acc regions (#172073)
use last modified analysis to test if RegionBranchOpInterface is correct on acc regions
1 parent cf4be78 commit 47b4c6a

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// RUN: mlir-opt -test-last-modified %s 2>&1 | FileCheck %s
2+
3+
// Test that RegionBranchOpInterface implementations for OpenACC single-region
4+
// ops behave reasonably under LastModifiedAnalysis.
5+
//
6+
// For acc.parallel / acc.serial, which only have value-based memory effects
7+
// coming from their bodies, the analysis can track the last writer precisely.
8+
// For other OpenACC region ops (e.g. acc.kernels, acc.data, acc.host_data),
9+
// which currently only report resource-only memory effects at the op level,
10+
// LastModifiedAnalysis cannot attribute a precise last writer and falls back
11+
// to "<unknown>" after the op for values not directly touched in the region.
12+
13+
14+
// CHECK-LABEL: test_tag: acc_parallel_after:
15+
// CHECK: operand #0
16+
// CHECK-NEXT: - parallel_region
17+
// CHECK-LABEL: test_tag: acc_parallel_return:
18+
// CHECK: operand #0
19+
// CHECK-NEXT: - parallel_region
20+
func.func @last_mod_openacc_parallel(%arg0: memref<f32>) -> memref<f32> {
21+
%one = arith.constant 1.0 : f32
22+
23+
// The only store to %arg0 happens inside the acc.parallel region.
24+
acc.parallel {
25+
memref.store %one, %arg0[] {tag_name = "parallel_region"} : memref<f32>
26+
acc.yield
27+
}
28+
29+
// With RegionBranchOpInterface wired up, the last modification at this load
30+
// is the store inside the acc.parallel region.
31+
memref.load %arg0[] {tag = "acc_parallel_after"} : memref<f32>
32+
33+
// And the same store should be seen at the function return.
34+
return {tag = "acc_parallel_return"} %arg0 : memref<f32>
35+
}
36+
37+
// -----
38+
39+
// CHECK-LABEL: test_tag: acc_serial_after:
40+
// CHECK: operand #0
41+
// CHECK-NEXT: - serial_region
42+
// CHECK-LABEL: test_tag: acc_serial_return:
43+
// CHECK: operand #0
44+
// CHECK-NEXT: - serial_region
45+
func.func @last_mod_openacc_serial(%arg0: memref<f32>) -> memref<f32> {
46+
%one = arith.constant 1.0 : f32
47+
48+
// The only store to %arg0 happens inside the acc.serial region.
49+
acc.serial {
50+
memref.store %one, %arg0[] {tag_name = "serial_region"} : memref<f32>
51+
acc.yield
52+
}
53+
54+
memref.load %arg0[] {tag = "acc_serial_after"} : memref<f32>
55+
56+
return {tag = "acc_serial_return"} %arg0 : memref<f32>
57+
}
58+
59+
// -----
60+
61+
// CHECK-LABEL: test_tag: acc_kernels_before:
62+
// CHECK: operand #0
63+
// CHECK-NEXT: - pre
64+
// CHECK-LABEL: test_tag: acc_kernels_after:
65+
// CHECK: operand #0
66+
// CHECK-NEXT: - <unknown>
67+
func.func @last_mod_openacc_kernels(%arg0: memref<f32>) -> memref<f32> {
68+
%zero = arith.constant 0.0 : f32
69+
70+
// Single store before the region.
71+
memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
72+
memref.load %arg0[] {tag = "acc_kernels_before"} : memref<f32>
73+
74+
// The acc.kernels region does not touch %arg0.
75+
acc.kernels {
76+
"test.openacc_dummy_op"() : () -> ()
77+
acc.terminator
78+
}
79+
80+
// After acc.kernels, LastModifiedAnalysis cannot prove that "pre" still
81+
// dominates all paths and therefore reports the last modifier conservatively
82+
// as "<unknown>" for this load.
83+
memref.load %arg0[] {tag = "acc_kernels_after"} : memref<f32>
84+
return %arg0 : memref<f32>
85+
}
86+
87+
// -----
88+
89+
// CHECK-LABEL: test_tag: acc_data_before:
90+
// CHECK: operand #0
91+
// CHECK-NEXT: - pre
92+
// CHECK-LABEL: test_tag: acc_data_after:
93+
// CHECK: operand #0
94+
// CHECK-NEXT: - <unknown>
95+
func.func @last_mod_openacc_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
96+
%zero = arith.constant 0.0 : f32
97+
98+
// Single store to %arg0 before the region.
99+
memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
100+
memref.load %arg0[] {tag = "acc_data_before"} : memref<f32>
101+
102+
// Map an unrelated buffer into device memory and run an acc.data region that
103+
// does not touch %arg0.
104+
%create = acc.create varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
105+
acc.data dataOperands(%create : memref<f32>) {
106+
"test.openacc_dummy_op"() : () -> ()
107+
acc.terminator
108+
}
109+
110+
// After acc.data, LastModifiedAnalysis cannot prove that "pre" still
111+
// dominates all paths for %arg0 and reports "<unknown>" for this load.
112+
memref.load %arg0[] {tag = "acc_data_after"} : memref<f32>
113+
return %arg0 : memref<f32>
114+
}
115+
116+
// -----
117+
118+
// CHECK-LABEL: test_tag: acc_host_before:
119+
// CHECK: operand #0
120+
// CHECK-NEXT: - pre
121+
// CHECK-LABEL: test_tag: acc_host_after:
122+
// CHECK: operand #0
123+
// CHECK-NEXT: - <unknown>
124+
func.func @last_mod_openacc_host_data(%arg0: memref<f32>, %mapped: memref<f32>) -> memref<f32> {
125+
%zero = arith.constant 0.0 : f32
126+
127+
// Single store to %arg0 before the region.
128+
memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
129+
memref.load %arg0[] {tag = "acc_host_before"} : memref<f32>
130+
131+
// Map %mapped into device memory and run an acc.host_data region that does
132+
// not touch %arg0.
133+
%devptr = acc.use_device varPtr(%mapped : memref<f32>) varType(tensor<f32>) -> memref<f32>
134+
acc.host_data dataOperands(%devptr : memref<f32>) {
135+
"test.openacc_dummy_op"() : () -> ()
136+
acc.terminator
137+
}
138+
139+
// After acc.host_data, the analysis cannot prove "pre" still dominates and
140+
// reports "<unknown>" for the last writer on %arg0.
141+
memref.load %arg0[] {tag = "acc_host_after"} : memref<f32>
142+
return %arg0 : memref<f32>
143+
}
144+
145+

0 commit comments

Comments
 (0)