1 /* Copyright (C) 2005-2018 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* This file handles the LOOP (FOR/DO) construct. */
34 ialias (GOMP_loop_runtime_next
)
35 ialias_redirect (GOMP_taskgroup_reduction_register
)
37 /* Initialize the given work share construct from the given arguments. */
40 gomp_loop_init (struct gomp_work_share
*ws
, long start
, long end
, long incr
,
41 enum gomp_schedule_type sched
, long chunk_size
)
44 ws
->chunk_size
= chunk_size
;
45 /* Canonicalize loops that have zero iterations to ->next == ->end. */
46 ws
->end
= ((incr
> 0 && start
> end
) || (incr
< 0 && start
< end
))
50 if (sched
== GFS_DYNAMIC
)
52 ws
->chunk_size
*= incr
;
54 #ifdef HAVE_SYNC_BUILTINS
56 /* For dynamic scheduling prepare things to make each iteration
58 struct gomp_thread
*thr
= gomp_thread ();
59 struct gomp_team
*team
= thr
->ts
.team
;
60 long nthreads
= team
? team
->nthreads
: 1;
62 if (__builtin_expect (incr
> 0, 1))
64 /* Cheap overflow protection. */
65 if (__builtin_expect ((nthreads
| ws
->chunk_size
)
66 >= 1UL << (sizeof (long)
67 * __CHAR_BIT__
/ 2 - 1), 0))
70 ws
->mode
= ws
->end
< (LONG_MAX
71 - (nthreads
+ 1) * ws
->chunk_size
);
73 /* Cheap overflow protection. */
74 else if (__builtin_expect ((nthreads
| -ws
->chunk_size
)
75 >= 1UL << (sizeof (long)
76 * __CHAR_BIT__
/ 2 - 1), 0))
79 ws
->mode
= ws
->end
> (nthreads
+ 1) * -ws
->chunk_size
- LONG_MAX
;
85 /* The *_start routines are called when first encountering a loop construct
86 that is not bound directly to a parallel construct. The first thread
87 that arrives will create the work-share construct; subsequent threads
88 will see the construct exists and allocate work from it.
90 START, END, INCR are the bounds of the loop; due to the restrictions of
91 OpenMP, these values must be the same in every thread. This is not
92 verified (nor is it entirely verifiable, since START is not necessarily
93 retained intact in the work-share data structure). CHUNK_SIZE is the
94 scheduling parameter; again this must be identical in all threads.
96 Returns true if there's any work for this thread to perform. If so,
97 *ISTART and *IEND are filled with the bounds of the iteration block
98 allocated to this thread. Returns false if all work was assigned to
99 other threads prior to this thread's arrival. */
102 gomp_loop_static_start (long start
, long end
, long incr
, long chunk_size
,
103 long *istart
, long *iend
)
105 struct gomp_thread
*thr
= gomp_thread ();
107 thr
->ts
.static_trip
= 0;
108 if (gomp_work_share_start (0))
110 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
111 GFS_STATIC
, chunk_size
);
112 gomp_work_share_init_done ();
115 return !gomp_iter_static_next (istart
, iend
);
118 /* The current dynamic implementation is always monotonic. The
119 entrypoints without nonmonotonic in them have to be always monotonic,
120 but the nonmonotonic ones could be changed to use work-stealing for
121 improved scalability. */
124 gomp_loop_dynamic_start (long start
, long end
, long incr
, long chunk_size
,
125 long *istart
, long *iend
)
127 struct gomp_thread
*thr
= gomp_thread ();
130 if (gomp_work_share_start (0))
132 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
133 GFS_DYNAMIC
, chunk_size
);
134 gomp_work_share_init_done ();
137 #ifdef HAVE_SYNC_BUILTINS
138 ret
= gomp_iter_dynamic_next (istart
, iend
);
140 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
141 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
142 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
148 /* Similarly as for dynamic, though the question is how can the chunk sizes
149 be decreased without a central locking or atomics. */
152 gomp_loop_guided_start (long start
, long end
, long incr
, long chunk_size
,
153 long *istart
, long *iend
)
155 struct gomp_thread
*thr
= gomp_thread ();
158 if (gomp_work_share_start (0))
160 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
161 GFS_GUIDED
, chunk_size
);
162 gomp_work_share_init_done ();
165 #ifdef HAVE_SYNC_BUILTINS
166 ret
= gomp_iter_guided_next (istart
, iend
);
168 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
169 ret
= gomp_iter_guided_next_locked (istart
, iend
);
170 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
177 GOMP_loop_runtime_start (long start
, long end
, long incr
,
178 long *istart
, long *iend
)
180 struct gomp_task_icv
*icv
= gomp_icv (false);
181 switch (icv
->run_sched_var
& ~GFS_MONOTONIC
)
184 return gomp_loop_static_start (start
, end
, incr
,
185 icv
->run_sched_chunk_size
,
188 return gomp_loop_dynamic_start (start
, end
, incr
,
189 icv
->run_sched_chunk_size
,
192 return gomp_loop_guided_start (start
, end
, incr
,
193 icv
->run_sched_chunk_size
,
196 /* For now map to schedule(static), later on we could play with feedback
198 return gomp_loop_static_start (start
, end
, incr
, 0, istart
, iend
);
205 gomp_adjust_sched (long sched
, long *chunk_size
)
207 sched
&= ~GFS_MONOTONIC
;
214 /* GFS_RUNTIME is used for runtime schedule without monotonic
215 or nonmonotonic modifiers on the clause.
216 GFS_RUNTIME|GFS_MONOTONIC for runtime schedule with monotonic
219 /* GFS_AUTO is used for runtime schedule with nonmonotonic
223 struct gomp_task_icv
*icv
= gomp_icv (false);
224 sched
= icv
->run_sched_var
& ~GFS_MONOTONIC
;
230 *chunk_size
= icv
->run_sched_chunk_size
;
247 GOMP_loop_start (long start
, long end
, long incr
, long sched
,
248 long chunk_size
, long *istart
, long *iend
,
249 uintptr_t *reductions
, void **mem
)
251 struct gomp_thread
*thr
= gomp_thread ();
253 thr
->ts
.static_trip
= 0;
255 gomp_workshare_taskgroup_start ();
256 if (gomp_work_share_start (0))
258 sched
= gomp_adjust_sched (sched
, &chunk_size
);
259 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
263 GOMP_taskgroup_reduction_register (reductions
);
264 thr
->task
->taskgroup
->workshare
= true;
265 thr
->ts
.work_share
->task_reductions
= reductions
;
269 uintptr_t size
= (uintptr_t) *mem
;
270 if (size
> (sizeof (struct gomp_work_share
)
271 - offsetof (struct gomp_work_share
,
272 inline_ordered_team_ids
)))
273 thr
->ts
.work_share
->ordered_team_ids
274 = gomp_malloc_cleared (size
);
276 memset (thr
->ts
.work_share
->ordered_team_ids
, '\0', size
);
277 *mem
= (void *) thr
->ts
.work_share
->ordered_team_ids
;
279 gomp_work_share_init_done ();
285 uintptr_t *first_reductions
= thr
->ts
.work_share
->task_reductions
;
286 gomp_workshare_task_reduction_register (reductions
,
290 *mem
= (void *) thr
->ts
.work_share
->ordered_team_ids
;
295 return ialias_call (GOMP_loop_runtime_next
) (istart
, iend
);
298 /* The *_ordered_*_start routines are similar. The only difference is that
299 this work-share construct is initialized to expect an ORDERED section. */
302 gomp_loop_ordered_static_start (long start
, long end
, long incr
,
303 long chunk_size
, long *istart
, long *iend
)
305 struct gomp_thread
*thr
= gomp_thread ();
307 thr
->ts
.static_trip
= 0;
308 if (gomp_work_share_start (1))
310 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
311 GFS_STATIC
, chunk_size
);
312 gomp_ordered_static_init ();
313 gomp_work_share_init_done ();
316 return !gomp_iter_static_next (istart
, iend
);
320 gomp_loop_ordered_dynamic_start (long start
, long end
, long incr
,
321 long chunk_size
, long *istart
, long *iend
)
323 struct gomp_thread
*thr
= gomp_thread ();
326 if (gomp_work_share_start (1))
328 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
329 GFS_DYNAMIC
, chunk_size
);
330 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
331 gomp_work_share_init_done ();
334 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
336 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
338 gomp_ordered_first ();
339 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
345 gomp_loop_ordered_guided_start (long start
, long end
, long incr
,
346 long chunk_size
, long *istart
, long *iend
)
348 struct gomp_thread
*thr
= gomp_thread ();
351 if (gomp_work_share_start (1))
353 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
354 GFS_GUIDED
, chunk_size
);
355 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
356 gomp_work_share_init_done ();
359 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
361 ret
= gomp_iter_guided_next_locked (istart
, iend
);
363 gomp_ordered_first ();
364 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
370 GOMP_loop_ordered_runtime_start (long start
, long end
, long incr
,
371 long *istart
, long *iend
)
373 struct gomp_task_icv
*icv
= gomp_icv (false);
374 switch (icv
->run_sched_var
& ~GFS_MONOTONIC
)
377 return gomp_loop_ordered_static_start (start
, end
, incr
,
378 icv
->run_sched_chunk_size
,
381 return gomp_loop_ordered_dynamic_start (start
, end
, incr
,
382 icv
->run_sched_chunk_size
,
385 return gomp_loop_ordered_guided_start (start
, end
, incr
,
386 icv
->run_sched_chunk_size
,
389 /* For now map to schedule(static), later on we could play with feedback
391 return gomp_loop_ordered_static_start (start
, end
, incr
,
399 GOMP_loop_ordered_start (long start
, long end
, long incr
, long sched
,
400 long chunk_size
, long *istart
, long *iend
,
401 uintptr_t *reductions
, void **mem
)
403 struct gomp_thread
*thr
= gomp_thread ();
407 thr
->ts
.static_trip
= 0;
409 gomp_workshare_taskgroup_start ();
411 ordered
+= (uintptr_t) *mem
;
412 if (gomp_work_share_start (ordered
))
414 sched
= gomp_adjust_sched (sched
, &chunk_size
);
415 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
419 GOMP_taskgroup_reduction_register (reductions
);
420 thr
->task
->taskgroup
->workshare
= true;
421 thr
->ts
.work_share
->task_reductions
= reductions
;
423 if (sched
== GFS_STATIC
)
424 gomp_ordered_static_init ();
426 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
427 gomp_work_share_init_done ();
433 uintptr_t *first_reductions
= thr
->ts
.work_share
->task_reductions
;
434 gomp_workshare_task_reduction_register (reductions
,
437 sched
= thr
->ts
.work_share
->sched
;
438 if (sched
!= GFS_STATIC
)
439 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
445 = (uintptr_t) (thr
->ts
.work_share
->ordered_team_ids
446 + (thr
->ts
.team
? thr
->ts
.team
->nthreads
: 1));
447 p
+= __alignof__ (long long) - 1;
448 p
&= ~(__alignof__ (long long) - 1);
456 return !gomp_iter_static_next (istart
, iend
);
458 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
461 ret
= gomp_iter_guided_next_locked (istart
, iend
);
468 gomp_ordered_first ();
469 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
473 /* The *_doacross_*_start routines are similar. The only difference is that
474 this work-share construct is initialized to expect an ORDERED(N) - DOACROSS
475 section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1
476 and other COUNTS array elements tell the library number of iterations
477 in the ordered inner loops. */
480 gomp_loop_doacross_static_start (unsigned ncounts
, long *counts
,
481 long chunk_size
, long *istart
, long *iend
)
483 struct gomp_thread
*thr
= gomp_thread ();
485 thr
->ts
.static_trip
= 0;
486 if (gomp_work_share_start (0))
488 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
489 GFS_STATIC
, chunk_size
);
490 gomp_doacross_init (ncounts
, counts
, chunk_size
, 0);
491 gomp_work_share_init_done ();
494 return !gomp_iter_static_next (istart
, iend
);
498 gomp_loop_doacross_dynamic_start (unsigned ncounts
, long *counts
,
499 long chunk_size
, long *istart
, long *iend
)
501 struct gomp_thread
*thr
= gomp_thread ();
504 if (gomp_work_share_start (0))
506 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
507 GFS_DYNAMIC
, chunk_size
);
508 gomp_doacross_init (ncounts
, counts
, chunk_size
, 0);
509 gomp_work_share_init_done ();
512 #ifdef HAVE_SYNC_BUILTINS
513 ret
= gomp_iter_dynamic_next (istart
, iend
);
515 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
516 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
517 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
524 gomp_loop_doacross_guided_start (unsigned ncounts
, long *counts
,
525 long chunk_size
, long *istart
, long *iend
)
527 struct gomp_thread
*thr
= gomp_thread ();
530 if (gomp_work_share_start (0))
532 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
533 GFS_GUIDED
, chunk_size
);
534 gomp_doacross_init (ncounts
, counts
, chunk_size
, 0);
535 gomp_work_share_init_done ();
538 #ifdef HAVE_SYNC_BUILTINS
539 ret
= gomp_iter_guided_next (istart
, iend
);
541 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
542 ret
= gomp_iter_guided_next_locked (istart
, iend
);
543 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
550 GOMP_loop_doacross_runtime_start (unsigned ncounts
, long *counts
,
551 long *istart
, long *iend
)
553 struct gomp_task_icv
*icv
= gomp_icv (false);
554 switch (icv
->run_sched_var
& ~GFS_MONOTONIC
)
557 return gomp_loop_doacross_static_start (ncounts
, counts
,
558 icv
->run_sched_chunk_size
,
561 return gomp_loop_doacross_dynamic_start (ncounts
, counts
,
562 icv
->run_sched_chunk_size
,
565 return gomp_loop_doacross_guided_start (ncounts
, counts
,
566 icv
->run_sched_chunk_size
,
569 /* For now map to schedule(static), later on we could play with feedback
571 return gomp_loop_doacross_static_start (ncounts
, counts
,
579 GOMP_loop_doacross_start (unsigned ncounts
, long *counts
, long sched
,
580 long chunk_size
, long *istart
, long *iend
,
581 uintptr_t *reductions
, void **mem
)
583 struct gomp_thread
*thr
= gomp_thread ();
585 thr
->ts
.static_trip
= 0;
587 gomp_workshare_taskgroup_start ();
588 if (gomp_work_share_start (0))
592 extra
= (uintptr_t) *mem
;
593 sched
= gomp_adjust_sched (sched
, &chunk_size
);
594 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
596 gomp_doacross_init (ncounts
, counts
, chunk_size
, extra
);
599 GOMP_taskgroup_reduction_register (reductions
);
600 thr
->task
->taskgroup
->workshare
= true;
601 thr
->ts
.work_share
->task_reductions
= reductions
;
603 gomp_work_share_init_done ();
609 uintptr_t *first_reductions
= thr
->ts
.work_share
->task_reductions
;
610 gomp_workshare_task_reduction_register (reductions
,
613 sched
= thr
->ts
.work_share
->sched
;
617 *mem
= thr
->ts
.work_share
->doacross
->extra
;
619 return ialias_call (GOMP_loop_runtime_next
) (istart
, iend
);
622 /* The *_next routines are called when the thread completes processing of
623 the iteration block currently assigned to it. If the work-share
624 construct is bound directly to a parallel construct, then the iteration
625 bounds may have been set up before the parallel. In which case, this
626 may be the first iteration for the thread.
628 Returns true if there is work remaining to be performed; *ISTART and
629 *IEND are filled with a new iteration block. Returns false if all work
630 has been assigned. */
633 gomp_loop_static_next (long *istart
, long *iend
)
635 return !gomp_iter_static_next (istart
, iend
);
639 gomp_loop_dynamic_next (long *istart
, long *iend
)
643 #ifdef HAVE_SYNC_BUILTINS
644 ret
= gomp_iter_dynamic_next (istart
, iend
);
646 struct gomp_thread
*thr
= gomp_thread ();
647 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
648 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
649 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
656 gomp_loop_guided_next (long *istart
, long *iend
)
660 #ifdef HAVE_SYNC_BUILTINS
661 ret
= gomp_iter_guided_next (istart
, iend
);
663 struct gomp_thread
*thr
= gomp_thread ();
664 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
665 ret
= gomp_iter_guided_next_locked (istart
, iend
);
666 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
673 GOMP_loop_runtime_next (long *istart
, long *iend
)
675 struct gomp_thread
*thr
= gomp_thread ();
677 switch (thr
->ts
.work_share
->sched
)
681 return gomp_loop_static_next (istart
, iend
);
683 return gomp_loop_dynamic_next (istart
, iend
);
685 return gomp_loop_guided_next (istart
, iend
);
691 /* The *_ordered_*_next routines are called when the thread completes
692 processing of the iteration block currently assigned to it.
694 Returns true if there is work remaining to be performed; *ISTART and
695 *IEND are filled with a new iteration block. Returns false if all work
696 has been assigned. */
699 gomp_loop_ordered_static_next (long *istart
, long *iend
)
701 struct gomp_thread
*thr
= gomp_thread ();
704 gomp_ordered_sync ();
705 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
706 test
= gomp_iter_static_next (istart
, iend
);
708 gomp_ordered_static_next ();
709 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
715 gomp_loop_ordered_dynamic_next (long *istart
, long *iend
)
717 struct gomp_thread
*thr
= gomp_thread ();
720 gomp_ordered_sync ();
721 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
722 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
724 gomp_ordered_next ();
726 gomp_ordered_last ();
727 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
733 gomp_loop_ordered_guided_next (long *istart
, long *iend
)
735 struct gomp_thread
*thr
= gomp_thread ();
738 gomp_ordered_sync ();
739 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
740 ret
= gomp_iter_guided_next_locked (istart
, iend
);
742 gomp_ordered_next ();
744 gomp_ordered_last ();
745 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
751 GOMP_loop_ordered_runtime_next (long *istart
, long *iend
)
753 struct gomp_thread
*thr
= gomp_thread ();
755 switch (thr
->ts
.work_share
->sched
)
759 return gomp_loop_ordered_static_next (istart
, iend
);
761 return gomp_loop_ordered_dynamic_next (istart
, iend
);
763 return gomp_loop_ordered_guided_next (istart
, iend
);
769 /* The GOMP_parallel_loop_* routines pre-initialize a work-share construct
770 to avoid one synchronization once we get into the loop. */
773 gomp_parallel_loop_start (void (*fn
) (void *), void *data
,
774 unsigned num_threads
, long start
, long end
,
775 long incr
, enum gomp_schedule_type sched
,
776 long chunk_size
, unsigned int flags
)
778 struct gomp_team
*team
;
780 num_threads
= gomp_resolve_num_threads (num_threads
, 0);
781 team
= gomp_new_team (num_threads
);
782 gomp_loop_init (&team
->work_shares
[0], start
, end
, incr
, sched
, chunk_size
);
783 gomp_team_start (fn
, data
, num_threads
, flags
, team
, NULL
);
787 GOMP_parallel_loop_static_start (void (*fn
) (void *), void *data
,
788 unsigned num_threads
, long start
, long end
,
789 long incr
, long chunk_size
)
791 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
792 GFS_STATIC
, chunk_size
, 0);
796 GOMP_parallel_loop_dynamic_start (void (*fn
) (void *), void *data
,
797 unsigned num_threads
, long start
, long end
,
798 long incr
, long chunk_size
)
800 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
801 GFS_DYNAMIC
, chunk_size
, 0);
805 GOMP_parallel_loop_guided_start (void (*fn
) (void *), void *data
,
806 unsigned num_threads
, long start
, long end
,
807 long incr
, long chunk_size
)
809 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
810 GFS_GUIDED
, chunk_size
, 0);
814 GOMP_parallel_loop_runtime_start (void (*fn
) (void *), void *data
,
815 unsigned num_threads
, long start
, long end
,
818 struct gomp_task_icv
*icv
= gomp_icv (false);
819 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
820 icv
->run_sched_var
& ~GFS_MONOTONIC
,
821 icv
->run_sched_chunk_size
, 0);
824 ialias_redirect (GOMP_parallel_end
)
827 GOMP_parallel_loop_static (void (*fn
) (void *), void *data
,
828 unsigned num_threads
, long start
, long end
,
829 long incr
, long chunk_size
, unsigned flags
)
831 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
832 GFS_STATIC
, chunk_size
, flags
);
834 GOMP_parallel_end ();
838 GOMP_parallel_loop_dynamic (void (*fn
) (void *), void *data
,
839 unsigned num_threads
, long start
, long end
,
840 long incr
, long chunk_size
, unsigned flags
)
842 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
843 GFS_DYNAMIC
, chunk_size
, flags
);
845 GOMP_parallel_end ();
849 GOMP_parallel_loop_guided (void (*fn
) (void *), void *data
,
850 unsigned num_threads
, long start
, long end
,
851 long incr
, long chunk_size
, unsigned flags
)
853 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
854 GFS_GUIDED
, chunk_size
, flags
);
856 GOMP_parallel_end ();
860 GOMP_parallel_loop_runtime (void (*fn
) (void *), void *data
,
861 unsigned num_threads
, long start
, long end
,
862 long incr
, unsigned flags
)
864 struct gomp_task_icv
*icv
= gomp_icv (false);
865 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
866 icv
->run_sched_var
& ~GFS_MONOTONIC
,
867 icv
->run_sched_chunk_size
, flags
);
869 GOMP_parallel_end ();
872 #ifdef HAVE_ATTRIBUTE_ALIAS
873 extern __typeof(GOMP_parallel_loop_dynamic
) GOMP_parallel_loop_nonmonotonic_dynamic
874 __attribute__((alias ("GOMP_parallel_loop_dynamic")));
875 extern __typeof(GOMP_parallel_loop_guided
) GOMP_parallel_loop_nonmonotonic_guided
876 __attribute__((alias ("GOMP_parallel_loop_guided")));
877 extern __typeof(GOMP_parallel_loop_runtime
) GOMP_parallel_loop_nonmonotonic_runtime
878 __attribute__((alias ("GOMP_parallel_loop_runtime")));
879 extern __typeof(GOMP_parallel_loop_runtime
) GOMP_parallel_loop_maybe_nonmonotonic_runtime
880 __attribute__((alias ("GOMP_parallel_loop_runtime")));
883 GOMP_parallel_loop_nonmonotonic_dynamic (void (*fn
) (void *), void *data
,
884 unsigned num_threads
, long start
,
885 long end
, long incr
, long chunk_size
,
888 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
889 GFS_DYNAMIC
, chunk_size
, flags
);
891 GOMP_parallel_end ();
895 GOMP_parallel_loop_nonmonotonic_guided (void (*fn
) (void *), void *data
,
896 unsigned num_threads
, long start
,
897 long end
, long incr
, long chunk_size
,
900 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
901 GFS_GUIDED
, chunk_size
, flags
);
903 GOMP_parallel_end ();
907 GOMP_parallel_loop_nonmonotonic_runtime (void (*fn
) (void *), void *data
,
908 unsigned num_threads
, long start
,
909 long end
, long incr
, unsigned flags
)
911 struct gomp_task_icv
*icv
= gomp_icv (false);
912 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
913 icv
->run_sched_var
& ~GFS_MONOTONIC
,
914 icv
->run_sched_chunk_size
, flags
);
916 GOMP_parallel_end ();
920 GOMP_parallel_loop_maybe_nonmonotonic_runtime (void (*fn
) (void *), void *data
,
921 unsigned num_threads
, long start
,
925 struct gomp_task_icv
*icv
= gomp_icv (false);
926 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
927 icv
->run_sched_var
& ~GFS_MONOTONIC
,
928 icv
->run_sched_chunk_size
, flags
);
930 GOMP_parallel_end ();
934 /* The GOMP_loop_end* routines are called after the thread is told that
935 all loop iterations are complete. The first two versions synchronize
936 all threads; the nowait version does not. */
941 gomp_work_share_end ();
945 GOMP_loop_end_cancel (void)
947 return gomp_work_share_end_cancel ();
951 GOMP_loop_end_nowait (void)
953 gomp_work_share_end_nowait ();
957 /* We use static functions above so that we're sure that the "runtime"
958 function can defer to the proper routine without interposition. We
959 export the static function with a strong alias when possible, or with
960 a wrapper function otherwise. */
962 #ifdef HAVE_ATTRIBUTE_ALIAS
963 extern __typeof(gomp_loop_static_start
) GOMP_loop_static_start
964 __attribute__((alias ("gomp_loop_static_start")));
965 extern __typeof(gomp_loop_dynamic_start
) GOMP_loop_dynamic_start
966 __attribute__((alias ("gomp_loop_dynamic_start")));
967 extern __typeof(gomp_loop_guided_start
) GOMP_loop_guided_start
968 __attribute__((alias ("gomp_loop_guided_start")));
969 extern __typeof(gomp_loop_dynamic_start
) GOMP_loop_nonmonotonic_dynamic_start
970 __attribute__((alias ("gomp_loop_dynamic_start")));
971 extern __typeof(gomp_loop_guided_start
) GOMP_loop_nonmonotonic_guided_start
972 __attribute__((alias ("gomp_loop_guided_start")));
973 extern __typeof(GOMP_loop_runtime_start
) GOMP_loop_nonmonotonic_runtime_start
974 __attribute__((alias ("GOMP_loop_runtime_start")));
975 extern __typeof(GOMP_loop_runtime_start
) GOMP_loop_maybe_nonmonotonic_runtime_start
976 __attribute__((alias ("GOMP_loop_runtime_start")));
978 extern __typeof(gomp_loop_ordered_static_start
) GOMP_loop_ordered_static_start
979 __attribute__((alias ("gomp_loop_ordered_static_start")));
980 extern __typeof(gomp_loop_ordered_dynamic_start
) GOMP_loop_ordered_dynamic_start
981 __attribute__((alias ("gomp_loop_ordered_dynamic_start")));
982 extern __typeof(gomp_loop_ordered_guided_start
) GOMP_loop_ordered_guided_start
983 __attribute__((alias ("gomp_loop_ordered_guided_start")));
985 extern __typeof(gomp_loop_doacross_static_start
) GOMP_loop_doacross_static_start
986 __attribute__((alias ("gomp_loop_doacross_static_start")));
987 extern __typeof(gomp_loop_doacross_dynamic_start
) GOMP_loop_doacross_dynamic_start
988 __attribute__((alias ("gomp_loop_doacross_dynamic_start")));
989 extern __typeof(gomp_loop_doacross_guided_start
) GOMP_loop_doacross_guided_start
990 __attribute__((alias ("gomp_loop_doacross_guided_start")));
992 extern __typeof(gomp_loop_static_next
) GOMP_loop_static_next
993 __attribute__((alias ("gomp_loop_static_next")));
994 extern __typeof(gomp_loop_dynamic_next
) GOMP_loop_dynamic_next
995 __attribute__((alias ("gomp_loop_dynamic_next")));
996 extern __typeof(gomp_loop_guided_next
) GOMP_loop_guided_next
997 __attribute__((alias ("gomp_loop_guided_next")));
998 extern __typeof(gomp_loop_dynamic_next
) GOMP_loop_nonmonotonic_dynamic_next
999 __attribute__((alias ("gomp_loop_dynamic_next")));
1000 extern __typeof(gomp_loop_guided_next
) GOMP_loop_nonmonotonic_guided_next
1001 __attribute__((alias ("gomp_loop_guided_next")));
1002 extern __typeof(GOMP_loop_runtime_next
) GOMP_loop_nonmonotonic_runtime_next
1003 __attribute__((alias ("GOMP_loop_runtime_next")));
1004 extern __typeof(GOMP_loop_runtime_next
) GOMP_loop_maybe_nonmonotonic_runtime_next
1005 __attribute__((alias ("GOMP_loop_runtime_next")));
1007 extern __typeof(gomp_loop_ordered_static_next
) GOMP_loop_ordered_static_next
1008 __attribute__((alias ("gomp_loop_ordered_static_next")));
1009 extern __typeof(gomp_loop_ordered_dynamic_next
) GOMP_loop_ordered_dynamic_next
1010 __attribute__((alias ("gomp_loop_ordered_dynamic_next")));
1011 extern __typeof(gomp_loop_ordered_guided_next
) GOMP_loop_ordered_guided_next
1012 __attribute__((alias ("gomp_loop_ordered_guided_next")));
1015 GOMP_loop_static_start (long start
, long end
, long incr
, long chunk_size
,
1016 long *istart
, long *iend
)
1018 return gomp_loop_static_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1022 GOMP_loop_dynamic_start (long start
, long end
, long incr
, long chunk_size
,
1023 long *istart
, long *iend
)
1025 return gomp_loop_dynamic_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1029 GOMP_loop_guided_start (long start
, long end
, long incr
, long chunk_size
,
1030 long *istart
, long *iend
)
1032 return gomp_loop_guided_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1036 GOMP_loop_nonmonotonic_dynamic_start (long start
, long end
, long incr
,
1037 long chunk_size
, long *istart
,
1040 return gomp_loop_dynamic_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1044 GOMP_loop_nonmonotonic_guided_start (long start
, long end
, long incr
,
1045 long chunk_size
, long *istart
, long *iend
)
1047 return gomp_loop_guided_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1051 GOMP_loop_nonmonotonic_runtime_start (long start
, long end
, long incr
,
1052 long *istart
, long *iend
)
1054 return GOMP_loop_runtime_start (start
, end
, incr
, istart
, iend
);
1058 GOMP_loop_maybe_nonmonotonic_runtime_start (long start
, long end
, long incr
,
1059 long *istart
, long *iend
)
1061 return GOMP_loop_runtime_start (start
, end
, incr
, istart
, iend
);
1065 GOMP_loop_ordered_static_start (long start
, long end
, long incr
,
1066 long chunk_size
, long *istart
, long *iend
)
1068 return gomp_loop_ordered_static_start (start
, end
, incr
, chunk_size
,
1073 GOMP_loop_ordered_dynamic_start (long start
, long end
, long incr
,
1074 long chunk_size
, long *istart
, long *iend
)
1076 return gomp_loop_ordered_dynamic_start (start
, end
, incr
, chunk_size
,
1081 GOMP_loop_ordered_guided_start (long start
, long end
, long incr
,
1082 long chunk_size
, long *istart
, long *iend
)
1084 return gomp_loop_ordered_guided_start (start
, end
, incr
, chunk_size
,
1089 GOMP_loop_doacross_static_start (unsigned ncounts
, long *counts
,
1090 long chunk_size
, long *istart
, long *iend
)
1092 return gomp_loop_doacross_static_start (ncounts
, counts
, chunk_size
,
1097 GOMP_loop_doacross_dynamic_start (unsigned ncounts
, long *counts
,
1098 long chunk_size
, long *istart
, long *iend
)
1100 return gomp_loop_doacross_dynamic_start (ncounts
, counts
, chunk_size
,
1105 GOMP_loop_doacross_guided_start (unsigned ncounts
, long *counts
,
1106 long chunk_size
, long *istart
, long *iend
)
1108 return gomp_loop_doacross_guided_start (ncounts
, counts
, chunk_size
,
1113 GOMP_loop_static_next (long *istart
, long *iend
)
1115 return gomp_loop_static_next (istart
, iend
);
1119 GOMP_loop_dynamic_next (long *istart
, long *iend
)
1121 return gomp_loop_dynamic_next (istart
, iend
);
1125 GOMP_loop_guided_next (long *istart
, long *iend
)
1127 return gomp_loop_guided_next (istart
, iend
);
1131 GOMP_loop_nonmonotonic_dynamic_next (long *istart
, long *iend
)
1133 return gomp_loop_dynamic_next (istart
, iend
);
1137 GOMP_loop_nonmonotonic_guided_next (long *istart
, long *iend
)
1139 return gomp_loop_guided_next (istart
, iend
);
1143 GOMP_loop_nonmonotonic_runtime_next (long *istart
, long *iend
)
1145 return GOMP_loop_runtime_next (istart
, iend
);
1149 GOMP_loop_maybe_nonmonotonic_runtime_next (long *istart
, long *iend
)
1151 return GOMP_loop_runtime_next (istart
, iend
);
1155 GOMP_loop_ordered_static_next (long *istart
, long *iend
)
1157 return gomp_loop_ordered_static_next (istart
, iend
);
1161 GOMP_loop_ordered_dynamic_next (long *istart
, long *iend
)
1163 return gomp_loop_ordered_dynamic_next (istart
, iend
);
1167 GOMP_loop_ordered_guided_next (long *istart
, long *iend
)
1169 return gomp_loop_ordered_guided_next (istart
, iend
);