1 // RUN: %libomp-cxx-compile-and-run 2 // RUN: %libomp-cxx-compile && env OMP_NUM_THREADS=1 %libomp-run 3 4 /* 5 * This test aims to check whether hidden helper thread has right gtid. We also 6 * test if there is mixed dependences between regular tasks and hidden helper 7 * tasks, the tasks are executed by right set of threads. It is equivalent to 8 * the following code: 9 * 10 * #pragma omp parallel for 11 * for (int i = 0; i < N; ++i) { 12 * int data1 = -1, data2 = -1, data3 = -1; 13 * int depvar; 14 * #pragma omp task shared(data1) depend(inout: depvar) 15 * { 16 * data1 = omp_get_global_thread_id(); 17 * } 18 * #pragma omp task hidden helper shared(data2) depend(inout: depvar) 19 * { 20 * data2 = omp_get_global_thread_id(); 21 * } 22 * #pragma omp task shared(data3) depend(inout: depvar) 23 * { 24 * data3 = omp_get_global_thread_id(); 25 * } 26 * #pragma omp taskwait 27 * assert(data1 == 0 || data1 > __kmp_num_hidden_helper_threads); 28 * assert(data2 > 0 && data2 <= __kmp_num_hidden_helper_threads); 29 * assert(data3 == 0 || data3 > __kmp_num_hidden_helper_threads); 30 * } 31 */ 32 33 #include "common.h" 34 35 extern "C" { 36 struct kmp_task_t_with_privates { 37 kmp_task_t task; 38 }; 39 40 struct anon { 41 int32_t *data; 42 }; 43 } 44 45 kmp_int32 __kmp_hidden_helper_threads_num; 46 47 kmp_int32 omp_task_entry(kmp_int32 gtid, kmp_task_t_with_privates *task) { 48 auto shareds = reinterpret_cast<anon *>(task->task.shareds); 49 auto p = shareds->data; 50 *p = __kmpc_global_thread_num(nullptr); 51 return 0; 52 } 53 54 template <bool hidden_helper_task> void assert_gtid(int v) { 55 if (__kmp_hidden_helper_threads_num) { 56 if (hidden_helper_task) { 57 assert(v > 0 && v <= __kmp_hidden_helper_threads_num); 58 } else { 59 assert(v == 0 || v > __kmp_hidden_helper_threads_num); 60 } 61 } else { 62 assert(v >= 0); 63 } 64 } 65 66 int main(int argc, char *argv[]) { 67 __kmp_hidden_helper_threads_num = get_num_hidden_helper_threads(); 68 69 constexpr const int N = 1024; 70 #pragma omp parallel for 71 for (int i = 0; i < N; ++i) { 72 int32_t data1 = -1, data2 = -1, data3 = -1; 73 int depvar; 74 int32_t gtid = __kmpc_global_thread_num(nullptr); 75 76 // Task 1, regular task 77 auto task1 = __kmpc_omp_task_alloc( 78 nullptr, gtid, 1, sizeof(kmp_task_t_with_privates), sizeof(anon), 79 reinterpret_cast<kmp_routine_entry_t>(omp_task_entry)); 80 auto shareds = reinterpret_cast<anon *>(task1->shareds); 81 shareds->data = &data1; 82 83 kmp_depend_info_t depinfo1; 84 depinfo1.base_addr = reinterpret_cast<intptr_t>(&depvar); 85 depinfo1.flag = 3; // INOUT 86 depinfo1.len = 4; 87 88 __kmpc_omp_task_with_deps(nullptr, gtid, task1, 1, &depinfo1, 0, nullptr); 89 90 // Task 2, hidden helper task 91 auto task2 = __kmpc_omp_target_task_alloc( 92 nullptr, gtid, 1, sizeof(kmp_task_t_with_privates), sizeof(anon), 93 reinterpret_cast<kmp_routine_entry_t>(omp_task_entry), -1); 94 shareds = reinterpret_cast<anon *>(task2->shareds); 95 shareds->data = &data2; 96 97 kmp_depend_info_t depinfo2; 98 depinfo2.base_addr = reinterpret_cast<intptr_t>(&depvar); 99 depinfo2.flag = 3; // INOUT 100 depinfo2.len = 4; 101 102 __kmpc_omp_task_with_deps(nullptr, gtid, task2, 1, &depinfo2, 0, nullptr); 103 104 // Task 3, regular task 105 auto task3 = __kmpc_omp_task_alloc( 106 nullptr, gtid, 1, sizeof(kmp_task_t_with_privates), sizeof(anon), 107 reinterpret_cast<kmp_routine_entry_t>(omp_task_entry)); 108 shareds = reinterpret_cast<anon *>(task3->shareds); 109 shareds->data = &data3; 110 111 kmp_depend_info_t depinfo3; 112 depinfo3.base_addr = reinterpret_cast<intptr_t>(&depvar); 113 depinfo3.flag = 3; // INOUT 114 depinfo3.len = 4; 115 116 __kmpc_omp_task_with_deps(nullptr, gtid, task3, 1, &depinfo3, 0, nullptr); 117 118 __kmpc_omp_taskwait(nullptr, gtid); 119 120 // FIXME: 8 here is not accurate 121 assert_gtid<false>(data1); 122 assert_gtid<true>(data2); 123 assert_gtid<false>(data3); 124 } 125 126 std::cout << "PASS\n"; 127 return 0; 128 } 129 130 // CHECK: PASS 131