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_variable_safe(var
, &nir
->inputs
) {
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_opt_deref
);
117 // Pick off the single entrypoint that we want.
118 foreach_list_typed_safe(nir_function
, func
, node
, &nir
->functions
) {
119 if (!func
->is_entrypoint
)
120 exec_node_remove(&func
->node
);
122 assert(exec_list_length(&nir
->functions
) == 1);
124 nir_validate_shader(nir
, "clover after function inlining");
126 NIR_PASS_V(nir
, nir_lower_variable_initializers
,
127 static_cast<nir_variable_mode
>(~nir_var_function_temp
));
129 // copy propagate to prepare for lower_explicit_io
130 NIR_PASS_V(nir
, nir_split_var_copies
);
131 NIR_PASS_V(nir
, nir_opt_copy_prop_vars
);
132 NIR_PASS_V(nir
, nir_lower_var_copies
);
133 NIR_PASS_V(nir
, nir_lower_vars_to_ssa
);
134 NIR_PASS_V(nir
, nir_opt_dce
);
136 nir_variable_mode modes
= (nir_variable_mode
)(
140 nir_address_format format
= nir
->info
.cs
.ptr_size
== 64 ?
141 nir_address_format_64bit_global
: nir_address_format_32bit_global
;
142 NIR_PASS_V(nir
, nir_lower_explicit_io
, modes
, format
);
144 NIR_PASS_V(nir
, nir_lower_system_values
);
145 if (compiler_options
->lower_int64_options
)
146 NIR_PASS_V(nir
, nir_lower_int64
,
147 compiler_options
->lower_int64_options
);
149 NIR_PASS_V(nir
, nir_opt_dce
);
153 nir_serialize(&blob
, nir
, false);
155 const pipe_binary_program_header header
{ uint32_t(blob
.size
) };
156 module::section text
{ section_id
, module::section::text_executable
, header
.num_bytes
, {} };
157 text
.data
.insert(text
.data
.end(), reinterpret_cast<const char *>(&header
),
158 reinterpret_cast<const char *>(&header
) + sizeof(header
));
159 text
.data
.insert(text
.data
.end(), blob
.data
, blob
.data
+ blob
.size
);
161 m
.syms
.emplace_back(sym
.name
, section_id
, 0, sym
.args
);
162 m
.secs
.push_back(text
);
168 module
clover::nir::spirv_to_nir(const module
&mod
, const device
&dev
, std::string
&r_log
)
170 r_log
+= "SPIR-V support in clover is not enabled.\n";
171 throw error(CL_LINKER_NOT_AVAILABLE
);