| 1 | // REQUIRES: linux |
| 2 | // RUN: %libomp-compile && env OMP_NUM_THREADS='2' %libomp-run |
| 3 | |
| 4 | #include <assert.h> |
| 5 | #include <omp.h> |
| 6 | |
| 7 | #include "kmp_task_deps.h" |
| 8 | |
| 9 | // Expected dependency graph (directed from top to bottom) |
| 10 | // |
| 11 | // A B C // inoutset(x), inoutset(x, y), inoutset(y) |
| 12 | // | \ | / | |
| 13 | // D E F // in(x), in(x, y), in(y) |
| 14 | // \ / |
| 15 | // G // out(y) |
| 16 | |
| 17 | // the test |
| 18 | int main(void) { |
| 19 | volatile int done = 0; |
| 20 | |
| 21 | #pragma omp parallel num_threads(2) |
| 22 | { |
| 23 | while (omp_get_thread_num() != 0 && !done) |
| 24 | ; |
| 25 | |
| 26 | #pragma omp single |
| 27 | { |
| 28 | kmp_task_t *A, *B, *C, *D, *E, *F, *G; |
| 29 | kmp_depnode_list_t *A_succ, *B_succ, *C_succ, *E_succ, *F_succ; |
| 30 | kmp_base_depnode_t *D_node, *E_node, *F_node, *G_node; |
| 31 | dep deps[2]; |
| 32 | int gtid; |
| 33 | int x, y; |
| 34 | |
| 35 | gtid = __kmpc_global_thread_num(&loc); |
| 36 | |
| 37 | deps[0].addr = (size_t)&x; |
| 38 | deps[0].len = 0; |
| 39 | deps[0].flags = 8; // INOUTSET |
| 40 | |
| 41 | deps[1].addr = (size_t)&y; |
| 42 | deps[1].len = 0; |
| 43 | deps[1].flags = 8; // INOUTSET |
| 44 | |
| 45 | // A inoutset(x) |
| 46 | A = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(kmp_task_t), shar: 0, NULL); |
| 47 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: A, nd: 1, dep_lst: deps + 0, nd_noalias: 0, noalias_dep_lst: 0); |
| 48 | |
| 49 | // B inoutset(x, y) |
| 50 | B = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(kmp_task_t), shar: 0, NULL); |
| 51 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: B, nd: 2, dep_lst: deps + 0, nd_noalias: 0, noalias_dep_lst: 0); |
| 52 | |
| 53 | // C inoutset(y) |
| 54 | C = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(kmp_task_t), shar: 0, NULL); |
| 55 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: C, nd: 1, dep_lst: deps + 1, nd_noalias: 0, noalias_dep_lst: 0); |
| 56 | |
| 57 | deps[0].flags = 1; // IN |
| 58 | deps[1].flags = 1; // IN |
| 59 | |
| 60 | // D in(x) |
| 61 | D = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(kmp_task_t), shar: 0, NULL); |
| 62 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: D, nd: 1, dep_lst: deps + 0, nd_noalias: 0, noalias_dep_lst: 0); |
| 63 | |
| 64 | // E in(x, y) |
| 65 | E = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(kmp_task_t), shar: 0, NULL); |
| 66 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: E, nd: 2, dep_lst: deps + 0, nd_noalias: 0, noalias_dep_lst: 0); |
| 67 | |
| 68 | // F in(y) |
| 69 | F = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(kmp_task_t), shar: 0, NULL); |
| 70 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: F, nd: 1, dep_lst: deps + 1, nd_noalias: 0, noalias_dep_lst: 0); |
| 71 | |
| 72 | deps[1].flags = 2; // OUT |
| 73 | |
| 74 | // G out(y) |
| 75 | G = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(kmp_task_t), shar: 0, NULL); |
| 76 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: G, nd: 1, dep_lst: deps + 1, nd_noalias: 0, noalias_dep_lst: 0); |
| 77 | |
| 78 | // Retrieve TDG nodes and check edges |
| 79 | A_succ = __kmpc_task_get_successors(task: A); |
| 80 | B_succ = __kmpc_task_get_successors(task: B); |
| 81 | C_succ = __kmpc_task_get_successors(task: C); |
| 82 | E_succ = __kmpc_task_get_successors(task: E); |
| 83 | F_succ = __kmpc_task_get_successors(task: F); |
| 84 | |
| 85 | D_node = __kmpc_task_get_depnode(task: D); |
| 86 | E_node = __kmpc_task_get_depnode(task: E); |
| 87 | F_node = __kmpc_task_get_depnode(task: F); |
| 88 | |
| 89 | G_node = __kmpc_task_get_depnode(task: G); |
| 90 | |
| 91 | // A -> D and A -> E |
| 92 | assert(A_succ && A_succ->next && !A_succ->next->next); |
| 93 | assert((A_succ->node == D_node && A_succ->next->node == E_node) || |
| 94 | (A_succ->node == E_node && A_succ->next->node == D_node)); |
| 95 | |
| 96 | // B -> D and B -> E and B -> F |
| 97 | // valid lists are |
| 98 | // (D, E, F) |
| 99 | // (D, F, E) |
| 100 | // (E, D, F) |
| 101 | // (E, F, D) |
| 102 | // (F, D, E) |
| 103 | // (F, E, D) |
| 104 | assert(B_succ && B_succ->next && B_succ->next->next && |
| 105 | !B_succ->next->next->next); |
| 106 | assert((B_succ->node == D_node && B_succ->next->node == E_node && |
| 107 | B_succ->next->next->node == F_node) || |
| 108 | (B_succ->node == D_node && B_succ->next->node == F_node && |
| 109 | B_succ->next->next->node == E_node) || |
| 110 | (B_succ->node == E_node && B_succ->next->node == D_node && |
| 111 | B_succ->next->next->node == F_node) || |
| 112 | (B_succ->node == E_node && B_succ->next->node == F_node && |
| 113 | B_succ->next->next->node == D_node) || |
| 114 | (B_succ->node == F_node && B_succ->next->node == D_node && |
| 115 | B_succ->next->next->node == E_node) || |
| 116 | (B_succ->node == F_node && B_succ->next->node == E_node && |
| 117 | B_succ->next->next->node == D_node)); |
| 118 | |
| 119 | // C -> E and C -> F |
| 120 | assert(C_succ && C_succ->next && !C_succ->next->next); |
| 121 | assert((C_succ->node == E_node && C_succ->next->node == F_node) || |
| 122 | (C_succ->node == F_node && C_succ->next->node == E_node)); |
| 123 | |
| 124 | // E -> G and F -> G |
| 125 | assert(E_succ && !E_succ->next); |
| 126 | assert(E_succ->node == G_node); |
| 127 | |
| 128 | assert(F_succ && !F_succ->next); |
| 129 | assert(F_succ->node == G_node); |
| 130 | |
| 131 | #pragma omp taskwait |
| 132 | |
| 133 | done = 1; |
| 134 | } |
| 135 | } |
| 136 | return 0; |
| 137 | } |
| 138 | |