1*8feb0f0bSmrg /* Copyright (C) 2005-2020 Free Software Foundation, Inc.
21debfc3dSmrg Contributed by Richard Henderson <rth@redhat.com>.
31debfc3dSmrg
41debfc3dSmrg This file is part of the GNU Offloading and Multi Processing Library
51debfc3dSmrg (libgomp).
61debfc3dSmrg
71debfc3dSmrg Libgomp is free software; you can redistribute it and/or modify it
81debfc3dSmrg under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg
121debfc3dSmrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
131debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
141debfc3dSmrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for
151debfc3dSmrg more details.
161debfc3dSmrg
171debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
181debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
191debfc3dSmrg 3.1, as published by the Free Software Foundation.
201debfc3dSmrg
211debfc3dSmrg You should have received a copy of the GNU General Public License and
221debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
231debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
241debfc3dSmrg <http://www.gnu.org/licenses/>. */
251debfc3dSmrg
261debfc3dSmrg /* This file handles the SECTIONS construct. */
271debfc3dSmrg
281debfc3dSmrg #include "libgomp.h"
29c0a68be4Smrg #include <string.h>
301debfc3dSmrg
311debfc3dSmrg
ialias_redirect(GOMP_taskgroup_reduction_register)32c0a68be4Smrg ialias_redirect (GOMP_taskgroup_reduction_register)
33c0a68be4Smrg
341debfc3dSmrg /* Initialize the given work share construct from the given arguments. */
351debfc3dSmrg
361debfc3dSmrg static inline void
371debfc3dSmrg gomp_sections_init (struct gomp_work_share *ws, unsigned count)
381debfc3dSmrg {
391debfc3dSmrg ws->sched = GFS_DYNAMIC;
401debfc3dSmrg ws->chunk_size = 1;
411debfc3dSmrg ws->end = count + 1L;
421debfc3dSmrg ws->incr = 1;
431debfc3dSmrg ws->next = 1;
441debfc3dSmrg #ifdef HAVE_SYNC_BUILTINS
451debfc3dSmrg /* Prepare things to make each iteration faster. */
461debfc3dSmrg if (sizeof (long) > sizeof (unsigned))
471debfc3dSmrg ws->mode = 1;
481debfc3dSmrg else
491debfc3dSmrg {
501debfc3dSmrg struct gomp_thread *thr = gomp_thread ();
511debfc3dSmrg struct gomp_team *team = thr->ts.team;
521debfc3dSmrg long nthreads = team ? team->nthreads : 1;
531debfc3dSmrg
541debfc3dSmrg ws->mode = ((nthreads | ws->end)
551debfc3dSmrg < 1UL << (sizeof (long) * __CHAR_BIT__ / 2 - 1));
561debfc3dSmrg }
571debfc3dSmrg #else
581debfc3dSmrg ws->mode = 0;
591debfc3dSmrg #endif
601debfc3dSmrg }
611debfc3dSmrg
621debfc3dSmrg /* This routine is called when first encountering a sections construct
631debfc3dSmrg that is not bound directly to a parallel construct. The first thread
641debfc3dSmrg that arrives will create the work-share construct; subsequent threads
651debfc3dSmrg will see the construct exists and allocate work from it.
661debfc3dSmrg
671debfc3dSmrg COUNT is the number of sections in this construct.
681debfc3dSmrg
691debfc3dSmrg Returns the 1-based section number for this thread to perform, or 0 if
701debfc3dSmrg all work was assigned to other threads prior to this thread's arrival. */
711debfc3dSmrg
721debfc3dSmrg unsigned
GOMP_sections_start(unsigned count)731debfc3dSmrg GOMP_sections_start (unsigned count)
741debfc3dSmrg {
751debfc3dSmrg struct gomp_thread *thr = gomp_thread ();
761debfc3dSmrg long s, e, ret;
771debfc3dSmrg
78c0a68be4Smrg if (gomp_work_share_start (0))
791debfc3dSmrg {
801debfc3dSmrg gomp_sections_init (thr->ts.work_share, count);
811debfc3dSmrg gomp_work_share_init_done ();
821debfc3dSmrg }
831debfc3dSmrg
841debfc3dSmrg #ifdef HAVE_SYNC_BUILTINS
851debfc3dSmrg if (gomp_iter_dynamic_next (&s, &e))
861debfc3dSmrg ret = s;
871debfc3dSmrg else
881debfc3dSmrg ret = 0;
891debfc3dSmrg #else
901debfc3dSmrg gomp_mutex_lock (&thr->ts.work_share->lock);
911debfc3dSmrg if (gomp_iter_dynamic_next_locked (&s, &e))
921debfc3dSmrg ret = s;
931debfc3dSmrg else
941debfc3dSmrg ret = 0;
951debfc3dSmrg gomp_mutex_unlock (&thr->ts.work_share->lock);
961debfc3dSmrg #endif
971debfc3dSmrg
981debfc3dSmrg return ret;
991debfc3dSmrg }
1001debfc3dSmrg
101c0a68be4Smrg unsigned
GOMP_sections2_start(unsigned count,uintptr_t * reductions,void ** mem)102c0a68be4Smrg GOMP_sections2_start (unsigned count, uintptr_t *reductions, void **mem)
103c0a68be4Smrg {
104c0a68be4Smrg struct gomp_thread *thr = gomp_thread ();
105c0a68be4Smrg long s, e, ret;
106c0a68be4Smrg
107c0a68be4Smrg if (reductions)
108c0a68be4Smrg gomp_workshare_taskgroup_start ();
109c0a68be4Smrg if (gomp_work_share_start (0))
110c0a68be4Smrg {
111c0a68be4Smrg gomp_sections_init (thr->ts.work_share, count);
112c0a68be4Smrg if (reductions)
113c0a68be4Smrg {
114c0a68be4Smrg GOMP_taskgroup_reduction_register (reductions);
115c0a68be4Smrg thr->task->taskgroup->workshare = true;
116c0a68be4Smrg thr->ts.work_share->task_reductions = reductions;
117c0a68be4Smrg }
118c0a68be4Smrg if (mem)
119c0a68be4Smrg {
120c0a68be4Smrg uintptr_t size = (uintptr_t) *mem;
121c0a68be4Smrg #define INLINE_ORDERED_TEAM_IDS_OFF \
122c0a68be4Smrg ((offsetof (struct gomp_work_share, inline_ordered_team_ids) \
123c0a68be4Smrg + __alignof__ (long long) - 1) & ~(__alignof__ (long long) - 1))
124c0a68be4Smrg if (size > (sizeof (struct gomp_work_share)
125c0a68be4Smrg - INLINE_ORDERED_TEAM_IDS_OFF))
126c0a68be4Smrg *mem
127c0a68be4Smrg = (void *) (thr->ts.work_share->ordered_team_ids
128c0a68be4Smrg = gomp_malloc_cleared (size));
129c0a68be4Smrg else
130c0a68be4Smrg *mem = memset (((char *) thr->ts.work_share)
131c0a68be4Smrg + INLINE_ORDERED_TEAM_IDS_OFF, '\0', size);
132c0a68be4Smrg }
133c0a68be4Smrg gomp_work_share_init_done ();
134c0a68be4Smrg }
135c0a68be4Smrg else
136c0a68be4Smrg {
137c0a68be4Smrg if (reductions)
138c0a68be4Smrg {
139c0a68be4Smrg uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
140c0a68be4Smrg gomp_workshare_task_reduction_register (reductions,
141c0a68be4Smrg first_reductions);
142c0a68be4Smrg }
143c0a68be4Smrg if (mem)
144c0a68be4Smrg {
145c0a68be4Smrg if ((offsetof (struct gomp_work_share, inline_ordered_team_ids)
146c0a68be4Smrg & (__alignof__ (long long) - 1)) == 0)
147c0a68be4Smrg *mem = (void *) thr->ts.work_share->ordered_team_ids;
148c0a68be4Smrg else
149c0a68be4Smrg {
150c0a68be4Smrg uintptr_t p = (uintptr_t) thr->ts.work_share->ordered_team_ids;
151c0a68be4Smrg p += __alignof__ (long long) - 1;
152c0a68be4Smrg p &= ~(__alignof__ (long long) - 1);
153c0a68be4Smrg *mem = (void *) p;
154c0a68be4Smrg }
155c0a68be4Smrg }
156c0a68be4Smrg }
157c0a68be4Smrg
158c0a68be4Smrg #ifdef HAVE_SYNC_BUILTINS
159c0a68be4Smrg if (gomp_iter_dynamic_next (&s, &e))
160c0a68be4Smrg ret = s;
161c0a68be4Smrg else
162c0a68be4Smrg ret = 0;
163c0a68be4Smrg #else
164c0a68be4Smrg gomp_mutex_lock (&thr->ts.work_share->lock);
165c0a68be4Smrg if (gomp_iter_dynamic_next_locked (&s, &e))
166c0a68be4Smrg ret = s;
167c0a68be4Smrg else
168c0a68be4Smrg ret = 0;
169c0a68be4Smrg gomp_mutex_unlock (&thr->ts.work_share->lock);
170c0a68be4Smrg #endif
171c0a68be4Smrg
172c0a68be4Smrg return ret;
173c0a68be4Smrg }
174c0a68be4Smrg
1751debfc3dSmrg /* This routine is called when the thread completes processing of the
1761debfc3dSmrg section currently assigned to it. If the work-share construct is
1771debfc3dSmrg bound directly to a parallel construct, then the construct may have
1781debfc3dSmrg been set up before the parallel. In which case, this may be the
1791debfc3dSmrg first iteration for the thread.
1801debfc3dSmrg
1811debfc3dSmrg Returns the 1-based section number for this thread to perform, or 0 if
1821debfc3dSmrg all work was assigned to other threads prior to this thread's arrival. */
1831debfc3dSmrg
1841debfc3dSmrg unsigned
GOMP_sections_next(void)1851debfc3dSmrg GOMP_sections_next (void)
1861debfc3dSmrg {
1871debfc3dSmrg long s, e, ret;
1881debfc3dSmrg
1891debfc3dSmrg #ifdef HAVE_SYNC_BUILTINS
1901debfc3dSmrg if (gomp_iter_dynamic_next (&s, &e))
1911debfc3dSmrg ret = s;
1921debfc3dSmrg else
1931debfc3dSmrg ret = 0;
1941debfc3dSmrg #else
1951debfc3dSmrg struct gomp_thread *thr = gomp_thread ();
1961debfc3dSmrg
1971debfc3dSmrg gomp_mutex_lock (&thr->ts.work_share->lock);
1981debfc3dSmrg if (gomp_iter_dynamic_next_locked (&s, &e))
1991debfc3dSmrg ret = s;
2001debfc3dSmrg else
2011debfc3dSmrg ret = 0;
2021debfc3dSmrg gomp_mutex_unlock (&thr->ts.work_share->lock);
2031debfc3dSmrg #endif
2041debfc3dSmrg
2051debfc3dSmrg return ret;
2061debfc3dSmrg }
2071debfc3dSmrg
2081debfc3dSmrg /* This routine pre-initializes a work-share construct to avoid one
2091debfc3dSmrg synchronization once we get into the loop. */
2101debfc3dSmrg
2111debfc3dSmrg void
GOMP_parallel_sections_start(void (* fn)(void *),void * data,unsigned num_threads,unsigned count)2121debfc3dSmrg GOMP_parallel_sections_start (void (*fn) (void *), void *data,
2131debfc3dSmrg unsigned num_threads, unsigned count)
2141debfc3dSmrg {
2151debfc3dSmrg struct gomp_team *team;
2161debfc3dSmrg
2171debfc3dSmrg num_threads = gomp_resolve_num_threads (num_threads, count);
2181debfc3dSmrg team = gomp_new_team (num_threads);
2191debfc3dSmrg gomp_sections_init (&team->work_shares[0], count);
220c0a68be4Smrg gomp_team_start (fn, data, num_threads, 0, team, NULL);
2211debfc3dSmrg }
2221debfc3dSmrg
ialias_redirect(GOMP_parallel_end)2231debfc3dSmrg ialias_redirect (GOMP_parallel_end)
2241debfc3dSmrg
2251debfc3dSmrg void
2261debfc3dSmrg GOMP_parallel_sections (void (*fn) (void *), void *data,
2271debfc3dSmrg unsigned num_threads, unsigned count, unsigned flags)
2281debfc3dSmrg {
2291debfc3dSmrg struct gomp_team *team;
2301debfc3dSmrg
2311debfc3dSmrg num_threads = gomp_resolve_num_threads (num_threads, count);
2321debfc3dSmrg team = gomp_new_team (num_threads);
2331debfc3dSmrg gomp_sections_init (&team->work_shares[0], count);
234c0a68be4Smrg gomp_team_start (fn, data, num_threads, flags, team, NULL);
2351debfc3dSmrg fn (data);
2361debfc3dSmrg GOMP_parallel_end ();
2371debfc3dSmrg }
2381debfc3dSmrg
2391debfc3dSmrg /* The GOMP_section_end* routines are called after the thread is told
2401debfc3dSmrg that all sections are complete. The first two versions synchronize
2411debfc3dSmrg all threads; the nowait version does not. */
2421debfc3dSmrg
2431debfc3dSmrg void
GOMP_sections_end(void)2441debfc3dSmrg GOMP_sections_end (void)
2451debfc3dSmrg {
2461debfc3dSmrg gomp_work_share_end ();
2471debfc3dSmrg }
2481debfc3dSmrg
2491debfc3dSmrg bool
GOMP_sections_end_cancel(void)2501debfc3dSmrg GOMP_sections_end_cancel (void)
2511debfc3dSmrg {
2521debfc3dSmrg return gomp_work_share_end_cancel ();
2531debfc3dSmrg }
2541debfc3dSmrg
2551debfc3dSmrg void
GOMP_sections_end_nowait(void)2561debfc3dSmrg GOMP_sections_end_nowait (void)
2571debfc3dSmrg {
2581debfc3dSmrg gomp_work_share_end_nowait ();
2591debfc3dSmrg }
260