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 #include "harness/testHarness.h"
17 #include "harness/kernelHelpers.h"
18 #include "harness/typeWrappers.h"
19
20 #include "common.h"
21
get_memory_order_type_name(TExplicitMemoryOrderType orderType)22 const char *get_memory_order_type_name(TExplicitMemoryOrderType orderType)
23 {
24 switch (orderType)
25 {
26 case MEMORY_ORDER_EMPTY:
27 return "";
28 case MEMORY_ORDER_RELAXED:
29 return "memory_order_relaxed";
30 case MEMORY_ORDER_ACQUIRE:
31 return "memory_order_acquire";
32 case MEMORY_ORDER_RELEASE:
33 return "memory_order_release";
34 case MEMORY_ORDER_ACQ_REL:
35 return "memory_order_acq_rel";
36 case MEMORY_ORDER_SEQ_CST:
37 return "memory_order_seq_cst";
38 default:
39 return 0;
40 }
41 }
42
get_memory_scope_type_name(TExplicitMemoryScopeType scopeType)43 const char *get_memory_scope_type_name(TExplicitMemoryScopeType scopeType)
44 {
45 switch (scopeType)
46 {
47 case MEMORY_SCOPE_EMPTY: return "";
48 case MEMORY_SCOPE_WORK_GROUP: return "memory_scope_work_group";
49 case MEMORY_SCOPE_DEVICE: return "memory_scope_device";
50 case MEMORY_SCOPE_ALL_DEVICES: return "memory_scope_all_devices";
51 case MEMORY_SCOPE_ALL_SVM_DEVICES: return "memory_scope_all_svm_devices";
52 default: return 0;
53 }
54 }
55
56
Size(cl_device_id device)57 cl_uint AtomicTypeInfo::Size(cl_device_id device)
58 {
59 switch(_type)
60 {
61 case TYPE_ATOMIC_INT:
62 case TYPE_ATOMIC_UINT:
63 case TYPE_ATOMIC_FLOAT:
64 case TYPE_ATOMIC_FLAG:
65 return sizeof(cl_int);
66 case TYPE_ATOMIC_LONG:
67 case TYPE_ATOMIC_ULONG:
68 case TYPE_ATOMIC_DOUBLE:
69 return sizeof(cl_long);
70 case TYPE_ATOMIC_INTPTR_T:
71 case TYPE_ATOMIC_UINTPTR_T:
72 case TYPE_ATOMIC_SIZE_T:
73 case TYPE_ATOMIC_PTRDIFF_T:
74 {
75 int error;
76 cl_uint addressBits = 0;
77
78 error = clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(addressBits), &addressBits, 0);
79 test_error_ret(error, "clGetDeviceInfo", 0);
80
81 return addressBits/8;
82 }
83 default:
84 return 0;
85 }
86 }
87
AtomicTypeName()88 const char *AtomicTypeInfo::AtomicTypeName()
89 {
90 switch(_type)
91 {
92 case TYPE_ATOMIC_INT:
93 return "atomic_int";
94 case TYPE_ATOMIC_UINT:
95 return "atomic_uint";
96 case TYPE_ATOMIC_FLOAT:
97 return "atomic_float";
98 case TYPE_ATOMIC_FLAG:
99 return "atomic_flag";
100 case TYPE_ATOMIC_LONG:
101 return "atomic_long";
102 case TYPE_ATOMIC_ULONG:
103 return "atomic_ulong";
104 case TYPE_ATOMIC_DOUBLE:
105 return "atomic_double";
106 case TYPE_ATOMIC_INTPTR_T:
107 return "atomic_intptr_t";
108 case TYPE_ATOMIC_UINTPTR_T:
109 return "atomic_uintptr_t";
110 case TYPE_ATOMIC_SIZE_T:
111 return "atomic_size_t";
112 case TYPE_ATOMIC_PTRDIFF_T:
113 return "atomic_ptrdiff_t";
114 default:
115 return 0;
116 }
117 }
118
RegularTypeName()119 const char *AtomicTypeInfo::RegularTypeName()
120 {
121 switch(_type)
122 {
123 case TYPE_ATOMIC_INT:
124 return "int";
125 case TYPE_ATOMIC_UINT:
126 return "uint";
127 case TYPE_ATOMIC_FLOAT:
128 return "float";
129 case TYPE_ATOMIC_FLAG:
130 return "int";
131 case TYPE_ATOMIC_LONG:
132 return "long";
133 case TYPE_ATOMIC_ULONG:
134 return "ulong";
135 case TYPE_ATOMIC_DOUBLE:
136 return "double";
137 case TYPE_ATOMIC_INTPTR_T:
138 return "intptr_t";
139 case TYPE_ATOMIC_UINTPTR_T:
140 return "uintptr_t";
141 case TYPE_ATOMIC_SIZE_T:
142 return "size_t";
143 case TYPE_ATOMIC_PTRDIFF_T:
144 return "ptrdiff_t";
145 default:
146 return 0;
147 }
148 }
149
AddSubOperandTypeName()150 const char *AtomicTypeInfo::AddSubOperandTypeName()
151 {
152 switch(_type)
153 {
154 case TYPE_ATOMIC_INTPTR_T:
155 case TYPE_ATOMIC_UINTPTR_T:
156 return AtomicTypeInfo(TYPE_ATOMIC_PTRDIFF_T).RegularTypeName();
157 default:
158 return RegularTypeName();
159 }
160 }
161
IsSupported(cl_device_id device)162 int AtomicTypeInfo::IsSupported(cl_device_id device)
163 {
164 switch(_type)
165 {
166 case TYPE_ATOMIC_INT:
167 case TYPE_ATOMIC_UINT:
168 case TYPE_ATOMIC_FLOAT:
169 case TYPE_ATOMIC_FLAG:
170 return 1;
171 case TYPE_ATOMIC_LONG:
172 case TYPE_ATOMIC_ULONG:
173 return is_extension_available(device, "cl_khr_int64_base_atomics") &&
174 is_extension_available(device, "cl_khr_int64_extended_atomics");
175 case TYPE_ATOMIC_DOUBLE:
176 return is_extension_available(device, "cl_khr_int64_base_atomics") &&
177 is_extension_available(device, "cl_khr_int64_extended_atomics") &&
178 is_extension_available(device, "cl_khr_fp64");
179 case TYPE_ATOMIC_INTPTR_T:
180 case TYPE_ATOMIC_UINTPTR_T:
181 case TYPE_ATOMIC_SIZE_T:
182 case TYPE_ATOMIC_PTRDIFF_T:
183 if(Size(device) == 4)
184 return 1;
185 return is_extension_available(device, "cl_khr_int64_base_atomics") &&
186 is_extension_available(device, "cl_khr_int64_extended_atomics");
187 default:
188 return 0;
189 }
190 }
191
MinValue()192 template<> cl_int AtomicTypeExtendedInfo<cl_int>::MinValue() {return CL_INT_MIN;}
MinValue()193 template<> cl_uint AtomicTypeExtendedInfo<cl_uint>::MinValue() {return 0;}
MinValue()194 template<> cl_long AtomicTypeExtendedInfo<cl_long>::MinValue() {return CL_LONG_MIN;}
MinValue()195 template<> cl_ulong AtomicTypeExtendedInfo<cl_ulong>::MinValue() {return 0;}
MinValue()196 template<> cl_float AtomicTypeExtendedInfo<cl_float>::MinValue() {return CL_FLT_MIN;}
MinValue()197 template<> cl_double AtomicTypeExtendedInfo<cl_double>::MinValue() {return CL_DBL_MIN;}
198
MaxValue()199 template<> cl_int AtomicTypeExtendedInfo<cl_int>::MaxValue() {return CL_INT_MAX;}
MaxValue()200 template<> cl_uint AtomicTypeExtendedInfo<cl_uint>::MaxValue() {return CL_UINT_MAX;}
MaxValue()201 template<> cl_long AtomicTypeExtendedInfo<cl_long>::MaxValue() {return CL_LONG_MAX;}
MaxValue()202 template<> cl_ulong AtomicTypeExtendedInfo<cl_ulong>::MaxValue() {return CL_ULONG_MAX;}
MaxValue()203 template<> cl_float AtomicTypeExtendedInfo<cl_float>::MaxValue() {return CL_FLT_MAX;}
MaxValue()204 template<> cl_double AtomicTypeExtendedInfo<cl_double>::MaxValue() {return CL_DBL_MAX;}
205
getSupportedMemoryOrdersAndScopes(cl_device_id device,std::vector<TExplicitMemoryOrderType> & memoryOrders,std::vector<TExplicitMemoryScopeType> & memoryScopes)206 cl_int getSupportedMemoryOrdersAndScopes(
207 cl_device_id device, std::vector<TExplicitMemoryOrderType> &memoryOrders,
208 std::vector<TExplicitMemoryScopeType> &memoryScopes)
209 {
210 // The CL_DEVICE_ATOMIC_MEMORY_CAPABILITES is missing before 3.0, but since
211 // all orderings and scopes are required for 2.X devices and this test is
212 // skipped before 2.0 we can safely return all orderings and scopes if the
213 // device is 2.X. Query device for the supported orders.
214 if (get_device_cl_version(device) < Version{ 3, 0 })
215 {
216 memoryOrders.push_back(MEMORY_ORDER_EMPTY);
217 memoryOrders.push_back(MEMORY_ORDER_RELAXED);
218 memoryOrders.push_back(MEMORY_ORDER_ACQUIRE);
219 memoryOrders.push_back(MEMORY_ORDER_RELEASE);
220 memoryOrders.push_back(MEMORY_ORDER_ACQ_REL);
221 memoryOrders.push_back(MEMORY_ORDER_SEQ_CST);
222 memoryScopes.push_back(MEMORY_SCOPE_EMPTY);
223 memoryScopes.push_back(MEMORY_SCOPE_WORK_GROUP);
224 memoryScopes.push_back(MEMORY_SCOPE_DEVICE);
225 memoryScopes.push_back(MEMORY_SCOPE_ALL_SVM_DEVICES);
226 return CL_SUCCESS;
227 }
228
229 // For a 3.0 device we can query the supported orderings and scopes
230 // directly.
231 cl_device_atomic_capabilities atomic_capabilities{};
232 test_error(
233 clGetDeviceInfo(device, CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES,
234 sizeof(atomic_capabilities), &atomic_capabilities,
235 nullptr),
236 "clGetDeviceInfo failed for CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES\n");
237
238 // Provided we succeeded, we can start filling the vectors.
239 if (atomic_capabilities & CL_DEVICE_ATOMIC_ORDER_RELAXED)
240 {
241 memoryOrders.push_back(MEMORY_ORDER_RELAXED);
242 }
243
244 if (atomic_capabilities & CL_DEVICE_ATOMIC_ORDER_ACQ_REL)
245 {
246 memoryOrders.push_back(MEMORY_ORDER_ACQUIRE);
247 memoryOrders.push_back(MEMORY_ORDER_RELEASE);
248 memoryOrders.push_back(MEMORY_ORDER_ACQ_REL);
249 }
250
251 if (atomic_capabilities & CL_DEVICE_ATOMIC_ORDER_SEQ_CST)
252 {
253 // The functions not ending in explicit have the same semantics as the
254 // corresponding explicit function with memory_order_seq_cst for the
255 // memory_order argument.
256 memoryOrders.push_back(MEMORY_ORDER_EMPTY);
257 memoryOrders.push_back(MEMORY_ORDER_SEQ_CST);
258 }
259
260 if (atomic_capabilities & CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP)
261 {
262 memoryScopes.push_back(MEMORY_SCOPE_WORK_GROUP);
263 }
264
265 if (atomic_capabilities & CL_DEVICE_ATOMIC_SCOPE_DEVICE)
266 {
267 // The functions that do not have memory_scope argument have the same
268 // semantics as the corresponding functions with the memory_scope
269 // argument set to memory_scope_device.
270 memoryScopes.push_back(MEMORY_SCOPE_EMPTY);
271 memoryScopes.push_back(MEMORY_SCOPE_DEVICE);
272 }
273 if (atomic_capabilities & CL_DEVICE_ATOMIC_SCOPE_ALL_DEVICES)
274 {
275 // OpenCL 3.0 added memory_scope_all_devices as an alias for
276 // memory_scope_all_svm_devices, so test both.
277 memoryScopes.push_back(MEMORY_SCOPE_ALL_DEVICES);
278 memoryScopes.push_back(MEMORY_SCOPE_ALL_SVM_DEVICES);
279 }
280 return CL_SUCCESS;
281 }
282