1 //
2 // Copyright 2019 Karol Herbst
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22
23 #include "invocation.hpp"
24
25 #include <tuple>
26
27 #include "core/device.hpp"
28 #include "core/error.hpp"
29 #include "core/binary.hpp"
30 #include "pipe/p_state.h"
31 #include "util/algorithm.hpp"
32 #include "util/functional.hpp"
33
34 #include <compiler/glsl_types.h>
35 #include <compiler/clc/nir_clc_helpers.h>
36 #include <compiler/nir/nir_builder.h>
37 #include <compiler/nir/nir_serialize.h>
38 #include <compiler/spirv/nir_spirv.h>
39 #include <util/u_math.h>
40 #include <util/hex.h>
41
42 using namespace clover;
43
44 #ifdef HAVE_CLOVER_SPIRV
45
46 // Refs and unrefs the glsl_type_singleton.
47 static class glsl_type_ref {
48 public:
glsl_type_ref()49 glsl_type_ref() {
50 glsl_type_singleton_init_or_ref();
51 }
52
~glsl_type_ref()53 ~glsl_type_ref() {
54 glsl_type_singleton_decref();
55 }
56 } glsl_type_ref;
57
58 static const nir_shader_compiler_options *
dev_get_nir_compiler_options(const device & dev)59 dev_get_nir_compiler_options(const device &dev)
60 {
61 const void *co = dev.get_compiler_options(PIPE_SHADER_IR_NIR);
62 return static_cast<const nir_shader_compiler_options*>(co);
63 }
64
debug_function(void * private_data,enum nir_spirv_debug_level level,size_t spirv_offset,const char * message)65 static void debug_function(void *private_data,
66 enum nir_spirv_debug_level level, size_t spirv_offset,
67 const char *message)
68 {
69 assert(private_data);
70 auto r_log = reinterpret_cast<std::string *>(private_data);
71 *r_log += message;
72 }
73
74 static void
clover_arg_size_align(const glsl_type * type,unsigned * size,unsigned * align)75 clover_arg_size_align(const glsl_type *type, unsigned *size, unsigned *align)
76 {
77 if (glsl_type_is_sampler(type) || glsl_type_is_image(type)) {
78 *size = 0;
79 *align = 1;
80 } else {
81 *size = glsl_get_cl_size(type);
82 *align = glsl_get_cl_alignment(type);
83 }
84 }
85
86 static void
clover_nir_add_image_uniforms(nir_shader * shader)87 clover_nir_add_image_uniforms(nir_shader *shader)
88 {
89 /* Clover expects each image variable to take up a cl_mem worth of space in
90 * the arguments data. Add uniforms as needed to match this expectation.
91 */
92 nir_foreach_image_variable_safe(var, shader) {
93 nir_variable *uniform = rzalloc(shader, nir_variable);
94 uniform->name = ralloc_strdup(uniform, var->name);
95 uniform->type = glsl_uintN_t_type(sizeof(cl_mem) * 8);
96 uniform->data.mode = nir_var_uniform;
97 uniform->data.read_only = true;
98 uniform->data.location = var->data.location;
99
100 exec_node_insert_node_before(&var->node, &uniform->node);
101 }
102 }
103
104 struct clover_lower_nir_state {
105 std::vector<binary::argument> &args;
106 uint32_t global_dims;
107 nir_variable *constant_var;
108 nir_variable *printf_buffer;
109 nir_variable *offset_vars[3];
110 };
111
112 static bool
clover_lower_nir_filter(const nir_instr * instr,const void *)113 clover_lower_nir_filter(const nir_instr *instr, const void *)
114 {
115 return instr->type == nir_instr_type_intrinsic;
116 }
117
118 static nir_def *
clover_lower_nir_instr(nir_builder * b,nir_instr * instr,void * _state)119 clover_lower_nir_instr(nir_builder *b, nir_instr *instr, void *_state)
120 {
121 clover_lower_nir_state *state = reinterpret_cast<clover_lower_nir_state*>(_state);
122 nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr);
123
124 switch (intrinsic->intrinsic) {
125 case nir_intrinsic_load_printf_buffer_address: {
126 if (!state->printf_buffer) {
127 unsigned location = state->args.size();
128 state->args.emplace_back(binary::argument::global, sizeof(size_t),
129 8, 8, binary::argument::zero_ext,
130 binary::argument::printf_buffer);
131
132 const glsl_type *type = glsl_uint64_t_type();
133 state->printf_buffer = nir_variable_create(b->shader, nir_var_uniform,
134 type, "global_printf_buffer");
135 state->printf_buffer->data.location = location;
136 }
137 return nir_load_var(b, state->printf_buffer);
138 }
139 case nir_intrinsic_load_base_global_invocation_id: {
140 nir_def *loads[3];
141
142 /* create variables if we didn't do so alrady */
143 if (!state->offset_vars[0]) {
144 /* TODO: fix for 64 bit */
145 /* Even though we only place one scalar argument, clover will bind up to
146 * three 32 bit values
147 */
148 unsigned location = state->args.size();
149 state->args.emplace_back(binary::argument::scalar, 4, 4, 4,
150 binary::argument::zero_ext,
151 binary::argument::grid_offset);
152
153 const glsl_type *type = glsl_uint_type();
154 for (uint32_t i = 0; i < 3; i++) {
155 state->offset_vars[i] =
156 nir_variable_create(b->shader, nir_var_uniform, type,
157 "global_invocation_id_offsets");
158 state->offset_vars[i]->data.location = location + i;
159 }
160 }
161
162 for (int i = 0; i < 3; i++) {
163 nir_variable *var = state->offset_vars[i];
164 loads[i] = var ? nir_load_var(b, var) : nir_imm_int(b, 0);
165 }
166
167 return nir_u2uN(b, nir_vec(b, loads, state->global_dims),
168 intrinsic->def.bit_size);
169 }
170 case nir_intrinsic_load_constant_base_ptr: {
171 return nir_load_var(b, state->constant_var);
172 }
173
174 default:
175 return NULL;
176 }
177 }
178
179 static bool
clover_lower_nir(nir_shader * nir,std::vector<binary::argument> & args,uint32_t dims,uint32_t pointer_bit_size)180 clover_lower_nir(nir_shader *nir, std::vector<binary::argument> &args,
181 uint32_t dims, uint32_t pointer_bit_size)
182 {
183 nir_variable *constant_var = NULL;
184 if (nir->constant_data_size) {
185 const glsl_type *type = pointer_bit_size == 64 ? glsl_uint64_t_type() : glsl_uint_type();
186
187 constant_var = nir_variable_create(nir, nir_var_uniform, type,
188 "constant_buffer_addr");
189 constant_var->data.location = args.size();
190
191 args.emplace_back(binary::argument::global, sizeof(cl_mem),
192 pointer_bit_size / 8, pointer_bit_size / 8,
193 binary::argument::zero_ext,
194 binary::argument::constant_buffer);
195 }
196
197 clover_lower_nir_state state = { args, dims, constant_var };
198 return nir_shader_lower_instructions(nir,
199 clover_lower_nir_filter, clover_lower_nir_instr, &state);
200 }
201
202 static spirv_to_nir_options
create_spirv_options(const device & dev,std::string & r_log)203 create_spirv_options(const device &dev, std::string &r_log)
204 {
205 struct spirv_to_nir_options spirv_options = {};
206 spirv_options.environment = NIR_SPIRV_OPENCL;
207 if (dev.address_bits() == 32u) {
208 spirv_options.shared_addr_format = nir_address_format_32bit_offset;
209 spirv_options.global_addr_format = nir_address_format_32bit_global;
210 spirv_options.temp_addr_format = nir_address_format_32bit_offset;
211 spirv_options.constant_addr_format = nir_address_format_32bit_global;
212 } else {
213 spirv_options.shared_addr_format = nir_address_format_32bit_offset_as_64bit;
214 spirv_options.global_addr_format = nir_address_format_64bit_global;
215 spirv_options.temp_addr_format = nir_address_format_32bit_offset_as_64bit;
216 spirv_options.constant_addr_format = nir_address_format_64bit_global;
217 }
218 spirv_options.caps.address = true;
219 spirv_options.caps.float64 = true;
220 spirv_options.caps.int8 = true;
221 spirv_options.caps.int16 = true;
222 spirv_options.caps.int64 = true;
223 spirv_options.caps.kernel = true;
224 spirv_options.caps.kernel_image = dev.image_support();
225 spirv_options.caps.int64_atomics = dev.has_int64_atomics();
226 spirv_options.debug.func = &debug_function;
227 spirv_options.debug.private_data = &r_log;
228 spirv_options.caps.printf = true;
229 return spirv_options;
230 }
231
create_clc_disk_cache(void)232 struct disk_cache *clover::nir::create_clc_disk_cache(void)
233 {
234 struct mesa_sha1 ctx;
235 unsigned char sha1[20];
236 char cache_id[20 * 2 + 1];
237 _mesa_sha1_init(&ctx);
238
239 if (!disk_cache_get_function_identifier((void *)clover::nir::create_clc_disk_cache, &ctx))
240 return NULL;
241
242 _mesa_sha1_final(&ctx, sha1);
243
244 mesa_bytes_to_hex(cache_id, sha1, 20);
245 return disk_cache_create("clover-clc", cache_id, 0);
246 }
247
check_for_libclc(const device & dev)248 void clover::nir::check_for_libclc(const device &dev)
249 {
250 if (!nir_can_find_libclc(dev.address_bits()))
251 throw error(CL_COMPILER_NOT_AVAILABLE);
252 }
253
load_libclc_nir(const device & dev,std::string & r_log)254 nir_shader *clover::nir::load_libclc_nir(const device &dev, std::string &r_log)
255 {
256 spirv_to_nir_options spirv_options = create_spirv_options(dev, r_log);
257 auto *compiler_options = dev_get_nir_compiler_options(dev);
258
259 return nir_load_libclc_shader(dev.address_bits(), dev.clc_cache,
260 &spirv_options, compiler_options,
261 dev.clc_cache != nullptr);
262 }
263
264 static bool
can_remove_var(nir_variable * var,void * data)265 can_remove_var(nir_variable *var, void *data)
266 {
267 return !(glsl_type_is_sampler(var->type) ||
268 glsl_type_is_texture(var->type) ||
269 glsl_type_is_image(var->type));
270 }
271
spirv_to_nir(const binary & mod,const device & dev,std::string & r_log)272 binary clover::nir::spirv_to_nir(const binary &mod, const device &dev,
273 std::string &r_log)
274 {
275 spirv_to_nir_options spirv_options = create_spirv_options(dev, r_log);
276 std::shared_ptr<nir_shader> nir = dev.clc_nir;
277 spirv_options.clc_shader = nir.get();
278
279 binary b;
280 // We only insert one section.
281 assert(mod.secs.size() == 1);
282 auto §ion = mod.secs[0];
283
284 binary::resource_id section_id = 0;
285 for (const auto &sym : mod.syms) {
286 assert(sym.section == 0);
287
288 const auto *binary =
289 reinterpret_cast<const pipe_binary_program_header *>(section.data.data());
290 const uint32_t *data = reinterpret_cast<const uint32_t *>(binary->blob);
291 const size_t num_words = binary->num_bytes / 4;
292 const char *name = sym.name.c_str();
293 auto *compiler_options = dev_get_nir_compiler_options(dev);
294
295 nir_shader *nir = spirv_to_nir(data, num_words, nullptr, 0,
296 MESA_SHADER_KERNEL, name,
297 &spirv_options, compiler_options);
298 if (!nir) {
299 r_log += "Translation from SPIR-V to NIR for kernel \"" + sym.name +
300 "\" failed.\n";
301 throw build_error();
302 }
303
304 nir->info.workgroup_size_variable = sym.reqd_work_group_size[0] == 0;
305 nir->info.workgroup_size[0] = sym.reqd_work_group_size[0];
306 nir->info.workgroup_size[1] = sym.reqd_work_group_size[1];
307 nir->info.workgroup_size[2] = sym.reqd_work_group_size[2];
308 nir_validate_shader(nir, "clover");
309
310 // Inline all functions first.
311 // according to the comment on nir_inline_functions
312 NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
313 NIR_PASS_V(nir, nir_lower_returns);
314 NIR_PASS_V(nir, nir_link_shader_functions, spirv_options.clc_shader);
315
316 NIR_PASS_V(nir, nir_inline_functions);
317 NIR_PASS_V(nir, nir_copy_prop);
318 NIR_PASS_V(nir, nir_opt_deref);
319
320 // Pick off the single entrypoint that we want.
321 nir_remove_non_entrypoints(nir);
322
323 nir_validate_shader(nir, "clover after function inlining");
324
325 NIR_PASS_V(nir, nir_lower_variable_initializers, ~nir_var_function_temp);
326
327 struct nir_lower_printf_options printf_options;
328 printf_options.max_buffer_size = dev.max_printf_buffer_size();
329
330 NIR_PASS_V(nir, nir_lower_printf, &printf_options);
331
332 NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL);
333
334 // copy propagate to prepare for lower_explicit_io
335 NIR_PASS_V(nir, nir_split_var_copies);
336 NIR_PASS_V(nir, nir_opt_copy_prop_vars);
337 NIR_PASS_V(nir, nir_lower_var_copies);
338 NIR_PASS_V(nir, nir_lower_vars_to_ssa);
339 NIR_PASS_V(nir, nir_opt_dce);
340 NIR_PASS_V(nir, nir_lower_convert_alu_types, NULL);
341
342 if (compiler_options->lower_to_scalar) {
343 NIR_PASS_V(nir, nir_lower_alu_to_scalar,
344 compiler_options->lower_to_scalar_filter, NULL);
345 }
346 NIR_PASS_V(nir, nir_lower_system_values);
347 nir_lower_compute_system_values_options sysval_options = { 0 };
348 sysval_options.has_base_global_invocation_id = true;
349 NIR_PASS_V(nir, nir_lower_compute_system_values, &sysval_options);
350
351 // constant fold before lowering mem constants
352 NIR_PASS_V(nir, nir_opt_constant_folding);
353
354 NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_mem_constant, NULL);
355 NIR_PASS_V(nir, nir_lower_vars_to_explicit_types, nir_var_mem_constant,
356 glsl_get_cl_type_size_align);
357 if (nir->constant_data_size > 0) {
358 assert(nir->constant_data == NULL);
359 nir->constant_data = rzalloc_size(nir, nir->constant_data_size);
360 nir_gather_explicit_io_initializers(nir, nir->constant_data,
361 nir->constant_data_size,
362 nir_var_mem_constant);
363 }
364 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_constant,
365 spirv_options.constant_addr_format);
366
367 auto args = sym.args;
368 NIR_PASS_V(nir, clover_lower_nir, args, dev.max_block_size().size(),
369 dev.address_bits());
370
371 NIR_PASS_V(nir, clover_nir_add_image_uniforms);
372 NIR_PASS_V(nir, nir_lower_vars_to_explicit_types,
373 nir_var_uniform, clover_arg_size_align);
374 NIR_PASS_V(nir, nir_lower_vars_to_explicit_types,
375 nir_var_mem_shared | nir_var_mem_global |
376 nir_var_function_temp,
377 glsl_get_cl_type_size_align);
378
379 NIR_PASS_V(nir, nir_opt_deref);
380 NIR_PASS_V(nir, nir_lower_readonly_images_to_tex, false);
381 NIR_PASS_V(nir, nir_lower_cl_images, true, true);
382 NIR_PASS_V(nir, nir_lower_memcpy);
383
384 /* use offsets for kernel inputs (uniform) */
385 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_uniform,
386 nir->info.cs.ptr_size == 64 ?
387 nir_address_format_32bit_offset_as_64bit :
388 nir_address_format_32bit_offset);
389
390 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_constant,
391 spirv_options.constant_addr_format);
392 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_shared,
393 spirv_options.shared_addr_format);
394
395 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_function_temp,
396 spirv_options.temp_addr_format);
397
398 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_global,
399 spirv_options.global_addr_format);
400
401 struct nir_remove_dead_variables_options remove_dead_variables_options = {};
402 remove_dead_variables_options.can_remove_var = can_remove_var;
403 NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_all, &remove_dead_variables_options);
404
405 if (compiler_options->lower_int64_options)
406 NIR_PASS_V(nir, nir_lower_int64);
407
408 NIR_PASS_V(nir, nir_opt_dce);
409
410 if (nir->constant_data_size) {
411 const char *ptr = reinterpret_cast<const char *>(nir->constant_data);
412 const binary::section constants {
413 section_id,
414 binary::section::data_constant,
415 nir->constant_data_size,
416 { ptr, ptr + nir->constant_data_size }
417 };
418 nir->constant_data = NULL;
419 nir->constant_data_size = 0;
420 b.secs.push_back(constants);
421 }
422
423 void *mem_ctx = ralloc_context(NULL);
424 unsigned printf_info_count = nir->printf_info_count;
425 u_printf_info *printf_infos = nir->printf_info;
426
427 ralloc_steal(mem_ctx, printf_infos);
428
429 struct blob blob;
430 blob_init(&blob);
431 nir_serialize(&blob, nir, false);
432
433 ralloc_free(nir);
434
435 const pipe_binary_program_header header { uint32_t(blob.size) };
436 binary::section text { section_id, binary::section::text_executable, header.num_bytes, {} };
437 text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
438 reinterpret_cast<const char *>(&header) + sizeof(header));
439 text.data.insert(text.data.end(), blob.data, blob.data + blob.size);
440
441 free(blob.data);
442
443 b.printf_strings_in_buffer = false;
444 b.printf_infos.reserve(printf_info_count);
445 for (unsigned i = 0; i < printf_info_count; i++) {
446 binary::printf_info info;
447
448 info.arg_sizes.reserve(printf_infos[i].num_args);
449 for (unsigned j = 0; j < printf_infos[i].num_args; j++)
450 info.arg_sizes.push_back(printf_infos[i].arg_sizes[j]);
451
452 info.strings.resize(printf_infos[i].string_size);
453 memcpy(info.strings.data(), printf_infos[i].strings, printf_infos[i].string_size);
454 b.printf_infos.push_back(info);
455 }
456
457 ralloc_free(mem_ctx);
458
459 b.syms.emplace_back(sym.name, sym.attributes,
460 sym.reqd_work_group_size, section_id, 0, args);
461 b.secs.push_back(text);
462 section_id++;
463 }
464 return b;
465 }
466 #else
spirv_to_nir(const binary & mod,const device & dev,std::string & r_log)467 binary clover::nir::spirv_to_nir(const binary &mod, const device &dev, std::string &r_log)
468 {
469 r_log += "SPIR-V support in clover is not enabled.\n";
470 throw error(CL_LINKER_NOT_AVAILABLE);
471 }
472 #endif
473