/* * Copyright © 2020 Valve Corporation * * SPDX-License-Identifier: MIT */ #include "aco_builder.h" #include "aco_ir.h" #include namespace aco { namespace { /* there can also be LDS and VALU clauses, but I don't see how those are interesting */ enum clause_type { clause_smem, clause_other, /* GFX10: */ clause_vmem, clause_flat, /* GFX11: */ clause_mimg_load, clause_mimg_store, clause_mimg_atomic, clause_mimg_sample, clause_vmem_load, clause_vmem_store, clause_vmem_atomic, clause_flat_load, clause_flat_store, clause_flat_atomic, clause_bvh, }; void emit_clause(Builder& bld, unsigned num_instrs, aco_ptr* instrs) { if (num_instrs > 1) bld.sopp(aco_opcode::s_clause, num_instrs - 1); for (unsigned i = 0; i < num_instrs; i++) bld.insert(std::move(instrs[i])); } clause_type get_type(Program* program, aco_ptr& instr) { if (instr->isSMEM() && !instr->operands.empty()) return clause_smem; if (program->gfx_level >= GFX11) { if (instr->isMIMG()) { uint8_t vmem_type = get_vmem_type(instr.get(), program->dev.has_point_sample_accel); switch (vmem_type) { case vmem_bvh: return clause_bvh; case vmem_sampler: return clause_mimg_sample; case vmem_nosampler: if (instr_info.is_atomic[(unsigned)instr->opcode]) return clause_mimg_atomic; else if (instr->definitions.empty()) return clause_mimg_store; else return clause_mimg_load; default: return clause_other; } } else if (instr->isMTBUF() || instr->isScratch() || instr->isMUBUF() || instr->isGlobal()) { if (instr_info.is_atomic[(unsigned)instr->opcode]) return clause_vmem_atomic; else if (instr->definitions.empty()) return clause_vmem_store; else return clause_vmem_load; } else if (instr->isFlat()) { if (instr_info.is_atomic[(unsigned)instr->opcode]) return clause_flat_atomic; else if (instr->definitions.empty()) return clause_flat_store; else return clause_flat_load; } } else { /* Exclude stores from clauses before GFX11. */ if (instr->definitions.empty()) return clause_other; if (instr->isVMEM() && !instr->operands.empty()) { if (program->gfx_level == GFX10 && instr->isMIMG() && get_mimg_nsa_dwords(instr.get()) > 0) return clause_other; else return clause_vmem; } else if (instr->isScratch() || instr->isGlobal()) { return clause_vmem; } else if (instr->isFlat()) { return clause_flat; } } return clause_other; } } /* end namespace */ void form_hard_clauses(Program* program) { /* The ISA documentation says 63 is the maximum for GFX11/12, but according to * LLVM there are HW bugs with more than 32 instructions. */ const unsigned max_clause_length = program->gfx_level >= GFX11 ? 32 : 63; for (Block& block : program->blocks) { unsigned num_instrs = 0; aco_ptr current_instrs[63]; clause_type current_type = clause_other; std::vector> new_instructions; new_instructions.reserve(block.instructions.size()); Builder bld(program, &new_instructions); for (unsigned i = 0; i < block.instructions.size(); i++) { aco_ptr& instr = block.instructions[i]; clause_type type = get_type(program, instr); if (type != current_type || num_instrs == max_clause_length || (num_instrs && !should_form_clause(current_instrs[0].get(), instr.get()))) { emit_clause(bld, num_instrs, current_instrs); num_instrs = 0; current_type = type; } if (type == clause_other) { bld.insert(std::move(instr)); continue; } current_instrs[num_instrs++] = std::move(instr); } emit_clause(bld, num_instrs, current_instrs); block.instructions = std::move(new_instructions); } } } // namespace aco