1 /*
2 * Copyright © 2018 Google
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "aco_interface.h"
8
9 #include "aco_ir.h"
10
11 #include "util/memstream.h"
12
13 #include "ac_gpu_info.h"
14 #include <array>
15 #include <iostream>
16 #include <vector>
17
18 using namespace aco;
19
20 namespace {
21
22 static const std::array<aco_compiler_statistic_info, aco_num_statistics> statistic_infos = []()
__anon47907a690202() 23 {
24 std::array<aco_compiler_statistic_info, aco_num_statistics> ret{};
25 ret[aco_statistic_hash] =
26 aco_compiler_statistic_info{"Hash", "CRC32 hash of code and constant data"};
27 ret[aco_statistic_instructions] =
28 aco_compiler_statistic_info{"Instructions", "Instruction count"};
29 ret[aco_statistic_copies] =
30 aco_compiler_statistic_info{"Copies", "Copy instructions created for pseudo-instructions"};
31 ret[aco_statistic_branches] = aco_compiler_statistic_info{"Branches", "Branch instructions"};
32 ret[aco_statistic_latency] =
33 aco_compiler_statistic_info{"Latency", "Issue cycles plus stall cycles"};
34 ret[aco_statistic_inv_throughput] = aco_compiler_statistic_info{
35 "Inverse Throughput", "Estimated busy cycles to execute one wave"};
36 ret[aco_statistic_vmem_clauses] = aco_compiler_statistic_info{
37 "VMEM Clause", "Number of VMEM clauses (includes 1-sized clauses)"};
38 ret[aco_statistic_smem_clauses] = aco_compiler_statistic_info{
39 "SMEM Clause", "Number of SMEM clauses (includes 1-sized clauses)"};
40 ret[aco_statistic_sgpr_presched] =
41 aco_compiler_statistic_info{"Pre-Sched SGPRs", "SGPR usage before scheduling"};
42 ret[aco_statistic_vgpr_presched] =
43 aco_compiler_statistic_info{"Pre-Sched VGPRs", "VGPR usage before scheduling"};
44 ret[aco_statistic_valu] = aco_compiler_statistic_info{"VALU", "Number of VALU instructions"};
45 ret[aco_statistic_salu] = aco_compiler_statistic_info{"SALU", "Number of SALU instructions"};
46 ret[aco_statistic_vmem] = aco_compiler_statistic_info{"VMEM", "Number of VMEM instructions"};
47 ret[aco_statistic_smem] = aco_compiler_statistic_info{"SMEM", "Number of SMEM instructions"};
48 ret[aco_statistic_vopd] = aco_compiler_statistic_info{"VOPD", "Number of VOPD instructions"};
49 return ret;
50 }();
51
52 static void
validate(Program * program)53 validate(Program* program)
54 {
55 if (!(debug_flags & DEBUG_VALIDATE_IR))
56 return;
57
58 ASSERTED bool is_valid = validate_ir(program);
59 assert(is_valid);
60 }
61
62 static std::string
get_disasm_string(Program * program,std::vector<uint32_t> & code,unsigned exec_size)63 get_disasm_string(Program* program, std::vector<uint32_t>& code, unsigned exec_size)
64 {
65 std::string disasm;
66
67 char* data = NULL;
68 size_t disasm_size = 0;
69 struct u_memstream mem;
70 if (u_memstream_open(&mem, &data, &disasm_size)) {
71 FILE* const memf = u_memstream_get(&mem);
72 if (check_print_asm_support(program)) {
73 print_asm(program, code, exec_size / 4u, memf);
74 } else {
75 fprintf(memf, "Shader disassembly is not supported in the current configuration"
76 #if !AMD_LLVM_AVAILABLE
77 " (LLVM not available)"
78 #endif
79 ", falling back to print_program.\n\n");
80 aco_print_program(program, memf);
81 }
82 fputc(0, memf);
83 u_memstream_close(&mem);
84 disasm = std::string(data, data + disasm_size);
85 free(data);
86 }
87
88 return disasm;
89 }
90
91 static std::string
aco_postprocess_shader(const struct aco_compiler_options * options,const struct aco_shader_info * info,std::unique_ptr<Program> & program)92 aco_postprocess_shader(const struct aco_compiler_options* options,
93 const struct aco_shader_info* info, std::unique_ptr<Program>& program)
94 {
95 std::string llvm_ir;
96
97 if (options->dump_preoptir)
98 aco_print_program(program.get(), stderr);
99
100 ASSERTED bool is_valid = validate_cfg(program.get());
101 assert(is_valid);
102
103 if (!info->is_trap_handler_shader) {
104 dominator_tree(program.get());
105 lower_phis(program.get());
106
107 if (program->gfx_level <= GFX7)
108 lower_subdword(program.get());
109
110 validate(program.get());
111
112 /* Optimization */
113 if (!options->optimisations_disabled) {
114 if (!(debug_flags & DEBUG_NO_VN))
115 value_numbering(program.get());
116 if (!(debug_flags & DEBUG_NO_OPT))
117 optimize(program.get());
118 }
119
120 /* cleanup and exec mask handling */
121 setup_reduce_temp(program.get());
122 insert_exec_mask(program.get());
123 validate(program.get());
124
125 /* spilling and scheduling */
126 live_var_analysis(program.get());
127 if (program->collect_statistics)
128 collect_presched_stats(program.get());
129 spill(program.get());
130 }
131
132 if (options->record_ir) {
133 char* data = NULL;
134 size_t size = 0;
135 u_memstream mem;
136 if (u_memstream_open(&mem, &data, &size)) {
137 FILE* const memf = u_memstream_get(&mem);
138 aco_print_program(program.get(), memf);
139 fputc(0, memf);
140 u_memstream_close(&mem);
141 }
142
143 llvm_ir = std::string(data, data + size);
144 free(data);
145 }
146
147 if ((debug_flags & DEBUG_LIVE_INFO) && options->dump_shader)
148 aco_print_program(program.get(), stderr, print_live_vars | print_kill);
149
150 if (!info->is_trap_handler_shader) {
151 if (!options->optimisations_disabled && !(debug_flags & DEBUG_NO_SCHED))
152 schedule_program(program.get());
153 validate(program.get());
154
155 /* Register Allocation */
156 register_allocation(program.get());
157
158 if (validate_ra(program.get())) {
159 aco_print_program(program.get(), stderr);
160 abort();
161 } else if (options->dump_shader) {
162 aco_print_program(program.get(), stderr);
163 }
164
165 validate(program.get());
166
167 /* Optimization */
168 if (!options->optimisations_disabled && !(debug_flags & DEBUG_NO_OPT)) {
169 optimize_postRA(program.get());
170 validate(program.get());
171 }
172
173 ssa_elimination(program.get());
174 }
175
176 /* Lower to HW Instructions */
177 lower_to_hw_instr(program.get());
178 validate(program.get());
179
180 if (!options->optimisations_disabled && !(debug_flags & DEBUG_NO_SCHED_VOPD))
181 schedule_vopd(program.get());
182
183 /* Schedule hardware instructions for ILP */
184 if (!options->optimisations_disabled && !(debug_flags & DEBUG_NO_SCHED_ILP))
185 schedule_ilp(program.get());
186
187 insert_waitcnt(program.get());
188 insert_NOPs(program.get());
189 if (program->gfx_level >= GFX11)
190 insert_delay_alu(program.get());
191
192 if (program->gfx_level >= GFX10)
193 form_hard_clauses(program.get());
194
195 if (program->gfx_level >= GFX11)
196 combine_delay_alu(program.get());
197
198 if (program->collect_statistics || (debug_flags & DEBUG_PERF_INFO))
199 collect_preasm_stats(program.get());
200
201 return llvm_ir;
202 }
203
204 typedef void(select_shader_part_callback)(Program* program, void* pinfo, ac_shader_config* config,
205 const struct aco_compiler_options* options,
206 const struct aco_shader_info* info,
207 const struct ac_shader_args* args);
208
209 static void
aco_compile_shader_part(const struct aco_compiler_options * options,const struct aco_shader_info * info,const struct ac_shader_args * args,select_shader_part_callback select_shader_part,void * pinfo,aco_shader_part_callback * build_binary,void ** binary,bool is_prolog=false)210 aco_compile_shader_part(const struct aco_compiler_options* options,
211 const struct aco_shader_info* info, const struct ac_shader_args* args,
212 select_shader_part_callback select_shader_part, void* pinfo,
213 aco_shader_part_callback* build_binary, void** binary,
214 bool is_prolog = false)
215 {
216 init();
217
218 ac_shader_config config = {0};
219 std::unique_ptr<Program> program{new Program};
220
221 program->collect_statistics = options->record_stats;
222 if (program->collect_statistics)
223 memset(program->statistics, 0, sizeof(program->statistics));
224
225 program->debug.func = options->debug.func;
226 program->debug.private_data = options->debug.private_data;
227
228 program->is_prolog = is_prolog;
229 program->is_epilog = !is_prolog;
230
231 /* Instruction selection */
232 select_shader_part(program.get(), pinfo, &config, options, info, args);
233
234 aco_postprocess_shader(options, info, program);
235
236 /* assembly */
237 std::vector<uint32_t> code;
238 bool append_endpgm = !(options->is_opengl && is_prolog);
239 unsigned exec_size = emit_program(program.get(), code, NULL, append_endpgm);
240
241 bool get_disasm = options->dump_shader || options->record_ir;
242
243 std::string disasm;
244 if (get_disasm)
245 disasm = get_disasm_string(program.get(), code, exec_size);
246
247 (*build_binary)(binary, config.num_sgprs, config.num_vgprs, code.data(), code.size(),
248 disasm.data(), disasm.size());
249 }
250
251 } /* end namespace */
252
253 void
aco_compile_shader(const struct aco_compiler_options * options,const struct aco_shader_info * info,unsigned shader_count,struct nir_shader * const * shaders,const struct ac_shader_args * args,aco_callback * build_binary,void ** binary)254 aco_compile_shader(const struct aco_compiler_options* options, const struct aco_shader_info* info,
255 unsigned shader_count, struct nir_shader* const* shaders,
256 const struct ac_shader_args* args, aco_callback* build_binary, void** binary)
257 {
258 init();
259
260 ac_shader_config config = {0};
261 std::unique_ptr<Program> program{new Program};
262
263 program->collect_statistics = options->record_stats;
264 if (program->collect_statistics)
265 memset(program->statistics, 0, sizeof(program->statistics));
266
267 program->debug.func = options->debug.func;
268 program->debug.private_data = options->debug.private_data;
269
270 /* Instruction Selection */
271 if (info->is_trap_handler_shader)
272 select_trap_handler_shader(program.get(), shaders[0], &config, options, info, args);
273 else
274 select_program(program.get(), shader_count, shaders, &config, options, info, args);
275
276 std::string llvm_ir = aco_postprocess_shader(options, info, program);
277
278 /* assembly */
279 std::vector<uint32_t> code;
280 std::vector<struct aco_symbol> symbols;
281 /* OpenGL combine multi shader parts into one continous code block,
282 * so only last part need the s_endpgm instruction.
283 */
284 bool append_endpgm = !(options->is_opengl && info->ps.has_epilog);
285 unsigned exec_size = emit_program(program.get(), code, &symbols, append_endpgm);
286
287 if (program->collect_statistics)
288 collect_postasm_stats(program.get(), code);
289
290 bool get_disasm = options->dump_shader || options->record_ir;
291
292 std::string disasm;
293 if (get_disasm)
294 disasm = get_disasm_string(program.get(), code, exec_size);
295
296 size_t stats_size = 0;
297 if (program->collect_statistics)
298 stats_size = aco_num_statistics * sizeof(uint32_t);
299
300 (*build_binary)(binary, &config, llvm_ir.c_str(), llvm_ir.size(), disasm.c_str(), disasm.size(),
301 program->statistics, stats_size, exec_size, code.data(), code.size(),
302 symbols.data(), symbols.size());
303 }
304
305 void
aco_compile_rt_prolog(const struct aco_compiler_options * options,const struct aco_shader_info * info,const struct ac_shader_args * in_args,const struct ac_shader_args * out_args,aco_callback * build_prolog,void ** binary)306 aco_compile_rt_prolog(const struct aco_compiler_options* options,
307 const struct aco_shader_info* info, const struct ac_shader_args* in_args,
308 const struct ac_shader_args* out_args, aco_callback* build_prolog,
309 void** binary)
310 {
311 init();
312
313 /* create program */
314 ac_shader_config config = {0};
315 std::unique_ptr<Program> program{new Program};
316 program->collect_statistics = false;
317 program->debug.func = NULL;
318 program->debug.private_data = NULL;
319
320 select_rt_prolog(program.get(), &config, options, info, in_args, out_args);
321 validate(program.get());
322 insert_waitcnt(program.get());
323 insert_NOPs(program.get());
324 if (program->gfx_level >= GFX11)
325 insert_delay_alu(program.get());
326 if (program->gfx_level >= GFX10)
327 form_hard_clauses(program.get());
328 if (program->gfx_level >= GFX11)
329 combine_delay_alu(program.get());
330
331 if (options->dump_shader)
332 aco_print_program(program.get(), stderr);
333
334 /* assembly */
335 std::vector<uint32_t> code;
336 code.reserve(align(program->blocks[0].instructions.size() * 2, 16));
337 unsigned exec_size = emit_program(program.get(), code);
338
339 bool get_disasm = options->dump_shader || options->record_ir;
340
341 std::string disasm;
342 if (get_disasm)
343 disasm = get_disasm_string(program.get(), code, exec_size);
344
345 (*build_prolog)(binary, &config, NULL, 0, disasm.c_str(), disasm.size(), program->statistics, 0,
346 exec_size, code.data(), code.size(), NULL, 0);
347 }
348
349 void
aco_compile_vs_prolog(const struct aco_compiler_options * options,const struct aco_shader_info * info,const struct aco_vs_prolog_info * pinfo,const struct ac_shader_args * args,aco_shader_part_callback * build_prolog,void ** binary)350 aco_compile_vs_prolog(const struct aco_compiler_options* options,
351 const struct aco_shader_info* info, const struct aco_vs_prolog_info* pinfo,
352 const struct ac_shader_args* args, aco_shader_part_callback* build_prolog,
353 void** binary)
354 {
355 init();
356
357 /* create program */
358 ac_shader_config config = {0};
359 std::unique_ptr<Program> program{new Program};
360 program->collect_statistics = false;
361 program->debug.func = NULL;
362 program->debug.private_data = NULL;
363
364 /* create IR */
365 select_vs_prolog(program.get(), pinfo, &config, options, info, args);
366 validate(program.get());
367 insert_NOPs(program.get());
368 if (program->gfx_level >= GFX10)
369 form_hard_clauses(program.get());
370
371 if (options->dump_shader)
372 aco_print_program(program.get(), stderr);
373
374 /* assembly */
375 std::vector<uint32_t> code;
376 code.reserve(align(program->blocks[0].instructions.size() * 2, 16));
377 unsigned exec_size = emit_program(program.get(), code);
378
379 bool get_disasm = options->dump_shader || options->record_ir;
380
381 std::string disasm;
382 if (get_disasm)
383 disasm = get_disasm_string(program.get(), code, exec_size);
384
385 (*build_prolog)(binary, config.num_sgprs, config.num_vgprs, code.data(), code.size(),
386 disasm.data(), disasm.size());
387 }
388
389 void
aco_compile_ps_epilog(const struct aco_compiler_options * options,const struct aco_shader_info * info,const struct aco_ps_epilog_info * pinfo,const struct ac_shader_args * args,aco_shader_part_callback * build_epilog,void ** binary)390 aco_compile_ps_epilog(const struct aco_compiler_options* options,
391 const struct aco_shader_info* info, const struct aco_ps_epilog_info* pinfo,
392 const struct ac_shader_args* args, aco_shader_part_callback* build_epilog,
393 void** binary)
394 {
395 aco_compile_shader_part(options, info, args, select_ps_epilog, (void*)pinfo, build_epilog,
396 binary);
397 }
398
399 void
aco_compile_ps_prolog(const struct aco_compiler_options * options,const struct aco_shader_info * info,const struct aco_ps_prolog_info * pinfo,const struct ac_shader_args * args,aco_shader_part_callback * build_prolog,void ** binary)400 aco_compile_ps_prolog(const struct aco_compiler_options* options,
401 const struct aco_shader_info* info, const struct aco_ps_prolog_info* pinfo,
402 const struct ac_shader_args* args, aco_shader_part_callback* build_prolog,
403 void** binary)
404 {
405 aco_compile_shader_part(options, info, args, select_ps_prolog, (void*)pinfo, build_prolog,
406 binary, true);
407 }
408
409 uint64_t
aco_get_codegen_flags()410 aco_get_codegen_flags()
411 {
412 init();
413 /* Exclude flags which don't affect code generation. */
414 uint64_t exclude =
415 DEBUG_VALIDATE_IR | DEBUG_VALIDATE_RA | DEBUG_PERF_INFO | DEBUG_LIVE_INFO;
416 return debug_flags & ~exclude;
417 }
418
419 bool
aco_is_gpu_supported(const struct radeon_info * info)420 aco_is_gpu_supported(const struct radeon_info* info)
421 {
422 switch (info->gfx_level) {
423 case GFX6:
424 case GFX7:
425 case GFX8:
426 return true;
427 case GFX9:
428 return info->has_graphics; /* no CDNA support */
429 case GFX10:
430 case GFX10_3:
431 case GFX11:
432 case GFX11_5:
433 return true;
434 default:
435 return false;
436 }
437 }
438
439 bool
aco_nir_op_supports_packed_math_16bit(const nir_alu_instr * alu)440 aco_nir_op_supports_packed_math_16bit(const nir_alu_instr* alu)
441 {
442 switch (alu->op) {
443 case nir_op_f2f16: {
444 nir_shader* shader = nir_cf_node_get_function(&alu->instr.block->cf_node)->function->shader;
445 unsigned execution_mode = shader->info.float_controls_execution_mode;
446 return (shader->options->force_f2f16_rtz && !nir_is_rounding_mode_rtne(execution_mode, 16)) ||
447 nir_is_rounding_mode_rtz(execution_mode, 16);
448 }
449 case nir_op_fadd:
450 case nir_op_fsub:
451 case nir_op_fmul:
452 case nir_op_ffma:
453 case nir_op_fdiv:
454 case nir_op_flrp:
455 case nir_op_fabs:
456 case nir_op_fneg:
457 case nir_op_fsat:
458 case nir_op_fmin:
459 case nir_op_fmax:
460 case nir_op_f2f16_rtz:
461 case nir_op_iabs:
462 case nir_op_iadd:
463 case nir_op_iadd_sat:
464 case nir_op_uadd_sat:
465 case nir_op_isub:
466 case nir_op_isub_sat:
467 case nir_op_usub_sat:
468 case nir_op_ineg:
469 case nir_op_imul:
470 case nir_op_imin:
471 case nir_op_imax:
472 case nir_op_umin:
473 case nir_op_umax: return true;
474 case nir_op_ishl: /* TODO: in NIR, these have 32bit shift operands */
475 case nir_op_ishr: /* while Radeon needs 16bit operands when vectorized */
476 case nir_op_ushr:
477 default: return false;
478 }
479 }
480
481 const aco_compiler_statistic_info* aco_statistic_infos = statistic_infos.data();
482
483 void
aco_print_asm(const struct radeon_info * info,unsigned wave_size,uint32_t * binary,unsigned num_dw)484 aco_print_asm(const struct radeon_info *info, unsigned wave_size,
485 uint32_t *binary, unsigned num_dw)
486 {
487 std::vector<uint32_t> binarray(binary, binary + num_dw);
488 aco::Program prog;
489
490 prog.gfx_level = info->gfx_level;
491 prog.family = info->family;
492 prog.wave_size = wave_size;
493 prog.blocks.push_back(aco::Block());
494
495 aco::print_asm(&prog, binarray, num_dw, stderr);
496 }
497