blob: f3dd26f201667cd5229d89dc23358a97d2ee7632 [file] [log] [blame]
Karol Herbstdeb04ad2019-08-06 20:35:48 +02001//
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"
Karol Herbst4fd2a452020-08-19 16:02:55 +020029#include "core/module.hpp"
Karol Herbstdeb04ad2019-08-06 20:35:48 +020030#include "pipe/p_state.h"
31#include "util/algorithm.hpp"
32#include "util/functional.hpp"
33
34#include <compiler/glsl_types.h>
Karol Herbst4fd2a452020-08-19 16:02:55 +020035#include <compiler/nir/nir_builder.h>
Karol Herbstdeb04ad2019-08-06 20:35:48 +020036#include <compiler/nir/nir_serialize.h>
37#include <compiler/spirv/nir_spirv.h>
38#include <util/u_math.h>
39
Dave Airlief33b4172019-04-10 10:24:46 +100040extern "C" {
41#include "nir_lower_libclc.h"
42}
43
Karol Herbstdeb04ad2019-08-06 20:35:48 +020044using namespace clover;
45
46#ifdef HAVE_CLOVER_SPIRV
47
48// Refs and unrefs the glsl_type_singleton.
49static class glsl_type_ref {
50public:
51 glsl_type_ref() {
52 glsl_type_singleton_init_or_ref();
53 }
54
55 ~glsl_type_ref() {
56 glsl_type_singleton_decref();
57 }
58} glsl_type_ref;
59
60static const nir_shader_compiler_options *
61dev_get_nir_compiler_options(const device &dev)
62{
63 const void *co = dev.get_compiler_options(PIPE_SHADER_IR_NIR);
64 return static_cast<const nir_shader_compiler_options*>(co);
65}
66
Pierre Moreaua624fae2020-05-10 23:21:56 +020067static void debug_function(void *private_data,
68 enum nir_spirv_debug_level level, size_t spirv_offset,
69 const char *message)
70{
71 assert(private_data);
72 auto r_log = reinterpret_cast<std::string *>(private_data);
73 *r_log += message;
74}
75
Karol Herbst4fd2a452020-08-19 16:02:55 +020076struct clover_lower_nir_state {
77 std::vector<module::argument> &args;
78 uint32_t global_dims;
Karol Herbst7c6f1d32020-09-02 20:45:26 +020079 nir_variable *constant_var;
Karol Herbst4fd2a452020-08-19 16:02:55 +020080 nir_variable *offset_vars[3];
81};
82
83static bool
84clover_lower_nir_filter(const nir_instr *instr, const void *)
85{
86 return instr->type == nir_instr_type_intrinsic;
87}
88
89static nir_ssa_def *
90clover_lower_nir_instr(nir_builder *b, nir_instr *instr, void *_state)
91{
92 clover_lower_nir_state *state = reinterpret_cast<clover_lower_nir_state*>(_state);
93 nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr);
94
95 switch (intrinsic->intrinsic) {
96 case nir_intrinsic_load_base_global_invocation_id: {
97 nir_ssa_def *loads[3];
98
99 /* create variables if we didn't do so alrady */
100 if (!state->offset_vars[0]) {
101 /* TODO: fix for 64 bit */
102 /* Even though we only place one scalar argument, clover will bind up to
103 * three 32 bit values
104 */
Jason Ekstrand8bea5aa2020-09-01 10:30:17 -0500105 unsigned location = state->args.size();
Karol Herbst4fd2a452020-08-19 16:02:55 +0200106 state->args.emplace_back(module::argument::scalar, 4, 4, 4,
107 module::argument::zero_ext,
108 module::argument::grid_offset);
109
110 const glsl_type *type = glsl_uint_type();
111 for (uint32_t i = 0; i < 3; i++) {
112 state->offset_vars[i] =
Jesse Natalie865a2ad2020-08-28 12:52:20 -0700113 nir_variable_create(b->shader, nir_var_uniform, type,
Karol Herbst4fd2a452020-08-19 16:02:55 +0200114 "global_invocation_id_offsets");
Jason Ekstrand8bea5aa2020-09-01 10:30:17 -0500115 state->offset_vars[i]->data.location = location + i;
Karol Herbst4fd2a452020-08-19 16:02:55 +0200116 }
117 }
118
119 for (int i = 0; i < 3; i++) {
120 nir_variable *var = state->offset_vars[i];
121 loads[i] = var ? nir_load_var(b, var) : nir_imm_int(b, 0);
122 }
123
124 return nir_u2u(b, nir_vec(b, loads, state->global_dims),
125 nir_dest_bit_size(intrinsic->dest));
126 }
Karol Herbst7c6f1d32020-09-02 20:45:26 +0200127 case nir_intrinsic_load_constant_base_ptr: {
128 return nir_load_var(b, state->constant_var);
129 }
130
Karol Herbst4fd2a452020-08-19 16:02:55 +0200131 default:
132 return NULL;
133 }
134}
135
136static bool
Karol Herbst7c6f1d32020-09-02 20:45:26 +0200137clover_lower_nir(nir_shader *nir, std::vector<module::argument> &args,
138 uint32_t dims, uint32_t pointer_bit_size)
Karol Herbst4fd2a452020-08-19 16:02:55 +0200139{
Karol Herbst7c6f1d32020-09-02 20:45:26 +0200140 nir_variable *constant_var = NULL;
141 if (nir->constant_data_size) {
142 const glsl_type *type = pointer_bit_size == 64 ? glsl_uint64_t_type() : glsl_uint_type();
143
144 constant_var = nir_variable_create(nir, nir_var_uniform, type,
145 "constant_buffer_addr");
146 constant_var->data.location = args.size();
147
148 args.emplace_back(module::argument::global,
149 pointer_bit_size / 8, pointer_bit_size / 8, pointer_bit_size / 8,
150 module::argument::zero_ext,
151 module::argument::constant_buffer);
152 }
153
154 clover_lower_nir_state state = { args, dims, constant_var };
Karol Herbst4fd2a452020-08-19 16:02:55 +0200155 return nir_shader_lower_instructions(nir,
156 clover_lower_nir_filter, clover_lower_nir_instr, &state);
157}
158
Dave Airlief33b4172019-04-10 10:24:46 +1000159static spirv_to_nir_options
160create_spirv_options(const device &dev, std::string &r_log)
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200161{
Karol Herbst697eb8f2019-09-22 15:27:33 +0200162 struct spirv_to_nir_options spirv_options = {};
Karol Herbstdba8bf12019-12-05 11:30:11 +0100163 spirv_options.environment = NIR_SPIRV_OPENCL;
Jesse Natalieee905aa2020-05-21 15:12:15 -0700164 if (dev.address_bits() == 32u) {
Jason Ekstrand8f7784e2020-08-19 12:15:23 -0500165 spirv_options.shared_addr_format = nir_address_format_32bit_offset;
Jesse Natalieee905aa2020-05-21 15:12:15 -0700166 spirv_options.global_addr_format = nir_address_format_32bit_global;
Karol Herbst7dc39832020-08-19 21:14:46 +0200167 spirv_options.temp_addr_format = nir_address_format_32bit_offset;
Jason Ekstrand26a4c8f2020-08-19 11:34:21 -0500168 spirv_options.constant_addr_format = nir_address_format_32bit_global;
Jesse Natalieee905aa2020-05-21 15:12:15 -0700169 } else {
Jason Ekstrand8f7784e2020-08-19 12:15:23 -0500170 spirv_options.shared_addr_format = nir_address_format_32bit_offset_as_64bit;
Jesse Natalieee905aa2020-05-21 15:12:15 -0700171 spirv_options.global_addr_format = nir_address_format_64bit_global;
Karol Herbst7dc39832020-08-19 21:14:46 +0200172 spirv_options.temp_addr_format = nir_address_format_32bit_offset_as_64bit;
Jason Ekstrand26a4c8f2020-08-19 11:34:21 -0500173 spirv_options.constant_addr_format = nir_address_format_64bit_global;
Jesse Natalieee905aa2020-05-21 15:12:15 -0700174 }
Karol Herbst697eb8f2019-09-22 15:27:33 +0200175 spirv_options.caps.address = true;
176 spirv_options.caps.float64 = true;
177 spirv_options.caps.int8 = true;
178 spirv_options.caps.int16 = true;
179 spirv_options.caps.int64 = true;
180 spirv_options.caps.kernel = true;
Karol Herbst44031762020-03-05 23:00:27 +0100181 spirv_options.caps.int64_atomics = dev.has_int64_atomics();
Pierre Moreaua624fae2020-05-10 23:21:56 +0200182 spirv_options.debug.func = &debug_function;
183 spirv_options.debug.private_data = &r_log;
Dave Airlief33b4172019-04-10 10:24:46 +1000184 return spirv_options;
185}
186
187struct disk_cache *clover::nir::create_clc_disk_cache(void)
188{
189 struct mesa_sha1 ctx;
190 unsigned char sha1[20];
191 char cache_id[20 * 2 + 1];
192 _mesa_sha1_init(&ctx);
193
194 if (!disk_cache_get_function_identifier((void *)clover::nir::create_clc_disk_cache, &ctx))
195 return NULL;
196
197 _mesa_sha1_final(&ctx, sha1);
198
199 disk_cache_format_hex_id(cache_id, sha1, 20 * 2);
200 return disk_cache_create("clover-clc", cache_id, 0);
201}
202
203nir_shader *clover::nir::libclc_spirv_to_nir(const module &mod, const device &dev,
204 std::string &r_log)
205{
206 spirv_to_nir_options spirv_options = create_spirv_options(dev, r_log);
207 spirv_options.create_library = true;
208
209 auto &section = mod.secs[0];
210 const auto *binary =
211 reinterpret_cast<const pipe_binary_program_header *>(section.data.data());
212 const uint32_t *data = reinterpret_cast<const uint32_t *>(binary->blob);
213 const size_t num_words = binary->num_bytes / 4;
214 auto *compiler_options = dev_get_nir_compiler_options(dev);
215 unsigned char clc_cache_key[20];
216 unsigned char sha1[CACHE_KEY_SIZE];
217 /* caching ftw. */
218 struct mesa_sha1 ctx;
219
220 size_t binary_size = 0;
221 uint8_t *buffer = NULL;
222 if (dev.clc_cache) {
223 _mesa_sha1_init(&ctx);
224 _mesa_sha1_update(&ctx, data, num_words * 4);
225 _mesa_sha1_final(&ctx, clc_cache_key);
226
227 disk_cache_compute_key(dev.clc_cache, clc_cache_key, 20, sha1);
228
229 buffer = (uint8_t *)disk_cache_get(dev.clc_cache, sha1, &binary_size);
230 }
231
232 nir_shader *nir;
233 if (!buffer) {
234 nir = spirv_to_nir(data, num_words, nullptr, 0,
235 MESA_SHADER_KERNEL, "clcspirv",
236 &spirv_options, compiler_options);
237 nir_validate_shader(nir, "clover-libclc");
238 nir->info.internal = true;
239 NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
240 NIR_PASS_V(nir, nir_lower_returns);
241
242 if (dev.clc_cache) {
243 struct blob blob = { 0 };
244 blob_init(&blob);
245 nir_serialize(&blob, nir, true);
246 disk_cache_put(dev.clc_cache, sha1, blob.data, blob.size, NULL);
247 blob_finish(&blob);
248 }
249 } else {
250 struct blob_reader blob_read;
251 blob_reader_init(&blob_read, buffer, binary_size);
252 nir = nir_deserialize(NULL, compiler_options, &blob_read);
253 free(buffer);
254 }
255
256 return nir;
257}
258
259module clover::nir::spirv_to_nir(const module &mod, const device &dev,
260 std::string &r_log)
261{
262 spirv_to_nir_options spirv_options = create_spirv_options(dev, r_log);
263 std::shared_ptr<nir_shader> nir = dev.clc_nir;
264 spirv_options.clc_shader = nir.get();
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200265
266 module m;
267 // We only insert one section.
268 assert(mod.secs.size() == 1);
269 auto &section = mod.secs[0];
270
271 module::resource_id section_id = 0;
272 for (const auto &sym : mod.syms) {
273 assert(sym.section == 0);
274
275 const auto *binary =
276 reinterpret_cast<const pipe_binary_program_header *>(section.data.data());
277 const uint32_t *data = reinterpret_cast<const uint32_t *>(binary->blob);
278 const size_t num_words = binary->num_bytes / 4;
279 const char *name = sym.name.c_str();
280 auto *compiler_options = dev_get_nir_compiler_options(dev);
281
282 nir_shader *nir = spirv_to_nir(data, num_words, nullptr, 0,
283 MESA_SHADER_KERNEL, name,
284 &spirv_options, compiler_options);
Pierre Moreau38bbfd32020-05-05 13:13:19 +0200285 if (!nir) {
286 r_log += "Translation from SPIR-V to NIR for kernel \"" + sym.name +
287 "\" failed.\n";
288 throw build_error();
289 }
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200290
Karol Herbstee5b46f2020-08-23 16:46:05 +0200291 nir->info.cs.local_size_variable = sym.reqd_work_group_size[0] == 0;
292 nir->info.cs.local_size[0] = sym.reqd_work_group_size[0];
293 nir->info.cs.local_size[1] = sym.reqd_work_group_size[1];
294 nir->info.cs.local_size[2] = sym.reqd_work_group_size[2];
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200295 nir_validate_shader(nir, "clover");
296
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200297 // Inline all functions first.
298 // according to the comment on nir_inline_functions
Arcady Goldmints-Orlove9f83182020-02-07 14:18:49 -0600299 NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200300 NIR_PASS_V(nir, nir_lower_returns);
Dave Airlief33b4172019-04-10 10:24:46 +1000301 NIR_PASS_V(nir, nir_lower_libclc, spirv_options.clc_shader);
302
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200303 NIR_PASS_V(nir, nir_inline_functions);
Jason Ekstrand196db512020-06-11 13:29:02 -0500304 NIR_PASS_V(nir, nir_copy_prop);
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200305 NIR_PASS_V(nir, nir_opt_deref);
306
307 // Pick off the single entrypoint that we want.
308 foreach_list_typed_safe(nir_function, func, node, &nir->functions) {
309 if (!func->is_entrypoint)
310 exec_node_remove(&func->node);
311 }
312 assert(exec_list_length(&nir->functions) == 1);
313
314 nir_validate_shader(nir, "clover after function inlining");
315
Karol Herbst70cbddc2020-08-31 18:08:49 +0200316 NIR_PASS_V(nir, nir_lower_variable_initializers, ~nir_var_function_temp);
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200317
318 // copy propagate to prepare for lower_explicit_io
319 NIR_PASS_V(nir, nir_split_var_copies);
320 NIR_PASS_V(nir, nir_opt_copy_prop_vars);
321 NIR_PASS_V(nir, nir_lower_var_copies);
322 NIR_PASS_V(nir, nir_lower_vars_to_ssa);
323 NIR_PASS_V(nir, nir_opt_dce);
324
Jason Ekstrandbc7ed032020-09-30 16:54:19 -0500325 NIR_PASS_V(nir, nir_lower_convert_alu_types, NULL);
326
Karol Herbst4fd2a452020-08-19 16:02:55 +0200327 NIR_PASS_V(nir, nir_lower_system_values);
328 nir_lower_compute_system_values_options sysval_options = { 0 };
329 sysval_options.has_base_global_invocation_id = true;
330 NIR_PASS_V(nir, nir_lower_compute_system_values, &sysval_options);
331
Karol Herbst7c6f1d32020-09-02 20:45:26 +0200332 NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_mem_constant, NULL);
Jason Ekstrandbcfeead2020-09-02 17:43:07 -0500333 NIR_PASS_V(nir, nir_lower_mem_constant_vars,
334 glsl_get_cl_type_size_align);
Karol Herbst7c6f1d32020-09-02 20:45:26 +0200335 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_constant,
336 spirv_options.constant_addr_format);
337
338 auto args = sym.args;
339 NIR_PASS_V(nir, clover_lower_nir, args, dev.max_block_size().size(),
340 dev.address_bits());
341
Karol Herbstd421af32020-08-16 17:43:18 +0200342 NIR_PASS_V(nir, nir_lower_vars_to_explicit_types,
Jason Ekstrand796d3fe2020-08-27 15:56:38 -0500343 nir_var_uniform | nir_var_mem_shared |
344 nir_var_mem_global | nir_var_function_temp,
Karol Herbst918e4442020-08-15 13:33:29 +0200345 glsl_get_cl_type_size_align);
346
Jason Ekstrandbf80fb72020-09-14 15:56:48 -0500347 NIR_PASS_V(nir, nir_lower_memcpy);
348
Jason Ekstrand526f3562020-08-21 17:23:59 -0500349 /* use offsets for kernel inputs (uniform) */
Jesse Natalie865a2ad2020-08-28 12:52:20 -0700350 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_uniform,
Jason Ekstrand526f3562020-08-21 17:23:59 -0500351 nir->info.cs.ptr_size == 64 ?
352 nir_address_format_32bit_offset_as_64bit :
Jason Ekstrand8f7784e2020-08-19 12:15:23 -0500353 nir_address_format_32bit_offset);
354
Jason Ekstrand26a4c8f2020-08-19 11:34:21 -0500355 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_constant,
356 spirv_options.constant_addr_format);
Jason Ekstrand8f7784e2020-08-19 12:15:23 -0500357 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_shared,
358 spirv_options.shared_addr_format);
Karol Herbst384c4df2020-08-14 21:56:00 +0200359
Karol Herbstd421af32020-08-16 17:43:18 +0200360 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_function_temp,
361 spirv_options.temp_addr_format);
362
Jason Ekstrandb2226f72020-08-19 11:32:32 -0500363 NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_global,
364 spirv_options.global_addr_format);
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200365
Karol Herbstd421af32020-08-16 17:43:18 +0200366 NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_all, NULL);
367
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200368 if (compiler_options->lower_int64_options)
Boris Brezillonbfee35b2020-07-13 20:28:16 +0200369 NIR_PASS_V(nir, nir_lower_int64);
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200370
371 NIR_PASS_V(nir, nir_opt_dce);
372
Karol Herbst7c6f1d32020-09-02 20:45:26 +0200373 if (nir->constant_data_size) {
374 const char *ptr = reinterpret_cast<const char *>(nir->constant_data);
375 const module::section constants {
376 section_id,
377 module::section::data_constant,
378 nir->constant_data_size,
379 { ptr, ptr + nir->constant_data_size }
380 };
381 nir->constant_data = NULL;
382 nir->constant_data_size = 0;
383 m.secs.push_back(constants);
384 }
385
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200386 struct blob blob;
387 blob_init(&blob);
Marek Olšákc38c8d02019-10-10 18:43:47 -0400388 nir_serialize(&blob, nir, false);
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200389
390 const pipe_binary_program_header header { uint32_t(blob.size) };
391 module::section text { section_id, module::section::text_executable, header.num_bytes, {} };
392 text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
393 reinterpret_cast<const char *>(&header) + sizeof(header));
394 text.data.insert(text.data.end(), blob.data, blob.data + blob.size);
395
Serge Martinc04d5e72020-09-27 15:45:33 +0200396 m.syms.emplace_back(sym.name, std::string(),
Karol Herbstee5b46f2020-08-23 16:46:05 +0200397 sym.reqd_work_group_size, section_id, 0, args);
Karol Herbstdeb04ad2019-08-06 20:35:48 +0200398 m.secs.push_back(text);
399 section_id++;
400 }
401 return m;
402}
403#else
404module clover::nir::spirv_to_nir(const module &mod, const device &dev, std::string &r_log)
405{
406 r_log += "SPIR-V support in clover is not enabled.\n";
407 throw error(CL_LINKER_NOT_AVAILABLE);
408}
409#endif