1 /* Copyright (C) 2005-2022 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 #define INLINE_ORDERED_TEAM_IDS_OFF \
271 ((offsetof (struct gomp_work_share, inline_ordered_team_ids) \
272 + __alignof__ (long long) - 1) & ~(__alignof__ (long long) - 1))
273 if (size
> (sizeof (struct gomp_work_share
)
274 - INLINE_ORDERED_TEAM_IDS_OFF
))
276 = (void *) (thr
->ts
.work_share
->ordered_team_ids
277 = gomp_malloc_cleared (size
));
279 *mem
= memset (((char *) thr
->ts
.work_share
)
280 + INLINE_ORDERED_TEAM_IDS_OFF
, '\0', size
);
282 gomp_work_share_init_done ();
288 uintptr_t *first_reductions
= thr
->ts
.work_share
->task_reductions
;
289 gomp_workshare_task_reduction_register (reductions
,
294 if ((offsetof (struct gomp_work_share
, inline_ordered_team_ids
)
295 & (__alignof__ (long long) - 1)) == 0)
296 *mem
= (void *) thr
->ts
.work_share
->ordered_team_ids
;
299 uintptr_t p
= (uintptr_t) thr
->ts
.work_share
->ordered_team_ids
;
300 p
+= __alignof__ (long long) - 1;
301 p
&= ~(__alignof__ (long long) - 1);
309 return ialias_call (GOMP_loop_runtime_next
) (istart
, iend
);
312 /* The *_ordered_*_start routines are similar. The only difference is that
313 this work-share construct is initialized to expect an ORDERED section. */
316 gomp_loop_ordered_static_start (long start
, long end
, long incr
,
317 long chunk_size
, long *istart
, long *iend
)
319 struct gomp_thread
*thr
= gomp_thread ();
321 thr
->ts
.static_trip
= 0;
322 if (gomp_work_share_start (1))
324 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
325 GFS_STATIC
, chunk_size
);
326 gomp_ordered_static_init ();
327 gomp_work_share_init_done ();
330 return !gomp_iter_static_next (istart
, iend
);
334 gomp_loop_ordered_dynamic_start (long start
, long end
, long incr
,
335 long chunk_size
, long *istart
, long *iend
)
337 struct gomp_thread
*thr
= gomp_thread ();
340 if (gomp_work_share_start (1))
342 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
343 GFS_DYNAMIC
, chunk_size
);
344 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
345 gomp_work_share_init_done ();
348 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
350 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
352 gomp_ordered_first ();
353 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
359 gomp_loop_ordered_guided_start (long start
, long end
, long incr
,
360 long chunk_size
, long *istart
, long *iend
)
362 struct gomp_thread
*thr
= gomp_thread ();
365 if (gomp_work_share_start (1))
367 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
368 GFS_GUIDED
, chunk_size
);
369 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
370 gomp_work_share_init_done ();
373 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
375 ret
= gomp_iter_guided_next_locked (istart
, iend
);
377 gomp_ordered_first ();
378 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
384 GOMP_loop_ordered_runtime_start (long start
, long end
, long incr
,
385 long *istart
, long *iend
)
387 struct gomp_task_icv
*icv
= gomp_icv (false);
388 switch (icv
->run_sched_var
& ~GFS_MONOTONIC
)
391 return gomp_loop_ordered_static_start (start
, end
, incr
,
392 icv
->run_sched_chunk_size
,
395 return gomp_loop_ordered_dynamic_start (start
, end
, incr
,
396 icv
->run_sched_chunk_size
,
399 return gomp_loop_ordered_guided_start (start
, end
, incr
,
400 icv
->run_sched_chunk_size
,
403 /* For now map to schedule(static), later on we could play with feedback
405 return gomp_loop_ordered_static_start (start
, end
, incr
,
413 GOMP_loop_ordered_start (long start
, long end
, long incr
, long sched
,
414 long chunk_size
, long *istart
, long *iend
,
415 uintptr_t *reductions
, void **mem
)
417 struct gomp_thread
*thr
= gomp_thread ();
421 thr
->ts
.static_trip
= 0;
423 gomp_workshare_taskgroup_start ();
425 ordered
+= (uintptr_t) *mem
;
426 if (gomp_work_share_start (ordered
))
428 sched
= gomp_adjust_sched (sched
, &chunk_size
);
429 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
433 GOMP_taskgroup_reduction_register (reductions
);
434 thr
->task
->taskgroup
->workshare
= true;
435 thr
->ts
.work_share
->task_reductions
= reductions
;
437 if (sched
== GFS_STATIC
)
438 gomp_ordered_static_init ();
440 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
441 gomp_work_share_init_done ();
447 uintptr_t *first_reductions
= thr
->ts
.work_share
->task_reductions
;
448 gomp_workshare_task_reduction_register (reductions
,
451 sched
= thr
->ts
.work_share
->sched
;
452 if (sched
!= GFS_STATIC
)
453 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
459 = (uintptr_t) (thr
->ts
.work_share
->ordered_team_ids
460 + (thr
->ts
.team
? thr
->ts
.team
->nthreads
: 1));
461 p
+= __alignof__ (long long) - 1;
462 p
&= ~(__alignof__ (long long) - 1);
470 return !gomp_iter_static_next (istart
, iend
);
472 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
475 ret
= gomp_iter_guided_next_locked (istart
, iend
);
482 gomp_ordered_first ();
483 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
487 /* The *_doacross_*_start routines are similar. The only difference is that
488 this work-share construct is initialized to expect an ORDERED(N) - DOACROSS
489 section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1
490 and other COUNTS array elements tell the library number of iterations
491 in the ordered inner loops. */
494 gomp_loop_doacross_static_start (unsigned ncounts
, long *counts
,
495 long chunk_size
, long *istart
, long *iend
)
497 struct gomp_thread
*thr
= gomp_thread ();
499 thr
->ts
.static_trip
= 0;
500 if (gomp_work_share_start (0))
502 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
503 GFS_STATIC
, chunk_size
);
504 gomp_doacross_init (ncounts
, counts
, chunk_size
, 0);
505 gomp_work_share_init_done ();
508 return !gomp_iter_static_next (istart
, iend
);
512 gomp_loop_doacross_dynamic_start (unsigned ncounts
, long *counts
,
513 long chunk_size
, long *istart
, long *iend
)
515 struct gomp_thread
*thr
= gomp_thread ();
518 if (gomp_work_share_start (0))
520 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
521 GFS_DYNAMIC
, chunk_size
);
522 gomp_doacross_init (ncounts
, counts
, chunk_size
, 0);
523 gomp_work_share_init_done ();
526 #ifdef HAVE_SYNC_BUILTINS
527 ret
= gomp_iter_dynamic_next (istart
, iend
);
529 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
530 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
531 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
538 gomp_loop_doacross_guided_start (unsigned ncounts
, long *counts
,
539 long chunk_size
, long *istart
, long *iend
)
541 struct gomp_thread
*thr
= gomp_thread ();
544 if (gomp_work_share_start (0))
546 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
547 GFS_GUIDED
, chunk_size
);
548 gomp_doacross_init (ncounts
, counts
, chunk_size
, 0);
549 gomp_work_share_init_done ();
552 #ifdef HAVE_SYNC_BUILTINS
553 ret
= gomp_iter_guided_next (istart
, iend
);
555 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
556 ret
= gomp_iter_guided_next_locked (istart
, iend
);
557 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
564 GOMP_loop_doacross_runtime_start (unsigned ncounts
, long *counts
,
565 long *istart
, long *iend
)
567 struct gomp_task_icv
*icv
= gomp_icv (false);
568 switch (icv
->run_sched_var
& ~GFS_MONOTONIC
)
571 return gomp_loop_doacross_static_start (ncounts
, counts
,
572 icv
->run_sched_chunk_size
,
575 return gomp_loop_doacross_dynamic_start (ncounts
, counts
,
576 icv
->run_sched_chunk_size
,
579 return gomp_loop_doacross_guided_start (ncounts
, counts
,
580 icv
->run_sched_chunk_size
,
583 /* For now map to schedule(static), later on we could play with feedback
585 return gomp_loop_doacross_static_start (ncounts
, counts
,
593 GOMP_loop_doacross_start (unsigned ncounts
, long *counts
, long sched
,
594 long chunk_size
, long *istart
, long *iend
,
595 uintptr_t *reductions
, void **mem
)
597 struct gomp_thread
*thr
= gomp_thread ();
599 thr
->ts
.static_trip
= 0;
601 gomp_workshare_taskgroup_start ();
602 if (gomp_work_share_start (0))
606 extra
= (uintptr_t) *mem
;
607 sched
= gomp_adjust_sched (sched
, &chunk_size
);
608 gomp_loop_init (thr
->ts
.work_share
, 0, counts
[0], 1,
610 gomp_doacross_init (ncounts
, counts
, chunk_size
, extra
);
613 GOMP_taskgroup_reduction_register (reductions
);
614 thr
->task
->taskgroup
->workshare
= true;
615 thr
->ts
.work_share
->task_reductions
= reductions
;
617 gomp_work_share_init_done ();
623 uintptr_t *first_reductions
= thr
->ts
.work_share
->task_reductions
;
624 gomp_workshare_task_reduction_register (reductions
,
627 sched
= thr
->ts
.work_share
->sched
;
631 *mem
= thr
->ts
.work_share
->doacross
->extra
;
633 return ialias_call (GOMP_loop_runtime_next
) (istart
, iend
);
636 /* The *_next routines are called when the thread completes processing of
637 the iteration block currently assigned to it. If the work-share
638 construct is bound directly to a parallel construct, then the iteration
639 bounds may have been set up before the parallel. In which case, this
640 may be the first iteration for the thread.
642 Returns true if there is work remaining to be performed; *ISTART and
643 *IEND are filled with a new iteration block. Returns false if all work
644 has been assigned. */
647 gomp_loop_static_next (long *istart
, long *iend
)
649 return !gomp_iter_static_next (istart
, iend
);
653 gomp_loop_dynamic_next (long *istart
, long *iend
)
657 #ifdef HAVE_SYNC_BUILTINS
658 ret
= gomp_iter_dynamic_next (istart
, iend
);
660 struct gomp_thread
*thr
= gomp_thread ();
661 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
662 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
663 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
670 gomp_loop_guided_next (long *istart
, long *iend
)
674 #ifdef HAVE_SYNC_BUILTINS
675 ret
= gomp_iter_guided_next (istart
, iend
);
677 struct gomp_thread
*thr
= gomp_thread ();
678 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
679 ret
= gomp_iter_guided_next_locked (istart
, iend
);
680 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
687 GOMP_loop_runtime_next (long *istart
, long *iend
)
689 struct gomp_thread
*thr
= gomp_thread ();
691 switch (thr
->ts
.work_share
->sched
)
695 return gomp_loop_static_next (istart
, iend
);
697 return gomp_loop_dynamic_next (istart
, iend
);
699 return gomp_loop_guided_next (istart
, iend
);
705 /* The *_ordered_*_next routines are called when the thread completes
706 processing of the iteration block currently assigned to it.
708 Returns true if there is work remaining to be performed; *ISTART and
709 *IEND are filled with a new iteration block. Returns false if all work
710 has been assigned. */
713 gomp_loop_ordered_static_next (long *istart
, long *iend
)
715 struct gomp_thread
*thr
= gomp_thread ();
718 gomp_ordered_sync ();
719 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
720 test
= gomp_iter_static_next (istart
, iend
);
722 gomp_ordered_static_next ();
723 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
729 gomp_loop_ordered_dynamic_next (long *istart
, long *iend
)
731 struct gomp_thread
*thr
= gomp_thread ();
734 gomp_ordered_sync ();
735 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
736 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
738 gomp_ordered_next ();
740 gomp_ordered_last ();
741 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
747 gomp_loop_ordered_guided_next (long *istart
, long *iend
)
749 struct gomp_thread
*thr
= gomp_thread ();
752 gomp_ordered_sync ();
753 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
754 ret
= gomp_iter_guided_next_locked (istart
, iend
);
756 gomp_ordered_next ();
758 gomp_ordered_last ();
759 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
765 GOMP_loop_ordered_runtime_next (long *istart
, long *iend
)
767 struct gomp_thread
*thr
= gomp_thread ();
769 switch (thr
->ts
.work_share
->sched
)
773 return gomp_loop_ordered_static_next (istart
, iend
);
775 return gomp_loop_ordered_dynamic_next (istart
, iend
);
777 return gomp_loop_ordered_guided_next (istart
, iend
);
783 /* The GOMP_parallel_loop_* routines pre-initialize a work-share construct
784 to avoid one synchronization once we get into the loop. */
787 gomp_parallel_loop_start (void (*fn
) (void *), void *data
,
788 unsigned num_threads
, long start
, long end
,
789 long incr
, enum gomp_schedule_type sched
,
790 long chunk_size
, unsigned int flags
)
792 struct gomp_team
*team
;
794 num_threads
= gomp_resolve_num_threads (num_threads
, 0);
795 team
= gomp_new_team (num_threads
);
796 gomp_loop_init (&team
->work_shares
[0], start
, end
, incr
, sched
, chunk_size
);
797 gomp_team_start (fn
, data
, num_threads
, flags
, team
, NULL
);
801 GOMP_parallel_loop_static_start (void (*fn
) (void *), void *data
,
802 unsigned num_threads
, long start
, long end
,
803 long incr
, long chunk_size
)
805 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
806 GFS_STATIC
, chunk_size
, 0);
810 GOMP_parallel_loop_dynamic_start (void (*fn
) (void *), void *data
,
811 unsigned num_threads
, long start
, long end
,
812 long incr
, long chunk_size
)
814 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
815 GFS_DYNAMIC
, chunk_size
, 0);
819 GOMP_parallel_loop_guided_start (void (*fn
) (void *), void *data
,
820 unsigned num_threads
, long start
, long end
,
821 long incr
, long chunk_size
)
823 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
824 GFS_GUIDED
, chunk_size
, 0);
828 GOMP_parallel_loop_runtime_start (void (*fn
) (void *), void *data
,
829 unsigned num_threads
, long start
, long end
,
832 struct gomp_task_icv
*icv
= gomp_icv (false);
833 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
834 icv
->run_sched_var
& ~GFS_MONOTONIC
,
835 icv
->run_sched_chunk_size
, 0);
838 ialias_redirect (GOMP_parallel_end
)
841 GOMP_parallel_loop_static (void (*fn
) (void *), void *data
,
842 unsigned num_threads
, long start
, long end
,
843 long incr
, long chunk_size
, unsigned flags
)
845 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
846 GFS_STATIC
, chunk_size
, flags
);
848 GOMP_parallel_end ();
852 GOMP_parallel_loop_dynamic (void (*fn
) (void *), void *data
,
853 unsigned num_threads
, long start
, long end
,
854 long incr
, long chunk_size
, unsigned flags
)
856 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
857 GFS_DYNAMIC
, chunk_size
, flags
);
859 GOMP_parallel_end ();
863 GOMP_parallel_loop_guided (void (*fn
) (void *), void *data
,
864 unsigned num_threads
, long start
, long end
,
865 long incr
, long chunk_size
, unsigned flags
)
867 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
868 GFS_GUIDED
, chunk_size
, flags
);
870 GOMP_parallel_end ();
874 GOMP_parallel_loop_runtime (void (*fn
) (void *), void *data
,
875 unsigned num_threads
, long start
, long end
,
876 long incr
, unsigned flags
)
878 struct gomp_task_icv
*icv
= gomp_icv (false);
879 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
880 icv
->run_sched_var
& ~GFS_MONOTONIC
,
881 icv
->run_sched_chunk_size
, flags
);
883 GOMP_parallel_end ();
886 #ifdef HAVE_ATTRIBUTE_ALIAS
887 extern __typeof(GOMP_parallel_loop_dynamic
) GOMP_parallel_loop_nonmonotonic_dynamic
888 __attribute__((alias ("GOMP_parallel_loop_dynamic")));
889 extern __typeof(GOMP_parallel_loop_guided
) GOMP_parallel_loop_nonmonotonic_guided
890 __attribute__((alias ("GOMP_parallel_loop_guided")));
891 extern __typeof(GOMP_parallel_loop_runtime
) GOMP_parallel_loop_nonmonotonic_runtime
892 __attribute__((alias ("GOMP_parallel_loop_runtime")));
893 extern __typeof(GOMP_parallel_loop_runtime
) GOMP_parallel_loop_maybe_nonmonotonic_runtime
894 __attribute__((alias ("GOMP_parallel_loop_runtime")));
897 GOMP_parallel_loop_nonmonotonic_dynamic (void (*fn
) (void *), void *data
,
898 unsigned num_threads
, long start
,
899 long end
, long incr
, long chunk_size
,
902 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
903 GFS_DYNAMIC
, chunk_size
, flags
);
905 GOMP_parallel_end ();
909 GOMP_parallel_loop_nonmonotonic_guided (void (*fn
) (void *), void *data
,
910 unsigned num_threads
, long start
,
911 long end
, long incr
, long chunk_size
,
914 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
915 GFS_GUIDED
, chunk_size
, flags
);
917 GOMP_parallel_end ();
921 GOMP_parallel_loop_nonmonotonic_runtime (void (*fn
) (void *), void *data
,
922 unsigned num_threads
, long start
,
923 long end
, long incr
, unsigned flags
)
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 GOMP_parallel_loop_maybe_nonmonotonic_runtime (void (*fn
) (void *), void *data
,
935 unsigned num_threads
, long start
,
939 struct gomp_task_icv
*icv
= gomp_icv (false);
940 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
941 icv
->run_sched_var
& ~GFS_MONOTONIC
,
942 icv
->run_sched_chunk_size
, flags
);
944 GOMP_parallel_end ();
948 /* The GOMP_loop_end* routines are called after the thread is told that
949 all loop iterations are complete. The first two versions synchronize
950 all threads; the nowait version does not. */
955 gomp_work_share_end ();
959 GOMP_loop_end_cancel (void)
961 return gomp_work_share_end_cancel ();
965 GOMP_loop_end_nowait (void)
967 gomp_work_share_end_nowait ();
971 /* We use static functions above so that we're sure that the "runtime"
972 function can defer to the proper routine without interposition. We
973 export the static function with a strong alias when possible, or with
974 a wrapper function otherwise. */
976 #ifdef HAVE_ATTRIBUTE_ALIAS
977 extern __typeof(gomp_loop_static_start
) GOMP_loop_static_start
978 __attribute__((alias ("gomp_loop_static_start")));
979 extern __typeof(gomp_loop_dynamic_start
) GOMP_loop_dynamic_start
980 __attribute__((alias ("gomp_loop_dynamic_start")));
981 extern __typeof(gomp_loop_guided_start
) GOMP_loop_guided_start
982 __attribute__((alias ("gomp_loop_guided_start")));
983 extern __typeof(gomp_loop_dynamic_start
) GOMP_loop_nonmonotonic_dynamic_start
984 __attribute__((alias ("gomp_loop_dynamic_start")));
985 extern __typeof(gomp_loop_guided_start
) GOMP_loop_nonmonotonic_guided_start
986 __attribute__((alias ("gomp_loop_guided_start")));
987 extern __typeof(GOMP_loop_runtime_start
) GOMP_loop_nonmonotonic_runtime_start
988 __attribute__((alias ("GOMP_loop_runtime_start")));
989 extern __typeof(GOMP_loop_runtime_start
) GOMP_loop_maybe_nonmonotonic_runtime_start
990 __attribute__((alias ("GOMP_loop_runtime_start")));
992 extern __typeof(gomp_loop_ordered_static_start
) GOMP_loop_ordered_static_start
993 __attribute__((alias ("gomp_loop_ordered_static_start")));
994 extern __typeof(gomp_loop_ordered_dynamic_start
) GOMP_loop_ordered_dynamic_start
995 __attribute__((alias ("gomp_loop_ordered_dynamic_start")));
996 extern __typeof(gomp_loop_ordered_guided_start
) GOMP_loop_ordered_guided_start
997 __attribute__((alias ("gomp_loop_ordered_guided_start")));
999 extern __typeof(gomp_loop_doacross_static_start
) GOMP_loop_doacross_static_start
1000 __attribute__((alias ("gomp_loop_doacross_static_start")));
1001 extern __typeof(gomp_loop_doacross_dynamic_start
) GOMP_loop_doacross_dynamic_start
1002 __attribute__((alias ("gomp_loop_doacross_dynamic_start")));
1003 extern __typeof(gomp_loop_doacross_guided_start
) GOMP_loop_doacross_guided_start
1004 __attribute__((alias ("gomp_loop_doacross_guided_start")));
1006 extern __typeof(gomp_loop_static_next
) GOMP_loop_static_next
1007 __attribute__((alias ("gomp_loop_static_next")));
1008 extern __typeof(gomp_loop_dynamic_next
) GOMP_loop_dynamic_next
1009 __attribute__((alias ("gomp_loop_dynamic_next")));
1010 extern __typeof(gomp_loop_guided_next
) GOMP_loop_guided_next
1011 __attribute__((alias ("gomp_loop_guided_next")));
1012 extern __typeof(gomp_loop_dynamic_next
) GOMP_loop_nonmonotonic_dynamic_next
1013 __attribute__((alias ("gomp_loop_dynamic_next")));
1014 extern __typeof(gomp_loop_guided_next
) GOMP_loop_nonmonotonic_guided_next
1015 __attribute__((alias ("gomp_loop_guided_next")));
1016 extern __typeof(GOMP_loop_runtime_next
) GOMP_loop_nonmonotonic_runtime_next
1017 __attribute__((alias ("GOMP_loop_runtime_next")));
1018 extern __typeof(GOMP_loop_runtime_next
) GOMP_loop_maybe_nonmonotonic_runtime_next
1019 __attribute__((alias ("GOMP_loop_runtime_next")));
1021 extern __typeof(gomp_loop_ordered_static_next
) GOMP_loop_ordered_static_next
1022 __attribute__((alias ("gomp_loop_ordered_static_next")));
1023 extern __typeof(gomp_loop_ordered_dynamic_next
) GOMP_loop_ordered_dynamic_next
1024 __attribute__((alias ("gomp_loop_ordered_dynamic_next")));
1025 extern __typeof(gomp_loop_ordered_guided_next
) GOMP_loop_ordered_guided_next
1026 __attribute__((alias ("gomp_loop_ordered_guided_next")));
1029 GOMP_loop_static_start (long start
, long end
, long incr
, long chunk_size
,
1030 long *istart
, long *iend
)
1032 return gomp_loop_static_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1036 GOMP_loop_dynamic_start (long start
, long end
, long incr
, long chunk_size
,
1037 long *istart
, long *iend
)
1039 return gomp_loop_dynamic_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1043 GOMP_loop_guided_start (long start
, long end
, long incr
, long chunk_size
,
1044 long *istart
, long *iend
)
1046 return gomp_loop_guided_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1050 GOMP_loop_nonmonotonic_dynamic_start (long start
, long end
, long incr
,
1051 long chunk_size
, long *istart
,
1054 return gomp_loop_dynamic_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1058 GOMP_loop_nonmonotonic_guided_start (long start
, long end
, long incr
,
1059 long chunk_size
, long *istart
, long *iend
)
1061 return gomp_loop_guided_start (start
, end
, incr
, chunk_size
, istart
, iend
);
1065 GOMP_loop_nonmonotonic_runtime_start (long start
, long end
, long incr
,
1066 long *istart
, long *iend
)
1068 return GOMP_loop_runtime_start (start
, end
, incr
, istart
, iend
);
1072 GOMP_loop_maybe_nonmonotonic_runtime_start (long start
, long end
, long incr
,
1073 long *istart
, long *iend
)
1075 return GOMP_loop_runtime_start (start
, end
, incr
, istart
, iend
);
1079 GOMP_loop_ordered_static_start (long start
, long end
, long incr
,
1080 long chunk_size
, long *istart
, long *iend
)
1082 return gomp_loop_ordered_static_start (start
, end
, incr
, chunk_size
,
1087 GOMP_loop_ordered_dynamic_start (long start
, long end
, long incr
,
1088 long chunk_size
, long *istart
, long *iend
)
1090 return gomp_loop_ordered_dynamic_start (start
, end
, incr
, chunk_size
,
1095 GOMP_loop_ordered_guided_start (long start
, long end
, long incr
,
1096 long chunk_size
, long *istart
, long *iend
)
1098 return gomp_loop_ordered_guided_start (start
, end
, incr
, chunk_size
,
1103 GOMP_loop_doacross_static_start (unsigned ncounts
, long *counts
,
1104 long chunk_size
, long *istart
, long *iend
)
1106 return gomp_loop_doacross_static_start (ncounts
, counts
, chunk_size
,
1111 GOMP_loop_doacross_dynamic_start (unsigned ncounts
, long *counts
,
1112 long chunk_size
, long *istart
, long *iend
)
1114 return gomp_loop_doacross_dynamic_start (ncounts
, counts
, chunk_size
,
1119 GOMP_loop_doacross_guided_start (unsigned ncounts
, long *counts
,
1120 long chunk_size
, long *istart
, long *iend
)
1122 return gomp_loop_doacross_guided_start (ncounts
, counts
, chunk_size
,
1127 GOMP_loop_static_next (long *istart
, long *iend
)
1129 return gomp_loop_static_next (istart
, iend
);
1133 GOMP_loop_dynamic_next (long *istart
, long *iend
)
1135 return gomp_loop_dynamic_next (istart
, iend
);
1139 GOMP_loop_guided_next (long *istart
, long *iend
)
1141 return gomp_loop_guided_next (istart
, iend
);
1145 GOMP_loop_nonmonotonic_dynamic_next (long *istart
, long *iend
)
1147 return gomp_loop_dynamic_next (istart
, iend
);
1151 GOMP_loop_nonmonotonic_guided_next (long *istart
, long *iend
)
1153 return gomp_loop_guided_next (istart
, iend
);
1157 GOMP_loop_nonmonotonic_runtime_next (long *istart
, long *iend
)
1159 return GOMP_loop_runtime_next (istart
, iend
);
1163 GOMP_loop_maybe_nonmonotonic_runtime_next (long *istart
, long *iend
)
1165 return GOMP_loop_runtime_next (istart
, iend
);
1169 GOMP_loop_ordered_static_next (long *istart
, long *iend
)
1171 return gomp_loop_ordered_static_next (istart
, iend
);
1175 GOMP_loop_ordered_dynamic_next (long *istart
, long *iend
)
1177 return gomp_loop_ordered_dynamic_next (istart
, iend
);
1181 GOMP_loop_ordered_guided_next (long *istart
, long *iend
)
1183 return gomp_loop_ordered_guided_next (istart
, iend
);