1// RUN: %libomptarget-compile-generic -fopenmp-extensions
2// RUN: %libomptarget-run-generic | %fcheck-generic -strict-whitespace
3
4#include <omp.h>
5#include <stdio.h>
6
7#pragma omp begin declare target
8#define MAX_NAME_SIZE 100
9char N1[MAX_NAME_SIZE], N2[MAX_NAME_SIZE];
10int V1, V2;
11void copy_name(char *dst, char *src) {
12 int i;
13 for (i = 0; i < MAX_NAME_SIZE - 1 && src[i]; ++i)
14 dst[i] = src[i];
15 dst[i] = 0;
16}
17#pragma omp end declare target
18
19#define CHECK_PRESENCE(Var1, Var2, Var3) \
20 printf(" presence of %s, %s, %s: %d, %d, %d\n", #Var1, #Var2, #Var3, \
21 omp_target_is_present(&(Var1), omp_get_default_device()), \
22 omp_target_is_present(&(Var2), omp_get_default_device()), \
23 omp_target_is_present(&(Var3), omp_get_default_device()))
24
25#define CHECK_VALUES_HELPER(N1, N2, Var1, Var2) \
26 printf(" values of %s, %s: %d, %d\n", N1, N2, (Var1), (Var2))
27
28#define CHECK_VALUES_DELAYED(Var1, Var2) \
29 copy_name(N1, #Var1); \
30 copy_name(N2, #Var2); \
31 V1 = (Var1); \
32 V2 = (Var2);
33
34#define CHECK_DELAYED_VALUES() \
35 _Pragma("omp target update from(N1, N2, V1, V2)") \
36 CHECK_VALUES_HELPER(N1, N2, V1, V2)
37
38#define CHECK_VALUES(Var1, Var2) \
39 CHECK_VALUES_HELPER(#Var1, #Var2, (Var1), (Var2))
40
41int main() {
42 struct S {
43 int i;
44 int j;
45 } s;
46 // CHECK: presence of s, s.i, s.j: 0, 0, 0
47 CHECK_PRESENCE(s, s.i, s.j);
48
49 // =======================================================================
50 // Check that ompx_hold keeps entire struct present.
51
52 // -----------------------------------------------------------------------
53 // CHECK-LABEL: check:{{.*}}
54 printf(format: "check: ompx_hold only on first member\n");
55 s.i = 20;
56 s.j = 30;
57#pragma omp target data map(tofrom : s) map(ompx_hold, tofrom : s.i) \
58 map(tofrom : s.j)
59 {
60 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
61 CHECK_PRESENCE(s, s.i, s.j);
62#pragma omp target map(tofrom : s)
63 {
64 s.i = 21;
65 s.j = 31;
66 }
67#pragma omp target exit data map(delete : s, s.i)
68 // ompx_hold on s.i applies to all of s.
69 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
70 // CHECK-NEXT: values of s.i, s.j: 20, 30
71 CHECK_PRESENCE(s, s.i, s.j);
72 CHECK_VALUES(s.i, s.j);
73 }
74 // CHECK-NEXT: presence of s, s.i, s.j: 0, 0, 0
75 // CHECK-NEXT: values of s.i, s.j: 21, 31
76 CHECK_PRESENCE(s, s.i, s.j);
77 CHECK_VALUES(s.i, s.j);
78
79 // -----------------------------------------------------------------------
80 // CHECK-LABEL: check:{{.*}}
81 printf(format: "check: ompx_hold only on last member\n");
82 s.i = 20;
83 s.j = 30;
84#pragma omp target data map(tofrom : s) map(tofrom : s.i) \
85 map(ompx_hold, tofrom : s.j)
86 {
87 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
88 CHECK_PRESENCE(s, s.i, s.j);
89#pragma omp target map(tofrom : s)
90 {
91 s.i = 21;
92 s.j = 31;
93 }
94#pragma omp target exit data map(delete : s, s.i)
95 // ompx_hold on s.j applies to all of s.
96 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
97 // CHECK-NEXT: values of s.i, s.j: 20, 30
98 CHECK_PRESENCE(s, s.i, s.j);
99 CHECK_VALUES(s.i, s.j);
100 }
101 // CHECK-NEXT: presence of s, s.i, s.j: 0, 0, 0
102 // CHECK-NEXT: values of s.i, s.j: 21, 31
103 CHECK_PRESENCE(s, s.i, s.j);
104 CHECK_VALUES(s.i, s.j);
105
106 // -----------------------------------------------------------------------
107 // CHECK-LABEL: check:{{.*}}
108 printf(format: "check: ompx_hold only on struct\n");
109 s.i = 20;
110 s.j = 30;
111#pragma omp target data map(ompx_hold, tofrom : s) map(tofrom : s.i) \
112 map(tofrom : s.j)
113 {
114 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
115 CHECK_PRESENCE(s, s.i, s.j);
116#pragma omp target map(tofrom : s)
117 {
118 s.i = 21;
119 s.j = 31;
120 }
121#pragma omp target exit data map(delete : s, s.i)
122 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
123 // CHECK-NEXT: values of s.i, s.j: 20, 30
124 CHECK_PRESENCE(s, s.i, s.j);
125 CHECK_VALUES(s.i, s.j);
126 }
127 // CHECK-NEXT: presence of s, s.i, s.j: 0, 0, 0
128 // CHECK-NEXT: values of s.i, s.j: 21, 31
129 CHECK_PRESENCE(s, s.i, s.j);
130 CHECK_VALUES(s.i, s.j);
131
132 // =======================================================================
133 // Check that transfer to/from host checks reference count correctly.
134
135 // -----------------------------------------------------------------------
136 // CHECK-LABEL: check:{{.*}}
137 printf(format: "check: parent DynRefCount=1 is not sufficient for transfer\n");
138 s.i = 20;
139 s.j = 30;
140#pragma omp target data map(ompx_hold, tofrom : s)
141#pragma omp target data map(ompx_hold, tofrom : s)
142 {
143 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
144 CHECK_PRESENCE(s, s.i, s.j);
145#pragma omp target map(from : s.i, s.j)
146 {
147 s.i = 21;
148 s.j = 31;
149 } // No transfer here even though parent's DynRefCount=1.
150 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
151 // CHECK-NEXT: values of s.i, s.j: 20, 30
152 CHECK_PRESENCE(s, s.i, s.j);
153 CHECK_VALUES(s.i, s.j);
154#pragma omp target map(to : s.i, s.j)
155 { // No transfer here even though parent's DynRefCount=1.
156 // CHECK-NEXT: values of s.i, s.j: 21, 31
157 CHECK_VALUES_DELAYED(s.i, s.j);
158 }
159 CHECK_DELAYED_VALUES();
160 }
161 // CHECK-NEXT: presence of s, s.i, s.j: 0, 0, 0
162 // CHECK-NEXT: values of s.i, s.j: 21, 31
163 CHECK_PRESENCE(s, s.i, s.j);
164 CHECK_VALUES(s.i, s.j);
165
166 // -----------------------------------------------------------------------
167 // CHECK-LABEL: check:{{.*}}
168 printf(format: "check: parent HoldRefCount=1 is not sufficient for transfer\n");
169 s.i = 20;
170 s.j = 30;
171#pragma omp target data map(tofrom : s)
172#pragma omp target data map(tofrom : s)
173 {
174 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
175 CHECK_PRESENCE(s, s.i, s.j);
176#pragma omp target map(ompx_hold, from : s.i, s.j)
177 {
178 s.i = 21;
179 s.j = 31;
180 } // No transfer here even though parent's HoldRefCount=1.
181 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
182 // CHECK-NEXT: values of s.i, s.j: 20, 30
183 CHECK_PRESENCE(s, s.i, s.j);
184 CHECK_VALUES(s.i, s.j);
185#pragma omp target map(ompx_hold, to : s.i, s.j)
186 { // No transfer here even though parent's HoldRefCount=1.
187 // CHECK-NEXT: values of s.i, s.j: 21, 31
188 CHECK_VALUES_DELAYED(s.i, s.j);
189 }
190 CHECK_DELAYED_VALUES();
191 }
192 // CHECK-NEXT: presence of s, s.i, s.j: 0, 0, 0
193 // CHECK-NEXT: values of s.i, s.j: 21, 31
194 CHECK_PRESENCE(s, s.i, s.j);
195 CHECK_VALUES(s.i, s.j);
196
197 // -----------------------------------------------------------------------
198 // CHECK-LABEL: check:{{.*}}
199 //
200 // At the beginning of a region, if the parent's TotalRefCount=1, then the
201 // transfer should happen.
202 //
203 // At the end of a region, it also must be true that the reference count being
204 // decremented is the reference count that is 1.
205 printf(format: "check: parent TotalRefCount=1 is not sufficient for transfer\n");
206 s.i = 20;
207 s.j = 30;
208#pragma omp target data map(ompx_hold, tofrom : s)
209 {
210 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
211 CHECK_PRESENCE(s, s.i, s.j);
212#pragma omp target map(ompx_hold, tofrom : s.i, s.j)
213 {
214 s.i = 21;
215 s.j = 31;
216 }
217#pragma omp target exit data map(from : s.i, s.j)
218 // No transfer here even though parent's TotalRefCount=1.
219 // CHECK-NEXT: presence of s, s.i, s.j: 1, 1, 1
220 // CHECK-NEXT: values of s.i, s.j: 20, 30
221 CHECK_PRESENCE(s, s.i, s.j);
222 CHECK_VALUES(s.i, s.j);
223 }
224 // CHECK-NEXT: presence of s, s.i, s.j: 0, 0, 0
225 // CHECK-NEXT: values of s.i, s.j: 21, 31
226 CHECK_PRESENCE(s, s.i, s.j);
227 CHECK_VALUES(s.i, s.j);
228
229 return 0;
230}
231

source code of offload/test/mapping/ompx_hold/struct.c