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