diff --git a/openmp/runtime/src/kmp_gsupport.cpp b/openmp/runtime/src/kmp_gsupport.cpp --- a/openmp/runtime/src/kmp_gsupport.cpp +++ b/openmp/runtime/src/kmp_gsupport.cpp @@ -17,6 +17,12 @@ #include "ompt-specific.h" #endif +enum { + KMP_GOMP_TASK_UNTIED_FLAG = 1, + KMP_GOMP_TASK_FINAL_FLAG = 2, + KMP_GOMP_TASK_DEPENDS_FLAG = 8 +}; + // This class helps convert gomp dependency info into // kmp_depend_info_t structures class kmp_gomp_depends_info_t { @@ -1181,11 +1187,11 @@ KA_TRACE(20, ("GOMP_task: T#%d\n", gtid)); // The low-order bit is the "untied" flag - if (!(gomp_flags & 1)) { + if (!(gomp_flags & KMP_GOMP_TASK_UNTIED_FLAG)) { input_flags->tiedness = 1; } // The second low-order bit is the "final" flag - if (gomp_flags & 2) { + if (gomp_flags & KMP_GOMP_TASK_FINAL_FLAG) { input_flags->final = 1; } input_flags->native = 1; @@ -1223,7 +1229,7 @@ #endif if (if_cond) { - if (gomp_flags & 8) { + if (gomp_flags & KMP_GOMP_TASK_DEPENDS_FLAG) { KMP_ASSERT(depend); kmp_gomp_depends_info_t gomp_depends(depend); kmp_int32 ndeps = gomp_depends.get_num_deps(); @@ -1250,6 +1256,15 @@ OMPT_STORE_RETURN_ADDRESS(gtid); } #endif + if (gomp_flags & KMP_GOMP_TASK_DEPENDS_FLAG) { + KMP_ASSERT(depend); + kmp_gomp_depends_info_t gomp_depends(depend); + kmp_int32 ndeps = gomp_depends.get_num_deps(); + kmp_depend_info_t dep_list[ndeps]; + for (kmp_int32 i = 0; i < ndeps; i++) + dep_list[i] = gomp_depends.get_kmp_depend(i); + __kmpc_omp_wait_deps(&loc, gtid, ndeps, dep_list, 0, NULL); + } __kmpc_omp_task_begin_if0(&loc, gtid, task); func(data); diff --git a/openmp/runtime/test/tasking/taskdep_if0.c b/openmp/runtime/test/tasking/taskdep_if0.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/tasking/taskdep_if0.c @@ -0,0 +1,39 @@ +// RUN: %libomp-compile-and-run + +#include +#include +#include +#include "omp_my_sleep.h" + +int a = 0; + +void task1() { + my_sleep(0.5); + a = 10; +} + +void task2() { + a++; +} + +int main(int argc, char** argv) +{ + #pragma omp parallel shared(argc) num_threads(2) + { + #pragma omp single + { + #pragma omp task depend(out: a) + task1(); + + #pragma omp task if(0) depend(inout: a) + task2(); + } + } + if (a != 11) { + fprintf(stderr, "fail: expected 11, but a is %d\n", a); + exit(1); + } else { + printf("pass\n"); + } + return 0; +} diff --git a/openmp/runtime/test/tasking/taskdep_if0_2.c b/openmp/runtime/test/tasking/taskdep_if0_2.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/tasking/taskdep_if0_2.c @@ -0,0 +1,104 @@ +// RUN: %libomp-compile-and-run + +#include +#include +#include +#include "omp_my_sleep.h" + +int a = 0, b = 0; +int task_grabbed = 0, task_can_proceed = 0; +int task2_grabbed = 0, task2_can_proceed = 0; + +static void wait_on_flag(int *flag) { + int flag_value; + int timelimit = 30; + int secs = 0; + do { + #pragma omp atomic read + flag_value = *flag; + my_sleep(1.0); + secs++; + if (secs == timelimit) { + fprintf(stderr, "error: timeout in wait_on_flag()\n"); + exit(EXIT_FAILURE); + } + } while (flag_value == 0); +} + +static void signal_flag(int *flag) { + #pragma omp atomic + (*flag)++; +} + +int main(int argc, char** argv) { + + // Ensure two threads are running + int num_threads = omp_get_max_threads(); + if (num_threads < 2) + omp_set_num_threads(2); + + #pragma omp parallel shared(a) + { + int a_value; + // Let us be extra safe here + if (omp_get_num_threads() > 1) { + #pragma omp single nowait + { + // Schedule independent child task that + // waits to be flagged after sebsequent taskwait depend() + #pragma omp task + { + signal_flag(&task_grabbed); + wait_on_flag(&task_can_proceed); + } + // Let another worker thread grab the task to execute + wait_on_flag(&task_grabbed); + // This should be ignored since the task above has + // no dependency information + #pragma omp task if(0) depend(inout: a) + {} + // Signal the independent task to proceed + signal_flag(&task_can_proceed); + + // Schedule child task with dependencies that taskwait does + // not care about + #pragma omp task depend(inout: b) + { + signal_flag(&task2_grabbed); + wait_on_flag(&task2_can_proceed); + #pragma omp atomic + b++; + } + // Let another worker thread grab the task to execute + wait_on_flag(&task2_grabbed); + // This should be ignored since the task above has + // dependency information on b instead of a + #pragma omp task if(0) depend(inout: a) + {} + // Signal the task to proceed + signal_flag(&task2_can_proceed); + + // Generate one child task for taskwait + #pragma omp task shared(a) depend(inout: a) + { + my_sleep(1.0); + #pragma omp atomic + a++; + } + #pragma omp task if(0) depend(inout: a) + {} + + #pragma omp atomic read + a_value = a; + + if (a_value != 1) { + fprintf(stderr, "error: dependent task was not executed before " + "taskwait finished\n"); + exit(EXIT_FAILURE); + } + } // #pragma omp single + } // if (num_threads > 1) + } // #pragma omp parallel + + return EXIT_SUCCESS; +}