1 // RUN: %libomp-cxx-compile-and-run 2 3 /* 4 * This test aims to check whether hidden helper task can work with regular task 5 * in terms of dependences. It is equivalent to the following code: 6 * 7 * #pragma omp parallel 8 * for (int i = 0; i < N; ++i) { 9 * int data1 = 0, data2 = 0; 10 * #pragma omp taskgroup 11 * { 12 * #pragma omp hidden helper task shared(data1) 13 * { 14 * data1 = 1; 15 * } 16 * #pragma omp hidden helper task shared(data2) 17 * { 18 * data2 = 2; 19 * } 20 * } 21 * assert(data1 == 1); 22 * assert(data2 == 2); 23 * } 24 */ 25 26 #include "common.h" 27 28 extern "C" { 29 struct kmp_task_t_with_privates { 30 kmp_task_t task; 31 }; 32 33 struct anon { 34 int32_t *data; 35 }; 36 } 37 38 template <int I> 39 kmp_int32 omp_task_entry(kmp_int32 gtid, kmp_task_t_with_privates *task) { 40 auto shareds = reinterpret_cast<anon *>(task->task.shareds); 41 auto p = shareds->data; 42 *p = I; 43 return 0; 44 } 45 46 int main(int argc, char *argv[]) { 47 constexpr const int N = 1024; 48 #pragma omp parallel for 49 for (int i = 0; i < N; ++i) { 50 int32_t gtid = __kmpc_global_thread_num(nullptr); 51 int32_t data1 = 0, data2 = 0; 52 __kmpc_taskgroup(nullptr, gtid); 53 54 auto task1 = __kmpc_omp_target_task_alloc( 55 nullptr, gtid, 1, sizeof(kmp_task_t_with_privates), sizeof(anon), 56 reinterpret_cast<kmp_routine_entry_t>(omp_task_entry<1>), -1); 57 auto shareds = reinterpret_cast<anon *>(task1->shareds); 58 shareds->data = &data1; 59 __kmpc_omp_task(nullptr, gtid, task1); 60 61 auto task2 = __kmpc_omp_target_task_alloc( 62 nullptr, gtid, 1, sizeof(kmp_task_t_with_privates), sizeof(anon), 63 reinterpret_cast<kmp_routine_entry_t>(omp_task_entry<2>), -1); 64 shareds = reinterpret_cast<anon *>(task2->shareds); 65 shareds->data = &data2; 66 __kmpc_omp_task(nullptr, gtid, task2); 67 68 __kmpc_end_taskgroup(nullptr, gtid); 69 70 assert(data1 == 1); 71 assert(data2 == 2); 72 } 73 74 std::cout << "PASS\n"; 75 return 0; 76 } 77 78 // CHECK: PASS 79