1 //
2 // Copyright (c) 2021 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 <iostream>
17 #include <vector>
18 #include "testBase.h"
19 #include "harness/errorHelpers.h"
20 #include "harness/typeWrappers.h"
21 #include "harness/kernelHelpers.h"
22
23 #define MINIMUM_OPENCL_PIPE_VERSION Version(2, 0)
24
25 static constexpr size_t KERNEL_ARGUMENT_LENGTH = 128;
26 static constexpr char KERNEL_ARGUMENT_NAME[] = "argument";
27 static constexpr int SINGLE_KERNEL_ARG_NUMBER = 0;
28 static constexpr int MAX_NUMBER_OF_KERNEL_ARGS = 128;
29
30 static const std::vector<cl_kernel_arg_address_qualifier> address_qualifiers = {
31 CL_KERNEL_ARG_ADDRESS_GLOBAL, CL_KERNEL_ARG_ADDRESS_LOCAL,
32 CL_KERNEL_ARG_ADDRESS_CONSTANT, CL_KERNEL_ARG_ADDRESS_PRIVATE
33 };
34
35 static const std::vector<std::string> image_arguments = {
36 "image2d_t", "image3d_t", "image2d_array_t",
37 "image1d_t", "image1d_buffer_t", "image1d_array_t"
38 };
39
40 static const std::vector<cl_kernel_arg_access_qualifier> access_qualifiers = {
41 CL_KERNEL_ARG_ACCESS_READ_WRITE, CL_KERNEL_ARG_ACCESS_READ_ONLY,
42 CL_KERNEL_ARG_ACCESS_WRITE_ONLY
43 };
44
45 static const std::vector<cl_kernel_arg_type_qualifier> type_qualifiers = {
46 CL_KERNEL_ARG_TYPE_NONE,
47 CL_KERNEL_ARG_TYPE_CONST,
48 CL_KERNEL_ARG_TYPE_VOLATILE,
49 CL_KERNEL_ARG_TYPE_RESTRICT,
50 CL_KERNEL_ARG_TYPE_CONST | CL_KERNEL_ARG_TYPE_VOLATILE,
51 CL_KERNEL_ARG_TYPE_CONST | CL_KERNEL_ARG_TYPE_RESTRICT,
52 CL_KERNEL_ARG_TYPE_VOLATILE | CL_KERNEL_ARG_TYPE_RESTRICT,
53 CL_KERNEL_ARG_TYPE_CONST | CL_KERNEL_ARG_TYPE_VOLATILE
54 | CL_KERNEL_ARG_TYPE_RESTRICT,
55 };
56
57 static const std::vector<cl_kernel_arg_type_qualifier> pipe_qualifiers = {
58 CL_KERNEL_ARG_TYPE_PIPE,
59 CL_KERNEL_ARG_TYPE_CONST | CL_KERNEL_ARG_TYPE_PIPE,
60 CL_KERNEL_ARG_TYPE_VOLATILE | CL_KERNEL_ARG_TYPE_PIPE,
61 CL_KERNEL_ARG_TYPE_CONST | CL_KERNEL_ARG_TYPE_VOLATILE
62 | CL_KERNEL_ARG_TYPE_PIPE,
63 };
64
65 static std::string
get_address_qualifier(cl_kernel_arg_address_qualifier address_qualifier)66 get_address_qualifier(cl_kernel_arg_address_qualifier address_qualifier)
67 {
68 std::string ret;
69 if (address_qualifier == CL_KERNEL_ARG_ADDRESS_GLOBAL)
70 ret = "global";
71 else if (address_qualifier == CL_KERNEL_ARG_ADDRESS_CONSTANT)
72 ret = "constant";
73 else if (address_qualifier == CL_KERNEL_ARG_ADDRESS_LOCAL)
74 ret = "local";
75 else if (address_qualifier == CL_KERNEL_ARG_ADDRESS_PRIVATE)
76 ret = "private";
77 return ret;
78 }
79
80 static std::string
get_access_qualifier(cl_kernel_arg_access_qualifier qualifier)81 get_access_qualifier(cl_kernel_arg_access_qualifier qualifier)
82 {
83 std::string ret;
84 if (qualifier == CL_KERNEL_ARG_ACCESS_READ_ONLY) ret = "read_only";
85 if (qualifier == CL_KERNEL_ARG_ACCESS_WRITE_ONLY) ret = "write_only";
86 if (qualifier == CL_KERNEL_ARG_ACCESS_READ_WRITE) ret = "read_write";
87 return ret;
88 }
89
90 static std::string
get_type_qualifier_prefix(cl_kernel_arg_type_qualifier type_qualifier)91 get_type_qualifier_prefix(cl_kernel_arg_type_qualifier type_qualifier)
92 {
93 std::string ret;
94 if (type_qualifier & CL_KERNEL_ARG_TYPE_CONST) ret += "const ";
95 if (type_qualifier & CL_KERNEL_ARG_TYPE_VOLATILE) ret += "volatile ";
96 if (type_qualifier & CL_KERNEL_ARG_TYPE_PIPE) ret += "pipe ";
97 return ret;
98 }
99
100 static std::string
get_type_qualifier_postfix(cl_kernel_arg_type_qualifier type_qualifier)101 get_type_qualifier_postfix(cl_kernel_arg_type_qualifier type_qualifier)
102 {
103 std::string ret;
104 if (type_qualifier & CL_KERNEL_ARG_TYPE_RESTRICT) ret = "restrict";
105 return ret;
106 }
107
108 class KernelArgInfo {
109 public:
KernelArgInfo(cl_kernel_arg_address_qualifier input_address_qualifier,cl_kernel_arg_access_qualifier input_access_qualifier,cl_kernel_arg_type_qualifier input_type_qualifier,const std::string & input_arg_type,const int argument_number,const std::string & input_arg_string="")110 KernelArgInfo(cl_kernel_arg_address_qualifier input_address_qualifier,
111 cl_kernel_arg_access_qualifier input_access_qualifier,
112 cl_kernel_arg_type_qualifier input_type_qualifier,
113 const std::string& input_arg_type, const int argument_number,
114 const std::string& input_arg_string = "")
115 : address_qualifier(input_address_qualifier),
116 access_qualifier(input_access_qualifier),
117 type_qualifier(input_type_qualifier), arg_string(input_arg_string)
118 {
119 strcpy(arg_type, input_arg_type.c_str());
120 std::string input_arg_name =
121 KERNEL_ARGUMENT_NAME + std::to_string(argument_number);
122 strcpy(arg_name, input_arg_name.c_str());
123 };
124 KernelArgInfo() = default;
125 cl_kernel_arg_address_qualifier address_qualifier;
126 cl_kernel_arg_access_qualifier access_qualifier;
127 cl_kernel_arg_type_qualifier type_qualifier;
128 char arg_type[KERNEL_ARGUMENT_LENGTH];
129 char arg_name[KERNEL_ARGUMENT_LENGTH];
130 std::string arg_string;
131 };
132
generate_argument(const KernelArgInfo & kernel_arg)133 static std::string generate_argument(const KernelArgInfo& kernel_arg)
134 {
135 std::string ret;
136
137 const bool is_image = strstr(kernel_arg.arg_type, "image")
138 || strstr(kernel_arg.arg_type, "sampler");
139 std::string address_qualifier = "";
140 // Image Objects are always allocated from the global address space so the
141 // qualifier should not be specified
142 if (!is_image)
143 {
144 address_qualifier = get_address_qualifier(kernel_arg.address_qualifier);
145 }
146
147 std::string access_qualifier =
148 get_access_qualifier(kernel_arg.access_qualifier);
149 std::string type_qualifier_prefix =
150 get_type_qualifier_prefix(kernel_arg.type_qualifier);
151 std::string type_qualifier_postfix =
152 get_type_qualifier_postfix(kernel_arg.type_qualifier);
153
154 ret += address_qualifier + " ";
155 ret += access_qualifier + " ";
156 ret += type_qualifier_prefix + " ";
157 ret += kernel_arg.arg_type;
158 ret += " ";
159 ret += type_qualifier_postfix + " ";
160 ret += kernel_arg.arg_name;
161 return ret;
162 }
163
164 /* This function generates a kernel source and allows for multiple arguments to
165 * be passed in and subsequently queried. */
generate_kernel(const std::vector<KernelArgInfo> & all_args,const bool supports_3d_image_writes=false,const bool kernel_uses_half_type=false)166 static std::string generate_kernel(const std::vector<KernelArgInfo>& all_args,
167 const bool supports_3d_image_writes = false,
168 const bool kernel_uses_half_type = false)
169 {
170
171 std::string ret;
172 if (supports_3d_image_writes)
173 {
174 ret += "#pragma OPENCL EXTENSION cl_khr_3d_image_writes: enable\n";
175 }
176 if (kernel_uses_half_type)
177 {
178 ret += "#pragma OPENCL EXTENSION cl_khr_fp16 : enable\n";
179 }
180 ret += "kernel void get_kernel_arg_info(\n";
181 for (size_t i = 0; i < all_args.size(); ++i)
182 {
183 ret += generate_argument(all_args[i]);
184 if (i == all_args.size() - 1)
185 {
186 ret += "\n";
187 }
188 else
189 {
190 ret += ",\n";
191 }
192 }
193 ret += "){}";
194 return ret;
195 }
196
get_kernel_arg_address_qualifier(cl_kernel_arg_address_qualifier address_qualifier)197 static const char* get_kernel_arg_address_qualifier(
198 cl_kernel_arg_address_qualifier address_qualifier)
199 {
200 switch (address_qualifier)
201 {
202 case CL_KERNEL_ARG_ADDRESS_GLOBAL: {
203 return "GLOBAL";
204 }
205 case CL_KERNEL_ARG_ADDRESS_LOCAL: {
206 return "LOCAL";
207 }
208 case CL_KERNEL_ARG_ADDRESS_CONSTANT: {
209 return "CONSTANT";
210 }
211 default: {
212 return "PRIVATE";
213 }
214 }
215 }
216
217 static const char*
get_kernel_arg_access_qualifier(cl_kernel_arg_access_qualifier access_qualifier)218 get_kernel_arg_access_qualifier(cl_kernel_arg_access_qualifier access_qualifier)
219 {
220 switch (access_qualifier)
221 {
222 case CL_KERNEL_ARG_ACCESS_READ_ONLY: {
223 return "READ_ONLY";
224 }
225 case CL_KERNEL_ARG_ACCESS_WRITE_ONLY: {
226 return "WRITE_ONLY";
227 }
228 case CL_KERNEL_ARG_ACCESS_READ_WRITE: {
229 return "READ_WRITE";
230 }
231 default: {
232 return "NONE";
233 }
234 }
235 }
236
237 std::string
get_kernel_arg_type_qualifier(cl_kernel_arg_type_qualifier type_qualifier)238 get_kernel_arg_type_qualifier(cl_kernel_arg_type_qualifier type_qualifier)
239 {
240 std::string ret;
241
242 if (type_qualifier & CL_KERNEL_ARG_TYPE_CONST) ret += "CONST ";
243 if (type_qualifier & CL_KERNEL_ARG_TYPE_RESTRICT) ret += "RESTRICT ";
244 if (type_qualifier & CL_KERNEL_ARG_TYPE_VOLATILE) ret += "VOLATILE ";
245 if (type_qualifier & CL_KERNEL_ARG_TYPE_PIPE) ret += "PIPE";
246
247 return ret;
248 }
249
output_difference(const KernelArgInfo & expected,const KernelArgInfo & actual)250 static void output_difference(const KernelArgInfo& expected,
251 const KernelArgInfo& actual)
252 {
253 if (actual.address_qualifier != expected.address_qualifier)
254 {
255 log_error("Address Qualifier: Expected: %s\t Actual: %s\n",
256 get_kernel_arg_address_qualifier(expected.address_qualifier),
257 get_kernel_arg_address_qualifier(actual.address_qualifier));
258 }
259 if (actual.access_qualifier != expected.access_qualifier)
260 {
261 log_error("Access Qualifier: Expected: %s\t Actual: %s\n",
262 get_kernel_arg_access_qualifier(expected.access_qualifier),
263 get_kernel_arg_access_qualifier(actual.access_qualifier));
264 }
265 if (actual.type_qualifier != expected.type_qualifier)
266 {
267 log_error(
268 "Type Qualifier: Expected: %s\t Actual: %s\n",
269 get_kernel_arg_type_qualifier(expected.type_qualifier).c_str(),
270 get_kernel_arg_type_qualifier(actual.type_qualifier).c_str());
271 }
272 if (strcmp(actual.arg_type, expected.arg_type) != 0)
273 {
274 log_error("Arg Type: Expected: %s\t Actual: %s\n", expected.arg_type,
275 actual.arg_type);
276 }
277 if (strcmp(actual.arg_name, expected.arg_name) != 0)
278 {
279 log_error("Arg Name: Expected: %s\t Actual: %s\n", expected.arg_name,
280 actual.arg_name);
281 }
282 log_error("Argument in Kernel Source Reported as:\n%s\n",
283 expected.arg_string.c_str());
284 }
compare_expected_actual(const KernelArgInfo & expected,const KernelArgInfo & actual)285 static int compare_expected_actual(const KernelArgInfo& expected,
286 const KernelArgInfo& actual)
287 {
288 ++gTestCount;
289 int ret = TEST_PASS;
290 if ((actual.address_qualifier != expected.address_qualifier)
291 || (actual.access_qualifier != expected.access_qualifier)
292 || (actual.type_qualifier != expected.type_qualifier)
293 || (strcmp(actual.arg_type, expected.arg_type) != 0)
294 || (strcmp(actual.arg_name, expected.arg_name) != 0))
295 {
296 ret = TEST_FAIL;
297 output_difference(expected, actual);
298 ++gFailCount;
299 }
300 return ret;
301 }
302
device_supports_pipes(cl_device_id deviceID)303 static bool device_supports_pipes(cl_device_id deviceID)
304 {
305 auto version = get_device_cl_version(deviceID);
306 if (version < MINIMUM_OPENCL_PIPE_VERSION)
307 {
308 return false;
309 }
310 cl_uint max_packet_size = 0;
311 cl_int err =
312 clGetDeviceInfo(deviceID, CL_DEVICE_PIPE_MAX_PACKET_SIZE,
313 sizeof(max_packet_size), &max_packet_size, nullptr);
314 test_error_ret(err, "clGetDeviceInfo", false);
315 if ((max_packet_size == 0) && (version >= Version(3, 0)))
316 {
317 return false;
318 }
319 return true;
320 }
321
get_build_options(cl_device_id deviceID)322 static std::string get_build_options(cl_device_id deviceID)
323 {
324 std::string ret = "-cl-kernel-arg-info";
325 if (get_device_cl_version(deviceID) >= MINIMUM_OPENCL_PIPE_VERSION)
326 {
327 if (device_supports_pipes(deviceID))
328 {
329 if (get_device_cl_version(deviceID) >= Version(3, 0))
330 {
331 ret += " -cl-std=CL3.0";
332 }
333 else
334 {
335 ret += " -cl-std=CL2.0";
336 }
337 }
338 }
339 return ret;
340 }
341
get_expected_arg_type(const std::string & type_string,const bool is_pointer)342 static std::string get_expected_arg_type(const std::string& type_string,
343 const bool is_pointer)
344 {
345 bool is_unsigned = false;
346 std::istringstream type_stream(type_string);
347 std::string base_type = "";
348 std::string ret = "";
349 /* Signed and Unsigned on their own represent an int */
350 if (type_string == "signed" || type_string == "signed*")
351 {
352 base_type = "int";
353 }
354 else if (type_string == "unsigned" || type_string == "unsigned*")
355 {
356 base_type = "int";
357 is_unsigned = true;
358 }
359 else
360 {
361 std::string token;
362 /* Iterate through the argument type to determine what the type is and
363 * whether or not it is signed */
364 while (std::getline(type_stream, token, ' '))
365 {
366 if (token.find("unsigned") != std::string::npos)
367 {
368 is_unsigned = true;
369 }
370 if (token.find("signed") == std::string::npos)
371 {
372 base_type = token;
373 }
374 }
375 }
376 ret = base_type;
377 if (is_unsigned)
378 {
379 ret.insert(0, "u");
380 }
381 /* Ensure that the data type is a pointer if it is not already when
382 * necessary */
383 if (is_pointer && ret.back() != '*')
384 {
385 ret += "*";
386 }
387 return ret;
388 }
389
390 static KernelArgInfo
create_expected_arg_info(const KernelArgInfo & kernel_argument,bool is_pointer)391 create_expected_arg_info(const KernelArgInfo& kernel_argument, bool is_pointer)
392 {
393 KernelArgInfo ret = kernel_argument;
394 const std::string arg_string = generate_argument(kernel_argument);
395 ret.arg_string = arg_string;
396
397 std::string type_string(kernel_argument.arg_type);
398 /* We only need to modify the expected return values for scalar types */
399 if ((is_pointer && !isdigit(type_string.back() - 1))
400 || !isdigit(type_string.back()))
401 {
402 std::string expected_arg_type =
403 get_expected_arg_type(type_string, is_pointer);
404
405 /* Reset the Contents of expected arg_type char[] and then assign it to
406 * the expected value */
407 memset(ret.arg_type, 0, sizeof(ret.arg_type));
408 strcpy(ret.arg_type, expected_arg_type.c_str());
409 }
410
411 /* Any values passed by reference has TYPE_NONE */
412 if (!is_pointer)
413 {
414 ret.type_qualifier = CL_KERNEL_ARG_TYPE_NONE;
415 }
416
417 /* If the address qualifier is CONSTANT we expect to see the TYPE_CONST
418 * qualifier*/
419 if (kernel_argument.address_qualifier == CL_KERNEL_ARG_ADDRESS_CONSTANT)
420 {
421 ret.type_qualifier |= CL_KERNEL_ARG_TYPE_CONST;
422 }
423
424 /* The PIPE qualifier is special. It can only be used in a global scope. It
425 * also ignores any other qualifiers */
426 if (kernel_argument.type_qualifier & CL_KERNEL_ARG_TYPE_PIPE)
427 {
428 ret.address_qualifier = CL_KERNEL_ARG_ADDRESS_GLOBAL;
429 ret.type_qualifier = CL_KERNEL_ARG_TYPE_PIPE;
430 }
431
432 return ret;
433 }
434
435 /* There are too many vector arguments for it to be worth writing down
436 * statically and are instead generated here and combined with all of the scalar
437 * and unsigned scalar types in a single data structure */
438 static std::vector<std::string>
generate_all_type_arguments(cl_device_id deviceID)439 generate_all_type_arguments(cl_device_id deviceID)
440 {
441 std::vector<std::string> ret = {
442 "char", "short", "int", "float",
443 "void", "uchar", "unsigned char", "ushort",
444 "unsigned short", "uint", "unsigned int", "char unsigned",
445 "short unsigned", "int unsigned", "signed short", "signed int",
446 "signed long", "short signed", "int signed", "signed",
447 "unsigned"
448 };
449
450 std::vector<std::string> vector_types = { "char", "uchar", "short",
451 "ushort", "int", "uint",
452 "float" };
453 if (gHasLong)
454 {
455 ret.push_back("long");
456 ret.push_back("ulong");
457 ret.push_back("unsigned long");
458 ret.push_back("long unsigned");
459 ret.push_back("long signed");
460 vector_types.push_back("long");
461 vector_types.push_back("ulong");
462 }
463 if (device_supports_half(deviceID))
464 {
465 vector_types.push_back("half");
466 }
467 if (device_supports_double(deviceID))
468 {
469 vector_types.push_back("double");
470 }
471 static const std::vector<std::string> vector_values = { "2", "3", "4", "8",
472 "16" };
473 for (auto vector_type : vector_types)
474 {
475 for (auto vector_value : vector_values)
476 {
477 ret.push_back(vector_type + vector_value);
478 }
479 }
480 return ret;
481 }
482
483 static int
compare_kernel_with_expected(cl_context context,cl_device_id deviceID,const char * kernel_src,const std::vector<KernelArgInfo> & expected_args)484 compare_kernel_with_expected(cl_context context, cl_device_id deviceID,
485 const char* kernel_src,
486 const std::vector<KernelArgInfo>& expected_args)
487 {
488 int failed_tests = 0;
489 clKernelWrapper kernel;
490 clProgramWrapper program;
491 cl_int err = create_single_kernel_helper_with_build_options(
492 context, &program, &kernel, 1, &kernel_src, "get_kernel_arg_info",
493 get_build_options(deviceID).c_str());
494 test_error(err, "create_single_kernel_helper_with_build_options");
495 for (size_t i = 0; i < expected_args.size(); ++i)
496 {
497 KernelArgInfo actual;
498 err = clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_ADDRESS_QUALIFIER,
499 sizeof(actual.address_qualifier),
500 &(actual.address_qualifier), nullptr);
501 test_error(err, "clGetKernelArgInfo");
502
503 err = clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_ACCESS_QUALIFIER,
504 sizeof(actual.access_qualifier),
505 &(actual.access_qualifier), nullptr);
506 test_error(err, "clGetKernelArgInfo");
507
508 err = clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_TYPE_QUALIFIER,
509 sizeof(actual.type_qualifier),
510 &(actual.type_qualifier), nullptr);
511 test_error(err, "clGetKernelArgInfo");
512
513 err = clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_TYPE_NAME,
514 sizeof(actual.arg_type), &(actual.arg_type),
515 nullptr);
516 test_error(err, "clGetKernelArgInfo");
517
518 err = clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_NAME,
519 sizeof(actual.arg_name), &(actual.arg_name),
520 nullptr);
521 test_error(err, "clGetKernelArgInfo");
522
523 failed_tests += compare_expected_actual(expected_args[i], actual);
524 }
525 return failed_tests;
526 }
527
get_param_size(const std::string & arg_type,cl_device_id deviceID,bool is_pipe)528 size_t get_param_size(const std::string& arg_type, cl_device_id deviceID,
529 bool is_pipe)
530 {
531 if (is_pipe)
532 {
533 return (sizeof(int*));
534 }
535 if (arg_type.find("*") != std::string::npos)
536 {
537 cl_uint device_address_bits = 0;
538 cl_int err = clGetDeviceInfo(deviceID, CL_DEVICE_ADDRESS_BITS,
539 sizeof(device_address_bits),
540 &device_address_bits, NULL);
541 test_error_ret(err, "clGetDeviceInfo", 0);
542 return (device_address_bits / 8);
543 }
544
545 size_t ret(0);
546 if (arg_type.find("char") != std::string::npos)
547 {
548 ret += sizeof(cl_char);
549 }
550 if (arg_type.find("short") != std::string::npos)
551 {
552 ret += sizeof(cl_short);
553 }
554 if (arg_type.find("half") != std::string::npos)
555 {
556 ret += sizeof(cl_half);
557 }
558 if (arg_type.find("int") != std::string::npos)
559 {
560 ret += sizeof(cl_int);
561 }
562 if (arg_type.find("long") != std::string::npos)
563 {
564 ret += sizeof(cl_long);
565 }
566 if (arg_type.find("float") != std::string::npos)
567 {
568 ret += sizeof(cl_float);
569 }
570 if (arg_type.find("double") != std::string::npos)
571 {
572 ret += sizeof(cl_double);
573 }
574 if (arg_type.back() == '2')
575 {
576 ret *= 2;
577 }
578 if (arg_type.back() == '3')
579 {
580 ret *= 4;
581 }
582 if (arg_type.back() == '4')
583 {
584 ret *= 4;
585 }
586 if (arg_type.back() == '8')
587 {
588 ret *= 8;
589 }
590 // If the last character is a 6 it represents a vector of 16
591 if (arg_type.back() == '6')
592 {
593 ret *= 16;
594 }
595 return ret;
596 }
597
run_scalar_vector_tests(cl_context context,cl_device_id deviceID)598 static int run_scalar_vector_tests(cl_context context, cl_device_id deviceID)
599 {
600 int failed_tests = 0;
601
602 std::vector<std::string> type_arguments =
603 generate_all_type_arguments(deviceID);
604
605 const std::vector<cl_kernel_arg_access_qualifier> access_qualifiers = {
606 CL_KERNEL_ARG_ACCESS_NONE, CL_KERNEL_ARG_ACCESS_READ_ONLY,
607 CL_KERNEL_ARG_ACCESS_WRITE_ONLY
608 };
609
610 std::vector<KernelArgInfo> all_args, expected_args;
611 size_t max_param_size = get_max_param_size(deviceID);
612 size_t total_param_size(0);
613 for (auto address_qualifier : address_qualifiers)
614 {
615 bool is_private = (address_qualifier == CL_KERNEL_ARG_ADDRESS_PRIVATE);
616
617 /* OpenCL kernels cannot take "private" pointers and only "private"
618 * variables can take values */
619 bool is_pointer = !is_private;
620
621 for (auto type_qualifier : type_qualifiers)
622 {
623 bool is_pipe = (type_qualifier & CL_KERNEL_ARG_TYPE_PIPE);
624 bool is_restrict = (type_qualifier & CL_KERNEL_ARG_TYPE_RESTRICT);
625
626 for (auto access_qualifier : access_qualifiers)
627 {
628 bool has_access_qualifier =
629 (access_qualifier != CL_KERNEL_ARG_ACCESS_NONE);
630
631 /*Only images and pipes can have an access qualifier,
632 * otherwise it should be ACCESS_NONE */
633 if (!is_pipe && has_access_qualifier)
634 {
635 continue;
636 }
637
638 /* If the type is a pipe, then either the specified or
639 * default access qualifier is returned and so "NONE" will
640 * never be returned */
641 if (is_pipe && !has_access_qualifier)
642 {
643 continue;
644 }
645
646 /* The "restrict" type qualifier can only apply to
647 * pointers
648 */
649 if (is_restrict && !is_pointer)
650 {
651 continue;
652 }
653
654 /* We cannot have pipe pointers */
655 if (is_pipe && is_pointer)
656 {
657 continue;
658 }
659
660
661 for (auto arg_type : type_arguments)
662 {
663 /* Void Types cannot be private */
664 if (is_private && arg_type == "void")
665 {
666 continue;
667 }
668
669 if (is_pointer)
670 {
671 arg_type += "*";
672 }
673 size_t param_size =
674 get_param_size(arg_type, deviceID, is_pipe);
675 if (param_size + total_param_size >= max_param_size
676 || all_args.size() == MAX_NUMBER_OF_KERNEL_ARGS)
677 {
678 const std::string kernel_src = generate_kernel(
679 all_args, false, device_supports_half(deviceID));
680 failed_tests += compare_kernel_with_expected(
681 context, deviceID, kernel_src.c_str(),
682 expected_args);
683 all_args.clear();
684 expected_args.clear();
685 total_param_size = 0;
686 }
687 total_param_size += param_size;
688
689 KernelArgInfo kernel_argument(
690 address_qualifier, access_qualifier, type_qualifier,
691 arg_type, all_args.size());
692
693 expected_args.push_back(
694 create_expected_arg_info(kernel_argument, is_pointer));
695
696 all_args.push_back(kernel_argument);
697 }
698 }
699 }
700 }
701 const std::string kernel_src =
702 generate_kernel(all_args, false, device_supports_half(deviceID));
703 failed_tests += compare_kernel_with_expected(
704 context, deviceID, kernel_src.c_str(), expected_args);
705 return failed_tests;
706 }
707
get_max_number_of_pipes(cl_device_id deviceID,cl_int & err)708 static cl_uint get_max_number_of_pipes(cl_device_id deviceID, cl_int& err)
709 {
710 cl_uint ret(0);
711 err = clGetDeviceInfo(deviceID, CL_DEVICE_MAX_PIPE_ARGS, sizeof(ret), &ret,
712 nullptr);
713 return ret;
714 }
715
run_pipe_tests(cl_context context,cl_device_id deviceID)716 static int run_pipe_tests(cl_context context, cl_device_id deviceID)
717 {
718 int failed_tests = 0;
719
720 cl_kernel_arg_address_qualifier address_qualifier =
721 CL_KERNEL_ARG_ADDRESS_PRIVATE;
722 std::vector<std::string> type_arguments =
723 generate_all_type_arguments(deviceID);
724 const std::vector<cl_kernel_arg_access_qualifier> access_qualifiers = {
725 CL_KERNEL_ARG_ACCESS_READ_ONLY, CL_KERNEL_ARG_ACCESS_WRITE_ONLY
726 };
727 std::vector<KernelArgInfo> all_args, expected_args;
728 size_t max_param_size = get_max_param_size(deviceID);
729 size_t total_param_size(0);
730 cl_int err = CL_SUCCESS;
731 cl_uint max_number_of_pipes = get_max_number_of_pipes(deviceID, err);
732 test_error_ret(err, "get_max_number_of_pipes", TEST_FAIL);
733 cl_uint number_of_pipes(0);
734
735 const bool is_pointer = false;
736 const bool is_pipe = true;
737
738 for (auto type_qualifier : pipe_qualifiers)
739 {
740 for (auto access_qualifier : access_qualifiers)
741 {
742 for (auto arg_type : type_arguments)
743 {
744 /* We cannot have void pipes */
745 if (arg_type == "void")
746 {
747 continue;
748 }
749
750 size_t param_size = get_param_size(arg_type, deviceID, is_pipe);
751 if (param_size + total_param_size >= max_param_size
752 || number_of_pipes == max_number_of_pipes)
753 {
754 const std::string kernel_src = generate_kernel(all_args);
755 failed_tests += compare_kernel_with_expected(
756 context, deviceID, kernel_src.c_str(), expected_args);
757 all_args.clear();
758 expected_args.clear();
759 total_param_size = 0;
760 number_of_pipes = 0;
761 }
762 total_param_size += param_size;
763 number_of_pipes++;
764
765 KernelArgInfo kernel_argument(address_qualifier,
766 access_qualifier, type_qualifier,
767 arg_type, all_args.size());
768
769 expected_args.push_back(
770 create_expected_arg_info(kernel_argument, is_pointer));
771
772 all_args.push_back(kernel_argument);
773 }
774 }
775 }
776 const std::string kernel_src = generate_kernel(all_args);
777 failed_tests += compare_kernel_with_expected(
778 context, deviceID, kernel_src.c_str(), expected_args);
779 return failed_tests;
780 }
781
run_sampler_test(cl_context context,cl_device_id deviceID)782 static int run_sampler_test(cl_context context, cl_device_id deviceID)
783 {
784 cl_kernel_arg_address_qualifier address_qualifier =
785 CL_KERNEL_ARG_ADDRESS_PRIVATE;
786 cl_kernel_arg_type_qualifier type_qualifier = CL_KERNEL_ARG_TYPE_NONE;
787 cl_kernel_arg_access_qualifier access_qualifier = CL_KERNEL_ARG_ACCESS_NONE;
788 std::string image_type = "sampler_t";
789 bool is_pointer = false;
790
791 KernelArgInfo kernel_argument(address_qualifier, access_qualifier,
792 type_qualifier, image_type,
793 SINGLE_KERNEL_ARG_NUMBER);
794
795 KernelArgInfo expected =
796 create_expected_arg_info(kernel_argument, is_pointer);
797
798 const std::string kernel_src = generate_kernel({ kernel_argument });
799
800 return compare_kernel_with_expected(context, deviceID, kernel_src.c_str(),
801 { expected });
802 }
803
run_image_tests(cl_context context,cl_device_id deviceID)804 static int run_image_tests(cl_context context, cl_device_id deviceID)
805 {
806 int failed_tests = 0;
807 bool supports_3d_image_writes =
808 is_extension_available(deviceID, "cl_khr_3d_image_writes");
809 bool is_pointer = false;
810 cl_kernel_arg_type_qualifier type_qualifier = CL_KERNEL_ARG_TYPE_NONE;
811 cl_kernel_arg_address_qualifier address_qualifier =
812 CL_KERNEL_ARG_ADDRESS_GLOBAL;
813
814 Version version = get_device_cl_version(deviceID);
815 bool supports_read_write_images = false;
816 if (version >= Version(3, 0))
817 {
818 cl_uint maxReadWriteImageArgs = 0;
819 cl_int error = clGetDeviceInfo(
820 deviceID, CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS,
821 sizeof(maxReadWriteImageArgs), &maxReadWriteImageArgs, NULL);
822 test_error(error,
823 "Unable to query "
824 "CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS");
825
826 // read-write images are supported if MAX_READ_WRITE_IMAGE_ARGS is
827 // nonzero
828 supports_read_write_images = maxReadWriteImageArgs != 0;
829 }
830 else if (version >= Version(2, 0))
831 {
832 // read-write images are required for OpenCL 2.x
833 supports_read_write_images = true;
834 }
835
836 for (auto access_qualifier : access_qualifiers)
837 {
838 if (access_qualifier == CL_KERNEL_ARG_ACCESS_READ_WRITE
839 && !supports_read_write_images)
840 continue;
841
842 bool is_write =
843 (access_qualifier == CL_KERNEL_ARG_ACCESS_WRITE_ONLY
844 || access_qualifier == CL_KERNEL_ARG_ACCESS_READ_WRITE);
845 for (auto image_type : image_arguments)
846 {
847 bool is_3d_image = image_type == "image3d_t";
848 /* We can only test 3d image writes if our device supports it */
849 if (is_3d_image && is_write)
850 {
851 if (!supports_3d_image_writes)
852 {
853 continue;
854 }
855 }
856 KernelArgInfo kernel_argument(address_qualifier, access_qualifier,
857 type_qualifier, image_type,
858 SINGLE_KERNEL_ARG_NUMBER);
859 KernelArgInfo expected =
860 create_expected_arg_info(kernel_argument, is_pointer);
861 const std::string kernel_src =
862 generate_kernel({ kernel_argument }, supports_3d_image_writes);
863
864 failed_tests += compare_kernel_with_expected(
865 context, deviceID, kernel_src.c_str(), { expected });
866 }
867 }
868 failed_tests += run_sampler_test(context, deviceID);
869 return failed_tests;
870 }
871
872 /* Ensure clGetKernelArgInfo returns successfully when param_value is
873 * set to null */
test_null_param(cl_context context,cl_device_id deviceID,char const * kernel_src)874 static int test_null_param(cl_context context, cl_device_id deviceID,
875 char const* kernel_src)
876 {
877 clProgramWrapper program;
878 clKernelWrapper kernel;
879 cl_int err = create_single_kernel_helper_with_build_options(
880 context, &program, &kernel, 1, &kernel_src, "get_kernel_arg_info",
881 get_build_options(deviceID).c_str());
882 test_error_ret(err, "create_single_kernel_helper_with_build_options",
883 TEST_FAIL);
884
885 err = clGetKernelArgInfo(kernel, SINGLE_KERNEL_ARG_NUMBER,
886 CL_KERNEL_ARG_ADDRESS_QUALIFIER, 0, nullptr,
887 nullptr);
888 test_error_ret(err, "clGetKernelArgInfo", TEST_FAIL);
889
890 err =
891 clGetKernelArgInfo(kernel, SINGLE_KERNEL_ARG_NUMBER,
892 CL_KERNEL_ARG_ACCESS_QUALIFIER, 0, nullptr, nullptr);
893 test_error_ret(err, "clGetKernelArgInfo", TEST_FAIL);
894
895 err = clGetKernelArgInfo(kernel, SINGLE_KERNEL_ARG_NUMBER,
896 CL_KERNEL_ARG_TYPE_QUALIFIER, 0, nullptr, nullptr);
897 test_error_ret(err, "clGetKernelArgInfo", TEST_FAIL);
898
899 err = clGetKernelArgInfo(kernel, SINGLE_KERNEL_ARG_NUMBER,
900 CL_KERNEL_ARG_TYPE_NAME, 0, nullptr, nullptr);
901 test_error_ret(err, "clGetKernelArgInfo", TEST_FAIL);
902
903 err = clGetKernelArgInfo(kernel, SINGLE_KERNEL_ARG_NUMBER,
904 CL_KERNEL_ARG_NAME, 0, nullptr, nullptr);
905 test_error_ret(err, "clGetKernelArgInfo", TEST_FAIL);
906
907 return TEST_PASS;
908 }
909
910 /* Ensure clGetKernelArgInfo returns the correct size in bytes for the
911 * kernel arg name */
test_arg_name_size(cl_context context,cl_device_id deviceID,char const * kernel_src)912 static int test_arg_name_size(cl_context context, cl_device_id deviceID,
913 char const* kernel_src)
914 {
915 size_t size;
916 /* We are adding +1 because the argument used in this kernel is argument0
917 * which has 1 extra character than just the base argument name */
918 char arg_return[sizeof(KERNEL_ARGUMENT_NAME) + 1];
919 clProgramWrapper program;
920 clKernelWrapper kernel;
921 cl_int err = create_single_kernel_helper_with_build_options(
922 context, &program, &kernel, 1, &kernel_src, "get_kernel_arg_info",
923 get_build_options(deviceID).c_str());
924
925 test_error_ret(err, "create_single_kernel_helper_with_build_options",
926 TEST_FAIL);
927
928 err =
929 clGetKernelArgInfo(kernel, SINGLE_KERNEL_ARG_NUMBER, CL_KERNEL_ARG_NAME,
930 sizeof(arg_return), &arg_return, &size);
931 test_error_ret(err, "clGetKernelArgInfo", TEST_FAIL);
932 if (size == sizeof(KERNEL_ARGUMENT_NAME) + 1)
933 {
934 return TEST_PASS;
935 }
936 else
937 {
938 return TEST_FAIL;
939 }
940 }
941
run_boundary_tests(cl_context context,cl_device_id deviceID)942 static int run_boundary_tests(cl_context context, cl_device_id deviceID)
943 {
944 int failed_tests = 0;
945
946 cl_kernel_arg_address_qualifier address_qualifier =
947 CL_KERNEL_ARG_ADDRESS_GLOBAL;
948 cl_kernel_arg_access_qualifier access_qualifier = CL_KERNEL_ARG_ACCESS_NONE;
949 cl_kernel_arg_type_qualifier type_qualifier = CL_KERNEL_ARG_TYPE_NONE;
950 std::string arg_type = "int*";
951 KernelArgInfo arg_info(address_qualifier, access_qualifier, type_qualifier,
952 arg_type, SINGLE_KERNEL_ARG_NUMBER);
953 const std::string kernel_src = generate_kernel({ arg_info });
954
955 failed_tests += test_arg_name_size(context, deviceID, kernel_src.c_str());
956
957 if (test_null_param(context, deviceID, kernel_src.c_str()) != TEST_PASS)
958 {
959 failed_tests++;
960 }
961
962 return failed_tests;
963 }
964
run_all_tests(cl_context context,cl_device_id deviceID)965 static int run_all_tests(cl_context context, cl_device_id deviceID)
966 {
967
968 int failed_scalar_tests = run_scalar_vector_tests(context, deviceID);
969 if (failed_scalar_tests == 0)
970 {
971 log_info("All Data Type Tests Passed\n");
972 }
973 else
974 {
975 log_error("%d Data Type Test(s) Failed\n", failed_scalar_tests);
976 }
977
978 int failed_image_tests = 0;
979 if (checkForImageSupport(deviceID) == 0)
980 {
981 failed_image_tests = run_image_tests(context, deviceID);
982 if (failed_image_tests == 0)
983 {
984 log_info("All Image Tests Passed\n");
985 }
986 else
987 {
988 log_error("%d Image Test(s) Failed\n", failed_image_tests);
989 }
990 }
991 int failed_pipe_tests = 0;
992 // TODO https://github.com/KhronosGroup/OpenCL-CTS/issues/1244
993 if (false)
994 {
995 failed_pipe_tests = run_pipe_tests(context, deviceID);
996 if (failed_pipe_tests == 0)
997 {
998 log_info("All Pipe Tests Passed\n");
999 }
1000 else
1001 {
1002 log_error("%d Pipe Test(s) Failed\n", failed_pipe_tests);
1003 }
1004 }
1005
1006 int failed_boundary_tests = run_boundary_tests(context, deviceID);
1007 if (failed_boundary_tests == 0)
1008 {
1009 log_info("All Edge Case Tests Passed\n");
1010 }
1011 else
1012 {
1013 log_error("%d Edge Case Test(s) Failed\n", failed_boundary_tests);
1014 }
1015
1016 return (failed_scalar_tests + failed_image_tests + failed_pipe_tests
1017 + failed_boundary_tests);
1018 }
1019
test_get_kernel_arg_info(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)1020 int test_get_kernel_arg_info(cl_device_id deviceID, cl_context context,
1021 cl_command_queue queue, int num_elements)
1022 {
1023 int failed_tests = run_all_tests(context, deviceID);
1024 if (failed_tests != 0)
1025 {
1026 log_error("%d Test(s) Failed\n", failed_tests);
1027 return TEST_FAIL;
1028 }
1029 else
1030 {
1031 return TEST_PASS;
1032 }
1033 }
1034