// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/config.h" #include "common/io_file.h" #include "common/path_util.h" #include "shader_recompiler/frontend/control_flow_graph.h" #include "shader_recompiler/frontend/decode.h" #include "shader_recompiler/frontend/structured_control_flow.h" #include "shader_recompiler/ir/passes/ir_passes.h" #include "shader_recompiler/ir/post_order.h" #include "shader_recompiler/recompiler.h" namespace Shader { IR::BlockList GenerateBlocks(const IR::AbstractSyntaxList& syntax_list) { size_t num_syntax_blocks{}; for (const auto& node : syntax_list) { if (node.type == IR::AbstractSyntaxNode::Type::Block) { ++num_syntax_blocks; } } IR::BlockList blocks; blocks.reserve(num_syntax_blocks); u32 order_index{}; for (const auto& node : syntax_list) { if (node.type == IR::AbstractSyntaxNode::Type::Block) { blocks.push_back(node.data.block); } } return blocks; } IR::Program TranslateProgram(std::span code, Pools& pools, Info& info, RuntimeInfo& runtime_info, const Profile& profile) { // Ensure first instruction is expected. constexpr u32 token_mov_vcchi = 0xBEEB03FF; if (code[0] != token_mov_vcchi) { LOG_WARNING(Render_Recompiler, "First instruction is not s_mov_b32 vcc_hi, #imm"); } Gcn::GcnCodeSlice slice(code.data(), code.data() + code.size()); Gcn::GcnDecodeContext decoder; // Decode and save instructions IR::Program program{info}; program.ins_list.reserve(code.size()); while (!slice.atEnd()) { program.ins_list.emplace_back(decoder.decodeInstruction(slice)); } // Clear any previous pooled data. pools.ReleaseContents(); // Create control flow graph Common::ObjectPool gcn_block_pool{64}; Gcn::CFG cfg{gcn_block_pool, program.ins_list}; // Structurize control flow graph and create program. program.syntax_list = Shader::Gcn::BuildASL(pools.inst_pool, pools.block_pool, cfg, program.info, runtime_info, profile); program.blocks = GenerateBlocks(program.syntax_list); program.post_order_blocks = Shader::IR::PostOrder(program.syntax_list.front()); // Run optimization passes const auto stage = program.info.stage; Shader::Optimization::SsaRewritePass(program.post_order_blocks); Shader::Optimization::IdentityRemovalPass(program.blocks); if (info.l_stage == LogicalStage::TessellationControl) { // Tess passes require previous const prop passes for now (for simplicity). TODO allow // fine grained folding or opportunistic folding we set an operand to an immediate Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::TessellationPreprocess(program, runtime_info); Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::HullShaderTransform(program, runtime_info); } else if (info.l_stage == LogicalStage::TessellationEval) { Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::TessellationPreprocess(program, runtime_info); Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::DomainShaderTransform(program, runtime_info); } Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::RingAccessElimination(program, runtime_info, stage); Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::FlattenExtendedUserdataPass(program); Shader::Optimization::ResourceTrackingPass(program); Shader::Optimization::LowerBufferFormatToRaw(program); Shader::Optimization::SharedMemoryToStoragePass(program, runtime_info, profile); Shader::Optimization::SharedMemoryBarrierPass(program, runtime_info, profile); Shader::Optimization::IdentityRemovalPass(program.blocks); Shader::Optimization::DeadCodeEliminationPass(program); Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::CollectShaderInfoPass(program); return program; } } // namespace Shader