1 /*
2  * kmp_tasking.cpp -- OpenMP 3.0 tasking support.
3  */
4 
5 //===----------------------------------------------------------------------===//
6 //
7 //                     The LLVM Compiler Infrastructure
8 //
9 // This file is dual licensed under the MIT and the University of Illinois Open
10 // Source Licenses. See LICENSE.txt for details.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "kmp.h"
15 #include "kmp_i18n.h"
16 #include "kmp_itt.h"
17 #include "kmp_stats.h"
18 #include "kmp_wait_release.h"
19 #include "kmp_taskdeps.h"
20 
21 #if OMPT_SUPPORT
22 #include "ompt-specific.h"
23 #endif
24 
25 #include "tsan_annotations.h"
26 
27 /* forward declaration */
28 static void __kmp_enable_tasking(kmp_task_team_t *task_team,
29                                  kmp_info_t *this_thr);
30 static void __kmp_alloc_task_deque(kmp_info_t *thread,
31                                    kmp_thread_data_t *thread_data);
32 static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
33                                            kmp_task_team_t *task_team);
34 
35 #if OMP_45_ENABLED
36 static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask);
37 #endif
38 
39 #ifdef BUILD_TIED_TASK_STACK
40 
41 //  __kmp_trace_task_stack: print the tied tasks from the task stack in order
42 //  from top do bottom
43 //
44 //  gtid: global thread identifier for thread containing stack
45 //  thread_data: thread data for task team thread containing stack
46 //  threshold: value above which the trace statement triggers
47 //  location: string identifying call site of this function (for trace)
48 static void __kmp_trace_task_stack(kmp_int32 gtid,
49                                    kmp_thread_data_t *thread_data,
50                                    int threshold, char *location) {
51   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
52   kmp_taskdata_t **stack_top = task_stack->ts_top;
53   kmp_int32 entries = task_stack->ts_entries;
54   kmp_taskdata_t *tied_task;
55 
56   KA_TRACE(
57       threshold,
58       ("__kmp_trace_task_stack(start): location = %s, gtid = %d, entries = %d, "
59        "first_block = %p, stack_top = %p \n",
60        location, gtid, entries, task_stack->ts_first_block, stack_top));
61 
62   KMP_DEBUG_ASSERT(stack_top != NULL);
63   KMP_DEBUG_ASSERT(entries > 0);
64 
65   while (entries != 0) {
66     KMP_DEBUG_ASSERT(stack_top != &task_stack->ts_first_block.sb_block[0]);
67     // fix up ts_top if we need to pop from previous block
68     if (entries & TASK_STACK_INDEX_MASK == 0) {
69       kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(stack_top);
70 
71       stack_block = stack_block->sb_prev;
72       stack_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE];
73     }
74 
75     // finish bookkeeping
76     stack_top--;
77     entries--;
78 
79     tied_task = *stack_top;
80 
81     KMP_DEBUG_ASSERT(tied_task != NULL);
82     KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED);
83 
84     KA_TRACE(threshold,
85              ("__kmp_trace_task_stack(%s):             gtid=%d, entry=%d, "
86               "stack_top=%p, tied_task=%p\n",
87               location, gtid, entries, stack_top, tied_task));
88   }
89   KMP_DEBUG_ASSERT(stack_top == &task_stack->ts_first_block.sb_block[0]);
90 
91   KA_TRACE(threshold,
92            ("__kmp_trace_task_stack(exit): location = %s, gtid = %d\n",
93             location, gtid));
94 }
95 
96 //  __kmp_init_task_stack: initialize the task stack for the first time
97 //  after a thread_data structure is created.
98 //  It should not be necessary to do this again (assuming the stack works).
99 //
100 //  gtid: global thread identifier of calling thread
101 //  thread_data: thread data for task team thread containing stack
102 static void __kmp_init_task_stack(kmp_int32 gtid,
103                                   kmp_thread_data_t *thread_data) {
104   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
105   kmp_stack_block_t *first_block;
106 
107   // set up the first block of the stack
108   first_block = &task_stack->ts_first_block;
109   task_stack->ts_top = (kmp_taskdata_t **)first_block;
110   memset((void *)first_block, '\0',
111          TASK_STACK_BLOCK_SIZE * sizeof(kmp_taskdata_t *));
112 
113   // initialize the stack to be empty
114   task_stack->ts_entries = TASK_STACK_EMPTY;
115   first_block->sb_next = NULL;
116   first_block->sb_prev = NULL;
117 }
118 
119 //  __kmp_free_task_stack: free the task stack when thread_data is destroyed.
120 //
121 //  gtid: global thread identifier for calling thread
122 //  thread_data: thread info for thread containing stack
123 static void __kmp_free_task_stack(kmp_int32 gtid,
124                                   kmp_thread_data_t *thread_data) {
125   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
126   kmp_stack_block_t *stack_block = &task_stack->ts_first_block;
127 
128   KMP_DEBUG_ASSERT(task_stack->ts_entries == TASK_STACK_EMPTY);
129   // free from the second block of the stack
130   while (stack_block != NULL) {
131     kmp_stack_block_t *next_block = (stack_block) ? stack_block->sb_next : NULL;
132 
133     stack_block->sb_next = NULL;
134     stack_block->sb_prev = NULL;
135     if (stack_block != &task_stack->ts_first_block) {
136       __kmp_thread_free(thread,
137                         stack_block); // free the block, if not the first
138     }
139     stack_block = next_block;
140   }
141   // initialize the stack to be empty
142   task_stack->ts_entries = 0;
143   task_stack->ts_top = NULL;
144 }
145 
146 //  __kmp_push_task_stack: Push the tied task onto the task stack.
147 //     Grow the stack if necessary by allocating another block.
148 //
149 //  gtid: global thread identifier for calling thread
150 //  thread: thread info for thread containing stack
151 //  tied_task: the task to push on the stack
152 static void __kmp_push_task_stack(kmp_int32 gtid, kmp_info_t *thread,
153                                   kmp_taskdata_t *tied_task) {
154   // GEH - need to consider what to do if tt_threads_data not allocated yet
155   kmp_thread_data_t *thread_data =
156       &thread->th.th_task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)];
157   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
158 
159   if (tied_task->td_flags.team_serial || tied_task->td_flags.tasking_ser) {
160     return; // Don't push anything on stack if team or team tasks are serialized
161   }
162 
163   KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED);
164   KMP_DEBUG_ASSERT(task_stack->ts_top != NULL);
165 
166   KA_TRACE(20,
167            ("__kmp_push_task_stack(enter): GTID: %d; THREAD: %p; TASK: %p\n",
168             gtid, thread, tied_task));
169   // Store entry
170   *(task_stack->ts_top) = tied_task;
171 
172   // Do bookkeeping for next push
173   task_stack->ts_top++;
174   task_stack->ts_entries++;
175 
176   if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) {
177     // Find beginning of this task block
178     kmp_stack_block_t *stack_block =
179         (kmp_stack_block_t *)(task_stack->ts_top - TASK_STACK_BLOCK_SIZE);
180 
181     // Check if we already have a block
182     if (stack_block->sb_next !=
183         NULL) { // reset ts_top to beginning of next block
184       task_stack->ts_top = &stack_block->sb_next->sb_block[0];
185     } else { // Alloc new block and link it up
186       kmp_stack_block_t *new_block = (kmp_stack_block_t *)__kmp_thread_calloc(
187           thread, sizeof(kmp_stack_block_t));
188 
189       task_stack->ts_top = &new_block->sb_block[0];
190       stack_block->sb_next = new_block;
191       new_block->sb_prev = stack_block;
192       new_block->sb_next = NULL;
193 
194       KA_TRACE(
195           30,
196           ("__kmp_push_task_stack(): GTID: %d; TASK: %p; Alloc new block: %p\n",
197            gtid, tied_task, new_block));
198     }
199   }
200   KA_TRACE(20, ("__kmp_push_task_stack(exit): GTID: %d; TASK: %p\n", gtid,
201                 tied_task));
202 }
203 
204 //  __kmp_pop_task_stack: Pop the tied task from the task stack.  Don't return
205 //  the task, just check to make sure it matches the ending task passed in.
206 //
207 //  gtid: global thread identifier for the calling thread
208 //  thread: thread info structure containing stack
209 //  tied_task: the task popped off the stack
210 //  ending_task: the task that is ending (should match popped task)
211 static void __kmp_pop_task_stack(kmp_int32 gtid, kmp_info_t *thread,
212                                  kmp_taskdata_t *ending_task) {
213   // GEH - need to consider what to do if tt_threads_data not allocated yet
214   kmp_thread_data_t *thread_data =
215       &thread->th.th_task_team->tt_threads_data[__kmp_tid_from_gtid(gtid)];
216   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
217   kmp_taskdata_t *tied_task;
218 
219   if (ending_task->td_flags.team_serial || ending_task->td_flags.tasking_ser) {
220     // Don't pop anything from stack if team or team tasks are serialized
221     return;
222   }
223 
224   KMP_DEBUG_ASSERT(task_stack->ts_top != NULL);
225   KMP_DEBUG_ASSERT(task_stack->ts_entries > 0);
226 
227   KA_TRACE(20, ("__kmp_pop_task_stack(enter): GTID: %d; THREAD: %p\n", gtid,
228                 thread));
229 
230   // fix up ts_top if we need to pop from previous block
231   if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) {
232     kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(task_stack->ts_top);
233 
234     stack_block = stack_block->sb_prev;
235     task_stack->ts_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE];
236   }
237 
238   // finish bookkeeping
239   task_stack->ts_top--;
240   task_stack->ts_entries--;
241 
242   tied_task = *(task_stack->ts_top);
243 
244   KMP_DEBUG_ASSERT(tied_task != NULL);
245   KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED);
246   KMP_DEBUG_ASSERT(tied_task == ending_task); // If we built the stack correctly
247 
248   KA_TRACE(20, ("__kmp_pop_task_stack(exit): GTID: %d; TASK: %p\n", gtid,
249                 tied_task));
250   return;
251 }
252 #endif /* BUILD_TIED_TASK_STACK */
253 
254 // returns 1 if new task is allowed to execute, 0 otherwise
255 // checks Task Scheduling constraint (if requested) and
256 // mutexinoutset dependencies if any
257 static bool __kmp_task_is_allowed(int gtid, const kmp_int32 is_constrained,
258                                   const kmp_taskdata_t *tasknew,
259                                   const kmp_taskdata_t *taskcurr) {
260   if (is_constrained && (tasknew->td_flags.tiedness == TASK_TIED)) {
261     // Check if the candidate obeys the Task Scheduling Constraints (TSC)
262     // only descendant of all deferred tied tasks can be scheduled, checking
263     // the last one is enough, as it in turn is the descendant of all others
264     kmp_taskdata_t *current = taskcurr->td_last_tied;
265     KMP_DEBUG_ASSERT(current != NULL);
266     // check if the task is not suspended on barrier
267     if (current->td_flags.tasktype == TASK_EXPLICIT ||
268         current->td_taskwait_thread > 0) { // <= 0 on barrier
269       kmp_int32 level = current->td_level;
270       kmp_taskdata_t *parent = tasknew->td_parent;
271       while (parent != current && parent->td_level > level) {
272         // check generation up to the level of the current task
273         parent = parent->td_parent;
274         KMP_DEBUG_ASSERT(parent != NULL);
275       }
276       if (parent != current)
277         return false;
278     }
279   }
280   // Check mutexinoutset dependencies, acquire locks
281   kmp_depnode_t *node = tasknew->td_depnode;
282   if (node && (node->dn.mtx_num_locks > 0)) {
283     for (int i = 0; i < node->dn.mtx_num_locks; ++i) {
284       KMP_DEBUG_ASSERT(node->dn.mtx_locks[i] != NULL);
285       if (__kmp_test_lock(node->dn.mtx_locks[i], gtid))
286         continue;
287       // could not get the lock, release previous locks
288       for (int j = i - 1; j >= 0; --j)
289         __kmp_release_lock(node->dn.mtx_locks[j], gtid);
290       return false;
291     }
292     // negative num_locks means all locks acquired successfully
293     node->dn.mtx_num_locks = -node->dn.mtx_num_locks;
294   }
295   return true;
296 }
297 
298 // __kmp_realloc_task_deque:
299 // Re-allocates a task deque for a particular thread, copies the content from
300 // the old deque and adjusts the necessary data structures relating to the
301 // deque. This operation must be done with the deque_lock being held
302 static void __kmp_realloc_task_deque(kmp_info_t *thread,
303                                      kmp_thread_data_t *thread_data) {
304   kmp_int32 size = TASK_DEQUE_SIZE(thread_data->td);
305   kmp_int32 new_size = 2 * size;
306 
307   KE_TRACE(10, ("__kmp_realloc_task_deque: T#%d reallocating deque[from %d to "
308                 "%d] for thread_data %p\n",
309                 __kmp_gtid_from_thread(thread), size, new_size, thread_data));
310 
311   kmp_taskdata_t **new_deque =
312       (kmp_taskdata_t **)__kmp_allocate(new_size * sizeof(kmp_taskdata_t *));
313 
314   int i, j;
315   for (i = thread_data->td.td_deque_head, j = 0; j < size;
316        i = (i + 1) & TASK_DEQUE_MASK(thread_data->td), j++)
317     new_deque[j] = thread_data->td.td_deque[i];
318 
319   __kmp_free(thread_data->td.td_deque);
320 
321   thread_data->td.td_deque_head = 0;
322   thread_data->td.td_deque_tail = size;
323   thread_data->td.td_deque = new_deque;
324   thread_data->td.td_deque_size = new_size;
325 }
326 
327 //  __kmp_push_task: Add a task to the thread's deque
328 static kmp_int32 __kmp_push_task(kmp_int32 gtid, kmp_task_t *task) {
329   kmp_info_t *thread = __kmp_threads[gtid];
330   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
331   kmp_task_team_t *task_team = thread->th.th_task_team;
332   kmp_int32 tid = __kmp_tid_from_gtid(gtid);
333   kmp_thread_data_t *thread_data;
334 
335   KA_TRACE(20,
336            ("__kmp_push_task: T#%d trying to push task %p.\n", gtid, taskdata));
337 
338   if (taskdata->td_flags.tiedness == TASK_UNTIED) {
339     // untied task needs to increment counter so that the task structure is not
340     // freed prematurely
341     kmp_int32 counter = 1 + KMP_ATOMIC_INC(&taskdata->td_untied_count);
342     KMP_DEBUG_USE_VAR(counter);
343     KA_TRACE(
344         20,
345         ("__kmp_push_task: T#%d untied_count (%d) incremented for task %p\n",
346          gtid, counter, taskdata));
347   }
348 
349   // The first check avoids building task_team thread data if serialized
350   if (taskdata->td_flags.task_serial) {
351     KA_TRACE(20, ("__kmp_push_task: T#%d team serialized; returning "
352                   "TASK_NOT_PUSHED for task %p\n",
353                   gtid, taskdata));
354     return TASK_NOT_PUSHED;
355   }
356 
357   // Now that serialized tasks have returned, we can assume that we are not in
358   // immediate exec mode
359   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
360   if (!KMP_TASKING_ENABLED(task_team)) {
361     __kmp_enable_tasking(task_team, thread);
362   }
363   KMP_DEBUG_ASSERT(TCR_4(task_team->tt.tt_found_tasks) == TRUE);
364   KMP_DEBUG_ASSERT(TCR_PTR(task_team->tt.tt_threads_data) != NULL);
365 
366   // Find tasking deque specific to encountering thread
367   thread_data = &task_team->tt.tt_threads_data[tid];
368 
369   // No lock needed since only owner can allocate
370   if (thread_data->td.td_deque == NULL) {
371     __kmp_alloc_task_deque(thread, thread_data);
372   }
373 
374   int locked = 0;
375   // Check if deque is full
376   if (TCR_4(thread_data->td.td_deque_ntasks) >=
377       TASK_DEQUE_SIZE(thread_data->td)) {
378     if (__kmp_task_is_allowed(gtid, __kmp_task_stealing_constraint, taskdata,
379                               thread->th.th_current_task)) {
380       KA_TRACE(20, ("__kmp_push_task: T#%d deque is full; returning "
381                     "TASK_NOT_PUSHED for task %p\n",
382                     gtid, taskdata));
383       return TASK_NOT_PUSHED;
384     } else {
385       __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
386       locked = 1;
387       // expand deque to push the task which is not allowed to execute
388       __kmp_realloc_task_deque(thread, thread_data);
389     }
390   }
391   // Lock the deque for the task push operation
392   if (!locked) {
393     __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
394 #if OMP_45_ENABLED
395     // Need to recheck as we can get a proxy task from thread outside of OpenMP
396     if (TCR_4(thread_data->td.td_deque_ntasks) >=
397         TASK_DEQUE_SIZE(thread_data->td)) {
398       if (__kmp_task_is_allowed(gtid, __kmp_task_stealing_constraint, taskdata,
399                                 thread->th.th_current_task)) {
400         __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
401         KA_TRACE(20, ("__kmp_push_task: T#%d deque is full on 2nd check; "
402                       "returning TASK_NOT_PUSHED for task %p\n",
403                       gtid, taskdata));
404         return TASK_NOT_PUSHED;
405       } else {
406         // expand deque to push the task which is not allowed to execute
407         __kmp_realloc_task_deque(thread, thread_data);
408       }
409     }
410 #endif
411   }
412   // Must have room since no thread can add tasks but calling thread
413   KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) <
414                    TASK_DEQUE_SIZE(thread_data->td));
415 
416   thread_data->td.td_deque[thread_data->td.td_deque_tail] =
417       taskdata; // Push taskdata
418   // Wrap index.
419   thread_data->td.td_deque_tail =
420       (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td);
421   TCW_4(thread_data->td.td_deque_ntasks,
422         TCR_4(thread_data->td.td_deque_ntasks) + 1); // Adjust task count
423 
424   KA_TRACE(20, ("__kmp_push_task: T#%d returning TASK_SUCCESSFULLY_PUSHED: "
425                 "task=%p ntasks=%d head=%u tail=%u\n",
426                 gtid, taskdata, thread_data->td.td_deque_ntasks,
427                 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
428 
429   __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
430 
431   return TASK_SUCCESSFULLY_PUSHED;
432 }
433 
434 // __kmp_pop_current_task_from_thread: set up current task from called thread
435 // when team ends
436 //
437 // this_thr: thread structure to set current_task in.
438 void __kmp_pop_current_task_from_thread(kmp_info_t *this_thr) {
439   KF_TRACE(10, ("__kmp_pop_current_task_from_thread(enter): T#%d "
440                 "this_thread=%p, curtask=%p, "
441                 "curtask_parent=%p\n",
442                 0, this_thr, this_thr->th.th_current_task,
443                 this_thr->th.th_current_task->td_parent));
444 
445   this_thr->th.th_current_task = this_thr->th.th_current_task->td_parent;
446 
447   KF_TRACE(10, ("__kmp_pop_current_task_from_thread(exit): T#%d "
448                 "this_thread=%p, curtask=%p, "
449                 "curtask_parent=%p\n",
450                 0, this_thr, this_thr->th.th_current_task,
451                 this_thr->th.th_current_task->td_parent));
452 }
453 
454 // __kmp_push_current_task_to_thread: set up current task in called thread for a
455 // new team
456 //
457 // this_thr: thread structure to set up
458 // team: team for implicit task data
459 // tid: thread within team to set up
460 void __kmp_push_current_task_to_thread(kmp_info_t *this_thr, kmp_team_t *team,
461                                        int tid) {
462   // current task of the thread is a parent of the new just created implicit
463   // tasks of new team
464   KF_TRACE(10, ("__kmp_push_current_task_to_thread(enter): T#%d this_thread=%p "
465                 "curtask=%p "
466                 "parent_task=%p\n",
467                 tid, this_thr, this_thr->th.th_current_task,
468                 team->t.t_implicit_task_taskdata[tid].td_parent));
469 
470   KMP_DEBUG_ASSERT(this_thr != NULL);
471 
472   if (tid == 0) {
473     if (this_thr->th.th_current_task != &team->t.t_implicit_task_taskdata[0]) {
474       team->t.t_implicit_task_taskdata[0].td_parent =
475           this_thr->th.th_current_task;
476       this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[0];
477     }
478   } else {
479     team->t.t_implicit_task_taskdata[tid].td_parent =
480         team->t.t_implicit_task_taskdata[0].td_parent;
481     this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[tid];
482   }
483 
484   KF_TRACE(10, ("__kmp_push_current_task_to_thread(exit): T#%d this_thread=%p "
485                 "curtask=%p "
486                 "parent_task=%p\n",
487                 tid, this_thr, this_thr->th.th_current_task,
488                 team->t.t_implicit_task_taskdata[tid].td_parent));
489 }
490 
491 // __kmp_task_start: bookkeeping for a task starting execution
492 //
493 // GTID: global thread id of calling thread
494 // task: task starting execution
495 // current_task: task suspending
496 static void __kmp_task_start(kmp_int32 gtid, kmp_task_t *task,
497                              kmp_taskdata_t *current_task) {
498   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
499   kmp_info_t *thread = __kmp_threads[gtid];
500 
501   KA_TRACE(10,
502            ("__kmp_task_start(enter): T#%d starting task %p: current_task=%p\n",
503             gtid, taskdata, current_task));
504 
505   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
506 
507   // mark currently executing task as suspended
508   // TODO: GEH - make sure root team implicit task is initialized properly.
509   // KMP_DEBUG_ASSERT( current_task -> td_flags.executing == 1 );
510   current_task->td_flags.executing = 0;
511 
512 // Add task to stack if tied
513 #ifdef BUILD_TIED_TASK_STACK
514   if (taskdata->td_flags.tiedness == TASK_TIED) {
515     __kmp_push_task_stack(gtid, thread, taskdata);
516   }
517 #endif /* BUILD_TIED_TASK_STACK */
518 
519   // mark starting task as executing and as current task
520   thread->th.th_current_task = taskdata;
521 
522   KMP_DEBUG_ASSERT(taskdata->td_flags.started == 0 ||
523                    taskdata->td_flags.tiedness == TASK_UNTIED);
524   KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0 ||
525                    taskdata->td_flags.tiedness == TASK_UNTIED);
526   taskdata->td_flags.started = 1;
527   taskdata->td_flags.executing = 1;
528   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
529   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
530 
531   // GEH TODO: shouldn't we pass some sort of location identifier here?
532   // APT: yes, we will pass location here.
533   // need to store current thread state (in a thread or taskdata structure)
534   // before setting work_state, otherwise wrong state is set after end of task
535 
536   KA_TRACE(10, ("__kmp_task_start(exit): T#%d task=%p\n", gtid, taskdata));
537 
538   return;
539 }
540 
541 #if OMPT_SUPPORT
542 //------------------------------------------------------------------------------
543 // __ompt_task_init:
544 //   Initialize OMPT fields maintained by a task. This will only be called after
545 //   ompt_start_tool, so we already know whether ompt is enabled or not.
546 
547 static inline void __ompt_task_init(kmp_taskdata_t *task, int tid) {
548   // The calls to __ompt_task_init already have the ompt_enabled condition.
549   task->ompt_task_info.task_data.value = 0;
550   task->ompt_task_info.frame.exit_frame = NULL;
551   task->ompt_task_info.frame.enter_frame = NULL;
552 #if OMP_40_ENABLED
553   task->ompt_task_info.ndeps = 0;
554   task->ompt_task_info.deps = NULL;
555 #endif /* OMP_40_ENABLED */
556 }
557 
558 // __ompt_task_start:
559 //   Build and trigger task-begin event
560 static inline void __ompt_task_start(kmp_task_t *task,
561                                      kmp_taskdata_t *current_task,
562                                      kmp_int32 gtid) {
563   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
564   ompt_task_status_t status = ompt_task_switch;
565   if (__kmp_threads[gtid]->th.ompt_thread_info.ompt_task_yielded) {
566     status = ompt_task_yield;
567     __kmp_threads[gtid]->th.ompt_thread_info.ompt_task_yielded = 0;
568   }
569   /* let OMPT know that we're about to run this task */
570   if (ompt_enabled.ompt_callback_task_schedule) {
571     ompt_callbacks.ompt_callback(ompt_callback_task_schedule)(
572         &(current_task->ompt_task_info.task_data), status,
573         &(taskdata->ompt_task_info.task_data));
574   }
575   taskdata->ompt_task_info.scheduling_parent = current_task;
576 }
577 
578 // __ompt_task_finish:
579 //   Build and trigger final task-schedule event
580 static inline void
581 __ompt_task_finish(kmp_task_t *task, kmp_taskdata_t *resumed_task,
582                    ompt_task_status_t status = ompt_task_complete) {
583   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
584   if (__kmp_omp_cancellation && taskdata->td_taskgroup &&
585       taskdata->td_taskgroup->cancel_request == cancel_taskgroup) {
586     status = ompt_task_cancel;
587   }
588 
589   /* let OMPT know that we're returning to the callee task */
590   if (ompt_enabled.ompt_callback_task_schedule) {
591     ompt_callbacks.ompt_callback(ompt_callback_task_schedule)(
592         &(taskdata->ompt_task_info.task_data), status,
593         &((resumed_task ? resumed_task
594                         : (taskdata->ompt_task_info.scheduling_parent
595                                ? taskdata->ompt_task_info.scheduling_parent
596                                : taskdata->td_parent))
597               ->ompt_task_info.task_data));
598   }
599 }
600 #endif
601 
602 template <bool ompt>
603 static void __kmpc_omp_task_begin_if0_template(ident_t *loc_ref, kmp_int32 gtid,
604                                                kmp_task_t *task,
605                                                void *frame_address,
606                                                void *return_address) {
607   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
608   kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
609 
610   KA_TRACE(10, ("__kmpc_omp_task_begin_if0(enter): T#%d loc=%p task=%p "
611                 "current_task=%p\n",
612                 gtid, loc_ref, taskdata, current_task));
613 
614   if (taskdata->td_flags.tiedness == TASK_UNTIED) {
615     // untied task needs to increment counter so that the task structure is not
616     // freed prematurely
617     kmp_int32 counter = 1 + KMP_ATOMIC_INC(&taskdata->td_untied_count);
618     KMP_DEBUG_USE_VAR(counter);
619     KA_TRACE(20, ("__kmpc_omp_task_begin_if0: T#%d untied_count (%d) "
620                   "incremented for task %p\n",
621                   gtid, counter, taskdata));
622   }
623 
624   taskdata->td_flags.task_serial =
625       1; // Execute this task immediately, not deferred.
626   __kmp_task_start(gtid, task, current_task);
627 
628 #if OMPT_SUPPORT
629   if (ompt) {
630     if (current_task->ompt_task_info.frame.enter_frame == NULL) {
631       current_task->ompt_task_info.frame.enter_frame =
632           taskdata->ompt_task_info.frame.exit_frame = frame_address;
633     }
634     if (ompt_enabled.ompt_callback_task_create) {
635       ompt_task_info_t *parent_info = &(current_task->ompt_task_info);
636       ompt_callbacks.ompt_callback(ompt_callback_task_create)(
637           &(parent_info->task_data), &(parent_info->frame),
638           &(taskdata->ompt_task_info.task_data),
639           ompt_task_explicit | TASK_TYPE_DETAILS_FORMAT(taskdata), 0,
640           return_address);
641     }
642     __ompt_task_start(task, current_task, gtid);
643   }
644 #endif // OMPT_SUPPORT
645 
646   KA_TRACE(10, ("__kmpc_omp_task_begin_if0(exit): T#%d loc=%p task=%p,\n", gtid,
647                 loc_ref, taskdata));
648 }
649 
650 #if OMPT_SUPPORT
651 OMPT_NOINLINE
652 static void __kmpc_omp_task_begin_if0_ompt(ident_t *loc_ref, kmp_int32 gtid,
653                                            kmp_task_t *task,
654                                            void *frame_address,
655                                            void *return_address) {
656   __kmpc_omp_task_begin_if0_template<true>(loc_ref, gtid, task, frame_address,
657                                            return_address);
658 }
659 #endif // OMPT_SUPPORT
660 
661 // __kmpc_omp_task_begin_if0: report that a given serialized task has started
662 // execution
663 //
664 // loc_ref: source location information; points to beginning of task block.
665 // gtid: global thread number.
666 // task: task thunk for the started task.
667 void __kmpc_omp_task_begin_if0(ident_t *loc_ref, kmp_int32 gtid,
668                                kmp_task_t *task) {
669 #if OMPT_SUPPORT
670   if (UNLIKELY(ompt_enabled.enabled)) {
671     OMPT_STORE_RETURN_ADDRESS(gtid);
672     __kmpc_omp_task_begin_if0_ompt(loc_ref, gtid, task,
673                                    OMPT_GET_FRAME_ADDRESS(1),
674                                    OMPT_LOAD_RETURN_ADDRESS(gtid));
675     return;
676   }
677 #endif
678   __kmpc_omp_task_begin_if0_template<false>(loc_ref, gtid, task, NULL, NULL);
679 }
680 
681 #ifdef TASK_UNUSED
682 // __kmpc_omp_task_begin: report that a given task has started execution
683 // NEVER GENERATED BY COMPILER, DEPRECATED!!!
684 void __kmpc_omp_task_begin(ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *task) {
685   kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
686 
687   KA_TRACE(
688       10,
689       ("__kmpc_omp_task_begin(enter): T#%d loc=%p task=%p current_task=%p\n",
690        gtid, loc_ref, KMP_TASK_TO_TASKDATA(task), current_task));
691 
692   __kmp_task_start(gtid, task, current_task);
693 
694   KA_TRACE(10, ("__kmpc_omp_task_begin(exit): T#%d loc=%p task=%p,\n", gtid,
695                 loc_ref, KMP_TASK_TO_TASKDATA(task)));
696   return;
697 }
698 #endif // TASK_UNUSED
699 
700 // __kmp_free_task: free the current task space and the space for shareds
701 //
702 // gtid: Global thread ID of calling thread
703 // taskdata: task to free
704 // thread: thread data structure of caller
705 static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata,
706                             kmp_info_t *thread) {
707   KA_TRACE(30, ("__kmp_free_task: T#%d freeing data from task %p\n", gtid,
708                 taskdata));
709 
710   // Check to make sure all flags and counters have the correct values
711   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
712   KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0);
713   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 1);
714   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
715   KMP_DEBUG_ASSERT(taskdata->td_allocated_child_tasks == 0 ||
716                    taskdata->td_flags.task_serial == 1);
717   KMP_DEBUG_ASSERT(taskdata->td_incomplete_child_tasks == 0);
718 
719   taskdata->td_flags.freed = 1;
720   ANNOTATE_HAPPENS_BEFORE(taskdata);
721 // deallocate the taskdata and shared variable blocks associated with this task
722 #if USE_FAST_MEMORY
723   __kmp_fast_free(thread, taskdata);
724 #else /* ! USE_FAST_MEMORY */
725   __kmp_thread_free(thread, taskdata);
726 #endif
727 
728   KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n", gtid, taskdata));
729 }
730 
731 // __kmp_free_task_and_ancestors: free the current task and ancestors without
732 // children
733 //
734 // gtid: Global thread ID of calling thread
735 // taskdata: task to free
736 // thread: thread data structure of caller
737 static void __kmp_free_task_and_ancestors(kmp_int32 gtid,
738                                           kmp_taskdata_t *taskdata,
739                                           kmp_info_t *thread) {
740 #if OMP_45_ENABLED
741   // Proxy tasks must always be allowed to free their parents
742   // because they can be run in background even in serial mode.
743   kmp_int32 team_serial =
744       (taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) &&
745       !taskdata->td_flags.proxy;
746 #else
747   kmp_int32 team_serial =
748       taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser;
749 #endif
750   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
751 
752   kmp_int32 children = KMP_ATOMIC_DEC(&taskdata->td_allocated_child_tasks) - 1;
753   KMP_DEBUG_ASSERT(children >= 0);
754 
755   // Now, go up the ancestor tree to see if any ancestors can now be freed.
756   while (children == 0) {
757     kmp_taskdata_t *parent_taskdata = taskdata->td_parent;
758 
759     KA_TRACE(20, ("__kmp_free_task_and_ancestors(enter): T#%d task %p complete "
760                   "and freeing itself\n",
761                   gtid, taskdata));
762 
763     // --- Deallocate my ancestor task ---
764     __kmp_free_task(gtid, taskdata, thread);
765 
766     taskdata = parent_taskdata;
767 
768     if (team_serial)
769       return;
770     // Stop checking ancestors at implicit task instead of walking up ancestor
771     // tree to avoid premature deallocation of ancestors.
772     if (taskdata->td_flags.tasktype == TASK_IMPLICIT) {
773       if (taskdata->td_dephash) { // do we need to cleanup dephash?
774         int children = KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks);
775         kmp_tasking_flags_t flags_old = taskdata->td_flags;
776         if (children == 0 && flags_old.complete == 1) {
777           kmp_tasking_flags_t flags_new = flags_old;
778           flags_new.complete = 0;
779           if (KMP_COMPARE_AND_STORE_ACQ32(
780                   RCAST(kmp_int32 *, &taskdata->td_flags),
781                   *RCAST(kmp_int32 *, &flags_old),
782                   *RCAST(kmp_int32 *, &flags_new))) {
783             KA_TRACE(100, ("__kmp_free_task_and_ancestors: T#%d cleans "
784                            "dephash of implicit task %p\n",
785                            gtid, taskdata));
786             // cleanup dephash of finished implicit task
787             __kmp_dephash_free_entries(thread, taskdata->td_dephash);
788           }
789         }
790       }
791       return;
792     }
793     // Predecrement simulated by "- 1" calculation
794     children = KMP_ATOMIC_DEC(&taskdata->td_allocated_child_tasks) - 1;
795     KMP_DEBUG_ASSERT(children >= 0);
796   }
797 
798   KA_TRACE(
799       20, ("__kmp_free_task_and_ancestors(exit): T#%d task %p has %d children; "
800            "not freeing it yet\n",
801            gtid, taskdata, children));
802 }
803 
804 // __kmp_task_finish: bookkeeping to do when a task finishes execution
805 //
806 // gtid: global thread ID for calling thread
807 // task: task to be finished
808 // resumed_task: task to be resumed.  (may be NULL if task is serialized)
809 template <bool ompt>
810 static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
811                               kmp_taskdata_t *resumed_task) {
812   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
813   kmp_info_t *thread = __kmp_threads[gtid];
814   kmp_task_team_t *task_team =
815       thread->th.th_task_team; // might be NULL for serial teams...
816   kmp_int32 children = 0;
817 
818   KA_TRACE(10, ("__kmp_task_finish(enter): T#%d finishing task %p and resuming "
819                 "task %p\n",
820                 gtid, taskdata, resumed_task));
821 
822   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
823 
824 // Pop task from stack if tied
825 #ifdef BUILD_TIED_TASK_STACK
826   if (taskdata->td_flags.tiedness == TASK_TIED) {
827     __kmp_pop_task_stack(gtid, thread, taskdata);
828   }
829 #endif /* BUILD_TIED_TASK_STACK */
830 
831   if (taskdata->td_flags.tiedness == TASK_UNTIED) {
832     // untied task needs to check the counter so that the task structure is not
833     // freed prematurely
834     kmp_int32 counter = KMP_ATOMIC_DEC(&taskdata->td_untied_count) - 1;
835     KA_TRACE(
836         20,
837         ("__kmp_task_finish: T#%d untied_count (%d) decremented for task %p\n",
838          gtid, counter, taskdata));
839     if (counter > 0) {
840       // untied task is not done, to be continued possibly by other thread, do
841       // not free it now
842       if (resumed_task == NULL) {
843         KMP_DEBUG_ASSERT(taskdata->td_flags.task_serial);
844         resumed_task = taskdata->td_parent; // In a serialized task, the resumed
845         // task is the parent
846       }
847       thread->th.th_current_task = resumed_task; // restore current_task
848       resumed_task->td_flags.executing = 1; // resume previous task
849       KA_TRACE(10, ("__kmp_task_finish(exit): T#%d partially done task %p, "
850                     "resuming task %p\n",
851                     gtid, taskdata, resumed_task));
852       return;
853     }
854   }
855 #if OMPT_SUPPORT
856   if (ompt)
857     __ompt_task_finish(task, resumed_task);
858 #endif
859 
860   // Check mutexinoutset dependencies, release locks
861   kmp_depnode_t *node = taskdata->td_depnode;
862   if (node && (node->dn.mtx_num_locks < 0)) {
863     // negative num_locks means all locks were acquired
864     node->dn.mtx_num_locks = -node->dn.mtx_num_locks;
865     for (int i = node->dn.mtx_num_locks - 1; i >= 0; --i) {
866       KMP_DEBUG_ASSERT(node->dn.mtx_locks[i] != NULL);
867       __kmp_release_lock(node->dn.mtx_locks[i], gtid);
868     }
869   }
870 
871   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
872   taskdata->td_flags.complete = 1; // mark the task as completed
873   KMP_DEBUG_ASSERT(taskdata->td_flags.started == 1);
874   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
875 
876   // Only need to keep track of count if team parallel and tasking not
877   // serialized
878   if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) {
879     // Predecrement simulated by "- 1" calculation
880     children =
881         KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks) - 1;
882     KMP_DEBUG_ASSERT(children >= 0);
883 #if OMP_40_ENABLED
884     if (taskdata->td_taskgroup)
885       KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
886     __kmp_release_deps(gtid, taskdata);
887 #if OMP_45_ENABLED
888   } else if (task_team && task_team->tt.tt_found_proxy_tasks) {
889     // if we found proxy tasks there could exist a dependency chain
890     // with the proxy task as origin
891     __kmp_release_deps(gtid, taskdata);
892 #endif // OMP_45_ENABLED
893 #endif // OMP_40_ENABLED
894   }
895 
896   // td_flags.executing must be marked as 0 after __kmp_release_deps has been
897   // called. Othertwise, if a task is executed immediately from the release_deps
898   // code, the flag will be reset to 1 again by this same function
899   KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 1);
900   taskdata->td_flags.executing = 0; // suspend the finishing task
901 
902   KA_TRACE(
903       20, ("__kmp_task_finish: T#%d finished task %p, %d incomplete children\n",
904            gtid, taskdata, children));
905 
906 #if OMP_40_ENABLED
907   /* If the tasks' destructor thunk flag has been set, we need to invoke the
908      destructor thunk that has been generated by the compiler. The code is
909      placed here, since at this point other tasks might have been released
910      hence overlapping the destructor invokations with some other work in the
911      released tasks.  The OpenMP spec is not specific on when the destructors
912      are invoked, so we should be free to choose. */
913   if (taskdata->td_flags.destructors_thunk) {
914     kmp_routine_entry_t destr_thunk = task->data1.destructors;
915     KMP_ASSERT(destr_thunk);
916     destr_thunk(gtid, task);
917   }
918 #endif // OMP_40_ENABLED
919 
920   // bookkeeping for resuming task:
921   // GEH - note tasking_ser => task_serial
922   KMP_DEBUG_ASSERT(
923       (taskdata->td_flags.tasking_ser || taskdata->td_flags.task_serial) ==
924       taskdata->td_flags.task_serial);
925   if (taskdata->td_flags.task_serial) {
926     if (resumed_task == NULL) {
927       resumed_task = taskdata->td_parent; // In a serialized task, the resumed
928       // task is the parent
929     }
930   } else {
931     KMP_DEBUG_ASSERT(resumed_task !=
932                      NULL); // verify that resumed task is passed as arguemnt
933   }
934 
935   // Free this task and then ancestor tasks if they have no children.
936   // Restore th_current_task first as suggested by John:
937   // johnmc: if an asynchronous inquiry peers into the runtime system
938   // it doesn't see the freed task as the current task.
939   thread->th.th_current_task = resumed_task;
940   __kmp_free_task_and_ancestors(gtid, taskdata, thread);
941 
942   // TODO: GEH - make sure root team implicit task is initialized properly.
943   // KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 );
944   resumed_task->td_flags.executing = 1; // resume previous task
945 
946   KA_TRACE(
947       10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n",
948            gtid, taskdata, resumed_task));
949 
950   return;
951 }
952 
953 template <bool ompt>
954 static void __kmpc_omp_task_complete_if0_template(ident_t *loc_ref,
955                                                   kmp_int32 gtid,
956                                                   kmp_task_t *task) {
957   KA_TRACE(10, ("__kmpc_omp_task_complete_if0(enter): T#%d loc=%p task=%p\n",
958                 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task)));
959   // this routine will provide task to resume
960   __kmp_task_finish<ompt>(gtid, task, NULL);
961 
962   KA_TRACE(10, ("__kmpc_omp_task_complete_if0(exit): T#%d loc=%p task=%p\n",
963                 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task)));
964 
965 #if OMPT_SUPPORT
966   if (ompt) {
967     omp_frame_t *ompt_frame;
968     __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
969     ompt_frame->enter_frame = NULL;
970   }
971 #endif
972 
973   return;
974 }
975 
976 #if OMPT_SUPPORT
977 OMPT_NOINLINE
978 void __kmpc_omp_task_complete_if0_ompt(ident_t *loc_ref, kmp_int32 gtid,
979                                        kmp_task_t *task) {
980   __kmpc_omp_task_complete_if0_template<true>(loc_ref, gtid, task);
981 }
982 #endif // OMPT_SUPPORT
983 
984 // __kmpc_omp_task_complete_if0: report that a task has completed execution
985 //
986 // loc_ref: source location information; points to end of task block.
987 // gtid: global thread number.
988 // task: task thunk for the completed task.
989 void __kmpc_omp_task_complete_if0(ident_t *loc_ref, kmp_int32 gtid,
990                                   kmp_task_t *task) {
991 #if OMPT_SUPPORT
992   if (UNLIKELY(ompt_enabled.enabled)) {
993     __kmpc_omp_task_complete_if0_ompt(loc_ref, gtid, task);
994     return;
995   }
996 #endif
997   __kmpc_omp_task_complete_if0_template<false>(loc_ref, gtid, task);
998 }
999 
1000 #ifdef TASK_UNUSED
1001 // __kmpc_omp_task_complete: report that a task has completed execution
1002 // NEVER GENERATED BY COMPILER, DEPRECATED!!!
1003 void __kmpc_omp_task_complete(ident_t *loc_ref, kmp_int32 gtid,
1004                               kmp_task_t *task) {
1005   KA_TRACE(10, ("__kmpc_omp_task_complete(enter): T#%d loc=%p task=%p\n", gtid,
1006                 loc_ref, KMP_TASK_TO_TASKDATA(task)));
1007 
1008   __kmp_task_finish<false>(gtid, task,
1009                            NULL); // Not sure how to find task to resume
1010 
1011   KA_TRACE(10, ("__kmpc_omp_task_complete(exit): T#%d loc=%p task=%p\n", gtid,
1012                 loc_ref, KMP_TASK_TO_TASKDATA(task)));
1013   return;
1014 }
1015 #endif // TASK_UNUSED
1016 
1017 // __kmp_init_implicit_task: Initialize the appropriate fields in the implicit
1018 // task for a given thread
1019 //
1020 // loc_ref:  reference to source location of parallel region
1021 // this_thr:  thread data structure corresponding to implicit task
1022 // team: team for this_thr
1023 // tid: thread id of given thread within team
1024 // set_curr_task: TRUE if need to push current task to thread
1025 // NOTE: Routine does not set up the implicit task ICVS.  This is assumed to
1026 // have already been done elsewhere.
1027 // TODO: Get better loc_ref.  Value passed in may be NULL
1028 void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr,
1029                               kmp_team_t *team, int tid, int set_curr_task) {
1030   kmp_taskdata_t *task = &team->t.t_implicit_task_taskdata[tid];
1031 
1032   KF_TRACE(
1033       10,
1034       ("__kmp_init_implicit_task(enter): T#:%d team=%p task=%p, reinit=%s\n",
1035        tid, team, task, set_curr_task ? "TRUE" : "FALSE"));
1036 
1037   task->td_task_id = KMP_GEN_TASK_ID();
1038   task->td_team = team;
1039   //    task->td_parent   = NULL;  // fix for CQ230101 (broken parent task info
1040   //    in debugger)
1041   task->td_ident = loc_ref;
1042   task->td_taskwait_ident = NULL;
1043   task->td_taskwait_counter = 0;
1044   task->td_taskwait_thread = 0;
1045 
1046   task->td_flags.tiedness = TASK_TIED;
1047   task->td_flags.tasktype = TASK_IMPLICIT;
1048 #if OMP_45_ENABLED
1049   task->td_flags.proxy = TASK_FULL;
1050 #endif
1051 
1052   // All implicit tasks are executed immediately, not deferred
1053   task->td_flags.task_serial = 1;
1054   task->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec);
1055   task->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0;
1056 
1057   task->td_flags.started = 1;
1058   task->td_flags.executing = 1;
1059   task->td_flags.complete = 0;
1060   task->td_flags.freed = 0;
1061 
1062 #if OMP_40_ENABLED
1063   task->td_depnode = NULL;
1064 #endif
1065   task->td_last_tied = task;
1066 
1067   if (set_curr_task) { // only do this init first time thread is created
1068     KMP_ATOMIC_ST_REL(&task->td_incomplete_child_tasks, 0);
1069     // Not used: don't need to deallocate implicit task
1070     KMP_ATOMIC_ST_REL(&task->td_allocated_child_tasks, 0);
1071 #if OMP_40_ENABLED
1072     task->td_taskgroup = NULL; // An implicit task does not have taskgroup
1073     task->td_dephash = NULL;
1074 #endif
1075     __kmp_push_current_task_to_thread(this_thr, team, tid);
1076   } else {
1077     KMP_DEBUG_ASSERT(task->td_incomplete_child_tasks == 0);
1078     KMP_DEBUG_ASSERT(task->td_allocated_child_tasks == 0);
1079   }
1080 
1081 #if OMPT_SUPPORT
1082   if (UNLIKELY(ompt_enabled.enabled))
1083     __ompt_task_init(task, tid);
1084 #endif
1085 
1086   KF_TRACE(10, ("__kmp_init_implicit_task(exit): T#:%d team=%p task=%p\n", tid,
1087                 team, task));
1088 }
1089 
1090 // __kmp_finish_implicit_task: Release resources associated to implicit tasks
1091 // at the end of parallel regions. Some resources are kept for reuse in the next
1092 // parallel region.
1093 //
1094 // thread:  thread data structure corresponding to implicit task
1095 void __kmp_finish_implicit_task(kmp_info_t *thread) {
1096   kmp_taskdata_t *task = thread->th.th_current_task;
1097   if (task->td_dephash) {
1098     int children;
1099     task->td_flags.complete = 1;
1100     children = KMP_ATOMIC_LD_ACQ(&task->td_incomplete_child_tasks);
1101     kmp_tasking_flags_t flags_old = task->td_flags;
1102     if (children == 0 && flags_old.complete == 1) {
1103       kmp_tasking_flags_t flags_new = flags_old;
1104       flags_new.complete = 0;
1105       if (KMP_COMPARE_AND_STORE_ACQ32(RCAST(kmp_int32 *, &task->td_flags),
1106                                       *RCAST(kmp_int32 *, &flags_old),
1107                                       *RCAST(kmp_int32 *, &flags_new))) {
1108         KA_TRACE(100, ("__kmp_finish_implicit_task: T#%d cleans "
1109                        "dephash of implicit task %p\n",
1110                        thread->th.th_info.ds.ds_gtid, task));
1111         __kmp_dephash_free_entries(thread, task->td_dephash);
1112       }
1113     }
1114   }
1115 }
1116 
1117 // __kmp_free_implicit_task: Release resources associated to implicit tasks
1118 // when these are destroyed regions
1119 //
1120 // thread:  thread data structure corresponding to implicit task
1121 void __kmp_free_implicit_task(kmp_info_t *thread) {
1122   kmp_taskdata_t *task = thread->th.th_current_task;
1123   if (task && task->td_dephash) {
1124     __kmp_dephash_free(thread, task->td_dephash);
1125     task->td_dephash = NULL;
1126   }
1127 }
1128 
1129 // Round up a size to a power of two specified by val: Used to insert padding
1130 // between structures co-allocated using a single malloc() call
1131 static size_t __kmp_round_up_to_val(size_t size, size_t val) {
1132   if (size & (val - 1)) {
1133     size &= ~(val - 1);
1134     if (size <= KMP_SIZE_T_MAX - val) {
1135       size += val; // Round up if there is no overflow.
1136     }
1137   }
1138   return size;
1139 } // __kmp_round_up_to_va
1140 
1141 // __kmp_task_alloc: Allocate the taskdata and task data structures for a task
1142 //
1143 // loc_ref: source location information
1144 // gtid: global thread number.
1145 // flags: include tiedness & task type (explicit vs. implicit) of the ''new''
1146 // task encountered. Converted from kmp_int32 to kmp_tasking_flags_t in routine.
1147 // sizeof_kmp_task_t:  Size in bytes of kmp_task_t data structure including
1148 // private vars accessed in task.
1149 // sizeof_shareds:  Size in bytes of array of pointers to shared vars accessed
1150 // in task.
1151 // task_entry: Pointer to task code entry point generated by compiler.
1152 // returns: a pointer to the allocated kmp_task_t structure (task).
1153 kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
1154                              kmp_tasking_flags_t *flags,
1155                              size_t sizeof_kmp_task_t, size_t sizeof_shareds,
1156                              kmp_routine_entry_t task_entry) {
1157   kmp_task_t *task;
1158   kmp_taskdata_t *taskdata;
1159   kmp_info_t *thread = __kmp_threads[gtid];
1160   kmp_team_t *team = thread->th.th_team;
1161   kmp_taskdata_t *parent_task = thread->th.th_current_task;
1162   size_t shareds_offset;
1163 
1164   if (!TCR_4(__kmp_init_middle))
1165     __kmp_middle_initialize();
1166 
1167   KA_TRACE(10, ("__kmp_task_alloc(enter): T#%d loc=%p, flags=(0x%x) "
1168                 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
1169                 gtid, loc_ref, *((kmp_int32 *)flags), sizeof_kmp_task_t,
1170                 sizeof_shareds, task_entry));
1171 
1172   if (parent_task->td_flags.final) {
1173     if (flags->merged_if0) {
1174     }
1175     flags->final = 1;
1176   }
1177   if (flags->tiedness == TASK_UNTIED && !team->t.t_serialized) {
1178     // Untied task encountered causes the TSC algorithm to check entire deque of
1179     // the victim thread. If no untied task encountered, then checking the head
1180     // of the deque should be enough.
1181     KMP_CHECK_UPDATE(thread->th.th_task_team->tt.tt_untied_task_encountered, 1);
1182   }
1183 
1184 #if OMP_45_ENABLED
1185   if (flags->proxy == TASK_PROXY) {
1186     flags->tiedness = TASK_UNTIED;
1187     flags->merged_if0 = 1;
1188 
1189     /* are we running in a sequential parallel or tskm_immediate_exec... we need
1190        tasking support enabled */
1191     if ((thread->th.th_task_team) == NULL) {
1192       /* This should only happen if the team is serialized
1193           setup a task team and propagate it to the thread */
1194       KMP_DEBUG_ASSERT(team->t.t_serialized);
1195       KA_TRACE(30,
1196                ("T#%d creating task team in __kmp_task_alloc for proxy task\n",
1197                 gtid));
1198       __kmp_task_team_setup(
1199           thread, team,
1200           1); // 1 indicates setup the current team regardless of nthreads
1201       thread->th.th_task_team = team->t.t_task_team[thread->th.th_task_state];
1202     }
1203     kmp_task_team_t *task_team = thread->th.th_task_team;
1204 
1205     /* tasking must be enabled now as the task might not be pushed */
1206     if (!KMP_TASKING_ENABLED(task_team)) {
1207       KA_TRACE(
1208           30,
1209           ("T#%d enabling tasking in __kmp_task_alloc for proxy task\n", gtid));
1210       __kmp_enable_tasking(task_team, thread);
1211       kmp_int32 tid = thread->th.th_info.ds.ds_tid;
1212       kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid];
1213       // No lock needed since only owner can allocate
1214       if (thread_data->td.td_deque == NULL) {
1215         __kmp_alloc_task_deque(thread, thread_data);
1216       }
1217     }
1218 
1219     if (task_team->tt.tt_found_proxy_tasks == FALSE)
1220       TCW_4(task_team->tt.tt_found_proxy_tasks, TRUE);
1221   }
1222 #endif
1223 
1224   // Calculate shared structure offset including padding after kmp_task_t struct
1225   // to align pointers in shared struct
1226   shareds_offset = sizeof(kmp_taskdata_t) + sizeof_kmp_task_t;
1227   shareds_offset = __kmp_round_up_to_val(shareds_offset, sizeof(void *));
1228 
1229   // Allocate a kmp_taskdata_t block and a kmp_task_t block.
1230   KA_TRACE(30, ("__kmp_task_alloc: T#%d First malloc size: %ld\n", gtid,
1231                 shareds_offset));
1232   KA_TRACE(30, ("__kmp_task_alloc: T#%d Second malloc size: %ld\n", gtid,
1233                 sizeof_shareds));
1234 
1235 // Avoid double allocation here by combining shareds with taskdata
1236 #if USE_FAST_MEMORY
1237   taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, shareds_offset +
1238                                                                sizeof_shareds);
1239 #else /* ! USE_FAST_MEMORY */
1240   taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, shareds_offset +
1241                                                                sizeof_shareds);
1242 #endif /* USE_FAST_MEMORY */
1243   ANNOTATE_HAPPENS_AFTER(taskdata);
1244 
1245   task = KMP_TASKDATA_TO_TASK(taskdata);
1246 
1247 // Make sure task & taskdata are aligned appropriately
1248 #if KMP_ARCH_X86 || KMP_ARCH_PPC64 || !KMP_HAVE_QUAD
1249   KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(double) - 1)) == 0);
1250   KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(double) - 1)) == 0);
1251 #else
1252   KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(_Quad) - 1)) == 0);
1253   KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(_Quad) - 1)) == 0);
1254 #endif
1255   if (sizeof_shareds > 0) {
1256     // Avoid double allocation here by combining shareds with taskdata
1257     task->shareds = &((char *)taskdata)[shareds_offset];
1258     // Make sure shareds struct is aligned to pointer size
1259     KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) ==
1260                      0);
1261   } else {
1262     task->shareds = NULL;
1263   }
1264   task->routine = task_entry;
1265   task->part_id = 0; // AC: Always start with 0 part id
1266 
1267   taskdata->td_task_id = KMP_GEN_TASK_ID();
1268   taskdata->td_team = team;
1269   taskdata->td_alloc_thread = thread;
1270   taskdata->td_parent = parent_task;
1271   taskdata->td_level = parent_task->td_level + 1; // increment nesting level
1272   KMP_ATOMIC_ST_RLX(&taskdata->td_untied_count, 0);
1273   taskdata->td_ident = loc_ref;
1274   taskdata->td_taskwait_ident = NULL;
1275   taskdata->td_taskwait_counter = 0;
1276   taskdata->td_taskwait_thread = 0;
1277   KMP_DEBUG_ASSERT(taskdata->td_parent != NULL);
1278 #if OMP_45_ENABLED
1279   // avoid copying icvs for proxy tasks
1280   if (flags->proxy == TASK_FULL)
1281 #endif
1282     copy_icvs(&taskdata->td_icvs, &taskdata->td_parent->td_icvs);
1283 
1284   taskdata->td_flags.tiedness = flags->tiedness;
1285   taskdata->td_flags.final = flags->final;
1286   taskdata->td_flags.merged_if0 = flags->merged_if0;
1287 #if OMP_40_ENABLED
1288   taskdata->td_flags.destructors_thunk = flags->destructors_thunk;
1289 #endif // OMP_40_ENABLED
1290 #if OMP_45_ENABLED
1291   taskdata->td_flags.proxy = flags->proxy;
1292   taskdata->td_task_team = thread->th.th_task_team;
1293   taskdata->td_size_alloc = shareds_offset + sizeof_shareds;
1294 #endif
1295   taskdata->td_flags.tasktype = TASK_EXPLICIT;
1296 
1297   // GEH - TODO: fix this to copy parent task's value of tasking_ser flag
1298   taskdata->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec);
1299 
1300   // GEH - TODO: fix this to copy parent task's value of team_serial flag
1301   taskdata->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0;
1302 
1303   // GEH - Note we serialize the task if the team is serialized to make sure
1304   // implicit parallel region tasks are not left until program termination to
1305   // execute. Also, it helps locality to execute immediately.
1306 
1307   taskdata->td_flags.task_serial =
1308       (parent_task->td_flags.final || taskdata->td_flags.team_serial ||
1309        taskdata->td_flags.tasking_ser);
1310 
1311   taskdata->td_flags.started = 0;
1312   taskdata->td_flags.executing = 0;
1313   taskdata->td_flags.complete = 0;
1314   taskdata->td_flags.freed = 0;
1315 
1316   taskdata->td_flags.native = flags->native;
1317 
1318   KMP_ATOMIC_ST_RLX(&taskdata->td_incomplete_child_tasks, 0);
1319   // start at one because counts current task and children
1320   KMP_ATOMIC_ST_RLX(&taskdata->td_allocated_child_tasks, 1);
1321 #if OMP_40_ENABLED
1322   taskdata->td_taskgroup =
1323       parent_task->td_taskgroup; // task inherits taskgroup from the parent task
1324   taskdata->td_dephash = NULL;
1325   taskdata->td_depnode = NULL;
1326 #endif
1327   if (flags->tiedness == TASK_UNTIED)
1328     taskdata->td_last_tied = NULL; // will be set when the task is scheduled
1329   else
1330     taskdata->td_last_tied = taskdata;
1331 
1332 #if OMPT_SUPPORT
1333   if (UNLIKELY(ompt_enabled.enabled))
1334     __ompt_task_init(taskdata, gtid);
1335 #endif
1336 // Only need to keep track of child task counts if team parallel and tasking not
1337 // serialized or if it is a proxy task
1338 #if OMP_45_ENABLED
1339   if (flags->proxy == TASK_PROXY ||
1340       !(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser))
1341 #else
1342   if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser))
1343 #endif
1344   {
1345     KMP_ATOMIC_INC(&parent_task->td_incomplete_child_tasks);
1346 #if OMP_40_ENABLED
1347     if (parent_task->td_taskgroup)
1348       KMP_ATOMIC_INC(&parent_task->td_taskgroup->count);
1349 #endif
1350     // Only need to keep track of allocated child tasks for explicit tasks since
1351     // implicit not deallocated
1352     if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT) {
1353       KMP_ATOMIC_INC(&taskdata->td_parent->td_allocated_child_tasks);
1354     }
1355   }
1356 
1357   KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n",
1358                 gtid, taskdata, taskdata->td_parent));
1359   ANNOTATE_HAPPENS_BEFORE(task);
1360 
1361   return task;
1362 }
1363 
1364 kmp_task_t *__kmpc_omp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
1365                                   kmp_int32 flags, size_t sizeof_kmp_task_t,
1366                                   size_t sizeof_shareds,
1367                                   kmp_routine_entry_t task_entry) {
1368   kmp_task_t *retval;
1369   kmp_tasking_flags_t *input_flags = (kmp_tasking_flags_t *)&flags;
1370 
1371   input_flags->native = FALSE;
1372 // __kmp_task_alloc() sets up all other runtime flags
1373 
1374 #if OMP_45_ENABLED
1375   KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s %s) "
1376                 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
1377                 gtid, loc_ref, input_flags->tiedness ? "tied  " : "untied",
1378                 input_flags->proxy ? "proxy" : "", sizeof_kmp_task_t,
1379                 sizeof_shareds, task_entry));
1380 #else
1381   KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s) "
1382                 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
1383                 gtid, loc_ref, input_flags->tiedness ? "tied  " : "untied",
1384                 sizeof_kmp_task_t, sizeof_shareds, task_entry));
1385 #endif
1386 
1387   retval = __kmp_task_alloc(loc_ref, gtid, input_flags, sizeof_kmp_task_t,
1388                             sizeof_shareds, task_entry);
1389 
1390   KA_TRACE(20, ("__kmpc_omp_task_alloc(exit): T#%d retval %p\n", gtid, retval));
1391 
1392   return retval;
1393 }
1394 
1395 #if OMP_50_ENABLED
1396 /*!
1397 @ingroup TASKING
1398 @param loc_ref location of the original task directive
1399 @param gtid Global Thread ID of encountering thread
1400 @param new_task task thunk allocated by __kmpc_omp_task_alloc() for the ''new
1401 task''
1402 @param naffins Number of affinity items
1403 @param affin_list List of affinity items
1404 @return Returns non-zero if registering affinity information was not successful.
1405  Returns 0 if registration was successful
1406 This entry registers the affinity information attached to a task with the task
1407 thunk structure kmp_taskdata_t.
1408 */
1409 kmp_int32
1410 __kmpc_omp_reg_task_with_affinity(ident_t *loc_ref, kmp_int32 gtid,
1411                                   kmp_task_t *new_task, kmp_int32 naffins,
1412                                   kmp_task_affinity_info_t *affin_list) {
1413   return 0;
1414 }
1415 #endif
1416 
1417 //  __kmp_invoke_task: invoke the specified task
1418 //
1419 // gtid: global thread ID of caller
1420 // task: the task to invoke
1421 // current_task: the task to resume after task invokation
1422 static void __kmp_invoke_task(kmp_int32 gtid, kmp_task_t *task,
1423                               kmp_taskdata_t *current_task) {
1424   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
1425   kmp_info_t *thread;
1426 #if OMP_40_ENABLED
1427   int discard = 0 /* false */;
1428 #endif
1429   KA_TRACE(
1430       30, ("__kmp_invoke_task(enter): T#%d invoking task %p, current_task=%p\n",
1431            gtid, taskdata, current_task));
1432   KMP_DEBUG_ASSERT(task);
1433 #if OMP_45_ENABLED
1434   if (taskdata->td_flags.proxy == TASK_PROXY &&
1435       taskdata->td_flags.complete == 1) {
1436     // This is a proxy task that was already completed but it needs to run
1437     // its bottom-half finish
1438     KA_TRACE(
1439         30,
1440         ("__kmp_invoke_task: T#%d running bottom finish for proxy task %p\n",
1441          gtid, taskdata));
1442 
1443     __kmp_bottom_half_finish_proxy(gtid, task);
1444 
1445     KA_TRACE(30, ("__kmp_invoke_task(exit): T#%d completed bottom finish for "
1446                   "proxy task %p, resuming task %p\n",
1447                   gtid, taskdata, current_task));
1448 
1449     return;
1450   }
1451 #endif
1452 
1453 #if OMPT_SUPPORT
1454   // For untied tasks, the first task executed only calls __kmpc_omp_task and
1455   // does not execute code.
1456   ompt_thread_info_t oldInfo;
1457   if (UNLIKELY(ompt_enabled.enabled)) {
1458     // Store the threads states and restore them after the task
1459     thread = __kmp_threads[gtid];
1460     oldInfo = thread->th.ompt_thread_info;
1461     thread->th.ompt_thread_info.wait_id = 0;
1462     thread->th.ompt_thread_info.state = (thread->th.th_team_serialized)
1463                                             ? omp_state_work_serial
1464                                             : omp_state_work_parallel;
1465     taskdata->ompt_task_info.frame.exit_frame = OMPT_GET_FRAME_ADDRESS(0);
1466   }
1467 #endif
1468 
1469 #if OMP_45_ENABLED
1470   // Proxy tasks are not handled by the runtime
1471   if (taskdata->td_flags.proxy != TASK_PROXY) {
1472 #endif
1473     ANNOTATE_HAPPENS_AFTER(task);
1474     __kmp_task_start(gtid, task, current_task); // OMPT only if not discarded
1475 #if OMP_45_ENABLED
1476   }
1477 #endif
1478 
1479 #if OMP_40_ENABLED
1480   // TODO: cancel tasks if the parallel region has also been cancelled
1481   // TODO: check if this sequence can be hoisted above __kmp_task_start
1482   // if cancellation has been enabled for this run ...
1483   if (__kmp_omp_cancellation) {
1484     thread = __kmp_threads[gtid];
1485     kmp_team_t *this_team = thread->th.th_team;
1486     kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup;
1487     if ((taskgroup && taskgroup->cancel_request) ||
1488         (this_team->t.t_cancel_request == cancel_parallel)) {
1489 #if OMPT_SUPPORT && OMPT_OPTIONAL
1490       ompt_data_t *task_data;
1491       if (UNLIKELY(ompt_enabled.ompt_callback_cancel)) {
1492         __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL, NULL);
1493         ompt_callbacks.ompt_callback(ompt_callback_cancel)(
1494             task_data,
1495             ((taskgroup && taskgroup->cancel_request) ? ompt_cancel_taskgroup
1496                                                       : ompt_cancel_parallel) |
1497                 ompt_cancel_discarded_task,
1498             NULL);
1499       }
1500 #endif
1501       KMP_COUNT_BLOCK(TASK_cancelled);
1502       // this task belongs to a task group and we need to cancel it
1503       discard = 1 /* true */;
1504     }
1505   }
1506 
1507   // Invoke the task routine and pass in relevant data.
1508   // Thunks generated by gcc take a different argument list.
1509   if (!discard) {
1510     if (taskdata->td_flags.tiedness == TASK_UNTIED) {
1511       taskdata->td_last_tied = current_task->td_last_tied;
1512       KMP_DEBUG_ASSERT(taskdata->td_last_tied);
1513     }
1514 #if KMP_STATS_ENABLED
1515     KMP_COUNT_BLOCK(TASK_executed);
1516     switch (KMP_GET_THREAD_STATE()) {
1517     case FORK_JOIN_BARRIER:
1518       KMP_PUSH_PARTITIONED_TIMER(OMP_task_join_bar);
1519       break;
1520     case PLAIN_BARRIER:
1521       KMP_PUSH_PARTITIONED_TIMER(OMP_task_plain_bar);
1522       break;
1523     case TASKYIELD:
1524       KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskyield);
1525       break;
1526     case TASKWAIT:
1527       KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskwait);
1528       break;
1529     case TASKGROUP:
1530       KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskgroup);
1531       break;
1532     default:
1533       KMP_PUSH_PARTITIONED_TIMER(OMP_task_immediate);
1534       break;
1535     }
1536 #endif // KMP_STATS_ENABLED
1537 #endif // OMP_40_ENABLED
1538 
1539 // OMPT task begin
1540 #if OMPT_SUPPORT
1541     if (UNLIKELY(ompt_enabled.enabled))
1542       __ompt_task_start(task, current_task, gtid);
1543 #endif
1544 
1545 #if USE_ITT_BUILD && USE_ITT_NOTIFY
1546     kmp_uint64 cur_time;
1547     kmp_int32 kmp_itt_count_task =
1548         __kmp_forkjoin_frames_mode == 3 && !taskdata->td_flags.task_serial &&
1549         current_task->td_flags.tasktype == TASK_IMPLICIT;
1550     if (kmp_itt_count_task) {
1551       thread = __kmp_threads[gtid];
1552       // Time outer level explicit task on barrier for adjusting imbalance time
1553       if (thread->th.th_bar_arrive_time)
1554         cur_time = __itt_get_timestamp();
1555       else
1556         kmp_itt_count_task = 0; // thread is not on a barrier - skip timing
1557     }
1558 #endif
1559 
1560 #ifdef KMP_GOMP_COMPAT
1561     if (taskdata->td_flags.native) {
1562       ((void (*)(void *))(*(task->routine)))(task->shareds);
1563     } else
1564 #endif /* KMP_GOMP_COMPAT */
1565     {
1566       (*(task->routine))(gtid, task);
1567     }
1568     KMP_POP_PARTITIONED_TIMER();
1569 
1570 #if USE_ITT_BUILD && USE_ITT_NOTIFY
1571     if (kmp_itt_count_task) {
1572       // Barrier imbalance - adjust arrive time with the task duration
1573       thread->th.th_bar_arrive_time += (__itt_get_timestamp() - cur_time);
1574     }
1575 #endif
1576 
1577 #if OMP_40_ENABLED
1578   }
1579 #endif // OMP_40_ENABLED
1580 
1581 
1582 #if OMP_45_ENABLED
1583   // Proxy tasks are not handled by the runtime
1584   if (taskdata->td_flags.proxy != TASK_PROXY) {
1585 #endif
1586     ANNOTATE_HAPPENS_BEFORE(taskdata->td_parent);
1587 #if OMPT_SUPPORT
1588     if (UNLIKELY(ompt_enabled.enabled)) {
1589       thread->th.ompt_thread_info = oldInfo;
1590       if (taskdata->td_flags.tiedness == TASK_TIED) {
1591         taskdata->ompt_task_info.frame.exit_frame = NULL;
1592       }
1593       __kmp_task_finish<true>(gtid, task, current_task);
1594     } else
1595 #endif
1596       __kmp_task_finish<false>(gtid, task, current_task);
1597 #if OMP_45_ENABLED
1598   }
1599 #endif
1600 
1601   KA_TRACE(
1602       30,
1603       ("__kmp_invoke_task(exit): T#%d completed task %p, resuming task %p\n",
1604        gtid, taskdata, current_task));
1605   return;
1606 }
1607 
1608 // __kmpc_omp_task_parts: Schedule a thread-switchable task for execution
1609 //
1610 // loc_ref: location of original task pragma (ignored)
1611 // gtid: Global Thread ID of encountering thread
1612 // new_task: task thunk allocated by __kmp_omp_task_alloc() for the ''new task''
1613 // Returns:
1614 //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1615 //    be resumed later.
1616 //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1617 //    resumed later.
1618 kmp_int32 __kmpc_omp_task_parts(ident_t *loc_ref, kmp_int32 gtid,
1619                                 kmp_task_t *new_task) {
1620   kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1621 
1622   KA_TRACE(10, ("__kmpc_omp_task_parts(enter): T#%d loc=%p task=%p\n", gtid,
1623                 loc_ref, new_taskdata));
1624 
1625 #if OMPT_SUPPORT
1626   kmp_taskdata_t *parent;
1627   if (UNLIKELY(ompt_enabled.enabled)) {
1628     parent = new_taskdata->td_parent;
1629     if (ompt_enabled.ompt_callback_task_create) {
1630       ompt_data_t task_data = ompt_data_none;
1631       ompt_callbacks.ompt_callback(ompt_callback_task_create)(
1632           parent ? &(parent->ompt_task_info.task_data) : &task_data,
1633           parent ? &(parent->ompt_task_info.frame) : NULL,
1634           &(new_taskdata->ompt_task_info.task_data), ompt_task_explicit, 0,
1635           OMPT_GET_RETURN_ADDRESS(0));
1636     }
1637   }
1638 #endif
1639 
1640   /* Should we execute the new task or queue it? For now, let's just always try
1641      to queue it.  If the queue fills up, then we'll execute it.  */
1642 
1643   if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
1644   { // Execute this task immediately
1645     kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
1646     new_taskdata->td_flags.task_serial = 1;
1647     __kmp_invoke_task(gtid, new_task, current_task);
1648   }
1649 
1650   KA_TRACE(
1651       10,
1652       ("__kmpc_omp_task_parts(exit): T#%d returning TASK_CURRENT_NOT_QUEUED: "
1653        "loc=%p task=%p, return: TASK_CURRENT_NOT_QUEUED\n",
1654        gtid, loc_ref, new_taskdata));
1655 
1656   ANNOTATE_HAPPENS_BEFORE(new_task);
1657 #if OMPT_SUPPORT
1658   if (UNLIKELY(ompt_enabled.enabled)) {
1659     parent->ompt_task_info.frame.enter_frame = NULL;
1660   }
1661 #endif
1662   return TASK_CURRENT_NOT_QUEUED;
1663 }
1664 
1665 // __kmp_omp_task: Schedule a non-thread-switchable task for execution
1666 //
1667 // gtid: Global Thread ID of encountering thread
1668 // new_task:non-thread-switchable task thunk allocated by __kmp_omp_task_alloc()
1669 // serialize_immediate: if TRUE then if the task is executed immediately its
1670 // execution will be serialized
1671 // Returns:
1672 //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1673 //    be resumed later.
1674 //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1675 //    resumed later.
1676 kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
1677                          bool serialize_immediate) {
1678   kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1679 
1680 /* Should we execute the new task or queue it? For now, let's just always try to
1681    queue it.  If the queue fills up, then we'll execute it.  */
1682 #if OMP_45_ENABLED
1683   if (new_taskdata->td_flags.proxy == TASK_PROXY ||
1684       __kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
1685 #else
1686   if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
1687 #endif
1688   { // Execute this task immediately
1689     kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
1690     if (serialize_immediate)
1691       new_taskdata->td_flags.task_serial = 1;
1692     __kmp_invoke_task(gtid, new_task, current_task);
1693   }
1694 
1695   ANNOTATE_HAPPENS_BEFORE(new_task);
1696   return TASK_CURRENT_NOT_QUEUED;
1697 }
1698 
1699 // __kmpc_omp_task: Wrapper around __kmp_omp_task to schedule a
1700 // non-thread-switchable task from the parent thread only!
1701 //
1702 // loc_ref: location of original task pragma (ignored)
1703 // gtid: Global Thread ID of encountering thread
1704 // new_task: non-thread-switchable task thunk allocated by
1705 // __kmp_omp_task_alloc()
1706 // Returns:
1707 //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1708 //    be resumed later.
1709 //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1710 //    resumed later.
1711 kmp_int32 __kmpc_omp_task(ident_t *loc_ref, kmp_int32 gtid,
1712                           kmp_task_t *new_task) {
1713   kmp_int32 res;
1714   KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK);
1715 
1716 #if KMP_DEBUG || OMPT_SUPPORT
1717   kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1718 #endif
1719   KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref,
1720                 new_taskdata));
1721 
1722 #if OMPT_SUPPORT
1723   kmp_taskdata_t *parent = NULL;
1724   if (UNLIKELY(ompt_enabled.enabled)) {
1725     if (!new_taskdata->td_flags.started) {
1726       OMPT_STORE_RETURN_ADDRESS(gtid);
1727       parent = new_taskdata->td_parent;
1728       if (!parent->ompt_task_info.frame.enter_frame) {
1729         parent->ompt_task_info.frame.enter_frame = OMPT_GET_FRAME_ADDRESS(1);
1730       }
1731       if (ompt_enabled.ompt_callback_task_create) {
1732         ompt_data_t task_data = ompt_data_none;
1733         ompt_callbacks.ompt_callback(ompt_callback_task_create)(
1734             parent ? &(parent->ompt_task_info.task_data) : &task_data,
1735             parent ? &(parent->ompt_task_info.frame) : NULL,
1736             &(new_taskdata->ompt_task_info.task_data),
1737             ompt_task_explicit | TASK_TYPE_DETAILS_FORMAT(new_taskdata), 0,
1738             OMPT_LOAD_RETURN_ADDRESS(gtid));
1739       }
1740     } else {
1741       // We are scheduling the continuation of an UNTIED task.
1742       // Scheduling back to the parent task.
1743       __ompt_task_finish(new_task,
1744                          new_taskdata->ompt_task_info.scheduling_parent,
1745                          ompt_task_switch);
1746       new_taskdata->ompt_task_info.frame.exit_frame = NULL;
1747     }
1748   }
1749 #endif
1750 
1751   res = __kmp_omp_task(gtid, new_task, true);
1752 
1753   KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning "
1754                 "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n",
1755                 gtid, loc_ref, new_taskdata));
1756 #if OMPT_SUPPORT
1757   if (UNLIKELY(ompt_enabled.enabled && parent != NULL)) {
1758     parent->ompt_task_info.frame.enter_frame = NULL;
1759   }
1760 #endif
1761   return res;
1762 }
1763 
1764 // __kmp_omp_taskloop_task: Wrapper around __kmp_omp_task to schedule
1765 // a taskloop task with the correct OMPT return address
1766 //
1767 // loc_ref: location of original task pragma (ignored)
1768 // gtid: Global Thread ID of encountering thread
1769 // new_task: non-thread-switchable task thunk allocated by
1770 // __kmp_omp_task_alloc()
1771 // codeptr_ra: return address for OMPT callback
1772 // Returns:
1773 //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1774 //    be resumed later.
1775 //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1776 //    resumed later.
1777 kmp_int32 __kmp_omp_taskloop_task(ident_t *loc_ref, kmp_int32 gtid,
1778                                   kmp_task_t *new_task, void *codeptr_ra) {
1779   kmp_int32 res;
1780   KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK);
1781 
1782 #if KMP_DEBUG || OMPT_SUPPORT
1783   kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1784 #endif
1785   KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref,
1786                 new_taskdata));
1787 
1788 #if OMPT_SUPPORT
1789   kmp_taskdata_t *parent = NULL;
1790   if (UNLIKELY(ompt_enabled.enabled && !new_taskdata->td_flags.started)) {
1791     parent = new_taskdata->td_parent;
1792     if (!parent->ompt_task_info.frame.enter_frame)
1793       parent->ompt_task_info.frame.enter_frame = OMPT_GET_FRAME_ADDRESS(1);
1794     if (ompt_enabled.ompt_callback_task_create) {
1795       ompt_data_t task_data = ompt_data_none;
1796       ompt_callbacks.ompt_callback(ompt_callback_task_create)(
1797           parent ? &(parent->ompt_task_info.task_data) : &task_data,
1798           parent ? &(parent->ompt_task_info.frame) : NULL,
1799           &(new_taskdata->ompt_task_info.task_data),
1800           ompt_task_explicit | TASK_TYPE_DETAILS_FORMAT(new_taskdata), 0,
1801           codeptr_ra);
1802     }
1803   }
1804 #endif
1805 
1806   res = __kmp_omp_task(gtid, new_task, true);
1807 
1808   KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning "
1809                 "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n",
1810                 gtid, loc_ref, new_taskdata));
1811 #if OMPT_SUPPORT
1812   if (UNLIKELY(ompt_enabled.enabled && parent != NULL)) {
1813     parent->ompt_task_info.frame.enter_frame = NULL;
1814   }
1815 #endif
1816   return res;
1817 }
1818 
1819 template <bool ompt>
1820 static kmp_int32 __kmpc_omp_taskwait_template(ident_t *loc_ref, kmp_int32 gtid,
1821                                               void *frame_address,
1822                                               void *return_address) {
1823   kmp_taskdata_t *taskdata;
1824   kmp_info_t *thread;
1825   int thread_finished = FALSE;
1826   KMP_SET_THREAD_STATE_BLOCK(TASKWAIT);
1827 
1828   KA_TRACE(10, ("__kmpc_omp_taskwait(enter): T#%d loc=%p\n", gtid, loc_ref));
1829 
1830   if (__kmp_tasking_mode != tskm_immediate_exec) {
1831     thread = __kmp_threads[gtid];
1832     taskdata = thread->th.th_current_task;
1833 
1834 #if OMPT_SUPPORT && OMPT_OPTIONAL
1835     ompt_data_t *my_task_data;
1836     ompt_data_t *my_parallel_data;
1837 
1838     if (ompt) {
1839       my_task_data = &(taskdata->ompt_task_info.task_data);
1840       my_parallel_data = OMPT_CUR_TEAM_DATA(thread);
1841 
1842       taskdata->ompt_task_info.frame.enter_frame = frame_address;
1843 
1844       if (ompt_enabled.ompt_callback_sync_region) {
1845         ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
1846             ompt_sync_region_taskwait, ompt_scope_begin, my_parallel_data,
1847             my_task_data, return_address);
1848       }
1849 
1850       if (ompt_enabled.ompt_callback_sync_region_wait) {
1851         ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
1852             ompt_sync_region_taskwait, ompt_scope_begin, my_parallel_data,
1853             my_task_data, return_address);
1854       }
1855     }
1856 #endif // OMPT_SUPPORT && OMPT_OPTIONAL
1857 
1858 // Debugger: The taskwait is active. Store location and thread encountered the
1859 // taskwait.
1860 #if USE_ITT_BUILD
1861 // Note: These values are used by ITT events as well.
1862 #endif /* USE_ITT_BUILD */
1863     taskdata->td_taskwait_counter += 1;
1864     taskdata->td_taskwait_ident = loc_ref;
1865     taskdata->td_taskwait_thread = gtid + 1;
1866 
1867 #if USE_ITT_BUILD
1868     void *itt_sync_obj = __kmp_itt_taskwait_object(gtid);
1869     if (itt_sync_obj != NULL)
1870       __kmp_itt_taskwait_starting(gtid, itt_sync_obj);
1871 #endif /* USE_ITT_BUILD */
1872 
1873     bool must_wait =
1874         !taskdata->td_flags.team_serial && !taskdata->td_flags.final;
1875 
1876 #if OMP_45_ENABLED
1877     must_wait = must_wait || (thread->th.th_task_team != NULL &&
1878                               thread->th.th_task_team->tt.tt_found_proxy_tasks);
1879 #endif
1880     if (must_wait) {
1881       kmp_flag_32 flag(RCAST(std::atomic<kmp_uint32> *,
1882                              &(taskdata->td_incomplete_child_tasks)),
1883                        0U);
1884       while (KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) != 0) {
1885         flag.execute_tasks(thread, gtid, FALSE,
1886                            &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
1887                            __kmp_task_stealing_constraint);
1888       }
1889     }
1890 #if USE_ITT_BUILD
1891     if (itt_sync_obj != NULL)
1892       __kmp_itt_taskwait_finished(gtid, itt_sync_obj);
1893 #endif /* USE_ITT_BUILD */
1894 
1895     // Debugger:  The taskwait is completed. Location remains, but thread is
1896     // negated.
1897     taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread;
1898 
1899 #if OMPT_SUPPORT && OMPT_OPTIONAL
1900     if (ompt) {
1901       if (ompt_enabled.ompt_callback_sync_region_wait) {
1902         ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
1903             ompt_sync_region_taskwait, ompt_scope_end, my_parallel_data,
1904             my_task_data, return_address);
1905       }
1906       if (ompt_enabled.ompt_callback_sync_region) {
1907         ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
1908             ompt_sync_region_taskwait, ompt_scope_end, my_parallel_data,
1909             my_task_data, return_address);
1910       }
1911       taskdata->ompt_task_info.frame.enter_frame = NULL;
1912     }
1913 #endif // OMPT_SUPPORT && OMPT_OPTIONAL
1914 
1915     ANNOTATE_HAPPENS_AFTER(taskdata);
1916   }
1917 
1918   KA_TRACE(10, ("__kmpc_omp_taskwait(exit): T#%d task %p finished waiting, "
1919                 "returning TASK_CURRENT_NOT_QUEUED\n",
1920                 gtid, taskdata));
1921 
1922   return TASK_CURRENT_NOT_QUEUED;
1923 }
1924 
1925 #if OMPT_SUPPORT && OMPT_OPTIONAL
1926 OMPT_NOINLINE
1927 static kmp_int32 __kmpc_omp_taskwait_ompt(ident_t *loc_ref, kmp_int32 gtid,
1928                                           void *frame_address,
1929                                           void *return_address) {
1930   return __kmpc_omp_taskwait_template<true>(loc_ref, gtid, frame_address,
1931                                             return_address);
1932 }
1933 #endif // OMPT_SUPPORT && OMPT_OPTIONAL
1934 
1935 // __kmpc_omp_taskwait: Wait until all tasks generated by the current task are
1936 // complete
1937 kmp_int32 __kmpc_omp_taskwait(ident_t *loc_ref, kmp_int32 gtid) {
1938 #if OMPT_SUPPORT && OMPT_OPTIONAL
1939   if (UNLIKELY(ompt_enabled.enabled)) {
1940     OMPT_STORE_RETURN_ADDRESS(gtid);
1941     return __kmpc_omp_taskwait_ompt(loc_ref, gtid, OMPT_GET_FRAME_ADDRESS(1),
1942                                     OMPT_LOAD_RETURN_ADDRESS(gtid));
1943   }
1944 #endif
1945   return __kmpc_omp_taskwait_template<false>(loc_ref, gtid, NULL, NULL);
1946 }
1947 
1948 // __kmpc_omp_taskyield: switch to a different task
1949 kmp_int32 __kmpc_omp_taskyield(ident_t *loc_ref, kmp_int32 gtid, int end_part) {
1950   kmp_taskdata_t *taskdata;
1951   kmp_info_t *thread;
1952   int thread_finished = FALSE;
1953 
1954   KMP_COUNT_BLOCK(OMP_TASKYIELD);
1955   KMP_SET_THREAD_STATE_BLOCK(TASKYIELD);
1956 
1957   KA_TRACE(10, ("__kmpc_omp_taskyield(enter): T#%d loc=%p end_part = %d\n",
1958                 gtid, loc_ref, end_part));
1959 
1960   if (__kmp_tasking_mode != tskm_immediate_exec && __kmp_init_parallel) {
1961     thread = __kmp_threads[gtid];
1962     taskdata = thread->th.th_current_task;
1963 // Should we model this as a task wait or not?
1964 // Debugger: The taskwait is active. Store location and thread encountered the
1965 // taskwait.
1966 #if USE_ITT_BUILD
1967 // Note: These values are used by ITT events as well.
1968 #endif /* USE_ITT_BUILD */
1969     taskdata->td_taskwait_counter += 1;
1970     taskdata->td_taskwait_ident = loc_ref;
1971     taskdata->td_taskwait_thread = gtid + 1;
1972 
1973 #if USE_ITT_BUILD
1974     void *itt_sync_obj = __kmp_itt_taskwait_object(gtid);
1975     if (itt_sync_obj != NULL)
1976       __kmp_itt_taskwait_starting(gtid, itt_sync_obj);
1977 #endif /* USE_ITT_BUILD */
1978     if (!taskdata->td_flags.team_serial) {
1979       kmp_task_team_t *task_team = thread->th.th_task_team;
1980       if (task_team != NULL) {
1981         if (KMP_TASKING_ENABLED(task_team)) {
1982 #if OMPT_SUPPORT
1983           if (UNLIKELY(ompt_enabled.enabled))
1984             thread->th.ompt_thread_info.ompt_task_yielded = 1;
1985 #endif
1986           __kmp_execute_tasks_32(
1987               thread, gtid, NULL, FALSE,
1988               &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
1989               __kmp_task_stealing_constraint);
1990 #if OMPT_SUPPORT
1991           if (UNLIKELY(ompt_enabled.enabled))
1992             thread->th.ompt_thread_info.ompt_task_yielded = 0;
1993 #endif
1994         }
1995       }
1996     }
1997 #if USE_ITT_BUILD
1998     if (itt_sync_obj != NULL)
1999       __kmp_itt_taskwait_finished(gtid, itt_sync_obj);
2000 #endif /* USE_ITT_BUILD */
2001 
2002     // Debugger:  The taskwait is completed. Location remains, but thread is
2003     // negated.
2004     taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread;
2005   }
2006 
2007   KA_TRACE(10, ("__kmpc_omp_taskyield(exit): T#%d task %p resuming, "
2008                 "returning TASK_CURRENT_NOT_QUEUED\n",
2009                 gtid, taskdata));
2010 
2011   return TASK_CURRENT_NOT_QUEUED;
2012 }
2013 
2014 #if OMP_50_ENABLED
2015 // Task Reduction implementation
2016 
2017 typedef struct kmp_task_red_flags {
2018   unsigned lazy_priv : 1; // hint: (1) use lazy allocation (big objects)
2019   unsigned reserved31 : 31;
2020 } kmp_task_red_flags_t;
2021 
2022 // internal structure for reduction data item related info
2023 typedef struct kmp_task_red_data {
2024   void *reduce_shar; // shared reduction item
2025   size_t reduce_size; // size of data item
2026   void *reduce_priv; // thread specific data
2027   void *reduce_pend; // end of private data for comparison op
2028   void *reduce_init; // data initialization routine
2029   void *reduce_fini; // data finalization routine
2030   void *reduce_comb; // data combiner routine
2031   kmp_task_red_flags_t flags; // flags for additional info from compiler
2032 } kmp_task_red_data_t;
2033 
2034 // structure sent us by compiler - one per reduction item
2035 typedef struct kmp_task_red_input {
2036   void *reduce_shar; // shared reduction item
2037   size_t reduce_size; // size of data item
2038   void *reduce_init; // data initialization routine
2039   void *reduce_fini; // data finalization routine
2040   void *reduce_comb; // data combiner routine
2041   kmp_task_red_flags_t flags; // flags for additional info from compiler
2042 } kmp_task_red_input_t;
2043 
2044 /*!
2045 @ingroup TASKING
2046 @param gtid      Global thread ID
2047 @param num       Number of data items to reduce
2048 @param data      Array of data for reduction
2049 @return The taskgroup identifier
2050 
2051 Initialize task reduction for the taskgroup.
2052 */
2053 void *__kmpc_task_reduction_init(int gtid, int num, void *data) {
2054   kmp_info_t *thread = __kmp_threads[gtid];
2055   kmp_taskgroup_t *tg = thread->th.th_current_task->td_taskgroup;
2056   kmp_int32 nth = thread->th.th_team_nproc;
2057   kmp_task_red_input_t *input = (kmp_task_red_input_t *)data;
2058   kmp_task_red_data_t *arr;
2059 
2060   // check input data just in case
2061   KMP_ASSERT(tg != NULL);
2062   KMP_ASSERT(data != NULL);
2063   KMP_ASSERT(num > 0);
2064   if (nth == 1) {
2065     KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, tg %p, exiting nth=1\n",
2066                   gtid, tg));
2067     return (void *)tg;
2068   }
2069   KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, taskgroup %p, #items %d\n",
2070                 gtid, tg, num));
2071   arr = (kmp_task_red_data_t *)__kmp_thread_malloc(
2072       thread, num * sizeof(kmp_task_red_data_t));
2073   for (int i = 0; i < num; ++i) {
2074     void (*f_init)(void *) = (void (*)(void *))(input[i].reduce_init);
2075     size_t size = input[i].reduce_size - 1;
2076     // round the size up to cache line per thread-specific item
2077     size += CACHE_LINE - size % CACHE_LINE;
2078     KMP_ASSERT(input[i].reduce_comb != NULL); // combiner is mandatory
2079     arr[i].reduce_shar = input[i].reduce_shar;
2080     arr[i].reduce_size = size;
2081     arr[i].reduce_init = input[i].reduce_init;
2082     arr[i].reduce_fini = input[i].reduce_fini;
2083     arr[i].reduce_comb = input[i].reduce_comb;
2084     arr[i].flags = input[i].flags;
2085     if (!input[i].flags.lazy_priv) {
2086       // allocate cache-line aligned block and fill it with zeros
2087       arr[i].reduce_priv = __kmp_allocate(nth * size);
2088       arr[i].reduce_pend = (char *)(arr[i].reduce_priv) + nth * size;
2089       if (f_init != NULL) {
2090         // initialize thread-specific items
2091         for (int j = 0; j < nth; ++j) {
2092           f_init((char *)(arr[i].reduce_priv) + j * size);
2093         }
2094       }
2095     } else {
2096       // only allocate space for pointers now,
2097       // objects will be lazily allocated/initialized once requested
2098       arr[i].reduce_priv = __kmp_allocate(nth * sizeof(void *));
2099     }
2100   }
2101   tg->reduce_data = (void *)arr;
2102   tg->reduce_num_data = num;
2103   return (void *)tg;
2104 }
2105 
2106 /*!
2107 @ingroup TASKING
2108 @param gtid    Global thread ID
2109 @param tskgrp  The taskgroup ID (optional)
2110 @param data    Shared location of the item
2111 @return The pointer to per-thread data
2112 
2113 Get thread-specific location of data item
2114 */
2115 void *__kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data) {
2116   kmp_info_t *thread = __kmp_threads[gtid];
2117   kmp_int32 nth = thread->th.th_team_nproc;
2118   if (nth == 1)
2119     return data; // nothing to do
2120 
2121   kmp_taskgroup_t *tg = (kmp_taskgroup_t *)tskgrp;
2122   if (tg == NULL)
2123     tg = thread->th.th_current_task->td_taskgroup;
2124   KMP_ASSERT(tg != NULL);
2125   kmp_task_red_data_t *arr = (kmp_task_red_data_t *)(tg->reduce_data);
2126   kmp_int32 num = tg->reduce_num_data;
2127   kmp_int32 tid = thread->th.th_info.ds.ds_tid;
2128 
2129   KMP_ASSERT(data != NULL);
2130   while (tg != NULL) {
2131     for (int i = 0; i < num; ++i) {
2132       if (!arr[i].flags.lazy_priv) {
2133         if (data == arr[i].reduce_shar ||
2134             (data >= arr[i].reduce_priv && data < arr[i].reduce_pend))
2135           return (char *)(arr[i].reduce_priv) + tid * arr[i].reduce_size;
2136       } else {
2137         // check shared location first
2138         void **p_priv = (void **)(arr[i].reduce_priv);
2139         if (data == arr[i].reduce_shar)
2140           goto found;
2141         // check if we get some thread specific location as parameter
2142         for (int j = 0; j < nth; ++j)
2143           if (data == p_priv[j])
2144             goto found;
2145         continue; // not found, continue search
2146       found:
2147         if (p_priv[tid] == NULL) {
2148           // allocate thread specific object lazily
2149           void (*f_init)(void *) = (void (*)(void *))(arr[i].reduce_init);
2150           p_priv[tid] = __kmp_allocate(arr[i].reduce_size);
2151           if (f_init != NULL) {
2152             f_init(p_priv[tid]);
2153           }
2154         }
2155         return p_priv[tid];
2156       }
2157     }
2158     tg = tg->parent;
2159     arr = (kmp_task_red_data_t *)(tg->reduce_data);
2160     num = tg->reduce_num_data;
2161   }
2162   KMP_ASSERT2(0, "Unknown task reduction item");
2163   return NULL; // ERROR, this line never executed
2164 }
2165 
2166 // Finalize task reduction.
2167 // Called from __kmpc_end_taskgroup()
2168 static void __kmp_task_reduction_fini(kmp_info_t *th, kmp_taskgroup_t *tg) {
2169   kmp_int32 nth = th->th.th_team_nproc;
2170   KMP_DEBUG_ASSERT(nth > 1); // should not be called if nth == 1
2171   kmp_task_red_data_t *arr = (kmp_task_red_data_t *)tg->reduce_data;
2172   kmp_int32 num = tg->reduce_num_data;
2173   for (int i = 0; i < num; ++i) {
2174     void *sh_data = arr[i].reduce_shar;
2175     void (*f_fini)(void *) = (void (*)(void *))(arr[i].reduce_fini);
2176     void (*f_comb)(void *, void *) =
2177         (void (*)(void *, void *))(arr[i].reduce_comb);
2178     if (!arr[i].flags.lazy_priv) {
2179       void *pr_data = arr[i].reduce_priv;
2180       size_t size = arr[i].reduce_size;
2181       for (int j = 0; j < nth; ++j) {
2182         void *priv_data = (char *)pr_data + j * size;
2183         f_comb(sh_data, priv_data); // combine results
2184         if (f_fini)
2185           f_fini(priv_data); // finalize if needed
2186       }
2187     } else {
2188       void **pr_data = (void **)(arr[i].reduce_priv);
2189       for (int j = 0; j < nth; ++j) {
2190         if (pr_data[j] != NULL) {
2191           f_comb(sh_data, pr_data[j]); // combine results
2192           if (f_fini)
2193             f_fini(pr_data[j]); // finalize if needed
2194           __kmp_free(pr_data[j]);
2195         }
2196       }
2197     }
2198     __kmp_free(arr[i].reduce_priv);
2199   }
2200   __kmp_thread_free(th, arr);
2201   tg->reduce_data = NULL;
2202   tg->reduce_num_data = 0;
2203 }
2204 #endif
2205 
2206 #if OMP_40_ENABLED
2207 // __kmpc_taskgroup: Start a new taskgroup
2208 void __kmpc_taskgroup(ident_t *loc, int gtid) {
2209   kmp_info_t *thread = __kmp_threads[gtid];
2210   kmp_taskdata_t *taskdata = thread->th.th_current_task;
2211   kmp_taskgroup_t *tg_new =
2212       (kmp_taskgroup_t *)__kmp_thread_malloc(thread, sizeof(kmp_taskgroup_t));
2213   KA_TRACE(10, ("__kmpc_taskgroup: T#%d loc=%p group=%p\n", gtid, loc, tg_new));
2214   KMP_ATOMIC_ST_RLX(&tg_new->count, 0);
2215   KMP_ATOMIC_ST_RLX(&tg_new->cancel_request, cancel_noreq);
2216   tg_new->parent = taskdata->td_taskgroup;
2217 #if OMP_50_ENABLED
2218   tg_new->reduce_data = NULL;
2219   tg_new->reduce_num_data = 0;
2220 #endif
2221   taskdata->td_taskgroup = tg_new;
2222 
2223 #if OMPT_SUPPORT && OMPT_OPTIONAL
2224   if (UNLIKELY(ompt_enabled.ompt_callback_sync_region)) {
2225     void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2226     if (!codeptr)
2227       codeptr = OMPT_GET_RETURN_ADDRESS(0);
2228     kmp_team_t *team = thread->th.th_team;
2229     ompt_data_t my_task_data = taskdata->ompt_task_info.task_data;
2230     // FIXME: I think this is wrong for lwt!
2231     ompt_data_t my_parallel_data = team->t.ompt_team_info.parallel_data;
2232 
2233     ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2234         ompt_sync_region_taskgroup, ompt_scope_begin, &(my_parallel_data),
2235         &(my_task_data), codeptr);
2236   }
2237 #endif
2238 }
2239 
2240 // __kmpc_end_taskgroup: Wait until all tasks generated by the current task
2241 //                       and its descendants are complete
2242 void __kmpc_end_taskgroup(ident_t *loc, int gtid) {
2243   kmp_info_t *thread = __kmp_threads[gtid];
2244   kmp_taskdata_t *taskdata = thread->th.th_current_task;
2245   kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup;
2246   int thread_finished = FALSE;
2247 
2248 #if OMPT_SUPPORT && OMPT_OPTIONAL
2249   kmp_team_t *team;
2250   ompt_data_t my_task_data;
2251   ompt_data_t my_parallel_data;
2252   void *codeptr;
2253   if (UNLIKELY(ompt_enabled.enabled)) {
2254     team = thread->th.th_team;
2255     my_task_data = taskdata->ompt_task_info.task_data;
2256     // FIXME: I think this is wrong for lwt!
2257     my_parallel_data = team->t.ompt_team_info.parallel_data;
2258     codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2259     if (!codeptr)
2260       codeptr = OMPT_GET_RETURN_ADDRESS(0);
2261   }
2262 #endif
2263 
2264   KA_TRACE(10, ("__kmpc_end_taskgroup(enter): T#%d loc=%p\n", gtid, loc));
2265   KMP_DEBUG_ASSERT(taskgroup != NULL);
2266   KMP_SET_THREAD_STATE_BLOCK(TASKGROUP);
2267 
2268   if (__kmp_tasking_mode != tskm_immediate_exec) {
2269     // mark task as waiting not on a barrier
2270     taskdata->td_taskwait_counter += 1;
2271     taskdata->td_taskwait_ident = loc;
2272     taskdata->td_taskwait_thread = gtid + 1;
2273 #if USE_ITT_BUILD
2274     // For ITT the taskgroup wait is similar to taskwait until we need to
2275     // distinguish them
2276     void *itt_sync_obj = __kmp_itt_taskwait_object(gtid);
2277     if (itt_sync_obj != NULL)
2278       __kmp_itt_taskwait_starting(gtid, itt_sync_obj);
2279 #endif /* USE_ITT_BUILD */
2280 
2281 #if OMPT_SUPPORT && OMPT_OPTIONAL
2282     if (UNLIKELY(ompt_enabled.ompt_callback_sync_region_wait)) {
2283       ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2284           ompt_sync_region_taskgroup, ompt_scope_begin, &(my_parallel_data),
2285           &(my_task_data), codeptr);
2286     }
2287 #endif
2288 
2289 #if OMP_45_ENABLED
2290     if (!taskdata->td_flags.team_serial ||
2291         (thread->th.th_task_team != NULL &&
2292          thread->th.th_task_team->tt.tt_found_proxy_tasks))
2293 #else
2294     if (!taskdata->td_flags.team_serial)
2295 #endif
2296     {
2297       kmp_flag_32 flag(RCAST(std::atomic<kmp_uint32> *, &(taskgroup->count)),
2298                        0U);
2299       while (KMP_ATOMIC_LD_ACQ(&taskgroup->count) != 0) {
2300         flag.execute_tasks(thread, gtid, FALSE,
2301                            &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
2302                            __kmp_task_stealing_constraint);
2303       }
2304     }
2305     taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread; // end waiting
2306 
2307 #if OMPT_SUPPORT && OMPT_OPTIONAL
2308     if (UNLIKELY(ompt_enabled.ompt_callback_sync_region_wait)) {
2309       ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2310           ompt_sync_region_taskgroup, ompt_scope_end, &(my_parallel_data),
2311           &(my_task_data), codeptr);
2312     }
2313 #endif
2314 
2315 #if USE_ITT_BUILD
2316     if (itt_sync_obj != NULL)
2317       __kmp_itt_taskwait_finished(gtid, itt_sync_obj);
2318 #endif /* USE_ITT_BUILD */
2319   }
2320   KMP_DEBUG_ASSERT(taskgroup->count == 0);
2321 
2322 #if OMP_50_ENABLED
2323   if (taskgroup->reduce_data != NULL) // need to reduce?
2324     __kmp_task_reduction_fini(thread, taskgroup);
2325 #endif
2326   // Restore parent taskgroup for the current task
2327   taskdata->td_taskgroup = taskgroup->parent;
2328   __kmp_thread_free(thread, taskgroup);
2329 
2330   KA_TRACE(10, ("__kmpc_end_taskgroup(exit): T#%d task %p finished waiting\n",
2331                 gtid, taskdata));
2332   ANNOTATE_HAPPENS_AFTER(taskdata);
2333 
2334 #if OMPT_SUPPORT && OMPT_OPTIONAL
2335   if (UNLIKELY(ompt_enabled.ompt_callback_sync_region)) {
2336     ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2337         ompt_sync_region_taskgroup, ompt_scope_end, &(my_parallel_data),
2338         &(my_task_data), codeptr);
2339   }
2340 #endif
2341 }
2342 #endif
2343 
2344 // __kmp_remove_my_task: remove a task from my own deque
2345 static kmp_task_t *__kmp_remove_my_task(kmp_info_t *thread, kmp_int32 gtid,
2346                                         kmp_task_team_t *task_team,
2347                                         kmp_int32 is_constrained) {
2348   kmp_task_t *task;
2349   kmp_taskdata_t *taskdata;
2350   kmp_thread_data_t *thread_data;
2351   kmp_uint32 tail;
2352 
2353   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
2354   KMP_DEBUG_ASSERT(task_team->tt.tt_threads_data !=
2355                    NULL); // Caller should check this condition
2356 
2357   thread_data = &task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)];
2358 
2359   KA_TRACE(10, ("__kmp_remove_my_task(enter): T#%d ntasks=%d head=%u tail=%u\n",
2360                 gtid, thread_data->td.td_deque_ntasks,
2361                 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2362 
2363   if (TCR_4(thread_data->td.td_deque_ntasks) == 0) {
2364     KA_TRACE(10,
2365              ("__kmp_remove_my_task(exit #1): T#%d No tasks to remove: "
2366               "ntasks=%d head=%u tail=%u\n",
2367               gtid, thread_data->td.td_deque_ntasks,
2368               thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2369     return NULL;
2370   }
2371 
2372   __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
2373 
2374   if (TCR_4(thread_data->td.td_deque_ntasks) == 0) {
2375     __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2376     KA_TRACE(10,
2377              ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: "
2378               "ntasks=%d head=%u tail=%u\n",
2379               gtid, thread_data->td.td_deque_ntasks,
2380               thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2381     return NULL;
2382   }
2383 
2384   tail = (thread_data->td.td_deque_tail - 1) &
2385          TASK_DEQUE_MASK(thread_data->td); // Wrap index.
2386   taskdata = thread_data->td.td_deque[tail];
2387 
2388   if (!__kmp_task_is_allowed(gtid, is_constrained, taskdata,
2389                              thread->th.th_current_task)) {
2390     // The TSC does not allow to steal victim task
2391     __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2392     KA_TRACE(10,
2393              ("__kmp_remove_my_task(exit #3): T#%d TSC blocks tail task: "
2394               "ntasks=%d head=%u tail=%u\n",
2395               gtid, thread_data->td.td_deque_ntasks,
2396               thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2397     return NULL;
2398   }
2399 
2400   thread_data->td.td_deque_tail = tail;
2401   TCW_4(thread_data->td.td_deque_ntasks, thread_data->td.td_deque_ntasks - 1);
2402 
2403   __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2404 
2405   KA_TRACE(10, ("__kmp_remove_my_task(exit #4): T#%d task %p removed: "
2406                 "ntasks=%d head=%u tail=%u\n",
2407                 gtid, taskdata, thread_data->td.td_deque_ntasks,
2408                 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2409 
2410   task = KMP_TASKDATA_TO_TASK(taskdata);
2411   return task;
2412 }
2413 
2414 // __kmp_steal_task: remove a task from another thread's deque
2415 // Assume that calling thread has already checked existence of
2416 // task_team thread_data before calling this routine.
2417 static kmp_task_t *__kmp_steal_task(kmp_info_t *victim_thr, kmp_int32 gtid,
2418                                     kmp_task_team_t *task_team,
2419                                     std::atomic<kmp_int32> *unfinished_threads,
2420                                     int *thread_finished,
2421                                     kmp_int32 is_constrained) {
2422   kmp_task_t *task;
2423   kmp_taskdata_t *taskdata;
2424   kmp_taskdata_t *current;
2425   kmp_thread_data_t *victim_td, *threads_data;
2426   kmp_int32 target;
2427   kmp_int32 victim_tid;
2428 
2429   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
2430 
2431   threads_data = task_team->tt.tt_threads_data;
2432   KMP_DEBUG_ASSERT(threads_data != NULL); // Caller should check this condition
2433 
2434   victim_tid = victim_thr->th.th_info.ds.ds_tid;
2435   victim_td = &threads_data[victim_tid];
2436 
2437   KA_TRACE(10, ("__kmp_steal_task(enter): T#%d try to steal from T#%d: "
2438                 "task_team=%p ntasks=%d head=%u tail=%u\n",
2439                 gtid, __kmp_gtid_from_thread(victim_thr), task_team,
2440                 victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
2441                 victim_td->td.td_deque_tail));
2442 
2443   if (TCR_4(victim_td->td.td_deque_ntasks) == 0) {
2444     KA_TRACE(10, ("__kmp_steal_task(exit #1): T#%d could not steal from T#%d: "
2445                   "task_team=%p ntasks=%d head=%u tail=%u\n",
2446                   gtid, __kmp_gtid_from_thread(victim_thr), task_team,
2447                   victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
2448                   victim_td->td.td_deque_tail));
2449     return NULL;
2450   }
2451 
2452   __kmp_acquire_bootstrap_lock(&victim_td->td.td_deque_lock);
2453 
2454   int ntasks = TCR_4(victim_td->td.td_deque_ntasks);
2455   // Check again after we acquire the lock
2456   if (ntasks == 0) {
2457     __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2458     KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: "
2459                   "task_team=%p ntasks=%d head=%u tail=%u\n",
2460                   gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks,
2461                   victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2462     return NULL;
2463   }
2464 
2465   KMP_DEBUG_ASSERT(victim_td->td.td_deque != NULL);
2466   current = __kmp_threads[gtid]->th.th_current_task;
2467   taskdata = victim_td->td.td_deque[victim_td->td.td_deque_head];
2468   if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) {
2469     // Bump head pointer and Wrap.
2470     victim_td->td.td_deque_head =
2471         (victim_td->td.td_deque_head + 1) & TASK_DEQUE_MASK(victim_td->td);
2472   } else {
2473     if (!task_team->tt.tt_untied_task_encountered) {
2474       // The TSC does not allow to steal victim task
2475       __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2476       KA_TRACE(10, ("__kmp_steal_task(exit #3): T#%d could not steal from "
2477                     "T#%d: task_team=%p ntasks=%d head=%u tail=%u\n",
2478                     gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks,
2479                     victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2480       return NULL;
2481     }
2482     int i;
2483     // walk through victim's deque trying to steal any task
2484     target = victim_td->td.td_deque_head;
2485     taskdata = NULL;
2486     for (i = 1; i < ntasks; ++i) {
2487       target = (target + 1) & TASK_DEQUE_MASK(victim_td->td);
2488       taskdata = victim_td->td.td_deque[target];
2489       if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) {
2490         break; // found victim task
2491       } else {
2492         taskdata = NULL;
2493       }
2494     }
2495     if (taskdata == NULL) {
2496       // No appropriate candidate to steal found
2497       __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2498       KA_TRACE(10, ("__kmp_steal_task(exit #4): T#%d could not steal from "
2499                     "T#%d: task_team=%p ntasks=%d head=%u tail=%u\n",
2500                     gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks,
2501                     victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2502       return NULL;
2503     }
2504     int prev = target;
2505     for (i = i + 1; i < ntasks; ++i) {
2506       // shift remaining tasks in the deque left by 1
2507       target = (target + 1) & TASK_DEQUE_MASK(victim_td->td);
2508       victim_td->td.td_deque[prev] = victim_td->td.td_deque[target];
2509       prev = target;
2510     }
2511     KMP_DEBUG_ASSERT(
2512         victim_td->td.td_deque_tail ==
2513         (kmp_uint32)((target + 1) & TASK_DEQUE_MASK(victim_td->td)));
2514     victim_td->td.td_deque_tail = target; // tail -= 1 (wrapped))
2515   }
2516   if (*thread_finished) {
2517     // We need to un-mark this victim as a finished victim.  This must be done
2518     // before releasing the lock, or else other threads (starting with the
2519     // master victim) might be prematurely released from the barrier!!!
2520     kmp_int32 count;
2521 
2522     count = KMP_ATOMIC_INC(unfinished_threads);
2523 
2524     KA_TRACE(
2525         20,
2526         ("__kmp_steal_task: T#%d inc unfinished_threads to %d: task_team=%p\n",
2527          gtid, count + 1, task_team));
2528 
2529     *thread_finished = FALSE;
2530   }
2531   TCW_4(victim_td->td.td_deque_ntasks, ntasks - 1);
2532 
2533   __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2534 
2535   KMP_COUNT_BLOCK(TASK_stolen);
2536   KA_TRACE(10,
2537            ("__kmp_steal_task(exit #5): T#%d stole task %p from T#%d: "
2538             "task_team=%p ntasks=%d head=%u tail=%u\n",
2539             gtid, taskdata, __kmp_gtid_from_thread(victim_thr), task_team,
2540             ntasks, victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2541 
2542   task = KMP_TASKDATA_TO_TASK(taskdata);
2543   return task;
2544 }
2545 
2546 // __kmp_execute_tasks_template: Choose and execute tasks until either the
2547 // condition is statisfied (return true) or there are none left (return false).
2548 //
2549 // final_spin is TRUE if this is the spin at the release barrier.
2550 // thread_finished indicates whether the thread is finished executing all
2551 // the tasks it has on its deque, and is at the release barrier.
2552 // spinner is the location on which to spin.
2553 // spinner == NULL means only execute a single task and return.
2554 // checker is the value to check to terminate the spin.
2555 template <class C>
2556 static inline int __kmp_execute_tasks_template(
2557     kmp_info_t *thread, kmp_int32 gtid, C *flag, int final_spin,
2558     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2559     kmp_int32 is_constrained) {
2560   kmp_task_team_t *task_team = thread->th.th_task_team;
2561   kmp_thread_data_t *threads_data;
2562   kmp_task_t *task;
2563   kmp_info_t *other_thread;
2564   kmp_taskdata_t *current_task = thread->th.th_current_task;
2565   std::atomic<kmp_int32> *unfinished_threads;
2566   kmp_int32 nthreads, victim_tid = -2, use_own_tasks = 1, new_victim = 0,
2567                       tid = thread->th.th_info.ds.ds_tid;
2568 
2569   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
2570   KMP_DEBUG_ASSERT(thread == __kmp_threads[gtid]);
2571 
2572   if (task_team == NULL || current_task == NULL)
2573     return FALSE;
2574 
2575   KA_TRACE(15, ("__kmp_execute_tasks_template(enter): T#%d final_spin=%d "
2576                 "*thread_finished=%d\n",
2577                 gtid, final_spin, *thread_finished));
2578 
2579   thread->th.th_reap_state = KMP_NOT_SAFE_TO_REAP;
2580   threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data);
2581   KMP_DEBUG_ASSERT(threads_data != NULL);
2582 
2583   nthreads = task_team->tt.tt_nproc;
2584   unfinished_threads = &(task_team->tt.tt_unfinished_threads);
2585 #if OMP_45_ENABLED
2586   KMP_DEBUG_ASSERT(nthreads > 1 || task_team->tt.tt_found_proxy_tasks);
2587 #else
2588   KMP_DEBUG_ASSERT(nthreads > 1);
2589 #endif
2590   KMP_DEBUG_ASSERT(*unfinished_threads >= 0);
2591 
2592   while (1) { // Outer loop keeps trying to find tasks in case of single thread
2593     // getting tasks from target constructs
2594     while (1) { // Inner loop to find a task and execute it
2595       task = NULL;
2596       if (use_own_tasks) { // check on own queue first
2597         task = __kmp_remove_my_task(thread, gtid, task_team, is_constrained);
2598       }
2599       if ((task == NULL) && (nthreads > 1)) { // Steal a task
2600         int asleep = 1;
2601         use_own_tasks = 0;
2602         // Try to steal from the last place I stole from successfully.
2603         if (victim_tid == -2) { // haven't stolen anything yet
2604           victim_tid = threads_data[tid].td.td_deque_last_stolen;
2605           if (victim_tid !=
2606               -1) // if we have a last stolen from victim, get the thread
2607             other_thread = threads_data[victim_tid].td.td_thr;
2608         }
2609         if (victim_tid != -1) { // found last victim
2610           asleep = 0;
2611         } else if (!new_victim) { // no recent steals and we haven't already
2612           // used a new victim; select a random thread
2613           do { // Find a different thread to steal work from.
2614             // Pick a random thread. Initial plan was to cycle through all the
2615             // threads, and only return if we tried to steal from every thread,
2616             // and failed.  Arch says that's not such a great idea.
2617             victim_tid = __kmp_get_random(thread) % (nthreads - 1);
2618             if (victim_tid >= tid) {
2619               ++victim_tid; // Adjusts random distribution to exclude self
2620             }
2621             // Found a potential victim
2622             other_thread = threads_data[victim_tid].td.td_thr;
2623             // There is a slight chance that __kmp_enable_tasking() did not wake
2624             // up all threads waiting at the barrier.  If victim is sleeping,
2625             // then wake it up. Since we were going to pay the cache miss
2626             // penalty for referencing another thread's kmp_info_t struct
2627             // anyway,
2628             // the check shouldn't cost too much performance at this point. In
2629             // extra barrier mode, tasks do not sleep at the separate tasking
2630             // barrier, so this isn't a problem.
2631             asleep = 0;
2632             if ((__kmp_tasking_mode == tskm_task_teams) &&
2633                 (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) &&
2634                 (TCR_PTR(CCAST(void *, other_thread->th.th_sleep_loc)) !=
2635                  NULL)) {
2636               asleep = 1;
2637               __kmp_null_resume_wrapper(__kmp_gtid_from_thread(other_thread),
2638                                         other_thread->th.th_sleep_loc);
2639               // A sleeping thread should not have any tasks on it's queue.
2640               // There is a slight possibility that it resumes, steals a task
2641               // from another thread, which spawns more tasks, all in the time
2642               // that it takes this thread to check => don't write an assertion
2643               // that the victim's queue is empty.  Try stealing from a
2644               // different thread.
2645             }
2646           } while (asleep);
2647         }
2648 
2649         if (!asleep) {
2650           // We have a victim to try to steal from
2651           task = __kmp_steal_task(other_thread, gtid, task_team,
2652                                   unfinished_threads, thread_finished,
2653                                   is_constrained);
2654         }
2655         if (task != NULL) { // set last stolen to victim
2656           if (threads_data[tid].td.td_deque_last_stolen != victim_tid) {
2657             threads_data[tid].td.td_deque_last_stolen = victim_tid;
2658             // The pre-refactored code did not try more than 1 successful new
2659             // vicitm, unless the last one generated more local tasks;
2660             // new_victim keeps track of this
2661             new_victim = 1;
2662           }
2663         } else { // No tasks found; unset last_stolen
2664           KMP_CHECK_UPDATE(threads_data[tid].td.td_deque_last_stolen, -1);
2665           victim_tid = -2; // no successful victim found
2666         }
2667       }
2668 
2669       if (task == NULL) // break out of tasking loop
2670         break;
2671 
2672 // Found a task; execute it
2673 #if USE_ITT_BUILD && USE_ITT_NOTIFY
2674       if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2675         if (itt_sync_obj == NULL) { // we are at fork barrier where we could not
2676           // get the object reliably
2677           itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2678         }
2679         __kmp_itt_task_starting(itt_sync_obj);
2680       }
2681 #endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2682       __kmp_invoke_task(gtid, task, current_task);
2683 #if USE_ITT_BUILD
2684       if (itt_sync_obj != NULL)
2685         __kmp_itt_task_finished(itt_sync_obj);
2686 #endif /* USE_ITT_BUILD */
2687       // If this thread is only partway through the barrier and the condition is
2688       // met, then return now, so that the barrier gather/release pattern can
2689       // proceed. If this thread is in the last spin loop in the barrier,
2690       // waiting to be released, we know that the termination condition will not
2691       // be satisified, so don't waste any cycles checking it.
2692       if (flag == NULL || (!final_spin && flag->done_check())) {
2693         KA_TRACE(
2694             15,
2695             ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n",
2696              gtid));
2697         return TRUE;
2698       }
2699       if (thread->th.th_task_team == NULL) {
2700         break;
2701       }
2702       // Yield before executing next task
2703       KMP_YIELD(__kmp_library == library_throughput);
2704       // If execution of a stolen task results in more tasks being placed on our
2705       // run queue, reset use_own_tasks
2706       if (!use_own_tasks && TCR_4(threads_data[tid].td.td_deque_ntasks) != 0) {
2707         KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d stolen task spawned "
2708                       "other tasks, restart\n",
2709                       gtid));
2710         use_own_tasks = 1;
2711         new_victim = 0;
2712       }
2713     }
2714 
2715 // The task source has been exhausted. If in final spin loop of barrier, check
2716 // if termination condition is satisfied.
2717 #if OMP_45_ENABLED
2718     // The work queue may be empty but there might be proxy tasks still
2719     // executing
2720     if (final_spin &&
2721         KMP_ATOMIC_LD_ACQ(&current_task->td_incomplete_child_tasks) == 0)
2722 #else
2723     if (final_spin)
2724 #endif
2725     {
2726       // First, decrement the #unfinished threads, if that has not already been
2727       // done.  This decrement might be to the spin location, and result in the
2728       // termination condition being satisfied.
2729       if (!*thread_finished) {
2730         kmp_int32 count;
2731 
2732         count = KMP_ATOMIC_DEC(unfinished_threads) - 1;
2733         KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d dec "
2734                       "unfinished_threads to %d task_team=%p\n",
2735                       gtid, count, task_team));
2736         *thread_finished = TRUE;
2737       }
2738 
2739       // It is now unsafe to reference thread->th.th_team !!!
2740       // Decrementing task_team->tt.tt_unfinished_threads can allow the master
2741       // thread to pass through the barrier, where it might reset each thread's
2742       // th.th_team field for the next parallel region. If we can steal more
2743       // work, we know that this has not happened yet.
2744       if (flag != NULL && flag->done_check()) {
2745         KA_TRACE(
2746             15,
2747             ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n",
2748              gtid));
2749         return TRUE;
2750       }
2751     }
2752 
2753     // If this thread's task team is NULL, master has recognized that there are
2754     // no more tasks; bail out
2755     if (thread->th.th_task_team == NULL) {
2756       KA_TRACE(15,
2757                ("__kmp_execute_tasks_template: T#%d no more tasks\n", gtid));
2758       return FALSE;
2759     }
2760 
2761 #if OMP_45_ENABLED
2762     // We could be getting tasks from target constructs; if this is the only
2763     // thread, keep trying to execute tasks from own queue
2764     if (nthreads == 1)
2765       use_own_tasks = 1;
2766     else
2767 #endif
2768     {
2769       KA_TRACE(15,
2770                ("__kmp_execute_tasks_template: T#%d can't find work\n", gtid));
2771       return FALSE;
2772     }
2773   }
2774 }
2775 
2776 int __kmp_execute_tasks_32(
2777     kmp_info_t *thread, kmp_int32 gtid, kmp_flag_32 *flag, int final_spin,
2778     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2779     kmp_int32 is_constrained) {
2780   return __kmp_execute_tasks_template(
2781       thread, gtid, flag, final_spin,
2782       thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
2783 }
2784 
2785 int __kmp_execute_tasks_64(
2786     kmp_info_t *thread, kmp_int32 gtid, kmp_flag_64 *flag, int final_spin,
2787     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2788     kmp_int32 is_constrained) {
2789   return __kmp_execute_tasks_template(
2790       thread, gtid, flag, final_spin,
2791       thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
2792 }
2793 
2794 int __kmp_execute_tasks_oncore(
2795     kmp_info_t *thread, kmp_int32 gtid, kmp_flag_oncore *flag, int final_spin,
2796     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2797     kmp_int32 is_constrained) {
2798   return __kmp_execute_tasks_template(
2799       thread, gtid, flag, final_spin,
2800       thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
2801 }
2802 
2803 // __kmp_enable_tasking: Allocate task team and resume threads sleeping at the
2804 // next barrier so they can assist in executing enqueued tasks.
2805 // First thread in allocates the task team atomically.
2806 static void __kmp_enable_tasking(kmp_task_team_t *task_team,
2807                                  kmp_info_t *this_thr) {
2808   kmp_thread_data_t *threads_data;
2809   int nthreads, i, is_init_thread;
2810 
2811   KA_TRACE(10, ("__kmp_enable_tasking(enter): T#%d\n",
2812                 __kmp_gtid_from_thread(this_thr)));
2813 
2814   KMP_DEBUG_ASSERT(task_team != NULL);
2815   KMP_DEBUG_ASSERT(this_thr->th.th_team != NULL);
2816 
2817   nthreads = task_team->tt.tt_nproc;
2818   KMP_DEBUG_ASSERT(nthreads > 0);
2819   KMP_DEBUG_ASSERT(nthreads == this_thr->th.th_team->t.t_nproc);
2820 
2821   // Allocate or increase the size of threads_data if necessary
2822   is_init_thread = __kmp_realloc_task_threads_data(this_thr, task_team);
2823 
2824   if (!is_init_thread) {
2825     // Some other thread already set up the array.
2826     KA_TRACE(
2827         20,
2828         ("__kmp_enable_tasking(exit): T#%d: threads array already set up.\n",
2829          __kmp_gtid_from_thread(this_thr)));
2830     return;
2831   }
2832   threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data);
2833   KMP_DEBUG_ASSERT(threads_data != NULL);
2834 
2835   if ((__kmp_tasking_mode == tskm_task_teams) &&
2836       (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME)) {
2837     // Release any threads sleeping at the barrier, so that they can steal
2838     // tasks and execute them.  In extra barrier mode, tasks do not sleep
2839     // at the separate tasking barrier, so this isn't a problem.
2840     for (i = 0; i < nthreads; i++) {
2841       volatile void *sleep_loc;
2842       kmp_info_t *thread = threads_data[i].td.td_thr;
2843 
2844       if (i == this_thr->th.th_info.ds.ds_tid) {
2845         continue;
2846       }
2847       // Since we haven't locked the thread's suspend mutex lock at this
2848       // point, there is a small window where a thread might be putting
2849       // itself to sleep, but hasn't set the th_sleep_loc field yet.
2850       // To work around this, __kmp_execute_tasks_template() periodically checks
2851       // see if other threads are sleeping (using the same random mechanism that
2852       // is used for task stealing) and awakens them if they are.
2853       if ((sleep_loc = TCR_PTR(CCAST(void *, thread->th.th_sleep_loc))) !=
2854           NULL) {
2855         KF_TRACE(50, ("__kmp_enable_tasking: T#%d waking up thread T#%d\n",
2856                       __kmp_gtid_from_thread(this_thr),
2857                       __kmp_gtid_from_thread(thread)));
2858         __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc);
2859       } else {
2860         KF_TRACE(50, ("__kmp_enable_tasking: T#%d don't wake up thread T#%d\n",
2861                       __kmp_gtid_from_thread(this_thr),
2862                       __kmp_gtid_from_thread(thread)));
2863       }
2864     }
2865   }
2866 
2867   KA_TRACE(10, ("__kmp_enable_tasking(exit): T#%d\n",
2868                 __kmp_gtid_from_thread(this_thr)));
2869 }
2870 
2871 /* // TODO: Check the comment consistency
2872  * Utility routines for "task teams".  A task team (kmp_task_t) is kind of
2873  * like a shadow of the kmp_team_t data struct, with a different lifetime.
2874  * After a child * thread checks into a barrier and calls __kmp_release() from
2875  * the particular variant of __kmp_<barrier_kind>_barrier_gather(), it can no
2876  * longer assume that the kmp_team_t structure is intact (at any moment, the
2877  * master thread may exit the barrier code and free the team data structure,
2878  * and return the threads to the thread pool).
2879  *
2880  * This does not work with the the tasking code, as the thread is still
2881  * expected to participate in the execution of any tasks that may have been
2882  * spawned my a member of the team, and the thread still needs access to all
2883  * to each thread in the team, so that it can steal work from it.
2884  *
2885  * Enter the existence of the kmp_task_team_t struct.  It employs a reference
2886  * counting mechanims, and is allocated by the master thread before calling
2887  * __kmp_<barrier_kind>_release, and then is release by the last thread to
2888  * exit __kmp_<barrier_kind>_release at the next barrier.  I.e. the lifetimes
2889  * of the kmp_task_team_t structs for consecutive barriers can overlap
2890  * (and will, unless the master thread is the last thread to exit the barrier
2891  * release phase, which is not typical).
2892  *
2893  * The existence of such a struct is useful outside the context of tasking,
2894  * but for now, I'm trying to keep it specific to the OMP_30_ENABLED macro,
2895  * so that any performance differences show up when comparing the 2.5 vs. 3.0
2896  * libraries.
2897  *
2898  * We currently use the existence of the threads array as an indicator that
2899  * tasks were spawned since the last barrier.  If the structure is to be
2900  * useful outside the context of tasking, then this will have to change, but
2901  * not settting the field minimizes the performance impact of tasking on
2902  * barriers, when no explicit tasks were spawned (pushed, actually).
2903  */
2904 
2905 static kmp_task_team_t *__kmp_free_task_teams =
2906     NULL; // Free list for task_team data structures
2907 // Lock for task team data structures
2908 kmp_bootstrap_lock_t __kmp_task_team_lock =
2909     KMP_BOOTSTRAP_LOCK_INITIALIZER(__kmp_task_team_lock);
2910 
2911 // __kmp_alloc_task_deque:
2912 // Allocates a task deque for a particular thread, and initialize the necessary
2913 // data structures relating to the deque.  This only happens once per thread
2914 // per task team since task teams are recycled. No lock is needed during
2915 // allocation since each thread allocates its own deque.
2916 static void __kmp_alloc_task_deque(kmp_info_t *thread,
2917                                    kmp_thread_data_t *thread_data) {
2918   __kmp_init_bootstrap_lock(&thread_data->td.td_deque_lock);
2919   KMP_DEBUG_ASSERT(thread_data->td.td_deque == NULL);
2920 
2921   // Initialize last stolen task field to "none"
2922   thread_data->td.td_deque_last_stolen = -1;
2923 
2924   KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) == 0);
2925   KMP_DEBUG_ASSERT(thread_data->td.td_deque_head == 0);
2926   KMP_DEBUG_ASSERT(thread_data->td.td_deque_tail == 0);
2927 
2928   KE_TRACE(
2929       10,
2930       ("__kmp_alloc_task_deque: T#%d allocating deque[%d] for thread_data %p\n",
2931        __kmp_gtid_from_thread(thread), INITIAL_TASK_DEQUE_SIZE, thread_data));
2932   // Allocate space for task deque, and zero the deque
2933   // Cannot use __kmp_thread_calloc() because threads not around for
2934   // kmp_reap_task_team( ).
2935   thread_data->td.td_deque = (kmp_taskdata_t **)__kmp_allocate(
2936       INITIAL_TASK_DEQUE_SIZE * sizeof(kmp_taskdata_t *));
2937   thread_data->td.td_deque_size = INITIAL_TASK_DEQUE_SIZE;
2938 }
2939 
2940 // __kmp_free_task_deque:
2941 // Deallocates a task deque for a particular thread. Happens at library
2942 // deallocation so don't need to reset all thread data fields.
2943 static void __kmp_free_task_deque(kmp_thread_data_t *thread_data) {
2944   if (thread_data->td.td_deque != NULL) {
2945     __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
2946     TCW_4(thread_data->td.td_deque_ntasks, 0);
2947     __kmp_free(thread_data->td.td_deque);
2948     thread_data->td.td_deque = NULL;
2949     __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2950   }
2951 
2952 #ifdef BUILD_TIED_TASK_STACK
2953   // GEH: Figure out what to do here for td_susp_tied_tasks
2954   if (thread_data->td.td_susp_tied_tasks.ts_entries != TASK_STACK_EMPTY) {
2955     __kmp_free_task_stack(__kmp_thread_from_gtid(gtid), thread_data);
2956   }
2957 #endif // BUILD_TIED_TASK_STACK
2958 }
2959 
2960 // __kmp_realloc_task_threads_data:
2961 // Allocates a threads_data array for a task team, either by allocating an
2962 // initial array or enlarging an existing array.  Only the first thread to get
2963 // the lock allocs or enlarges the array and re-initializes the array eleemnts.
2964 // That thread returns "TRUE", the rest return "FALSE".
2965 // Assumes that the new array size is given by task_team -> tt.tt_nproc.
2966 // The current size is given by task_team -> tt.tt_max_threads.
2967 static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
2968                                            kmp_task_team_t *task_team) {
2969   kmp_thread_data_t **threads_data_p;
2970   kmp_int32 nthreads, maxthreads;
2971   int is_init_thread = FALSE;
2972 
2973   if (TCR_4(task_team->tt.tt_found_tasks)) {
2974     // Already reallocated and initialized.
2975     return FALSE;
2976   }
2977 
2978   threads_data_p = &task_team->tt.tt_threads_data;
2979   nthreads = task_team->tt.tt_nproc;
2980   maxthreads = task_team->tt.tt_max_threads;
2981 
2982   // All threads must lock when they encounter the first task of the implicit
2983   // task region to make sure threads_data fields are (re)initialized before
2984   // used.
2985   __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock);
2986 
2987   if (!TCR_4(task_team->tt.tt_found_tasks)) {
2988     // first thread to enable tasking
2989     kmp_team_t *team = thread->th.th_team;
2990     int i;
2991 
2992     is_init_thread = TRUE;
2993     if (maxthreads < nthreads) {
2994 
2995       if (*threads_data_p != NULL) {
2996         kmp_thread_data_t *old_data = *threads_data_p;
2997         kmp_thread_data_t *new_data = NULL;
2998 
2999         KE_TRACE(
3000             10,
3001             ("__kmp_realloc_task_threads_data: T#%d reallocating "
3002              "threads data for task_team %p, new_size = %d, old_size = %d\n",
3003              __kmp_gtid_from_thread(thread), task_team, nthreads, maxthreads));
3004         // Reallocate threads_data to have more elements than current array
3005         // Cannot use __kmp_thread_realloc() because threads not around for
3006         // kmp_reap_task_team( ).  Note all new array entries are initialized
3007         // to zero by __kmp_allocate().
3008         new_data = (kmp_thread_data_t *)__kmp_allocate(
3009             nthreads * sizeof(kmp_thread_data_t));
3010         // copy old data to new data
3011         KMP_MEMCPY_S((void *)new_data, nthreads * sizeof(kmp_thread_data_t),
3012                      (void *)old_data, maxthreads * sizeof(kmp_thread_data_t));
3013 
3014 #ifdef BUILD_TIED_TASK_STACK
3015         // GEH: Figure out if this is the right thing to do
3016         for (i = maxthreads; i < nthreads; i++) {
3017           kmp_thread_data_t *thread_data = &(*threads_data_p)[i];
3018           __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data);
3019         }
3020 #endif // BUILD_TIED_TASK_STACK
3021         // Install the new data and free the old data
3022         (*threads_data_p) = new_data;
3023         __kmp_free(old_data);
3024       } else {
3025         KE_TRACE(10, ("__kmp_realloc_task_threads_data: T#%d allocating "
3026                       "threads data for task_team %p, size = %d\n",
3027                       __kmp_gtid_from_thread(thread), task_team, nthreads));
3028         // Make the initial allocate for threads_data array, and zero entries
3029         // Cannot use __kmp_thread_calloc() because threads not around for
3030         // kmp_reap_task_team( ).
3031         ANNOTATE_IGNORE_WRITES_BEGIN();
3032         *threads_data_p = (kmp_thread_data_t *)__kmp_allocate(
3033             nthreads * sizeof(kmp_thread_data_t));
3034         ANNOTATE_IGNORE_WRITES_END();
3035 #ifdef BUILD_TIED_TASK_STACK
3036         // GEH: Figure out if this is the right thing to do
3037         for (i = 0; i < nthreads; i++) {
3038           kmp_thread_data_t *thread_data = &(*threads_data_p)[i];
3039           __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data);
3040         }
3041 #endif // BUILD_TIED_TASK_STACK
3042       }
3043       task_team->tt.tt_max_threads = nthreads;
3044     } else {
3045       // If array has (more than) enough elements, go ahead and use it
3046       KMP_DEBUG_ASSERT(*threads_data_p != NULL);
3047     }
3048 
3049     // initialize threads_data pointers back to thread_info structures
3050     for (i = 0; i < nthreads; i++) {
3051       kmp_thread_data_t *thread_data = &(*threads_data_p)[i];
3052       thread_data->td.td_thr = team->t.t_threads[i];
3053 
3054       if (thread_data->td.td_deque_last_stolen >= nthreads) {
3055         // The last stolen field survives across teams / barrier, and the number
3056         // of threads may have changed.  It's possible (likely?) that a new
3057         // parallel region will exhibit the same behavior as previous region.
3058         thread_data->td.td_deque_last_stolen = -1;
3059       }
3060     }
3061 
3062     KMP_MB();
3063     TCW_SYNC_4(task_team->tt.tt_found_tasks, TRUE);
3064   }
3065 
3066   __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock);
3067   return is_init_thread;
3068 }
3069 
3070 // __kmp_free_task_threads_data:
3071 // Deallocates a threads_data array for a task team, including any attached
3072 // tasking deques.  Only occurs at library shutdown.
3073 static void __kmp_free_task_threads_data(kmp_task_team_t *task_team) {
3074   __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock);
3075   if (task_team->tt.tt_threads_data != NULL) {
3076     int i;
3077     for (i = 0; i < task_team->tt.tt_max_threads; i++) {
3078       __kmp_free_task_deque(&task_team->tt.tt_threads_data[i]);
3079     }
3080     __kmp_free(task_team->tt.tt_threads_data);
3081     task_team->tt.tt_threads_data = NULL;
3082   }
3083   __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock);
3084 }
3085 
3086 // __kmp_allocate_task_team:
3087 // Allocates a task team associated with a specific team, taking it from
3088 // the global task team free list if possible.  Also initializes data
3089 // structures.
3090 static kmp_task_team_t *__kmp_allocate_task_team(kmp_info_t *thread,
3091                                                  kmp_team_t *team) {
3092   kmp_task_team_t *task_team = NULL;
3093   int nthreads;
3094 
3095   KA_TRACE(20, ("__kmp_allocate_task_team: T#%d entering; team = %p\n",
3096                 (thread ? __kmp_gtid_from_thread(thread) : -1), team));
3097 
3098   if (TCR_PTR(__kmp_free_task_teams) != NULL) {
3099     // Take a task team from the task team pool
3100     __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
3101     if (__kmp_free_task_teams != NULL) {
3102       task_team = __kmp_free_task_teams;
3103       TCW_PTR(__kmp_free_task_teams, task_team->tt.tt_next);
3104       task_team->tt.tt_next = NULL;
3105     }
3106     __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
3107   }
3108 
3109   if (task_team == NULL) {
3110     KE_TRACE(10, ("__kmp_allocate_task_team: T#%d allocating "
3111                   "task team for team %p\n",
3112                   __kmp_gtid_from_thread(thread), team));
3113     // Allocate a new task team if one is not available.
3114     // Cannot use __kmp_thread_malloc() because threads not around for
3115     // kmp_reap_task_team( ).
3116     task_team = (kmp_task_team_t *)__kmp_allocate(sizeof(kmp_task_team_t));
3117     __kmp_init_bootstrap_lock(&task_team->tt.tt_threads_lock);
3118     // AC: __kmp_allocate zeroes returned memory
3119     // task_team -> tt.tt_threads_data = NULL;
3120     // task_team -> tt.tt_max_threads = 0;
3121     // task_team -> tt.tt_next = NULL;
3122   }
3123 
3124   TCW_4(task_team->tt.tt_found_tasks, FALSE);
3125 #if OMP_45_ENABLED
3126   TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE);
3127 #endif
3128   task_team->tt.tt_nproc = nthreads = team->t.t_nproc;
3129 
3130   KMP_ATOMIC_ST_REL(&task_team->tt.tt_unfinished_threads, nthreads);
3131   TCW_4(task_team->tt.tt_active, TRUE);
3132 
3133   KA_TRACE(20, ("__kmp_allocate_task_team: T#%d exiting; task_team = %p "
3134                 "unfinished_threads init'd to %d\n",
3135                 (thread ? __kmp_gtid_from_thread(thread) : -1), task_team,
3136                 KMP_ATOMIC_LD_RLX(&task_team->tt.tt_unfinished_threads)));
3137   return task_team;
3138 }
3139 
3140 // __kmp_free_task_team:
3141 // Frees the task team associated with a specific thread, and adds it
3142 // to the global task team free list.
3143 void __kmp_free_task_team(kmp_info_t *thread, kmp_task_team_t *task_team) {
3144   KA_TRACE(20, ("__kmp_free_task_team: T#%d task_team = %p\n",
3145                 thread ? __kmp_gtid_from_thread(thread) : -1, task_team));
3146 
3147   // Put task team back on free list
3148   __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
3149 
3150   KMP_DEBUG_ASSERT(task_team->tt.tt_next == NULL);
3151   task_team->tt.tt_next = __kmp_free_task_teams;
3152   TCW_PTR(__kmp_free_task_teams, task_team);
3153 
3154   __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
3155 }
3156 
3157 // __kmp_reap_task_teams:
3158 // Free all the task teams on the task team free list.
3159 // Should only be done during library shutdown.
3160 // Cannot do anything that needs a thread structure or gtid since they are
3161 // already gone.
3162 void __kmp_reap_task_teams(void) {
3163   kmp_task_team_t *task_team;
3164 
3165   if (TCR_PTR(__kmp_free_task_teams) != NULL) {
3166     // Free all task_teams on the free list
3167     __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
3168     while ((task_team = __kmp_free_task_teams) != NULL) {
3169       __kmp_free_task_teams = task_team->tt.tt_next;
3170       task_team->tt.tt_next = NULL;
3171 
3172       // Free threads_data if necessary
3173       if (task_team->tt.tt_threads_data != NULL) {
3174         __kmp_free_task_threads_data(task_team);
3175       }
3176       __kmp_free(task_team);
3177     }
3178     __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
3179   }
3180 }
3181 
3182 // __kmp_wait_to_unref_task_teams:
3183 // Some threads could still be in the fork barrier release code, possibly
3184 // trying to steal tasks.  Wait for each thread to unreference its task team.
3185 void __kmp_wait_to_unref_task_teams(void) {
3186   kmp_info_t *thread;
3187   kmp_uint32 spins;
3188   int done;
3189 
3190   KMP_INIT_YIELD(spins);
3191 
3192   for (;;) {
3193     done = TRUE;
3194 
3195     // TODO: GEH - this may be is wrong because some sync would be necessary
3196     // in case threads are added to the pool during the traversal. Need to
3197     // verify that lock for thread pool is held when calling this routine.
3198     for (thread = CCAST(kmp_info_t *, __kmp_thread_pool); thread != NULL;
3199          thread = thread->th.th_next_pool) {
3200 #if KMP_OS_WINDOWS
3201       DWORD exit_val;
3202 #endif
3203       if (TCR_PTR(thread->th.th_task_team) == NULL) {
3204         KA_TRACE(10, ("__kmp_wait_to_unref_task_team: T#%d task_team == NULL\n",
3205                       __kmp_gtid_from_thread(thread)));
3206         continue;
3207       }
3208 #if KMP_OS_WINDOWS
3209       // TODO: GEH - add this check for Linux* OS / OS X* as well?
3210       if (!__kmp_is_thread_alive(thread, &exit_val)) {
3211         thread->th.th_task_team = NULL;
3212         continue;
3213       }
3214 #endif
3215 
3216       done = FALSE; // Because th_task_team pointer is not NULL for this thread
3217 
3218       KA_TRACE(10, ("__kmp_wait_to_unref_task_team: Waiting for T#%d to "
3219                     "unreference task_team\n",
3220                     __kmp_gtid_from_thread(thread)));
3221 
3222       if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
3223         volatile void *sleep_loc;
3224         // If the thread is sleeping, awaken it.
3225         if ((sleep_loc = TCR_PTR(CCAST(void *, thread->th.th_sleep_loc))) !=
3226             NULL) {
3227           KA_TRACE(
3228               10,
3229               ("__kmp_wait_to_unref_task_team: T#%d waking up thread T#%d\n",
3230                __kmp_gtid_from_thread(thread), __kmp_gtid_from_thread(thread)));
3231           __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc);
3232         }
3233       }
3234     }
3235     if (done) {
3236       break;
3237     }
3238 
3239     // If we are oversubscribed, or have waited a bit (and library mode is
3240     // throughput), yield. Pause is in the following code.
3241     KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc);
3242     KMP_YIELD_SPIN(spins); // Yields only if KMP_LIBRARY=throughput
3243   }
3244 }
3245 
3246 // __kmp_task_team_setup:  Create a task_team for the current team, but use
3247 // an already created, unused one if it already exists.
3248 void __kmp_task_team_setup(kmp_info_t *this_thr, kmp_team_t *team, int always) {
3249   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
3250 
3251   // If this task_team hasn't been created yet, allocate it. It will be used in
3252   // the region after the next.
3253   // If it exists, it is the current task team and shouldn't be touched yet as
3254   // it may still be in use.
3255   if (team->t.t_task_team[this_thr->th.th_task_state] == NULL &&
3256       (always || team->t.t_nproc > 1)) {
3257     team->t.t_task_team[this_thr->th.th_task_state] =
3258         __kmp_allocate_task_team(this_thr, team);
3259     KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created new task_team %p "
3260                   "for team %d at parity=%d\n",
3261                   __kmp_gtid_from_thread(this_thr),
3262                   team->t.t_task_team[this_thr->th.th_task_state],
3263                   ((team != NULL) ? team->t.t_id : -1),
3264                   this_thr->th.th_task_state));
3265   }
3266 
3267   // After threads exit the release, they will call sync, and then point to this
3268   // other task_team; make sure it is allocated and properly initialized. As
3269   // threads spin in the barrier release phase, they will continue to use the
3270   // previous task_team struct(above), until they receive the signal to stop
3271   // checking for tasks (they can't safely reference the kmp_team_t struct,
3272   // which could be reallocated by the master thread). No task teams are formed
3273   // for serialized teams.
3274   if (team->t.t_nproc > 1) {
3275     int other_team = 1 - this_thr->th.th_task_state;
3276     if (team->t.t_task_team[other_team] == NULL) { // setup other team as well
3277       team->t.t_task_team[other_team] =
3278           __kmp_allocate_task_team(this_thr, team);
3279       KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created second new "
3280                     "task_team %p for team %d at parity=%d\n",
3281                     __kmp_gtid_from_thread(this_thr),
3282                     team->t.t_task_team[other_team],
3283                     ((team != NULL) ? team->t.t_id : -1), other_team));
3284     } else { // Leave the old task team struct in place for the upcoming region;
3285       // adjust as needed
3286       kmp_task_team_t *task_team = team->t.t_task_team[other_team];
3287       if (!task_team->tt.tt_active ||
3288           team->t.t_nproc != task_team->tt.tt_nproc) {
3289         TCW_4(task_team->tt.tt_nproc, team->t.t_nproc);
3290         TCW_4(task_team->tt.tt_found_tasks, FALSE);
3291 #if OMP_45_ENABLED
3292         TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE);
3293 #endif
3294         KMP_ATOMIC_ST_REL(&task_team->tt.tt_unfinished_threads,
3295                           team->t.t_nproc);
3296         TCW_4(task_team->tt.tt_active, TRUE);
3297       }
3298       // if team size has changed, the first thread to enable tasking will
3299       // realloc threads_data if necessary
3300       KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d reset next task_team "
3301                     "%p for team %d at parity=%d\n",
3302                     __kmp_gtid_from_thread(this_thr),
3303                     team->t.t_task_team[other_team],
3304                     ((team != NULL) ? team->t.t_id : -1), other_team));
3305     }
3306   }
3307 }
3308 
3309 // __kmp_task_team_sync: Propagation of task team data from team to threads
3310 // which happens just after the release phase of a team barrier.  This may be
3311 // called by any thread, but only for teams with # threads > 1.
3312 void __kmp_task_team_sync(kmp_info_t *this_thr, kmp_team_t *team) {
3313   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
3314 
3315   // Toggle the th_task_state field, to switch which task_team this thread
3316   // refers to
3317   this_thr->th.th_task_state = 1 - this_thr->th.th_task_state;
3318   // It is now safe to propagate the task team pointer from the team struct to
3319   // the current thread.
3320   TCW_PTR(this_thr->th.th_task_team,
3321           team->t.t_task_team[this_thr->th.th_task_state]);
3322   KA_TRACE(20,
3323            ("__kmp_task_team_sync: Thread T#%d task team switched to task_team "
3324             "%p from Team #%d (parity=%d)\n",
3325             __kmp_gtid_from_thread(this_thr), this_thr->th.th_task_team,
3326             ((team != NULL) ? team->t.t_id : -1), this_thr->th.th_task_state));
3327 }
3328 
3329 // __kmp_task_team_wait: Master thread waits for outstanding tasks after the
3330 // barrier gather phase. Only called by master thread if #threads in team > 1 or
3331 // if proxy tasks were created.
3332 //
3333 // wait is a flag that defaults to 1 (see kmp.h), but waiting can be turned off
3334 // by passing in 0 optionally as the last argument. When wait is zero, master
3335 // thread does not wait for unfinished_threads to reach 0.
3336 void __kmp_task_team_wait(
3337     kmp_info_t *this_thr,
3338     kmp_team_t *team USE_ITT_BUILD_ARG(void *itt_sync_obj), int wait) {
3339   kmp_task_team_t *task_team = team->t.t_task_team[this_thr->th.th_task_state];
3340 
3341   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
3342   KMP_DEBUG_ASSERT(task_team == this_thr->th.th_task_team);
3343 
3344   if ((task_team != NULL) && KMP_TASKING_ENABLED(task_team)) {
3345     if (wait) {
3346       KA_TRACE(20, ("__kmp_task_team_wait: Master T#%d waiting for all tasks "
3347                     "(for unfinished_threads to reach 0) on task_team = %p\n",
3348                     __kmp_gtid_from_thread(this_thr), task_team));
3349       // Worker threads may have dropped through to release phase, but could
3350       // still be executing tasks. Wait here for tasks to complete. To avoid
3351       // memory contention, only master thread checks termination condition.
3352       kmp_flag_32 flag(RCAST(std::atomic<kmp_uint32> *,
3353                              &task_team->tt.tt_unfinished_threads),
3354                        0U);
3355       flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
3356     }
3357     // Deactivate the old task team, so that the worker threads will stop
3358     // referencing it while spinning.
3359     KA_TRACE(
3360         20,
3361         ("__kmp_task_team_wait: Master T#%d deactivating task_team %p: "
3362          "setting active to false, setting local and team's pointer to NULL\n",
3363          __kmp_gtid_from_thread(this_thr), task_team));
3364 #if OMP_45_ENABLED
3365     KMP_DEBUG_ASSERT(task_team->tt.tt_nproc > 1 ||
3366                      task_team->tt.tt_found_proxy_tasks == TRUE);
3367     TCW_SYNC_4(task_team->tt.tt_found_proxy_tasks, FALSE);
3368 #else
3369     KMP_DEBUG_ASSERT(task_team->tt.tt_nproc > 1);
3370 #endif
3371     KMP_CHECK_UPDATE(task_team->tt.tt_untied_task_encountered, 0);
3372     TCW_SYNC_4(task_team->tt.tt_active, FALSE);
3373     KMP_MB();
3374 
3375     TCW_PTR(this_thr->th.th_task_team, NULL);
3376   }
3377 }
3378 
3379 // __kmp_tasking_barrier:
3380 // This routine may only called when __kmp_tasking_mode == tskm_extra_barrier.
3381 // Internal function to execute all tasks prior to a regular barrier or a join
3382 // barrier. It is a full barrier itself, which unfortunately turns regular
3383 // barriers into double barriers and join barriers into 1 1/2 barriers.
3384 void __kmp_tasking_barrier(kmp_team_t *team, kmp_info_t *thread, int gtid) {
3385   std::atomic<kmp_uint32> *spin = RCAST(
3386       std::atomic<kmp_uint32> *,
3387       &team->t.t_task_team[thread->th.th_task_state]->tt.tt_unfinished_threads);
3388   int flag = FALSE;
3389   KMP_DEBUG_ASSERT(__kmp_tasking_mode == tskm_extra_barrier);
3390 
3391 #if USE_ITT_BUILD
3392   KMP_FSYNC_SPIN_INIT(spin, NULL);
3393 #endif /* USE_ITT_BUILD */
3394   kmp_flag_32 spin_flag(spin, 0U);
3395   while (!spin_flag.execute_tasks(thread, gtid, TRUE,
3396                                   &flag USE_ITT_BUILD_ARG(NULL), 0)) {
3397 #if USE_ITT_BUILD
3398     // TODO: What about itt_sync_obj??
3399     KMP_FSYNC_SPIN_PREPARE(RCAST(void *, spin));
3400 #endif /* USE_ITT_BUILD */
3401 
3402     if (TCR_4(__kmp_global.g.g_done)) {
3403       if (__kmp_global.g.g_abort)
3404         __kmp_abort_thread();
3405       break;
3406     }
3407     KMP_YIELD(TRUE); // GH: We always yield here
3408   }
3409 #if USE_ITT_BUILD
3410   KMP_FSYNC_SPIN_ACQUIRED(RCAST(void *, spin));
3411 #endif /* USE_ITT_BUILD */
3412 }
3413 
3414 #if OMP_45_ENABLED
3415 
3416 // __kmp_give_task puts a task into a given thread queue if:
3417 //  - the queue for that thread was created
3418 //  - there's space in that queue
3419 // Because of this, __kmp_push_task needs to check if there's space after
3420 // getting the lock
3421 static bool __kmp_give_task(kmp_info_t *thread, kmp_int32 tid, kmp_task_t *task,
3422                             kmp_int32 pass) {
3423   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
3424   kmp_task_team_t *task_team = taskdata->td_task_team;
3425 
3426   KA_TRACE(20, ("__kmp_give_task: trying to give task %p to thread %d.\n",
3427                 taskdata, tid));
3428 
3429   // If task_team is NULL something went really bad...
3430   KMP_DEBUG_ASSERT(task_team != NULL);
3431 
3432   bool result = false;
3433   kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid];
3434 
3435   if (thread_data->td.td_deque == NULL) {
3436     // There's no queue in this thread, go find another one
3437     // We're guaranteed that at least one thread has a queue
3438     KA_TRACE(30,
3439              ("__kmp_give_task: thread %d has no queue while giving task %p.\n",
3440               tid, taskdata));
3441     return result;
3442   }
3443 
3444   if (TCR_4(thread_data->td.td_deque_ntasks) >=
3445       TASK_DEQUE_SIZE(thread_data->td)) {
3446     KA_TRACE(
3447         30,
3448         ("__kmp_give_task: queue is full while giving task %p to thread %d.\n",
3449          taskdata, tid));
3450 
3451     // if this deque is bigger than the pass ratio give a chance to another
3452     // thread
3453     if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass)
3454       return result;
3455 
3456     __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
3457     __kmp_realloc_task_deque(thread, thread_data);
3458 
3459   } else {
3460 
3461     __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
3462 
3463     if (TCR_4(thread_data->td.td_deque_ntasks) >=
3464         TASK_DEQUE_SIZE(thread_data->td)) {
3465       KA_TRACE(30, ("__kmp_give_task: queue is full while giving task %p to "
3466                     "thread %d.\n",
3467                     taskdata, tid));
3468 
3469       // if this deque is bigger than the pass ratio give a chance to another
3470       // thread
3471       if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass)
3472         goto release_and_exit;
3473 
3474       __kmp_realloc_task_deque(thread, thread_data);
3475     }
3476   }
3477 
3478   // lock is held here, and there is space in the deque
3479 
3480   thread_data->td.td_deque[thread_data->td.td_deque_tail] = taskdata;
3481   // Wrap index.
3482   thread_data->td.td_deque_tail =
3483       (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td);
3484   TCW_4(thread_data->td.td_deque_ntasks,
3485         TCR_4(thread_data->td.td_deque_ntasks) + 1);
3486 
3487   result = true;
3488   KA_TRACE(30, ("__kmp_give_task: successfully gave task %p to thread %d.\n",
3489                 taskdata, tid));
3490 
3491 release_and_exit:
3492   __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
3493 
3494   return result;
3495 }
3496 
3497 /* The finish of the proxy tasks is divided in two pieces:
3498     - the top half is the one that can be done from a thread outside the team
3499     - the bottom half must be run from a thread within the team
3500 
3501    In order to run the bottom half the task gets queued back into one of the
3502    threads of the team. Once the td_incomplete_child_task counter of the parent
3503    is decremented the threads can leave the barriers. So, the bottom half needs
3504    to be queued before the counter is decremented. The top half is therefore
3505    divided in two parts:
3506     - things that can be run before queuing the bottom half
3507     - things that must be run after queuing the bottom half
3508 
3509    This creates a second race as the bottom half can free the task before the
3510    second top half is executed. To avoid this we use the
3511    td_incomplete_child_task of the proxy task to synchronize the top and bottom
3512    half. */
3513 static void __kmp_first_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
3514   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
3515   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
3516   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
3517   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
3518 
3519   taskdata->td_flags.complete = 1; // mark the task as completed
3520 
3521   if (taskdata->td_taskgroup)
3522     KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
3523 
3524   // Create an imaginary children for this task so the bottom half cannot
3525   // release the task before we have completed the second top half
3526   KMP_ATOMIC_INC(&taskdata->td_incomplete_child_tasks);
3527 }
3528 
3529 static void __kmp_second_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
3530   kmp_int32 children = 0;
3531 
3532   // Predecrement simulated by "- 1" calculation
3533   children =
3534       KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks) - 1;
3535   KMP_DEBUG_ASSERT(children >= 0);
3536 
3537   // Remove the imaginary children
3538   KMP_ATOMIC_DEC(&taskdata->td_incomplete_child_tasks);
3539 }
3540 
3541 static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask) {
3542   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
3543   kmp_info_t *thread = __kmp_threads[gtid];
3544 
3545   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
3546   KMP_DEBUG_ASSERT(taskdata->td_flags.complete ==
3547                    1); // top half must run before bottom half
3548 
3549   // We need to wait to make sure the top half is finished
3550   // Spinning here should be ok as this should happen quickly
3551   while (KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) > 0)
3552     ;
3553 
3554   __kmp_release_deps(gtid, taskdata);
3555   __kmp_free_task_and_ancestors(gtid, taskdata, thread);
3556 }
3557 
3558 /*!
3559 @ingroup TASKING
3560 @param gtid Global Thread ID of encountering thread
3561 @param ptask Task which execution is completed
3562 
3563 Execute the completation of a proxy task from a thread of that is part of the
3564 team. Run first and bottom halves directly.
3565 */
3566 void __kmpc_proxy_task_completed(kmp_int32 gtid, kmp_task_t *ptask) {
3567   KMP_DEBUG_ASSERT(ptask != NULL);
3568   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
3569   KA_TRACE(
3570       10, ("__kmp_proxy_task_completed(enter): T#%d proxy task %p completing\n",
3571            gtid, taskdata));
3572 
3573   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
3574 
3575   __kmp_first_top_half_finish_proxy(taskdata);
3576   __kmp_second_top_half_finish_proxy(taskdata);
3577   __kmp_bottom_half_finish_proxy(gtid, ptask);
3578 
3579   KA_TRACE(10,
3580            ("__kmp_proxy_task_completed(exit): T#%d proxy task %p completing\n",
3581             gtid, taskdata));
3582 }
3583 
3584 /*!
3585 @ingroup TASKING
3586 @param ptask Task which execution is completed
3587 
3588 Execute the completation of a proxy task from a thread that could not belong to
3589 the team.
3590 */
3591 void __kmpc_proxy_task_completed_ooo(kmp_task_t *ptask) {
3592   KMP_DEBUG_ASSERT(ptask != NULL);
3593   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
3594 
3595   KA_TRACE(
3596       10,
3597       ("__kmp_proxy_task_completed_ooo(enter): proxy task completing ooo %p\n",
3598        taskdata));
3599 
3600   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
3601 
3602   __kmp_first_top_half_finish_proxy(taskdata);
3603 
3604   // Enqueue task to complete bottom half completion from a thread within the
3605   // corresponding team
3606   kmp_team_t *team = taskdata->td_team;
3607   kmp_int32 nthreads = team->t.t_nproc;
3608   kmp_info_t *thread;
3609 
3610   // This should be similar to start_k = __kmp_get_random( thread ) % nthreads
3611   // but we cannot use __kmp_get_random here
3612   kmp_int32 start_k = 0;
3613   kmp_int32 pass = 1;
3614   kmp_int32 k = start_k;
3615 
3616   do {
3617     // For now we're just linearly trying to find a thread
3618     thread = team->t.t_threads[k];
3619     k = (k + 1) % nthreads;
3620 
3621     // we did a full pass through all the threads
3622     if (k == start_k)
3623       pass = pass << 1;
3624 
3625   } while (!__kmp_give_task(thread, k, ptask, pass));
3626 
3627   __kmp_second_top_half_finish_proxy(taskdata);
3628 
3629   KA_TRACE(
3630       10,
3631       ("__kmp_proxy_task_completed_ooo(exit): proxy task completing ooo %p\n",
3632        taskdata));
3633 }
3634 
3635 // __kmp_task_dup_alloc: Allocate the taskdata and make a copy of source task
3636 // for taskloop
3637 //
3638 // thread:   allocating thread
3639 // task_src: pointer to source task to be duplicated
3640 // returns:  a pointer to the allocated kmp_task_t structure (task).
3641 kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src) {
3642   kmp_task_t *task;
3643   kmp_taskdata_t *taskdata;
3644   kmp_taskdata_t *taskdata_src;
3645   kmp_taskdata_t *parent_task = thread->th.th_current_task;
3646   size_t shareds_offset;
3647   size_t task_size;
3648 
3649   KA_TRACE(10, ("__kmp_task_dup_alloc(enter): Th %p, source task %p\n", thread,
3650                 task_src));
3651   taskdata_src = KMP_TASK_TO_TASKDATA(task_src);
3652   KMP_DEBUG_ASSERT(taskdata_src->td_flags.proxy ==
3653                    TASK_FULL); // it should not be proxy task
3654   KMP_DEBUG_ASSERT(taskdata_src->td_flags.tasktype == TASK_EXPLICIT);
3655   task_size = taskdata_src->td_size_alloc;
3656 
3657   // Allocate a kmp_taskdata_t block and a kmp_task_t block.
3658   KA_TRACE(30, ("__kmp_task_dup_alloc: Th %p, malloc size %ld\n", thread,
3659                 task_size));
3660 #if USE_FAST_MEMORY
3661   taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, task_size);
3662 #else
3663   taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, task_size);
3664 #endif /* USE_FAST_MEMORY */
3665   KMP_MEMCPY(taskdata, taskdata_src, task_size);
3666 
3667   task = KMP_TASKDATA_TO_TASK(taskdata);
3668 
3669   // Initialize new task (only specific fields not affected by memcpy)
3670   taskdata->td_task_id = KMP_GEN_TASK_ID();
3671   if (task->shareds != NULL) { // need setup shareds pointer
3672     shareds_offset = (char *)task_src->shareds - (char *)taskdata_src;
3673     task->shareds = &((char *)taskdata)[shareds_offset];
3674     KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) ==
3675                      0);
3676   }
3677   taskdata->td_alloc_thread = thread;
3678   taskdata->td_parent = parent_task;
3679   taskdata->td_taskgroup =
3680       parent_task
3681           ->td_taskgroup; // task inherits the taskgroup from the parent task
3682 
3683   // Only need to keep track of child task counts if team parallel and tasking
3684   // not serialized
3685   if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) {
3686     KMP_ATOMIC_INC(&parent_task->td_incomplete_child_tasks);
3687     if (parent_task->td_taskgroup)
3688       KMP_ATOMIC_INC(&parent_task->td_taskgroup->count);
3689     // Only need to keep track of allocated child tasks for explicit tasks since
3690     // implicit not deallocated
3691     if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT)
3692       KMP_ATOMIC_INC(&taskdata->td_parent->td_allocated_child_tasks);
3693   }
3694 
3695   KA_TRACE(20,
3696            ("__kmp_task_dup_alloc(exit): Th %p, created task %p, parent=%p\n",
3697             thread, taskdata, taskdata->td_parent));
3698 #if OMPT_SUPPORT
3699   if (UNLIKELY(ompt_enabled.enabled))
3700     __ompt_task_init(taskdata, thread->th.th_info.ds.ds_gtid);
3701 #endif
3702   return task;
3703 }
3704 
3705 // Routine optionally generated by the compiler for setting the lastprivate flag
3706 // and calling needed constructors for private/firstprivate objects
3707 // (used to form taskloop tasks from pattern task)
3708 // Parameters: dest task, src task, lastprivate flag.
3709 typedef void (*p_task_dup_t)(kmp_task_t *, kmp_task_t *, kmp_int32);
3710 
3711 KMP_BUILD_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);
3712 
3713 // class to encapsulate manipulating loop bounds in a taskloop task.
3714 // this abstracts away the Intel vs GOMP taskloop interface for setting/getting
3715 // the loop bound variables.
3716 class kmp_taskloop_bounds_t {
3717   kmp_task_t *task;
3718   const kmp_taskdata_t *taskdata;
3719   size_t lower_offset;
3720   size_t upper_offset;
3721 
3722 public:
3723   kmp_taskloop_bounds_t(kmp_task_t *_task, kmp_uint64 *lb, kmp_uint64 *ub)
3724       : task(_task), taskdata(KMP_TASK_TO_TASKDATA(task)),
3725         lower_offset((char *)lb - (char *)task),
3726         upper_offset((char *)ub - (char *)task) {
3727     KMP_DEBUG_ASSERT((char *)lb > (char *)_task);
3728     KMP_DEBUG_ASSERT((char *)ub > (char *)_task);
3729   }
3730   kmp_taskloop_bounds_t(kmp_task_t *_task, const kmp_taskloop_bounds_t &bounds)
3731       : task(_task), taskdata(KMP_TASK_TO_TASKDATA(_task)),
3732         lower_offset(bounds.lower_offset), upper_offset(bounds.upper_offset) {}
3733   size_t get_lower_offset() const { return lower_offset; }
3734   size_t get_upper_offset() const { return upper_offset; }
3735   kmp_uint64 get_lb() const {
3736     kmp_int64 retval;
3737 #if defined(KMP_GOMP_COMPAT)
3738     // Intel task just returns the lower bound normally
3739     if (!taskdata->td_flags.native) {
3740       retval = *(kmp_int64 *)((char *)task + lower_offset);
3741     } else {
3742       // GOMP task has to take into account the sizeof(long)
3743       if (taskdata->td_size_loop_bounds == 4) {
3744         kmp_int32 *lb = RCAST(kmp_int32 *, task->shareds);
3745         retval = (kmp_int64)*lb;
3746       } else {
3747         kmp_int64 *lb = RCAST(kmp_int64 *, task->shareds);
3748         retval = (kmp_int64)*lb;
3749       }
3750     }
3751 #else
3752     retval = *(kmp_int64 *)((char *)task + lower_offset);
3753 #endif // defined(KMP_GOMP_COMPAT)
3754     return retval;
3755   }
3756   kmp_uint64 get_ub() const {
3757     kmp_int64 retval;
3758 #if defined(KMP_GOMP_COMPAT)
3759     // Intel task just returns the upper bound normally
3760     if (!taskdata->td_flags.native) {
3761       retval = *(kmp_int64 *)((char *)task + upper_offset);
3762     } else {
3763       // GOMP task has to take into account the sizeof(long)
3764       if (taskdata->td_size_loop_bounds == 4) {
3765         kmp_int32 *ub = RCAST(kmp_int32 *, task->shareds) + 1;
3766         retval = (kmp_int64)*ub;
3767       } else {
3768         kmp_int64 *ub = RCAST(kmp_int64 *, task->shareds) + 1;
3769         retval = (kmp_int64)*ub;
3770       }
3771     }
3772 #else
3773     retval = *(kmp_int64 *)((char *)task + upper_offset);
3774 #endif // defined(KMP_GOMP_COMPAT)
3775     return retval;
3776   }
3777   void set_lb(kmp_uint64 lb) {
3778 #if defined(KMP_GOMP_COMPAT)
3779     // Intel task just sets the lower bound normally
3780     if (!taskdata->td_flags.native) {
3781       *(kmp_uint64 *)((char *)task + lower_offset) = lb;
3782     } else {
3783       // GOMP task has to take into account the sizeof(long)
3784       if (taskdata->td_size_loop_bounds == 4) {
3785         kmp_uint32 *lower = RCAST(kmp_uint32 *, task->shareds);
3786         *lower = (kmp_uint32)lb;
3787       } else {
3788         kmp_uint64 *lower = RCAST(kmp_uint64 *, task->shareds);
3789         *lower = (kmp_uint64)lb;
3790       }
3791     }
3792 #else
3793     *(kmp_uint64 *)((char *)task + lower_offset) = lb;
3794 #endif // defined(KMP_GOMP_COMPAT)
3795   }
3796   void set_ub(kmp_uint64 ub) {
3797 #if defined(KMP_GOMP_COMPAT)
3798     // Intel task just sets the upper bound normally
3799     if (!taskdata->td_flags.native) {
3800       *(kmp_uint64 *)((char *)task + upper_offset) = ub;
3801     } else {
3802       // GOMP task has to take into account the sizeof(long)
3803       if (taskdata->td_size_loop_bounds == 4) {
3804         kmp_uint32 *upper = RCAST(kmp_uint32 *, task->shareds) + 1;
3805         *upper = (kmp_uint32)ub;
3806       } else {
3807         kmp_uint64 *upper = RCAST(kmp_uint64 *, task->shareds) + 1;
3808         *upper = (kmp_uint64)ub;
3809       }
3810     }
3811 #else
3812     *(kmp_uint64 *)((char *)task + upper_offset) = ub;
3813 #endif // defined(KMP_GOMP_COMPAT)
3814   }
3815 };
3816 
3817 // __kmp_taskloop_linear: Start tasks of the taskloop linearly
3818 //
3819 // loc        Source location information
3820 // gtid       Global thread ID
3821 // task       Pattern task, exposes the loop iteration range
3822 // lb         Pointer to loop lower bound in task structure
3823 // ub         Pointer to loop upper bound in task structure
3824 // st         Loop stride
3825 // ub_glob    Global upper bound (used for lastprivate check)
3826 // num_tasks  Number of tasks to execute
3827 // grainsize  Number of loop iterations per task
3828 // extras     Number of chunks with grainsize+1 iterations
3829 // tc         Iterations count
3830 // task_dup   Tasks duplication routine
3831 // codeptr_ra Return address for OMPT events
3832 void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task,
3833                            kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
3834                            kmp_uint64 ub_glob, kmp_uint64 num_tasks,
3835                            kmp_uint64 grainsize, kmp_uint64 extras,
3836                            kmp_uint64 tc,
3837 #if OMPT_SUPPORT
3838                            void *codeptr_ra,
3839 #endif
3840                            void *task_dup) {
3841   KMP_COUNT_BLOCK(OMP_TASKLOOP);
3842   KMP_TIME_PARTITIONED_BLOCK(OMP_taskloop_scheduling);
3843   p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
3844   // compiler provides global bounds here
3845   kmp_taskloop_bounds_t task_bounds(task, lb, ub);
3846   kmp_uint64 lower = task_bounds.get_lb();
3847   kmp_uint64 upper = task_bounds.get_ub();
3848   kmp_uint64 i;
3849   kmp_info_t *thread = __kmp_threads[gtid];
3850   kmp_taskdata_t *current_task = thread->th.th_current_task;
3851   kmp_task_t *next_task;
3852   kmp_int32 lastpriv = 0;
3853 
3854   KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras);
3855   KMP_DEBUG_ASSERT(num_tasks > extras);
3856   KMP_DEBUG_ASSERT(num_tasks > 0);
3857   KA_TRACE(20, ("__kmp_taskloop_linear: T#%d: %lld tasks, grainsize %lld, "
3858                 "extras %lld, i=%lld,%lld(%d)%lld, dup %p\n",
3859                 gtid, num_tasks, grainsize, extras, lower, upper, ub_glob, st,
3860                 task_dup));
3861 
3862   // Launch num_tasks tasks, assign grainsize iterations each task
3863   for (i = 0; i < num_tasks; ++i) {
3864     kmp_uint64 chunk_minus_1;
3865     if (extras == 0) {
3866       chunk_minus_1 = grainsize - 1;
3867     } else {
3868       chunk_minus_1 = grainsize;
3869       --extras; // first extras iterations get bigger chunk (grainsize+1)
3870     }
3871     upper = lower + st * chunk_minus_1;
3872     if (i == num_tasks - 1) {
3873       // schedule the last task, set lastprivate flag if needed
3874       if (st == 1) { // most common case
3875         KMP_DEBUG_ASSERT(upper == *ub);
3876         if (upper == ub_glob)
3877           lastpriv = 1;
3878       } else if (st > 0) { // positive loop stride
3879         KMP_DEBUG_ASSERT((kmp_uint64)st > *ub - upper);
3880         if ((kmp_uint64)st > ub_glob - upper)
3881           lastpriv = 1;
3882       } else { // negative loop stride
3883         KMP_DEBUG_ASSERT(upper + st < *ub);
3884         if (upper - ub_glob < (kmp_uint64)(-st))
3885           lastpriv = 1;
3886       }
3887     }
3888     next_task = __kmp_task_dup_alloc(thread, task); // allocate new task
3889     kmp_taskdata_t *next_taskdata = KMP_TASK_TO_TASKDATA(next_task);
3890     kmp_taskloop_bounds_t next_task_bounds =
3891         kmp_taskloop_bounds_t(next_task, task_bounds);
3892 
3893     // adjust task-specific bounds
3894     next_task_bounds.set_lb(lower);
3895     if (next_taskdata->td_flags.native) {
3896       next_task_bounds.set_ub(upper + (st > 0 ? 1 : -1));
3897     } else {
3898       next_task_bounds.set_ub(upper);
3899     }
3900     if (ptask_dup != NULL) // set lastprivate flag, construct fistprivates, etc.
3901       ptask_dup(next_task, task, lastpriv);
3902     KA_TRACE(40,
3903              ("__kmp_taskloop_linear: T#%d; task #%llu: task %p: lower %lld, "
3904               "upper %lld stride %lld, (offsets %p %p)\n",
3905               gtid, i, next_task, lower, upper, st,
3906               next_task_bounds.get_lower_offset(),
3907               next_task_bounds.get_upper_offset()));
3908 #if OMPT_SUPPORT
3909     __kmp_omp_taskloop_task(NULL, gtid, next_task,
3910                            codeptr_ra); // schedule new task
3911 #else
3912     __kmp_omp_task(gtid, next_task, true); // schedule new task
3913 #endif
3914     lower = upper + st; // adjust lower bound for the next iteration
3915   }
3916   // free the pattern task and exit
3917   __kmp_task_start(gtid, task, current_task); // make internal bookkeeping
3918   // do not execute the pattern task, just do internal bookkeeping
3919   __kmp_task_finish<false>(gtid, task, current_task);
3920 }
3921 
3922 // Structure to keep taskloop parameters for auxiliary task
3923 // kept in the shareds of the task structure.
3924 typedef struct __taskloop_params {
3925   kmp_task_t *task;
3926   kmp_uint64 *lb;
3927   kmp_uint64 *ub;
3928   void *task_dup;
3929   kmp_int64 st;
3930   kmp_uint64 ub_glob;
3931   kmp_uint64 num_tasks;
3932   kmp_uint64 grainsize;
3933   kmp_uint64 extras;
3934   kmp_uint64 tc;
3935   kmp_uint64 num_t_min;
3936 #if OMPT_SUPPORT
3937   void *codeptr_ra;
3938 #endif
3939 } __taskloop_params_t;
3940 
3941 void __kmp_taskloop_recur(ident_t *, int, kmp_task_t *, kmp_uint64 *,
3942                           kmp_uint64 *, kmp_int64, kmp_uint64, kmp_uint64,
3943                           kmp_uint64, kmp_uint64, kmp_uint64, kmp_uint64,
3944 #if OMPT_SUPPORT
3945                           void *,
3946 #endif
3947                           void *);
3948 
3949 // Execute part of the the taskloop submitted as a task.
3950 int __kmp_taskloop_task(int gtid, void *ptask) {
3951   __taskloop_params_t *p =
3952       (__taskloop_params_t *)((kmp_task_t *)ptask)->shareds;
3953   kmp_task_t *task = p->task;
3954   kmp_uint64 *lb = p->lb;
3955   kmp_uint64 *ub = p->ub;
3956   void *task_dup = p->task_dup;
3957   //  p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
3958   kmp_int64 st = p->st;
3959   kmp_uint64 ub_glob = p->ub_glob;
3960   kmp_uint64 num_tasks = p->num_tasks;
3961   kmp_uint64 grainsize = p->grainsize;
3962   kmp_uint64 extras = p->extras;
3963   kmp_uint64 tc = p->tc;
3964   kmp_uint64 num_t_min = p->num_t_min;
3965 #if OMPT_SUPPORT
3966   void *codeptr_ra = p->codeptr_ra;
3967 #endif
3968 #if KMP_DEBUG
3969   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
3970   KMP_DEBUG_ASSERT(task != NULL);
3971   KA_TRACE(20, ("__kmp_taskloop_task: T#%d, task %p: %lld tasks, grainsize"
3972                 " %lld, extras %lld, i=%lld,%lld(%d), dup %p\n",
3973                 gtid, taskdata, num_tasks, grainsize, extras, *lb, *ub, st,
3974                 task_dup));
3975 #endif
3976   KMP_DEBUG_ASSERT(num_tasks * 2 + 1 > num_t_min);
3977   if (num_tasks > num_t_min)
3978     __kmp_taskloop_recur(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks,
3979                          grainsize, extras, tc, num_t_min,
3980 #if OMPT_SUPPORT
3981                          codeptr_ra,
3982 #endif
3983                          task_dup);
3984   else
3985     __kmp_taskloop_linear(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks,
3986                           grainsize, extras, tc,
3987 #if OMPT_SUPPORT
3988                           codeptr_ra,
3989 #endif
3990                           task_dup);
3991 
3992   KA_TRACE(40, ("__kmp_taskloop_task(exit): T#%d\n", gtid));
3993   return 0;
3994 }
3995 
3996 // Schedule part of the the taskloop as a task,
3997 // execute the rest of the the taskloop.
3998 //
3999 // loc        Source location information
4000 // gtid       Global thread ID
4001 // task       Pattern task, exposes the loop iteration range
4002 // lb         Pointer to loop lower bound in task structure
4003 // ub         Pointer to loop upper bound in task structure
4004 // st         Loop stride
4005 // ub_glob    Global upper bound (used for lastprivate check)
4006 // num_tasks  Number of tasks to execute
4007 // grainsize  Number of loop iterations per task
4008 // extras     Number of chunks with grainsize+1 iterations
4009 // tc         Iterations count
4010 // num_t_min  Threashold to launch tasks recursively
4011 // task_dup   Tasks duplication routine
4012 // codeptr_ra Return address for OMPT events
4013 void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task,
4014                           kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
4015                           kmp_uint64 ub_glob, kmp_uint64 num_tasks,
4016                           kmp_uint64 grainsize, kmp_uint64 extras,
4017                           kmp_uint64 tc, kmp_uint64 num_t_min,
4018 #if OMPT_SUPPORT
4019                           void *codeptr_ra,
4020 #endif
4021                           void *task_dup) {
4022 #if KMP_DEBUG
4023   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
4024   KMP_DEBUG_ASSERT(task != NULL);
4025   KMP_DEBUG_ASSERT(num_tasks > num_t_min);
4026   KA_TRACE(20, ("__kmp_taskloop_recur: T#%d, task %p: %lld tasks, grainsize"
4027                 " %lld, extras %lld, i=%lld,%lld(%d), dup %p\n",
4028                 gtid, taskdata, num_tasks, grainsize, extras, *lb, *ub, st,
4029                 task_dup));
4030 #endif
4031   p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
4032   kmp_uint64 lower = *lb;
4033   kmp_info_t *thread = __kmp_threads[gtid];
4034   //  kmp_taskdata_t *current_task = thread->th.th_current_task;
4035   kmp_task_t *next_task;
4036   size_t lower_offset =
4037       (char *)lb - (char *)task; // remember offset of lb in the task structure
4038   size_t upper_offset =
4039       (char *)ub - (char *)task; // remember offset of ub in the task structure
4040 
4041   KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras);
4042   KMP_DEBUG_ASSERT(num_tasks > extras);
4043   KMP_DEBUG_ASSERT(num_tasks > 0);
4044 
4045   // split the loop in two halves
4046   kmp_uint64 lb1, ub0, tc0, tc1, ext0, ext1;
4047   kmp_uint64 gr_size0 = grainsize;
4048   kmp_uint64 n_tsk0 = num_tasks >> 1; // num_tasks/2 to execute
4049   kmp_uint64 n_tsk1 = num_tasks - n_tsk0; // to schedule as a task
4050   if (n_tsk0 <= extras) {
4051     gr_size0++; // integrate extras into grainsize
4052     ext0 = 0; // no extra iters in 1st half
4053     ext1 = extras - n_tsk0; // remaining extras
4054     tc0 = gr_size0 * n_tsk0;
4055     tc1 = tc - tc0;
4056   } else { // n_tsk0 > extras
4057     ext1 = 0; // no extra iters in 2nd half
4058     ext0 = extras;
4059     tc1 = grainsize * n_tsk1;
4060     tc0 = tc - tc1;
4061   }
4062   ub0 = lower + st * (tc0 - 1);
4063   lb1 = ub0 + st;
4064 
4065   // create pattern task for 2nd half of the loop
4066   next_task = __kmp_task_dup_alloc(thread, task); // duplicate the task
4067   // adjust lower bound (upper bound is not changed) for the 2nd half
4068   *(kmp_uint64 *)((char *)next_task + lower_offset) = lb1;
4069   if (ptask_dup != NULL) // construct fistprivates, etc.
4070     ptask_dup(next_task, task, 0);
4071   *ub = ub0; // adjust upper bound for the 1st half
4072 
4073   // create auxiliary task for 2nd half of the loop
4074   kmp_task_t *new_task =
4075       __kmpc_omp_task_alloc(loc, gtid, 1, 3 * sizeof(void *),
4076                             sizeof(__taskloop_params_t), &__kmp_taskloop_task);
4077   __taskloop_params_t *p = (__taskloop_params_t *)new_task->shareds;
4078   p->task = next_task;
4079   p->lb = (kmp_uint64 *)((char *)next_task + lower_offset);
4080   p->ub = (kmp_uint64 *)((char *)next_task + upper_offset);
4081   p->task_dup = task_dup;
4082   p->st = st;
4083   p->ub_glob = ub_glob;
4084   p->num_tasks = n_tsk1;
4085   p->grainsize = grainsize;
4086   p->extras = ext1;
4087   p->tc = tc1;
4088   p->num_t_min = num_t_min;
4089 #if OMPT_SUPPORT
4090   p->codeptr_ra = codeptr_ra;
4091 #endif
4092 
4093 #if OMPT_SUPPORT
4094   // schedule new task with correct return address for OMPT events
4095   __kmp_omp_taskloop_task(NULL, gtid, new_task, codeptr_ra);
4096 #else
4097   __kmp_omp_task(gtid, new_task, true); // schedule new task
4098 #endif
4099 
4100   // execute the 1st half of current subrange
4101   if (n_tsk0 > num_t_min)
4102     __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0, gr_size0,
4103                          ext0, tc0, num_t_min,
4104 #if OMPT_SUPPORT
4105                          codeptr_ra,
4106 #endif
4107                          task_dup);
4108   else
4109     __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0,
4110                           gr_size0, ext0, tc0,
4111 #if OMPT_SUPPORT
4112                           codeptr_ra,
4113 #endif
4114                           task_dup);
4115 
4116   KA_TRACE(40, ("__kmpc_taskloop_recur(exit): T#%d\n", gtid));
4117 }
4118 
4119 /*!
4120 @ingroup TASKING
4121 @param loc       Source location information
4122 @param gtid      Global thread ID
4123 @param task      Task structure
4124 @param if_val    Value of the if clause
4125 @param lb        Pointer to loop lower bound in task structure
4126 @param ub        Pointer to loop upper bound in task structure
4127 @param st        Loop stride
4128 @param nogroup   Flag, 1 if nogroup clause specified, 0 otherwise
4129 @param sched     Schedule specified 0/1/2 for none/grainsize/num_tasks
4130 @param grainsize Schedule value if specified
4131 @param task_dup  Tasks duplication routine
4132 
4133 Execute the taskloop construct.
4134 */
4135 void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
4136                      kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup,
4137                      int sched, kmp_uint64 grainsize, void *task_dup) {
4138   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
4139   KMP_DEBUG_ASSERT(task != NULL);
4140 
4141   if (nogroup == 0) {
4142 #if OMPT_SUPPORT && OMPT_OPTIONAL
4143     OMPT_STORE_RETURN_ADDRESS(gtid);
4144 #endif
4145     __kmpc_taskgroup(loc, gtid);
4146   }
4147 
4148   // =========================================================================
4149   // calculate loop parameters
4150   kmp_taskloop_bounds_t task_bounds(task, lb, ub);
4151   kmp_uint64 tc;
4152   // compiler provides global bounds here
4153   kmp_uint64 lower = task_bounds.get_lb();
4154   kmp_uint64 upper = task_bounds.get_ub();
4155   kmp_uint64 ub_glob = upper; // global upper used to calc lastprivate flag
4156   kmp_uint64 num_tasks = 0, extras = 0;
4157   kmp_uint64 num_tasks_min = __kmp_taskloop_min_tasks;
4158   kmp_info_t *thread = __kmp_threads[gtid];
4159   kmp_taskdata_t *current_task = thread->th.th_current_task;
4160 
4161   KA_TRACE(20, ("__kmpc_taskloop: T#%d, task %p, lb %lld, ub %lld, st %lld, "
4162                 "grain %llu(%d), dup %p\n",
4163                 gtid, taskdata, lower, upper, st, grainsize, sched, task_dup));
4164 
4165   // compute trip count
4166   if (st == 1) { // most common case
4167     tc = upper - lower + 1;
4168   } else if (st < 0) {
4169     tc = (lower - upper) / (-st) + 1;
4170   } else { // st > 0
4171     tc = (upper - lower) / st + 1;
4172   }
4173   if (tc == 0) {
4174     KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d zero-trip loop\n", gtid));
4175     // free the pattern task and exit
4176     __kmp_task_start(gtid, task, current_task);
4177     // do not execute anything for zero-trip loop
4178     __kmp_task_finish<false>(gtid, task, current_task);
4179     return;
4180   }
4181 
4182 #if OMPT_SUPPORT && OMPT_OPTIONAL
4183   ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
4184   ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
4185   if (ompt_enabled.ompt_callback_work) {
4186     ompt_callbacks.ompt_callback(ompt_callback_work)(
4187         ompt_work_taskloop, ompt_scope_begin, &(team_info->parallel_data),
4188         &(task_info->task_data), tc, OMPT_GET_RETURN_ADDRESS(0));
4189   }
4190 #endif
4191 
4192   if (num_tasks_min == 0)
4193     // TODO: can we choose better default heuristic?
4194     num_tasks_min =
4195         KMP_MIN(thread->th.th_team_nproc * 10, INITIAL_TASK_DEQUE_SIZE);
4196 
4197   // compute num_tasks/grainsize based on the input provided
4198   switch (sched) {
4199   case 0: // no schedule clause specified, we can choose the default
4200     // let's try to schedule (team_size*10) tasks
4201     grainsize = thread->th.th_team_nproc * 10;
4202   case 2: // num_tasks provided
4203     if (grainsize > tc) {
4204       num_tasks = tc; // too big num_tasks requested, adjust values
4205       grainsize = 1;
4206       extras = 0;
4207     } else {
4208       num_tasks = grainsize;
4209       grainsize = tc / num_tasks;
4210       extras = tc % num_tasks;
4211     }
4212     break;
4213   case 1: // grainsize provided
4214     if (grainsize > tc) {
4215       num_tasks = 1; // too big grainsize requested, adjust values
4216       grainsize = tc;
4217       extras = 0;
4218     } else {
4219       num_tasks = tc / grainsize;
4220       // adjust grainsize for balanced distribution of iterations
4221       grainsize = tc / num_tasks;
4222       extras = tc % num_tasks;
4223     }
4224     break;
4225   default:
4226     KMP_ASSERT2(0, "unknown scheduling of taskloop");
4227   }
4228   KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras);
4229   KMP_DEBUG_ASSERT(num_tasks > extras);
4230   KMP_DEBUG_ASSERT(num_tasks > 0);
4231   // =========================================================================
4232 
4233   // check if clause value first
4234   // Also require GOMP_taskloop to reduce to linear (taskdata->td_flags.native)
4235   if (if_val == 0) { // if(0) specified, mark task as serial
4236     taskdata->td_flags.task_serial = 1;
4237     taskdata->td_flags.tiedness = TASK_TIED; // AC: serial task cannot be untied
4238     // always start serial tasks linearly
4239     __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks,
4240                           grainsize, extras, tc,
4241 #if OMPT_SUPPORT
4242                           OMPT_GET_RETURN_ADDRESS(0),
4243 #endif
4244                           task_dup);
4245     // !taskdata->td_flags.native => currently force linear spawning of tasks
4246     // for GOMP_taskloop
4247   } else if (num_tasks > num_tasks_min && !taskdata->td_flags.native) {
4248     KA_TRACE(20, ("__kmpc_taskloop: T#%d, go recursive: tc %llu, #tasks %llu"
4249                   "(%lld), grain %llu, extras %llu\n",
4250                   gtid, tc, num_tasks, num_tasks_min, grainsize, extras));
4251     __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, num_tasks,
4252                          grainsize, extras, tc, num_tasks_min,
4253 #if OMPT_SUPPORT
4254                          OMPT_GET_RETURN_ADDRESS(0),
4255 #endif
4256                          task_dup);
4257   } else {
4258     KA_TRACE(20, ("__kmpc_taskloop: T#%d, go linear: tc %llu, #tasks %llu"
4259                   "(%lld), grain %llu, extras %llu\n",
4260                   gtid, tc, num_tasks, num_tasks_min, grainsize, extras));
4261     __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks,
4262                           grainsize, extras, tc,
4263 #if OMPT_SUPPORT
4264                           OMPT_GET_RETURN_ADDRESS(0),
4265 #endif
4266                           task_dup);
4267   }
4268 
4269 #if OMPT_SUPPORT && OMPT_OPTIONAL
4270   if (ompt_enabled.ompt_callback_work) {
4271     ompt_callbacks.ompt_callback(ompt_callback_work)(
4272         ompt_work_taskloop, ompt_scope_end, &(team_info->parallel_data),
4273         &(task_info->task_data), tc, OMPT_GET_RETURN_ADDRESS(0));
4274   }
4275 #endif
4276 
4277   if (nogroup == 0) {
4278 #if OMPT_SUPPORT && OMPT_OPTIONAL
4279     OMPT_STORE_RETURN_ADDRESS(gtid);
4280 #endif
4281     __kmpc_end_taskgroup(loc, gtid);
4282   }
4283   KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d\n", gtid));
4284 }
4285 
4286 #endif
4287