1 /* Copyright (C) 2005 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
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
13 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
16 You should have received a copy of the GNU Lesser General Public License
17 along with libgomp; see the file COPYING.LIB. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 /* As a special exception, if you link this library with other files, some
22 of which are compiled with GCC, to produce an executable, this library
23 does not by itself cause the resulting executable to be covered by the
24 GNU General Public License. This exception does not however invalidate
25 any other reasons why the executable file might be covered by the GNU
26 General Public License. */
28 /* This file handles the LOOP (FOR/DO) construct. */
34 /* Initialize the given work share construct from the given arguments. */
37 gomp_loop_init (struct gomp_work_share
*ws
, long start
, long end
, long incr
,
38 enum gomp_schedule_type sched
, long chunk_size
)
41 ws
->chunk_size
= chunk_size
;
42 /* Canonicalize loops that have zero iterations to ->next == ->end. */
43 ws
->end
= ((incr
> 0 && start
> end
) || (incr
< 0 && start
< end
))
49 /* The *_start routines are called when first encountering a loop construct
50 that is not bound directly to a parallel construct. The first thread
51 that arrives will create the work-share construct; subsequent threads
52 will see the construct exists and allocate work from it.
54 START, END, INCR are the bounds of the loop; due to the restrictions of
55 OpenMP, these values must be the same in every thread. This is not
56 verified (nor is it entirely verifiable, since START is not necessarily
57 retained intact in the work-share data structure). CHUNK_SIZE is the
58 scheduling parameter; again this must be identical in all threads.
60 Returns true if there's any work for this thread to perform. If so,
61 *ISTART and *IEND are filled with the bounds of the iteration block
62 allocated to this thread. Returns false if all work was assigned to
63 other threads prior to this thread's arrival. */
66 gomp_loop_static_start (long start
, long end
, long incr
, long chunk_size
,
67 long *istart
, long *iend
)
69 struct gomp_thread
*thr
= gomp_thread ();
71 if (gomp_work_share_start (false))
72 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
73 GFS_STATIC
, chunk_size
);
74 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
76 return !gomp_iter_static_next (istart
, iend
);
80 gomp_loop_dynamic_start (long start
, long end
, long incr
, long chunk_size
,
81 long *istart
, long *iend
)
83 struct gomp_thread
*thr
= gomp_thread ();
86 if (gomp_work_share_start (false))
87 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
88 GFS_DYNAMIC
, chunk_size
);
90 #ifdef HAVE_SYNC_BUILTINS
91 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
92 ret
= gomp_iter_dynamic_next (istart
, iend
);
94 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
95 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
102 gomp_loop_guided_start (long start
, long end
, long incr
, long chunk_size
,
103 long *istart
, long *iend
)
105 struct gomp_thread
*thr
= gomp_thread ();
108 if (gomp_work_share_start (false))
109 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
110 GFS_GUIDED
, chunk_size
);
112 #ifdef HAVE_SYNC_BUILTINS
113 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
114 ret
= gomp_iter_guided_next (istart
, iend
);
116 ret
= gomp_iter_guided_next_locked (istart
, iend
);
117 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
124 GOMP_loop_runtime_start (long start
, long end
, long incr
,
125 long *istart
, long *iend
)
127 switch (gomp_run_sched_var
)
130 return gomp_loop_static_start (start
, end
, incr
, gomp_run_sched_chunk
,
133 return gomp_loop_dynamic_start (start
, end
, incr
, gomp_run_sched_chunk
,
136 return gomp_loop_guided_start (start
, end
, incr
, gomp_run_sched_chunk
,
143 /* The *_ordered_*_start routines are similar. The only difference is that
144 this work-share construct is initialized to expect an ORDERED section. */
147 gomp_loop_ordered_static_start (long start
, long end
, long incr
,
148 long chunk_size
, long *istart
, long *iend
)
150 struct gomp_thread
*thr
= gomp_thread ();
152 if (gomp_work_share_start (true))
154 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
155 GFS_STATIC
, chunk_size
);
156 gomp_ordered_static_init ();
158 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
160 return !gomp_iter_static_next (istart
, iend
);
164 gomp_loop_ordered_dynamic_start (long start
, long end
, long incr
,
165 long chunk_size
, long *istart
, long *iend
)
167 struct gomp_thread
*thr
= gomp_thread ();
170 if (gomp_work_share_start (true))
171 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
172 GFS_DYNAMIC
, chunk_size
);
174 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
176 gomp_ordered_first ();
177 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
183 gomp_loop_ordered_guided_start (long start
, long end
, long incr
,
184 long chunk_size
, long *istart
, long *iend
)
186 struct gomp_thread
*thr
= gomp_thread ();
189 if (gomp_work_share_start (true))
190 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
191 GFS_GUIDED
, chunk_size
);
193 ret
= gomp_iter_guided_next_locked (istart
, iend
);
195 gomp_ordered_first ();
196 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
202 GOMP_loop_ordered_runtime_start (long start
, long end
, long incr
,
203 long *istart
, long *iend
)
205 switch (gomp_run_sched_var
)
208 return gomp_loop_ordered_static_start (start
, end
, incr
,
209 gomp_run_sched_chunk
,
212 return gomp_loop_ordered_dynamic_start (start
, end
, incr
,
213 gomp_run_sched_chunk
,
216 return gomp_loop_ordered_guided_start (start
, end
, incr
,
217 gomp_run_sched_chunk
,
224 /* The *_next routines are called when the thread completes processing of
225 the iteration block currently assigned to it. If the work-share
226 construct is bound directly to a parallel construct, then the iteration
227 bounds may have been set up before the parallel. In which case, this
228 may be the first iteration for the thread.
230 Returns true if there is work remaining to be performed; *ISTART and
231 *IEND are filled with a new iteration block. Returns false if all work
232 has been assigned. */
235 gomp_loop_static_next (long *istart
, long *iend
)
237 return !gomp_iter_static_next (istart
, iend
);
241 gomp_loop_dynamic_next (long *istart
, long *iend
)
245 #ifdef HAVE_SYNC_BUILTINS
246 ret
= gomp_iter_dynamic_next (istart
, iend
);
248 struct gomp_thread
*thr
= gomp_thread ();
249 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
250 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
251 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
258 gomp_loop_guided_next (long *istart
, long *iend
)
262 #ifdef HAVE_SYNC_BUILTINS
263 ret
= gomp_iter_guided_next (istart
, iend
);
265 struct gomp_thread
*thr
= gomp_thread ();
266 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
267 ret
= gomp_iter_guided_next_locked (istart
, iend
);
268 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
275 GOMP_loop_runtime_next (long *istart
, long *iend
)
277 struct gomp_thread
*thr
= gomp_thread ();
279 switch (thr
->ts
.work_share
->sched
)
282 return gomp_loop_static_next (istart
, iend
);
284 return gomp_loop_dynamic_next (istart
, iend
);
286 return gomp_loop_guided_next (istart
, iend
);
292 /* The *_ordered_*_next routines are called when the thread completes
293 processing of the iteration block currently assigned to it.
295 Returns true if there is work remaining to be performed; *ISTART and
296 *IEND are filled with a new iteration block. Returns false if all work
297 has been assigned. */
300 gomp_loop_ordered_static_next (long *istart
, long *iend
)
302 struct gomp_thread
*thr
= gomp_thread ();
305 gomp_ordered_sync ();
306 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
307 test
= gomp_iter_static_next (istart
, iend
);
309 gomp_ordered_static_next ();
310 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
316 gomp_loop_ordered_dynamic_next (long *istart
, long *iend
)
318 struct gomp_thread
*thr
= gomp_thread ();
321 gomp_ordered_sync ();
322 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
323 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
325 gomp_ordered_next ();
327 gomp_ordered_last ();
328 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
334 gomp_loop_ordered_guided_next (long *istart
, long *iend
)
336 struct gomp_thread
*thr
= gomp_thread ();
339 gomp_ordered_sync ();
340 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
341 ret
= gomp_iter_guided_next_locked (istart
, iend
);
343 gomp_ordered_next ();
345 gomp_ordered_last ();
346 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
352 GOMP_loop_ordered_runtime_next (long *istart
, long *iend
)
354 struct gomp_thread
*thr
= gomp_thread ();
356 switch (thr
->ts
.work_share
->sched
)
359 return gomp_loop_ordered_static_next (istart
, iend
);
361 return gomp_loop_ordered_dynamic_next (istart
, iend
);
363 return gomp_loop_ordered_guided_next (istart
, iend
);
369 /* The GOMP_parallel_loop_* routines pre-initialize a work-share construct
370 to avoid one synchronization once we get into the loop. */
373 gomp_parallel_loop_start (void (*fn
) (void *), void *data
,
374 unsigned num_threads
, long start
, long end
,
375 long incr
, enum gomp_schedule_type sched
,
378 struct gomp_work_share
*ws
;
380 num_threads
= gomp_resolve_num_threads (num_threads
);
381 ws
= gomp_new_work_share (false, num_threads
);
382 gomp_loop_init (ws
, start
, end
, incr
, sched
, chunk_size
);
383 gomp_team_start (fn
, data
, num_threads
, ws
);
387 GOMP_parallel_loop_static_start (void (*fn
) (void *), void *data
,
388 unsigned num_threads
, long start
, long end
,
389 long incr
, long chunk_size
)
391 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
392 GFS_STATIC
, chunk_size
);
396 GOMP_parallel_loop_dynamic_start (void (*fn
) (void *), void *data
,
397 unsigned num_threads
, long start
, long end
,
398 long incr
, long chunk_size
)
400 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
401 GFS_DYNAMIC
, chunk_size
);
405 GOMP_parallel_loop_guided_start (void (*fn
) (void *), void *data
,
406 unsigned num_threads
, long start
, long end
,
407 long incr
, long chunk_size
)
409 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
410 GFS_GUIDED
, chunk_size
);
414 GOMP_parallel_loop_runtime_start (void (*fn
) (void *), void *data
,
415 unsigned num_threads
, long start
, long end
,
418 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
419 gomp_run_sched_var
, gomp_run_sched_chunk
);
422 /* The GOMP_loop_end* routines are called after the thread is told that
423 all loop iterations are complete. This first version synchronizes
424 all threads; the nowait version does not. */
429 gomp_work_share_end ();
433 GOMP_loop_end_nowait (void)
435 gomp_work_share_end_nowait ();
439 /* We use static functions above so that we're sure that the "runtime"
440 function can defer to the proper routine without interposition. We
441 export the static function with a strong alias when possible, or with
442 a wrapper function otherwise. */
444 #ifdef HAVE_ATTRIBUTE_ALIAS
445 extern __typeof(gomp_loop_static_start
) GOMP_loop_static_start
446 __attribute__((alias ("gomp_loop_static_start")));
447 extern __typeof(gomp_loop_dynamic_start
) GOMP_loop_dynamic_start
448 __attribute__((alias ("gomp_loop_dynamic_start")));
449 extern __typeof(gomp_loop_guided_start
) GOMP_loop_guided_start
450 __attribute__((alias ("gomp_loop_guided_start")));
452 extern __typeof(gomp_loop_ordered_static_start
) GOMP_loop_ordered_static_start
453 __attribute__((alias ("gomp_loop_ordered_static_start")));
454 extern __typeof(gomp_loop_ordered_dynamic_start
) GOMP_loop_ordered_dynamic_start
455 __attribute__((alias ("gomp_loop_ordered_dynamic_start")));
456 extern __typeof(gomp_loop_ordered_guided_start
) GOMP_loop_ordered_guided_start
457 __attribute__((alias ("gomp_loop_ordered_guided_start")));
459 extern __typeof(gomp_loop_static_next
) GOMP_loop_static_next
460 __attribute__((alias ("gomp_loop_static_next")));
461 extern __typeof(gomp_loop_dynamic_next
) GOMP_loop_dynamic_next
462 __attribute__((alias ("gomp_loop_dynamic_next")));
463 extern __typeof(gomp_loop_guided_next
) GOMP_loop_guided_next
464 __attribute__((alias ("gomp_loop_guided_next")));
466 extern __typeof(gomp_loop_ordered_static_next
) GOMP_loop_ordered_static_next
467 __attribute__((alias ("gomp_loop_ordered_static_next")));
468 extern __typeof(gomp_loop_ordered_dynamic_next
) GOMP_loop_ordered_dynamic_next
469 __attribute__((alias ("gomp_loop_ordered_dynamic_next")));
470 extern __typeof(gomp_loop_ordered_guided_next
) GOMP_loop_ordered_guided_next
471 __attribute__((alias ("gomp_loop_ordered_guided_next")));
474 GOMP_loop_static_start (long start
, long end
, long incr
, long chunk_size
,
475 long *istart
, long *iend
)
477 return gomp_loop_static_start (start
, end
, incr
, chunk_size
, istart
, iend
);
481 GOMP_loop_dynamic_start (long start
, long end
, long incr
, long chunk_size
,
482 long *istart
, long *iend
)
484 return gomp_loop_dynamic_start (start
, end
, incr
, chunk_size
, istart
, iend
);
488 GOMP_loop_guided_start (long start
, long end
, long incr
, long chunk_size
,
489 long *istart
, long *iend
)
491 return gomp_loop_guided_start (start
, end
, incr
, chunk_size
, istart
, iend
);
495 GOMP_loop_ordered_static_start (long start
, long end
, long incr
,
496 long chunk_size
, long *istart
, long *iend
)
498 return gomp_loop_ordered_static_start (start
, end
, incr
, chunk_size
,
503 GOMP_loop_ordered_dynamic_start (long start
, long end
, long incr
,
504 long chunk_size
, long *istart
, long *iend
)
506 return gomp_loop_ordered_dynamic_start (start
, end
, incr
, chunk_size
,
511 GOMP_loop_ordered_guided_start (long start
, long end
, long incr
,
512 long chunk_size
, long *istart
, long *iend
)
514 return gomp_loop_ordered_guided_start (start
, end
, incr
, chunk_size
,
519 GOMP_loop_static_next (long *istart
, long *iend
)
521 return gomp_loop_static_next (istart
, iend
);
525 GOMP_loop_dynamic_next (long *istart
, long *iend
)
527 return gomp_loop_dynamic_next (istart
, iend
);
531 GOMP_loop_guided_next (long *istart
, long *iend
)
533 return gomp_loop_guided_next (istart
, iend
);
537 GOMP_loop_ordered_static_next (long *istart
, long *iend
)
539 return gomp_loop_ordered_static_next (istart
, iend
);
543 GOMP_loop_ordered_dynamic_next (long *istart
, long *iend
)
545 return gomp_loop_ordered_dynamic_next (istart
, iend
);
549 GOMP_loop_ordered_guided_next (long *istart
, long *iend
)
551 return gomp_loop_ordered_guided_next (istart
, iend
);