xref: /netbsd-src/external/gpl3/gcc.old/dist/libgomp/sections.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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