1*610fea65SAndreyChurbanov // RUN: %libomp-compile-and-run
2*610fea65SAndreyChurbanov // RUN: %libomp-cxx-compile-and-run
3*610fea65SAndreyChurbanov // UNSUPPORTED: gcc
4*610fea65SAndreyChurbanov
5*610fea65SAndreyChurbanov // Tests OMP 5.0 task dependences "mutexinoutset" and 5.1 "inoutset",
6*610fea65SAndreyChurbanov // emulates compiler codegen for new dep kinds
7*610fea65SAndreyChurbanov // Mutually exclusive tasks get same input dependency info array
8*610fea65SAndreyChurbanov //
9*610fea65SAndreyChurbanov // Task tree created:
10*610fea65SAndreyChurbanov // task0 - task1 (in)
11*610fea65SAndreyChurbanov // \
12*610fea65SAndreyChurbanov // task2 - task3 (inoutset)
13*610fea65SAndreyChurbanov // /
14*610fea65SAndreyChurbanov // task3 - task4 (in)
15*610fea65SAndreyChurbanov // /
16*610fea65SAndreyChurbanov // task6 <-->task7 (mutexinoutset)
17*610fea65SAndreyChurbanov // \ /
18*610fea65SAndreyChurbanov // task8 (in)
19*610fea65SAndreyChurbanov //
20*610fea65SAndreyChurbanov #include <stdio.h>
21*610fea65SAndreyChurbanov #include <omp.h>
22*610fea65SAndreyChurbanov
23*610fea65SAndreyChurbanov #ifdef _WIN32
24*610fea65SAndreyChurbanov #include <windows.h>
25*610fea65SAndreyChurbanov #define mysleep(n) Sleep(n)
26*610fea65SAndreyChurbanov #else
27*610fea65SAndreyChurbanov #include <unistd.h>
28*610fea65SAndreyChurbanov #define mysleep(n) usleep((n)*1000)
29*610fea65SAndreyChurbanov #endif
30*610fea65SAndreyChurbanov
31*610fea65SAndreyChurbanov // to check the # of concurrent tasks (must be 1 for MTX, <3 for other kinds)
32*610fea65SAndreyChurbanov static int volatile checker = 0;
33*610fea65SAndreyChurbanov static int err = 0;
34*610fea65SAndreyChurbanov #ifndef DELAY
35*610fea65SAndreyChurbanov #define DELAY 100
36*610fea65SAndreyChurbanov #endif
37*610fea65SAndreyChurbanov
38*610fea65SAndreyChurbanov // ---------------------------------------------------------------------------
39*610fea65SAndreyChurbanov // internal data to emulate compiler codegen
40*610fea65SAndreyChurbanov typedef struct DEP {
41*610fea65SAndreyChurbanov size_t addr;
42*610fea65SAndreyChurbanov size_t len;
43*610fea65SAndreyChurbanov unsigned char flags;
44*610fea65SAndreyChurbanov } dep;
45*610fea65SAndreyChurbanov typedef struct task {
46*610fea65SAndreyChurbanov void** shareds;
47*610fea65SAndreyChurbanov void* entry;
48*610fea65SAndreyChurbanov int part_id;
49*610fea65SAndreyChurbanov void* destr_thunk;
50*610fea65SAndreyChurbanov int priority;
51*610fea65SAndreyChurbanov long long device_id;
52*610fea65SAndreyChurbanov int f_priv;
53*610fea65SAndreyChurbanov } task_t;
54*610fea65SAndreyChurbanov #define TIED 1
55*610fea65SAndreyChurbanov typedef int(*entry_t)(int, task_t*);
56*610fea65SAndreyChurbanov typedef struct ID {
57*610fea65SAndreyChurbanov int reserved_1;
58*610fea65SAndreyChurbanov int flags;
59*610fea65SAndreyChurbanov int reserved_2;
60*610fea65SAndreyChurbanov int reserved_3;
61*610fea65SAndreyChurbanov char *psource;
62*610fea65SAndreyChurbanov } id;
63*610fea65SAndreyChurbanov // thunk routine for tasks with MTX dependency
thunk_m(int gtid,task_t * ptask)64*610fea65SAndreyChurbanov int thunk_m(int gtid, task_t* ptask) {
65*610fea65SAndreyChurbanov int th = omp_get_thread_num();
66*610fea65SAndreyChurbanov #pragma omp atomic
67*610fea65SAndreyChurbanov ++checker;
68*610fea65SAndreyChurbanov printf("task _%d, th %d\n", ptask->f_priv, th);
69*610fea65SAndreyChurbanov if (checker != 1) { // no more than 1 task at a time
70*610fea65SAndreyChurbanov err++;
71*610fea65SAndreyChurbanov printf("Error1, checker %d != 1\n", checker);
72*610fea65SAndreyChurbanov }
73*610fea65SAndreyChurbanov mysleep(DELAY);
74*610fea65SAndreyChurbanov if (checker != 1) { // no more than 1 task at a time
75*610fea65SAndreyChurbanov err++;
76*610fea65SAndreyChurbanov printf("Error2, checker %d != 1\n", checker);
77*610fea65SAndreyChurbanov }
78*610fea65SAndreyChurbanov #pragma omp atomic
79*610fea65SAndreyChurbanov --checker;
80*610fea65SAndreyChurbanov return 0;
81*610fea65SAndreyChurbanov }
82*610fea65SAndreyChurbanov // thunk routine for tasks with inoutset dependency
thunk_s(int gtid,task_t * ptask)83*610fea65SAndreyChurbanov int thunk_s(int gtid, task_t* ptask) {
84*610fea65SAndreyChurbanov int th = omp_get_thread_num();
85*610fea65SAndreyChurbanov #pragma omp atomic
86*610fea65SAndreyChurbanov ++checker;
87*610fea65SAndreyChurbanov printf("task _%d, th %d\n", ptask->f_priv, th);
88*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
89*610fea65SAndreyChurbanov err++;
90*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
91*610fea65SAndreyChurbanov }
92*610fea65SAndreyChurbanov mysleep(DELAY);
93*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
94*610fea65SAndreyChurbanov err++;
95*610fea65SAndreyChurbanov printf("Error2, checker %d > 2\n", checker);
96*610fea65SAndreyChurbanov }
97*610fea65SAndreyChurbanov #pragma omp atomic
98*610fea65SAndreyChurbanov --checker;
99*610fea65SAndreyChurbanov return 0;
100*610fea65SAndreyChurbanov }
101*610fea65SAndreyChurbanov
102*610fea65SAndreyChurbanov #ifdef __cplusplus
103*610fea65SAndreyChurbanov extern "C" {
104*610fea65SAndreyChurbanov #endif
105*610fea65SAndreyChurbanov int __kmpc_global_thread_num(id*);
106*610fea65SAndreyChurbanov extern task_t* __kmpc_omp_task_alloc(id *loc, int gtid, int flags,
107*610fea65SAndreyChurbanov size_t sz, size_t shar, entry_t rtn);
108*610fea65SAndreyChurbanov int
109*610fea65SAndreyChurbanov __kmpc_omp_task_with_deps(id *loc, int gtid, task_t *task, int nd, dep *dep_lst,
110*610fea65SAndreyChurbanov int nd_noalias, dep *noalias_dep_lst);
111*610fea65SAndreyChurbanov static id loc = {0, 2, 0, 0, ";file;func;0;0;;"};
112*610fea65SAndreyChurbanov #ifdef __cplusplus
113*610fea65SAndreyChurbanov } // extern "C"
114*610fea65SAndreyChurbanov #endif
115*610fea65SAndreyChurbanov // End of internal data
116*610fea65SAndreyChurbanov // ---------------------------------------------------------------------------
117*610fea65SAndreyChurbanov
main()118*610fea65SAndreyChurbanov int main()
119*610fea65SAndreyChurbanov {
120*610fea65SAndreyChurbanov int i1,i2,i3;
121*610fea65SAndreyChurbanov omp_set_num_threads(4);
122*610fea65SAndreyChurbanov omp_set_dynamic(0);
123*610fea65SAndreyChurbanov #pragma omp parallel
124*610fea65SAndreyChurbanov {
125*610fea65SAndreyChurbanov #pragma omp single nowait
126*610fea65SAndreyChurbanov {
127*610fea65SAndreyChurbanov dep sdep[2];
128*610fea65SAndreyChurbanov task_t *ptr;
129*610fea65SAndreyChurbanov int gtid = __kmpc_global_thread_num(&loc);
130*610fea65SAndreyChurbanov int t = omp_get_thread_num();
131*610fea65SAndreyChurbanov #pragma omp task depend(in: i1, i2)
132*610fea65SAndreyChurbanov { int th = omp_get_thread_num();
133*610fea65SAndreyChurbanov printf("task 0_%d, th %d\n", t, th);
134*610fea65SAndreyChurbanov #pragma omp atomic
135*610fea65SAndreyChurbanov ++checker;
136*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
137*610fea65SAndreyChurbanov err++;
138*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
139*610fea65SAndreyChurbanov }
140*610fea65SAndreyChurbanov mysleep(DELAY);
141*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
142*610fea65SAndreyChurbanov err++;
143*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
144*610fea65SAndreyChurbanov }
145*610fea65SAndreyChurbanov #pragma omp atomic
146*610fea65SAndreyChurbanov --checker;
147*610fea65SAndreyChurbanov }
148*610fea65SAndreyChurbanov #pragma omp task depend(in: i1, i2)
149*610fea65SAndreyChurbanov { int th = omp_get_thread_num();
150*610fea65SAndreyChurbanov printf("task 1_%d, th %d\n", t, th);
151*610fea65SAndreyChurbanov #pragma omp atomic
152*610fea65SAndreyChurbanov ++checker;
153*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
154*610fea65SAndreyChurbanov err++;
155*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
156*610fea65SAndreyChurbanov }
157*610fea65SAndreyChurbanov mysleep(DELAY);
158*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
159*610fea65SAndreyChurbanov err++;
160*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
161*610fea65SAndreyChurbanov }
162*610fea65SAndreyChurbanov #pragma omp atomic
163*610fea65SAndreyChurbanov --checker;
164*610fea65SAndreyChurbanov }
165*610fea65SAndreyChurbanov // compiler codegen start
166*610fea65SAndreyChurbanov // task2
167*610fea65SAndreyChurbanov ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_s);
168*610fea65SAndreyChurbanov sdep[0].addr = (size_t)&i1;
169*610fea65SAndreyChurbanov sdep[0].len = 0; // not used
170*610fea65SAndreyChurbanov sdep[0].flags = 1; // IN
171*610fea65SAndreyChurbanov sdep[1].addr = (size_t)&i2;
172*610fea65SAndreyChurbanov sdep[1].len = 0; // not used
173*610fea65SAndreyChurbanov sdep[1].flags = 8; // INOUTSET
174*610fea65SAndreyChurbanov ptr->f_priv = t + 10; // init single first-private variable
175*610fea65SAndreyChurbanov __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0);
176*610fea65SAndreyChurbanov
177*610fea65SAndreyChurbanov // task3
178*610fea65SAndreyChurbanov ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_s);
179*610fea65SAndreyChurbanov ptr->f_priv = t + 20; // init single first-private variable
180*610fea65SAndreyChurbanov __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0);
181*610fea65SAndreyChurbanov // compiler codegen end
182*610fea65SAndreyChurbanov t = omp_get_thread_num();
183*610fea65SAndreyChurbanov #pragma omp task depend(in: i1, i2)
184*610fea65SAndreyChurbanov { int th = omp_get_thread_num();
185*610fea65SAndreyChurbanov printf("task 4_%d, th %d\n", t, th);
186*610fea65SAndreyChurbanov #pragma omp atomic
187*610fea65SAndreyChurbanov ++checker;
188*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
189*610fea65SAndreyChurbanov err++;
190*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
191*610fea65SAndreyChurbanov }
192*610fea65SAndreyChurbanov mysleep(DELAY);
193*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
194*610fea65SAndreyChurbanov err++;
195*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
196*610fea65SAndreyChurbanov }
197*610fea65SAndreyChurbanov #pragma omp atomic
198*610fea65SAndreyChurbanov --checker;
199*610fea65SAndreyChurbanov }
200*610fea65SAndreyChurbanov #pragma omp task depend(in: i1, i2)
201*610fea65SAndreyChurbanov { int th = omp_get_thread_num();
202*610fea65SAndreyChurbanov printf("task 5_%d, th %d\n", t, th);
203*610fea65SAndreyChurbanov #pragma omp atomic
204*610fea65SAndreyChurbanov ++checker;
205*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
206*610fea65SAndreyChurbanov err++;
207*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
208*610fea65SAndreyChurbanov }
209*610fea65SAndreyChurbanov mysleep(DELAY);
210*610fea65SAndreyChurbanov if (checker > 2) { // no more than 2 tasks concurrently
211*610fea65SAndreyChurbanov err++;
212*610fea65SAndreyChurbanov printf("Error1, checker %d > 2\n", checker);
213*610fea65SAndreyChurbanov }
214*610fea65SAndreyChurbanov #pragma omp atomic
215*610fea65SAndreyChurbanov --checker;
216*610fea65SAndreyChurbanov }
217*610fea65SAndreyChurbanov // compiler codegen start
218*610fea65SAndreyChurbanov // task6
219*610fea65SAndreyChurbanov ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_m);
220*610fea65SAndreyChurbanov sdep[0].addr = (size_t)&i1;
221*610fea65SAndreyChurbanov sdep[0].len = 0; // not used
222*610fea65SAndreyChurbanov sdep[0].flags = 4; // MUTEXINOUTSET
223*610fea65SAndreyChurbanov sdep[1].addr = (size_t)&i3;
224*610fea65SAndreyChurbanov sdep[1].len = 0; // not used
225*610fea65SAndreyChurbanov sdep[1].flags = 4; // MUTEXINOUTSET
226*610fea65SAndreyChurbanov ptr->f_priv = t + 30; // init single first-private variable
227*610fea65SAndreyChurbanov __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0);
228*610fea65SAndreyChurbanov
229*610fea65SAndreyChurbanov // task7
230*610fea65SAndreyChurbanov ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_m);
231*610fea65SAndreyChurbanov ptr->f_priv = t + 40; // init single first-private variable
232*610fea65SAndreyChurbanov __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0);
233*610fea65SAndreyChurbanov // compiler codegen end
234*610fea65SAndreyChurbanov #pragma omp task depend(in: i3)
235*610fea65SAndreyChurbanov { int th = omp_get_thread_num();
236*610fea65SAndreyChurbanov printf("task 8_%d, th %d\n", t, th);
237*610fea65SAndreyChurbanov #pragma omp atomic
238*610fea65SAndreyChurbanov ++checker;
239*610fea65SAndreyChurbanov if (checker != 1) { // last task should run exclusively
240*610fea65SAndreyChurbanov err++;
241*610fea65SAndreyChurbanov printf("Error1, checker %d != 1\n", checker); }
242*610fea65SAndreyChurbanov mysleep(DELAY);
243*610fea65SAndreyChurbanov if (checker != 1) { // last task should run exclusively
244*610fea65SAndreyChurbanov err++;
245*610fea65SAndreyChurbanov printf("Error1, checker %d != 1\n", checker); }
246*610fea65SAndreyChurbanov #pragma omp atomic
247*610fea65SAndreyChurbanov --checker;
248*610fea65SAndreyChurbanov }
249*610fea65SAndreyChurbanov } // single
250*610fea65SAndreyChurbanov } // parallel
251*610fea65SAndreyChurbanov if (err == 0) {
252*610fea65SAndreyChurbanov printf("passed\n");
253*610fea65SAndreyChurbanov return 0;
254*610fea65SAndreyChurbanov } else {
255*610fea65SAndreyChurbanov printf("failed\n");
256*610fea65SAndreyChurbanov return 1;
257*610fea65SAndreyChurbanov }
258*610fea65SAndreyChurbanov }
259