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