1 // RUN: %libomp-compile-and-run
2 // The runtime currently does not get dependency information from GCC.
3 // UNSUPPORTED: gcc
4 
5 // Very flaky on openmp-clang-x86_64-linux-debian.
6 // https://bugs.llvm.org/show_bug.cgi?id=45397
7 // UNSUPPORTED: linux
8 
9 #include <stdio.h>
10 #include <omp.h>
11 #include <pthread.h>
12 #include "omp_my_sleep.h"
13 
14 /*
15  An explicit task can have a dependency on a target task. If it is not
16  directly satisfied, the runtime should not wait but resume execution.
17 */
18 
19 // Compiler-generated code (emulation)
20 typedef long kmp_intptr_t;
21 typedef int kmp_int32;
22 
23 typedef char bool;
24 
25 typedef struct ident {
26     kmp_int32 reserved_1;   /**<  might be used in Fortran; see above  */
27     kmp_int32 flags;        /**<  also f.flags; KMP_IDENT_xxx flags; KMP_IDENT_KMPC identifies this union member  */
28     kmp_int32 reserved_2;   /**<  not really used in Fortran any more; see above */
29 #if USE_ITT_BUILD
30                             /*  but currently used for storing region-specific ITT */
31                             /*  contextual information. */
32 #endif /* USE_ITT_BUILD */
33     kmp_int32 reserved_3;   /**< source[4] in Fortran, do not use for C++  */
34     char const *psource;    /**< String describing the source location.
35                             The string is composed of semi-colon separated fields which describe the source file,
36                             the function and a pair of line numbers that delimit the construct.
37                              */
38 } ident_t;
39 
40 typedef struct kmp_depend_info {
41      kmp_intptr_t               base_addr;
42      size_t                     len;
43      struct {
44          bool                   in:1;
45          bool                   out:1;
46      } flags;
47 } kmp_depend_info_t;
48 
49 struct kmp_task;
50 typedef kmp_int32 (* kmp_routine_entry_t)( kmp_int32, struct kmp_task * );
51 
52 typedef struct kmp_task {                   /* GEH: Shouldn't this be aligned somehow? */
53     void *              shareds;            /**< pointer to block of pointers to shared vars   */
54     kmp_routine_entry_t routine;            /**< pointer to routine to call for executing task */
55     kmp_int32           part_id;            /**< part id for the task                          */
56 } kmp_task_t;
57 
58 #ifdef __cplusplus
59 extern "C" {
60 #endif
61 kmp_int32  __kmpc_global_thread_num  ( ident_t * );
62 kmp_task_t*
63 __kmpc_omp_task_alloc( ident_t *loc_ref, kmp_int32 gtid, kmp_int32 flags,
64                        size_t sizeof_kmp_task_t, size_t sizeof_shareds,
65                        kmp_routine_entry_t task_entry );
66 void __kmpc_proxy_task_completed_ooo ( kmp_task_t *ptask );
67 kmp_int32 __kmpc_omp_task_with_deps ( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task,
68                                       kmp_int32 ndeps, kmp_depend_info_t *dep_list,
69                                       kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list );
70 kmp_int32
71 __kmpc_omp_task( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task );
72 #ifdef __cplusplus
73 }
74 #endif
75 
target(void * task)76 void *target(void *task)
77 {
78     my_sleep( 0.1 );
79     __kmpc_proxy_task_completed_ooo((kmp_task_t*) task);
80     return NULL;
81 }
82 
83 pthread_t target_thread;
84 
85 // User's code
task_entry(kmp_int32 gtid,kmp_task_t * task)86 int task_entry(kmp_int32 gtid, kmp_task_t *task)
87 {
88     pthread_create(&target_thread, NULL, &target, task);
89     return 0;
90 }
91 
main()92 int main()
93 {
94     int dep;
95 
96 /*
97  *  Corresponds to:
98     #pragma omp target nowait depend(out: dep)
99     {
100         my_sleep( 0.1 );
101     }
102 */
103     kmp_depend_info_t dep_info;
104     dep_info.base_addr = (long) &dep;
105     dep_info.len = sizeof(int);
106     // out = inout per spec and runtime expects this
107     dep_info.flags.in = 1;
108     dep_info.flags.out = 1;
109 
110     kmp_int32 gtid = __kmpc_global_thread_num(NULL);
111     kmp_task_t *proxy_task = __kmpc_omp_task_alloc(NULL,gtid,17,sizeof(kmp_task_t),0,&task_entry);
112     __kmpc_omp_task_with_deps(NULL,gtid,proxy_task,1,&dep_info,0,NULL);
113 
114     int first_task_finished = 0;
115     #pragma omp task shared(first_task_finished) depend(inout: dep)
116     {
117         first_task_finished = 1;
118     }
119 
120     int second_task_finished = 0;
121     #pragma omp task shared(second_task_finished) depend(in: dep)
122     {
123         second_task_finished = 1;
124     }
125 
126     // check that execution has been resumed and the runtime has not waited
127     // for the dependencies to be satisfied.
128     int error = (first_task_finished == 1);
129     error += (second_task_finished == 1);
130 
131     #pragma omp taskwait
132 
133     // by now all tasks should have finished
134     error += (first_task_finished != 1);
135     error += (second_task_finished != 1);
136 
137     return error;
138 }
139