From 86a95676fc7e4439b013aa45f0cd9532bcf5f837 Mon Sep 17 00:00:00 2001 From: Lander Gallastegi Date: Thu, 20 Mar 2025 12:48:36 +0100 Subject: [PATCH] Num executions --- CMakeLists.txt | 2 + .../ir/compute_value/compute.cpp | 7 +-- .../ir/compute_value/compute.h | 4 +- src/shader_recompiler/ir/num_executions.cpp | 61 +++++++++++++++++++ src/shader_recompiler/ir/num_executions.h | 16 +++++ 5 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 src/shader_recompiler/ir/num_executions.cpp create mode 100644 src/shader_recompiler/ir/num_executions.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 21b3bdeb2..e2f1e9ab9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -875,6 +875,8 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h src/shader_recompiler/ir/ir_emitter.cpp src/shader_recompiler/ir/ir_emitter.h src/shader_recompiler/ir/microinstruction.cpp + src/shader_recompiler/ir/num_executions.cpp + src/shader_recompiler/ir/num_executions.cpp src/shader_recompiler/ir/opcodes.cpp src/shader_recompiler/ir/opcodes.h src/shader_recompiler/ir/opcodes.inc diff --git a/src/shader_recompiler/ir/compute_value/compute.cpp b/src/shader_recompiler/ir/compute_value/compute.cpp index ad01ae799..f2cb9007b 100644 --- a/src/shader_recompiler/ir/compute_value/compute.cpp +++ b/src/shader_recompiler/ir/compute_value/compute.cpp @@ -23,7 +23,7 @@ static void Invoke(ImmValueList& inst_values, const std::array -static void Invoke(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { +static void Invoke(Inst* inst, ImmValueList& inst_values, Cache& cache) { using Traits = Common::FuncTraits; constexpr size_t num_args = Traits::NUM_ARGS - 1; ASSERT(inst->NumArgs() >= num_args); @@ -34,8 +34,7 @@ static void Invoke(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& Invoke(inst_values, args, std::make_index_sequence{}); } -static void DoInstructionOperation(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { +static void DoInstructionOperation(Inst* inst, ImmValueList& inst_values, Cache& cache) { switch (inst->GetOpcode()) { #define OPCODE(name, result_type, ...) \ case Opcode::name: \ @@ -64,7 +63,7 @@ static bool IsSelectInst(Inst* inst) { } } -void Compute(const Value& value, ImmValueList& values, ComputeImmValuesCache& cache) { +void Compute(const Value& value, ImmValueList& values, Cache& cache) { Value resolved = value.Resolve(); if (ImmValue::IsSupportedValue(resolved)) { values.insert(ImmValue(resolved)); diff --git a/src/shader_recompiler/ir/compute_value/compute.h b/src/shader_recompiler/ir/compute_value/compute.h index b98b4ecae..57907c3c6 100644 --- a/src/shader_recompiler/ir/compute_value/compute.h +++ b/src/shader_recompiler/ir/compute_value/compute.h @@ -15,8 +15,8 @@ namespace Shader::IR::ComputeValue { using ImmValueList = std::unordered_set; -using ComputeImmValuesCache = boost::container::flat_map; +using Cache = boost::container::flat_map; -void Compute(const Value& value, ImmValueList& values, ComputeImmValuesCache& cache); +void Compute(const Value& value, ImmValueList& values, Cache& cache); } // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/num_executions.cpp b/src/shader_recompiler/ir/num_executions.cpp new file mode 100644 index 000000000..4c79135d7 --- /dev/null +++ b/src/shader_recompiler/ir/num_executions.cpp @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/cartesian_invoke.h" +#include "shader_recompiler/ir/basic_block.h" +#include "shader_recompiler/ir/compute_value/compute.h" +#include "shader_recompiler/ir/num_executions.h" + +namespace Shader::IR { + +static bool Is64BitCondition(const Inst* inst) { + switch (inst->GetOpcode()) { + case Opcode::SLessThan64: + case Opcode::ULessThan64: + case Opcode::IEqual64: + case Opcode::INotEqual64: + return true; + default: + return false; + } +} + +static u64 GetDistance32(const ComputeValue::ImmValue& a, const ComputeValue::ImmValue& b) { + return a.U32() < b.U32() ? b.U32() - a.U32() : a.U32() - b.U32(); +} + +static u64 GetDistance64(const ComputeValue::ImmValue& a, const ComputeValue::ImmValue& b) { + return a.U64() < b.U64() ? b.U64() - a.U64() : a.U64() - b.U64(); +} + +u64 GetNumExecutions(const Inst* inst) { + u64 num_executions = 1; + const auto* cond_data = &inst->GetParent()->CondData(); + while (cond_data->asl_node) { + if (cond_data->asl_node->type == AbstractSyntaxNode::Type::Loop) { + ComputeValue::ImmValueList cond_arg0, cond_arg1; + ComputeValue::Cache cache; + Block* cont_block = cond_data->asl_node->data.loop.continue_block; + Inst* cond_inst = cont_block->back().Arg(0).InstRecursive(); + ASSERT(cond_inst); + ComputeValue::Compute(cond_inst->Arg(0), cond_arg0, cache); + ComputeValue::Compute(cond_inst->Arg(1), cond_arg1, cache); + std::unordered_set distances; + if (Is64BitCondition(cond_inst)) { + Common::CartesianInvoke(GetDistance64, + std::insert_iterator(distances, distances.end()), cond_arg0, + cond_arg1); + } else { + Common::CartesianInvoke(GetDistance32, + std::insert_iterator(distances, distances.end()), cond_arg0, + cond_arg1); + } + num_executions *= + std::max(1, *std::max_element(distances.begin(), distances.end())); + } + cond_data = cond_data->parent; + } + return num_executions; +} + +} // namespace Shader::IR \ No newline at end of file diff --git a/src/shader_recompiler/ir/num_executions.h b/src/shader_recompiler/ir/num_executions.h new file mode 100644 index 000000000..68ade024d --- /dev/null +++ b/src/shader_recompiler/ir/num_executions.h @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" +#include "shader_recompiler/ir/type.h" + +// Get the number of times an instruction will be executed. +// 0 if it cannot be determined statically. + +namespace Shader::IR { + +u64 GetNumExecutions(const Inst* inst); + +} // namespace Shader::IR