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 @@ -23,18 +23,24 @@ KMP_GOMP_TASK_DEPENDS_FLAG = 8 }; +enum { + KMP_GOMP_DEPOBJ_IN = 1, + KMP_GOMP_DEPOBJ_OUT = 2, + KMP_GOMP_DEPOBJ_INOUT = 3, + KMP_GOMP_DEPOBJ_MTXINOUTSET = 4 +}; + // This class helps convert gomp dependency info into // kmp_depend_info_t structures class kmp_gomp_depends_info_t { void **depend; kmp_int32 num_deps; - size_t num_out, num_mutexinout, num_in; + size_t num_out, num_mutexinout, num_in, num_depobj; size_t offset; public: kmp_gomp_depends_info_t(void **depend) : depend(depend) { size_t ndeps = (kmp_intptr_t)depend[0]; - size_t num_doable; // GOMP taskdep structure: // if depend[0] != 0: // depend = [ ndeps | nout | &out | ... | &out | &in | ... | &in ] @@ -45,21 +51,17 @@ if (ndeps) { num_out = (kmp_intptr_t)depend[1]; num_in = ndeps - num_out; - num_mutexinout = 0; - num_doable = ndeps; + num_mutexinout = num_depobj = 0; offset = 2; } else { ndeps = (kmp_intptr_t)depend[1]; num_out = (kmp_intptr_t)depend[2]; num_mutexinout = (kmp_intptr_t)depend[3]; num_in = (kmp_intptr_t)depend[4]; - num_doable = num_out + num_mutexinout + num_in; + num_depobj = ndeps - num_out - num_mutexinout - num_in; + KMP_ASSERT(num_depobj <= ndeps); offset = 5; } - // TODO: Support gomp depobj - if (ndeps != num_doable) { - KMP_FATAL(GompFeatureNotSupported, "depobj"); - } num_deps = static_cast(ndeps); } kmp_int32 get_num_deps() const { return num_deps; } @@ -67,7 +69,6 @@ kmp_depend_info_t retval; memset(&retval, '\0', sizeof(retval)); KMP_ASSERT(index < (size_t)num_deps); - retval.base_addr = (kmp_intptr_t)depend[offset + index]; retval.len = 0; // Because inout and out are logically equivalent, // use inout and in dependency flags. GOMP does not provide a @@ -75,10 +76,37 @@ if (index < num_out) { retval.flags.in = 1; retval.flags.out = 1; + retval.base_addr = (kmp_intptr_t)depend[offset + index]; } else if (index >= num_out && index < (num_out + num_mutexinout)) { retval.flags.mtx = 1; - } else { + retval.base_addr = (kmp_intptr_t)depend[offset + index]; + } else if (index >= (num_out + num_mutexinout) && + index < (num_out + num_mutexinout + num_in)) { retval.flags.in = 1; + retval.base_addr = (kmp_intptr_t)depend[offset + index]; + } else { + // depobj is a two element array (size of elements are size of pointer) + // depobj[0] = base_addr + // depobj[1] = type (in, out, inout, mutexinoutset, etc.) + kmp_intptr_t *depobj = (kmp_intptr_t *)depend[offset + index]; + retval.base_addr = depobj[0]; + switch (depobj[1]) { + case KMP_GOMP_DEPOBJ_IN: + retval.flags.in = 1; + break; + case KMP_GOMP_DEPOBJ_OUT: + retval.flags.out = 1; + break; + case KMP_GOMP_DEPOBJ_INOUT: + retval.flags.in = 1; + retval.flags.out = 1; + break; + case KMP_GOMP_DEPOBJ_MTXINOUTSET: + retval.flags.mtx = 1; + break; + default: + KMP_FATAL(GompFeatureNotSupported, "Unknown depobj type"); + } } return retval; } diff --git a/openmp/runtime/test/CMakeLists.txt b/openmp/runtime/test/CMakeLists.txt --- a/openmp/runtime/test/CMakeLists.txt +++ b/openmp/runtime/test/CMakeLists.txt @@ -29,6 +29,7 @@ pythonize_bool(LIBOMP_OMPT_OPTIONAL) pythonize_bool(LIBOMP_HAVE_LIBM) pythonize_bool(LIBOMP_HAVE_LIBATOMIC) +pythonize_bool(OPENMP_STANDALONE_BUILD) add_library(ompt-print-callback INTERFACE) target_include_directories(ompt-print-callback INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/ompt) diff --git a/openmp/runtime/test/lit.cfg b/openmp/runtime/test/lit.cfg --- a/openmp/runtime/test/lit.cfg +++ b/openmp/runtime/test/lit.cfg @@ -42,10 +42,11 @@ config.test_format = lit.formats.ShTest() # compiler flags -config.test_flags = " -I " + config.test_source_root + \ - " -I " + config.omp_header_directory + \ +flags = " -I " + config.test_source_root + \ " -L " + config.library_dir + \ " " + config.test_extra_flags +config.test_flags = " -I " + config.omp_header_directory + flags +config.test_flags_use_compiler_omp_h = flags # extra libraries libs = "" @@ -126,6 +127,16 @@ config.substitutions.append(("%clangXX", config.test_cxx_compiler)) config.substitutions.append(("%clang", config.test_c_compiler)) config.substitutions.append(("%openmp_flags", config.test_openmp_flags)) +# %flags-use-compiler-omp-h allows us to use the test compiler's omp.h file which +# may have different definitions of structures than our omp.h file. +if config.is_standalone_build: + config.substitutions.append(("%flags-use-compiler-omp-h", + config.test_flags_use_compiler_omp_h)) +else: + # If testing the runtime within an LLVM tree, then always include omp.h + # directory associated with the new clang compiler. + config.substitutions.append(("%flags-use-compiler-omp-h", + config.test_flags)) config.substitutions.append(("%flags", config.test_flags)) config.substitutions.append(("%python", '"%s"' % (sys.executable))) config.substitutions.append(("%not", config.test_not)) diff --git a/openmp/runtime/test/lit.site.cfg.in b/openmp/runtime/test/lit.site.cfg.in --- a/openmp/runtime/test/lit.site.cfg.in +++ b/openmp/runtime/test/lit.site.cfg.in @@ -16,6 +16,7 @@ config.has_ompt = @LIBOMP_OMPT_SUPPORT@ and @LIBOMP_OMPT_OPTIONAL@ config.has_libm = @LIBOMP_HAVE_LIBM@ config.has_libatomic = @LIBOMP_HAVE_LIBATOMIC@ +config.is_standalone_build = @OPENMP_STANDALONE_BUILD@ # Let the main config do the real work. lit_config.load_config(config, "@LIBOMP_BASE_DIR@/test/lit.cfg") diff --git a/openmp/runtime/test/tasking/omp50_taskdep_depobj.c b/openmp/runtime/test/tasking/omp50_taskdep_depobj.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/tasking/omp50_taskdep_depobj.c @@ -0,0 +1,89 @@ +// RUN: %clang %openmp_flags %flags-use-compiler-omp-h %s -o %t && %libomp-run +// UNSUPPORTED: gcc-5, gcc-6, gcc-7, gcc-8 +// UNSUPPORTED: clang-5, clang-6, clang-7, clang-8, clang-9, clang-10 +// UNSUPPORTED: icc + +#include +#include +#include +#include "omp_my_sleep.h" + +int a, b; + +void mutexinoutset_task() { + if (b != 0) { + fprintf(stderr, "mutexinoutset_task: b != 0 at start of task\n"); + exit(EXIT_FAILURE); + } + b++; + if (b != 1) { + fprintf(stderr, "mutexinoutset_task: b != 1\n"); + exit(EXIT_FAILURE); + } + my_sleep(0.1); + b--; + if (b != 0) { + fprintf(stderr, "mutexinoutset_task: b != 0 at end of task\n"); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char** argv) { + omp_depend_t dep_a_in; + omp_depend_t dep_a_out; + omp_depend_t dep_a_inout; + omp_depend_t dep_a_mutexinoutset; + + a = 0; + b = 0; + + #pragma omp depobj(dep_a_in) depend(in: a) + #pragma omp depobj(dep_a_out) depend(out: a) + #pragma omp depobj(dep_a_inout) depend(inout: a) + #pragma omp depobj(dep_a_mutexinoutset) depend(mutexinoutset: a) + + #pragma omp parallel + { + #pragma omp single + { + + #pragma omp task depend(depobj: dep_a_out) + { + my_sleep(0.1); + a = 10; + } + + #pragma omp task depend(depobj: dep_a_inout) + { + my_sleep(0.1); + a++; + } + + #pragma omp task depend(depobj: dep_a_mutexinoutset) + mutexinoutset_task(); + #pragma omp task depend(depobj: dep_a_mutexinoutset) + mutexinoutset_task(); + #pragma omp task depend(depobj: dep_a_mutexinoutset) + mutexinoutset_task(); + #pragma omp task depend(depobj: dep_a_mutexinoutset) + mutexinoutset_task(); + #pragma omp task depend(depobj: dep_a_mutexinoutset) + mutexinoutset_task(); + + #pragma omp task depend(depobj: dep_a_in) + { a += 10; } + } + } + + if (a != 21) { + fprintf(stderr, "a (%d) != 21\n", a); + exit(EXIT_FAILURE); + } + + #pragma omp depobj(dep_a_in) destroy + #pragma omp depobj(dep_a_out) destroy + #pragma omp depobj(dep_a_inout) destroy + #pragma omp depobj(dep_a_mutexinoutset) destroy + + return EXIT_SUCCESS; +}