Home | History | Annotate | Line # | Download | only in nvptx
bar.c revision 1.1.1.1.4.3
      1  1.1.1.1.4.3  martin /* Copyright (C) 2015-2017 Free Software Foundation, Inc.
      2  1.1.1.1.4.3  martin    Contributed by Alexander Monakov <amonakov (at) ispras.ru>
      3  1.1.1.1.4.3  martin 
      4  1.1.1.1.4.3  martin    This file is part of the GNU Offloading and Multi Processing Library
      5  1.1.1.1.4.3  martin    (libgomp).
      6  1.1.1.1.4.3  martin 
      7  1.1.1.1.4.3  martin    Libgomp is free software; you can redistribute it and/or modify it
      8  1.1.1.1.4.3  martin    under the terms of the GNU General Public License as published by
      9  1.1.1.1.4.3  martin    the Free Software Foundation; either version 3, or (at your option)
     10  1.1.1.1.4.3  martin    any later version.
     11  1.1.1.1.4.3  martin 
     12  1.1.1.1.4.3  martin    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
     13  1.1.1.1.4.3  martin    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     14  1.1.1.1.4.3  martin    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     15  1.1.1.1.4.3  martin    more details.
     16  1.1.1.1.4.3  martin 
     17  1.1.1.1.4.3  martin    Under Section 7 of GPL version 3, you are granted additional
     18  1.1.1.1.4.3  martin    permissions described in the GCC Runtime Library Exception, version
     19  1.1.1.1.4.3  martin    3.1, as published by the Free Software Foundation.
     20  1.1.1.1.4.3  martin 
     21  1.1.1.1.4.3  martin    You should have received a copy of the GNU General Public License and
     22  1.1.1.1.4.3  martin    a copy of the GCC Runtime Library Exception along with this program;
     23  1.1.1.1.4.3  martin    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24  1.1.1.1.4.3  martin    <http://www.gnu.org/licenses/>.  */
     25  1.1.1.1.4.3  martin 
     26  1.1.1.1.4.3  martin /* This is an NVPTX specific implementation of a barrier synchronization
     27  1.1.1.1.4.3  martin    mechanism for libgomp.  This type is private to the library.  This
     28  1.1.1.1.4.3  martin    implementation uses atomic instructions and bar.sync instruction.  */
     29  1.1.1.1.4.3  martin 
     30  1.1.1.1.4.3  martin #include <limits.h>
     31  1.1.1.1.4.3  martin #include "libgomp.h"
     32  1.1.1.1.4.3  martin 
     33  1.1.1.1.4.3  martin 
     34  1.1.1.1.4.3  martin void
     35  1.1.1.1.4.3  martin gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
     36  1.1.1.1.4.3  martin {
     37  1.1.1.1.4.3  martin   if (__builtin_expect (state & BAR_WAS_LAST, 0))
     38  1.1.1.1.4.3  martin     {
     39  1.1.1.1.4.3  martin       /* Next time we'll be awaiting TOTAL threads again.  */
     40  1.1.1.1.4.3  martin       bar->awaited = bar->total;
     41  1.1.1.1.4.3  martin       __atomic_store_n (&bar->generation, bar->generation + BAR_INCR,
     42  1.1.1.1.4.3  martin 			MEMMODEL_RELEASE);
     43  1.1.1.1.4.3  martin     }
     44  1.1.1.1.4.3  martin   asm ("bar.sync 1, %0;" : : "r" (32 * bar->total));
     45  1.1.1.1.4.3  martin }
     46  1.1.1.1.4.3  martin 
     47  1.1.1.1.4.3  martin void
     48  1.1.1.1.4.3  martin gomp_barrier_wait (gomp_barrier_t *bar)
     49  1.1.1.1.4.3  martin {
     50  1.1.1.1.4.3  martin   gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
     51  1.1.1.1.4.3  martin }
     52  1.1.1.1.4.3  martin 
     53  1.1.1.1.4.3  martin /* Like gomp_barrier_wait, except that if the encountering thread
     54  1.1.1.1.4.3  martin    is not the last one to hit the barrier, it returns immediately.
     55  1.1.1.1.4.3  martin    The intended usage is that a thread which intends to gomp_barrier_destroy
     56  1.1.1.1.4.3  martin    this barrier calls gomp_barrier_wait, while all other threads
     57  1.1.1.1.4.3  martin    call gomp_barrier_wait_last.  When gomp_barrier_wait returns,
     58  1.1.1.1.4.3  martin    the barrier can be safely destroyed.  */
     59  1.1.1.1.4.3  martin 
     60  1.1.1.1.4.3  martin void
     61  1.1.1.1.4.3  martin gomp_barrier_wait_last (gomp_barrier_t *bar)
     62  1.1.1.1.4.3  martin {
     63  1.1.1.1.4.3  martin   /* Deferring to gomp_barrier_wait does not use the optimization opportunity
     64  1.1.1.1.4.3  martin      allowed by the interface contract for all-but-last participants.  The
     65  1.1.1.1.4.3  martin      original implementation in config/linux/bar.c handles this better.  */
     66  1.1.1.1.4.3  martin   gomp_barrier_wait (bar);
     67  1.1.1.1.4.3  martin }
     68  1.1.1.1.4.3  martin 
     69  1.1.1.1.4.3  martin void
     70  1.1.1.1.4.3  martin gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
     71  1.1.1.1.4.3  martin {
     72  1.1.1.1.4.3  martin   asm ("bar.sync 1, %0;" : : "r" (32 * bar->total));
     73  1.1.1.1.4.3  martin }
     74  1.1.1.1.4.3  martin 
     75  1.1.1.1.4.3  martin void
     76  1.1.1.1.4.3  martin gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
     77  1.1.1.1.4.3  martin {
     78  1.1.1.1.4.3  martin   unsigned int generation, gen;
     79  1.1.1.1.4.3  martin 
     80  1.1.1.1.4.3  martin   if (__builtin_expect (state & BAR_WAS_LAST, 0))
     81  1.1.1.1.4.3  martin     {
     82  1.1.1.1.4.3  martin       /* Next time we'll be awaiting TOTAL threads again.  */
     83  1.1.1.1.4.3  martin       struct gomp_thread *thr = gomp_thread ();
     84  1.1.1.1.4.3  martin       struct gomp_team *team = thr->ts.team;
     85  1.1.1.1.4.3  martin 
     86  1.1.1.1.4.3  martin       bar->awaited = bar->total;
     87  1.1.1.1.4.3  martin       team->work_share_cancelled = 0;
     88  1.1.1.1.4.3  martin       if (__builtin_expect (team->task_count, 0))
     89  1.1.1.1.4.3  martin 	{
     90  1.1.1.1.4.3  martin 	  gomp_barrier_handle_tasks (state);
     91  1.1.1.1.4.3  martin 	  state &= ~BAR_WAS_LAST;
     92  1.1.1.1.4.3  martin 	}
     93  1.1.1.1.4.3  martin       else
     94  1.1.1.1.4.3  martin 	{
     95  1.1.1.1.4.3  martin 	  state &= ~BAR_CANCELLED;
     96  1.1.1.1.4.3  martin 	  state += BAR_INCR - BAR_WAS_LAST;
     97  1.1.1.1.4.3  martin 	  __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
     98  1.1.1.1.4.3  martin 	  asm ("bar.sync 1, %0;" : : "r" (32 * bar->total));
     99  1.1.1.1.4.3  martin 	  return;
    100  1.1.1.1.4.3  martin 	}
    101  1.1.1.1.4.3  martin     }
    102  1.1.1.1.4.3  martin 
    103  1.1.1.1.4.3  martin   generation = state;
    104  1.1.1.1.4.3  martin   state &= ~BAR_CANCELLED;
    105  1.1.1.1.4.3  martin   do
    106  1.1.1.1.4.3  martin     {
    107  1.1.1.1.4.3  martin       asm ("bar.sync 1, %0;" : : "r" (32 * bar->total));
    108  1.1.1.1.4.3  martin       gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    109  1.1.1.1.4.3  martin       if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
    110  1.1.1.1.4.3  martin 	{
    111  1.1.1.1.4.3  martin 	  gomp_barrier_handle_tasks (state);
    112  1.1.1.1.4.3  martin 	  gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    113  1.1.1.1.4.3  martin 	}
    114  1.1.1.1.4.3  martin       generation |= gen & BAR_WAITING_FOR_TASK;
    115  1.1.1.1.4.3  martin     }
    116  1.1.1.1.4.3  martin   while (gen != state + BAR_INCR);
    117  1.1.1.1.4.3  martin }
    118  1.1.1.1.4.3  martin 
    119  1.1.1.1.4.3  martin void
    120  1.1.1.1.4.3  martin gomp_team_barrier_wait (gomp_barrier_t *bar)
    121  1.1.1.1.4.3  martin {
    122  1.1.1.1.4.3  martin   gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
    123  1.1.1.1.4.3  martin }
    124  1.1.1.1.4.3  martin 
    125  1.1.1.1.4.3  martin void
    126  1.1.1.1.4.3  martin gomp_team_barrier_wait_final (gomp_barrier_t *bar)
    127  1.1.1.1.4.3  martin {
    128  1.1.1.1.4.3  martin   gomp_barrier_state_t state = gomp_barrier_wait_final_start (bar);
    129  1.1.1.1.4.3  martin   if (__builtin_expect (state & BAR_WAS_LAST, 0))
    130  1.1.1.1.4.3  martin     bar->awaited_final = bar->total;
    131  1.1.1.1.4.3  martin   gomp_team_barrier_wait_end (bar, state);
    132  1.1.1.1.4.3  martin }
    133  1.1.1.1.4.3  martin 
    134  1.1.1.1.4.3  martin bool
    135  1.1.1.1.4.3  martin gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
    136  1.1.1.1.4.3  martin 				   gomp_barrier_state_t state)
    137  1.1.1.1.4.3  martin {
    138  1.1.1.1.4.3  martin   unsigned int generation, gen;
    139  1.1.1.1.4.3  martin 
    140  1.1.1.1.4.3  martin   if (__builtin_expect (state & BAR_WAS_LAST, 0))
    141  1.1.1.1.4.3  martin     {
    142  1.1.1.1.4.3  martin       /* Next time we'll be awaiting TOTAL threads again.  */
    143  1.1.1.1.4.3  martin       /* BAR_CANCELLED should never be set in state here, because
    144  1.1.1.1.4.3  martin 	 cancellation means that at least one of the threads has been
    145  1.1.1.1.4.3  martin 	 cancelled, thus on a cancellable barrier we should never see
    146  1.1.1.1.4.3  martin 	 all threads to arrive.  */
    147  1.1.1.1.4.3  martin       struct gomp_thread *thr = gomp_thread ();
    148  1.1.1.1.4.3  martin       struct gomp_team *team = thr->ts.team;
    149  1.1.1.1.4.3  martin 
    150  1.1.1.1.4.3  martin       bar->awaited = bar->total;
    151  1.1.1.1.4.3  martin       team->work_share_cancelled = 0;
    152  1.1.1.1.4.3  martin       if (__builtin_expect (team->task_count, 0))
    153  1.1.1.1.4.3  martin 	{
    154  1.1.1.1.4.3  martin 	  gomp_barrier_handle_tasks (state);
    155  1.1.1.1.4.3  martin 	  state &= ~BAR_WAS_LAST;
    156  1.1.1.1.4.3  martin 	}
    157  1.1.1.1.4.3  martin       else
    158  1.1.1.1.4.3  martin 	{
    159  1.1.1.1.4.3  martin 	  state += BAR_INCR - BAR_WAS_LAST;
    160  1.1.1.1.4.3  martin 	  __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
    161  1.1.1.1.4.3  martin 	  asm ("bar.sync 1, %0;" : : "r" (32 * bar->total));
    162  1.1.1.1.4.3  martin 	  return false;
    163  1.1.1.1.4.3  martin 	}
    164  1.1.1.1.4.3  martin     }
    165  1.1.1.1.4.3  martin 
    166  1.1.1.1.4.3  martin   if (__builtin_expect (state & BAR_CANCELLED, 0))
    167  1.1.1.1.4.3  martin     return true;
    168  1.1.1.1.4.3  martin 
    169  1.1.1.1.4.3  martin   generation = state;
    170  1.1.1.1.4.3  martin   do
    171  1.1.1.1.4.3  martin     {
    172  1.1.1.1.4.3  martin       asm ("bar.sync 1, %0;" : : "r" (32 * bar->total));
    173  1.1.1.1.4.3  martin       gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    174  1.1.1.1.4.3  martin       if (__builtin_expect (gen & BAR_CANCELLED, 0))
    175  1.1.1.1.4.3  martin 	return true;
    176  1.1.1.1.4.3  martin       if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
    177  1.1.1.1.4.3  martin 	{
    178  1.1.1.1.4.3  martin 	  gomp_barrier_handle_tasks (state);
    179  1.1.1.1.4.3  martin 	  gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    180  1.1.1.1.4.3  martin 	}
    181  1.1.1.1.4.3  martin       generation |= gen & BAR_WAITING_FOR_TASK;
    182  1.1.1.1.4.3  martin     }
    183  1.1.1.1.4.3  martin   while (gen != state + BAR_INCR);
    184  1.1.1.1.4.3  martin 
    185  1.1.1.1.4.3  martin   return false;
    186  1.1.1.1.4.3  martin }
    187  1.1.1.1.4.3  martin 
    188  1.1.1.1.4.3  martin bool
    189  1.1.1.1.4.3  martin gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
    190  1.1.1.1.4.3  martin {
    191  1.1.1.1.4.3  martin   return gomp_team_barrier_wait_cancel_end (bar, gomp_barrier_wait_start (bar));
    192  1.1.1.1.4.3  martin }
    193  1.1.1.1.4.3  martin 
    194  1.1.1.1.4.3  martin void
    195  1.1.1.1.4.3  martin gomp_team_barrier_cancel (struct gomp_team *team)
    196  1.1.1.1.4.3  martin {
    197  1.1.1.1.4.3  martin   gomp_mutex_lock (&team->task_lock);
    198  1.1.1.1.4.3  martin   if (team->barrier.generation & BAR_CANCELLED)
    199  1.1.1.1.4.3  martin     {
    200  1.1.1.1.4.3  martin       gomp_mutex_unlock (&team->task_lock);
    201  1.1.1.1.4.3  martin       return;
    202  1.1.1.1.4.3  martin     }
    203  1.1.1.1.4.3  martin   team->barrier.generation |= BAR_CANCELLED;
    204  1.1.1.1.4.3  martin   gomp_mutex_unlock (&team->task_lock);
    205  1.1.1.1.4.3  martin   gomp_team_barrier_wake (&team->barrier, INT_MAX);
    206  1.1.1.1.4.3  martin }
    207