xref: /aosp_15_r20/external/OpenCL-CTS/test_conformance/api/test_kernel_arg_info.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
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