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 spirv_options
.caps
.address
= true;
67 spirv_options
.caps
.float64
= true;
68 spirv_options
.caps
.int8
= true;
69 spirv_options
.caps
.int16
= true;
70 spirv_options
.caps
.int64
= true;
71 spirv_options
.caps
.kernel
= true;
72 spirv_options
.constant_as_global
= true;
75 // We only insert one section.
76 assert(mod
.secs
.size() == 1);
77 auto §ion
= mod
.secs
[0];
79 module::resource_id section_id
= 0;
80 for (const auto &sym
: mod
.syms
) {
81 assert(sym
.section
== 0);
84 reinterpret_cast<const pipe_binary_program_header
*>(section
.data
.data());
85 const uint32_t *data
= reinterpret_cast<const uint32_t *>(binary
->blob
);
86 const size_t num_words
= binary
->num_bytes
/ 4;
87 const char *name
= sym
.name
.c_str();
88 auto *compiler_options
= dev_get_nir_compiler_options(dev
);
90 nir_shader
*nir
= spirv_to_nir(data
, num_words
, nullptr, 0,
91 MESA_SHADER_KERNEL
, name
,
92 &spirv_options
, compiler_options
);
94 r_log
+= "Translation from SPIR-V to NIR for kernel \"" + sym
.name
+
99 nir
->info
.cs
.local_size_variable
= true;
100 nir_validate_shader(nir
, "clover");
102 // Calculate input offsets.
104 nir_foreach_shader_in_variable_safe(var
, nir
) {
105 offset
= align(offset
, glsl_get_cl_alignment(var
->type
));
106 var
->data
.driver_location
= offset
;
107 offset
+= glsl_get_cl_size(var
->type
);
110 // Inline all functions first.
111 // according to the comment on nir_inline_functions
112 NIR_PASS_V(nir
, nir_lower_variable_initializers
, nir_var_function_temp
);
113 NIR_PASS_V(nir
, nir_lower_returns
);
114 NIR_PASS_V(nir
, nir_inline_functions
);
115 NIR_PASS_V(nir
, nir_copy_prop
);
116 NIR_PASS_V(nir
, nir_opt_deref
);
118 // Pick off the single entrypoint that we want.
119 foreach_list_typed_safe(nir_function
, func
, node
, &nir
->functions
) {
120 if (!func
->is_entrypoint
)
121 exec_node_remove(&func
->node
);
123 assert(exec_list_length(&nir
->functions
) == 1);
125 nir_validate_shader(nir
, "clover after function inlining");
127 NIR_PASS_V(nir
, nir_lower_variable_initializers
,
128 static_cast<nir_variable_mode
>(~nir_var_function_temp
));
130 // copy propagate to prepare for lower_explicit_io
131 NIR_PASS_V(nir
, nir_split_var_copies
);
132 NIR_PASS_V(nir
, nir_opt_copy_prop_vars
);
133 NIR_PASS_V(nir
, nir_lower_var_copies
);
134 NIR_PASS_V(nir
, nir_lower_vars_to_ssa
);
135 NIR_PASS_V(nir
, nir_opt_dce
);
137 NIR_PASS_V(nir
, nir_lower_explicit_io
, nir_var_shader_in
, nir_address_format_32bit_offset
);
138 nir_variable_mode modes
= (nir_variable_mode
)(
141 nir_address_format format
= nir
->info
.cs
.ptr_size
== 64 ?
142 nir_address_format_64bit_global
: nir_address_format_32bit_global
;
143 NIR_PASS_V(nir
, nir_lower_explicit_io
, modes
, format
);
145 NIR_PASS_V(nir
, nir_lower_system_values
);
146 if (compiler_options
->lower_int64_options
)
147 NIR_PASS_V(nir
, nir_lower_int64
,
148 compiler_options
->lower_int64_options
);
150 NIR_PASS_V(nir
, nir_opt_dce
);
154 nir_serialize(&blob
, nir
, false);
156 const pipe_binary_program_header header
{ uint32_t(blob
.size
) };
157 module::section text
{ section_id
, module::section::text_executable
, header
.num_bytes
, {} };
158 text
.data
.insert(text
.data
.end(), reinterpret_cast<const char *>(&header
),
159 reinterpret_cast<const char *>(&header
) + sizeof(header
));
160 text
.data
.insert(text
.data
.end(), blob
.data
, blob
.data
+ blob
.size
);
162 m
.syms
.emplace_back(sym
.name
, section_id
, 0, sym
.args
);
163 m
.secs
.push_back(text
);
169 module
clover::nir::spirv_to_nir(const module
&mod
, const device
&dev
, std::string
&r_log
)
171 r_log
+= "SPIR-V support in clover is not enabled.\n";
172 throw error(CL_LINKER_NOT_AVAILABLE
);