1 1.1.1.3 mrg /* Copyright (C) 2015-2024 Free Software Foundation, Inc. 2 1.1 mrg Contributed by Mentor Embedded. 3 1.1 mrg 4 1.1 mrg This file is part of the GNU Offloading and Multi Processing Library 5 1.1 mrg (libgomp). 6 1.1 mrg 7 1.1 mrg Libgomp is free software; you can redistribute it and/or modify it 8 1.1 mrg under the terms of the GNU General Public License as published by 9 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 10 1.1 mrg any later version. 11 1.1 mrg 12 1.1 mrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY 13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 1.1 mrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 1.1 mrg more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg /* This is an AMD GCN specific implementation of a barrier synchronization 27 1.1 mrg mechanism for libgomp. This type is private to the library. This 28 1.1 mrg implementation uses atomic instructions and s_barrier instruction. It 29 1.1 mrg uses MEMMODEL_RELAXED here because barriers are within workgroups and 30 1.1 mrg therefore don't need to flush caches. */ 31 1.1 mrg 32 1.1 mrg #ifndef GOMP_BARRIER_H 33 1.1 mrg #define GOMP_BARRIER_H 1 34 1.1 mrg 35 1.1 mrg #include "mutex.h" 36 1.1 mrg 37 1.1 mrg typedef struct 38 1.1 mrg { 39 1.1 mrg unsigned total; 40 1.1 mrg unsigned generation; 41 1.1 mrg unsigned awaited; 42 1.1 mrg unsigned awaited_final; 43 1.1 mrg } gomp_barrier_t; 44 1.1 mrg 45 1.1 mrg typedef unsigned int gomp_barrier_state_t; 46 1.1 mrg 47 1.1 mrg /* The generation field contains a counter in the high bits, with a few 48 1.1 mrg low bits dedicated to flags. Note that TASK_PENDING and WAS_LAST can 49 1.1 mrg share space because WAS_LAST is never stored back to generation. */ 50 1.1 mrg #define BAR_TASK_PENDING 1 51 1.1 mrg #define BAR_WAS_LAST 1 52 1.1 mrg #define BAR_WAITING_FOR_TASK 2 53 1.1 mrg #define BAR_CANCELLED 4 54 1.1 mrg #define BAR_INCR 8 55 1.1 mrg 56 1.1 mrg static inline void gomp_barrier_init (gomp_barrier_t *bar, unsigned count) 57 1.1 mrg { 58 1.1 mrg bar->total = count; 59 1.1 mrg bar->awaited = count; 60 1.1 mrg bar->awaited_final = count; 61 1.1 mrg bar->generation = 0; 62 1.1 mrg } 63 1.1 mrg 64 1.1 mrg static inline void gomp_barrier_reinit (gomp_barrier_t *bar, unsigned count) 65 1.1 mrg { 66 1.1 mrg __atomic_add_fetch (&bar->awaited, count - bar->total, MEMMODEL_RELAXED); 67 1.1 mrg bar->total = count; 68 1.1 mrg } 69 1.1 mrg 70 1.1 mrg static inline void gomp_barrier_destroy (gomp_barrier_t *bar) 71 1.1 mrg { 72 1.1 mrg } 73 1.1 mrg 74 1.1 mrg extern void gomp_barrier_wait (gomp_barrier_t *); 75 1.1 mrg extern void gomp_barrier_wait_last (gomp_barrier_t *); 76 1.1 mrg extern void gomp_barrier_wait_end (gomp_barrier_t *, gomp_barrier_state_t); 77 1.1 mrg extern void gomp_team_barrier_wait (gomp_barrier_t *); 78 1.1 mrg extern void gomp_team_barrier_wait_final (gomp_barrier_t *); 79 1.1 mrg extern void gomp_team_barrier_wait_end (gomp_barrier_t *, 80 1.1 mrg gomp_barrier_state_t); 81 1.1 mrg extern bool gomp_team_barrier_wait_cancel (gomp_barrier_t *); 82 1.1 mrg extern bool gomp_team_barrier_wait_cancel_end (gomp_barrier_t *, 83 1.1 mrg gomp_barrier_state_t); 84 1.1 mrg extern void gomp_team_barrier_wake (gomp_barrier_t *, int); 85 1.1 mrg struct gomp_team; 86 1.1 mrg extern void gomp_team_barrier_cancel (struct gomp_team *); 87 1.1 mrg 88 1.1 mrg static inline gomp_barrier_state_t 89 1.1 mrg gomp_barrier_wait_start (gomp_barrier_t *bar) 90 1.1 mrg { 91 1.1 mrg unsigned int ret = __atomic_load_n (&bar->generation, MEMMODEL_RELAXED); 92 1.1 mrg ret &= -BAR_INCR | BAR_CANCELLED; 93 1.1 mrg /* A memory barrier is needed before exiting from the various forms 94 1.1 mrg of gomp_barrier_wait, to satisfy OpenMP API version 3.1 section 95 1.1 mrg 2.8.6 flush Construct, which says there is an implicit flush during 96 1.1 mrg a barrier region. This is a convenient place to add the barrier, 97 1.1 mrg so we use MEMMODEL_ACQ_REL here rather than MEMMODEL_ACQUIRE. */ 98 1.1 mrg if (__atomic_add_fetch (&bar->awaited, -1, MEMMODEL_RELAXED) == 0) 99 1.1 mrg ret |= BAR_WAS_LAST; 100 1.1 mrg return ret; 101 1.1 mrg } 102 1.1 mrg 103 1.1 mrg static inline gomp_barrier_state_t 104 1.1 mrg gomp_barrier_wait_cancel_start (gomp_barrier_t *bar) 105 1.1 mrg { 106 1.1 mrg return gomp_barrier_wait_start (bar); 107 1.1 mrg } 108 1.1 mrg 109 1.1 mrg /* This is like gomp_barrier_wait_start, except it decrements 110 1.1 mrg bar->awaited_final rather than bar->awaited and should be used 111 1.1 mrg for the gomp_team_end barrier only. */ 112 1.1 mrg static inline gomp_barrier_state_t 113 1.1 mrg gomp_barrier_wait_final_start (gomp_barrier_t *bar) 114 1.1 mrg { 115 1.1 mrg unsigned int ret = __atomic_load_n (&bar->generation, MEMMODEL_RELAXED); 116 1.1 mrg ret &= -BAR_INCR | BAR_CANCELLED; 117 1.1 mrg /* See above gomp_barrier_wait_start comment. */ 118 1.1 mrg if (__atomic_add_fetch (&bar->awaited_final, -1, MEMMODEL_RELAXED) == 0) 119 1.1 mrg ret |= BAR_WAS_LAST; 120 1.1 mrg return ret; 121 1.1 mrg } 122 1.1 mrg 123 1.1 mrg static inline bool 124 1.1 mrg gomp_barrier_last_thread (gomp_barrier_state_t state) 125 1.1 mrg { 126 1.1 mrg return state & BAR_WAS_LAST; 127 1.1 mrg } 128 1.1 mrg 129 1.1 mrg /* All the inlines below must be called with team->task_lock 130 1.1 mrg held. */ 131 1.1 mrg 132 1.1 mrg static inline void 133 1.1 mrg gomp_team_barrier_set_task_pending (gomp_barrier_t *bar) 134 1.1 mrg { 135 1.1 mrg bar->generation |= BAR_TASK_PENDING; 136 1.1 mrg } 137 1.1 mrg 138 1.1 mrg static inline void 139 1.1 mrg gomp_team_barrier_clear_task_pending (gomp_barrier_t *bar) 140 1.1 mrg { 141 1.1 mrg bar->generation &= ~BAR_TASK_PENDING; 142 1.1 mrg } 143 1.1 mrg 144 1.1 mrg static inline void 145 1.1 mrg gomp_team_barrier_set_waiting_for_tasks (gomp_barrier_t *bar) 146 1.1 mrg { 147 1.1 mrg bar->generation |= BAR_WAITING_FOR_TASK; 148 1.1 mrg } 149 1.1 mrg 150 1.1 mrg static inline bool 151 1.1 mrg gomp_team_barrier_waiting_for_tasks (gomp_barrier_t *bar) 152 1.1 mrg { 153 1.1 mrg return (bar->generation & BAR_WAITING_FOR_TASK) != 0; 154 1.1 mrg } 155 1.1 mrg 156 1.1 mrg static inline bool 157 1.1 mrg gomp_team_barrier_cancelled (gomp_barrier_t *bar) 158 1.1 mrg { 159 1.1 mrg return __builtin_expect ((bar->generation & BAR_CANCELLED) != 0, 0); 160 1.1 mrg } 161 1.1 mrg 162 1.1 mrg static inline void 163 1.1 mrg gomp_team_barrier_done (gomp_barrier_t *bar, gomp_barrier_state_t state) 164 1.1 mrg { 165 1.1 mrg bar->generation = (state & -BAR_INCR) + BAR_INCR; 166 1.1 mrg } 167 1.1 mrg 168 1.1 mrg #endif /* GOMP_BARRIER_H */ 169