From 301f51e57d35be5274a049154f66fee3ce57553c Mon Sep 17 00:00:00 2001 From: Lander Gallastegi Date: Wed, 19 Mar 2025 23:55:32 +0100 Subject: [PATCH] ComputeValue rewrite --- CMakeLists.txt | 16 + src/common/cartesian_invoke.h | 43 + src/common/func_traits.h | 1 + .../ir/compute_value/compute.cpp | 747 +----- .../ir/compute_value/compute.h | 10 +- .../ir/compute_value/do_bitcast.cpp | 32 + .../ir/compute_value/do_bitcast.h | 17 + .../ir/compute_value/do_composite.cpp | 230 ++ .../ir/compute_value/do_composite.h | 64 + .../ir/compute_value/do_convert.cpp | 81 + .../ir/compute_value/do_convert.h | 25 + .../ir/compute_value/do_float_operations.cpp | 254 ++ .../ir/compute_value/do_float_operations.h | 62 + .../compute_value/do_integer_operations.cpp | 233 ++ .../ir/compute_value/do_integer_operations.h | 70 + .../compute_value/do_logical_operations.cpp | 29 + .../ir/compute_value/do_logical_operations.h | 15 + .../ir/compute_value/do_nop_functions.h | 210 ++ .../ir/compute_value/do_packing.cpp | 132 + .../ir/compute_value/do_packing.h | 42 + .../ir/compute_value/imm_value.cpp | 2240 ++++++++--------- .../ir/compute_value/imm_value.h | 377 ++- 22 files changed, 2739 insertions(+), 2191 deletions(-) create mode 100644 src/common/cartesian_invoke.h create mode 100644 src/shader_recompiler/ir/compute_value/do_bitcast.cpp create mode 100644 src/shader_recompiler/ir/compute_value/do_bitcast.h create mode 100644 src/shader_recompiler/ir/compute_value/do_composite.cpp create mode 100644 src/shader_recompiler/ir/compute_value/do_composite.h create mode 100644 src/shader_recompiler/ir/compute_value/do_convert.cpp create mode 100644 src/shader_recompiler/ir/compute_value/do_convert.h create mode 100644 src/shader_recompiler/ir/compute_value/do_float_operations.cpp create mode 100644 src/shader_recompiler/ir/compute_value/do_float_operations.h create mode 100644 src/shader_recompiler/ir/compute_value/do_integer_operations.cpp create mode 100644 src/shader_recompiler/ir/compute_value/do_integer_operations.h create mode 100644 src/shader_recompiler/ir/compute_value/do_logical_operations.cpp create mode 100644 src/shader_recompiler/ir/compute_value/do_logical_operations.h create mode 100644 src/shader_recompiler/ir/compute_value/do_nop_functions.h create mode 100644 src/shader_recompiler/ir/compute_value/do_packing.cpp create mode 100644 src/shader_recompiler/ir/compute_value/do_packing.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b723f76c..26c03c301 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -630,6 +630,7 @@ set(COMMON src/common/logging/backend.cpp src/common/assert.h src/common/bit_field.h src/common/bounded_threadsafe_queue.h + src/common/cartesian_invoke.h src/common/concepts.h src/common/config.cpp src/common/config.h @@ -845,6 +846,21 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp src/shader_recompiler/ir/compute_value/compute.cpp src/shader_recompiler/ir/compute_value/compute.h + src/shader_recompiler/ir/compute_value/do_bitcast.cpp + src/shader_recompiler/ir/compute_value/do_bitcast.h + src/shader_recompiler/ir/compute_value/do_composite.cpp + src/shader_recompiler/ir/compute_value/do_composite.h + src/shader_recompiler/ir/compute_value/do_convert.cpp + src/shader_recompiler/ir/compute_value/do_convert.h + src/shader_recompiler/ir/compute_value/do_float_operations.cpp + src/shader_recompiler/ir/compute_value/do_float_operations.h + src/shader_recompiler/ir/compute_value/do_integer_operations.cpp + src/shader_recompiler/ir/compute_value/do_integer_operations.h + src/shader_recompiler/ir/compute_value/do_logical_operations.cpp + src/shader_recompiler/ir/compute_value/do_logical_operations.h + src/shader_recompiler/ir/compute_value/do_nop_functions.h + src/shader_recompiler/ir/compute_value/do_packing.cpp + src/shader_recompiler/ir/compute_value/do_packing.h src/shader_recompiler/ir/compute_value/imm_value.cpp src/shader_recompiler/ir/compute_value/imm_value.h src/shader_recompiler/ir/abstract_syntax_list.cpp diff --git a/src/common/cartesian_invoke.h b/src/common/cartesian_invoke.h new file mode 100644 index 000000000..6bbc4cd4a --- /dev/null +++ b/src/common/cartesian_invoke.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +namespace Common { +namespace Detail { + +template +void CartesianInvokeImpl(Func func, OutputIt out_it, + std::tuple& arglists_its, + const std::tuple& arglists_tuple) { + if constexpr (Level == N) { + auto get_tuple = [&](std::index_sequence) { + return std::forward_as_tuple(*std::get(arglists_its)...); + }; + *out_it++ = std::move(std::apply(func, get_tuple(std::make_index_sequence{}))); + return; + } else { + const auto& arglist = std::get(arglists_tuple); + for (auto it = arglist.begin(); it != arglist.end(); ++it) { + std::get(arglists_its) = it; + CartesianInvokeImpl( + func, out_it, arglists_its, arglists_tuple); + } + } +} + +} // namespace Detail + +template +void CartesianInvoke(Func func, OutputIt out_it, const ArgLists&... arg_lists) { + constexpr std::size_t N = sizeof...(ArgLists); + const std::tuple arglists_tuple = std::forward_as_tuple(arg_lists...); + + std::tuple arglists_it; + Detail::CartesianInvokeImpl(func, out_it, arglists_it, + arglists_tuple); +} + +} // namespace Common diff --git a/src/common/func_traits.h b/src/common/func_traits.h index 407b2dbe6..c3035d7cc 100644 --- a/src/common/func_traits.h +++ b/src/common/func_traits.h @@ -4,6 +4,7 @@ #pragma once #include +#include namespace Common { diff --git a/src/shader_recompiler/ir/compute_value/compute.cpp b/src/shader_recompiler/ir/compute_value/compute.cpp index 7ba40d5bb..ad01ae799 100644 --- a/src/shader_recompiler/ir/compute_value/compute.cpp +++ b/src/shader_recompiler/ir/compute_value/compute.cpp @@ -2,724 +2,51 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include -#include -#include +#include "common/cartesian_invoke.h" +#include "common/func_traits.h" #include "shader_recompiler/ir/compute_value/compute.h" +#include "shader_recompiler/ir/compute_value/do_bitcast.h" +#include "shader_recompiler/ir/compute_value/do_composite.h" +#include "shader_recompiler/ir/compute_value/do_convert.h" +#include "shader_recompiler/ir/compute_value/do_float_operations.h" +#include "shader_recompiler/ir/compute_value/do_integer_operations.h" +#include "shader_recompiler/ir/compute_value/do_logical_operations.h" +#include "shader_recompiler/ir/compute_value/do_nop_functions.h" +#include "shader_recompiler/ir/compute_value/do_packing.h" -namespace Shader::IR { +namespace Shader::IR::ComputeValue { -template -static void CartesianInvokeImpl(Func func, OutputIt out_it, - std::tuple& arglists_its, - const std::tuple& arglists_tuple) { - if constexpr (Level == N) { - auto get_tuple = [&](std::index_sequence) { - return std::forward_as_tuple(*std::get(arglists_its)...); - }; - *out_it++ = std::move(std::apply(func, get_tuple(std::make_index_sequence{}))); - return; - } else { - const auto& arglist = std::get(arglists_tuple); - for (auto it = arglist.begin(); it != arglist.end(); ++it) { - std::get(arglists_its) = it; - CartesianInvokeImpl( - func, out_it, arglists_its, arglists_tuple); - } +template +static void Invoke(ImmValueList& inst_values, const std::array& args, + std::index_sequence) { + func(inst_values, args[I]...); +} + +template +static void Invoke(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { + using Traits = Common::FuncTraits; + constexpr size_t num_args = Traits::NUM_ARGS - 1; + ASSERT(inst->NumArgs() >= num_args); + std::array args{}; + for (size_t i = 0; i < num_args; ++i) { + Compute(inst->Arg(i), args[i], cache); } -} - -template -static void CartesianInvoke(Func func, OutputIt out_it, const ArgLists&... arg_lists) { - constexpr size_t N = sizeof...(ArgLists); - const std::tuple arglists_tuple = std::forward_as_tuple(arg_lists...); - - std::tuple arglists_it; - CartesianInvokeImpl(func, out_it, arglists_it, - arglists_tuple); -} - -static void SetSigned(ImmValueList& values, bool is_signed) { - for (auto& value : values) { - value.SetSigned(is_signed); - } -} - -static void OperationAbs(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.abs(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationAdd(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a + b; }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationSub(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a - b; }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationFma(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args0, args1, args2; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - ComputeImmValues(inst->Arg(2), args2, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b, const ImmValue& c) { - return ImmValue::fma(ImmF32F64(a), ImmF32F64(b), ImmF32F64(c)); - }; - - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1, args2); -} - -static void OperationMin(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1, is_legacy_args; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - if (inst->NumArgs() > 2) { - ComputeImmValues(inst->Arg(2), is_legacy_args, cache); - } else { - is_legacy_args.insert(ImmValue(false)); - } - - const auto op = [](const ImmValue& a, const ImmValue& b, const ImmValue& is_legacy) { - if (is_legacy.U1()) { - if (a.isnan()) - return b; - if (b.isnan()) - return a; - } - return std::min(a, b); - }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1, - is_legacy_args); -} - -static void OperationMax(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1, is_legacy_args; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - if (inst->NumArgs() > 2) { - ComputeImmValues(inst->Arg(2), is_legacy_args, cache); - } else { - is_legacy_args.insert(ImmValue(false)); - } - - const auto op = [](const ImmValue& a, const ImmValue& b, const ImmValue& is_legacy) { - if (is_legacy.U1()) { - if (a.isnan()) - return b; - if (b.isnan()) - return a; - } - return std::max(a, b); - }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1, - is_legacy_args); -} - -static void OperationMul(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a * b; }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationDiv(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a / b; }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationMod(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a % b; }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationNeg(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return -a; }; - - SetSigned(args, true); - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationRecip(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.recip(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationRecipSqrt(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.rsqrt(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationSqrt(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.sqrt(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationSin(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.sin(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationExp2(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.exp2(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationLdexp(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a.ldexp(ImmU32(b)); }; - - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationCos(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.cos(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationLog2(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.log2(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationClamp(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1, args2; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - ComputeImmValues(inst->Arg(2), args2, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b, const ImmValue& c) { - return a.clamp(b, c); - }; - - SetSigned(args0, is_signed); - SetSigned(args1, is_signed); - SetSigned(args2, is_signed); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1, args2); -} - -static void OperationRound(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.round(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationFloor(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.floor(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationCeil(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.ceil(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationTrunc(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.trunc(); }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationFract(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return a.fract(); }; - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationShiftLeft(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a << ImmU32(b); }; - - SetSigned(args1, false); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationShiftRight(Inst* inst, bool is_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a >> ImmU32(b); }; - - SetSigned(args0, is_signed); - SetSigned(args1, false); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationBitwiseNot(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [](const ImmValue& a) { return ~a; }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationBitwiseAnd(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a & b; }; - - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationBitwiseOr(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a | b; }; - - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationBitwiseXor(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a ^ b; }; - - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationConvert(Inst* inst, bool is_signed, Type new_type, bool new_signed, - ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [new_type, new_signed](const ImmValue& a) { - return a.Convert(new_type, new_signed); - }; - - SetSigned(args, is_signed); - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -static void OperationBitCast(Inst* inst, Type new_type, bool new_signed, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args; - ComputeImmValues(inst->Arg(0), args, cache); - - const auto op = [new_type, new_signed](const ImmValue& a) { - return a.Bitcast(new_type, new_signed); - }; - - std::transform(args.begin(), args.end(), std::inserter(inst_values, inst_values.begin()), op); -} - -template -static void OperationCompositeConstruct(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - std::array args; - for (size_t i = 0; i < N; ++i) { - ComputeImmValues(inst->Arg(i), args[i], cache); - } - - const auto op = [](const Args&... args) { return ImmValue(args...); }; - - const auto call_cartesian = [&](std::index_sequence) { - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args[I]...); - }; - call_cartesian(std::make_index_sequence{}); -} - -static void OperationCompositeExtract(Inst* inst, ImmValueList& inst_values, - ComputeImmValuesCache& cache) { - ImmValueList args0, args1; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b) { return a.Extract(ImmU32(b)); }; - - SetSigned(args1, false); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1); -} - -static void OperationInsert(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { - ImmValueList args0, args1, args2; - ComputeImmValues(inst->Arg(0), args0, cache); - ComputeImmValues(inst->Arg(1), args1, cache); - ComputeImmValues(inst->Arg(2), args2, cache); - - const auto op = [](const ImmValue& a, const ImmValue& b, const ImmValue& c) { - return a.Insert(b, ImmU32(c)); - }; - - SetSigned(args2, false); - CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args0, args1, args2); + Invoke(inst_values, args, std::make_index_sequence{}); } static void DoInstructionOperation(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) { switch (inst->GetOpcode()) { - case Opcode::CompositeConstructU32x2: - case Opcode::CompositeConstructU32x2x2: - case Opcode::CompositeConstructF16x2: - case Opcode::CompositeConstructF32x2: - case Opcode::CompositeConstructF32x2x2: - case Opcode::CompositeConstructF64x2: - OperationCompositeConstruct<2>(inst, inst_values, cache); - break; - case Opcode::CompositeConstructU32x3: - case Opcode::CompositeConstructF16x3: - case Opcode::CompositeConstructF32x3: - case Opcode::CompositeConstructF64x3: - OperationCompositeConstruct<3>(inst, inst_values, cache); - break; - case Opcode::CompositeConstructU32x4: - case Opcode::CompositeConstructF16x4: - case Opcode::CompositeConstructF32x4: - case Opcode::CompositeConstructF64x4: - OperationCompositeConstruct<4>(inst, inst_values, cache); - break; - case Opcode::CompositeExtractU32x2: - case Opcode::CompositeExtractU32x3: - case Opcode::CompositeExtractU32x4: - case Opcode::CompositeExtractF16x2: - case Opcode::CompositeExtractF16x3: - case Opcode::CompositeExtractF16x4: - case Opcode::CompositeExtractF32x2: - case Opcode::CompositeExtractF32x3: - case Opcode::CompositeExtractF32x4: - case Opcode::CompositeExtractF64x2: - case Opcode::CompositeExtractF64x3: - case Opcode::CompositeExtractF64x4: - OperationCompositeExtract(inst, inst_values, cache); - break; - case Opcode::CompositeInsertU32x2: - case Opcode::CompositeInsertU32x3: - case Opcode::CompositeInsertU32x4: - case Opcode::CompositeInsertF16x2: - case Opcode::CompositeInsertF16x3: - case Opcode::CompositeInsertF16x4: - case Opcode::CompositeInsertF32x2: - case Opcode::CompositeInsertF32x3: - case Opcode::CompositeInsertF32x4: - case Opcode::CompositeInsertF64x2: - case Opcode::CompositeInsertF64x3: - case Opcode::CompositeInsertF64x4: - OperationInsert(inst, inst_values, cache); - break; - case Opcode::BitCastU16F16: - OperationBitCast(inst, IR::Type::U16, false, inst_values, cache); - break; - case Opcode::BitCastU32F32: - OperationBitCast(inst, IR::Type::U32, false, inst_values, cache); - break; - case Opcode::BitCastU64F64: - OperationBitCast(inst, IR::Type::U64, false, inst_values, cache); - break; - case Opcode::BitCastF16U16: - OperationBitCast(inst, IR::Type::F16, true, inst_values, cache); - break; - case Opcode::BitCastF32U32: - OperationBitCast(inst, IR::Type::F32, true, inst_values, cache); - break; - case Opcode::BitCastF64U64: - OperationBitCast(inst, IR::Type::F64, true, inst_values, cache); - break; - case Opcode::FPAbs32: - case Opcode::FPAbs64: - case Opcode::IAbs32: - OperationAbs(inst, inst_values, cache); - break; - case Opcode::FPAdd32: - case Opcode::FPAdd64: - OperationAdd(inst, true, inst_values, cache); - break; - case Opcode::IAdd32: - case Opcode::IAdd64: - OperationAdd(inst, false, inst_values, cache); - break; - case Opcode::FPSub32: - OperationSub(inst, true, inst_values, cache); - break; - case Opcode::ISub32: - case Opcode::ISub64: - OperationSub(inst, false, inst_values, cache); - break; - case Opcode::FPMul32: - case Opcode::FPMul64: - OperationMul(inst, true, inst_values, cache); - break; - case Opcode::IMul32: - case Opcode::IMul64: - OperationMul(inst, false, inst_values, cache); - break; - case Opcode::FPDiv32: - case Opcode::FPDiv64: - case Opcode::SDiv32: - OperationDiv(inst, true, inst_values, cache); - break; - case Opcode::UDiv32: - OperationDiv(inst, false, inst_values, cache); - break; - case Opcode::SMod32: - OperationMod(inst, true, inst_values, cache); - break; - case Opcode::UMod32: - OperationMod(inst, false, inst_values, cache); - break; - case Opcode::INeg32: - case Opcode::INeg64: - OperationNeg(inst, inst_values, cache); - break; - case Opcode::FPFma32: - case Opcode::FPFma64: - OperationFma(inst, inst_values, cache); - break; - case Opcode::FPMin32: - case Opcode::FPMin64: - case Opcode::SMin32: - OperationMin(inst, true, inst_values, cache); - break; - case Opcode::UMin32: - OperationMin(inst, false, inst_values, cache); - break; - case Opcode::FPMax32: - case Opcode::FPMax64: - case Opcode::SMax32: - OperationMax(inst, true, inst_values, cache); - break; - case Opcode::UMax32: - OperationMax(inst, false, inst_values, cache); - break; - case Opcode::FPNeg32: - case Opcode::FPNeg64: - OperationNeg(inst, inst_values, cache); - break; - case Opcode::FPRecip32: - case Opcode::FPRecip64: - OperationRecip(inst, inst_values, cache); - break; - case Opcode::FPRecipSqrt32: - case Opcode::FPRecipSqrt64: - OperationRecipSqrt(inst, inst_values, cache); - break; - case Opcode::FPSqrt: - OperationSqrt(inst, inst_values, cache); - break; - case Opcode::FPSin: - OperationSin(inst, inst_values, cache); - break; - case Opcode::FPCos: - OperationCos(inst, inst_values, cache); - break; - case Opcode::FPExp2: - OperationExp2(inst, inst_values, cache); - break; - case Opcode::FPLdexp: - OperationLdexp(inst, inst_values, cache); - break; - case Opcode::FPLog2: - OperationLog2(inst, inst_values, cache); - break; - case Opcode::FPClamp32: - case Opcode::FPClamp64: - case Opcode::SClamp32: - OperationClamp(inst, true, inst_values, cache); - break; - case Opcode::UClamp32: - OperationClamp(inst, false, inst_values, cache); - break; - case Opcode::FPRoundEven32: - case Opcode::FPRoundEven64: - OperationRound(inst, inst_values, cache); - break; - case Opcode::FPFloor32: - case Opcode::FPFloor64: - OperationFloor(inst, inst_values, cache); - break; - case Opcode::FPCeil32: - case Opcode::FPCeil64: - OperationCeil(inst, inst_values, cache); - break; - case Opcode::FPTrunc32: - case Opcode::FPTrunc64: - OperationTrunc(inst, inst_values, cache); - break; - case Opcode::FPFract32: - case Opcode::FPFract64: - OperationFract(inst, inst_values, cache); - break; - case Opcode::ShiftLeftLogical32: - case Opcode::ShiftLeftLogical64: - OperationShiftLeft(inst, inst_values, cache); - break; - case Opcode::ShiftRightLogical32: - case Opcode::ShiftRightLogical64: - OperationShiftRight(inst, false, inst_values, cache); - break; - case Opcode::ShiftRightArithmetic32: - case Opcode::ShiftRightArithmetic64: - OperationShiftRight(inst, true, inst_values, cache); - break; - case Opcode::BitwiseAnd32: - case Opcode::BitwiseAnd64: - case Opcode::LogicalAnd: - OperationBitwiseAnd(inst, inst_values, cache); - break; - case Opcode::BitwiseOr32: - case Opcode::BitwiseOr64: - case Opcode::LogicalOr: - OperationBitwiseOr(inst, inst_values, cache); - break; - case Opcode::BitwiseXor32: - case Opcode::LogicalXor: - OperationBitwiseXor(inst, inst_values, cache); - break; - case Opcode::BitwiseNot32: - case Opcode::LogicalNot: - OperationBitwiseNot(inst, inst_values, cache); - break; - case Opcode::ConvertU16U32: - OperationConvert(inst, false, Type::U16, false, inst_values, cache); - break; - case Opcode::ConvertS32F32: - case Opcode::ConvertS32F64: - OperationConvert(inst, true, Type::U32, true, inst_values, cache); - break; - case Opcode::ConvertU32F32: - OperationConvert(inst, true, Type::U32, false, inst_values, cache); - break; - case Opcode::ConvertU32U16: - OperationConvert(inst, false, Type::U32, false, inst_values, cache); - break; - case Opcode::ConvertF32F16: - case Opcode::ConvertF32F64: - case Opcode::ConvertF32S32: - OperationConvert(inst, true, Type::F32, true, inst_values, cache); - break; - case Opcode::ConvertF32U32: - OperationConvert(inst, false, Type::F32, true, inst_values, cache); - break; - case Opcode::ConvertF64F32: - case Opcode::ConvertF64S32: - OperationConvert(inst, true, Type::F64, true, inst_values, cache); - break; - case Opcode::ConvertF64U32: - OperationConvert(inst, false, Type::F64, true, inst_values, cache); +#define OPCODE(name, result_type, ...) \ + case Opcode::name: \ + Invoke<&Do##name>(inst, inst_values, cache); \ break; +#include "shader_recompiler/ir/opcodes.inc" +#undef OPCODE default: break; } + UNREACHABLE_MSG("Invalid opcode: {}", inst->GetOpcode()); } static bool IsSelectInst(Inst* inst) { @@ -737,7 +64,7 @@ static bool IsSelectInst(Inst* inst) { } } -void ComputeImmValues(const Value& value, ImmValueList& values, ComputeImmValuesCache& cache) { +void Compute(const Value& value, ImmValueList& values, ComputeImmValuesCache& cache) { Value resolved = value.Resolve(); if (ImmValue::IsSupportedValue(resolved)) { values.insert(ImmValue(resolved)); @@ -755,16 +82,16 @@ void ComputeImmValues(const Value& value, ImmValueList& values, ComputeImmValues auto& inst_values = cache.emplace(inst, ImmValueList{}).first->second; if (inst->GetOpcode() == Opcode::Phi) { for (size_t i = 0; i < inst->NumArgs(); ++i) { - ComputeImmValues(inst->Arg(i), inst_values, cache); + Compute(inst->Arg(i), inst_values, cache); } } if (IsSelectInst(inst)) { - ComputeImmValues(inst->Arg(1), inst_values, cache); - ComputeImmValues(inst->Arg(2), inst_values, cache); + Compute(inst->Arg(1), inst_values, cache); + Compute(inst->Arg(2), inst_values, cache); } else { DoInstructionOperation(inst, inst_values, cache); } values.insert(inst_values.begin(), inst_values.end()); } -} // namespace Shader::IR +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/compute.h b/src/shader_recompiler/ir/compute_value/compute.h index 8b6e7b86b..b98b4ecae 100644 --- a/src/shader_recompiler/ir/compute_value/compute.h +++ b/src/shader_recompiler/ir/compute_value/compute.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "shader_recompiler/ir/compute_value/imm_value.h" #include "shader_recompiler/ir/value.h" @@ -12,11 +12,11 @@ // that can represent. If the value can't be computed statically, the list will // be empty. -namespace Shader::IR { +namespace Shader::IR::ComputeValue { -using ImmValueList = boost::container::flat_set; +using ImmValueList = std::unordered_set; using ComputeImmValuesCache = boost::container::flat_map; -void ComputeImmValues(const Value& value, ImmValueList& values, ComputeImmValuesCache& cache); +void Compute(const Value& value, ImmValueList& values, ComputeImmValuesCache& cache); -} // namespace Shader::IR +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_bitcast.cpp b/src/shader_recompiler/ir/compute_value/do_bitcast.cpp new file mode 100644 index 000000000..2d011bc62 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_bitcast.cpp @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "shader_recompiler/ir/compute_value/do_bitcast.h" + +namespace Shader::IR::ComputeValue { + +void DoBitCastU16F16(ImmValueList& inst_values, const ImmValueList& src_values) { + inst_values.insert(src_values.begin(), src_values.end()); +} + +void DoBitCastU32F32(ImmValueList& inst_values, const ImmValueList& src_values) { + inst_values.insert(src_values.begin(), src_values.end()); +} + +void DoBitCastU64F64(ImmValueList& inst_values, const ImmValueList& src_values) { + inst_values.insert(src_values.begin(), src_values.end()); +} + +void DoBitCastF16U16(ImmValueList& inst_values, const ImmValueList& src_values) { + inst_values.insert(src_values.begin(), src_values.end()); +} + +void DoBitCastF32U32(ImmValueList& inst_values, const ImmValueList& src_values) { + inst_values.insert(src_values.begin(), src_values.end()); +} + +void DoBitCastF64U64(ImmValueList& inst_values, const ImmValueList& src_values) { + inst_values.insert(src_values.begin(), src_values.end()); +} + +} // namespace Shader::IR::ComputeValue diff --git a/src/shader_recompiler/ir/compute_value/do_bitcast.h b/src/shader_recompiler/ir/compute_value/do_bitcast.h new file mode 100644 index 000000000..4f9441612 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_bitcast.h @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/compute_value/compute.h" + +namespace Shader::IR::ComputeValue { + +void DoBitCastU16F16(ImmValueList& inst_values, const ImmValueList& src_values); +void DoBitCastU32F32(ImmValueList& inst_values, const ImmValueList& src_values); +void DoBitCastU64F64(ImmValueList& inst_values, const ImmValueList& src_values); +void DoBitCastF16U16(ImmValueList& inst_values, const ImmValueList& src_values); +void DoBitCastF32U32(ImmValueList& inst_values, const ImmValueList& src_values); +void DoBitCastF64U64(ImmValueList& inst_values, const ImmValueList& src_values); + +} // namespace Shader::IR::ComputeValue diff --git a/src/shader_recompiler/ir/compute_value/do_composite.cpp b/src/shader_recompiler/ir/compute_value/do_composite.cpp new file mode 100644 index 000000000..41cbd04f9 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_composite.cpp @@ -0,0 +1,230 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/cartesian_invoke.h" +#include "shader_recompiler/ir/compute_value/do_composite.h" + +namespace Shader::IR::ComputeValue { + +static void CommonCompositeConstruct(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1) { + const auto op = [](const ImmValue& a, const ImmValue& b) { + return ImmValue(a, b); + }; + Common::CartesianInvoke(op, std::insert_iterator(inst_values, inst_values.begin()), arg0, arg1); +} + +static void CommonCompositeConstruct(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2) { + const auto op = [](const ImmValue& a, const ImmValue& b, const ImmValue& c) { + return ImmValue(a, b, c); + }; + Common::CartesianInvoke(op, std::insert_iterator(inst_values, inst_values.begin()), arg0, arg1, arg2); +} + +static void CommonCompositeConstruct(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3) { + const auto op = [](const ImmValue& a, const ImmValue& b, const ImmValue& c, const ImmValue& d) { + return ImmValue(a, b, c, d); + }; + Common::CartesianInvoke(op, std::insert_iterator(inst_values, inst_values.begin()), arg0, arg1, arg2, arg3); +} + +void DoCompositeConstructU32x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1) { + CommonCompositeConstruct(inst_values, arg0, arg1); +} + +void DoCompositeConstructU32x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2); +} + +void DoCompositeConstructU32x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2, arg3); +} + +void DoCompositeConstructU32x2x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1) { + Common::CartesianInvoke(ImmValue::CompositeFrom2x2, std::insert_iterator(inst_values, inst_values.begin()), arg0, arg1); +} + +void DoCompositeExtractU32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractU32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractU32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeInsertU32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertU32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertU32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeShuffleU32x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleU32x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleU32x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeConstructF16x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1) { + CommonCompositeConstruct(inst_values, arg0, arg1); +} + +void DoCompositeConstructF16x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2); +} + +void DoCompositeConstructF16x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2, arg3); +} + +void DoCompositeConstructF32x2x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1) { + Common::CartesianInvoke(ImmValue::CompositeFrom2x2, std::insert_iterator(inst_values, inst_values.begin()), arg0, arg1); +} + +void DoCompositeExtractF16x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractF16x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractF16x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeInsertF16x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertF16x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertF16x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeShuffleF16x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleF16x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleF16x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeConstructF32x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1) { + CommonCompositeConstruct(inst_values, arg0, arg1); +} + +void DoCompositeConstructF32x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2); +} + +void DoCompositeConstructF32x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2, arg3); +} + +void DoCompositeExtractF32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractF32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractF32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeInsertF32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertF32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertF32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeShuffleF32x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleF32x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleF32x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeConstructF64x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1) { + CommonCompositeConstruct(inst_values, arg0, arg1); +} + +void DoCompositeConstructF64x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2); +} + +void DoCompositeConstructF64x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3) { + CommonCompositeConstruct(inst_values, arg0, arg1, arg2, arg3); +} + +void DoCompositeExtractF64x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractF64x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeExtractF64x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Extract, std::insert_iterator(inst_values, inst_values.begin()), vec, idx); +} + +void DoCompositeInsertF64x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertF64x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeInsertF64x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx) { + Common::CartesianInvoke(ImmValue::Insert, std::insert_iterator(inst_values, inst_values.begin()), vec, val, idx); +} + +void DoCompositeShuffleF64x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleF64x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoCompositeShuffleF64x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3) { + UNREACHABLE_MSG("Unimplemented"); +} + +} // namespace Shader::IR::ComputeValue diff --git a/src/shader_recompiler/ir/compute_value/do_composite.h b/src/shader_recompiler/ir/compute_value/do_composite.h new file mode 100644 index 000000000..a55fd0fd8 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_composite.h @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/compute_value/compute.h" + +namespace Shader::IR::ComputeValue { + +void DoCompositeConstructU32x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1); +void DoCompositeConstructU32x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2); +void DoCompositeConstructU32x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3); +void DoCompositeConstructU32x2x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1); +void DoCompositeExtractU32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractU32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractU32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeInsertU32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertU32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertU32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeShuffleU32x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1); +void DoCompositeShuffleU32x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2); +void DoCompositeShuffleU32x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3); + +void DoCompositeConstructF16x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1); +void DoCompositeConstructF16x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2); +void DoCompositeConstructF16x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3); +void DoCompositeExtractF16x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractF16x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractF16x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeInsertF16x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertF16x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertF16x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeShuffleF16x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1); +void DoCompositeShuffleF16x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2); +void DoCompositeShuffleF16x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3); + +void DoCompositeConstructF32x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1); +void DoCompositeConstructF32x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2); +void DoCompositeConstructF32x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3); +void DoCompositeConstructF32x2x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1); +void DoCompositeExtractF32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractF32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractF32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeInsertF32x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertF32x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertF32x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeShuffleF32x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1); +void DoCompositeShuffleF32x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2); +void DoCompositeShuffleF32x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3); + +void DoCompositeConstructF64x2(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1); +void DoCompositeConstructF64x3(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2); +void DoCompositeConstructF64x4(ImmValueList& inst_values, const ImmValueList& arg0, const ImmValueList& arg1, const ImmValueList& arg2, const ImmValueList& arg3); +void DoCompositeExtractF64x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractF64x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeExtractF64x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& idx); +void DoCompositeInsertF64x2(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertF64x3(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeInsertF64x4(ImmValueList& inst_values, const ImmValueList& vec, const ImmValueList& val, const ImmValueList& idx); +void DoCompositeShuffleF64x2(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1); +void DoCompositeShuffleF64x3(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2); +void DoCompositeShuffleF64x4(ImmValueList& inst_values, const ImmValueList& vec0, const ImmValueList& vec1, const ImmValueList& idx0, const ImmValueList& idx1, const ImmValueList& idx2, const ImmValueList& idx3); + +} // namespace Shader::IR::ComputeValue diff --git a/src/shader_recompiler/ir/compute_value/do_convert.cpp b/src/shader_recompiler/ir/compute_value/do_convert.cpp new file mode 100644 index 000000000..aad5d24e4 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_convert.cpp @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/cartesian_invoke.h" +#include "shader_recompiler/ir/compute_value/do_convert.h" + +namespace Shader::IR::ComputeValue { + +void DoConvertS32F32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertS32F64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertU32F32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertF16F32(ImmValueList& inst_values, const ImmValueList& args) { + // Common::CartesianInvoke(ImmValue::Convert, + // std::insert_iterator(inst_values, inst_values.begin()), args); + UNREACHABLE_MSG("F32 to F16 conversion is not implemented"); +} + +void DoConvertF32F16(ImmValueList& inst_values, const ImmValueList& args) { + // Common::CartesianInvoke(ImmValue::Convert, + // std::insert_iterator(inst_values, inst_values.begin()), args); + UNREACHABLE_MSG("F16 to F32 conversion is not implemented"); +} + +void DoConvertF32F64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertF64F32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertF32S32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertF32U32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertF64S32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertF64U32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertF32U16(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertU16U32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +void DoConvertU32U16(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Convert, + std::insert_iterator(inst_values, inst_values.begin()), args); +} + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_convert.h b/src/shader_recompiler/ir/compute_value/do_convert.h new file mode 100644 index 000000000..9fd5e0302 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_convert.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/compute_value/compute.h" + +namespace Shader::IR::ComputeValue { + +void DoConvertS32F32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertS32F64(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertU32F32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF16F32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF32F16(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF32F64(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF64F32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF32S32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF32U32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF64S32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF64U32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertF32U16(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertU16U32(ImmValueList& inst_values, const ImmValueList& args); +void DoConvertU32U16(ImmValueList& inst_values, const ImmValueList& args); + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_float_operations.cpp b/src/shader_recompiler/ir/compute_value/do_float_operations.cpp new file mode 100644 index 000000000..9868c2333 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_float_operations.cpp @@ -0,0 +1,254 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/cartesian_invoke.h" +#include "shader_recompiler/ir/compute_value/do_float_operations.h" + +namespace Shader::IR::ComputeValue { + +void DoFPAbs32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Abs, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPAbs64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Abs, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPAdd32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Add, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPAdd64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Add, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPSub32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Sub, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPFma32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::Fma, + std::insert_iterator(inst_values, inst_values.end()), args0, args1, + args2); +} + +void DoFPFma64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::Fma, + std::insert_iterator(inst_values, inst_values.end()), args0, args1, + args2); +} + +void DoFPMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args_legacy) { + const auto& op = [](const ImmValue& a, const ImmValue& b, const ImmValue& legacy) { + if (legacy.U1()) { + if (ImmValue::IsNan(a)) + return b; + if (ImmValue::IsNan(b)) + return a; + } + return ImmValue::Max(a, b); + }; + Common::CartesianInvoke(op, std::insert_iterator(inst_values, inst_values.end()), args0, args1, + args_legacy); +} + +void DoFPMax64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Max, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args_legacy) { + const auto& op = [](const ImmValue& a, const ImmValue& b, const ImmValue& legacy) { + if (legacy.U1()) { + if (ImmValue::IsNan(a)) + return b; + if (ImmValue::IsNan(b)) + return a; + } + return ImmValue::Min(a, b); + }; + Common::CartesianInvoke(op, std::insert_iterator(inst_values, inst_values.end()), args0, args1, + args_legacy); +} + +void DoFPMin64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Min, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPMul32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Mul, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPMul64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Mul, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPDiv32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Div, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPDiv64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Div, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoFPNeg32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Neg, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPNeg64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Neg, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPRecip32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Recip, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPRecip64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Recip, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPRecipSqrt32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Rsqrt, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPRecipSqrt64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Rsqrt, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPSqrt(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Sqrt, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPSin(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Sin, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPExp2(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Exp2, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPLdexp(ImmValueList& inst_values, const ImmValueList& args, const ImmValueList& exponents) { + Common::CartesianInvoke(ImmValue::Ldexp, + std::insert_iterator(inst_values, inst_values.end()), args, exponents); +} + +void DoFPCos(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Cos, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPLog2(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Log2, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPSaturate32(ImmValueList& inst_values, const ImmValueList& args) { + UNREACHABLE_MSG("FPSaturate32 not implemented"); +} + +void DoFPSaturate64(ImmValueList& inst_values, const ImmValueList& args) { + UNREACHABLE_MSG("FPSaturate64 not implemented"); +} + +void DoFPClamp32(ImmValueList& inst_values, const ImmValueList& args, const ImmValueList& mins, + const ImmValueList& maxs) { + Common::CartesianInvoke(ImmValue::Clamp, + std::insert_iterator(inst_values, inst_values.end()), args, mins, maxs); +} + +void DoFPClamp64(ImmValueList& inst_values, const ImmValueList& args, const ImmValueList& mins, + const ImmValueList& maxs) { + Common::CartesianInvoke(ImmValue::Clamp, + std::insert_iterator(inst_values, inst_values.end()), args, mins, maxs); +} + +void DoFPRoundEven32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Round, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPRoundEven64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Round, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPFloor32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Floor, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPFloor64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Floor, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPCeil32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Ceil, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPCeil64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Ceil, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPTrunc32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Trunc, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPTrunc64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Trunc, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPFract32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Fract, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPFract64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Fract, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoFPFrexpSig32(ImmValueList& inst_values, const ImmValueList& args) { + UNREACHABLE_MSG("FPFrexpSig32 not implemented"); +} + +void DoFPFrexpSig64(ImmValueList& inst_values, const ImmValueList& args) { + UNREACHABLE_MSG("FPFrexpSig64 not implemented"); +} + +void DoFPFrexpExp32(ImmValueList& inst_values, const ImmValueList& args) { + UNREACHABLE_MSG("FPFrexpExp32 not implemented"); +} + +void DoFPFrexpExp64(ImmValueList& inst_values, const ImmValueList& args) { + UNREACHABLE_MSG("FPFrexpExp64 not implemented"); +} + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_float_operations.h b/src/shader_recompiler/ir/compute_value/do_float_operations.h new file mode 100644 index 000000000..ffc8040d1 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_float_operations.h @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/compute_value/compute.h" + +namespace Shader::IR::ComputeValue { + +void DoFPAbs32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPAbs64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPAdd32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPAdd64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPSub32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPFma32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2); +void DoFPFma64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2); +void DoFPMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args_legacy); +void DoFPMax64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args_legacy); +void DoFPMin64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPMul32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPMul64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPDiv32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPDiv64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPNeg32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPNeg64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPRecip32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPRecip64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPRecipSqrt32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPRecipSqrt64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPSqrt(ImmValueList& inst_values, const ImmValueList& args); +void DoFPSin(ImmValueList& inst_values, const ImmValueList& args); +void DoFPExp2(ImmValueList& inst_values, const ImmValueList& args); +void DoFPLdexp(ImmValueList& inst_values, const ImmValueList& args, const ImmValueList& exponents); +void DoFPCos(ImmValueList& inst_values, const ImmValueList& args); +void DoFPLog2(ImmValueList& inst_values, const ImmValueList& args); +void DoFPSaturate32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPSaturate64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPClamp32(ImmValueList& inst_values, const ImmValueList& args, const ImmValueList& mins, + const ImmValueList& maxs); +void DoFPClamp64(ImmValueList& inst_values, const ImmValueList& args, const ImmValueList& mins, + const ImmValueList& maxs); +void DoFPRoundEven32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPRoundEven64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFloor32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFloor64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPCeil32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPCeil64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPTrunc32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPTrunc64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFract32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFract64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFrexpSig32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFrexpSig64(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFrexpExp32(ImmValueList& inst_values, const ImmValueList& args); +void DoFPFrexpExp64(ImmValueList& inst_values, const ImmValueList& args); + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_integer_operations.cpp b/src/shader_recompiler/ir/compute_value/do_integer_operations.cpp new file mode 100644 index 000000000..bcc101bde --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_integer_operations.cpp @@ -0,0 +1,233 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/cartesian_invoke.h" +#include "shader_recompiler/ir/compute_value/do_integer_operations.h" + +namespace Shader::IR::ComputeValue { + +void DoIAdd32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Add, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoIAdd64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Add, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoIAddCary32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + UNREACHABLE_MSG("IAddCary32 not implemented"); +} + +void DoISub32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Sub, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoISub64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Sub, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoIMul32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Mul, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoIMul64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Mul, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoSMulExt(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + UNREACHABLE_MSG("SMulExt not implemented"); +} + +void DoUMulExt(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + UNREACHABLE_MSG("UMulExt not implemented"); +} + +void DoSDiv32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Div, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoUDiv32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Div, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoSMod32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Mod, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoUMod32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Mod, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoINeg32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Neg, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoINeg64(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Neg, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoIAbs32(ImmValueList& inst_values, const ImmValueList& args) { + Common::CartesianInvoke(ImmValue::Abs, + std::insert_iterator(inst_values, inst_values.end()), args); +} + +void DoShiftLeftLogical32(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift) { + Common::CartesianInvoke(ImmValue::LShift, + std::insert_iterator(inst_values, inst_values.end()), args, shift); +} + +void DoShiftLeftLogical64(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift) { + Common::CartesianInvoke(ImmValue::LShift, + std::insert_iterator(inst_values, inst_values.end()), args, shift); +} + +void DoShiftRightLogical32(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift) { + Common::CartesianInvoke(ImmValue::RShift, + std::insert_iterator(inst_values, inst_values.end()), args, shift); +} + +void DoShiftRightLogical64(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift) { + Common::CartesianInvoke(ImmValue::RShift, + std::insert_iterator(inst_values, inst_values.end()), args, shift); +} + +void DoShiftRightArithmetic32(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift) { + Common::CartesianInvoke(ImmValue::RShift, + std::insert_iterator(inst_values, inst_values.end()), args, shift); +} + +void DoShiftRightArithmetic64(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift) { + Common::CartesianInvoke(ImmValue::RShift, + std::insert_iterator(inst_values, inst_values.end()), args, shift); +} + +void DoBitwiseAnd32(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::And, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoBitwiseAnd64(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::And, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoBitwiseOr32(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Or, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoBitwiseOr64(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Or, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoBitwiseXor32(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Xor, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoBitFieldInsert(ImmValueList& inst_values, const ImmValueList& arg, + const ImmValueList& insert, const ImmValueList& offset, + const ImmValueList& count) { + UNREACHABLE_MSG("BitFieldInsert not implemented"); +} + +void DoBitFieldSExtract(ImmValueList& inst_values, const ImmValueList& arg, + const ImmValueList& offset, const ImmValueList& count) { + UNREACHABLE_MSG("BitFieldSExtract not implemented"); +} + +void DoBitFieldUExtract(ImmValueList& inst_values, const ImmValueList& arg, + const ImmValueList& offset, const ImmValueList& count) { + UNREACHABLE_MSG("BitFieldUExtract not implemented"); +} + +void DoBitReverse32(ImmValueList& inst_values, const ImmValueList& arg) { + UNREACHABLE_MSG("BitReverse32 not implemented"); +} + +void DoBitCount32(ImmValueList& inst_values, const ImmValueList& arg) { + UNREACHABLE_MSG("BitCount32 not implemented"); +} + +void DoBitCount64(ImmValueList& inst_values, const ImmValueList& arg) { + UNREACHABLE_MSG("BitCount64 not implemented"); +} + +void DoBitwiseNot32(ImmValueList& inst_values, const ImmValueList& arg) { + Common::CartesianInvoke(ImmValue::Not, + std::insert_iterator(inst_values, inst_values.end()), arg); +} + +void DoFindSMsb32(ImmValueList& inst_values, const ImmValueList& arg) { + UNREACHABLE_MSG("FindSMsb32 not implemented"); +} + +void DoFindUMsb32(ImmValueList& inst_values, const ImmValueList& arg) { + UNREACHABLE_MSG("FindUMsb32 not implemented"); +} + +void DoFindILsb32(ImmValueList& inst_values, const ImmValueList& arg) { + UNREACHABLE_MSG("FindILsb32 not implemented"); +} + +void DoFindILsb64(ImmValueList& inst_values, const ImmValueList& arg) { + UNREACHABLE_MSG("FindILsb64 not implemented"); +} + +void DoSMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Min, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoUMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Min, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoSMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Max, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoUMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { + Common::CartesianInvoke(ImmValue::Max, + std::insert_iterator(inst_values, inst_values.end()), args0, args1); +} + +void DoSClamp32(ImmValueList& inst_values, const ImmValueList& value, const ImmValueList& min, + const ImmValueList& max) { + Common::CartesianInvoke(ImmValue::Clamp, + std::insert_iterator(inst_values, inst_values.end()), value, min, max); +} + +void DoUClamp32(ImmValueList& inst_values, const ImmValueList& value, const ImmValueList& min, + const ImmValueList& max) { + Common::CartesianInvoke(ImmValue::Clamp, + std::insert_iterator(inst_values, inst_values.end()), value, min, max); +} + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_integer_operations.h b/src/shader_recompiler/ir/compute_value/do_integer_operations.h new file mode 100644 index 000000000..e698f2b12 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_integer_operations.h @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/compute_value/compute.h" + +namespace Shader::IR::ComputeValue { + +void DoIAdd32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoIAdd64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoIAddCary32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoISub32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoISub64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoIMul32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoIMul64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoSMulExt(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoUMulExt(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoSDiv32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoUDiv32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoSMod32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoUMod32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoINeg32(ImmValueList& inst_values, const ImmValueList& args); +void DoINeg64(ImmValueList& inst_values, const ImmValueList& args); +void DoIAbs32(ImmValueList& inst_values, const ImmValueList& args); +void DoShiftLeftLogical32(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift); +void DoShiftLeftLogical64(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift); +void DoShiftRightLogical32(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift); +void DoShiftRightLogical64(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift); +void DoShiftRightArithmetic32(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift); +void DoShiftRightArithmetic64(ImmValueList& inst_values, const ImmValueList& args, + const ImmValueList& shift); +void DoBitwiseAnd32(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1); +void DoBitwiseAnd64(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1); +void DoBitwiseOr32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoBitwiseOr64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoBitwiseXor32(ImmValueList& inst_values, const ImmValueList& args0, + const ImmValueList& args1); +void DoBitFieldInsert(ImmValueList& inst_values, const ImmValueList& arg, + const ImmValueList& insert, const ImmValueList& offset, + const ImmValueList& count); +void DoBitFieldSExtract(ImmValueList& inst_values, const ImmValueList& arg, + const ImmValueList& offset, const ImmValueList& count); +void DoBitFieldUExtract(ImmValueList& inst_values, const ImmValueList& arg, + const ImmValueList& offset, const ImmValueList& count); +void DoBitReverse32(ImmValueList& inst_values, const ImmValueList& arg); +void DoBitCount32(ImmValueList& inst_values, const ImmValueList& arg); +void DoBitCount64(ImmValueList& inst_values, const ImmValueList& arg); +void DoBitwiseNot32(ImmValueList& inst_values, const ImmValueList& arg); +void DoFindSMsb32(ImmValueList& inst_values, const ImmValueList& arg); +void DoFindUMsb32(ImmValueList& inst_values, const ImmValueList& arg); +void DoFindILsb32(ImmValueList& inst_values, const ImmValueList& arg); +void DoFindILsb64(ImmValueList& inst_values, const ImmValueList& arg); +void DoSMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoUMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoSMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoUMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoSClamp32(ImmValueList& inst_values, const ImmValueList& value, const ImmValueList& min, + const ImmValueList& max); +void DoUClamp32(ImmValueList& inst_values, const ImmValueList& value, const ImmValueList& min, + const ImmValueList& max); + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_logical_operations.cpp b/src/shader_recompiler/ir/compute_value/do_logical_operations.cpp new file mode 100644 index 000000000..8b494aafa --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_logical_operations.cpp @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/cartesian_invoke.h" +#include "shader_recompiler/ir/compute_value/do_logical_operations.h" + +namespace Shader::IR::ComputeValue { + +void DoLogicalOr(ImmValueList& inst_values, const ImmValueList& arg1, const ImmValueList& arg2) { + Common::CartesianInvoke(ImmValue::Or, + std::insert_iterator(inst_values, inst_values.end()), arg1, arg2); +} + +void DoLogicalAnd(ImmValueList& inst_values, const ImmValueList& arg1, const ImmValueList& arg2) { + Common::CartesianInvoke(ImmValue::And, + std::insert_iterator(inst_values, inst_values.end()), arg1, arg2); +} + +void DoLogicalXor(ImmValueList& inst_values, const ImmValueList& arg1, const ImmValueList& arg2) { + Common::CartesianInvoke(ImmValue::Xor, + std::insert_iterator(inst_values, inst_values.end()), arg1, arg2); +} + +void DoLogicalNot(ImmValueList& inst_values, const ImmValueList& arg1) { + Common::CartesianInvoke(ImmValue::Not, + std::insert_iterator(inst_values, inst_values.end()), arg1); +} + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_logical_operations.h b/src/shader_recompiler/ir/compute_value/do_logical_operations.h new file mode 100644 index 000000000..1e2b3dca2 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_logical_operations.h @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/compute_value/compute.h" + +namespace Shader::IR::ComputeValue { + +void DoLogicalOr(ImmValueList& inst_values, const ImmValueList& arg1, const ImmValueList& arg2); +void DoLogicalAnd(ImmValueList& inst_values, const ImmValueList& arg1, const ImmValueList& arg2); +void DoLogicalXor(ImmValueList& inst_values, const ImmValueList& arg1, const ImmValueList& arg2); +void DoLogicalNot(ImmValueList& inst_values, const ImmValueList& arg1); + +} // namespace Shader::IR::ComputeValue \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/do_nop_functions.h b/src/shader_recompiler/ir/compute_value/do_nop_functions.h new file mode 100644 index 000000000..69acced68 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_nop_functions.h @@ -0,0 +1,210 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +namespace Shader::IR::ComputeValue { + +#define NOP_FUNCTION(name) inline void Do##name(ImmValueList& inst_values) {} + +NOP_FUNCTION(Phi) +NOP_FUNCTION(Identity) +NOP_FUNCTION(Void) +NOP_FUNCTION(ConditionRef) +NOP_FUNCTION(Reference) +NOP_FUNCTION(PhiMove) + +NOP_FUNCTION(Prologue) +NOP_FUNCTION(Epilogue) +NOP_FUNCTION(Discard) +NOP_FUNCTION(DiscardCond) +NOP_FUNCTION(DebugPrint) + +NOP_FUNCTION(ReadConst) +NOP_FUNCTION(ReadConstBuffer) + +NOP_FUNCTION(Barrier) +NOP_FUNCTION(WorkgroupMemoryBarrier) +NOP_FUNCTION(DeviceMemoryBarrier) + +NOP_FUNCTION(EmitVertex) +NOP_FUNCTION(EmitPrimitive) + +NOP_FUNCTION(LoadSharedU32) +NOP_FUNCTION(LoadSharedU64) +NOP_FUNCTION(WriteSharedU32) +NOP_FUNCTION(WriteSharedU64) + +NOP_FUNCTION(SharedAtomicIAdd32) +NOP_FUNCTION(SharedAtomicSMin32) +NOP_FUNCTION(SharedAtomicUMin32) +NOP_FUNCTION(SharedAtomicSMax32) +NOP_FUNCTION(SharedAtomicUMax32) +NOP_FUNCTION(SharedAtomicAnd32) +NOP_FUNCTION(SharedAtomicOr32) +NOP_FUNCTION(SharedAtomicXor32) + +NOP_FUNCTION(GetUserData) +NOP_FUNCTION(GetThreadBitScalarReg) +NOP_FUNCTION(SetThreadBitScalarReg) +NOP_FUNCTION(GetScalarRegister) +NOP_FUNCTION(SetScalarRegister) +NOP_FUNCTION(GetVectorRegister) +NOP_FUNCTION(SetVectorRegister) +NOP_FUNCTION(GetGotoVariable) +NOP_FUNCTION(SetGotoVariable) +NOP_FUNCTION(GetAttribute) +NOP_FUNCTION(GetAttributeU32) +NOP_FUNCTION(SetAttribute) +NOP_FUNCTION(GetPatch) +NOP_FUNCTION(SetPatch) +NOP_FUNCTION(GetTessGenericAttribute) +NOP_FUNCTION(SetTcsGenericAttribute) +NOP_FUNCTION(ReadTcsGenericOuputAttribute) + +NOP_FUNCTION(GetScc) +NOP_FUNCTION(GetExec) +NOP_FUNCTION(GetVcc) +NOP_FUNCTION(GetVccLo) +NOP_FUNCTION(GetVccHi) +NOP_FUNCTION(GetM0) +NOP_FUNCTION(SetScc) +NOP_FUNCTION(SetExec) +NOP_FUNCTION(SetVcc) +NOP_FUNCTION(SetSccLo) +NOP_FUNCTION(SetVccLo) +NOP_FUNCTION(SetVccHi) +NOP_FUNCTION(SetM0) + +NOP_FUNCTION(UndefU1) +NOP_FUNCTION(UndefU8) +NOP_FUNCTION(UndefU16) +NOP_FUNCTION(UndefU32) +NOP_FUNCTION(UndefU64) + +NOP_FUNCTION(LoadBufferU8) +NOP_FUNCTION(LoadBufferU16) +NOP_FUNCTION(LoadBufferU32) +NOP_FUNCTION(LoadBufferU32x2) +NOP_FUNCTION(LoadBufferU32x3) +NOP_FUNCTION(LoadBufferU32x4) +NOP_FUNCTION(LoadBufferF32) +NOP_FUNCTION(LoadBufferF32x2) +NOP_FUNCTION(LoadBufferF32x3) +NOP_FUNCTION(LoadBufferF32x4) +NOP_FUNCTION(LoadBufferFormatF32) +NOP_FUNCTION(StoreBufferU8) +NOP_FUNCTION(StoreBufferU16) +NOP_FUNCTION(StoreBufferU32) +NOP_FUNCTION(StoreBufferU32x2) +NOP_FUNCTION(StoreBufferU32x3) +NOP_FUNCTION(StoreBufferU32x4) +NOP_FUNCTION(StoreBufferF32) +NOP_FUNCTION(StoreBufferF32x2) +NOP_FUNCTION(StoreBufferF32x3) +NOP_FUNCTION(StoreBufferF32x4) +NOP_FUNCTION(StoreBufferFormatF32) + +NOP_FUNCTION(BufferAtomicIAdd32) +NOP_FUNCTION(BufferAtomicSMin32) +NOP_FUNCTION(BufferAtomicUMin32) +NOP_FUNCTION(BufferAtomicSMax32) +NOP_FUNCTION(BufferAtomicUMax32) +NOP_FUNCTION(BufferAtomicInc32) +NOP_FUNCTION(BufferAtomicDec32) +NOP_FUNCTION(BufferAtomicAnd32) +NOP_FUNCTION(BufferAtomicOr32) +NOP_FUNCTION(BufferAtomicXor32) +NOP_FUNCTION(BufferAtomicSwap32) + +// Select instructions are handled separately +NOP_FUNCTION(SelectU1) +NOP_FUNCTION(SelectU8) +NOP_FUNCTION(SelectU16) +NOP_FUNCTION(SelectU32) +NOP_FUNCTION(SelectU64) +NOP_FUNCTION(SelectF32) +NOP_FUNCTION(SelectF64) + +NOP_FUNCTION(FPOrdEqual32) +NOP_FUNCTION(FPOrdEqual64) +NOP_FUNCTION(FPUnordEqual32) +NOP_FUNCTION(FPUnordEqual64) +NOP_FUNCTION(FPOrdNotEqual32) +NOP_FUNCTION(FPOrdNotEqual64) +NOP_FUNCTION(FPUnordNotEqual32) +NOP_FUNCTION(FPUnordNotEqual64) +NOP_FUNCTION(FPOrdLessThan32) +NOP_FUNCTION(FPOrdLessThan64) +NOP_FUNCTION(FPUnordLessThan32) +NOP_FUNCTION(FPUnordLessThan64) +NOP_FUNCTION(FPOrdGreaterThan32) +NOP_FUNCTION(FPOrdGreaterThan64) +NOP_FUNCTION(FPUnordGreaterThan32) +NOP_FUNCTION(FPUnordGreaterThan64) +NOP_FUNCTION(FPOrdLessThanEqual32) +NOP_FUNCTION(FPOrdLessThanEqual64) +NOP_FUNCTION(FPUnordLessThanEqual32) +NOP_FUNCTION(FPUnordLessThanEqual64) +NOP_FUNCTION(FPOrdGreaterThanEqual32) +NOP_FUNCTION(FPOrdGreaterThanEqual64) +NOP_FUNCTION(FPUnordGreaterThanEqual32) +NOP_FUNCTION(FPUnordGreaterThanEqual64) +NOP_FUNCTION(FPIsNan32) +NOP_FUNCTION(FPIsNan64) +NOP_FUNCTION(FPIsInf32) +NOP_FUNCTION(FPIsInf64) +NOP_FUNCTION(FPCmpClass32) + +NOP_FUNCTION(SLessThan32) +NOP_FUNCTION(SLessThan64) +NOP_FUNCTION(ULessThan32) +NOP_FUNCTION(ULessThan64) +NOP_FUNCTION(IEqual32) +NOP_FUNCTION(IEqual64) +NOP_FUNCTION(SLessThanEqual) +NOP_FUNCTION(ULessThanEqual) +NOP_FUNCTION(SGreaterThan) +NOP_FUNCTION(UGreaterThan) +NOP_FUNCTION(INotEqual32) +NOP_FUNCTION(INotEqual64) +NOP_FUNCTION(SGreaterThanEqual) +NOP_FUNCTION(UGreaterThanEqual) + +NOP_FUNCTION(ImageSampleRaw) +NOP_FUNCTION(ImageSampleImplicitLod) +NOP_FUNCTION(ImageSampleExplicitLod) +NOP_FUNCTION(ImageSampleDrefImplicitLod) +NOP_FUNCTION(ImageSampleDrefExplicitLod) +NOP_FUNCTION(ImageGather) +NOP_FUNCTION(ImageGatherDref) +NOP_FUNCTION(ImageQueryDimensions) +NOP_FUNCTION(ImageQueryLod) +NOP_FUNCTION(ImageGradient) +NOP_FUNCTION(ImageRead) +NOP_FUNCTION(ImageWrite) + +NOP_FUNCTION(ImageAtomicIAdd32) +NOP_FUNCTION(ImageAtomicSMin32) +NOP_FUNCTION(ImageAtomicUMin32) +NOP_FUNCTION(ImageAtomicSMax32) +NOP_FUNCTION(ImageAtomicUMax32) +NOP_FUNCTION(ImageAtomicInc32) +NOP_FUNCTION(ImageAtomicDec32) +NOP_FUNCTION(ImageAtomicAnd32) +NOP_FUNCTION(ImageAtomicOr32) +NOP_FUNCTION(ImageAtomicXor32) +NOP_FUNCTION(ImageAtomicExchange32) + +NOP_FUNCTION(CubeFaceIndex) + +NOP_FUNCTION(LaneId) +NOP_FUNCTION(WarpId) +NOP_FUNCTION(QuadShuffle) +NOP_FUNCTION(ReadFirstLane) +NOP_FUNCTION(ReadLane) +NOP_FUNCTION(WriteLane) +NOP_FUNCTION(DataAppend) +NOP_FUNCTION(DataConsume) + +#undef NOP_FUNCTION + +} // namespace Shader::IR::ComputeValue diff --git a/src/shader_recompiler/ir/compute_value/do_packing.cpp b/src/shader_recompiler/ir/compute_value/do_packing.cpp new file mode 100644 index 000000000..9d5169f43 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_packing.cpp @@ -0,0 +1,132 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "shader_recompiler/ir/compute_value/do_packing.h" + +namespace Shader::IR::ComputeValue { + +void DoPackUint2x32(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUint2x32(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackFloat2x32(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackUnorm2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUnorm2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackSnorm2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackSnorm2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackUint2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUint2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackSint2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackSint2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackHalf2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackHalf2x16(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackUnorm4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUnorm4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackSnorm4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackSnorm4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackUint4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUint4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackSint4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackSint4x8(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackUfloat10_11_11(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUfloat10_11_11(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackUnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackSnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackSnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackUint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackUint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoPackSint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +void DoUnpackSint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0) { + UNREACHABLE_MSG("Unimplemented"); +} + +} // namespace Shader::IR::ComputeValue diff --git a/src/shader_recompiler/ir/compute_value/do_packing.h b/src/shader_recompiler/ir/compute_value/do_packing.h new file mode 100644 index 000000000..9699894f4 --- /dev/null +++ b/src/shader_recompiler/ir/compute_value/do_packing.h @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/compute_value/compute.h" + +namespace Shader::IR::ComputeValue { + +void DoPackUint2x32(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUint2x32(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackFloat2x32(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackUnorm2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUnorm2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackSnorm2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackSnorm2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackUint2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUint2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackSint2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackSint2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackHalf2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackHalf2x16(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackUnorm4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUnorm4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackSnorm4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackSnorm4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackUint4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUint4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackSint4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackSint4x8(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackUfloat10_11_11(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUfloat10_11_11(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackUnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackSnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackSnorm2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackUint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackUint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); +void DoPackSint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); +void DoUnpackSint2_10_10_10(ImmValueList& inst_values, const ImmValueList& args0); + +} // namespace Shader::IR::ComputeValue diff --git a/src/shader_recompiler/ir/compute_value/imm_value.cpp b/src/shader_recompiler/ir/compute_value/imm_value.cpp index e94533e57..d92aed43c 100644 --- a/src/shader_recompiler/ir/compute_value/imm_value.cpp +++ b/src/shader_recompiler/ir/compute_value/imm_value.cpp @@ -4,11 +4,10 @@ #include "common/hash.h" #include "shader_recompiler/ir/compute_value/imm_value.h" -namespace Shader::IR { +namespace Shader::IR::ComputeValue { ImmValue::ImmValue(const IR::Value& value) noexcept { - type = value.Type(); - switch (type) { + switch (value.Type()) { case Type::U1: imm_values[0].imm_u1 = value.U1(); break; @@ -31,1423 +30,1196 @@ ImmValue::ImmValue(const IR::Value& value) noexcept { imm_values[0].imm_f64 = value.F64(); break; default: - UNREACHABLE_MSG("Invalid type {}", type); + UNREACHABLE_MSG("Invalid type {}", value.Type()); } } -ImmValue::ImmValue(bool value) noexcept : type{Type::U1}, is_signed{false} { +ImmValue::ImmValue(bool value) noexcept { imm_values[0].imm_u1 = value; } -ImmValue::ImmValue(u8 value) noexcept : type{Type::U8}, is_signed{false} { +ImmValue::ImmValue(u8 value) noexcept { imm_values[0].imm_u8 = value; } -ImmValue::ImmValue(s8 value) noexcept : type{Type::U8}, is_signed{true} { +ImmValue::ImmValue(s8 value) noexcept { imm_values[0].imm_s8 = value; } -ImmValue::ImmValue(u16 value) noexcept : type{Type::U16}, is_signed{false} { +ImmValue::ImmValue(u16 value) noexcept { imm_values[0].imm_u16 = value; } -ImmValue::ImmValue(s16 value) noexcept : type{Type::U16}, is_signed{true} { +ImmValue::ImmValue(s16 value) noexcept { imm_values[0].imm_s16 = value; } -ImmValue::ImmValue(u32 value) noexcept : type{Type::U32}, is_signed{false} { +ImmValue::ImmValue(u32 value) noexcept { imm_values[0].imm_u32 = value; } -ImmValue::ImmValue(s32 value) noexcept : type{Type::U32}, is_signed{true} { +ImmValue::ImmValue(s32 value) noexcept { imm_values[0].imm_s32 = value; } -ImmValue::ImmValue(f32 value) noexcept : type{Type::F32}, is_signed{true} { +ImmValue::ImmValue(f32 value) noexcept { imm_values[0].imm_f32 = value; } -ImmValue::ImmValue(u64 value) noexcept : type{Type::U64}, is_signed{false} { +ImmValue::ImmValue(u64 value) noexcept { imm_values[0].imm_u64 = value; } -ImmValue::ImmValue(s64 value) noexcept : type{Type::U64}, is_signed{true} { +ImmValue::ImmValue(s64 value) noexcept { imm_values[0].imm_s64 = value; } -ImmValue::ImmValue(f64 value) noexcept : type{Type::F64}, is_signed{true} { +ImmValue::ImmValue(f64 value) noexcept { imm_values[0].imm_f64 = value; } -ImmValue::ImmValue(u32 value1, u32 value2) noexcept : type{Type::U32x2}, is_signed{false} { +ImmValue::ImmValue(u32 value1, u32 value2) noexcept { imm_values[0].imm_u32 = value1; imm_values[1].imm_u32 = value2; } -ImmValue::ImmValue(u32 value1, u32 value2, u32 value3) noexcept - : type{Type::U32x3}, is_signed{false} { +ImmValue::ImmValue(u32 value1, u32 value2, u32 value3) noexcept { imm_values[0].imm_u32 = value1; imm_values[1].imm_u32 = value2; imm_values[2].imm_u32 = value3; } -ImmValue::ImmValue(u32 value1, u32 value2, u32 value3, u32 value4) noexcept - : type{Type::U32x4}, is_signed{false} { +ImmValue::ImmValue(u32 value1, u32 value2, u32 value3, u32 value4) noexcept { imm_values[0].imm_u32 = value1; imm_values[1].imm_u32 = value2; imm_values[2].imm_u32 = value3; imm_values[3].imm_u32 = value4; } -ImmValue::ImmValue(s32 value1, s32 value2) noexcept : type{Type::U32x2}, is_signed{true} { +ImmValue::ImmValue(s32 value1, s32 value2) noexcept { imm_values[0].imm_s32 = value1; imm_values[1].imm_s32 = value2; } -ImmValue::ImmValue(s32 value1, s32 value2, s32 value3) noexcept - : type{Type::U32x3}, is_signed{true} { +ImmValue::ImmValue(s32 value1, s32 value2, s32 value3) noexcept { imm_values[0].imm_s32 = value1; imm_values[1].imm_s32 = value2; imm_values[2].imm_s32 = value3; } -ImmValue::ImmValue(s32 value1, s32 value2, s32 value3, s32 value4) noexcept - : type{Type::U32x4}, is_signed{true} { +ImmValue::ImmValue(s32 value1, s32 value2, s32 value3, s32 value4) noexcept { imm_values[0].imm_s32 = value1; imm_values[1].imm_s32 = value2; imm_values[2].imm_s32 = value3; imm_values[3].imm_s32 = value4; } -ImmValue::ImmValue(f32 value1, f32 value2) noexcept : type{Type::F32x2}, is_signed{true} { +ImmValue::ImmValue(f32 value1, f32 value2) noexcept { imm_values[0].imm_f32 = value1; imm_values[1].imm_f32 = value2; } -ImmValue::ImmValue(f32 value1, f32 value2, f32 value3) noexcept - : type{Type::F32x3}, is_signed{true} { +ImmValue::ImmValue(f32 value1, f32 value2, f32 value3) noexcept { imm_values[0].imm_f32 = value1; imm_values[1].imm_f32 = value2; imm_values[2].imm_f32 = value3; } -ImmValue::ImmValue(f32 value1, f32 value2, f32 value3, f32 value4) noexcept - : type{Type::F32x4}, is_signed{true} { +ImmValue::ImmValue(f32 value1, f32 value2, f32 value3, f32 value4) noexcept { imm_values[0].imm_f32 = value1; imm_values[1].imm_f32 = value2; imm_values[2].imm_f32 = value3; imm_values[3].imm_f32 = value4; } -ImmValue::ImmValue(f64 value1, f64 value2) noexcept : type{Type::F64x2}, is_signed{true} { +ImmValue::ImmValue(u64 value1, u64 value2) noexcept { + imm_values[0].imm_u64 = value1; + imm_values[1].imm_u64 = value2; +} + +ImmValue::ImmValue(u64 value1, u64 value2, u64 value3) noexcept { + imm_values[0].imm_u64 = value1; + imm_values[1].imm_u64 = value2; + imm_values[2].imm_u64 = value3; +} + +ImmValue::ImmValue(u64 value1, u64 value2, u64 value3, u64 value4) noexcept { + imm_values[0].imm_u64 = value1; + imm_values[1].imm_u64 = value2; + imm_values[2].imm_u64 = value3; + imm_values[3].imm_u64 = value4; +} + +ImmValue::ImmValue(s64 value1, s64 value2) noexcept { + imm_values[0].imm_s64 = value1; + imm_values[1].imm_s64 = value2; +} + +ImmValue::ImmValue(s64 value1, s64 value2, s64 value3) noexcept { + imm_values[0].imm_s64 = value1; + imm_values[1].imm_s64 = value2; + imm_values[2].imm_s64 = value3; +} + +ImmValue::ImmValue(s64 value1, s64 value2, s64 value3, s64 value4) noexcept { + imm_values[0].imm_s64 = value1; + imm_values[1].imm_s64 = value2; + imm_values[2].imm_s64 = value3; + imm_values[3].imm_s64 = value4; +} + +ImmValue::ImmValue(f64 value1, f64 value2) noexcept { imm_values[0].imm_f64 = value1; imm_values[1].imm_f64 = value2; } -ImmValue::ImmValue(f64 value1, f64 value2, f64 value3) noexcept - : type{Type::F64x3}, is_signed{true} { +ImmValue::ImmValue(f64 value1, f64 value2, f64 value3) noexcept { imm_values[0].imm_f64 = value1; imm_values[1].imm_f64 = value2; imm_values[2].imm_f64 = value3; } -ImmValue::ImmValue(f64 value1, f64 value2, f64 value3, f64 value4) noexcept - : type{Type::F64x4}, is_signed{true} { +ImmValue::ImmValue(f64 value1, f64 value2, f64 value3, f64 value4) noexcept { imm_values[0].imm_f64 = value1; imm_values[1].imm_f64 = value2; imm_values[2].imm_f64 = value3; imm_values[3].imm_f64 = value4; } -ImmValue::ImmValue(const ImmValue& value1, const ImmValue& value2) noexcept - : type{value1.type}, is_signed{value1.is_signed} { - ASSERT(value1.type == value2.type && value1.is_signed == value2.is_signed); - switch (value1.Dimensions()) { - case 1: - imm_values[0] = value1.imm_values[0]; - imm_values[1] = value2.imm_values[0]; - break; - case 2: - imm_values[0] = value1.imm_values[0]; - imm_values[1] = value1.imm_values[1]; - imm_values[2] = value2.imm_values[0]; - imm_values[3] = value2.imm_values[1]; - break; - default: - UNREACHABLE_MSG("Invalid dimensions {}", value1.Dimensions()); - } +ImmValue::ImmValue(const ImmValue& value1, const ImmValue& value2) noexcept { + imm_values[0] = value1.imm_values[0]; + imm_values[1] = value2.imm_values[0]; } -ImmValue::ImmValue(const ImmValue& value1, const ImmValue& value2, const ImmValue& value3) noexcept - : type{value1.type}, is_signed{value1.is_signed} { - ASSERT(value1.type == value2.type && value1.type == value3.type && - value1.is_signed == value2.is_signed && value1.is_signed == value3.is_signed && - value1.Dimensions() == 1); +ImmValue::ImmValue(const ImmValue& value1, const ImmValue& value2, + const ImmValue& value3) noexcept { imm_values[0] = value1.imm_values[0]; imm_values[1] = value2.imm_values[0]; imm_values[2] = value3.imm_values[0]; } ImmValue::ImmValue(const ImmValue& value1, const ImmValue& value2, const ImmValue& value3, - const ImmValue& value4) noexcept - : type{value1.type}, is_signed{value1.is_signed} { - ASSERT(value1.type == value2.type && value1.type == value3.type && value1.type == value4.type && - value1.is_signed == value2.is_signed && value1.is_signed == value3.is_signed && - value1.is_signed == value4.is_signed && value1.Dimensions() == 1); + const ImmValue& value4) noexcept { imm_values[0] = value1.imm_values[0]; imm_values[1] = value2.imm_values[0]; imm_values[2] = value3.imm_values[0]; imm_values[3] = value4.imm_values[0]; } -IR::Type ImmValue::BaseType() const noexcept { - switch (type) { - case Type::U1: - return Type::U1; - case Type::U8: - return Type::U8; - case Type::U16: - return Type::U16; - case Type::U32: - case Type::U32x2: - case Type::U32x3: - case Type::U32x4: - return Type::U32; - case Type::U64: - return Type::U64; - case Type::F32: - case Type::F32x2: - case Type::F32x3: - case Type::F32x4: - return Type::F32; - case Type::F64: - case Type::F64x2: - case Type::F64x3: - case Type::F64x4: - return Type::F64; - default: - UNREACHABLE_MSG("Invalid type {}", type); - } -} - -u32 ImmValue::Dimensions() const noexcept { - switch (type) { - case Type::U1: - case Type::U8: - case Type::U16: - case Type::U32: - case Type::U64: - case Type::F32: - case Type::F64: - return 1; - case Type::U32x2: - case Type::F32x2: - case Type::F64x2: - return 2; - case Type::U32x3: - case Type::F32x3: - case Type::F64x3: - return 3; - case Type::U32x4: - case Type::F32x4: - case Type::F64x4: - return 4; - default: - UNREACHABLE_MSG("Invalid type {}", type); - } -} - -bool ImmValue::IsSigned() const noexcept { - return is_signed; -} - -void ImmValue::SetSigned(bool signed_) noexcept { - is_signed = signed_; -} - -void ImmValue::SameSignAs(const ImmValue& other) noexcept { - SetSigned(other.IsSigned()); -} - -ImmValue ImmValue::Convert(IR::Type new_type, bool new_signed) const noexcept { - switch (new_type) { - case Type::U16: { - switch (type) { - case Type::U32: - return ImmValue(static_cast(imm_values[0].imm_u32)); - default: - break; - } - break; - } - case Type::U32: { - if (new_signed) { - switch (type) { - case Type::F32: - return ImmValue(static_cast(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(static_cast(imm_values[0].imm_f64)); - default: - break; - } - } else { - switch (type) { - case Type::U16: - return ImmValue(static_cast(imm_values[0].imm_u16)); - case Type::U32: - if (is_signed) { - return ImmValue(static_cast(imm_values[0].imm_s32)); - } - break; - case Type::F32: - return ImmValue(static_cast(imm_values[0].imm_f32)); - default: - break; - } - } - } - case Type::F32: { - switch (type) { - case Type::U16: - return ImmValue(static_cast(imm_values[0].imm_u16)); - case Type::U32: - if (is_signed) { - return ImmValue(static_cast(imm_values[0].imm_s32)); - } else { - return ImmValue(static_cast(imm_values[0].imm_u32)); - } - case Type::F64: - return ImmValue(static_cast(imm_values[0].imm_f64)); - default: - break; - } - break; - } - case Type::F64: { - switch (type) { - case Type::F32: - return ImmValue(static_cast(imm_values[0].imm_f32)); - default: - break; - } - break; - } - default: - break; - } - UNREACHABLE_MSG("Invalid conversion from {} {} to {} {}", is_signed ? "signed" : "unsigned", - type, new_signed ? "signed" : "unsigned", new_type); -} - -ImmValue ImmValue::Bitcast(IR::Type new_type, bool new_signed) const noexcept { +ImmValue ImmValue::CompositeFrom2x2(const ImmValue& value1, const ImmValue& value2) noexcept { ImmValue result; - result.type = new_type; - result.is_signed = new_signed; - result.imm_values = imm_values; - ASSERT(Dimensions() == result.Dimensions()); - return result; -} - -ImmValue ImmValue::Extract(const ImmU32& index) const noexcept { - ASSERT(index.imm_values[0].imm_u32 < Dimensions()); - ImmValue result; - result.type = BaseType(); - result.is_signed = IsSigned(); - result.imm_values[0] = imm_values[index.imm_values[0].imm_u32]; - return result; -} - -ImmValue ImmValue::Insert(const ImmValue& value, const ImmU32& index) const noexcept { - ASSERT(index.imm_values[0].imm_u32 < Dimensions()); - ASSERT(value.type == BaseType() && value.IsSigned() == IsSigned()); - ImmValue result = *this; - result.imm_values[index.imm_values[0].imm_u32] = value.imm_values[0]; + result.imm_values[0] = value1.imm_values[0]; + result.imm_values[1] = value1.imm_values[1]; + result.imm_values[2] = value2.imm_values[0]; + result.imm_values[3] = value2.imm_values[1]; return result; } bool ImmValue::operator==(const ImmValue& other) const noexcept { - if (type != other.type) { - return false; - } - switch (type) { - case Type::U1: - return imm_values[0].imm_u1 == other.imm_values[0].imm_u1; - case Type::U8: - return imm_values[0].imm_u8 == other.imm_values[0].imm_u8; - case Type::U16: - return imm_values[0].imm_u16 == other.imm_values[0].imm_u16; - case Type::U32: - case Type::F32: - return imm_values[0].imm_u32 == other.imm_values[0].imm_u32; - case Type::U64: - case Type::F64: - return imm_values[0].imm_u64 == other.imm_values[0].imm_u64; - case Type::U32x2: - case Type::F32x2: - case Type::F64x2: - return imm_values[0].imm_u32 == other.imm_values[0].imm_u32 && - imm_values[1].imm_u32 == other.imm_values[1].imm_u32; - case Type::U32x3: - case Type::F32x3: - case Type::F64x3: - return imm_values[0].imm_u32 == other.imm_values[0].imm_u32 && - imm_values[1].imm_u32 == other.imm_values[1].imm_u32 && - imm_values[2].imm_u32 == other.imm_values[2].imm_u32; - case Type::U32x4: - case Type::F32x4: - case Type::F64x4: - return imm_values[0].imm_u32 == other.imm_values[0].imm_u32 && - imm_values[1].imm_u32 == other.imm_values[1].imm_u32 && - imm_values[2].imm_u32 == other.imm_values[2].imm_u32 && - imm_values[3].imm_u32 == other.imm_values[3].imm_u32; - default: - UNREACHABLE_MSG("Invalid type {}", type); - } + return imm_values[0].imm_u64 == other.imm_values[0].imm_u64 && + imm_values[1].imm_u64 == other.imm_values[1].imm_u64 && + imm_values[2].imm_u64 == other.imm_values[2].imm_u64 && + imm_values[3].imm_u64 == other.imm_values[3].imm_u64; } bool ImmValue::operator!=(const ImmValue& other) const noexcept { return !operator==(other); } -bool ImmValue::operator<(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U8: - return is_signed && other.is_signed ? imm_values[0].imm_s8 < other.imm_values[0].imm_s8 - : imm_values[0].imm_u8 < other.imm_values[0].imm_u8; - case Type::U16: - return is_signed && other.is_signed ? imm_values[0].imm_s16 < other.imm_values[0].imm_s16 - : imm_values[0].imm_u16 < other.imm_values[0].imm_u16; - case Type::U32: - return is_signed && other.is_signed ? imm_values[0].imm_s32 < other.imm_values[0].imm_s32 - : imm_values[0].imm_u32 < other.imm_values[0].imm_u32; - case Type::F32: - return imm_values[0].imm_f32 < other.imm_values[0].imm_f32; - case Type::U64: - return is_signed && other.is_signed ? imm_values[0].imm_s64 < other.imm_values[0].imm_s64 - : imm_values[0].imm_u64 < other.imm_values[0].imm_u64; - case Type::F64: - return imm_values[0].imm_f64 < other.imm_values[0].imm_f64; - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +ImmValue ImmValue::Extract(const ImmValue& vec, const ImmValue& index) noexcept { + ImmValue result; + result.imm_values[0] = vec.imm_values[index.imm_values[0].imm_u32]; + return result; } -bool ImmValue::operator>(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U8: - return is_signed && other.is_signed ? imm_values[0].imm_s8 > other.imm_values[0].imm_s8 - : imm_values[0].imm_u8 > other.imm_values[0].imm_u8; - case Type::U16: - return is_signed && other.is_signed ? imm_values[0].imm_s16 > other.imm_values[0].imm_s16 - : imm_values[0].imm_u16 > other.imm_values[0].imm_u16; - case Type::U32: - return is_signed && other.is_signed ? imm_values[0].imm_s32 > other.imm_values[0].imm_s32 - : imm_values[0].imm_u32 > other.imm_values[0].imm_u32; - case Type::F32: - return imm_values[0].imm_f32 > other.imm_values[0].imm_f32; - case Type::U64: - return is_signed && other.is_signed ? imm_values[0].imm_s64 > other.imm_values[0].imm_s64 - : imm_values[0].imm_u64 > other.imm_values[0].imm_u64; - case Type::F64: - return imm_values[0].imm_f64 > other.imm_values[0].imm_f64; - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +ImmValue ImmValue::Insert(const ImmValue& vec, const ImmValue& value, + const ImmValue& index) noexcept { + ImmValue result = vec; + result.imm_values[index.imm_values[0].imm_u32] = value.imm_values[0]; + return result; } -bool ImmValue::operator<=(const ImmValue& other) const noexcept { - return !operator>(other); +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_u32)); } -bool ImmValue::operator>=(const ImmValue& other) const noexcept { - return !operator<(other); +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_u16)); } -ImmValue ImmValue::operator+(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U8: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s8 + other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 + other.imm_values[0].imm_u8); - case Type::U16: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s16 + other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 + other.imm_values[0].imm_u16); - case Type::U32: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 + other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 + other.imm_values[0].imm_u32); - case Type::F32: - return ImmValue(imm_values[0].imm_f32 + other.imm_values[0].imm_f32); - case Type::U32x2: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 + other.imm_values[0].imm_s32, - imm_values[1].imm_s32 + other.imm_values[1].imm_s32) - : ImmValue(imm_values[0].imm_u32 + other.imm_values[0].imm_u32, - imm_values[1].imm_u32 + other.imm_values[1].imm_u32); - case Type::F32x2: - return ImmValue(imm_values[0].imm_f32 + other.imm_values[0].imm_f32, - imm_values[1].imm_f32 + other.imm_values[1].imm_f32); - case Type::U32x3: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 + other.imm_values[0].imm_s32, - imm_values[1].imm_s32 + other.imm_values[1].imm_s32, - imm_values[2].imm_s32 + other.imm_values[2].imm_s32) - : ImmValue(imm_values[0].imm_u32 + other.imm_values[0].imm_u32, - imm_values[1].imm_u32 + other.imm_values[1].imm_u32, - imm_values[2].imm_u32 + other.imm_values[2].imm_u32); - case Type::F32x3: - return ImmValue(imm_values[0].imm_f32 + other.imm_values[0].imm_f32, - imm_values[1].imm_f32 + other.imm_values[1].imm_f32, - imm_values[2].imm_f32 + other.imm_values[2].imm_f32); - case Type::U32x4: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 + other.imm_values[0].imm_s32, - imm_values[1].imm_s32 + other.imm_values[1].imm_s32, - imm_values[2].imm_s32 + other.imm_values[2].imm_s32, - imm_values[3].imm_s32 + other.imm_values[3].imm_s32) - : ImmValue(imm_values[0].imm_u32 + other.imm_values[0].imm_u32, - imm_values[1].imm_u32 + other.imm_values[1].imm_u32, - imm_values[2].imm_u32 + other.imm_values[2].imm_u32, - imm_values[3].imm_u32 + other.imm_values[3].imm_u32); - case Type::F32x4: - return ImmValue(imm_values[0].imm_f32 + other.imm_values[0].imm_f32, - imm_values[1].imm_f32 + other.imm_values[1].imm_f32, - imm_values[2].imm_f32 + other.imm_values[2].imm_f32, - imm_values[3].imm_f32 + other.imm_values[3].imm_f32); - case Type::U64: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s64 + other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 + other.imm_values[0].imm_u64); - case Type::F64: - return ImmValue(imm_values[0].imm_f64 + other.imm_values[0].imm_f64); - case Type::F64x2: - return ImmValue(imm_values[0].imm_f64 + other.imm_values[0].imm_f64, - imm_values[1].imm_f64 + other.imm_values[1].imm_f64); - case Type::F64x3: - return ImmValue(imm_values[0].imm_f64 + other.imm_values[0].imm_f64, - imm_values[1].imm_f64 + other.imm_values[1].imm_f64, - imm_values[2].imm_f64 + other.imm_values[2].imm_f64); - case Type::F64x4: - return ImmValue(imm_values[0].imm_f64 + other.imm_values[0].imm_f64, - imm_values[1].imm_f64 + other.imm_values[1].imm_f64, - imm_values[2].imm_f64 + other.imm_values[2].imm_f64, - imm_values[3].imm_f64 + other.imm_values[3].imm_f64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_s32)); } -ImmValue ImmValue::operator-(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U8: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s8 - other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 - other.imm_values[0].imm_u8); - case Type::U16: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s16 - other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 - other.imm_values[0].imm_u16); - case Type::U32: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 - other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 - other.imm_values[0].imm_u32); - case Type::F32: - return ImmValue(imm_values[0].imm_f32 - other.imm_values[0].imm_f32); - case Type::U32x2: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 - other.imm_values[0].imm_s32, - imm_values[1].imm_s32 - other.imm_values[1].imm_s32) - : ImmValue(imm_values[0].imm_u32 - other.imm_values[0].imm_u32, - imm_values[1].imm_u32 - other.imm_values[1].imm_u32); - case Type::F32x2: - return ImmValue(imm_values[0].imm_f32 - other.imm_values[0].imm_f32, - imm_values[1].imm_f32 - other.imm_values[1].imm_f32); - case Type::U32x3: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 - other.imm_values[0].imm_s32, - imm_values[1].imm_s32 - other.imm_values[1].imm_s32, - imm_values[2].imm_s32 - other.imm_values[2].imm_s32) - : ImmValue(imm_values[0].imm_u32 - other.imm_values[0].imm_u32, - imm_values[1].imm_u32 - other.imm_values[1].imm_u32, - imm_values[2].imm_u32 - other.imm_values[2].imm_u32); - case Type::F32x3: - return ImmValue(imm_values[0].imm_f32 - other.imm_values[0].imm_f32, - imm_values[1].imm_f32 - other.imm_values[1].imm_f32, - imm_values[2].imm_f32 - other.imm_values[2].imm_f32); - case Type::U32x4: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 - other.imm_values[0].imm_s32, - imm_values[1].imm_s32 - other.imm_values[1].imm_s32, - imm_values[2].imm_s32 - other.imm_values[2].imm_s32, - imm_values[3].imm_s32 - other.imm_values[3].imm_s32) - : ImmValue(imm_values[0].imm_u32 - other.imm_values[0].imm_u32, - imm_values[1].imm_u32 - other.imm_values[1].imm_u32, - imm_values[2].imm_u32 - other.imm_values[2].imm_u32, - imm_values[3].imm_u32 - other.imm_values[3].imm_u32); - case Type::F32x4: - return ImmValue(imm_values[0].imm_f32 - other.imm_values[0].imm_f32, - imm_values[1].imm_f32 - other.imm_values[1].imm_f32, - imm_values[2].imm_f32 - other.imm_values[2].imm_f32, - imm_values[3].imm_f32 - other.imm_values[3].imm_f32); - case Type::U64: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s64 - other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 - other.imm_values[0].imm_u64); - case Type::F64: - return ImmValue(imm_values[0].imm_f64 - other.imm_values[0].imm_f64); - case Type::F64x2: - return ImmValue(imm_values[0].imm_f64 - other.imm_values[0].imm_f64, - imm_values[1].imm_f64 - other.imm_values[1].imm_f64); - case Type::F64x3: - return ImmValue(imm_values[0].imm_f64 - other.imm_values[0].imm_f64, - imm_values[1].imm_f64 - other.imm_values[1].imm_f64, - imm_values[2].imm_f64 - other.imm_values[2].imm_f64); - case Type::F64x4: - return ImmValue(imm_values[0].imm_f64 - other.imm_values[0].imm_f64, - imm_values[1].imm_f64 - other.imm_values[1].imm_f64, - imm_values[2].imm_f64 - other.imm_values[2].imm_f64, - imm_values[3].imm_f64 - other.imm_values[3].imm_f64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_f32)); } -ImmValue ImmValue::operator*(const ImmValue& other) const noexcept { - ASSERT(BaseType() == other.BaseType()); - const ImmValue* vector; - const ImmValue* scalar; - if (Dimensions() == 1) { - scalar = this; - vector = &other; - } else if (other.Dimensions() == 1) { - scalar = &other; - vector = this; - } else { - UNREACHABLE_MSG("Unspecified behavior for vector * vector multiplication"); - } - switch (vector->type) { - case Type::U8: - return is_signed && scalar->is_signed - ? ImmValue(scalar->imm_values[0].imm_s8 * vector->imm_values[0].imm_s8) - : ImmValue(scalar->imm_values[0].imm_u8 * vector->imm_values[0].imm_u8); - case Type::U16: - return is_signed && scalar->is_signed - ? ImmValue(scalar->imm_values[0].imm_s16 * vector->imm_values[0].imm_s16) - : ImmValue(scalar->imm_values[0].imm_u16 * vector->imm_values[0].imm_u16); - case Type::U32: - return is_signed && scalar->is_signed - ? ImmValue(scalar->imm_values[0].imm_s32 * vector->imm_values[0].imm_s32) - : ImmValue(scalar->imm_values[0].imm_u32 * vector->imm_values[0].imm_u32); - case Type::F32: - return ImmValue(scalar->imm_values[0].imm_f32 * vector->imm_values[0].imm_f32); - case Type::U32x2: - return is_signed && scalar->is_signed - ? ImmValue(scalar->imm_values[0].imm_s32 * vector->imm_values[0].imm_s32, - scalar->imm_values[0].imm_s32 * vector->imm_values[1].imm_s32) - : ImmValue(scalar->imm_values[0].imm_u32 * vector->imm_values[0].imm_u32, - scalar->imm_values[0].imm_u32 * vector->imm_values[1].imm_u32); - case Type::F32x2: - return ImmValue(scalar->imm_values[0].imm_f32 * vector->imm_values[0].imm_f32, - scalar->imm_values[0].imm_f32 * vector->imm_values[1].imm_f32); - case Type::U32x3: - return is_signed && scalar->is_signed - ? ImmValue(scalar->imm_values[0].imm_s32 * vector->imm_values[0].imm_s32, - scalar->imm_values[0].imm_s32 * vector->imm_values[1].imm_s32, - scalar->imm_values[0].imm_s32 * vector->imm_values[2].imm_s32) - : ImmValue(scalar->imm_values[0].imm_u32 * vector->imm_values[0].imm_u32, - scalar->imm_values[0].imm_u32 * vector->imm_values[1].imm_u32, - scalar->imm_values[0].imm_u32 * vector->imm_values[2].imm_u32); - case Type::F32x3: - return ImmValue(scalar->imm_values[0].imm_f32 * vector->imm_values[0].imm_f32, - scalar->imm_values[0].imm_f32 * vector->imm_values[1].imm_f32, - scalar->imm_values[0].imm_f32 * vector->imm_values[2].imm_f32); - case Type::U32x4: - return is_signed && scalar->is_signed - ? ImmValue(scalar->imm_values[0].imm_s32 * vector->imm_values[0].imm_s32, - scalar->imm_values[0].imm_s32 * vector->imm_values[1].imm_s32, - scalar->imm_values[0].imm_s32 * vector->imm_values[2].imm_s32, - scalar->imm_values[0].imm_s32 * vector->imm_values[3].imm_s32) - : ImmValue(scalar->imm_values[0].imm_u32 * vector->imm_values[0].imm_u32, - scalar->imm_values[0].imm_u32 * vector->imm_values[1].imm_u32, - scalar->imm_values[0].imm_u32 * vector->imm_values[2].imm_u32, - scalar->imm_values[0].imm_u32 * vector->imm_values[3].imm_u32); - case Type::F32x4: - return ImmValue(scalar->imm_values[0].imm_f32 * vector->imm_values[0].imm_f32, - scalar->imm_values[0].imm_f32 * vector->imm_values[1].imm_f32, - scalar->imm_values[0].imm_f32 * vector->imm_values[2].imm_f32, - scalar->imm_values[0].imm_f32 * vector->imm_values[3].imm_f32); - case Type::U64: - return is_signed && scalar->is_signed - ? ImmValue(scalar->imm_values[0].imm_s64 * vector->imm_values[0].imm_s64) - : ImmValue(scalar->imm_values[0].imm_u64 * vector->imm_values[0].imm_u64); - case Type::F64: - return ImmValue(scalar->imm_values[0].imm_f64 * vector->imm_values[0].imm_f64); - case Type::F64x2: - return ImmValue(scalar->imm_values[0].imm_f64 * vector->imm_values[0].imm_f64, - scalar->imm_values[0].imm_f64 * vector->imm_values[1].imm_f64); - case Type::F64x3: - return ImmValue(scalar->imm_values[0].imm_f64 * vector->imm_values[0].imm_f64, - scalar->imm_values[0].imm_f64 * vector->imm_values[1].imm_f64, - scalar->imm_values[0].imm_f64 * vector->imm_values[2].imm_f64); - case Type::F64x4: - return ImmValue(scalar->imm_values[0].imm_f64 * vector->imm_values[0].imm_f64, - scalar->imm_values[0].imm_f64 * vector->imm_values[1].imm_f64, - scalar->imm_values[0].imm_f64 * vector->imm_values[2].imm_f64, - scalar->imm_values[0].imm_f64 * vector->imm_values[3].imm_f64); - default: - UNREACHABLE_MSG("Invalid type {}", vector->type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_f32)); } -ImmValue ImmValue::operator/(const ImmValue& other) const { - ASSERT(BaseType() == other.BaseType() && other.Dimensions() == 1); - switch (type) { - case Type::U8: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s8 / other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 / other.imm_values[0].imm_u8); - case Type::U16: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s16 / other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 / other.imm_values[0].imm_u16); - case Type::U32: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 / other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 / other.imm_values[0].imm_u32); - case Type::F32: - return ImmValue(imm_values[0].imm_f32 / other.imm_values[0].imm_f32); - case Type::U32x2: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 / other.imm_values[0].imm_s32, - imm_values[1].imm_s32 / other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 / other.imm_values[0].imm_u32, - imm_values[1].imm_u32 / other.imm_values[0].imm_u32); - case Type::F32x2: - return ImmValue(imm_values[0].imm_f32 / other.imm_values[0].imm_f32, - imm_values[1].imm_f32 / other.imm_values[0].imm_f32); - case Type::U32x3: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 / other.imm_values[0].imm_s32, - imm_values[1].imm_s32 / other.imm_values[0].imm_s32, - imm_values[2].imm_s32 / other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 / other.imm_values[0].imm_u32, - imm_values[1].imm_u32 / other.imm_values[0].imm_u32, - imm_values[2].imm_u32 / other.imm_values[0].imm_u32); - case Type::F32x3: - return ImmValue(imm_values[0].imm_f32 / other.imm_values[0].imm_f32, - imm_values[1].imm_f32 / other.imm_values[0].imm_f32, - imm_values[2].imm_f32 / other.imm_values[0].imm_f32); - case Type::U32x4: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 / other.imm_values[0].imm_s32, - imm_values[1].imm_s32 / other.imm_values[0].imm_s32, - imm_values[2].imm_s32 / other.imm_values[0].imm_s32, - imm_values[3].imm_s32 / other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 / other.imm_values[0].imm_u32, - imm_values[1].imm_u32 / other.imm_values[0].imm_u32, - imm_values[2].imm_u32 / other.imm_values[0].imm_u32, - imm_values[3].imm_u32 / other.imm_values[0].imm_u32); - case Type::F32x4: - return ImmValue(imm_values[0].imm_f32 / other.imm_values[0].imm_f32, - imm_values[1].imm_f32 / other.imm_values[0].imm_f32, - imm_values[2].imm_f32 / other.imm_values[0].imm_f32, - imm_values[3].imm_f32 / other.imm_values[0].imm_f32); - case Type::U64: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s64 / other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 / other.imm_values[0].imm_u64); - case Type::F64: - return ImmValue(imm_values[0].imm_f64 / other.imm_values[0].imm_f64); - case Type::F64x2: - return ImmValue(imm_values[0].imm_f64 / other.imm_values[0].imm_f64, - imm_values[1].imm_f64 / other.imm_values[0].imm_f64); - case Type::F64x3: - return ImmValue(imm_values[0].imm_f64 / other.imm_values[0].imm_f64, - imm_values[1].imm_f64 / other.imm_values[0].imm_f64, - imm_values[2].imm_f64 / other.imm_values[0].imm_f64); - case Type::F64x4: - return ImmValue(imm_values[0].imm_f64 / other.imm_values[0].imm_f64, - imm_values[1].imm_f64 / other.imm_values[0].imm_f64, - imm_values[2].imm_f64 / other.imm_values[0].imm_f64, - imm_values[3].imm_f64 / other.imm_values[0].imm_f64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_u16)); } -ImmValue ImmValue::operator%(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U8: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s8 % other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 % other.imm_values[0].imm_u8); - case Type::U16: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s16 % other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 % other.imm_values[0].imm_u16); - case Type::U32: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 % other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 % other.imm_values[0].imm_u32); - case Type::U64: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s64 % other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 % other.imm_values[0].imm_u64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_u16)); } -ImmValue ImmValue::operator&(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U1: - return ImmValue(imm_values[0].imm_u1 & other.imm_values[0].imm_u1); - case Type::U8: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s8 & other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 & other.imm_values[0].imm_u8); - case Type::U16: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s16 & other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 & other.imm_values[0].imm_u16); - case Type::U32: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 & other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 & other.imm_values[0].imm_u32); - case Type::U64: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s64 & other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 & other.imm_values[0].imm_u64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_u32)); } -ImmValue ImmValue::operator|(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U1: - return ImmValue(imm_values[0].imm_u1 | other.imm_values[0].imm_u1); - case Type::U8: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s8 | other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 | other.imm_values[0].imm_u8); - case Type::U16: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s16 | other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 | other.imm_values[0].imm_u16); - case Type::U32: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 | other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 | other.imm_values[0].imm_u32); - case Type::U64: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s64 | other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 | other.imm_values[0].imm_u64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_u32)); } -ImmValue ImmValue::operator^(const ImmValue& other) const noexcept { - ASSERT(type == other.type); - switch (type) { - case Type::U1: - return ImmValue(imm_values[0].imm_u1 ^ other.imm_values[0].imm_u1); - case Type::U8: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s8 ^ other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 ^ other.imm_values[0].imm_u8); - case Type::U16: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s16 ^ other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 ^ other.imm_values[0].imm_u16); - case Type::U32: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s32 ^ other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 ^ other.imm_values[0].imm_u32); - case Type::U64: - return is_signed && other.is_signed - ? ImmValue(imm_values[0].imm_s64 ^ other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 ^ other.imm_values[0].imm_u64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_f64)); } -ImmValue ImmValue::operator<<(const ImmU32& other) const noexcept { - switch (type) { - case Type::U1: - return ImmValue(imm_values[0].imm_u1 << other.imm_values[0].imm_u1); - case Type::U8: - return is_signed ? ImmValue(imm_values[0].imm_s8 << other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 << other.imm_values[0].imm_u8); - case Type::U16: - return is_signed ? ImmValue(imm_values[0].imm_s16 << other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 << other.imm_values[0].imm_u16); - case Type::U32: - return is_signed ? ImmValue(imm_values[0].imm_s32 << other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 << other.imm_values[0].imm_u32); - case Type::U64: - return is_signed ? ImmValue(imm_values[0].imm_s64 << other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 << other.imm_values[0].imm_u64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_u32)); } -ImmValue ImmValue::operator>>(const ImmU32& other) const noexcept { - switch (type) { - case Type::U1: - return ImmValue(imm_values[0].imm_u1 >> other.imm_values[0].imm_u1); - case Type::U8: - return is_signed ? ImmValue(imm_values[0].imm_s8 >> other.imm_values[0].imm_s8) - : ImmValue(imm_values[0].imm_u8 >> other.imm_values[0].imm_u8); - case Type::U16: - return is_signed ? ImmValue(imm_values[0].imm_s16 >> other.imm_values[0].imm_s16) - : ImmValue(imm_values[0].imm_u16 >> other.imm_values[0].imm_u16); - case Type::U32: - return is_signed ? ImmValue(imm_values[0].imm_s32 >> other.imm_values[0].imm_s32) - : ImmValue(imm_values[0].imm_u32 >> other.imm_values[0].imm_u32); - case Type::U64: - return is_signed ? ImmValue(imm_values[0].imm_s64 >> other.imm_values[0].imm_s64) - : ImmValue(imm_values[0].imm_u64 >> other.imm_values[0].imm_u64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_s32)); } -ImmValue ImmValue::operator~() const noexcept { - switch (type) { - case Type::U1: - return ImmValue(~imm_values[0].imm_u1); - case Type::U8: - return is_signed ? ImmValue(imm_values[0].imm_s8) : ImmValue(imm_values[0].imm_u8); - case Type::U16: - return is_signed ? ImmValue(imm_values[0].imm_s16) : ImmValue(imm_values[0].imm_u16); - case Type::U32: - return is_signed ? ImmValue(imm_values[0].imm_s32) : ImmValue(imm_values[0].imm_u32); - case Type::U64: - return is_signed ? ImmValue(imm_values[0].imm_s64) : ImmValue(imm_values[0].imm_u64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Convert(const ImmValue& in) noexcept { + return ImmValue(static_cast(in.imm_values[0].imm_f32)); } -ImmValue ImmValue::operator++(int) noexcept { - switch (type) { - case Type::U8: - return is_signed ? ImmValue(imm_values[0].imm_s8++) : ImmValue(imm_values[0].imm_u8++); - case Type::U16: - return is_signed ? ImmValue(imm_values[0].imm_s16++) : ImmValue(imm_values[0].imm_u16++); - case Type::U32: - return is_signed ? ImmValue(imm_values[0].imm_s32++) : ImmValue(imm_values[0].imm_u32++); - case Type::U64: - return is_signed ? ImmValue(imm_values[0].imm_s64++) : ImmValue(imm_values[0].imm_u64++); - case Type::F32: - return ImmValue(imm_values[0].imm_f32++); - case Type::F64: - return ImmValue(imm_values[0].imm_f64++); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 + b.imm_values[0].imm_u8, + a.imm_values[1].imm_u8 + b.imm_values[1].imm_u8, + a.imm_values[2].imm_u8 + b.imm_values[2].imm_u8, + a.imm_values[3].imm_u8 + b.imm_values[3].imm_u8); } -ImmValue ImmValue::operator--(int) noexcept { - switch (type) { - case Type::U8: - return is_signed ? ImmValue(imm_values[0].imm_s8--) : ImmValue(imm_values[0].imm_u8--); - case Type::U16: - return is_signed ? ImmValue(imm_values[0].imm_s16--) : ImmValue(imm_values[0].imm_u16--); - case Type::U32: - return is_signed ? ImmValue(imm_values[0].imm_s32--) : ImmValue(imm_values[0].imm_u32--); - case Type::U64: - return is_signed ? ImmValue(imm_values[0].imm_s64--) : ImmValue(imm_values[0].imm_u64--); - case Type::F32: - return ImmValue(imm_values[0].imm_f32--); - case Type::F64: - return ImmValue(imm_values[0].imm_f64--); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s8 + b.imm_values[0].imm_s8, + a.imm_values[1].imm_s8 + b.imm_values[1].imm_s8, + a.imm_values[2].imm_s8 + b.imm_values[2].imm_s8, + a.imm_values[3].imm_s8 + b.imm_values[3].imm_s8); } -ImmValue& ImmValue::operator++() noexcept { - switch (type) { - case Type::U8: - if (is_signed) { - imm_values[0].imm_s8++; - } else { - imm_values[0].imm_u8++; - } - break; - case Type::U16: - if (is_signed) { - imm_values[0].imm_s16++; - } else { - imm_values[0].imm_u16++; - } - break; - case Type::U32: - if (is_signed) { - imm_values[0].imm_s32++; - } else { - imm_values[0].imm_u32++; - } - break; - case Type::U64: - if (is_signed) { - imm_values[0].imm_s64++; - } else { - imm_values[0].imm_u64++; - } - break; - case Type::F32: - imm_values[0].imm_f32++; - break; - case Type::F64: - imm_values[0].imm_f64++; - break; - default: - UNREACHABLE_MSG("Invalid type {}", type); - } - return *this; +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 + b.imm_values[0].imm_u16, + a.imm_values[1].imm_u16 + b.imm_values[1].imm_u16, + a.imm_values[2].imm_u16 + b.imm_values[2].imm_u16, + a.imm_values[3].imm_u16 + b.imm_values[3].imm_u16); } -ImmValue& ImmValue::operator--() noexcept { - switch (type) { - case Type::U8: - if (is_signed) { - imm_values[0].imm_s8--; - } else { - imm_values[0].imm_u8--; - } - break; - case Type::U16: - if (is_signed) { - imm_values[0].imm_s16--; - } else { - imm_values[0].imm_u16--; - } - break; - case Type::U32: - if (is_signed) { - imm_values[0].imm_s32--; - } else { - imm_values[0].imm_u32--; - } - break; - case Type::U64: - if (is_signed) { - imm_values[0].imm_s64--; - } else { - imm_values[0].imm_u64--; - } - break; - case Type::F32: - imm_values[0].imm_f32--; - break; - case Type::F64: - imm_values[0].imm_f64--; - break; - default: - UNREACHABLE_MSG("Invalid type {}", type); - } - return *this; +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s16 + b.imm_values[0].imm_s16, + a.imm_values[1].imm_s16 + b.imm_values[1].imm_s16, + a.imm_values[2].imm_s16 + b.imm_values[2].imm_s16, + a.imm_values[3].imm_s16 + b.imm_values[3].imm_s16); } -ImmValue ImmValue::operator-() const noexcept { - switch (type) { - case Type::U8: - return is_signed ? ImmValue(-imm_values[0].imm_s8) : ImmValue(-imm_values[0].imm_u8); - case Type::U16: - return is_signed ? ImmValue(-imm_values[0].imm_s16) : ImmValue(-imm_values[0].imm_u16); - case Type::U32: - return is_signed ? ImmValue(-imm_values[0].imm_s32) : ImmValue(-imm_values[0].imm_u32); - case Type::U32x2: - return is_signed ? ImmValue(-imm_values[0].imm_s32, -imm_values[1].imm_s32) - : ImmValue(-imm_values[0].imm_u32, -imm_values[1].imm_u32); - case Type::U32x3: - return is_signed ? ImmValue(-imm_values[0].imm_s32, -imm_values[1].imm_s32, - -imm_values[2].imm_s32) - : ImmValue(-imm_values[0].imm_u32, -imm_values[1].imm_u32, - -imm_values[2].imm_u32); - case Type::U32x4: - return is_signed ? ImmValue(-imm_values[0].imm_s32, -imm_values[1].imm_s32, - -imm_values[2].imm_s32, -imm_values[3].imm_s32) - : ImmValue(-imm_values[0].imm_u32, -imm_values[1].imm_u32, - -imm_values[2].imm_u32, -imm_values[3].imm_u32); - case Type::U64: - return is_signed ? ImmValue(-imm_values[0].imm_s64) : ImmValue(-imm_values[0].imm_u64); - case Type::F32: - return ImmValue(-imm_values[0].imm_f32); - case Type::F32x2: - return ImmValue(-imm_values[0].imm_f32, -imm_values[1].imm_f32); - case Type::F32x3: - return ImmValue(-imm_values[0].imm_f32, -imm_values[1].imm_f32, -imm_values[2].imm_f32); - case Type::F32x4: - return ImmValue(-imm_values[0].imm_f32, -imm_values[1].imm_f32, -imm_values[2].imm_f32, - -imm_values[3].imm_f32); - case Type::F64: - return ImmValue(-imm_values[0].imm_f64); - case Type::F64x2: - return ImmValue(-imm_values[0].imm_f64, -imm_values[1].imm_f64); - case Type::F64x3: - return ImmValue(-imm_values[0].imm_f64, -imm_values[1].imm_f64, -imm_values[2].imm_f64); - case Type::F64x4: - return ImmValue(-imm_values[0].imm_f64, -imm_values[1].imm_f64, -imm_values[2].imm_f64, - -imm_values[3].imm_f64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 + b.imm_values[0].imm_u32, + a.imm_values[1].imm_u32 + b.imm_values[1].imm_u32, + a.imm_values[2].imm_u32 + b.imm_values[2].imm_u32, + a.imm_values[3].imm_u32 + b.imm_values[3].imm_u32); } -ImmValue ImmValue::operator+() const noexcept { - return *this; +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s32 + b.imm_values[0].imm_s32, + a.imm_values[1].imm_s32 + b.imm_values[1].imm_s32, + a.imm_values[2].imm_s32 + b.imm_values[2].imm_s32, + a.imm_values[3].imm_s32 + b.imm_values[3].imm_s32); } -// this is not the best way - -ImmValue& ImmValue::operator+=(const ImmValue& other) noexcept { - ImmValue result = *this + other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_f32 + b.imm_values[0].imm_f32, + a.imm_values[1].imm_f32 + b.imm_values[1].imm_f32, + a.imm_values[2].imm_f32 + b.imm_values[2].imm_f32, + a.imm_values[3].imm_f32 + b.imm_values[3].imm_f32); } -ImmValue& ImmValue::operator-=(const ImmValue& other) noexcept { - ImmValue result = *this - other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 + b.imm_values[0].imm_u64, + a.imm_values[1].imm_u64 + b.imm_values[1].imm_u64, + a.imm_values[2].imm_u64 + b.imm_values[2].imm_u64, + a.imm_values[3].imm_u64 + b.imm_values[3].imm_u64); } -ImmValue& ImmValue::operator*=(const ImmValue& other) noexcept { - ImmValue result = *this * other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s64 + b.imm_values[0].imm_s64, + a.imm_values[1].imm_s64 + b.imm_values[1].imm_s64, + a.imm_values[2].imm_s64 + b.imm_values[2].imm_s64, + a.imm_values[3].imm_s64 + b.imm_values[3].imm_s64); } -ImmValue& ImmValue::operator/=(const ImmValue& other) { - ImmValue result = *this / other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Add(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_f64 + b.imm_values[0].imm_f64, + a.imm_values[1].imm_f64 + b.imm_values[1].imm_f64, + a.imm_values[2].imm_f64 + b.imm_values[2].imm_f64, + a.imm_values[3].imm_f64 + b.imm_values[3].imm_f64); } -ImmValue& ImmValue::operator%=(const ImmValue& other) noexcept { - ImmValue result = *this % other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 - b.imm_values[0].imm_u8, + a.imm_values[1].imm_u8 - b.imm_values[1].imm_u8, + a.imm_values[2].imm_u8 - b.imm_values[2].imm_u8, + a.imm_values[3].imm_u8 - b.imm_values[3].imm_u8); } -ImmValue& ImmValue::operator&=(const ImmValue& other) noexcept { - ImmValue result = *this & other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s8 - b.imm_values[0].imm_s8, + a.imm_values[1].imm_s8 - b.imm_values[1].imm_s8, + a.imm_values[2].imm_s8 - b.imm_values[2].imm_s8, + a.imm_values[3].imm_s8 - b.imm_values[3].imm_s8); } -ImmValue& ImmValue::operator|=(const ImmValue& other) noexcept { - ImmValue result = *this | other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 - b.imm_values[0].imm_u16, + a.imm_values[1].imm_u16 - b.imm_values[1].imm_u16, + a.imm_values[2].imm_u16 - b.imm_values[2].imm_u16, + a.imm_values[3].imm_u16 - b.imm_values[3].imm_u16); } -ImmValue& ImmValue::operator^=(const ImmValue& other) noexcept { - ImmValue result = *this ^ other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s16 - b.imm_values[0].imm_s16, + a.imm_values[1].imm_s16 - b.imm_values[1].imm_s16, + a.imm_values[2].imm_s16 - b.imm_values[2].imm_s16, + a.imm_values[3].imm_s16 - b.imm_values[3].imm_s16); } -ImmValue& ImmValue::operator<<=(const ImmU32& other) noexcept { - ImmValue result = *this << other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 - b.imm_values[0].imm_u32, + a.imm_values[1].imm_u32 - b.imm_values[1].imm_u32, + a.imm_values[2].imm_u32 - b.imm_values[2].imm_u32, + a.imm_values[3].imm_u32 - b.imm_values[3].imm_u32); } -ImmValue& ImmValue::operator>>=(const ImmU32& other) noexcept { - ImmValue result = *this >> other; - *this = result; - return *this; +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s32 - b.imm_values[0].imm_s32, + a.imm_values[1].imm_s32 - b.imm_values[1].imm_s32, + a.imm_values[2].imm_s32 - b.imm_values[2].imm_s32, + a.imm_values[3].imm_s32 - b.imm_values[3].imm_s32); } -ImmValue ImmValue::abs() const noexcept { - switch (type) { - case Type::U8: - return is_signed ? ImmValue(std::abs(imm_values[0].imm_s8)) - : ImmValue(imm_values[0].imm_u8); - case Type::U16: - return is_signed ? ImmValue(std::abs(imm_values[0].imm_s16)) - : ImmValue(imm_values[0].imm_u16); - case Type::U32: - return is_signed ? ImmValue(std::abs(imm_values[0].imm_s32)) - : ImmValue(imm_values[0].imm_u32); - case Type::U64: - return is_signed ? ImmValue(std::abs(imm_values[0].imm_s64)) - : ImmValue(imm_values[0].imm_u64); - case Type::F32: - return ImmValue(std::abs(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::abs(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_f32 - b.imm_values[0].imm_f32, + a.imm_values[1].imm_f32 - b.imm_values[1].imm_f32, + a.imm_values[2].imm_f32 - b.imm_values[2].imm_f32, + a.imm_values[3].imm_f32 - b.imm_values[3].imm_f32); } -ImmValue ImmValue::recip() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(1.0f / imm_values[0].imm_f32); - case Type::F64: - return ImmValue(1.0 / imm_values[0].imm_f64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 - b.imm_values[0].imm_u64, + a.imm_values[1].imm_u64 - b.imm_values[1].imm_u64, + a.imm_values[2].imm_u64 - b.imm_values[2].imm_u64, + a.imm_values[3].imm_u64 - b.imm_values[3].imm_u64); } -ImmValue ImmValue::sqrt() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::sqrt(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::sqrt(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s64 - b.imm_values[0].imm_s64, + a.imm_values[1].imm_s64 - b.imm_values[1].imm_s64, + a.imm_values[2].imm_s64 - b.imm_values[2].imm_s64, + a.imm_values[3].imm_s64 - b.imm_values[3].imm_s64); } -ImmValue ImmValue::rsqrt() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(1.0f / std::sqrt(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(1.0 / std::sqrt(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Sub(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_f64 - b.imm_values[0].imm_f64, + a.imm_values[1].imm_f64 - b.imm_values[1].imm_f64, + a.imm_values[2].imm_f64 - b.imm_values[2].imm_f64, + a.imm_values[3].imm_f64 - b.imm_values[3].imm_f64); } -ImmValue ImmValue::sin() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::sin(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::sin(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 * b.imm_values[0].imm_u8, + a.imm_values[1].imm_u8 * b.imm_values[0].imm_u8, + a.imm_values[2].imm_u8 * b.imm_values[0].imm_u8, + a.imm_values[3].imm_u8 * b.imm_values[0].imm_u8); } -ImmValue ImmValue::cos() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::cos(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::cos(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s8 * b.imm_values[0].imm_s8, + a.imm_values[1].imm_s8 * b.imm_values[0].imm_s8, + a.imm_values[2].imm_s8 * b.imm_values[0].imm_s8, + a.imm_values[3].imm_s8 * b.imm_values[0].imm_s8); } -ImmValue ImmValue::exp2() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::exp2(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::exp2(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 * b.imm_values[0].imm_u16, + a.imm_values[1].imm_u16 * b.imm_values[0].imm_u16, + a.imm_values[2].imm_u16 * b.imm_values[0].imm_u16, + a.imm_values[3].imm_u16 * b.imm_values[0].imm_u16); } -ImmValue ImmValue::ldexp(const ImmU32& exp) const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::ldexp(imm_values[0].imm_f32, exp.imm_values[0].imm_s32)); - case Type::F64: - return ImmValue(std::ldexp(imm_values[0].imm_f64, exp.imm_values[0].imm_s32)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s16 * b.imm_values[0].imm_s16, + a.imm_values[1].imm_s16 * b.imm_values[0].imm_s16, + a.imm_values[2].imm_s16 * b.imm_values[0].imm_s16, + a.imm_values[3].imm_s16 * b.imm_values[0].imm_s16); } -ImmValue ImmValue::log2() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::log2(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::log2(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 * b.imm_values[0].imm_u32, + a.imm_values[1].imm_u32 * b.imm_values[0].imm_u32, + a.imm_values[2].imm_u32 * b.imm_values[0].imm_u32, + a.imm_values[3].imm_u32 * b.imm_values[0].imm_u32); } -ImmValue ImmValue::clamp(const ImmValue& min, const ImmValue& max) const noexcept { - ASSERT(type == min.type && min.type == max.type); - switch (type) { - case Type::U8: - return is_signed && min.is_signed && max.is_signed - ? ImmValue(std::clamp(imm_values[0].imm_s8, min.imm_values[0].imm_s8, - max.imm_values[0].imm_s8)) - : ImmValue(std::clamp(imm_values[0].imm_u8, min.imm_values[0].imm_u8, - max.imm_values[0].imm_u8)); - case Type::U16: - return is_signed && min.is_signed && max.is_signed - ? ImmValue(std::clamp(imm_values[0].imm_s16, min.imm_values[0].imm_s16, - max.imm_values[0].imm_s16)) - : ImmValue(std::clamp(imm_values[0].imm_u16, min.imm_values[0].imm_u16, - max.imm_values[0].imm_u16)); - case Type::U32: - return is_signed && min.is_signed && max.is_signed - ? ImmValue(std::clamp(imm_values[0].imm_s32, min.imm_values[0].imm_s32, - max.imm_values[0].imm_s32)) - : ImmValue(std::clamp(imm_values[0].imm_u32, min.imm_values[0].imm_u32, - max.imm_values[0].imm_u32)); - case Type::U64: - return is_signed && min.is_signed && max.is_signed - ? ImmValue(std::clamp(imm_values[0].imm_s64, min.imm_values[0].imm_s64, - max.imm_values[0].imm_s64)) - : ImmValue(std::clamp(imm_values[0].imm_u64, min.imm_values[0].imm_u64, - max.imm_values[0].imm_u64)); - case Type::F32: - return ImmValue(std::clamp(imm_values[0].imm_f32, min.imm_values[0].imm_f32, - max.imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::clamp(imm_values[0].imm_f64, min.imm_values[0].imm_f64, - max.imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s32 * b.imm_values[0].imm_s32, + a.imm_values[1].imm_s32 * b.imm_values[0].imm_s32, + a.imm_values[2].imm_s32 * b.imm_values[0].imm_s32, + a.imm_values[3].imm_s32 * b.imm_values[0].imm_s32); } -ImmValue ImmValue::floor() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::floor(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::floor(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_f32 * b.imm_values[0].imm_f32, + a.imm_values[1].imm_f32 * b.imm_values[0].imm_f32, + a.imm_values[2].imm_f32 * b.imm_values[0].imm_f32, + a.imm_values[3].imm_f32 * b.imm_values[0].imm_f32); } -ImmValue ImmValue::ceil() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::ceil(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::ceil(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 * b.imm_values[0].imm_u64, + a.imm_values[1].imm_u64 * b.imm_values[0].imm_u64, + a.imm_values[2].imm_u64 * b.imm_values[0].imm_u64, + a.imm_values[3].imm_u64 * b.imm_values[0].imm_u64); } -ImmValue ImmValue::round() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::round(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::round(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s64 * b.imm_values[0].imm_s64, + a.imm_values[1].imm_s64 * b.imm_values[0].imm_s64, + a.imm_values[2].imm_s64 * b.imm_values[0].imm_s64, + a.imm_values[3].imm_s64 * b.imm_values[0].imm_s64); } -ImmValue ImmValue::trunc() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(std::trunc(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(std::trunc(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Mul(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_f64 * b.imm_values[0].imm_f64, + a.imm_values[1].imm_f64 * b.imm_values[0].imm_f64, + a.imm_values[2].imm_f64 * b.imm_values[0].imm_f64, + a.imm_values[3].imm_f64 * b.imm_values[0].imm_f64); } -ImmValue ImmValue::fract() const noexcept { - switch (type) { - case Type::F32: - return ImmValue(imm_values[0].imm_f32 - std::floor(imm_values[0].imm_f32)); - case Type::F64: - return ImmValue(imm_values[0].imm_f64 - std::floor(imm_values[0].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_u8 / b.imm_values[0].imm_u8, + a.imm_values[1].imm_u8 / b.imm_values[0].imm_u8, + a.imm_values[2].imm_u8 / b.imm_values[0].imm_u8, + a.imm_values[3].imm_u8 / b.imm_values[0].imm_u8); } -bool ImmValue::isnan() const noexcept { - switch (type) { - case Type::F32: - return std::isnan(imm_values[0].imm_f32); - case Type::F64: - return std::isnan(imm_values[0].imm_f64); - case Type::F32x2: - return std::isnan(imm_values[0].imm_f32) || std::isnan(imm_values[1].imm_f32); - case Type::F64x2: - return std::isnan(imm_values[0].imm_f64) || std::isnan(imm_values[1].imm_f64); - case Type::F32x3: - return std::isnan(imm_values[0].imm_f32) || std::isnan(imm_values[1].imm_f32) || - std::isnan(imm_values[2].imm_f32); - case Type::F64x3: - return std::isnan(imm_values[0].imm_f64) || std::isnan(imm_values[1].imm_f64) || - std::isnan(imm_values[2].imm_f64); - case Type::F32x4: - return std::isnan(imm_values[0].imm_f32) || std::isnan(imm_values[1].imm_f32) || - std::isnan(imm_values[2].imm_f32) || std::isnan(imm_values[3].imm_f32); - case Type::F64x4: - return std::isnan(imm_values[0].imm_f64) || std::isnan(imm_values[1].imm_f64) || - std::isnan(imm_values[2].imm_f64) || std::isnan(imm_values[3].imm_f64); - default: - UNREACHABLE_MSG("Invalid type {}", type); - } +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_s8 / b.imm_values[0].imm_s8, + a.imm_values[1].imm_s8 / b.imm_values[0].imm_s8, + a.imm_values[2].imm_s8 / b.imm_values[0].imm_s8, + a.imm_values[3].imm_s8 / b.imm_values[0].imm_s8); } -ImmValue ImmValue::fma(const ImmF32F64& a, const ImmF32F64& b, const ImmF32F64& c) noexcept { - ASSERT(a.type == b.type && b.type == c.type); - switch (a.type) { - case Type::F32: - return ImmValue( - std::fma(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32, c.imm_values[0].imm_f32)); - case Type::F64: - return ImmValue( - std::fma(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64, c.imm_values[0].imm_f64)); - case Type::F32x2: - return ImmValue( - std::fma(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32, c.imm_values[0].imm_f32), - std::fma(a.imm_values[1].imm_f32, b.imm_values[1].imm_f32, c.imm_values[1].imm_f32)); - case Type::F64x2: - return ImmValue( - std::fma(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64, c.imm_values[0].imm_f64), - std::fma(a.imm_values[1].imm_f64, b.imm_values[1].imm_f64, c.imm_values[1].imm_f64)); - case Type::F32x3: - return ImmValue( - std::fma(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32, c.imm_values[0].imm_f32), - std::fma(a.imm_values[1].imm_f32, b.imm_values[1].imm_f32, c.imm_values[1].imm_f32), - std::fma(a.imm_values[2].imm_f32, b.imm_values[2].imm_f32, c.imm_values[2].imm_f32)); - case Type::F64x3: - return ImmValue( - std::fma(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64, c.imm_values[0].imm_f64), - std::fma(a.imm_values[1].imm_f64, b.imm_values[1].imm_f64, c.imm_values[1].imm_f64), - std::fma(a.imm_values[2].imm_f64, b.imm_values[2].imm_f64, c.imm_values[2].imm_f64)); - case Type::F32x4: - return ImmValue( - std::fma(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32, c.imm_values[0].imm_f32), - std::fma(a.imm_values[1].imm_f32, b.imm_values[1].imm_f32, c.imm_values[1].imm_f32), - std::fma(a.imm_values[2].imm_f32, b.imm_values[2].imm_f32, c.imm_values[2].imm_f32), - std::fma(a.imm_values[3].imm_f32, b.imm_values[3].imm_f32, c.imm_values[3].imm_f32)); - case Type::F64x4: - return ImmValue( - std::fma(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64, c.imm_values[0].imm_f64), - std::fma(a.imm_values[1].imm_f64, b.imm_values[1].imm_f64, c.imm_values[1].imm_f64), - std::fma(a.imm_values[2].imm_f64, b.imm_values[2].imm_f64, c.imm_values[2].imm_f64), - std::fma(a.imm_values[3].imm_f64, b.imm_values[3].imm_f64, c.imm_values[3].imm_f64)); - default: - UNREACHABLE_MSG("Invalid type {}", a.type); - } +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_u16 / b.imm_values[0].imm_u16, + a.imm_values[1].imm_u16 / b.imm_values[0].imm_u16, + a.imm_values[2].imm_u16 / b.imm_values[0].imm_u16, + a.imm_values[3].imm_u16 / b.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_s16 / b.imm_values[0].imm_s16, + a.imm_values[1].imm_s16 / b.imm_values[0].imm_s16, + a.imm_values[2].imm_s16 / b.imm_values[0].imm_s16, + a.imm_values[3].imm_s16 / b.imm_values[0].imm_s16); +} + +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_u32 / b.imm_values[0].imm_u32, + a.imm_values[1].imm_u32 / b.imm_values[0].imm_u32, + a.imm_values[2].imm_u32 / b.imm_values[0].imm_u32, + a.imm_values[3].imm_u32 / b.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_s32 / b.imm_values[0].imm_s32, + a.imm_values[1].imm_s32 / b.imm_values[0].imm_s32, + a.imm_values[2].imm_s32 / b.imm_values[0].imm_s32, + a.imm_values[3].imm_s32 / b.imm_values[0].imm_s32); +} + +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_f32 / b.imm_values[0].imm_f32, + a.imm_values[1].imm_f32 / b.imm_values[0].imm_f32, + a.imm_values[2].imm_f32 / b.imm_values[0].imm_f32, + a.imm_values[3].imm_f32 / b.imm_values[0].imm_f32); +} + +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_u64 / b.imm_values[0].imm_u64, + a.imm_values[1].imm_u64 / b.imm_values[0].imm_u64, + a.imm_values[2].imm_u64 / b.imm_values[0].imm_u64, + a.imm_values[3].imm_u64 / b.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_s64 / b.imm_values[0].imm_s64, + a.imm_values[1].imm_s64 / b.imm_values[0].imm_s64, + a.imm_values[2].imm_s64 / b.imm_values[0].imm_s64, + a.imm_values[3].imm_s64 / b.imm_values[0].imm_s64); +} + +template <> +ImmValue ImmValue::Div(const ImmValue& a, const ImmValue& b) { + return ImmValue(a.imm_values[0].imm_f64 / b.imm_values[0].imm_f64, + a.imm_values[1].imm_f64 / b.imm_values[0].imm_f64, + a.imm_values[2].imm_f64 / b.imm_values[0].imm_f64, + a.imm_values[3].imm_f64 / b.imm_values[0].imm_f64); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 % b.imm_values[0].imm_u8); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s8 % b.imm_values[0].imm_s8); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 % b.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s16 % b.imm_values[0].imm_s16); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 % b.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s32 % b.imm_values[0].imm_s32); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 % b.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::Mod(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s64 % b.imm_values[0].imm_s64); +} + +template <> +ImmValue ImmValue::And(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u1 & b.imm_values[0].imm_u1); +} + +template <> +ImmValue ImmValue::And(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 & b.imm_values[0].imm_u8); +} + +template <> +ImmValue ImmValue::And(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 & b.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::And(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 & b.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::And(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 & b.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::Or(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u1 | b.imm_values[0].imm_u1); +} + +template <> +ImmValue ImmValue::Or(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 | b.imm_values[0].imm_u8); +} + +template <> +ImmValue ImmValue::Or(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 | b.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::Or(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 | b.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::Or(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 | b.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::Xor(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u1 ^ b.imm_values[0].imm_u1); +} + +template <> +ImmValue ImmValue::Xor(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 ^ b.imm_values[0].imm_u8); +} + +template <> +ImmValue ImmValue::Xor(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 ^ b.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::Xor(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 ^ b.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::Xor(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 ^ b.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::LShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 << b.imm_values[0].imm_u8); +} + +template <> +ImmValue ImmValue::LShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 << b.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::LShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 << b.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::LShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 << b.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u8 >> b.imm_values[0].imm_u8); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s8 >> b.imm_values[0].imm_s8); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u16 >> b.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s16 >> b.imm_values[0].imm_s16); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u32 >> b.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s32 >> b.imm_values[0].imm_s32); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_u64 >> b.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::RShift(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(a.imm_values[0].imm_s64 >> b.imm_values[0].imm_s64); +} + +template <> +ImmValue ImmValue::Not(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_u1); +} + +template <> +ImmValue ImmValue::Not(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_u8); +} + +template <> +ImmValue ImmValue::Not(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_u16); +} + +template <> +ImmValue ImmValue::Not(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_u32); +} + +template <> +ImmValue ImmValue::Not(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_u64); +} + +template <> +ImmValue ImmValue::Neg(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_s8, -in.imm_values[1].imm_s8, -in.imm_values[2].imm_s8, + -in.imm_values[3].imm_s8); +} + +template <> +ImmValue ImmValue::Neg(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_s16, -in.imm_values[1].imm_s16, -in.imm_values[2].imm_s16, + -in.imm_values[3].imm_s16); +} + +template <> +ImmValue ImmValue::Neg(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_s32, -in.imm_values[1].imm_s32, -in.imm_values[2].imm_s32, + -in.imm_values[3].imm_s32); +} + +template <> +ImmValue ImmValue::Neg(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_f32, -in.imm_values[1].imm_f32, -in.imm_values[2].imm_f32, + -in.imm_values[3].imm_f32); +} + +template <> +ImmValue ImmValue::Neg(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_s64, -in.imm_values[1].imm_s64, -in.imm_values[2].imm_s64, + -in.imm_values[3].imm_s64); +} + +template <> +ImmValue ImmValue::Neg(const ImmValue& in) noexcept { + return ImmValue(-in.imm_values[0].imm_f64, -in.imm_values[1].imm_f64, -in.imm_values[2].imm_f64, + -in.imm_values[3].imm_f64); +} + +template <> +ImmValue ImmValue::Abs(const ImmValue& in) noexcept { + return ImmValue(std::abs(in.imm_values[0].imm_s8)); +} + +template <> +ImmValue ImmValue::Abs(const ImmValue& in) noexcept { + return ImmValue(std::abs(in.imm_values[0].imm_s16)); +} + +template <> +ImmValue ImmValue::Abs(const ImmValue& in) noexcept { + return ImmValue(std::abs(in.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::Abs(const ImmValue& in) noexcept { + return ImmValue(std::abs(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Abs(const ImmValue& in) noexcept { + return ImmValue(std::abs(in.imm_values[0].imm_s64)); +} + +template <> +ImmValue ImmValue::Abs(const ImmValue& in) noexcept { + return ImmValue(std::abs(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Recip(const ImmValue& in) noexcept { + return ImmValue(1.0f / in.imm_values[0].imm_f32); +} + +template <> +ImmValue ImmValue::Recip(const ImmValue& in) noexcept { + return ImmValue(1.0 / in.imm_values[0].imm_f64); +} + +template <> +ImmValue ImmValue::Sqrt(const ImmValue& in) noexcept { + return ImmValue(std::sqrt(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Sqrt(const ImmValue& in) noexcept { + return ImmValue(std::sqrt(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Rsqrt(const ImmValue& in) noexcept { + return ImmValue(1.0f / std::sqrt(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Rsqrt(const ImmValue& in) noexcept { + return ImmValue(1.0 / std::sqrt(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Sin(const ImmValue& in) noexcept { + return ImmValue(std::sin(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Sin(const ImmValue& in) noexcept { + return ImmValue(std::sin(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Cos(const ImmValue& in) noexcept { + return ImmValue(std::cos(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Cos(const ImmValue& in) noexcept { + return ImmValue(std::cos(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Exp2(const ImmValue& in) noexcept { + return ImmValue(std::exp2(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Exp2(const ImmValue& in) noexcept { + return ImmValue(std::exp2(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Ldexp(const ImmValue& in, const ImmValue& exp) noexcept { + return ImmValue(std::ldexp(in.imm_values[0].imm_f32, exp.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::Ldexp(const ImmValue& in, const ImmValue& exp) noexcept { + return ImmValue(std::ldexp(in.imm_values[0].imm_f64, exp.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::Log2(const ImmValue& in) noexcept { + return ImmValue(std::log2(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Log2(const ImmValue& in) noexcept { + return ImmValue(std::log2(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_u8, b.imm_values[0].imm_u8)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_s8, b.imm_values[0].imm_s8)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_u16, b.imm_values[0].imm_u16)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_s16, b.imm_values[0].imm_s16)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_u32, b.imm_values[0].imm_u32)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_s32, b.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_u64, b.imm_values[0].imm_u64)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_s64, b.imm_values[0].imm_s64)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Min(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::min(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_u8, b.imm_values[0].imm_u8)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_s8, b.imm_values[0].imm_s8)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_u16, b.imm_values[0].imm_u16)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_s16, b.imm_values[0].imm_s16)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_u32, b.imm_values[0].imm_u32)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_s32, b.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_u64, b.imm_values[0].imm_u64)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_s64, b.imm_values[0].imm_s64)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) noexcept { + return ImmValue(std::max(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_u8, min.imm_values[0].imm_u8, max.imm_values[0].imm_u8)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_s8, min.imm_values[0].imm_s8, max.imm_values[0].imm_s8)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_u16, min.imm_values[0].imm_u16, max.imm_values[0].imm_u16)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_s16, min.imm_values[0].imm_s16, max.imm_values[0].imm_s16)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_u32, min.imm_values[0].imm_u32, max.imm_values[0].imm_u32)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_s32, min.imm_values[0].imm_s32, max.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_u64, min.imm_values[0].imm_u64, max.imm_values[0].imm_u64)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_s64, min.imm_values[0].imm_s64, max.imm_values[0].imm_s64)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_f32, min.imm_values[0].imm_f32, max.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept { + return ImmValue( + std::clamp(in.imm_values[0].imm_f64, min.imm_values[0].imm_f64, max.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Floor(const ImmValue& in) noexcept { + return ImmValue(std::floor(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Floor(const ImmValue& in) noexcept { + return ImmValue(std::floor(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Ceil(const ImmValue& in) noexcept { + return ImmValue(std::ceil(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Ceil(const ImmValue& in) noexcept { + return ImmValue(std::ceil(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Round(const ImmValue& in) noexcept { + return ImmValue(std::round(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Round(const ImmValue& in) noexcept { + return ImmValue(std::round(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Trunc(const ImmValue& in) noexcept { + return ImmValue(std::trunc(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Trunc(const ImmValue& in) noexcept { + return ImmValue(std::trunc(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Fract(const ImmValue& in) noexcept { + return ImmValue(in.imm_values[0].imm_f32 - std::floor(in.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::Fract(const ImmValue& in) noexcept { + return ImmValue(in.imm_values[0].imm_f64 - std::floor(in.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::Fma(const ImmValue& a, const ImmValue& b, + const ImmValue& c) noexcept { + return ImmValue( + std::fma(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32, c.imm_values[0].imm_f32), + std::fma(a.imm_values[1].imm_f32, b.imm_values[1].imm_f32, c.imm_values[1].imm_f32), + std::fma(a.imm_values[2].imm_f32, b.imm_values[2].imm_f32, c.imm_values[2].imm_f32), + std::fma(a.imm_values[3].imm_f32, b.imm_values[3].imm_f32, c.imm_values[3].imm_f32)); +} + +template <> +ImmValue ImmValue::Fma(const ImmValue& a, const ImmValue& b, + const ImmValue& c) noexcept { + return ImmValue( + std::fma(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64, c.imm_values[0].imm_f64), + std::fma(a.imm_values[1].imm_f64, b.imm_values[1].imm_f64, c.imm_values[1].imm_f64), + std::fma(a.imm_values[2].imm_f64, b.imm_values[2].imm_f64, c.imm_values[2].imm_f64), + std::fma(a.imm_values[3].imm_f64, b.imm_values[3].imm_f64, c.imm_values[3].imm_f64)); +} + +template <> +bool ImmValue::IsNan(const ImmValue& in) noexcept { + return std::isnan(in.imm_values[0].imm_f32) || std::isnan(in.imm_values[1].imm_f32) || + std::isnan(in.imm_values[2].imm_f32) || std::isnan(in.imm_values[3].imm_f32); +} + +template <> +bool ImmValue::IsNan(const ImmValue& in) noexcept { + return std::isnan(in.imm_values[0].imm_f64) || std::isnan(in.imm_values[1].imm_f64) || + std::isnan(in.imm_values[2].imm_f64) || std::isnan(in.imm_values[3].imm_f64); } bool ImmValue::IsSupportedValue(const IR::Value& value) noexcept { @@ -1465,58 +1237,18 @@ bool ImmValue::IsSupportedValue(const IR::Value& value) noexcept { } } -} // namespace Shader::IR +} // namespace Shader::IR::ComputeValue namespace std { -std::size_t hash::operator()(const Shader::IR::ImmValue& value) const { - using namespace Shader::IR; +std::size_t hash::operator()( + const Shader::IR::ComputeValue::ImmValue& value) const { + using namespace Shader::IR::ComputeValue; - u64 h = HashCombine(static_cast(value.Type()), 0ULL); - - switch (value.Type()) { - case Type::U1: - return HashCombine(static_cast(value.imm_values[0].imm_u1), h); - case Type::U8: - return HashCombine(static_cast(value.imm_values[0].imm_u8), h); - case Type::U16: - return HashCombine(static_cast(value.imm_values[0].imm_u16), h); - case Type::U32: - case Type::F32: - return HashCombine(static_cast(value.imm_values[0].imm_u32), h); - case Type::U64: - case Type::F64: - return HashCombine(static_cast(value.imm_values[0].imm_u64), h); - case Type::U32x2: - case Type::F32x2: - h = HashCombine(static_cast(value.imm_values[0].imm_u32), h); - return HashCombine(static_cast(value.imm_values[1].imm_u32), h); - case Type::F64x2: - h = HashCombine(static_cast(value.imm_values[0].imm_f64), h); - return HashCombine(static_cast(value.imm_values[1].imm_f64), h); - case Type::U32x3: - case Type::F32x3: - h = HashCombine(static_cast(value.imm_values[0].imm_u32), h); - h = HashCombine(static_cast(value.imm_values[1].imm_u32), h); - return HashCombine(static_cast(value.imm_values[2].imm_u32), h); - case Type::F64x3: - h = HashCombine(static_cast(value.imm_values[0].imm_f64), h); - h = HashCombine(static_cast(value.imm_values[1].imm_f64), h); - return HashCombine(static_cast(value.imm_values[2].imm_f64), h); - case Type::U32x4: - case Type::F32x4: - h = HashCombine(static_cast(value.imm_values[0].imm_u32), h); - h = HashCombine(static_cast(value.imm_values[1].imm_u32), h); - h = HashCombine(static_cast(value.imm_values[2].imm_u32), h); - return HashCombine(static_cast(value.imm_values[3].imm_u32), h); - case Type::F64x4: - h = HashCombine(static_cast(value.imm_values[0].imm_f64), h); - h = HashCombine(static_cast(value.imm_values[1].imm_f64), h); - h = HashCombine(static_cast(value.imm_values[2].imm_f64), h); - return HashCombine(static_cast(value.imm_values[3].imm_f64), h); - default: - UNREACHABLE_MSG("Invalid type {}", value.Type()); - } + u64 h = HashCombine(value.imm_values[0].imm_u64, 0UL); + h = HashCombine(value.imm_values[1].imm_u64, h); + h = HashCombine(value.imm_values[2].imm_u64, h); + return HashCombine(value.imm_values[3].imm_u64, h); } -} // namespace std +} // namespace std \ No newline at end of file diff --git a/src/shader_recompiler/ir/compute_value/imm_value.h b/src/shader_recompiler/ir/compute_value/imm_value.h index 74b9d39b7..a46712ce5 100644 --- a/src/shader_recompiler/ir/compute_value/imm_value.h +++ b/src/shader_recompiler/ir/compute_value/imm_value.h @@ -11,62 +11,9 @@ #include "shader_recompiler/ir/type.h" #include "shader_recompiler/ir/value.h" -namespace Shader::IR { +namespace Shader::IR::ComputeValue { -// Like IR::Value but can only hold immediate values. Additionally, can hold vectors of values. -// Has arithmetic operations defined for it. Usefull for computing a value at shader compile time. - -template -class TypedImmValue; - -using ImmU1 = TypedImmValue; -using ImmU8 = TypedImmValue; -using ImmS8 = TypedImmValue; -using ImmU16 = TypedImmValue; -using ImmS16 = TypedImmValue; -using ImmU32 = TypedImmValue; -using ImmS32 = TypedImmValue; -using ImmF32 = TypedImmValue; -using ImmU64 = TypedImmValue; -using ImmS64 = TypedImmValue; -using ImmF64 = TypedImmValue; -using ImmS32F32 = TypedImmValue; -using ImmS64F64 = TypedImmValue; -using ImmU32U64 = TypedImmValue; -using ImmS32S64 = TypedImmValue; -using ImmU16U32U64 = TypedImmValue; -using ImmS16S32S64 = TypedImmValue; -using ImmF32F64 = TypedImmValue; -using ImmUAny = TypedImmValue; -using ImmSAny = TypedImmValue; -using ImmU32x2 = TypedImmValue; -using ImmU32x3 = TypedImmValue; -using ImmU32x4 = TypedImmValue; -using ImmS32x2 = TypedImmValue; -using ImmS32x3 = TypedImmValue; -using ImmS32x4 = TypedImmValue; -using ImmF32x2 = TypedImmValue; -using ImmF32x3 = TypedImmValue; -using ImmF32x4 = TypedImmValue; -using ImmF64x2 = TypedImmValue; -using ImmF64x3 = TypedImmValue; -using ImmF64x4 = TypedImmValue; -using ImmS32F32x2 = TypedImmValue; -using ImmS32F32x3 = TypedImmValue; -using ImmS32F32x4 = TypedImmValue; -using ImmF32F64x2 = TypedImmValue; -using ImmF32F64x3 = TypedImmValue; -using ImmF32F64x4 = TypedImmValue; -using ImmU32xAny = TypedImmValue; -using ImmS32xAny = TypedImmValue; -using ImmF32xAny = TypedImmValue; -using ImmF64xAny = TypedImmValue; -using ImmS32F32xAny = TypedImmValue; -using ImmF32F64xAny = TypedImmValue; +// Holds an immediate value and provides helper functions to do arithmetic operations on it. class ImmValue { public: @@ -93,6 +40,12 @@ public: ImmValue(f32 value1, f32 value2) noexcept; ImmValue(f32 value1, f32 value2, f32 value3) noexcept; ImmValue(f32 value1, f32 value2, f32 value3, f32 value4) noexcept; + ImmValue(u64 value1, u64 value2) noexcept; + ImmValue(u64 value1, u64 value2, u64 value3) noexcept; + ImmValue(u64 value1, u64 value2, u64 value3, u64 value4) noexcept; + ImmValue(s64 value1, s64 value2) noexcept; + ImmValue(s64 value1, s64 value2, s64 value3) noexcept; + ImmValue(s64 value1, s64 value2, s64 value3, s64 value4) noexcept; ImmValue(f64 value1, f64 value2) noexcept; ImmValue(f64 value1, f64 value2, f64 value3) noexcept; ImmValue(f64 value1, f64 value2, f64 value3, f64 value4) noexcept; @@ -101,107 +54,142 @@ public: ImmValue(const ImmValue& value1, const ImmValue& value2, const ImmValue& value3, const ImmValue& value4) noexcept; - [[nodiscard]] bool IsEmpty() const noexcept; - [[nodiscard]] IR::Type Type() const noexcept; - [[nodiscard]] IR::Type BaseType() const noexcept; - [[nodiscard]] u32 Dimensions() const noexcept; + [[nodiscard]] static ImmValue CompositeFrom2x2(const ImmValue& value1, + const ImmValue& value2) noexcept; - [[nodiscard]] bool IsSigned() const noexcept; - void SetSigned(bool signed_) noexcept; - void SameSignAs(const ImmValue& other) noexcept; + [[nodiscard]] bool U1() const noexcept; + [[nodiscard]] u8 U8() const noexcept; + [[nodiscard]] s8 S8() const noexcept; + [[nodiscard]] u16 U16() const noexcept; + [[nodiscard]] s16 S16() const noexcept; + [[nodiscard]] u32 U32() const noexcept; + [[nodiscard]] s32 S32() const noexcept; + [[nodiscard]] f32 F32() const noexcept; + [[nodiscard]] u64 U64() const noexcept; + [[nodiscard]] s64 S64() const noexcept; + [[nodiscard]] f64 F64() const noexcept; - [[nodiscard]] ImmValue Convert(IR::Type new_type, bool new_signed) const noexcept; - [[nodiscard]] ImmValue Bitcast(IR::Type new_type, bool new_signed) const noexcept; - [[nodiscard]] ImmValue Extract(const ImmU32& index) const noexcept; - [[nodiscard]] ImmValue Insert(const ImmValue& value, const ImmU32& indndex) const noexcept; - - [[nodiscard]] bool U1() const; - [[nodiscard]] u8 U8() const; - [[nodiscard]] s8 S8() const; - [[nodiscard]] u16 U16() const; - [[nodiscard]] s16 S16() const; - [[nodiscard]] u32 U32() const; - [[nodiscard]] s32 S32() const; - [[nodiscard]] f32 F32() const; - [[nodiscard]] u64 U64() const; - [[nodiscard]] s64 S64() const; - [[nodiscard]] f64 F64() const; - - [[nodiscard]] std::tuple U32x2() const; - [[nodiscard]] std::tuple U32x3() const; - [[nodiscard]] std::tuple U32x4() const; - [[nodiscard]] std::tuple S32x2() const; - [[nodiscard]] std::tuple S32x3() const; - [[nodiscard]] std::tuple S32x4() const; - [[nodiscard]] std::tuple F32x2() const; - [[nodiscard]] std::tuple F32x3() const; - [[nodiscard]] std::tuple F32x4() const; - [[nodiscard]] std::tuple F64x2() const; - [[nodiscard]] std::tuple F64x3() const; - [[nodiscard]] std::tuple F64x4() const; + [[nodiscard]] std::tuple U32x2() const noexcept; + [[nodiscard]] std::tuple U32x3() const noexcept; + [[nodiscard]] std::tuple U32x4() const noexcept; + [[nodiscard]] std::tuple S32x2() const noexcept; + [[nodiscard]] std::tuple S32x3() const noexcept; + [[nodiscard]] std::tuple S32x4() const noexcept; + [[nodiscard]] std::tuple F32x2() const noexcept; + [[nodiscard]] std::tuple F32x3() const noexcept; + [[nodiscard]] std::tuple F32x4() const noexcept; + [[nodiscard]] std::tuple F64x2() const noexcept; + [[nodiscard]] std::tuple F64x3() const noexcept; + [[nodiscard]] std::tuple F64x4() const noexcept; ImmValue& operator=(const ImmValue& value) noexcept = default; [[nodiscard]] bool operator==(const ImmValue& other) const noexcept; [[nodiscard]] bool operator!=(const ImmValue& other) const noexcept; - [[nodiscard]] bool operator<(const ImmValue& other) const noexcept; - [[nodiscard]] bool operator>(const ImmValue& other) const noexcept; - [[nodiscard]] bool operator<=(const ImmValue& other) const noexcept; - [[nodiscard]] bool operator>=(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator+(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator-(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator*(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator/(const ImmValue& other) const; - [[nodiscard]] ImmValue operator%(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator&(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator|(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator^(const ImmValue& other) const noexcept; - [[nodiscard]] ImmValue operator<<(const ImmU32& other) const noexcept; - [[nodiscard]] ImmValue operator>>(const ImmU32& other) const noexcept; - [[nodiscard]] ImmValue operator~() const noexcept; + [[nodiscard]] static ImmValue Extract(const ImmValue& vec, const ImmValue& index) noexcept; + [[nodiscard]] static ImmValue Insert(const ImmValue& vec, const ImmValue& value, + const ImmValue& index) noexcept; - [[nodiscard]] ImmValue operator++(int) noexcept; - [[nodiscard]] ImmValue operator--(int) noexcept; + template + [[nodiscard]] static ImmValue Convert(const ImmValue& in) noexcept; - ImmValue& operator++() noexcept; - ImmValue& operator--() noexcept; + template + [[nodiscard]] static ImmValue Add(const ImmValue& a, const ImmValue& b) noexcept; - [[nodiscard]] ImmValue operator-() const noexcept; - [[nodiscard]] ImmValue operator+() const noexcept; + template + [[nodiscard]] static ImmValue Sub(const ImmValue& a, const ImmValue& b) noexcept; - ImmValue& operator+=(const ImmValue& other) noexcept; - ImmValue& operator-=(const ImmValue& other) noexcept; - ImmValue& operator*=(const ImmValue& other) noexcept; - ImmValue& operator/=(const ImmValue& other); - ImmValue& operator%=(const ImmValue& other) noexcept; - ImmValue& operator&=(const ImmValue& other) noexcept; - ImmValue& operator|=(const ImmValue& other) noexcept; - ImmValue& operator^=(const ImmValue& other) noexcept; - ImmValue& operator<<=(const ImmU32& other) noexcept; - ImmValue& operator>>=(const ImmU32& other) noexcept; + template + [[nodiscard]] static ImmValue Mul(const ImmValue& a, const ImmValue& b) noexcept; - [[nodiscard]] ImmValue abs() const noexcept; - [[nodiscard]] ImmValue recip() const noexcept; - [[nodiscard]] ImmValue sqrt() const noexcept; - [[nodiscard]] ImmValue rsqrt() const noexcept; - [[nodiscard]] ImmValue sin() const noexcept; - [[nodiscard]] ImmValue cos() const noexcept; - [[nodiscard]] ImmValue exp2() const noexcept; - [[nodiscard]] ImmValue ldexp(const ImmU32& exp) const noexcept; - [[nodiscard]] ImmValue log2() const noexcept; - [[nodiscard]] ImmValue clamp(const ImmValue& min, const ImmValue& max) const noexcept; - [[nodiscard]] ImmValue floor() const noexcept; - [[nodiscard]] ImmValue ceil() const noexcept; - [[nodiscard]] ImmValue round() const noexcept; - [[nodiscard]] ImmValue trunc() const noexcept; - [[nodiscard]] ImmValue fract() const noexcept; - [[nodiscard]] bool isnan() const noexcept; + template + [[nodiscard]] static ImmValue Div(const ImmValue& a, const ImmValue& b); - [[nodiscard]] static ImmValue fma(const ImmF32F64& a, const ImmF32F64& b, - const ImmF32F64& c) noexcept; + template + [[nodiscard]] static ImmValue Mod(const ImmValue& a, const ImmValue& b) noexcept; - static bool IsSupportedValue(const IR::Value& value) noexcept; + template + [[nodiscard]] static ImmValue And(const ImmValue& a, const ImmValue& b) noexcept; + + template + [[nodiscard]] static ImmValue Or(const ImmValue& a, const ImmValue& b) noexcept; + + template + [[nodiscard]] static ImmValue Xor(const ImmValue& a, const ImmValue& b) noexcept; + + template + [[nodiscard]] static ImmValue LShift(const ImmValue& a, const ImmValue& shift) noexcept; + + template + [[nodiscard]] static ImmValue RShift(const ImmValue& a, const ImmValue& shift) noexcept; + + template + [[nodiscard]] static ImmValue Not(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Neg(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Abs(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Recip(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Sqrt(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Rsqrt(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Sin(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Cos(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Exp2(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Ldexp(const ImmValue& in, const ImmValue& exp) noexcept; + + template + [[nodiscard]] static ImmValue Log2(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Min(const ImmValue& a, const ImmValue& b) noexcept; + + template + [[nodiscard]] static ImmValue Max(const ImmValue& a, const ImmValue& b) noexcept; + + template + [[nodiscard]] static ImmValue Clamp(const ImmValue& in, const ImmValue& min, + const ImmValue& max) noexcept; + + template + [[nodiscard]] static ImmValue Floor(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Ceil(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Round(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Trunc(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Fract(const ImmValue& in) noexcept; + + template + [[nodiscard]] static ImmValue Fma(const ImmValue& a, const ImmValue& b, + const ImmValue& c) noexcept; + + template + [[nodiscard]] static bool IsNan(const ImmValue& in) noexcept; + + [[nodiscard]] static bool IsSupportedValue(const IR::Value& value) noexcept; private: union Value { @@ -218,168 +206,113 @@ private: f64 imm_f64; }; - IR::Type type{}; - bool is_signed{}; std::array imm_values; friend class std::hash; }; static_assert(std::is_trivially_copyable_v); -template -class TypedImmValue : public ImmValue { -public: - inline static constexpr IR::Type static_type = type_; - inline static constexpr bool static_is_signed = is_signed_; - - TypedImmValue() = default; - - template - requires((other_type & type_) != IR::Type::Void && other_signed == is_signed_) - explicit(false) TypedImmValue(const TypedImmValue& other) - : ImmValue(other) {} - - explicit TypedImmValue(const ImmValue& value) : ImmValue(value) { - if ((value.Type() & type_) == IR::Type::Void && value.IsSigned() == is_signed_) { - throw InvalidArgument("Incompatible types {} {} and {} {}", - is_signed_ ? "signed" : "unsigned", type_, value.Type(), - value.IsSigned() ? "signed" : "unsigned"); - } - } -}; - -inline bool ImmValue::IsEmpty() const noexcept { - return type == Type::Void; -} - -inline IR::Type ImmValue::Type() const noexcept { - return type; -} - -inline bool ImmValue::U1() const { - ASSERT(type == Type::U1 && !is_signed); +inline bool ImmValue::U1() const noexcept { return imm_values[0].imm_u1; } -inline u8 ImmValue::U8() const { - ASSERT(type == Type::U8 && !is_signed); +inline u8 ImmValue::U8() const noexcept { return imm_values[0].imm_u8; } -inline s8 ImmValue::S8() const { - ASSERT(type == Type::U8 && is_signed); +inline s8 ImmValue::S8() const noexcept { return imm_values[0].imm_s8; } -inline u16 ImmValue::U16() const { - ASSERT(type == Type::U16 && !is_signed); +inline u16 ImmValue::U16() const noexcept { return imm_values[0].imm_u16; } -inline s16 ImmValue::S16() const { - ASSERT(type == Type::U16 && is_signed); +inline s16 ImmValue::S16() const noexcept { return imm_values[0].imm_s16; } -inline u32 ImmValue::U32() const { - ASSERT(type == Type::U32 && !is_signed); +inline u32 ImmValue::U32() const noexcept { return imm_values[0].imm_u32; } -inline s32 ImmValue::S32() const { - ASSERT(type == Type::U32 && is_signed); +inline s32 ImmValue::S32() const noexcept { return imm_values[0].imm_s32; } -inline f32 ImmValue::F32() const { - ASSERT(type == Type::F32 && is_signed); +inline f32 ImmValue::F32() const noexcept { return imm_values[0].imm_f32; } -inline u64 ImmValue::U64() const { - ASSERT(type == Type::U64 && !is_signed); +inline u64 ImmValue::U64() const noexcept { return imm_values[0].imm_u64; } -inline s64 ImmValue::S64() const { - ASSERT(type == Type::U64 && is_signed); +inline s64 ImmValue::S64() const noexcept { return imm_values[0].imm_s64; } -inline f64 ImmValue::F64() const { - ASSERT(type == Type::F64 && is_signed); +inline f64 ImmValue::F64() const noexcept { return imm_values[0].imm_f64; } -inline std::tuple ImmValue::U32x2() const { - ASSERT(type == Type::U32x2 && !is_signed); +inline std::tuple ImmValue::U32x2() const noexcept { return {imm_values[0].imm_u32, imm_values[1].imm_u32}; } -inline std::tuple ImmValue::U32x3() const { - ASSERT(type == Type::U32x3 && !is_signed); +inline std::tuple ImmValue::U32x3() const noexcept { return {imm_values[0].imm_u32, imm_values[1].imm_u32, imm_values[2].imm_u32}; } -inline std::tuple ImmValue::U32x4() const { - ASSERT(type == Type::U32x4 && !is_signed); +inline std::tuple ImmValue::U32x4() const noexcept { return {imm_values[0].imm_u32, imm_values[1].imm_u32, imm_values[2].imm_u32, imm_values[3].imm_u32}; } -inline std::tuple ImmValue::S32x2() const { - ASSERT(type == Type::U32x2 && is_signed); +inline std::tuple ImmValue::S32x2() const noexcept { return {imm_values[0].imm_s32, imm_values[1].imm_s32}; } -inline std::tuple ImmValue::S32x3() const { - ASSERT(type == Type::U32x3 && is_signed); +inline std::tuple ImmValue::S32x3() const noexcept { return {imm_values[0].imm_s32, imm_values[1].imm_s32, imm_values[2].imm_s32}; } -inline std::tuple ImmValue::S32x4() const { - ASSERT(type == Type::U32x4 && is_signed); +inline std::tuple ImmValue::S32x4() const noexcept { return {imm_values[0].imm_s32, imm_values[1].imm_s32, imm_values[2].imm_s32, imm_values[3].imm_s32}; } -inline std::tuple ImmValue::F32x2() const { - ASSERT(type == Type::F32x2 && is_signed); +inline std::tuple ImmValue::F32x2() const noexcept { return {imm_values[0].imm_f32, imm_values[1].imm_f32}; } -inline std::tuple ImmValue::F32x3() const { - ASSERT(type == Type::F32x3 && is_signed); +inline std::tuple ImmValue::F32x3() const noexcept { return {imm_values[0].imm_f32, imm_values[1].imm_f32, imm_values[2].imm_f32}; } -inline std::tuple ImmValue::F32x4() const { - ASSERT(type == Type::F32x4 && is_signed); +inline std::tuple ImmValue::F32x4() const noexcept { return {imm_values[0].imm_f32, imm_values[1].imm_f32, imm_values[2].imm_f32, imm_values[3].imm_f32}; } -inline std::tuple ImmValue::F64x2() const { - ASSERT(type == Type::F64x2 && is_signed); +inline std::tuple ImmValue::F64x2() const noexcept { return {imm_values[0].imm_f64, imm_values[1].imm_f64}; } -inline std::tuple ImmValue::F64x3() const { - ASSERT(type == Type::F64x3 && is_signed); +inline std::tuple ImmValue::F64x3() const noexcept { return {imm_values[0].imm_f64, imm_values[1].imm_f64, imm_values[2].imm_f64}; } -inline std::tuple ImmValue::F64x4() const { - ASSERT(type == Type::F64x4 && is_signed); +inline std::tuple ImmValue::F64x4() const noexcept { return {imm_values[0].imm_f64, imm_values[1].imm_f64, imm_values[2].imm_f64, imm_values[3].imm_f64}; } -} // namespace Shader::IR +} // namespace Shader::IR::ComputeValue namespace std { template <> -struct hash { - std::size_t operator()(const Shader::IR::ImmValue& value) const; +struct hash { + std::size_t operator()(const Shader::IR::ComputeValue::ImmValue& value) const; }; } // namespace std \ No newline at end of file