1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #ifndef _HOST_ATOMICS_H_
17 #define _HOST_ATOMICS_H_
18
19 #include "harness/testHarness.h"
20
21 #ifdef WIN32
22 #include "Windows.h"
23 #endif
24
25 //flag for test verification (good test should discover non-atomic functions and fail)
26 //#define NON_ATOMIC_FUNCTIONS
27
28 enum TExplicitMemoryOrderType
29 {
30 MEMORY_ORDER_EMPTY,
31 MEMORY_ORDER_RELAXED,
32 MEMORY_ORDER_ACQUIRE,
33 MEMORY_ORDER_RELEASE,
34 MEMORY_ORDER_ACQ_REL,
35 MEMORY_ORDER_SEQ_CST
36 };
37
38 // host atomic types (applicable for atomic functions supported on host OS)
39 #ifdef WIN32
40 #define HOST_ATOMIC_INT unsigned long
41 #define HOST_ATOMIC_UINT unsigned long
42 #define HOST_ATOMIC_LONG unsigned long long
43 #define HOST_ATOMIC_ULONG unsigned long long
44 #define HOST_ATOMIC_FLOAT float
45 #define HOST_ATOMIC_DOUBLE double
46 #else
47 #define HOST_ATOMIC_INT cl_int
48 #define HOST_ATOMIC_UINT cl_uint
49 #define HOST_ATOMIC_LONG cl_long
50 #define HOST_ATOMIC_ULONG cl_ulong
51 #define HOST_ATOMIC_FLOAT cl_float
52 #define HOST_ATOMIC_DOUBLE cl_double
53 #endif
54
55 #define HOST_ATOMIC_INTPTR_T32 HOST_ATOMIC_INT
56 #define HOST_ATOMIC_UINTPTR_T32 HOST_ATOMIC_INT
57 #define HOST_ATOMIC_SIZE_T32 HOST_ATOMIC_UINT
58 #define HOST_ATOMIC_PTRDIFF_T32 HOST_ATOMIC_INT
59
60 #define HOST_ATOMIC_INTPTR_T64 HOST_ATOMIC_LONG
61 #define HOST_ATOMIC_UINTPTR_T64 HOST_ATOMIC_LONG
62 #define HOST_ATOMIC_SIZE_T64 HOST_ATOMIC_ULONG
63 #define HOST_ATOMIC_PTRDIFF_T64 HOST_ATOMIC_LONG
64
65 #define HOST_ATOMIC_FLAG HOST_ATOMIC_INT
66
67 // host regular types corresponding to atomic types
68 #define HOST_INT cl_int
69 #define HOST_UINT cl_uint
70 #define HOST_LONG cl_long
71 #define HOST_ULONG cl_ulong
72 #define HOST_FLOAT cl_float
73 #define HOST_DOUBLE cl_double
74
75 #define HOST_INTPTR_T32 cl_int
76 #define HOST_UINTPTR_T32 cl_uint
77 #define HOST_SIZE_T32 cl_uint
78 #define HOST_PTRDIFF_T32 cl_int
79
80 #define HOST_INTPTR_T64 cl_long
81 #define HOST_UINTPTR_T64 cl_ulong
82 #define HOST_SIZE_T64 cl_ulong
83 #define HOST_PTRDIFF_T64 cl_long
84
85 #define HOST_FLAG cl_uint
86
87 // host atomic functions
88 void host_atomic_thread_fence(TExplicitMemoryOrderType order);
89
90 template <typename AtomicType, typename CorrespondingType>
host_atomic_fetch_add(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)91 CorrespondingType host_atomic_fetch_add(volatile AtomicType *a, CorrespondingType c,
92 TExplicitMemoryOrderType order)
93 {
94 #if defined( _MSC_VER ) || (defined( __INTEL_COMPILER ) && defined(WIN32))
95 return InterlockedExchangeAdd(a, c);
96 #elif defined(__GNUC__)
97 return __sync_fetch_and_add(a, c);
98 #else
99 log_info("Host function not implemented: atomic_fetch_add\n");
100 return 0;
101 #endif
102 }
103
104 template <typename AtomicType, typename CorrespondingType>
host_atomic_fetch_sub(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)105 CorrespondingType host_atomic_fetch_sub(volatile AtomicType *a, CorrespondingType c,
106 TExplicitMemoryOrderType order)
107 {
108 #if defined( _MSC_VER ) || (defined( __INTEL_COMPILER ) && defined(WIN32))
109 return InterlockedExchangeSubtract(a, c);
110 #elif defined(__GNUC__)
111 return __sync_fetch_and_sub(a, c);
112 #else
113 log_info("Host function not implemented: atomic_fetch_sub\n");
114 return 0;
115 #endif
116 }
117
118 template <typename AtomicType, typename CorrespondingType>
host_atomic_exchange(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)119 CorrespondingType host_atomic_exchange(volatile AtomicType *a, CorrespondingType c,
120 TExplicitMemoryOrderType order)
121 {
122 #if defined( _MSC_VER ) || (defined( __INTEL_COMPILER ) && defined(WIN32))
123 return InterlockedExchange(a, c);
124 #elif defined(__GNUC__)
125 return __sync_lock_test_and_set(a, c);
126 #else
127 log_info("Host function not implemented: atomic_exchange\n");
128 return 0;
129 #endif
130 }
131 template <> HOST_FLOAT host_atomic_exchange(volatile HOST_ATOMIC_FLOAT *a, HOST_FLOAT c,
132 TExplicitMemoryOrderType order);
133 template <> HOST_DOUBLE host_atomic_exchange(volatile HOST_ATOMIC_DOUBLE *a, HOST_DOUBLE c,
134 TExplicitMemoryOrderType order);
135
136 template <typename AtomicType, typename CorrespondingType>
host_atomic_compare_exchange(volatile AtomicType * a,CorrespondingType * expected,CorrespondingType desired,TExplicitMemoryOrderType order_success,TExplicitMemoryOrderType order_failure)137 bool host_atomic_compare_exchange(volatile AtomicType *a, CorrespondingType *expected, CorrespondingType desired,
138 TExplicitMemoryOrderType order_success,
139 TExplicitMemoryOrderType order_failure)
140 {
141 CorrespondingType tmp;
142 #if defined( _MSC_VER ) || (defined( __INTEL_COMPILER ) && defined(WIN32))
143 tmp = InterlockedCompareExchange(a, desired, *expected);
144 #elif defined(__GNUC__)
145 tmp = __sync_val_compare_and_swap(a, *expected, desired);
146 #else
147 log_info("Host function not implemented: atomic_compare_exchange\n");
148 tmp = 0;
149 #endif
150 if(tmp == *expected)
151 return true;
152 *expected = tmp;
153 return false;
154 }
155
156 template <typename AtomicType, typename CorrespondingType>
host_atomic_load(volatile AtomicType * a,TExplicitMemoryOrderType order)157 CorrespondingType host_atomic_load(volatile AtomicType *a,
158 TExplicitMemoryOrderType order)
159 {
160 #if defined( _MSC_VER ) || (defined( __INTEL_COMPILER ) && defined(WIN32))
161 return InterlockedExchangeAdd(a, 0);
162 #elif defined(__GNUC__)
163 return __sync_add_and_fetch(a, 0);
164 #else
165 log_info("Host function not implemented: atomic_load\n");
166 return 0;
167 #endif
168 }
169 template <> HOST_FLOAT host_atomic_load(volatile HOST_ATOMIC_FLOAT *a,
170 TExplicitMemoryOrderType order);
171 template <> HOST_DOUBLE host_atomic_load(volatile HOST_ATOMIC_DOUBLE *a,
172 TExplicitMemoryOrderType order);
173
174 template <typename AtomicType, typename CorrespondingType>
host_atomic_store(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)175 void host_atomic_store(volatile AtomicType* a, CorrespondingType c,
176 TExplicitMemoryOrderType order)
177 {
178 host_atomic_exchange(a, c, order);
179 }
180
181 template <typename AtomicType, typename CorrespondingType>
host_atomic_init(volatile AtomicType * a,CorrespondingType c)182 void host_atomic_init(volatile AtomicType* a, CorrespondingType c)
183 {
184 host_atomic_exchange(a, c, MEMORY_ORDER_RELAXED);
185 }
186
187 template <typename AtomicType, typename CorrespondingType>
host_atomic_fetch_or(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)188 CorrespondingType host_atomic_fetch_or(volatile AtomicType *a, CorrespondingType c,
189 TExplicitMemoryOrderType order)
190 {
191 CorrespondingType expected = host_atomic_load<AtomicType, CorrespondingType>(a, order);
192 CorrespondingType desired;
193 do
194 desired = expected | c;
195 while(!host_atomic_compare_exchange(a, &expected, desired, order, order));
196 return expected;
197 }
198
199 template <typename AtomicType, typename CorrespondingType>
host_atomic_fetch_and(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)200 CorrespondingType host_atomic_fetch_and(volatile AtomicType *a, CorrespondingType c,
201 TExplicitMemoryOrderType order)
202 {
203 CorrespondingType expected = host_atomic_load<AtomicType, CorrespondingType>(a, order);
204 CorrespondingType desired;
205 do
206 desired = expected & c;
207 while(!host_atomic_compare_exchange(a, &expected, desired, order, order));
208 return expected;
209 }
210
211 template <typename AtomicType, typename CorrespondingType>
host_atomic_fetch_xor(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)212 CorrespondingType host_atomic_fetch_xor(volatile AtomicType *a, CorrespondingType c,
213 TExplicitMemoryOrderType order)
214 {
215 CorrespondingType expected = host_atomic_load<AtomicType, CorrespondingType>(a, order);
216 CorrespondingType desired;
217 do
218 desired = expected ^ c;
219 while(!host_atomic_compare_exchange(a, &expected, desired, order, order));
220 return expected;
221 }
222
223 template <typename AtomicType, typename CorrespondingType>
host_atomic_fetch_min(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)224 CorrespondingType host_atomic_fetch_min(volatile AtomicType *a, CorrespondingType c,
225 TExplicitMemoryOrderType order)
226 {
227 CorrespondingType expected = host_atomic_load<AtomicType, CorrespondingType>(a, order);
228 CorrespondingType desired;
229 do
230 desired = expected < c ? expected : c;
231 while(!host_atomic_compare_exchange(a, &expected, desired, order, order));
232 return expected;
233 }
234
235 template <typename AtomicType, typename CorrespondingType>
host_atomic_fetch_max(volatile AtomicType * a,CorrespondingType c,TExplicitMemoryOrderType order)236 CorrespondingType host_atomic_fetch_max(volatile AtomicType *a, CorrespondingType c,
237 TExplicitMemoryOrderType order)
238 {
239 CorrespondingType expected = host_atomic_load<AtomicType, CorrespondingType>(a, order);
240 CorrespondingType desired;
241 do
242 desired = expected > c ? expected : c;
243 while(!host_atomic_compare_exchange(a, &expected, desired, order, order));
244 return expected;
245 }
246
247 bool host_atomic_flag_test_and_set(volatile HOST_ATOMIC_FLAG *a, TExplicitMemoryOrderType order);
248 void host_atomic_flag_clear(volatile HOST_ATOMIC_FLAG *a, TExplicitMemoryOrderType order);
249
250 #endif //_HOST_ATOMICS_H_
251