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
, unsigned long start
,
38 unsigned long end
, unsigned long incr
,
39 enum gomp_schedule_type sched
, unsigned long chunk_size
)
42 ws
->chunk_size
= chunk_size
;
48 /* The *_start routines are called when first encountering a loop construct
49 that is not bound directly to a parallel construct. The first thread
50 that arrives will create the work-share construct; subsequent threads
51 will see the construct exists and allocate work from it.
53 START, END, INCR are the bounds of the loop; due to the restrictions of
54 OpenMP, these values must be the same in every thread. This is not
55 verified (nor is it entirely verifiable, since START is not necessarily
56 retained intact in the work-share data structure). CHUNK_SIZE is the
57 scheduling parameter; again this must be identical in all threads.
59 Returns true if there's any work for this thread to perform. If so,
60 *ISTART and *IEND are filled with the bounds of the iteration block
61 allocated to this thread. Returns false if all work was assigned to
62 other threads prior to this thread's arrival. */
65 gomp_loop_static_start (long start
, long end
, long incr
, long chunk_size
,
66 long *istart
, long *iend
)
68 struct gomp_thread
*thr
= gomp_thread ();
70 if (gomp_work_share_start (false))
71 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
72 GFS_STATIC
, chunk_size
);
73 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
75 return !gomp_iter_static_next (istart
, iend
);
79 gomp_loop_dynamic_start (long start
, long end
, long incr
, long chunk_size
,
80 long *istart
, long *iend
)
82 struct gomp_thread
*thr
= gomp_thread ();
85 if (gomp_work_share_start (false))
86 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
87 GFS_DYNAMIC
, chunk_size
);
89 #ifdef HAVE_SYNC_BUILTINS
90 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
91 ret
= gomp_iter_dynamic_next (istart
, iend
);
93 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
94 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
101 gomp_loop_guided_start (long start
, long end
, long incr
, long chunk_size
,
102 long *istart
, long *iend
)
104 struct gomp_thread
*thr
= gomp_thread ();
107 if (gomp_work_share_start (false))
108 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
109 GFS_GUIDED
, chunk_size
);
111 #ifdef HAVE_SYNC_BUILTINS
112 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
113 ret
= gomp_iter_guided_next (istart
, iend
);
115 ret
= gomp_iter_guided_next_locked (istart
, iend
);
116 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
123 GOMP_loop_runtime_start (long start
, long end
, long incr
,
124 long *istart
, long *iend
)
126 switch (gomp_run_sched_var
)
129 return gomp_loop_static_start (start
, end
, incr
, gomp_run_sched_chunk
,
132 return gomp_loop_dynamic_start (start
, end
, incr
, gomp_run_sched_chunk
,
135 return gomp_loop_guided_start (start
, end
, incr
, gomp_run_sched_chunk
,
142 /* The *_ordered_*_start routines are similar. The only difference is that
143 this work-share construct is initialized to expect an ORDERED section. */
146 gomp_loop_ordered_static_start (long start
, long end
, long incr
,
147 long chunk_size
, long *istart
, long *iend
)
149 struct gomp_thread
*thr
= gomp_thread ();
154 if (gomp_work_share_start (true))
156 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
157 GFS_STATIC
, chunk_size
);
158 gomp_ordered_static_init ();
160 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
162 return !gomp_iter_static_next (istart
, iend
);
166 gomp_loop_ordered_dynamic_start (long start
, long end
, long incr
,
167 long chunk_size
, long *istart
, long *iend
)
169 struct gomp_thread
*thr
= gomp_thread ();
172 if (gomp_work_share_start (true))
173 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
174 GFS_DYNAMIC
, chunk_size
);
176 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
178 gomp_ordered_first ();
179 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
185 gomp_loop_ordered_guided_start (long start
, long end
, long incr
,
186 long chunk_size
, long *istart
, long *iend
)
188 struct gomp_thread
*thr
= gomp_thread ();
191 if (gomp_work_share_start (true))
192 gomp_loop_init (thr
->ts
.work_share
, start
, end
, incr
,
193 GFS_GUIDED
, chunk_size
);
195 ret
= gomp_iter_guided_next_locked (istart
, iend
);
197 gomp_ordered_first ();
198 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
204 GOMP_loop_ordered_runtime_start (long start
, long end
, long incr
,
205 long *istart
, long *iend
)
207 switch (gomp_run_sched_var
)
210 return gomp_loop_ordered_static_start (start
, end
, incr
,
211 gomp_run_sched_chunk
,
214 return gomp_loop_ordered_dynamic_start (start
, end
, incr
,
215 gomp_run_sched_chunk
,
218 return gomp_loop_ordered_guided_start (start
, end
, incr
,
219 gomp_run_sched_chunk
,
226 /* The *_next routines are called when the thread completes processing of
227 the iteration block currently assigned to it. If the work-share
228 construct is bound directly to a parallel construct, then the iteration
229 bounds may have been set up before the parallel. In which case, this
230 may be the first iteration for the thread.
232 Returns true if there is work remaining to be performed; *ISTART and
233 *IEND are filled with a new iteration block. Returns false if all work
234 has been assigned. */
237 gomp_loop_static_next (long *istart
, long *iend
)
239 return !gomp_iter_static_next (istart
, iend
);
243 gomp_loop_dynamic_next (long *istart
, long *iend
)
247 #ifdef HAVE_SYNC_BUILTINS
248 ret
= gomp_iter_dynamic_next (istart
, iend
);
250 struct gomp_thread
*thr
= gomp_thread ();
251 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
252 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
253 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
260 gomp_loop_guided_next (long *istart
, long *iend
)
264 #ifdef HAVE_SYNC_BUILTINS
265 ret
= gomp_iter_guided_next (istart
, iend
);
267 struct gomp_thread
*thr
= gomp_thread ();
268 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
269 ret
= gomp_iter_guided_next_locked (istart
, iend
);
270 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
277 GOMP_loop_runtime_next (long *istart
, long *iend
)
279 struct gomp_thread
*thr
= gomp_thread ();
281 switch (thr
->ts
.work_share
->sched
)
284 return gomp_loop_static_next (istart
, iend
);
286 return gomp_loop_dynamic_next (istart
, iend
);
288 return gomp_loop_guided_next (istart
, iend
);
294 /* The *_ordered_*_next routines are called when the thread completes
295 processing of the iteration block currently assigned to it.
297 Returns true if there is work remaining to be performed; *ISTART and
298 *IEND are filled with a new iteration block. Returns false if all work
299 has been assigned. */
302 gomp_loop_ordered_static_next (long *istart
, long *iend
)
304 struct gomp_thread
*thr
= gomp_thread ();
307 gomp_ordered_sync ();
308 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
309 test
= gomp_iter_static_next (istart
, iend
);
311 gomp_ordered_static_next ();
312 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
318 gomp_loop_ordered_dynamic_next (long *istart
, long *iend
)
320 struct gomp_thread
*thr
= gomp_thread ();
323 gomp_ordered_sync ();
324 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
325 ret
= gomp_iter_dynamic_next_locked (istart
, iend
);
327 gomp_ordered_next ();
329 gomp_ordered_last ();
330 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
336 gomp_loop_ordered_guided_next (long *istart
, long *iend
)
338 struct gomp_thread
*thr
= gomp_thread ();
341 gomp_ordered_sync ();
342 gomp_mutex_lock (&thr
->ts
.work_share
->lock
);
343 ret
= gomp_iter_guided_next_locked (istart
, iend
);
345 gomp_ordered_next ();
347 gomp_ordered_last ();
348 gomp_mutex_unlock (&thr
->ts
.work_share
->lock
);
354 GOMP_loop_ordered_runtime_next (long *istart
, long *iend
)
356 struct gomp_thread
*thr
= gomp_thread ();
358 switch (thr
->ts
.work_share
->sched
)
361 return gomp_loop_ordered_static_next (istart
, iend
);
363 return gomp_loop_ordered_dynamic_next (istart
, iend
);
365 return gomp_loop_ordered_guided_next (istart
, iend
);
371 /* The GOMP_parallel_loop_* routines pre-initialize a work-share construct
372 to avoid one synchronization once we get into the loop. */
375 gomp_parallel_loop_start (void (*fn
) (void *), void *data
,
376 unsigned num_threads
, long start
, long end
,
377 long incr
, enum gomp_schedule_type sched
,
380 struct gomp_work_share
*ws
;
382 num_threads
= gomp_resolve_num_threads (num_threads
);
383 ws
= gomp_new_work_share (false, num_threads
);
384 gomp_loop_init (ws
, start
, end
, incr
, sched
, chunk_size
);
385 gomp_team_start (fn
, data
, num_threads
, ws
);
389 GOMP_parallel_loop_static_start (void (*fn
) (void *), void *data
,
390 unsigned num_threads
, long start
, long end
,
391 long incr
, long chunk_size
)
393 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
394 GFS_STATIC
, chunk_size
);
398 GOMP_parallel_loop_dynamic_start (void (*fn
) (void *), void *data
,
399 unsigned num_threads
, long start
, long end
,
400 long incr
, long chunk_size
)
402 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
403 GFS_DYNAMIC
, chunk_size
);
407 GOMP_parallel_loop_guided_start (void (*fn
) (void *), void *data
,
408 unsigned num_threads
, long start
, long end
,
409 long incr
, long chunk_size
)
411 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
412 GFS_GUIDED
, chunk_size
);
416 GOMP_parallel_loop_runtime_start (void (*fn
) (void *), void *data
,
417 unsigned num_threads
, long start
, long end
,
420 gomp_parallel_loop_start (fn
, data
, num_threads
, start
, end
, incr
,
421 gomp_run_sched_var
, gomp_run_sched_chunk
);
424 /* The GOMP_loop_end* routines are called after the thread is told that
425 all loop iterations are complete. This first version synchronizes
426 all threads; the nowait version does not. */
431 gomp_work_share_end ();
435 GOMP_loop_end_nowait (void)
437 gomp_work_share_end_nowait ();
441 /* We use static functions above so that we're sure that the "runtime"
442 function can defer to the proper routine without interposition. We
443 export the static function with a strong alias when possible, or with
444 a wrapper function otherwise. */
446 #ifdef HAVE_ATTRIBUTE_ALIAS
447 extern __typeof(gomp_loop_static_start
) GOMP_loop_static_start
448 __attribute__((alias ("gomp_loop_static_start")));
449 extern __typeof(gomp_loop_dynamic_start
) GOMP_loop_dynamic_start
450 __attribute__((alias ("gomp_loop_dynamic_start")));
451 extern __typeof(gomp_loop_guided_start
) GOMP_loop_guided_start
452 __attribute__((alias ("gomp_loop_guided_start")));
454 extern __typeof(gomp_loop_ordered_static_start
) GOMP_loop_ordered_static_start
455 __attribute__((alias ("gomp_loop_ordered_static_start")));
456 extern __typeof(gomp_loop_ordered_dynamic_start
) GOMP_loop_ordered_dynamic_start
457 __attribute__((alias ("gomp_loop_ordered_dynamic_start")));
458 extern __typeof(gomp_loop_ordered_guided_start
) GOMP_loop_ordered_guided_start
459 __attribute__((alias ("gomp_loop_ordered_guided_start")));
461 extern __typeof(gomp_loop_static_next
) GOMP_loop_static_next
462 __attribute__((alias ("gomp_loop_static_next")));
463 extern __typeof(gomp_loop_dynamic_next
) GOMP_loop_dynamic_next
464 __attribute__((alias ("gomp_loop_dynamic_next")));
465 extern __typeof(gomp_loop_guided_next
) GOMP_loop_guided_next
466 __attribute__((alias ("gomp_loop_guided_next")));
468 extern __typeof(gomp_loop_ordered_static_next
) GOMP_loop_ordered_static_next
469 __attribute__((alias ("gomp_loop_ordered_static_next")));
470 extern __typeof(gomp_loop_ordered_dynamic_next
) GOMP_loop_ordered_dynamic_next
471 __attribute__((alias ("gomp_loop_ordered_dynamic_next")));
472 extern __typeof(gomp_loop_ordered_guided_next
) GOMP_loop_ordered_guided_next
473 __attribute__((alias ("gomp_loop_ordered_guided_next")));
476 GOMP_loop_static_start (long start
, long end
, long incr
, long chunk_size
,
477 long *istart
, long *iend
)
479 return gomp_loop_static_start (start
, end
, incr
, chunk_size
, istart
, iend
);
483 GOMP_loop_dynamic_start (long start
, long end
, long incr
, long chunk_size
,
484 long *istart
, long *iend
)
486 return gomp_loop_dynamic_start (start
, end
, incr
, chunk_size
, istart
, iend
);
490 GOMP_loop_guided_start (long start
, long end
, long incr
, long chunk_size
,
491 long *istart
, long *iend
)
493 return gomp_loop_guided_start (start
, end
, incr
, chunk_size
, istart
, iend
);
497 GOMP_loop_ordered_static_start (long start
, long end
, long incr
,
498 long chunk_size
, long *istart
, long *iend
)
500 return gomp_loop_ordered_static_start (start
, end
, incr
, chunk_size
,
505 GOMP_loop_ordered_dynamic_start (long start
, long end
, long incr
,
506 long chunk_size
, long *istart
, long *iend
)
508 return gomp_loop_ordered_dynamic_start (start
, end
, incr
, chunk_size
,
513 GOMP_loop_ordered_guided_start (long start
, long end
, long incr
,
514 long chunk_size
, long *istart
, long *iend
)
516 return gomp_loop_ordered_guided_start (start
, end
, incr
, chunk_size
,
521 GOMP_loop_static_next (long *istart
, long *iend
)
523 return gomp_loop_static_next (istart
, iend
);
527 GOMP_loop_dynamic_next (long *istart
, long *iend
)
529 return gomp_loop_dynamic_next (istart
, iend
);
533 GOMP_loop_guided_next (long *istart
, long *iend
)
535 return gomp_loop_guided_next (istart
, iend
);
539 GOMP_loop_ordered_static_next (long *istart
, long *iend
)
541 return gomp_loop_ordered_static_next (istart
, iend
);
545 GOMP_loop_ordered_dynamic_next (long *istart
, long *iend
)
547 return gomp_loop_ordered_dynamic_next (istart
, iend
);
551 GOMP_loop_ordered_guided_next (long *istart
, long *iend
)
553 return gomp_loop_ordered_guided_next (istart
, iend
);