1*629ff9f7SJohn Marino /* Copyright (C) 2005, 2008, 2009 Free Software Foundation, Inc.
2*629ff9f7SJohn Marino Contributed by Richard Henderson <rth@redhat.com>.
3*629ff9f7SJohn Marino
4*629ff9f7SJohn Marino This file is part of the GNU OpenMP Library (libgomp).
5*629ff9f7SJohn Marino
6*629ff9f7SJohn Marino Libgomp is free software; you can redistribute it and/or modify it
7*629ff9f7SJohn Marino under the terms of the GNU General Public License as published by
8*629ff9f7SJohn Marino the Free Software Foundation; either version 3, or (at your option)
9*629ff9f7SJohn Marino any later version.
10*629ff9f7SJohn Marino
11*629ff9f7SJohn Marino Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12*629ff9f7SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13*629ff9f7SJohn Marino FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14*629ff9f7SJohn Marino more details.
15*629ff9f7SJohn Marino
16*629ff9f7SJohn Marino Under Section 7 of GPL version 3, you are granted additional
17*629ff9f7SJohn Marino permissions described in the GCC Runtime Library Exception, version
18*629ff9f7SJohn Marino 3.1, as published by the Free Software Foundation.
19*629ff9f7SJohn Marino
20*629ff9f7SJohn Marino You should have received a copy of the GNU General Public License and
21*629ff9f7SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
22*629ff9f7SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23*629ff9f7SJohn Marino <http://www.gnu.org/licenses/>. */
24*629ff9f7SJohn Marino
25*629ff9f7SJohn Marino /* This file handles the LOOP (FOR/DO) construct. */
26*629ff9f7SJohn Marino
27*629ff9f7SJohn Marino #include <limits.h>
28*629ff9f7SJohn Marino #include <stdlib.h>
29*629ff9f7SJohn Marino #include "libgomp.h"
30*629ff9f7SJohn Marino
31*629ff9f7SJohn Marino
32*629ff9f7SJohn Marino /* Initialize the given work share construct from the given arguments. */
33*629ff9f7SJohn Marino
34*629ff9f7SJohn Marino static inline void
gomp_loop_init(struct gomp_work_share * ws,long start,long end,long incr,enum gomp_schedule_type sched,long chunk_size)35*629ff9f7SJohn Marino gomp_loop_init (struct gomp_work_share *ws, long start, long end, long incr,
36*629ff9f7SJohn Marino enum gomp_schedule_type sched, long chunk_size)
37*629ff9f7SJohn Marino {
38*629ff9f7SJohn Marino ws->sched = sched;
39*629ff9f7SJohn Marino ws->chunk_size = chunk_size;
40*629ff9f7SJohn Marino /* Canonicalize loops that have zero iterations to ->next == ->end. */
41*629ff9f7SJohn Marino ws->end = ((incr > 0 && start > end) || (incr < 0 && start < end))
42*629ff9f7SJohn Marino ? start : end;
43*629ff9f7SJohn Marino ws->incr = incr;
44*629ff9f7SJohn Marino ws->next = start;
45*629ff9f7SJohn Marino if (sched == GFS_DYNAMIC)
46*629ff9f7SJohn Marino {
47*629ff9f7SJohn Marino ws->chunk_size *= incr;
48*629ff9f7SJohn Marino
49*629ff9f7SJohn Marino #ifdef HAVE_SYNC_BUILTINS
50*629ff9f7SJohn Marino {
51*629ff9f7SJohn Marino /* For dynamic scheduling prepare things to make each iteration
52*629ff9f7SJohn Marino faster. */
53*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
54*629ff9f7SJohn Marino struct gomp_team *team = thr->ts.team;
55*629ff9f7SJohn Marino long nthreads = team ? team->nthreads : 1;
56*629ff9f7SJohn Marino
57*629ff9f7SJohn Marino if (__builtin_expect (incr > 0, 1))
58*629ff9f7SJohn Marino {
59*629ff9f7SJohn Marino /* Cheap overflow protection. */
60*629ff9f7SJohn Marino if (__builtin_expect ((nthreads | ws->chunk_size)
61*629ff9f7SJohn Marino >= 1UL << (sizeof (long)
62*629ff9f7SJohn Marino * __CHAR_BIT__ / 2 - 1), 0))
63*629ff9f7SJohn Marino ws->mode = 0;
64*629ff9f7SJohn Marino else
65*629ff9f7SJohn Marino ws->mode = ws->end < (LONG_MAX
66*629ff9f7SJohn Marino - (nthreads + 1) * ws->chunk_size);
67*629ff9f7SJohn Marino }
68*629ff9f7SJohn Marino /* Cheap overflow protection. */
69*629ff9f7SJohn Marino else if (__builtin_expect ((nthreads | -ws->chunk_size)
70*629ff9f7SJohn Marino >= 1UL << (sizeof (long)
71*629ff9f7SJohn Marino * __CHAR_BIT__ / 2 - 1), 0))
72*629ff9f7SJohn Marino ws->mode = 0;
73*629ff9f7SJohn Marino else
74*629ff9f7SJohn Marino ws->mode = ws->end > (nthreads + 1) * -ws->chunk_size - LONG_MAX;
75*629ff9f7SJohn Marino }
76*629ff9f7SJohn Marino #endif
77*629ff9f7SJohn Marino }
78*629ff9f7SJohn Marino }
79*629ff9f7SJohn Marino
80*629ff9f7SJohn Marino /* The *_start routines are called when first encountering a loop construct
81*629ff9f7SJohn Marino that is not bound directly to a parallel construct. The first thread
82*629ff9f7SJohn Marino that arrives will create the work-share construct; subsequent threads
83*629ff9f7SJohn Marino will see the construct exists and allocate work from it.
84*629ff9f7SJohn Marino
85*629ff9f7SJohn Marino START, END, INCR are the bounds of the loop; due to the restrictions of
86*629ff9f7SJohn Marino OpenMP, these values must be the same in every thread. This is not
87*629ff9f7SJohn Marino verified (nor is it entirely verifiable, since START is not necessarily
88*629ff9f7SJohn Marino retained intact in the work-share data structure). CHUNK_SIZE is the
89*629ff9f7SJohn Marino scheduling parameter; again this must be identical in all threads.
90*629ff9f7SJohn Marino
91*629ff9f7SJohn Marino Returns true if there's any work for this thread to perform. If so,
92*629ff9f7SJohn Marino *ISTART and *IEND are filled with the bounds of the iteration block
93*629ff9f7SJohn Marino allocated to this thread. Returns false if all work was assigned to
94*629ff9f7SJohn Marino other threads prior to this thread's arrival. */
95*629ff9f7SJohn Marino
96*629ff9f7SJohn Marino static bool
gomp_loop_static_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)97*629ff9f7SJohn Marino gomp_loop_static_start (long start, long end, long incr, long chunk_size,
98*629ff9f7SJohn Marino long *istart, long *iend)
99*629ff9f7SJohn Marino {
100*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
101*629ff9f7SJohn Marino
102*629ff9f7SJohn Marino thr->ts.static_trip = 0;
103*629ff9f7SJohn Marino if (gomp_work_share_start (false))
104*629ff9f7SJohn Marino {
105*629ff9f7SJohn Marino gomp_loop_init (thr->ts.work_share, start, end, incr,
106*629ff9f7SJohn Marino GFS_STATIC, chunk_size);
107*629ff9f7SJohn Marino gomp_work_share_init_done ();
108*629ff9f7SJohn Marino }
109*629ff9f7SJohn Marino
110*629ff9f7SJohn Marino return !gomp_iter_static_next (istart, iend);
111*629ff9f7SJohn Marino }
112*629ff9f7SJohn Marino
113*629ff9f7SJohn Marino static bool
gomp_loop_dynamic_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)114*629ff9f7SJohn Marino gomp_loop_dynamic_start (long start, long end, long incr, long chunk_size,
115*629ff9f7SJohn Marino long *istart, long *iend)
116*629ff9f7SJohn Marino {
117*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
118*629ff9f7SJohn Marino bool ret;
119*629ff9f7SJohn Marino
120*629ff9f7SJohn Marino if (gomp_work_share_start (false))
121*629ff9f7SJohn Marino {
122*629ff9f7SJohn Marino gomp_loop_init (thr->ts.work_share, start, end, incr,
123*629ff9f7SJohn Marino GFS_DYNAMIC, chunk_size);
124*629ff9f7SJohn Marino gomp_work_share_init_done ();
125*629ff9f7SJohn Marino }
126*629ff9f7SJohn Marino
127*629ff9f7SJohn Marino #ifdef HAVE_SYNC_BUILTINS
128*629ff9f7SJohn Marino ret = gomp_iter_dynamic_next (istart, iend);
129*629ff9f7SJohn Marino #else
130*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
131*629ff9f7SJohn Marino ret = gomp_iter_dynamic_next_locked (istart, iend);
132*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
133*629ff9f7SJohn Marino #endif
134*629ff9f7SJohn Marino
135*629ff9f7SJohn Marino return ret;
136*629ff9f7SJohn Marino }
137*629ff9f7SJohn Marino
138*629ff9f7SJohn Marino static bool
gomp_loop_guided_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)139*629ff9f7SJohn Marino gomp_loop_guided_start (long start, long end, long incr, long chunk_size,
140*629ff9f7SJohn Marino long *istart, long *iend)
141*629ff9f7SJohn Marino {
142*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
143*629ff9f7SJohn Marino bool ret;
144*629ff9f7SJohn Marino
145*629ff9f7SJohn Marino if (gomp_work_share_start (false))
146*629ff9f7SJohn Marino {
147*629ff9f7SJohn Marino gomp_loop_init (thr->ts.work_share, start, end, incr,
148*629ff9f7SJohn Marino GFS_GUIDED, chunk_size);
149*629ff9f7SJohn Marino gomp_work_share_init_done ();
150*629ff9f7SJohn Marino }
151*629ff9f7SJohn Marino
152*629ff9f7SJohn Marino #ifdef HAVE_SYNC_BUILTINS
153*629ff9f7SJohn Marino ret = gomp_iter_guided_next (istart, iend);
154*629ff9f7SJohn Marino #else
155*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
156*629ff9f7SJohn Marino ret = gomp_iter_guided_next_locked (istart, iend);
157*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
158*629ff9f7SJohn Marino #endif
159*629ff9f7SJohn Marino
160*629ff9f7SJohn Marino return ret;
161*629ff9f7SJohn Marino }
162*629ff9f7SJohn Marino
163*629ff9f7SJohn Marino bool
GOMP_loop_runtime_start(long start,long end,long incr,long * istart,long * iend)164*629ff9f7SJohn Marino GOMP_loop_runtime_start (long start, long end, long incr,
165*629ff9f7SJohn Marino long *istart, long *iend)
166*629ff9f7SJohn Marino {
167*629ff9f7SJohn Marino struct gomp_task_icv *icv = gomp_icv (false);
168*629ff9f7SJohn Marino switch (icv->run_sched_var)
169*629ff9f7SJohn Marino {
170*629ff9f7SJohn Marino case GFS_STATIC:
171*629ff9f7SJohn Marino return gomp_loop_static_start (start, end, incr, icv->run_sched_modifier,
172*629ff9f7SJohn Marino istart, iend);
173*629ff9f7SJohn Marino case GFS_DYNAMIC:
174*629ff9f7SJohn Marino return gomp_loop_dynamic_start (start, end, incr, icv->run_sched_modifier,
175*629ff9f7SJohn Marino istart, iend);
176*629ff9f7SJohn Marino case GFS_GUIDED:
177*629ff9f7SJohn Marino return gomp_loop_guided_start (start, end, incr, icv->run_sched_modifier,
178*629ff9f7SJohn Marino istart, iend);
179*629ff9f7SJohn Marino case GFS_AUTO:
180*629ff9f7SJohn Marino /* For now map to schedule(static), later on we could play with feedback
181*629ff9f7SJohn Marino driven choice. */
182*629ff9f7SJohn Marino return gomp_loop_static_start (start, end, incr, 0, istart, iend);
183*629ff9f7SJohn Marino default:
184*629ff9f7SJohn Marino abort ();
185*629ff9f7SJohn Marino }
186*629ff9f7SJohn Marino }
187*629ff9f7SJohn Marino
188*629ff9f7SJohn Marino /* The *_ordered_*_start routines are similar. The only difference is that
189*629ff9f7SJohn Marino this work-share construct is initialized to expect an ORDERED section. */
190*629ff9f7SJohn Marino
191*629ff9f7SJohn Marino static bool
gomp_loop_ordered_static_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)192*629ff9f7SJohn Marino gomp_loop_ordered_static_start (long start, long end, long incr,
193*629ff9f7SJohn Marino long chunk_size, long *istart, long *iend)
194*629ff9f7SJohn Marino {
195*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
196*629ff9f7SJohn Marino
197*629ff9f7SJohn Marino thr->ts.static_trip = 0;
198*629ff9f7SJohn Marino if (gomp_work_share_start (true))
199*629ff9f7SJohn Marino {
200*629ff9f7SJohn Marino gomp_loop_init (thr->ts.work_share, start, end, incr,
201*629ff9f7SJohn Marino GFS_STATIC, chunk_size);
202*629ff9f7SJohn Marino gomp_ordered_static_init ();
203*629ff9f7SJohn Marino gomp_work_share_init_done ();
204*629ff9f7SJohn Marino }
205*629ff9f7SJohn Marino
206*629ff9f7SJohn Marino return !gomp_iter_static_next (istart, iend);
207*629ff9f7SJohn Marino }
208*629ff9f7SJohn Marino
209*629ff9f7SJohn Marino static bool
gomp_loop_ordered_dynamic_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)210*629ff9f7SJohn Marino gomp_loop_ordered_dynamic_start (long start, long end, long incr,
211*629ff9f7SJohn Marino long chunk_size, long *istart, long *iend)
212*629ff9f7SJohn Marino {
213*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
214*629ff9f7SJohn Marino bool ret;
215*629ff9f7SJohn Marino
216*629ff9f7SJohn Marino if (gomp_work_share_start (true))
217*629ff9f7SJohn Marino {
218*629ff9f7SJohn Marino gomp_loop_init (thr->ts.work_share, start, end, incr,
219*629ff9f7SJohn Marino GFS_DYNAMIC, chunk_size);
220*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
221*629ff9f7SJohn Marino gomp_work_share_init_done ();
222*629ff9f7SJohn Marino }
223*629ff9f7SJohn Marino else
224*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
225*629ff9f7SJohn Marino
226*629ff9f7SJohn Marino ret = gomp_iter_dynamic_next_locked (istart, iend);
227*629ff9f7SJohn Marino if (ret)
228*629ff9f7SJohn Marino gomp_ordered_first ();
229*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
230*629ff9f7SJohn Marino
231*629ff9f7SJohn Marino return ret;
232*629ff9f7SJohn Marino }
233*629ff9f7SJohn Marino
234*629ff9f7SJohn Marino static bool
gomp_loop_ordered_guided_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)235*629ff9f7SJohn Marino gomp_loop_ordered_guided_start (long start, long end, long incr,
236*629ff9f7SJohn Marino long chunk_size, long *istart, long *iend)
237*629ff9f7SJohn Marino {
238*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
239*629ff9f7SJohn Marino bool ret;
240*629ff9f7SJohn Marino
241*629ff9f7SJohn Marino if (gomp_work_share_start (true))
242*629ff9f7SJohn Marino {
243*629ff9f7SJohn Marino gomp_loop_init (thr->ts.work_share, start, end, incr,
244*629ff9f7SJohn Marino GFS_GUIDED, chunk_size);
245*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
246*629ff9f7SJohn Marino gomp_work_share_init_done ();
247*629ff9f7SJohn Marino }
248*629ff9f7SJohn Marino else
249*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
250*629ff9f7SJohn Marino
251*629ff9f7SJohn Marino ret = gomp_iter_guided_next_locked (istart, iend);
252*629ff9f7SJohn Marino if (ret)
253*629ff9f7SJohn Marino gomp_ordered_first ();
254*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
255*629ff9f7SJohn Marino
256*629ff9f7SJohn Marino return ret;
257*629ff9f7SJohn Marino }
258*629ff9f7SJohn Marino
259*629ff9f7SJohn Marino bool
GOMP_loop_ordered_runtime_start(long start,long end,long incr,long * istart,long * iend)260*629ff9f7SJohn Marino GOMP_loop_ordered_runtime_start (long start, long end, long incr,
261*629ff9f7SJohn Marino long *istart, long *iend)
262*629ff9f7SJohn Marino {
263*629ff9f7SJohn Marino struct gomp_task_icv *icv = gomp_icv (false);
264*629ff9f7SJohn Marino switch (icv->run_sched_var)
265*629ff9f7SJohn Marino {
266*629ff9f7SJohn Marino case GFS_STATIC:
267*629ff9f7SJohn Marino return gomp_loop_ordered_static_start (start, end, incr,
268*629ff9f7SJohn Marino icv->run_sched_modifier,
269*629ff9f7SJohn Marino istart, iend);
270*629ff9f7SJohn Marino case GFS_DYNAMIC:
271*629ff9f7SJohn Marino return gomp_loop_ordered_dynamic_start (start, end, incr,
272*629ff9f7SJohn Marino icv->run_sched_modifier,
273*629ff9f7SJohn Marino istart, iend);
274*629ff9f7SJohn Marino case GFS_GUIDED:
275*629ff9f7SJohn Marino return gomp_loop_ordered_guided_start (start, end, incr,
276*629ff9f7SJohn Marino icv->run_sched_modifier,
277*629ff9f7SJohn Marino istart, iend);
278*629ff9f7SJohn Marino case GFS_AUTO:
279*629ff9f7SJohn Marino /* For now map to schedule(static), later on we could play with feedback
280*629ff9f7SJohn Marino driven choice. */
281*629ff9f7SJohn Marino return gomp_loop_ordered_static_start (start, end, incr,
282*629ff9f7SJohn Marino 0, istart, iend);
283*629ff9f7SJohn Marino default:
284*629ff9f7SJohn Marino abort ();
285*629ff9f7SJohn Marino }
286*629ff9f7SJohn Marino }
287*629ff9f7SJohn Marino
288*629ff9f7SJohn Marino /* The *_next routines are called when the thread completes processing of
289*629ff9f7SJohn Marino the iteration block currently assigned to it. If the work-share
290*629ff9f7SJohn Marino construct is bound directly to a parallel construct, then the iteration
291*629ff9f7SJohn Marino bounds may have been set up before the parallel. In which case, this
292*629ff9f7SJohn Marino may be the first iteration for the thread.
293*629ff9f7SJohn Marino
294*629ff9f7SJohn Marino Returns true if there is work remaining to be performed; *ISTART and
295*629ff9f7SJohn Marino *IEND are filled with a new iteration block. Returns false if all work
296*629ff9f7SJohn Marino has been assigned. */
297*629ff9f7SJohn Marino
298*629ff9f7SJohn Marino static bool
gomp_loop_static_next(long * istart,long * iend)299*629ff9f7SJohn Marino gomp_loop_static_next (long *istart, long *iend)
300*629ff9f7SJohn Marino {
301*629ff9f7SJohn Marino return !gomp_iter_static_next (istart, iend);
302*629ff9f7SJohn Marino }
303*629ff9f7SJohn Marino
304*629ff9f7SJohn Marino static bool
gomp_loop_dynamic_next(long * istart,long * iend)305*629ff9f7SJohn Marino gomp_loop_dynamic_next (long *istart, long *iend)
306*629ff9f7SJohn Marino {
307*629ff9f7SJohn Marino bool ret;
308*629ff9f7SJohn Marino
309*629ff9f7SJohn Marino #ifdef HAVE_SYNC_BUILTINS
310*629ff9f7SJohn Marino ret = gomp_iter_dynamic_next (istart, iend);
311*629ff9f7SJohn Marino #else
312*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
313*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
314*629ff9f7SJohn Marino ret = gomp_iter_dynamic_next_locked (istart, iend);
315*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
316*629ff9f7SJohn Marino #endif
317*629ff9f7SJohn Marino
318*629ff9f7SJohn Marino return ret;
319*629ff9f7SJohn Marino }
320*629ff9f7SJohn Marino
321*629ff9f7SJohn Marino static bool
gomp_loop_guided_next(long * istart,long * iend)322*629ff9f7SJohn Marino gomp_loop_guided_next (long *istart, long *iend)
323*629ff9f7SJohn Marino {
324*629ff9f7SJohn Marino bool ret;
325*629ff9f7SJohn Marino
326*629ff9f7SJohn Marino #ifdef HAVE_SYNC_BUILTINS
327*629ff9f7SJohn Marino ret = gomp_iter_guided_next (istart, iend);
328*629ff9f7SJohn Marino #else
329*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
330*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
331*629ff9f7SJohn Marino ret = gomp_iter_guided_next_locked (istart, iend);
332*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
333*629ff9f7SJohn Marino #endif
334*629ff9f7SJohn Marino
335*629ff9f7SJohn Marino return ret;
336*629ff9f7SJohn Marino }
337*629ff9f7SJohn Marino
338*629ff9f7SJohn Marino bool
GOMP_loop_runtime_next(long * istart,long * iend)339*629ff9f7SJohn Marino GOMP_loop_runtime_next (long *istart, long *iend)
340*629ff9f7SJohn Marino {
341*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
342*629ff9f7SJohn Marino
343*629ff9f7SJohn Marino switch (thr->ts.work_share->sched)
344*629ff9f7SJohn Marino {
345*629ff9f7SJohn Marino case GFS_STATIC:
346*629ff9f7SJohn Marino case GFS_AUTO:
347*629ff9f7SJohn Marino return gomp_loop_static_next (istart, iend);
348*629ff9f7SJohn Marino case GFS_DYNAMIC:
349*629ff9f7SJohn Marino return gomp_loop_dynamic_next (istart, iend);
350*629ff9f7SJohn Marino case GFS_GUIDED:
351*629ff9f7SJohn Marino return gomp_loop_guided_next (istart, iend);
352*629ff9f7SJohn Marino default:
353*629ff9f7SJohn Marino abort ();
354*629ff9f7SJohn Marino }
355*629ff9f7SJohn Marino }
356*629ff9f7SJohn Marino
357*629ff9f7SJohn Marino /* The *_ordered_*_next routines are called when the thread completes
358*629ff9f7SJohn Marino processing of the iteration block currently assigned to it.
359*629ff9f7SJohn Marino
360*629ff9f7SJohn Marino Returns true if there is work remaining to be performed; *ISTART and
361*629ff9f7SJohn Marino *IEND are filled with a new iteration block. Returns false if all work
362*629ff9f7SJohn Marino has been assigned. */
363*629ff9f7SJohn Marino
364*629ff9f7SJohn Marino static bool
gomp_loop_ordered_static_next(long * istart,long * iend)365*629ff9f7SJohn Marino gomp_loop_ordered_static_next (long *istart, long *iend)
366*629ff9f7SJohn Marino {
367*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
368*629ff9f7SJohn Marino int test;
369*629ff9f7SJohn Marino
370*629ff9f7SJohn Marino gomp_ordered_sync ();
371*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
372*629ff9f7SJohn Marino test = gomp_iter_static_next (istart, iend);
373*629ff9f7SJohn Marino if (test >= 0)
374*629ff9f7SJohn Marino gomp_ordered_static_next ();
375*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
376*629ff9f7SJohn Marino
377*629ff9f7SJohn Marino return test == 0;
378*629ff9f7SJohn Marino }
379*629ff9f7SJohn Marino
380*629ff9f7SJohn Marino static bool
gomp_loop_ordered_dynamic_next(long * istart,long * iend)381*629ff9f7SJohn Marino gomp_loop_ordered_dynamic_next (long *istart, long *iend)
382*629ff9f7SJohn Marino {
383*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
384*629ff9f7SJohn Marino bool ret;
385*629ff9f7SJohn Marino
386*629ff9f7SJohn Marino gomp_ordered_sync ();
387*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
388*629ff9f7SJohn Marino ret = gomp_iter_dynamic_next_locked (istart, iend);
389*629ff9f7SJohn Marino if (ret)
390*629ff9f7SJohn Marino gomp_ordered_next ();
391*629ff9f7SJohn Marino else
392*629ff9f7SJohn Marino gomp_ordered_last ();
393*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
394*629ff9f7SJohn Marino
395*629ff9f7SJohn Marino return ret;
396*629ff9f7SJohn Marino }
397*629ff9f7SJohn Marino
398*629ff9f7SJohn Marino static bool
gomp_loop_ordered_guided_next(long * istart,long * iend)399*629ff9f7SJohn Marino gomp_loop_ordered_guided_next (long *istart, long *iend)
400*629ff9f7SJohn Marino {
401*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
402*629ff9f7SJohn Marino bool ret;
403*629ff9f7SJohn Marino
404*629ff9f7SJohn Marino gomp_ordered_sync ();
405*629ff9f7SJohn Marino gomp_mutex_lock (&thr->ts.work_share->lock);
406*629ff9f7SJohn Marino ret = gomp_iter_guided_next_locked (istart, iend);
407*629ff9f7SJohn Marino if (ret)
408*629ff9f7SJohn Marino gomp_ordered_next ();
409*629ff9f7SJohn Marino else
410*629ff9f7SJohn Marino gomp_ordered_last ();
411*629ff9f7SJohn Marino gomp_mutex_unlock (&thr->ts.work_share->lock);
412*629ff9f7SJohn Marino
413*629ff9f7SJohn Marino return ret;
414*629ff9f7SJohn Marino }
415*629ff9f7SJohn Marino
416*629ff9f7SJohn Marino bool
GOMP_loop_ordered_runtime_next(long * istart,long * iend)417*629ff9f7SJohn Marino GOMP_loop_ordered_runtime_next (long *istart, long *iend)
418*629ff9f7SJohn Marino {
419*629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
420*629ff9f7SJohn Marino
421*629ff9f7SJohn Marino switch (thr->ts.work_share->sched)
422*629ff9f7SJohn Marino {
423*629ff9f7SJohn Marino case GFS_STATIC:
424*629ff9f7SJohn Marino case GFS_AUTO:
425*629ff9f7SJohn Marino return gomp_loop_ordered_static_next (istart, iend);
426*629ff9f7SJohn Marino case GFS_DYNAMIC:
427*629ff9f7SJohn Marino return gomp_loop_ordered_dynamic_next (istart, iend);
428*629ff9f7SJohn Marino case GFS_GUIDED:
429*629ff9f7SJohn Marino return gomp_loop_ordered_guided_next (istart, iend);
430*629ff9f7SJohn Marino default:
431*629ff9f7SJohn Marino abort ();
432*629ff9f7SJohn Marino }
433*629ff9f7SJohn Marino }
434*629ff9f7SJohn Marino
435*629ff9f7SJohn Marino /* The GOMP_parallel_loop_* routines pre-initialize a work-share construct
436*629ff9f7SJohn Marino to avoid one synchronization once we get into the loop. */
437*629ff9f7SJohn Marino
438*629ff9f7SJohn Marino static void
gomp_parallel_loop_start(void (* fn)(void *),void * data,unsigned num_threads,long start,long end,long incr,enum gomp_schedule_type sched,long chunk_size)439*629ff9f7SJohn Marino gomp_parallel_loop_start (void (*fn) (void *), void *data,
440*629ff9f7SJohn Marino unsigned num_threads, long start, long end,
441*629ff9f7SJohn Marino long incr, enum gomp_schedule_type sched,
442*629ff9f7SJohn Marino long chunk_size)
443*629ff9f7SJohn Marino {
444*629ff9f7SJohn Marino struct gomp_team *team;
445*629ff9f7SJohn Marino
446*629ff9f7SJohn Marino num_threads = gomp_resolve_num_threads (num_threads, 0);
447*629ff9f7SJohn Marino team = gomp_new_team (num_threads);
448*629ff9f7SJohn Marino gomp_loop_init (&team->work_shares[0], start, end, incr, sched, chunk_size);
449*629ff9f7SJohn Marino gomp_team_start (fn, data, num_threads, team);
450*629ff9f7SJohn Marino }
451*629ff9f7SJohn Marino
452*629ff9f7SJohn Marino void
GOMP_parallel_loop_static_start(void (* fn)(void *),void * data,unsigned num_threads,long start,long end,long incr,long chunk_size)453*629ff9f7SJohn Marino GOMP_parallel_loop_static_start (void (*fn) (void *), void *data,
454*629ff9f7SJohn Marino unsigned num_threads, long start, long end,
455*629ff9f7SJohn Marino long incr, long chunk_size)
456*629ff9f7SJohn Marino {
457*629ff9f7SJohn Marino gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
458*629ff9f7SJohn Marino GFS_STATIC, chunk_size);
459*629ff9f7SJohn Marino }
460*629ff9f7SJohn Marino
461*629ff9f7SJohn Marino void
GOMP_parallel_loop_dynamic_start(void (* fn)(void *),void * data,unsigned num_threads,long start,long end,long incr,long chunk_size)462*629ff9f7SJohn Marino GOMP_parallel_loop_dynamic_start (void (*fn) (void *), void *data,
463*629ff9f7SJohn Marino unsigned num_threads, long start, long end,
464*629ff9f7SJohn Marino long incr, long chunk_size)
465*629ff9f7SJohn Marino {
466*629ff9f7SJohn Marino gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
467*629ff9f7SJohn Marino GFS_DYNAMIC, chunk_size);
468*629ff9f7SJohn Marino }
469*629ff9f7SJohn Marino
470*629ff9f7SJohn Marino void
GOMP_parallel_loop_guided_start(void (* fn)(void *),void * data,unsigned num_threads,long start,long end,long incr,long chunk_size)471*629ff9f7SJohn Marino GOMP_parallel_loop_guided_start (void (*fn) (void *), void *data,
472*629ff9f7SJohn Marino unsigned num_threads, long start, long end,
473*629ff9f7SJohn Marino long incr, long chunk_size)
474*629ff9f7SJohn Marino {
475*629ff9f7SJohn Marino gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
476*629ff9f7SJohn Marino GFS_GUIDED, chunk_size);
477*629ff9f7SJohn Marino }
478*629ff9f7SJohn Marino
479*629ff9f7SJohn Marino void
GOMP_parallel_loop_runtime_start(void (* fn)(void *),void * data,unsigned num_threads,long start,long end,long incr)480*629ff9f7SJohn Marino GOMP_parallel_loop_runtime_start (void (*fn) (void *), void *data,
481*629ff9f7SJohn Marino unsigned num_threads, long start, long end,
482*629ff9f7SJohn Marino long incr)
483*629ff9f7SJohn Marino {
484*629ff9f7SJohn Marino struct gomp_task_icv *icv = gomp_icv (false);
485*629ff9f7SJohn Marino gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
486*629ff9f7SJohn Marino icv->run_sched_var, icv->run_sched_modifier);
487*629ff9f7SJohn Marino }
488*629ff9f7SJohn Marino
489*629ff9f7SJohn Marino /* The GOMP_loop_end* routines are called after the thread is told that
490*629ff9f7SJohn Marino all loop iterations are complete. This first version synchronizes
491*629ff9f7SJohn Marino all threads; the nowait version does not. */
492*629ff9f7SJohn Marino
493*629ff9f7SJohn Marino void
GOMP_loop_end(void)494*629ff9f7SJohn Marino GOMP_loop_end (void)
495*629ff9f7SJohn Marino {
496*629ff9f7SJohn Marino gomp_work_share_end ();
497*629ff9f7SJohn Marino }
498*629ff9f7SJohn Marino
499*629ff9f7SJohn Marino void
GOMP_loop_end_nowait(void)500*629ff9f7SJohn Marino GOMP_loop_end_nowait (void)
501*629ff9f7SJohn Marino {
502*629ff9f7SJohn Marino gomp_work_share_end_nowait ();
503*629ff9f7SJohn Marino }
504*629ff9f7SJohn Marino
505*629ff9f7SJohn Marino
506*629ff9f7SJohn Marino /* We use static functions above so that we're sure that the "runtime"
507*629ff9f7SJohn Marino function can defer to the proper routine without interposition. We
508*629ff9f7SJohn Marino export the static function with a strong alias when possible, or with
509*629ff9f7SJohn Marino a wrapper function otherwise. */
510*629ff9f7SJohn Marino
511*629ff9f7SJohn Marino #ifdef HAVE_ATTRIBUTE_ALIAS
512*629ff9f7SJohn Marino extern __typeof(gomp_loop_static_start) GOMP_loop_static_start
513*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_static_start")));
514*629ff9f7SJohn Marino extern __typeof(gomp_loop_dynamic_start) GOMP_loop_dynamic_start
515*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_dynamic_start")));
516*629ff9f7SJohn Marino extern __typeof(gomp_loop_guided_start) GOMP_loop_guided_start
517*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_guided_start")));
518*629ff9f7SJohn Marino
519*629ff9f7SJohn Marino extern __typeof(gomp_loop_ordered_static_start) GOMP_loop_ordered_static_start
520*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_ordered_static_start")));
521*629ff9f7SJohn Marino extern __typeof(gomp_loop_ordered_dynamic_start) GOMP_loop_ordered_dynamic_start
522*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_ordered_dynamic_start")));
523*629ff9f7SJohn Marino extern __typeof(gomp_loop_ordered_guided_start) GOMP_loop_ordered_guided_start
524*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_ordered_guided_start")));
525*629ff9f7SJohn Marino
526*629ff9f7SJohn Marino extern __typeof(gomp_loop_static_next) GOMP_loop_static_next
527*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_static_next")));
528*629ff9f7SJohn Marino extern __typeof(gomp_loop_dynamic_next) GOMP_loop_dynamic_next
529*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_dynamic_next")));
530*629ff9f7SJohn Marino extern __typeof(gomp_loop_guided_next) GOMP_loop_guided_next
531*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_guided_next")));
532*629ff9f7SJohn Marino
533*629ff9f7SJohn Marino extern __typeof(gomp_loop_ordered_static_next) GOMP_loop_ordered_static_next
534*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_ordered_static_next")));
535*629ff9f7SJohn Marino extern __typeof(gomp_loop_ordered_dynamic_next) GOMP_loop_ordered_dynamic_next
536*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_ordered_dynamic_next")));
537*629ff9f7SJohn Marino extern __typeof(gomp_loop_ordered_guided_next) GOMP_loop_ordered_guided_next
538*629ff9f7SJohn Marino __attribute__((alias ("gomp_loop_ordered_guided_next")));
539*629ff9f7SJohn Marino #else
540*629ff9f7SJohn Marino bool
GOMP_loop_static_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)541*629ff9f7SJohn Marino GOMP_loop_static_start (long start, long end, long incr, long chunk_size,
542*629ff9f7SJohn Marino long *istart, long *iend)
543*629ff9f7SJohn Marino {
544*629ff9f7SJohn Marino return gomp_loop_static_start (start, end, incr, chunk_size, istart, iend);
545*629ff9f7SJohn Marino }
546*629ff9f7SJohn Marino
547*629ff9f7SJohn Marino bool
GOMP_loop_dynamic_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)548*629ff9f7SJohn Marino GOMP_loop_dynamic_start (long start, long end, long incr, long chunk_size,
549*629ff9f7SJohn Marino long *istart, long *iend)
550*629ff9f7SJohn Marino {
551*629ff9f7SJohn Marino return gomp_loop_dynamic_start (start, end, incr, chunk_size, istart, iend);
552*629ff9f7SJohn Marino }
553*629ff9f7SJohn Marino
554*629ff9f7SJohn Marino bool
GOMP_loop_guided_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)555*629ff9f7SJohn Marino GOMP_loop_guided_start (long start, long end, long incr, long chunk_size,
556*629ff9f7SJohn Marino long *istart, long *iend)
557*629ff9f7SJohn Marino {
558*629ff9f7SJohn Marino return gomp_loop_guided_start (start, end, incr, chunk_size, istart, iend);
559*629ff9f7SJohn Marino }
560*629ff9f7SJohn Marino
561*629ff9f7SJohn Marino bool
GOMP_loop_ordered_static_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)562*629ff9f7SJohn Marino GOMP_loop_ordered_static_start (long start, long end, long incr,
563*629ff9f7SJohn Marino long chunk_size, long *istart, long *iend)
564*629ff9f7SJohn Marino {
565*629ff9f7SJohn Marino return gomp_loop_ordered_static_start (start, end, incr, chunk_size,
566*629ff9f7SJohn Marino istart, iend);
567*629ff9f7SJohn Marino }
568*629ff9f7SJohn Marino
569*629ff9f7SJohn Marino bool
GOMP_loop_ordered_dynamic_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)570*629ff9f7SJohn Marino GOMP_loop_ordered_dynamic_start (long start, long end, long incr,
571*629ff9f7SJohn Marino long chunk_size, long *istart, long *iend)
572*629ff9f7SJohn Marino {
573*629ff9f7SJohn Marino return gomp_loop_ordered_dynamic_start (start, end, incr, chunk_size,
574*629ff9f7SJohn Marino istart, iend);
575*629ff9f7SJohn Marino }
576*629ff9f7SJohn Marino
577*629ff9f7SJohn Marino bool
GOMP_loop_ordered_guided_start(long start,long end,long incr,long chunk_size,long * istart,long * iend)578*629ff9f7SJohn Marino GOMP_loop_ordered_guided_start (long start, long end, long incr,
579*629ff9f7SJohn Marino long chunk_size, long *istart, long *iend)
580*629ff9f7SJohn Marino {
581*629ff9f7SJohn Marino return gomp_loop_ordered_guided_start (start, end, incr, chunk_size,
582*629ff9f7SJohn Marino istart, iend);
583*629ff9f7SJohn Marino }
584*629ff9f7SJohn Marino
585*629ff9f7SJohn Marino bool
GOMP_loop_static_next(long * istart,long * iend)586*629ff9f7SJohn Marino GOMP_loop_static_next (long *istart, long *iend)
587*629ff9f7SJohn Marino {
588*629ff9f7SJohn Marino return gomp_loop_static_next (istart, iend);
589*629ff9f7SJohn Marino }
590*629ff9f7SJohn Marino
591*629ff9f7SJohn Marino bool
GOMP_loop_dynamic_next(long * istart,long * iend)592*629ff9f7SJohn Marino GOMP_loop_dynamic_next (long *istart, long *iend)
593*629ff9f7SJohn Marino {
594*629ff9f7SJohn Marino return gomp_loop_dynamic_next (istart, iend);
595*629ff9f7SJohn Marino }
596*629ff9f7SJohn Marino
597*629ff9f7SJohn Marino bool
GOMP_loop_guided_next(long * istart,long * iend)598*629ff9f7SJohn Marino GOMP_loop_guided_next (long *istart, long *iend)
599*629ff9f7SJohn Marino {
600*629ff9f7SJohn Marino return gomp_loop_guided_next (istart, iend);
601*629ff9f7SJohn Marino }
602*629ff9f7SJohn Marino
603*629ff9f7SJohn Marino bool
GOMP_loop_ordered_static_next(long * istart,long * iend)604*629ff9f7SJohn Marino GOMP_loop_ordered_static_next (long *istart, long *iend)
605*629ff9f7SJohn Marino {
606*629ff9f7SJohn Marino return gomp_loop_ordered_static_next (istart, iend);
607*629ff9f7SJohn Marino }
608*629ff9f7SJohn Marino
609*629ff9f7SJohn Marino bool
GOMP_loop_ordered_dynamic_next(long * istart,long * iend)610*629ff9f7SJohn Marino GOMP_loop_ordered_dynamic_next (long *istart, long *iend)
611*629ff9f7SJohn Marino {
612*629ff9f7SJohn Marino return gomp_loop_ordered_dynamic_next (istart, iend);
613*629ff9f7SJohn Marino }
614*629ff9f7SJohn Marino
615*629ff9f7SJohn Marino bool
GOMP_loop_ordered_guided_next(long * istart,long * iend)616*629ff9f7SJohn Marino GOMP_loop_ordered_guided_next (long *istart, long *iend)
617*629ff9f7SJohn Marino {
618*629ff9f7SJohn Marino return gomp_loop_ordered_guided_next (istart, iend);
619*629ff9f7SJohn Marino }
620*629ff9f7SJohn Marino #endif
621