1*38fd1498Szrj /* Copyright (C) 2005-2018 Free Software Foundation, Inc.
2*38fd1498Szrj    Contributed by Richard Henderson <rth@redhat.com>.
3*38fd1498Szrj 
4*38fd1498Szrj    This file is part of the GNU Offloading and Multi Processing Library
5*38fd1498Szrj    (libgomp).
6*38fd1498Szrj 
7*38fd1498Szrj    Libgomp is free software; you can redistribute it and/or modify it
8*38fd1498Szrj    under the terms of the GNU General Public License as published by
9*38fd1498Szrj    the Free Software Foundation; either version 3, or (at your option)
10*38fd1498Szrj    any later version.
11*38fd1498Szrj 
12*38fd1498Szrj    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13*38fd1498Szrj    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14*38fd1498Szrj    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15*38fd1498Szrj    more details.
16*38fd1498Szrj 
17*38fd1498Szrj    Under Section 7 of GPL version 3, you are granted additional
18*38fd1498Szrj    permissions described in the GCC Runtime Library Exception, version
19*38fd1498Szrj    3.1, as published by the Free Software Foundation.
20*38fd1498Szrj 
21*38fd1498Szrj    You should have received a copy of the GNU General Public License and
22*38fd1498Szrj    a copy of the GCC Runtime Library Exception along with this program;
23*38fd1498Szrj    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24*38fd1498Szrj    <http://www.gnu.org/licenses/>.  */
25*38fd1498Szrj 
26*38fd1498Szrj /* This file handles the SECTIONS construct.  */
27*38fd1498Szrj 
28*38fd1498Szrj #include "libgomp.h"
29*38fd1498Szrj 
30*38fd1498Szrj 
31*38fd1498Szrj /* Initialize the given work share construct from the given arguments.  */
32*38fd1498Szrj 
33*38fd1498Szrj static inline void
gomp_sections_init(struct gomp_work_share * ws,unsigned count)34*38fd1498Szrj gomp_sections_init (struct gomp_work_share *ws, unsigned count)
35*38fd1498Szrj {
36*38fd1498Szrj   ws->sched = GFS_DYNAMIC;
37*38fd1498Szrj   ws->chunk_size = 1;
38*38fd1498Szrj   ws->end = count + 1L;
39*38fd1498Szrj   ws->incr = 1;
40*38fd1498Szrj   ws->next = 1;
41*38fd1498Szrj #ifdef HAVE_SYNC_BUILTINS
42*38fd1498Szrj   /* Prepare things to make each iteration faster.  */
43*38fd1498Szrj   if (sizeof (long) > sizeof (unsigned))
44*38fd1498Szrj     ws->mode = 1;
45*38fd1498Szrj   else
46*38fd1498Szrj     {
47*38fd1498Szrj       struct gomp_thread *thr = gomp_thread ();
48*38fd1498Szrj       struct gomp_team *team = thr->ts.team;
49*38fd1498Szrj       long nthreads = team ? team->nthreads : 1;
50*38fd1498Szrj 
51*38fd1498Szrj       ws->mode = ((nthreads | ws->end)
52*38fd1498Szrj 		  < 1UL << (sizeof (long) * __CHAR_BIT__ / 2 - 1));
53*38fd1498Szrj     }
54*38fd1498Szrj #else
55*38fd1498Szrj   ws->mode = 0;
56*38fd1498Szrj #endif
57*38fd1498Szrj }
58*38fd1498Szrj 
59*38fd1498Szrj /* This routine is called when first encountering a sections construct
60*38fd1498Szrj    that is not bound directly to a parallel construct.  The first thread
61*38fd1498Szrj    that arrives will create the work-share construct; subsequent threads
62*38fd1498Szrj    will see the construct exists and allocate work from it.
63*38fd1498Szrj 
64*38fd1498Szrj    COUNT is the number of sections in this construct.
65*38fd1498Szrj 
66*38fd1498Szrj    Returns the 1-based section number for this thread to perform, or 0 if
67*38fd1498Szrj    all work was assigned to other threads prior to this thread's arrival.  */
68*38fd1498Szrj 
69*38fd1498Szrj unsigned
GOMP_sections_start(unsigned count)70*38fd1498Szrj GOMP_sections_start (unsigned count)
71*38fd1498Szrj {
72*38fd1498Szrj   struct gomp_thread *thr = gomp_thread ();
73*38fd1498Szrj   long s, e, ret;
74*38fd1498Szrj 
75*38fd1498Szrj   if (gomp_work_share_start (false))
76*38fd1498Szrj     {
77*38fd1498Szrj       gomp_sections_init (thr->ts.work_share, count);
78*38fd1498Szrj       gomp_work_share_init_done ();
79*38fd1498Szrj     }
80*38fd1498Szrj 
81*38fd1498Szrj #ifdef HAVE_SYNC_BUILTINS
82*38fd1498Szrj   if (gomp_iter_dynamic_next (&s, &e))
83*38fd1498Szrj     ret = s;
84*38fd1498Szrj   else
85*38fd1498Szrj     ret = 0;
86*38fd1498Szrj #else
87*38fd1498Szrj   gomp_mutex_lock (&thr->ts.work_share->lock);
88*38fd1498Szrj   if (gomp_iter_dynamic_next_locked (&s, &e))
89*38fd1498Szrj     ret = s;
90*38fd1498Szrj   else
91*38fd1498Szrj     ret = 0;
92*38fd1498Szrj   gomp_mutex_unlock (&thr->ts.work_share->lock);
93*38fd1498Szrj #endif
94*38fd1498Szrj 
95*38fd1498Szrj   return ret;
96*38fd1498Szrj }
97*38fd1498Szrj 
98*38fd1498Szrj /* This routine is called when the thread completes processing of the
99*38fd1498Szrj    section currently assigned to it.  If the work-share construct is
100*38fd1498Szrj    bound directly to a parallel construct, then the construct may have
101*38fd1498Szrj    been set up before the parallel.  In which case, this may be the
102*38fd1498Szrj    first iteration for the thread.
103*38fd1498Szrj 
104*38fd1498Szrj    Returns the 1-based section number for this thread to perform, or 0 if
105*38fd1498Szrj    all work was assigned to other threads prior to this thread's arrival.  */
106*38fd1498Szrj 
107*38fd1498Szrj unsigned
GOMP_sections_next(void)108*38fd1498Szrj GOMP_sections_next (void)
109*38fd1498Szrj {
110*38fd1498Szrj   long s, e, ret;
111*38fd1498Szrj 
112*38fd1498Szrj #ifdef HAVE_SYNC_BUILTINS
113*38fd1498Szrj   if (gomp_iter_dynamic_next (&s, &e))
114*38fd1498Szrj     ret = s;
115*38fd1498Szrj   else
116*38fd1498Szrj     ret = 0;
117*38fd1498Szrj #else
118*38fd1498Szrj   struct gomp_thread *thr = gomp_thread ();
119*38fd1498Szrj 
120*38fd1498Szrj   gomp_mutex_lock (&thr->ts.work_share->lock);
121*38fd1498Szrj   if (gomp_iter_dynamic_next_locked (&s, &e))
122*38fd1498Szrj     ret = s;
123*38fd1498Szrj   else
124*38fd1498Szrj     ret = 0;
125*38fd1498Szrj   gomp_mutex_unlock (&thr->ts.work_share->lock);
126*38fd1498Szrj #endif
127*38fd1498Szrj 
128*38fd1498Szrj   return ret;
129*38fd1498Szrj }
130*38fd1498Szrj 
131*38fd1498Szrj /* This routine pre-initializes a work-share construct to avoid one
132*38fd1498Szrj    synchronization once we get into the loop.  */
133*38fd1498Szrj 
134*38fd1498Szrj void
GOMP_parallel_sections_start(void (* fn)(void *),void * data,unsigned num_threads,unsigned count)135*38fd1498Szrj GOMP_parallel_sections_start (void (*fn) (void *), void *data,
136*38fd1498Szrj 			      unsigned num_threads, unsigned count)
137*38fd1498Szrj {
138*38fd1498Szrj   struct gomp_team *team;
139*38fd1498Szrj 
140*38fd1498Szrj   num_threads = gomp_resolve_num_threads (num_threads, count);
141*38fd1498Szrj   team = gomp_new_team (num_threads);
142*38fd1498Szrj   gomp_sections_init (&team->work_shares[0], count);
143*38fd1498Szrj   gomp_team_start (fn, data, num_threads, 0, team);
144*38fd1498Szrj }
145*38fd1498Szrj 
ialias_redirect(GOMP_parallel_end)146*38fd1498Szrj ialias_redirect (GOMP_parallel_end)
147*38fd1498Szrj 
148*38fd1498Szrj void
149*38fd1498Szrj GOMP_parallel_sections (void (*fn) (void *), void *data,
150*38fd1498Szrj 			unsigned num_threads, unsigned count, unsigned flags)
151*38fd1498Szrj {
152*38fd1498Szrj   struct gomp_team *team;
153*38fd1498Szrj 
154*38fd1498Szrj   num_threads = gomp_resolve_num_threads (num_threads, count);
155*38fd1498Szrj   team = gomp_new_team (num_threads);
156*38fd1498Szrj   gomp_sections_init (&team->work_shares[0], count);
157*38fd1498Szrj   gomp_team_start (fn, data, num_threads, flags, team);
158*38fd1498Szrj   fn (data);
159*38fd1498Szrj   GOMP_parallel_end ();
160*38fd1498Szrj }
161*38fd1498Szrj 
162*38fd1498Szrj /* The GOMP_section_end* routines are called after the thread is told
163*38fd1498Szrj    that all sections are complete.  The first two versions synchronize
164*38fd1498Szrj    all threads; the nowait version does not.  */
165*38fd1498Szrj 
166*38fd1498Szrj void
GOMP_sections_end(void)167*38fd1498Szrj GOMP_sections_end (void)
168*38fd1498Szrj {
169*38fd1498Szrj   gomp_work_share_end ();
170*38fd1498Szrj }
171*38fd1498Szrj 
172*38fd1498Szrj bool
GOMP_sections_end_cancel(void)173*38fd1498Szrj GOMP_sections_end_cancel (void)
174*38fd1498Szrj {
175*38fd1498Szrj   return gomp_work_share_end_cancel ();
176*38fd1498Szrj }
177*38fd1498Szrj 
178*38fd1498Szrj void
GOMP_sections_end_nowait(void)179*38fd1498Szrj GOMP_sections_end_nowait (void)
180*38fd1498Szrj {
181*38fd1498Szrj   gomp_work_share_end_nowait ();
182*38fd1498Szrj }
183