diff --git a/openmp/runtime/src/kmp_ftn_os.h b/openmp/runtime/src/kmp_ftn_os.h --- a/openmp/runtime/src/kmp_ftn_os.h +++ b/openmp/runtime/src/kmp_ftn_os.h @@ -680,5 +680,6 @@ #define KMP_API_NAME_GOMP_PARALLEL_LOOP_MAYBE_NONMONOTONIC_RUNTIME \ GOMP_parallel_loop_maybe_nonmonotonic_runtime #define KMP_API_NAME_GOMP_TEAMS_REG GOMP_teams_reg +#define KMP_API_NAME_GOMP_TASKWAIT_DEPEND GOMP_taskwait_depend #endif /* KMP_FTN_OS_H */ 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 @@ -1867,6 +1867,19 @@ KA_TRACE(20, ("GOMP_teams_reg exit: T#%d\n", gtid)); } +void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_TASKWAIT_DEPEND)(void **depend) { + MKLOC(loc, "GOMP_taskwait_depend"); + int gtid = __kmp_entry_gtid(); + KA_TRACE(20, ("GOMP_taskwait_depend: T#%d\n", gtid)); + 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); + KA_TRACE(20, ("GOMP_taskwait_depend exit: T#%d\n", gtid)); +} + /* The following sections of code create aliases for the GOMP_* functions, then create versioned symbols using the assembler directive .symver. This is only pertinent for ELF .so library. The KMP_VERSION_SYMBOL macro is defined in @@ -2039,6 +2052,7 @@ KMP_VERSION_SYMBOL(KMP_API_NAME_GOMP_PARALLEL_LOOP_MAYBE_NONMONOTONIC_RUNTIME, 50, "GOMP_5.0"); KMP_VERSION_SYMBOL(KMP_API_NAME_GOMP_TEAMS_REG, 50, "GOMP_5.0"); +KMP_VERSION_SYMBOL(KMP_API_NAME_GOMP_TASKWAIT_DEPEND, 50, "GOMP_5.0"); #endif // KMP_USE_VERSION_SYMBOLS diff --git a/openmp/runtime/test/tasking/omp50_taskwait_depend.c b/openmp/runtime/test/tasking/omp50_taskwait_depend.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/tasking/omp50_taskwait_depend.c @@ -0,0 +1,108 @@ +// RUN: %libomp-compile-and-run +// UNSUPPORTED: gcc-4, gcc-5, gcc-6, gcc-7, gcc-8 +// clang does not yet support taskwait with depend clause +// clang-12 introduced parsing, but no codegen +// TODO: update expected result when codegen in clang is added +// icc does not yet support taskwait with depend clause +// TODO: update expected result when support for icc is added +// XFAIL: clang, icc + +#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 taskwait 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 taskwait 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 taskwait 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; +}