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