1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 2023 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker * Copyright 2020 Intel Corporation
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #include "asahi/compiler/agx_compile.h"
8*61046927SAndroid Build Coastguard Worker #include "compiler/clc/clc.h"
9*61046927SAndroid Build Coastguard Worker #include "compiler/glsl_types.h"
10*61046927SAndroid Build Coastguard Worker #include "compiler/spirv/nir_spirv.h"
11*61046927SAndroid Build Coastguard Worker #include "compiler/spirv/spirv_info.h"
12*61046927SAndroid Build Coastguard Worker #include "util/build_id.h"
13*61046927SAndroid Build Coastguard Worker #include "util/disk_cache.h"
14*61046927SAndroid Build Coastguard Worker #include "util/macros.h"
15*61046927SAndroid Build Coastguard Worker #include "util/mesa-sha1.h"
16*61046927SAndroid Build Coastguard Worker #include "util/u_dynarray.h"
17*61046927SAndroid Build Coastguard Worker #include "nir.h"
18*61046927SAndroid Build Coastguard Worker #include "nir_builder.h"
19*61046927SAndroid Build Coastguard Worker #include "nir_serialize.h"
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker #include <fcntl.h>
22*61046927SAndroid Build Coastguard Worker #include <getopt.h>
23*61046927SAndroid Build Coastguard Worker #include <inttypes.h>
24*61046927SAndroid Build Coastguard Worker #include <stdio.h>
25*61046927SAndroid Build Coastguard Worker #include <string.h>
26*61046927SAndroid Build Coastguard Worker #include <unistd.h>
27*61046927SAndroid Build Coastguard Worker #include "util/u_math.h"
28*61046927SAndroid Build Coastguard Worker #include <sys/mman.h>
29*61046927SAndroid Build Coastguard Worker
30*61046927SAndroid Build Coastguard Worker static const struct spirv_to_nir_options spirv_options = {
31*61046927SAndroid Build Coastguard Worker .environment = NIR_SPIRV_OPENCL,
32*61046927SAndroid Build Coastguard Worker .shared_addr_format = nir_address_format_62bit_generic,
33*61046927SAndroid Build Coastguard Worker .global_addr_format = nir_address_format_62bit_generic,
34*61046927SAndroid Build Coastguard Worker .temp_addr_format = nir_address_format_62bit_generic,
35*61046927SAndroid Build Coastguard Worker .constant_addr_format = nir_address_format_64bit_global,
36*61046927SAndroid Build Coastguard Worker .create_library = true,
37*61046927SAndroid Build Coastguard Worker };
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker static bool
lower_builtins(nir_builder * b,nir_instr * instr,void * data)40*61046927SAndroid Build Coastguard Worker lower_builtins(nir_builder *b, nir_instr *instr, void *data)
41*61046927SAndroid Build Coastguard Worker {
42*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_call)
43*61046927SAndroid Build Coastguard Worker return false;
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker nir_call_instr *call = nir_instr_as_call(instr);
46*61046927SAndroid Build Coastguard Worker nir_function *func = call->callee;
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker if (strcmp(func->name, "nir_interleave_agx") == 0) {
49*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
50*61046927SAndroid Build Coastguard Worker nir_store_deref(
51*61046927SAndroid Build Coastguard Worker b, nir_src_as_deref(call->params[0]),
52*61046927SAndroid Build Coastguard Worker nir_interleave_agx(b, call->params[1].ssa, call->params[2].ssa), 1);
53*61046927SAndroid Build Coastguard Worker
54*61046927SAndroid Build Coastguard Worker return true;
55*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_doorbell_agx") == 0) {
56*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
57*61046927SAndroid Build Coastguard Worker nir_doorbell_agx(b, call->params[0].ssa);
58*61046927SAndroid Build Coastguard Worker return true;
59*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_stack_map_agx") == 0) {
60*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
61*61046927SAndroid Build Coastguard Worker nir_stack_map_agx(b, call->params[0].ssa, call->params[1].ssa);
62*61046927SAndroid Build Coastguard Worker return true;
63*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_stack_unmap_agx") == 0) {
64*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
65*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]),
66*61046927SAndroid Build Coastguard Worker nir_stack_unmap_agx(b, call->params[1].ssa), 1);
67*61046927SAndroid Build Coastguard Worker return true;
68*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_load_core_id_agx") == 0) {
69*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
70*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]),
71*61046927SAndroid Build Coastguard Worker nir_load_core_id_agx(b), 1);
72*61046927SAndroid Build Coastguard Worker return true;
73*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_load_helper_op_id_agx") == 0) {
74*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
75*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]),
76*61046927SAndroid Build Coastguard Worker nir_load_helper_op_id_agx(b, 1, 32), 1);
77*61046927SAndroid Build Coastguard Worker return true;
78*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_load_helper_arg_lo_agx") == 0) {
79*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
80*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]),
81*61046927SAndroid Build Coastguard Worker nir_load_helper_arg_lo_agx(b, 1, 32), 1);
82*61046927SAndroid Build Coastguard Worker return true;
83*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_load_helper_arg_hi_agx") == 0) {
84*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
85*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]),
86*61046927SAndroid Build Coastguard Worker nir_load_helper_arg_hi_agx(b, 1, 32), 1);
87*61046927SAndroid Build Coastguard Worker return true;
88*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "ballot") == 0) {
89*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
90*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]),
91*61046927SAndroid Build Coastguard Worker nir_ballot(b, 1, 32, call->params[1].ssa), 1);
92*61046927SAndroid Build Coastguard Worker return true;
93*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_fence_helper_exit_agx") == 0) {
94*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
95*61046927SAndroid Build Coastguard Worker nir_fence_helper_exit_agx(b);
96*61046927SAndroid Build Coastguard Worker return true;
97*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_bindless_image_load_array") == 0) {
98*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker nir_def *texel = nir_bindless_image_load(
101*61046927SAndroid Build Coastguard Worker b, 4, 32, call->params[1].ssa, call->params[2].ssa, nir_imm_int(b, 0),
102*61046927SAndroid Build Coastguard Worker nir_imm_int(b, 0), .image_array = true,
103*61046927SAndroid Build Coastguard Worker .image_dim = GLSL_SAMPLER_DIM_2D, .dest_type = nir_type_uint32,
104*61046927SAndroid Build Coastguard Worker .access = ACCESS_IN_BOUNDS_AGX);
105*61046927SAndroid Build Coastguard Worker
106*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]), texel, 0xf);
107*61046927SAndroid Build Coastguard Worker return true;
108*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_bindless_image_store_array") == 0) {
109*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker nir_bindless_image_store(
112*61046927SAndroid Build Coastguard Worker b, call->params[0].ssa, call->params[1].ssa, nir_imm_int(b, 0),
113*61046927SAndroid Build Coastguard Worker call->params[2].ssa, nir_imm_int(b, 0), .image_array = true,
114*61046927SAndroid Build Coastguard Worker .image_dim = GLSL_SAMPLER_DIM_2D, .src_type = nir_type_uint32,
115*61046927SAndroid Build Coastguard Worker .access = ACCESS_NON_READABLE);
116*61046927SAndroid Build Coastguard Worker return true;
117*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_bindless_image_load_ms_array") == 0) {
118*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
119*61046927SAndroid Build Coastguard Worker
120*61046927SAndroid Build Coastguard Worker nir_def *texel = nir_bindless_image_load(
121*61046927SAndroid Build Coastguard Worker b, 4, 32, call->params[1].ssa, call->params[2].ssa,
122*61046927SAndroid Build Coastguard Worker call->params[3].ssa, nir_imm_int(b, 0), .image_array = true,
123*61046927SAndroid Build Coastguard Worker .image_dim = GLSL_SAMPLER_DIM_MS, .dest_type = nir_type_uint32,
124*61046927SAndroid Build Coastguard Worker .access = ACCESS_IN_BOUNDS_AGX);
125*61046927SAndroid Build Coastguard Worker
126*61046927SAndroid Build Coastguard Worker nir_store_deref(b, nir_src_as_deref(call->params[0]), texel, 0xf);
127*61046927SAndroid Build Coastguard Worker return true;
128*61046927SAndroid Build Coastguard Worker } else if (strcmp(func->name, "nir_bindless_image_store_ms_array") == 0) {
129*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&call->instr);
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker nir_bindless_image_store(
132*61046927SAndroid Build Coastguard Worker b, call->params[0].ssa, call->params[1].ssa, call->params[2].ssa,
133*61046927SAndroid Build Coastguard Worker call->params[3].ssa, nir_imm_int(b, 0), .image_array = true,
134*61046927SAndroid Build Coastguard Worker .image_dim = GLSL_SAMPLER_DIM_MS, .src_type = nir_type_uint32,
135*61046927SAndroid Build Coastguard Worker .access = ACCESS_NON_READABLE);
136*61046927SAndroid Build Coastguard Worker return true;
137*61046927SAndroid Build Coastguard Worker }
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker return false;
140*61046927SAndroid Build Coastguard Worker }
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker /* Standard optimization loop */
143*61046927SAndroid Build Coastguard Worker static void
optimize(nir_shader * nir)144*61046927SAndroid Build Coastguard Worker optimize(nir_shader *nir)
145*61046927SAndroid Build Coastguard Worker {
146*61046927SAndroid Build Coastguard Worker bool progress;
147*61046927SAndroid Build Coastguard Worker do {
148*61046927SAndroid Build Coastguard Worker progress = false;
149*61046927SAndroid Build Coastguard Worker
150*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_lower_var_copies);
151*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_lower_vars_to_ssa);
152*61046927SAndroid Build Coastguard Worker
153*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_copy_prop);
154*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_remove_phis);
155*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_lower_phis_to_scalar, true);
156*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_dce);
157*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_dead_cf);
158*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_cse);
159*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_peephole_select, 64, false, true);
160*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_phi_precision);
161*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_algebraic);
162*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_constant_folding);
163*61046927SAndroid Build Coastguard Worker
164*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_deref);
165*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_copy_prop_vars);
166*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_undef);
167*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_lower_undef_to_zero);
168*61046927SAndroid Build Coastguard Worker
169*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_shrink_vectors, true);
170*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_opt_loop_unroll);
171*61046927SAndroid Build Coastguard Worker
172*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_split_var_copies);
173*61046927SAndroid Build Coastguard Worker NIR_PASS(progress, nir, nir_split_struct_vars, nir_var_function_temp);
174*61046927SAndroid Build Coastguard Worker } while (progress);
175*61046927SAndroid Build Coastguard Worker }
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker static nir_shader *
compile(void * memctx,const uint32_t * spirv,size_t spirv_size)178*61046927SAndroid Build Coastguard Worker compile(void *memctx, const uint32_t *spirv, size_t spirv_size)
179*61046927SAndroid Build Coastguard Worker {
180*61046927SAndroid Build Coastguard Worker const nir_shader_compiler_options *nir_options = &agx_nir_options;
181*61046927SAndroid Build Coastguard Worker
182*61046927SAndroid Build Coastguard Worker assert(spirv_size % 4 == 0);
183*61046927SAndroid Build Coastguard Worker nir_shader *nir =
184*61046927SAndroid Build Coastguard Worker spirv_to_nir(spirv, spirv_size / 4, NULL, 0, MESA_SHADER_KERNEL,
185*61046927SAndroid Build Coastguard Worker "library", &spirv_options, nir_options);
186*61046927SAndroid Build Coastguard Worker nir_validate_shader(nir, "after spirv_to_nir");
187*61046927SAndroid Build Coastguard Worker nir_validate_ssa_dominance(nir, "after spirv_to_nir");
188*61046927SAndroid Build Coastguard Worker ralloc_steal(memctx, nir);
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_system_values);
191*61046927SAndroid Build Coastguard Worker nir_shader_instructions_pass(nir, lower_builtins, nir_metadata_none, NULL);
192*61046927SAndroid Build Coastguard Worker
193*61046927SAndroid Build Coastguard Worker /* We have to lower away local constant initializers right before we
194*61046927SAndroid Build Coastguard Worker * inline functions. That way they get properly initialized at the top
195*61046927SAndroid Build Coastguard Worker * of the function and not at the top of its caller.
196*61046927SAndroid Build Coastguard Worker */
197*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_variable_initializers, nir_var_function_temp);
198*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_returns);
199*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_inline_functions);
200*61046927SAndroid Build Coastguard Worker nir_remove_non_exported(nir);
201*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_copy_prop);
202*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_opt_deref);
203*61046927SAndroid Build Coastguard Worker
204*61046927SAndroid Build Coastguard Worker /* We can go ahead and lower the rest of the constant initializers. We do
205*61046927SAndroid Build Coastguard Worker * this here so that nir_remove_dead_variables and split_per_member_structs
206*61046927SAndroid Build Coastguard Worker * below see the corresponding stores.
207*61046927SAndroid Build Coastguard Worker */
208*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_variable_initializers, ~0);
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker /* LLVM loves take advantage of the fact that vec3s in OpenCL are 16B
211*61046927SAndroid Build Coastguard Worker * aligned and so it can just read/write them as vec4s. This results in a
212*61046927SAndroid Build Coastguard Worker * LOT of vec4->vec3 casts on loads and stores. One solution to this
213*61046927SAndroid Build Coastguard Worker * problem is to get rid of all vec3 variables.
214*61046927SAndroid Build Coastguard Worker */
215*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_vec3_to_vec4,
216*61046927SAndroid Build Coastguard Worker nir_var_shader_temp | nir_var_function_temp | nir_var_mem_shared |
217*61046927SAndroid Build Coastguard Worker nir_var_mem_global | nir_var_mem_constant);
218*61046927SAndroid Build Coastguard Worker
219*61046927SAndroid Build Coastguard Worker /* We assign explicit types early so that the optimizer can take advantage
220*61046927SAndroid Build Coastguard Worker * of that information and hopefully get rid of some of our memcpys.
221*61046927SAndroid Build Coastguard Worker */
222*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_vars_to_explicit_types,
223*61046927SAndroid Build Coastguard Worker nir_var_uniform | nir_var_shader_temp | nir_var_function_temp |
224*61046927SAndroid Build Coastguard Worker nir_var_mem_shared | nir_var_mem_global,
225*61046927SAndroid Build Coastguard Worker glsl_get_cl_type_size_align);
226*61046927SAndroid Build Coastguard Worker
227*61046927SAndroid Build Coastguard Worker optimize(nir);
228*61046927SAndroid Build Coastguard Worker
229*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_remove_dead_variables, nir_var_all, NULL);
230*61046927SAndroid Build Coastguard Worker
231*61046927SAndroid Build Coastguard Worker /* Lower again, this time after dead-variables to get more compact variable
232*61046927SAndroid Build Coastguard Worker * layouts.
233*61046927SAndroid Build Coastguard Worker */
234*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_vars_to_explicit_types,
235*61046927SAndroid Build Coastguard Worker nir_var_shader_temp | nir_var_function_temp | nir_var_mem_shared |
236*61046927SAndroid Build Coastguard Worker nir_var_mem_global | nir_var_mem_constant,
237*61046927SAndroid Build Coastguard Worker glsl_get_cl_type_size_align);
238*61046927SAndroid Build Coastguard Worker if (nir->constant_data_size > 0) {
239*61046927SAndroid Build Coastguard Worker assert(nir->constant_data == NULL);
240*61046927SAndroid Build Coastguard Worker nir->constant_data = rzalloc_size(nir, nir->constant_data_size);
241*61046927SAndroid Build Coastguard Worker nir_gather_explicit_io_initializers(nir, nir->constant_data,
242*61046927SAndroid Build Coastguard Worker nir->constant_data_size,
243*61046927SAndroid Build Coastguard Worker nir_var_mem_constant);
244*61046927SAndroid Build Coastguard Worker }
245*61046927SAndroid Build Coastguard Worker
246*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_memcpy);
247*61046927SAndroid Build Coastguard Worker
248*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_explicit_io, nir_var_mem_constant,
249*61046927SAndroid Build Coastguard Worker nir_address_format_64bit_global);
250*61046927SAndroid Build Coastguard Worker
251*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_explicit_io, nir_var_uniform,
252*61046927SAndroid Build Coastguard Worker nir_address_format_32bit_offset_as_64bit);
253*61046927SAndroid Build Coastguard Worker
254*61046927SAndroid Build Coastguard Worker /* Note: we cannot lower explicit I/O here, because we need derefs in tact
255*61046927SAndroid Build Coastguard Worker * for function calls into the library to work.
256*61046927SAndroid Build Coastguard Worker */
257*61046927SAndroid Build Coastguard Worker
258*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_convert_alu_types, NULL);
259*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_opt_if, 0);
260*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_opt_idiv_const, 16);
261*61046927SAndroid Build Coastguard Worker
262*61046927SAndroid Build Coastguard Worker optimize(nir);
263*61046927SAndroid Build Coastguard Worker
264*61046927SAndroid Build Coastguard Worker return nir;
265*61046927SAndroid Build Coastguard Worker }
266*61046927SAndroid Build Coastguard Worker
267*61046927SAndroid Build Coastguard Worker /* Shader functions */
268*61046927SAndroid Build Coastguard Worker #define SPIR_V_MAGIC_NUMBER 0x07230203
269*61046927SAndroid Build Coastguard Worker
270*61046927SAndroid Build Coastguard Worker static void
msg_callback(void * priv,const char * msg)271*61046927SAndroid Build Coastguard Worker msg_callback(void *priv, const char *msg)
272*61046927SAndroid Build Coastguard Worker {
273*61046927SAndroid Build Coastguard Worker (void)priv;
274*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%s", msg);
275*61046927SAndroid Build Coastguard Worker }
276*61046927SAndroid Build Coastguard Worker
277*61046927SAndroid Build Coastguard Worker static void
print_u32_data(FILE * fp,const char * prefix,const char * arr_name,const uint32_t * data,size_t len)278*61046927SAndroid Build Coastguard Worker print_u32_data(FILE *fp, const char *prefix, const char *arr_name,
279*61046927SAndroid Build Coastguard Worker const uint32_t *data, size_t len)
280*61046927SAndroid Build Coastguard Worker {
281*61046927SAndroid Build Coastguard Worker fprintf(fp, "static const uint32_t %s_%s[] = {", prefix, arr_name);
282*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < (len / 4); i++) {
283*61046927SAndroid Build Coastguard Worker if (i % 4 == 0)
284*61046927SAndroid Build Coastguard Worker fprintf(fp, "\n ");
285*61046927SAndroid Build Coastguard Worker
286*61046927SAndroid Build Coastguard Worker fprintf(fp, " 0x%08" PRIx32 ",", data[i]);
287*61046927SAndroid Build Coastguard Worker }
288*61046927SAndroid Build Coastguard Worker
289*61046927SAndroid Build Coastguard Worker if (len % 4) {
290*61046927SAndroid Build Coastguard Worker const uint8_t *data_u8 = (const uint8_t *)data;
291*61046927SAndroid Build Coastguard Worker uint32_t last = 0;
292*61046927SAndroid Build Coastguard Worker unsigned last_offs = ROUND_DOWN_TO(len, 4);
293*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < len % 4; ++i) {
294*61046927SAndroid Build Coastguard Worker last |= (uint32_t)data_u8[last_offs + i] << (i * 8);
295*61046927SAndroid Build Coastguard Worker }
296*61046927SAndroid Build Coastguard Worker
297*61046927SAndroid Build Coastguard Worker fprintf(fp, " 0x%08" PRIx32 ",", last);
298*61046927SAndroid Build Coastguard Worker }
299*61046927SAndroid Build Coastguard Worker
300*61046927SAndroid Build Coastguard Worker fprintf(fp, "\n};\n");
301*61046927SAndroid Build Coastguard Worker }
302*61046927SAndroid Build Coastguard Worker
303*61046927SAndroid Build Coastguard Worker static void
print_usage(char * exec_name,FILE * f)304*61046927SAndroid Build Coastguard Worker print_usage(char *exec_name, FILE *f)
305*61046927SAndroid Build Coastguard Worker {
306*61046927SAndroid Build Coastguard Worker fprintf(
307*61046927SAndroid Build Coastguard Worker f,
308*61046927SAndroid Build Coastguard Worker "Usage: %s [options] -- [clang args]\n"
309*61046927SAndroid Build Coastguard Worker "Options:\n"
310*61046927SAndroid Build Coastguard Worker " -h --help Print this help.\n"
311*61046927SAndroid Build Coastguard Worker " --prefix <prefix> Prefix for variable names in generated C code.\n"
312*61046927SAndroid Build Coastguard Worker " -o, --out <filename> Specify the output filename.\n"
313*61046927SAndroid Build Coastguard Worker " -i, --in <filename> Specify one input filename. Accepted multiple times.\n"
314*61046927SAndroid Build Coastguard Worker " -s, --spv <filename> Specify the output filename for spirv.\n"
315*61046927SAndroid Build Coastguard Worker " -v, --verbose Print more information during compilation.\n",
316*61046927SAndroid Build Coastguard Worker exec_name);
317*61046927SAndroid Build Coastguard Worker }
318*61046927SAndroid Build Coastguard Worker
319*61046927SAndroid Build Coastguard Worker #define OPT_PREFIX 1000
320*61046927SAndroid Build Coastguard Worker
321*61046927SAndroid Build Coastguard Worker static uint32_t
get_module_spirv_version(const uint32_t * spirv,size_t size)322*61046927SAndroid Build Coastguard Worker get_module_spirv_version(const uint32_t *spirv, size_t size)
323*61046927SAndroid Build Coastguard Worker {
324*61046927SAndroid Build Coastguard Worker assert(size >= 8);
325*61046927SAndroid Build Coastguard Worker assert(spirv[0] == SPIR_V_MAGIC_NUMBER);
326*61046927SAndroid Build Coastguard Worker return spirv[1];
327*61046927SAndroid Build Coastguard Worker }
328*61046927SAndroid Build Coastguard Worker
329*61046927SAndroid Build Coastguard Worker static void
set_module_spirv_version(uint32_t * spirv,size_t size,uint32_t version)330*61046927SAndroid Build Coastguard Worker set_module_spirv_version(uint32_t *spirv, size_t size, uint32_t version)
331*61046927SAndroid Build Coastguard Worker {
332*61046927SAndroid Build Coastguard Worker assert(size >= 8);
333*61046927SAndroid Build Coastguard Worker assert(spirv[0] == SPIR_V_MAGIC_NUMBER);
334*61046927SAndroid Build Coastguard Worker spirv[1] = version;
335*61046927SAndroid Build Coastguard Worker }
336*61046927SAndroid Build Coastguard Worker
337*61046927SAndroid Build Coastguard Worker int
main(int argc,char ** argv)338*61046927SAndroid Build Coastguard Worker main(int argc, char **argv)
339*61046927SAndroid Build Coastguard Worker {
340*61046927SAndroid Build Coastguard Worker static struct option long_options[] = {
341*61046927SAndroid Build Coastguard Worker {"help", no_argument, 0, 'h'},
342*61046927SAndroid Build Coastguard Worker {"prefix", required_argument, 0, OPT_PREFIX},
343*61046927SAndroid Build Coastguard Worker {"in", required_argument, 0, 'i'},
344*61046927SAndroid Build Coastguard Worker {"out", required_argument, 0, 'o'},
345*61046927SAndroid Build Coastguard Worker {"spv", required_argument, 0, 's'},
346*61046927SAndroid Build Coastguard Worker {"verbose", no_argument, 0, 'v'},
347*61046927SAndroid Build Coastguard Worker {0, 0, 0, 0},
348*61046927SAndroid Build Coastguard Worker };
349*61046927SAndroid Build Coastguard Worker
350*61046927SAndroid Build Coastguard Worker char *outfile = NULL, *spv_outfile = NULL, *prefix = NULL;
351*61046927SAndroid Build Coastguard Worker struct util_dynarray clang_args;
352*61046927SAndroid Build Coastguard Worker struct util_dynarray input_files;
353*61046927SAndroid Build Coastguard Worker struct util_dynarray spirv_objs;
354*61046927SAndroid Build Coastguard Worker struct util_dynarray spirv_ptr_objs;
355*61046927SAndroid Build Coastguard Worker
356*61046927SAndroid Build Coastguard Worker void *mem_ctx = ralloc_context(NULL);
357*61046927SAndroid Build Coastguard Worker
358*61046927SAndroid Build Coastguard Worker util_dynarray_init(&clang_args, mem_ctx);
359*61046927SAndroid Build Coastguard Worker util_dynarray_init(&input_files, mem_ctx);
360*61046927SAndroid Build Coastguard Worker util_dynarray_init(&spirv_objs, mem_ctx);
361*61046927SAndroid Build Coastguard Worker util_dynarray_init(&spirv_ptr_objs, mem_ctx);
362*61046927SAndroid Build Coastguard Worker
363*61046927SAndroid Build Coastguard Worker int ch;
364*61046927SAndroid Build Coastguard Worker while ((ch = getopt_long(argc, argv, "he:p:s:i:o:v", long_options, NULL)) !=
365*61046927SAndroid Build Coastguard Worker -1) {
366*61046927SAndroid Build Coastguard Worker switch (ch) {
367*61046927SAndroid Build Coastguard Worker case 'h':
368*61046927SAndroid Build Coastguard Worker print_usage(argv[0], stdout);
369*61046927SAndroid Build Coastguard Worker return 0;
370*61046927SAndroid Build Coastguard Worker case 'o':
371*61046927SAndroid Build Coastguard Worker outfile = optarg;
372*61046927SAndroid Build Coastguard Worker break;
373*61046927SAndroid Build Coastguard Worker case 'i':
374*61046927SAndroid Build Coastguard Worker util_dynarray_append(&input_files, char *, optarg);
375*61046927SAndroid Build Coastguard Worker break;
376*61046927SAndroid Build Coastguard Worker case 's':
377*61046927SAndroid Build Coastguard Worker spv_outfile = optarg;
378*61046927SAndroid Build Coastguard Worker break;
379*61046927SAndroid Build Coastguard Worker case OPT_PREFIX:
380*61046927SAndroid Build Coastguard Worker prefix = optarg;
381*61046927SAndroid Build Coastguard Worker break;
382*61046927SAndroid Build Coastguard Worker default:
383*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Unrecognized option \"%s\".\n", optarg);
384*61046927SAndroid Build Coastguard Worker print_usage(argv[0], stderr);
385*61046927SAndroid Build Coastguard Worker return 1;
386*61046927SAndroid Build Coastguard Worker }
387*61046927SAndroid Build Coastguard Worker }
388*61046927SAndroid Build Coastguard Worker
389*61046927SAndroid Build Coastguard Worker for (int i = optind; i < argc; i++) {
390*61046927SAndroid Build Coastguard Worker util_dynarray_append(&clang_args, char *, argv[i]);
391*61046927SAndroid Build Coastguard Worker }
392*61046927SAndroid Build Coastguard Worker
393*61046927SAndroid Build Coastguard Worker if (util_dynarray_num_elements(&input_files, char *) == 0) {
394*61046927SAndroid Build Coastguard Worker fprintf(stderr, "No input file(s).\n");
395*61046927SAndroid Build Coastguard Worker print_usage(argv[0], stderr);
396*61046927SAndroid Build Coastguard Worker return -1;
397*61046927SAndroid Build Coastguard Worker }
398*61046927SAndroid Build Coastguard Worker
399*61046927SAndroid Build Coastguard Worker if (prefix == NULL) {
400*61046927SAndroid Build Coastguard Worker fprintf(stderr, "No prefix specified.\n");
401*61046927SAndroid Build Coastguard Worker print_usage(argv[0], stderr);
402*61046927SAndroid Build Coastguard Worker return -1;
403*61046927SAndroid Build Coastguard Worker }
404*61046927SAndroid Build Coastguard Worker
405*61046927SAndroid Build Coastguard Worker struct clc_logger logger = {
406*61046927SAndroid Build Coastguard Worker .error = msg_callback,
407*61046927SAndroid Build Coastguard Worker .warning = msg_callback,
408*61046927SAndroid Build Coastguard Worker };
409*61046927SAndroid Build Coastguard Worker
410*61046927SAndroid Build Coastguard Worker util_dynarray_foreach(&input_files, char *, infile) {
411*61046927SAndroid Build Coastguard Worker int fd = open(*infile, O_RDONLY);
412*61046927SAndroid Build Coastguard Worker if (fd < 0) {
413*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Failed to open %s\n", *infile);
414*61046927SAndroid Build Coastguard Worker ralloc_free(mem_ctx);
415*61046927SAndroid Build Coastguard Worker return 1;
416*61046927SAndroid Build Coastguard Worker }
417*61046927SAndroid Build Coastguard Worker
418*61046927SAndroid Build Coastguard Worker off_t len = lseek(fd, 0, SEEK_END);
419*61046927SAndroid Build Coastguard Worker const void *map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
420*61046927SAndroid Build Coastguard Worker close(fd);
421*61046927SAndroid Build Coastguard Worker if (map == MAP_FAILED) {
422*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Failed to mmap the file: errno=%d, %s\n", errno,
423*61046927SAndroid Build Coastguard Worker strerror(errno));
424*61046927SAndroid Build Coastguard Worker ralloc_free(mem_ctx);
425*61046927SAndroid Build Coastguard Worker return 1;
426*61046927SAndroid Build Coastguard Worker }
427*61046927SAndroid Build Coastguard Worker
428*61046927SAndroid Build Coastguard Worker const char *allowed_spirv_extensions[] = {
429*61046927SAndroid Build Coastguard Worker "SPV_EXT_shader_atomic_float_add",
430*61046927SAndroid Build Coastguard Worker "SPV_EXT_shader_atomic_float_min_max",
431*61046927SAndroid Build Coastguard Worker "SPV_KHR_float_controls",
432*61046927SAndroid Build Coastguard Worker "SPV_INTEL_subgroups",
433*61046927SAndroid Build Coastguard Worker NULL,
434*61046927SAndroid Build Coastguard Worker };
435*61046927SAndroid Build Coastguard Worker
436*61046927SAndroid Build Coastguard Worker struct clc_compile_args clc_args = {
437*61046927SAndroid Build Coastguard Worker .source =
438*61046927SAndroid Build Coastguard Worker {
439*61046927SAndroid Build Coastguard Worker .name = *infile,
440*61046927SAndroid Build Coastguard Worker .value = map,
441*61046927SAndroid Build Coastguard Worker },
442*61046927SAndroid Build Coastguard Worker .features =
443*61046927SAndroid Build Coastguard Worker {
444*61046927SAndroid Build Coastguard Worker .fp16 = true,
445*61046927SAndroid Build Coastguard Worker .intel_subgroups = true,
446*61046927SAndroid Build Coastguard Worker .subgroups = true,
447*61046927SAndroid Build Coastguard Worker .subgroups_ifp = true,
448*61046927SAndroid Build Coastguard Worker },
449*61046927SAndroid Build Coastguard Worker .args = util_dynarray_begin(&clang_args),
450*61046927SAndroid Build Coastguard Worker .num_args = util_dynarray_num_elements(&clang_args, char *),
451*61046927SAndroid Build Coastguard Worker .allowed_spirv_extensions = allowed_spirv_extensions,
452*61046927SAndroid Build Coastguard Worker };
453*61046927SAndroid Build Coastguard Worker
454*61046927SAndroid Build Coastguard Worker struct clc_binary *spirv_out =
455*61046927SAndroid Build Coastguard Worker util_dynarray_grow(&spirv_objs, struct clc_binary, 1);
456*61046927SAndroid Build Coastguard Worker
457*61046927SAndroid Build Coastguard Worker if (!clc_compile_c_to_spirv(&clc_args, &logger, spirv_out)) {
458*61046927SAndroid Build Coastguard Worker ralloc_free(mem_ctx);
459*61046927SAndroid Build Coastguard Worker return 1;
460*61046927SAndroid Build Coastguard Worker }
461*61046927SAndroid Build Coastguard Worker }
462*61046927SAndroid Build Coastguard Worker
463*61046927SAndroid Build Coastguard Worker util_dynarray_foreach(&spirv_objs, struct clc_binary, p) {
464*61046927SAndroid Build Coastguard Worker util_dynarray_append(&spirv_ptr_objs, struct clc_binary *, p);
465*61046927SAndroid Build Coastguard Worker }
466*61046927SAndroid Build Coastguard Worker
467*61046927SAndroid Build Coastguard Worker /* The SPIRV-Tools linker started checking that all modules have the same
468*61046927SAndroid Build Coastguard Worker * version. But SPIRV-LLVM-Translator picks the lower required version for
469*61046927SAndroid Build Coastguard Worker * each module it compiles. So we have to iterate over all of them and set
470*61046927SAndroid Build Coastguard Worker * the max found to make SPIRV-Tools link our modules.
471*61046927SAndroid Build Coastguard Worker *
472*61046927SAndroid Build Coastguard Worker * TODO: This is not the correct thing to do. We need SPIRV-LLVM-Translator
473*61046927SAndroid Build Coastguard Worker * to pick a given SPIRV version given to it and have all the modules
474*61046927SAndroid Build Coastguard Worker * at that version. We should remove this hack when this issue is
475*61046927SAndroid Build Coastguard Worker * fixed :
476*61046927SAndroid Build Coastguard Worker * https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1445
477*61046927SAndroid Build Coastguard Worker */
478*61046927SAndroid Build Coastguard Worker uint32_t max_spirv_version = 0;
479*61046927SAndroid Build Coastguard Worker util_dynarray_foreach(&spirv_ptr_objs, struct clc_binary *, module) {
480*61046927SAndroid Build Coastguard Worker max_spirv_version =
481*61046927SAndroid Build Coastguard Worker MAX2(max_spirv_version,
482*61046927SAndroid Build Coastguard Worker get_module_spirv_version((*module)->data, (*module)->size));
483*61046927SAndroid Build Coastguard Worker }
484*61046927SAndroid Build Coastguard Worker
485*61046927SAndroid Build Coastguard Worker assert(max_spirv_version > 0);
486*61046927SAndroid Build Coastguard Worker util_dynarray_foreach(&spirv_ptr_objs, struct clc_binary *, module) {
487*61046927SAndroid Build Coastguard Worker set_module_spirv_version((*module)->data, (*module)->size,
488*61046927SAndroid Build Coastguard Worker max_spirv_version);
489*61046927SAndroid Build Coastguard Worker }
490*61046927SAndroid Build Coastguard Worker
491*61046927SAndroid Build Coastguard Worker struct clc_linker_args link_args = {
492*61046927SAndroid Build Coastguard Worker .in_objs = util_dynarray_begin(&spirv_ptr_objs),
493*61046927SAndroid Build Coastguard Worker .num_in_objs =
494*61046927SAndroid Build Coastguard Worker util_dynarray_num_elements(&spirv_ptr_objs, struct clc_binary *),
495*61046927SAndroid Build Coastguard Worker .create_library = true,
496*61046927SAndroid Build Coastguard Worker };
497*61046927SAndroid Build Coastguard Worker struct clc_binary final_spirv;
498*61046927SAndroid Build Coastguard Worker if (!clc_link_spirv(&link_args, &logger, &final_spirv)) {
499*61046927SAndroid Build Coastguard Worker ralloc_free(mem_ctx);
500*61046927SAndroid Build Coastguard Worker return 1;
501*61046927SAndroid Build Coastguard Worker }
502*61046927SAndroid Build Coastguard Worker
503*61046927SAndroid Build Coastguard Worker if (spv_outfile) {
504*61046927SAndroid Build Coastguard Worker FILE *fp = fopen(spv_outfile, "w");
505*61046927SAndroid Build Coastguard Worker fwrite(final_spirv.data, final_spirv.size, 1, fp);
506*61046927SAndroid Build Coastguard Worker fclose(fp);
507*61046927SAndroid Build Coastguard Worker }
508*61046927SAndroid Build Coastguard Worker
509*61046927SAndroid Build Coastguard Worker FILE *fp = stdout;
510*61046927SAndroid Build Coastguard Worker if (outfile != NULL)
511*61046927SAndroid Build Coastguard Worker fp = fopen(outfile, "w");
512*61046927SAndroid Build Coastguard Worker
513*61046927SAndroid Build Coastguard Worker glsl_type_singleton_init_or_ref();
514*61046927SAndroid Build Coastguard Worker
515*61046927SAndroid Build Coastguard Worker fprintf(fp, "/*\n");
516*61046927SAndroid Build Coastguard Worker fprintf(fp, " * Copyright The Asahi Linux Contributors\n");
517*61046927SAndroid Build Coastguard Worker fprintf(fp, " * SPDX-License-Identifier: MIT\n");
518*61046927SAndroid Build Coastguard Worker fprintf(fp, " *\n");
519*61046927SAndroid Build Coastguard Worker fprintf(fp, " * Autogenerated file, do not edit\n");
520*61046927SAndroid Build Coastguard Worker fprintf(fp, " */\n");
521*61046927SAndroid Build Coastguard Worker fprintf(fp, " #include <stdint.h>\n");
522*61046927SAndroid Build Coastguard Worker
523*61046927SAndroid Build Coastguard Worker /* Compile SPIR-V to NIR */
524*61046927SAndroid Build Coastguard Worker nir_shader *nir = compile(mem_ctx, final_spirv.data, final_spirv.size);
525*61046927SAndroid Build Coastguard Worker
526*61046927SAndroid Build Coastguard Worker {
527*61046927SAndroid Build Coastguard Worker nir_builder b = nir_builder_init_simple_shader(
528*61046927SAndroid Build Coastguard Worker MESA_SHADER_COMPUTE, &agx_nir_options, "Helper shader");
529*61046927SAndroid Build Coastguard Worker
530*61046927SAndroid Build Coastguard Worker nir_function *func =
531*61046927SAndroid Build Coastguard Worker nir_shader_get_function_for_name(nir, "libagx_helper");
532*61046927SAndroid Build Coastguard Worker
533*61046927SAndroid Build Coastguard Worker nir_call(&b, nir_function_clone(b.shader, func));
534*61046927SAndroid Build Coastguard Worker
535*61046927SAndroid Build Coastguard Worker struct agx_shader_part compiled;
536*61046927SAndroid Build Coastguard Worker struct agx_shader_key key = {
537*61046927SAndroid Build Coastguard Worker .libagx = nir,
538*61046927SAndroid Build Coastguard Worker .is_helper = true,
539*61046927SAndroid Build Coastguard Worker };
540*61046927SAndroid Build Coastguard Worker
541*61046927SAndroid Build Coastguard Worker agx_preprocess_nir(b.shader, nir);
542*61046927SAndroid Build Coastguard Worker agx_compile_shader_nir(b.shader, &key, NULL, &compiled);
543*61046927SAndroid Build Coastguard Worker
544*61046927SAndroid Build Coastguard Worker print_u32_data(fp, "libagx_g13", "helper", compiled.binary,
545*61046927SAndroid Build Coastguard Worker compiled.binary_size);
546*61046927SAndroid Build Coastguard Worker free(compiled.binary);
547*61046927SAndroid Build Coastguard Worker ralloc_free(b.shader);
548*61046927SAndroid Build Coastguard Worker
549*61046927SAndroid Build Coastguard Worker /* Remove the NIR function, it's compiled, we don't need it at runtime */
550*61046927SAndroid Build Coastguard Worker exec_node_remove(&func->node);
551*61046927SAndroid Build Coastguard Worker }
552*61046927SAndroid Build Coastguard Worker
553*61046927SAndroid Build Coastguard Worker spirv_library_to_nir_builder(fp, final_spirv.data, final_spirv.size / 4,
554*61046927SAndroid Build Coastguard Worker &spirv_options);
555*61046927SAndroid Build Coastguard Worker
556*61046927SAndroid Build Coastguard Worker /* Serialize NIR for embedding */
557*61046927SAndroid Build Coastguard Worker struct blob blob;
558*61046927SAndroid Build Coastguard Worker blob_init(&blob);
559*61046927SAndroid Build Coastguard Worker nir_serialize(&blob, nir, false /* strip */);
560*61046927SAndroid Build Coastguard Worker print_u32_data(fp, prefix, "nir", (const uint32_t *)blob.data, blob.size);
561*61046927SAndroid Build Coastguard Worker blob_finish(&blob);
562*61046927SAndroid Build Coastguard Worker
563*61046927SAndroid Build Coastguard Worker glsl_type_singleton_decref();
564*61046927SAndroid Build Coastguard Worker
565*61046927SAndroid Build Coastguard Worker if (fp != stdout)
566*61046927SAndroid Build Coastguard Worker fclose(fp);
567*61046927SAndroid Build Coastguard Worker
568*61046927SAndroid Build Coastguard Worker util_dynarray_foreach(&spirv_objs, struct clc_binary, p) {
569*61046927SAndroid Build Coastguard Worker clc_free_spirv(p);
570*61046927SAndroid Build Coastguard Worker }
571*61046927SAndroid Build Coastguard Worker
572*61046927SAndroid Build Coastguard Worker clc_free_spirv(&final_spirv);
573*61046927SAndroid Build Coastguard Worker ralloc_free(mem_ctx);
574*61046927SAndroid Build Coastguard Worker
575*61046927SAndroid Build Coastguard Worker return 0;
576*61046927SAndroid Build Coastguard Worker }
577