diff --git a/CMakeLists.txt b/CMakeLists.txt index f55767611..cdb835dea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -856,6 +856,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp src/shader_recompiler/ir/passes/shared_memory_to_storage_pass.cpp src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp + src/shader_recompiler/ir/abstract_syntax_list.cpp src/shader_recompiler/ir/abstract_syntax_list.h src/shader_recompiler/ir/attribute.cpp src/shader_recompiler/ir/attribute.h diff --git a/src/shader_recompiler/ir/abstract_syntax_list.cpp b/src/shader_recompiler/ir/abstract_syntax_list.cpp new file mode 100644 index 000000000..0d967ac11 --- /dev/null +++ b/src/shader_recompiler/ir/abstract_syntax_list.cpp @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "abstract_syntax_list.h" + +namespace Shader::IR { + +std::string DumpASLNode(const AbstractSyntaxNode& node, + const std::map& block_to_index, + const std::map& inst_to_index) { + switch (node.type) { + case AbstractSyntaxNode::Type::Block: + return fmt::format("Block: ${}", block_to_index.at(node.data.block)); + case AbstractSyntaxNode::Type::If: + return fmt::format("If: cond = %{}, body = ${}, merge = ${}", + inst_to_index.at(node.data.if_node.cond.Inst()), + block_to_index.at(node.data.if_node.body), + block_to_index.at(node.data.if_node.merge)); + case AbstractSyntaxNode::Type::EndIf: + return fmt::format("EndIf: merge = ${}", block_to_index.at(node.data.end_if.merge)); + case AbstractSyntaxNode::Type::Loop: + return fmt::format("Loop: body = ${}, continue = ${}, merge = ${}", + block_to_index.at(node.data.loop.body), + block_to_index.at(node.data.loop.continue_block), + block_to_index.at(node.data.loop.merge)); + case AbstractSyntaxNode::Type::Repeat: + return fmt::format("Repeat: cond = %{}, header = ${}, merge = ${}", + inst_to_index.at(node.data.repeat.cond.Inst()), + block_to_index.at(node.data.repeat.loop_header), + block_to_index.at(node.data.repeat.merge)); + case AbstractSyntaxNode::Type::Break: + return fmt::format("Break: cond = %{}, merge = ${}, skip = ${}", + inst_to_index.at(node.data.break_node.cond.Inst()), + block_to_index.at(node.data.break_node.merge), + block_to_index.at(node.data.break_node.skip)); + case AbstractSyntaxNode::Type::Return: + return "Return"; + case AbstractSyntaxNode::Type::Unreachable: + return "Unreachable"; + }; + UNREACHABLE(); +} + +} // namespace Shader::IR \ No newline at end of file diff --git a/src/shader_recompiler/ir/abstract_syntax_list.h b/src/shader_recompiler/ir/abstract_syntax_list.h index 313a23abc..a620baccb 100644 --- a/src/shader_recompiler/ir/abstract_syntax_list.h +++ b/src/shader_recompiler/ir/abstract_syntax_list.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include "shader_recompiler/ir/value.h" @@ -53,4 +54,8 @@ struct AbstractSyntaxNode { }; using AbstractSyntaxList = std::vector; +std::string DumpASLNode(const AbstractSyntaxNode& node, + const std::map& block_to_index, + const std::map& inst_to_index); + } // namespace Shader::IR diff --git a/src/shader_recompiler/ir/program.cpp b/src/shader_recompiler/ir/program.cpp index 7728a3ccb..f2f6e34fa 100644 --- a/src/shader_recompiler/ir/program.cpp +++ b/src/shader_recompiler/ir/program.cpp @@ -6,13 +6,30 @@ #include +#include "common/config.h" +#include "common/io_file.h" +#include "common/path_util.h" #include "shader_recompiler/ir/basic_block.h" #include "shader_recompiler/ir/program.h" #include "shader_recompiler/ir/value.h" namespace Shader::IR { -std::string DumpProgram(const Program& program) { +void DumpProgram(const Program& program, const Info& info, const std::string& type) { + using namespace Common::FS; + + if (!Config::dumpShaders()) { + return; + } + + const auto dump_dir = GetUserPath(PathType::ShaderDir) / "dumps"; + if (!std::filesystem::exists(dump_dir)) { + std::filesystem::create_directories(dump_dir); + } + const auto ir_filename = + fmt::format("{}_{:#018x}.{}irprogram.txt", info.stage, info.pgm_hash, type); + const auto ir_file = IOFile{dump_dir / ir_filename, FileAccessMode::Write, FileType::TextFile}; + size_t index{0}; std::map inst_to_index; std::map block_to_index; @@ -21,11 +38,20 @@ std::string DumpProgram(const Program& program) { block_to_index.emplace(block, index); ++index; } - std::string ret; + for (const auto& block : program.blocks) { - ret += IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n'; + std::string s = IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n'; + ir_file.WriteString(s); + } + + const auto asl_filename = fmt::format("{}_{:#018x}.{}asl.txt", info.stage, info.pgm_hash, type); + const auto asl_file = + IOFile{dump_dir / asl_filename, FileAccessMode::Write, FileType::TextFile}; + + for (const auto& node : program.syntax_list) { + std::string s = IR::DumpASLNode(node, block_to_index, inst_to_index) + '\n'; + asl_file.WriteString(s); } - return ret; } } // namespace Shader::IR diff --git a/src/shader_recompiler/ir/program.h b/src/shader_recompiler/ir/program.h index 84a1a2d40..3ffd4dc96 100644 --- a/src/shader_recompiler/ir/program.h +++ b/src/shader_recompiler/ir/program.h @@ -21,6 +21,6 @@ struct Program { Info& info; }; -[[nodiscard]] std::string DumpProgram(const Program& program); +void DumpProgram(const Program& program, const Info& info, const std::string& type = ""); } // namespace Shader::IR diff --git a/src/shader_recompiler/recompiler.cpp b/src/shader_recompiler/recompiler.cpp index 3e0bd98d2..9f92857d6 100644 --- a/src/shader_recompiler/recompiler.cpp +++ b/src/shader_recompiler/recompiler.cpp @@ -85,6 +85,8 @@ IR::Program TranslateProgram(std::span code, Pools& pools, Info& info Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::CollectShaderInfoPass(program); + Shader::IR::DumpProgram(program, info); + return program; }