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