2 // Copyright 2019 Karol Herbst
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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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.
23 #include "invocation.hpp"
27 #include "core/device.hpp"
28 #include "core/error.hpp"
29 #include "pipe/p_state.h"
30 #include "util/algorithm.hpp"
31 #include "util/functional.hpp"
33 #include <compiler/glsl_types.h>
34 #include <compiler/nir/nir_serialize.h>
35 #include <compiler/spirv/nir_spirv.h>
36 #include <util/u_math.h>
38 using namespace clover
;
40 #ifdef HAVE_CLOVER_SPIRV
42 // Refs and unrefs the glsl_type_singleton.
43 static class glsl_type_ref
{
46 glsl_type_singleton_init_or_ref();
50 glsl_type_singleton_decref();
54 static const nir_shader_compiler_options
*
55 dev_get_nir_compiler_options(const device
&dev
)
57 const void *co
= dev
.get_compiler_options(PIPE_SHADER_IR_NIR
);
58 return static_cast<const nir_shader_compiler_options
*>(co
);
61 module
clover::nir::spirv_to_nir(const module
&mod
, const device
&dev
,
64 struct spirv_to_nir_options spirv_options
= {};
65 spirv_options
.environment
= NIR_SPIRV_OPENCL
;
66 if (dev
.address_bits() == 32u) {
67 spirv_options
.shared_addr_format
= nir_address_format_32bit_global
;
68 spirv_options
.global_addr_format
= nir_address_format_32bit_global
;
69 spirv_options
.temp_addr_format
= nir_address_format_32bit_global
;
70 spirv_options
.ubo_addr_format
= nir_address_format_32bit_global
;
72 spirv_options
.shared_addr_format
= nir_address_format_64bit_global
;
73 spirv_options
.global_addr_format
= nir_address_format_64bit_global
;
74 spirv_options
.temp_addr_format
= nir_address_format_64bit_global
;
75 spirv_options
.ubo_addr_format
= nir_address_format_32bit_index_offset
;
77 spirv_options
.caps
.address
= true;
78 spirv_options
.caps
.float64
= true;
79 spirv_options
.caps
.int8
= true;
80 spirv_options
.caps
.int16
= true;
81 spirv_options
.caps
.int64
= true;
82 spirv_options
.caps
.kernel
= true;
83 spirv_options
.constant_as_global
= true;
86 // We only insert one section.
87 assert(mod
.secs
.size() == 1);
88 auto §ion
= mod
.secs
[0];
90 module::resource_id section_id
= 0;
91 for (const auto &sym
: mod
.syms
) {
92 assert(sym
.section
== 0);
95 reinterpret_cast<const pipe_binary_program_header
*>(section
.data
.data());
96 const uint32_t *data
= reinterpret_cast<const uint32_t *>(binary
->blob
);
97 const size_t num_words
= binary
->num_bytes
/ 4;
98 const char *name
= sym
.name
.c_str();
99 auto *compiler_options
= dev_get_nir_compiler_options(dev
);
101 nir_shader
*nir
= spirv_to_nir(data
, num_words
, nullptr, 0,
102 MESA_SHADER_KERNEL
, name
,
103 &spirv_options
, compiler_options
);
105 r_log
+= "Translation from SPIR-V to NIR for kernel \"" + sym
.name
+
110 nir
->info
.cs
.local_size_variable
= true;
111 nir_validate_shader(nir
, "clover");
113 // Calculate input offsets.
115 nir_foreach_shader_in_variable_safe(var
, nir
) {
116 offset
= align(offset
, glsl_get_cl_alignment(var
->type
));
117 var
->data
.driver_location
= offset
;
118 offset
+= glsl_get_cl_size(var
->type
);
121 // Inline all functions first.
122 // according to the comment on nir_inline_functions
123 NIR_PASS_V(nir
, nir_lower_variable_initializers
, nir_var_function_temp
);
124 NIR_PASS_V(nir
, nir_lower_returns
);
125 NIR_PASS_V(nir
, nir_inline_functions
);
126 NIR_PASS_V(nir
, nir_copy_prop
);
127 NIR_PASS_V(nir
, nir_opt_deref
);
129 // Pick off the single entrypoint that we want.
130 foreach_list_typed_safe(nir_function
, func
, node
, &nir
->functions
) {
131 if (!func
->is_entrypoint
)
132 exec_node_remove(&func
->node
);
134 assert(exec_list_length(&nir
->functions
) == 1);
136 nir_validate_shader(nir
, "clover after function inlining");
138 NIR_PASS_V(nir
, nir_lower_variable_initializers
,
139 static_cast<nir_variable_mode
>(~nir_var_function_temp
));
141 // copy propagate to prepare for lower_explicit_io
142 NIR_PASS_V(nir
, nir_split_var_copies
);
143 NIR_PASS_V(nir
, nir_opt_copy_prop_vars
);
144 NIR_PASS_V(nir
, nir_lower_var_copies
);
145 NIR_PASS_V(nir
, nir_lower_vars_to_ssa
);
146 NIR_PASS_V(nir
, nir_opt_dce
);
148 NIR_PASS_V(nir
, nir_lower_vars_to_explicit_types
, nir_var_mem_shared
,
149 glsl_get_cl_type_size_align
);
151 /* use offsets for shader_in and shared memory */
152 nir_variable_mode modes
= (nir_variable_mode
)(
155 NIR_PASS_V(nir
, nir_lower_explicit_io
, modes
, nir_address_format_32bit_offset
);
157 /* use global format for global memory */
158 nir_address_format format
= nir
->info
.cs
.ptr_size
== 64 ?
159 nir_address_format_64bit_global
: nir_address_format_32bit_global
;
160 NIR_PASS_V(nir
, nir_lower_explicit_io
, nir_var_mem_global
, format
);
162 NIR_PASS_V(nir
, nir_lower_system_values
);
163 if (compiler_options
->lower_int64_options
)
164 NIR_PASS_V(nir
, nir_lower_int64
);
166 NIR_PASS_V(nir
, nir_opt_dce
);
170 nir_serialize(&blob
, nir
, false);
172 const pipe_binary_program_header header
{ uint32_t(blob
.size
) };
173 module::section text
{ section_id
, module::section::text_executable
, header
.num_bytes
, {} };
174 text
.data
.insert(text
.data
.end(), reinterpret_cast<const char *>(&header
),
175 reinterpret_cast<const char *>(&header
) + sizeof(header
));
176 text
.data
.insert(text
.data
.end(), blob
.data
, blob
.data
+ blob
.size
);
178 m
.syms
.emplace_back(sym
.name
, section_id
, 0, sym
.args
);
179 m
.secs
.push_back(text
);
185 module
clover::nir::spirv_to_nir(const module
&mod
, const device
&dev
, std::string
&r_log
)
187 r_log
+= "SPIR-V support in clover is not enabled.\n";
188 throw error(CL_LINKER_NOT_AVAILABLE
);