1 /* OpenCL runtime library: clSetKernelArg()
2 
3    Copyright (c) 2011 Universidad Rey Juan Carlos
4                  2013 Pekka Jääskeläinen / Tampere University of Technology
5 
6    Permission is hereby granted, free of charge, to any person obtaining a copy
7    of this software and associated documentation files (the "Software"), to deal
8    in the Software without restriction, including without limitation the rights
9    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10    copies of the Software, and to permit persons to whom the Software is
11    furnished to do so, subject to the following conditions:
12 
13    The above copyright notice and this permission notice shall be included in
14    all copies or substantial portions of the Software.
15 
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22    THE SOFTWARE.
23 */
24 
25 #include "config.h"
26 #include "pocl_cl.h"
27 #include "pocl_debug.h"
28 #include "pocl_util.h"
29 #include <assert.h>
30 #include <stdbool.h>
31 #include <string.h>
32 
33 static char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
34                       '9', 'A', 'B', 'C', 'D', 'E', 'F', 'X', 'Y' };
35 
36 static void
dump_hex(const char * data,size_t size,char * buffer)37 dump_hex (const char *data, size_t size, char *buffer)
38 {
39   size_t j = 0;
40   for (size_t i = 0; i < size; ++i)
41     {
42       if (i % 4 == 0)
43         buffer[j++] = ' ';
44       char c = data[i];
45       buffer[j] = hex[(c & 0xF0) >> 4];
46       buffer[j + 1] = hex[c & 0x0F];
47       j += 2;
48     }
49   buffer[j] = 0;
50 }
51 
52 CL_API_ENTRY cl_int CL_API_CALL
POname(clSetKernelArg)53 POname(clSetKernelArg)(cl_kernel kernel,
54                cl_uint arg_index,
55                size_t arg_size,
56                const void *arg_value) CL_API_SUFFIX__VERSION_1_0
57 {
58   size_t arg_alignment, arg_alloc_size;
59   struct pocl_argument *p;
60   struct pocl_argument_info *pi;
61 
62   POCL_RETURN_ERROR_COND ((!IS_CL_OBJECT_VALID (kernel)), CL_INVALID_KERNEL);
63 
64   POCL_RETURN_ERROR_ON ((arg_index >= kernel->meta->num_args),
65                         CL_INVALID_ARG_INDEX,
66                         "This kernel has %u args, cannot set arg %u\n",
67                         (unsigned)kernel->meta->num_args, (unsigned)arg_index);
68 
69   POCL_RETURN_ERROR_ON((kernel->dyn_arguments == NULL), CL_INVALID_KERNEL,
70     "This kernel has no arguments that could be set\n");
71 
72   pi = &(kernel->meta->arg_info[arg_index]);
73   int is_local = ARGP_IS_LOCAL (pi);
74 
75   const void *ptr_value = NULL;
76   if (((pi->type == POCL_ARG_TYPE_POINTER)
77        || (pi->type == POCL_ARG_TYPE_IMAGE))
78       && arg_value)
79     ptr_value = *(const void **)arg_value;
80 
81   if (POCL_DEBUGGING_ON)
82     {
83       const void *ptr_value = NULL;
84       uint32_t uint32_value = 0;
85       uint64_t uint64_value = 0;
86       if (((pi->type == POCL_ARG_TYPE_POINTER)
87            || (pi->type == POCL_ARG_TYPE_IMAGE))
88           && arg_value)
89         {
90           ptr_value = *(const void **)arg_value;
91         }
92       else
93         {
94           if (arg_value && (arg_size == 4))
95             uint32_value = *(uint32_t *)arg_value;
96           if (arg_value && (arg_size == 8))
97             uint64_value = *(uint64_t *)arg_value;
98         }
99 
100       char *hexval = NULL;
101       if (arg_value && (arg_size < 1024))
102         {
103           hexval = (char *)alloca ((arg_size * 2) + (arg_size / 4) + 8);
104           dump_hex (arg_value, arg_size, hexval);
105         }
106 
107       POCL_MSG_PRINT_GENERAL ("Kernel %15s || SetArg idx %3u || %8s || "
108                               "Local %1i || Size %6zu || Value %p || "
109                               "Pointer %p || *(uint32*)Value: %8u || "
110                               "*(uint64*)Value: %8lu ||\nHex Value: %s\n",
111                               kernel->name, arg_index, pi->type_name, is_local,
112                               arg_size, arg_value, ptr_value, uint32_value,
113                               uint64_value, hexval);
114     }
115 
116   POCL_RETURN_ERROR_ON (
117       ((arg_value != NULL) && is_local), CL_INVALID_ARG_VALUE,
118       "arg_value != NULL and arg %u is in local address space\n", arg_index);
119 
120   /* Trigger CL_INVALID_ARG_VALUE if arg_value specified is NULL
121    * for an argument that is not declared with the __local qualifier. */
122   POCL_RETURN_ERROR_ON (
123       ((arg_value == NULL) && (!is_local)
124        && (pi->type != POCL_ARG_TYPE_POINTER)),
125       CL_INVALID_ARG_VALUE,
126       "arg_value == NULL and arg %u is not in local address space\n",
127       arg_index);
128 
129   /* Trigger CL_INVALID_ARG_SIZE if arg_size is zero
130    * and the argument is declared with the __local qualifier. */
131   POCL_RETURN_ERROR_ON (((arg_size == 0) && is_local), CL_INVALID_ARG_SIZE,
132                         "arg_size == 0 and arg %u is in local address space\n",
133                         arg_index);
134 
135   POCL_RETURN_ERROR_ON (
136       ((pi->type == POCL_ARG_TYPE_SAMPLER) && (arg_value == NULL)),
137       CL_INVALID_SAMPLER, "arg_value == NULL and arg is a cl_sampler\n");
138 
139   if (pi->type == POCL_ARG_TYPE_POINTER || pi->type == POCL_ARG_TYPE_IMAGE
140       || pi->type == POCL_ARG_TYPE_SAMPLER)
141     {
142       POCL_RETURN_ERROR_ON (((!is_local) && (arg_size != sizeof (cl_mem))),
143                             CL_INVALID_ARG_SIZE,
144                             "Arg %u is pointer/buffer/image, but arg_size is "
145                             "not sizeof(cl_mem)\n",
146                             arg_index);
147       if (ptr_value)
148         {
149           POCL_RETURN_ERROR_ON (
150               !IS_CL_OBJECT_VALID ((const cl_mem)ptr_value),
151               CL_INVALID_ARG_VALUE,
152               "Arg %u is not a valid CL object\n", arg_index);
153         }
154     }
155   else if (pi->type_size)
156     {
157       size_t as = arg_size;
158       /* handle <type>3 vectors, we accept both <type>3 and <type>4 sizes */
159       if (as % 3 == 0)
160         as = (as / 3) * 4;
161       POCL_RETURN_ERROR_ON (
162           (pi->type_size != as), CL_INVALID_ARG_SIZE,
163           "Arg %u is %s, but arg_size is not sizeof(%s) == %u\n", arg_index,
164           pi->type_name, pi->type_name, pi->type_size);
165     }
166 
167   p = &(kernel->dyn_arguments[arg_index]);
168   if (kernel->dyn_argument_storage == NULL)
169     pocl_aligned_free (p->value);
170   p->value = NULL;
171   p->is_set = 0;
172   p->is_readonly = 0;
173   p->is_svm = 0;
174 
175   /* Even if the buffer/image is read-write, the kernel might be using it as
176    * read-only */
177   if ((kernel->meta->has_arg_metadata & POCL_HAS_KERNEL_ARG_ACCESS_QUALIFIER)
178       && (pi->address_qualifier == CL_KERNEL_ARG_ADDRESS_GLOBAL))
179     {
180       if (pi->type == POCL_ARG_TYPE_IMAGE)
181         {
182           p->is_readonly
183               = (pi->access_qualifier & CL_KERNEL_ARG_ACCESS_READ_ONLY ? 1
184                                                                        : 0);
185         }
186       if (pi->type == POCL_ARG_TYPE_POINTER)
187         {
188           p->is_readonly
189               = (pi->type_qualifier & CL_KERNEL_ARG_TYPE_CONST ? 1 : 0);
190         }
191     }
192 
193   if (arg_value != NULL
194       && !(pi->type == POCL_ARG_TYPE_POINTER
195            && *(const intptr_t *)arg_value == 0))
196     {
197       void *value;
198       if (kernel->dyn_argument_storage != NULL)
199         value = kernel->dyn_argument_offsets[arg_index];
200       else
201         {
202           /* FIXME: this is a cludge to determine an acceptable alignment,
203            * we should probably extract the argument alignment from the
204            * LLVM bytecode during kernel header generation. */
205           arg_alignment = pocl_size_ceil2 (arg_size);
206           if (arg_alignment >= MAX_EXTENDED_ALIGNMENT)
207             arg_alignment = MAX_EXTENDED_ALIGNMENT;
208 
209           arg_alloc_size = arg_size;
210           if (arg_alloc_size < arg_alignment)
211             arg_alloc_size = arg_alignment;
212 
213           value = pocl_aligned_malloc (arg_alignment, arg_alloc_size);
214           if (value == NULL)
215             {
216               return CL_OUT_OF_HOST_MEMORY;
217             }
218         }
219 
220       if ((pi->type == POCL_ARG_TYPE_POINTER) && (arg_value != NULL))
221         {
222           cl_mem buf = *(const cl_mem *)arg_value;
223           if (buf->parent != NULL)
224             {
225               p->offset = buf->origin;
226               buf = buf->parent;
227             }
228           else
229             {
230               p->offset = 0;
231             }
232           memcpy (value, &buf, arg_size);
233         }
234       else
235         memcpy (value, arg_value, arg_size);
236       p->value = value;
237     }
238 
239 #if 0
240   printf(
241       "### clSetKernelArg for %s arg %d (size %u) set to %x points to %x\n",
242       kernel->name, arg_index, arg_size, p->value, *(int*)arg_value);
243 #endif
244 
245   p->size = arg_size;
246   p->is_set = 1;
247 
248   return CL_SUCCESS;
249 }
250 POsym(clSetKernelArg)
251