ComputeValue rewrite

This commit is contained in:
Lander Gallastegi 2025-03-19 23:55:32 +01:00 committed by Lander Gallastegi
parent 47cc275203
commit 301f51e57d
22 changed files with 2739 additions and 2191 deletions

View File

@ -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

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <tuple>
namespace Common {
namespace Detail {
template <typename Func, typename OutputIt, std::size_t N, std::size_t Level, typename... ArgLists>
void CartesianInvokeImpl(Func func, OutputIt out_it,
std::tuple<typename ArgLists::const_iterator...>& arglists_its,
const std::tuple<const ArgLists&...>& arglists_tuple) {
if constexpr (Level == N) {
auto get_tuple = [&]<std::size_t... I>(std::index_sequence<I...>) {
return std::forward_as_tuple(*std::get<I>(arglists_its)...);
};
*out_it++ = std::move(std::apply(func, get_tuple(std::make_index_sequence<N>{})));
return;
} else {
const auto& arglist = std::get<Level>(arglists_tuple);
for (auto it = arglist.begin(); it != arglist.end(); ++it) {
std::get<Level>(arglists_its) = it;
CartesianInvokeImpl<Func, OutputIt, N, Level + 1, ArgLists...>(
func, out_it, arglists_its, arglists_tuple);
}
}
}
} // namespace Detail
template <typename Func, typename OutputIt, typename... ArgLists>
void CartesianInvoke(Func func, OutputIt out_it, const ArgLists&... arg_lists) {
constexpr std::size_t N = sizeof...(ArgLists);
const std::tuple<const ArgLists&...> arglists_tuple = std::forward_as_tuple(arg_lists...);
std::tuple<typename ArgLists::const_iterator...> arglists_it;
Detail::CartesianInvokeImpl<Func, OutputIt, N, 0, ArgLists...>(func, out_it, arglists_it,
arglists_tuple);
}
} // namespace Common

View File

@ -4,6 +4,7 @@
#pragma once
#include <tuple>
#include <cstddef>
namespace Common {

View File

@ -2,724 +2,51 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <functional>
#include <tuple>
#include <vector>
#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 <typename Func, typename OutputIt, size_t N, size_t Level, typename... ArgLists>
static void CartesianInvokeImpl(Func func, OutputIt out_it,
std::tuple<typename ArgLists::const_iterator...>& arglists_its,
const std::tuple<const ArgLists&...>& arglists_tuple) {
if constexpr (Level == N) {
auto get_tuple = [&]<size_t... I>(std::index_sequence<I...>) {
return std::forward_as_tuple(*std::get<I>(arglists_its)...);
};
*out_it++ = std::move(std::apply(func, get_tuple(std::make_index_sequence<N>{})));
return;
} else {
const auto& arglist = std::get<Level>(arglists_tuple);
for (auto it = arglist.begin(); it != arglist.end(); ++it) {
std::get<Level>(arglists_its) = it;
CartesianInvokeImpl<Func, OutputIt, N, Level + 1, ArgLists...>(
func, out_it, arglists_its, arglists_tuple);
}
template <auto func, size_t... I>
static void Invoke(ImmValueList& inst_values, const std::array<ImmValueList, sizeof...(I)>& args,
std::index_sequence<I...>) {
func(inst_values, args[I]...);
}
template <auto func>
static void Invoke(Inst* inst, ImmValueList& inst_values, ComputeImmValuesCache& cache) {
using Traits = Common::FuncTraits<decltype(func)>;
constexpr size_t num_args = Traits::NUM_ARGS - 1;
ASSERT(inst->NumArgs() >= num_args);
std::array<ImmValueList, num_args> args{};
for (size_t i = 0; i < num_args; ++i) {
Compute(inst->Arg(i), args[i], cache);
}
}
template <typename Func, typename OutputIt, typename... ArgLists>
static void CartesianInvoke(Func func, OutputIt out_it, const ArgLists&... arg_lists) {
constexpr size_t N = sizeof...(ArgLists);
const std::tuple<const ArgLists&...> arglists_tuple = std::forward_as_tuple(arg_lists...);
std::tuple<typename ArgLists::const_iterator...> arglists_it;
CartesianInvokeImpl<Func, OutputIt, N, 0, ArgLists...>(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 <size_t N>
static void OperationCompositeConstruct(Inst* inst, ImmValueList& inst_values,
ComputeImmValuesCache& cache) {
std::array<ImmValueList, N> args;
for (size_t i = 0; i < N; ++i) {
ComputeImmValues(inst->Arg(i), args[i], cache);
}
const auto op = []<typename... Args>(const Args&... args) { return ImmValue(args...); };
const auto call_cartesian = [&]<size_t... I>(std::index_sequence<I...>) {
CartesianInvoke(op, std::inserter(inst_values, inst_values.begin()), args[I]...);
};
call_cartesian(std::make_index_sequence<N>{});
}
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<func>(inst_values, args, std::make_index_sequence<num_args>{});
}
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

View File

@ -3,8 +3,8 @@
#pragma once
#include <unordered_set>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#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<ImmValue>;
using ImmValueList = std::unordered_set<ImmValue>;
using ComputeImmValuesCache = boost::container::flat_map<Inst*, ImmValueList>;
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<Type::U32, true, Type::F32, true>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertS32F64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::U32, true, Type::F64, true>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertU32F32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::U32, false, Type::F32, true>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertF16F32(ImmValueList& inst_values, const ImmValueList& args) {
// Common::CartesianInvoke(ImmValue::Convert<Type::F16, true, Type::F32, true>,
// 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<Type::F32, true, Type::F16, true>,
// 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<Type::F32, true, Type::F64, true>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertF64F32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::F64, true, Type::F32, true>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertF32S32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::F32, true, Type::U32, true>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertF32U32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::F32, true, Type::U32, false>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertF64S32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::F64, true, Type::U32, true>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertF64U32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::F64, true, Type::U32, false>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertF32U16(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::F32, true, Type::U16, false>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertU16U32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::U16, false, Type::U32, false>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
void DoConvertU32U16(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Convert<Type::U32, false, Type::U16, false>,
std::insert_iterator(inst_values, inst_values.begin()), args);
}
} // namespace Shader::IR::ComputeValue

View File

@ -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

View File

@ -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<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPAbs64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Abs<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPAdd32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) {
Common::CartesianInvoke(ImmValue::Add<Type::F32, true>,
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<Type::F64, true>,
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<Type::F32, true>,
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<Type::F32>,
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<Type::F64>,
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<Type::F32>(a))
return b;
if (ImmValue::IsNan<Type::F32>(b))
return a;
}
return ImmValue::Max<Type::F32, true>(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<Type::F64, true>,
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<Type::F64>(a))
return b;
if (ImmValue::IsNan<Type::F64>(b))
return a;
}
return ImmValue::Min<Type::F32, true>(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<Type::F64, true>,
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<Type::F32, true>,
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<Type::F64, true>,
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<Type::F32, true>,
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<Type::F64, true>,
std::insert_iterator(inst_values, inst_values.end()), args0, args1);
}
void DoFPNeg32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Neg<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPNeg64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Neg<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPRecip32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Recip<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPRecip64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Recip<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPRecipSqrt32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Rsqrt<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPRecipSqrt64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Rsqrt<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPSqrt(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Sqrt<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPSin(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Sin<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPExp2(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Exp2<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPLdexp(ImmValueList& inst_values, const ImmValueList& args, const ImmValueList& exponents) {
Common::CartesianInvoke(ImmValue::Ldexp<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args, exponents);
}
void DoFPCos(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Cos<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPLog2(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Log2<Type::F32>,
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<Type::F32, true>,
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<Type::F64, true>,
std::insert_iterator(inst_values, inst_values.end()), args, mins, maxs);
}
void DoFPRoundEven32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Round<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPRoundEven64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Round<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPFloor32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Floor<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPFloor64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Floor<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPCeil32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Ceil<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPCeil64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Ceil<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPTrunc32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Trunc<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPTrunc64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Trunc<Type::F64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPFract32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Fract<Type::F32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoFPFract64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Fract<Type::F64>,
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

View File

@ -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

View File

@ -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<Type::U32, false>,
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<Type::U64, false>,
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<Type::U32, false>,
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<Type::U64, false>,
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<Type::U32, false>,
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<Type::U64, false>,
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<Type::U32, true>,
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<Type::U32, false>,
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<Type::U32, true>,
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<Type::U32, false>,
std::insert_iterator(inst_values, inst_values.end()), args0, args1);
}
void DoINeg32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Neg<Type::U32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoINeg64(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Neg<Type::U64>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoIAbs32(ImmValueList& inst_values, const ImmValueList& args) {
Common::CartesianInvoke(ImmValue::Abs<Type::U32>,
std::insert_iterator(inst_values, inst_values.end()), args);
}
void DoShiftLeftLogical32(ImmValueList& inst_values, const ImmValueList& args,
const ImmValueList& shift) {
Common::CartesianInvoke(ImmValue::LShift<Type::U32>,
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<Type::U64>,
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<Type::U32, false>,
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<Type::U64, false>,
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<Type::U32, true>,
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<Type::U64, true>,
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<Type::U32>,
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<Type::U64>,
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<Type::U32>,
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<Type::U64>,
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<Type::U32>,
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<Type::U32>,
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<Type::U32, true>,
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<Type::U32, false>,
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<Type::U32, true>,
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<Type::U32, false>,
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<Type::U32, true>,
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<Type::U32, false>,
std::insert_iterator(inst_values, inst_values.end()), value, min, max);
}
} // namespace Shader::IR::ComputeValue

View File

@ -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

View File

@ -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<Type::U1>,
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<Type::U1>,
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<Type::U1>,
std::insert_iterator(inst_values, inst_values.end()), arg1, arg2);
}
void DoLogicalNot(ImmValueList& inst_values, const ImmValueList& arg1) {
Common::CartesianInvoke(ImmValue::Not<Type::U1>,
std::insert_iterator(inst_values, inst_values.end()), arg1);
}
} // namespace Shader::IR::ComputeValue

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 <IR::Type type_, bool is_signed_>
class TypedImmValue;
using ImmU1 = TypedImmValue<Type::U1, false>;
using ImmU8 = TypedImmValue<Type::U8, false>;
using ImmS8 = TypedImmValue<Type::U8, true>;
using ImmU16 = TypedImmValue<Type::U16, false>;
using ImmS16 = TypedImmValue<Type::U16, true>;
using ImmU32 = TypedImmValue<Type::U32, false>;
using ImmS32 = TypedImmValue<Type::U32, true>;
using ImmF32 = TypedImmValue<Type::F32, true>;
using ImmU64 = TypedImmValue<Type::U64, false>;
using ImmS64 = TypedImmValue<Type::U64, true>;
using ImmF64 = TypedImmValue<Type::F64, true>;
using ImmS32F32 = TypedImmValue<Type::U32 | Type::F32, true>;
using ImmS64F64 = TypedImmValue<Type::U64 | Type::F64, true>;
using ImmU32U64 = TypedImmValue<Type::U32 | Type::U64, false>;
using ImmS32S64 = TypedImmValue<Type::U32 | Type::U64, true>;
using ImmU16U32U64 = TypedImmValue<Type::U16 | Type::U32 | Type::U64, false>;
using ImmS16S32S64 = TypedImmValue<Type::U16 | Type::U32 | Type::U64, true>;
using ImmF32F64 = TypedImmValue<Type::F32 | Type::F64, true>;
using ImmUAny = TypedImmValue<Type::U1 | Type::U8 | Type::U16 | Type::U32 | Type::U64, false>;
using ImmSAny = TypedImmValue<Type::U8 | Type::U16 | Type::U32 | Type::U64, true>;
using ImmU32x2 = TypedImmValue<Type::U32x2, false>;
using ImmU32x3 = TypedImmValue<Type::U32x3, false>;
using ImmU32x4 = TypedImmValue<Type::U32x4, false>;
using ImmS32x2 = TypedImmValue<Type::U32x2, true>;
using ImmS32x3 = TypedImmValue<Type::U32x3, true>;
using ImmS32x4 = TypedImmValue<Type::U32x4, true>;
using ImmF32x2 = TypedImmValue<Type::F32x2, true>;
using ImmF32x3 = TypedImmValue<Type::F32x3, true>;
using ImmF32x4 = TypedImmValue<Type::F32x4, true>;
using ImmF64x2 = TypedImmValue<Type::F64x2, true>;
using ImmF64x3 = TypedImmValue<Type::F64x3, true>;
using ImmF64x4 = TypedImmValue<Type::F64x4, true>;
using ImmS32F32x2 = TypedImmValue<Type::U32x2 | Type::F32x2, true>;
using ImmS32F32x3 = TypedImmValue<Type::U32x3 | Type::F32x3, true>;
using ImmS32F32x4 = TypedImmValue<Type::U32x4 | Type::F32x4, true>;
using ImmF32F64x2 = TypedImmValue<Type::F32x2 | Type::F64x2, true>;
using ImmF32F64x3 = TypedImmValue<Type::F32x3 | Type::F64x3, true>;
using ImmF32F64x4 = TypedImmValue<Type::F32x4 | Type::F64x4, true>;
using ImmU32xAny = TypedImmValue<Type::U32 | Type::U32x2 | Type::U32x3 | Type::U32x4, false>;
using ImmS32xAny = TypedImmValue<Type::U32 | Type::U32x2 | Type::U32x3 | Type::U32x4, true>;
using ImmF32xAny = TypedImmValue<Type::F32 | Type::F32x2 | Type::F32x3 | Type::F32x4, true>;
using ImmF64xAny = TypedImmValue<Type::F64 | Type::F64x2 | Type::F64x3 | Type::F64x4, true>;
using ImmS32F32xAny = TypedImmValue<Type::U32 | Type::F32 | Type::U32x2 | Type::F32x2 |
Type::U32x3 | Type::F32x3 | Type::U32x4 | Type::F32x4,
true>;
using ImmF32F64xAny = TypedImmValue<Type::F32 | Type::F64 | Type::F32x2 | Type::F64x2 |
Type::F32x3 | Type::F64x3 | Type::F32x4 | Type::F64x4,
true>;
// 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<u32, u32> U32x2() const;
[[nodiscard]] std::tuple<u32, u32, u32> U32x3() const;
[[nodiscard]] std::tuple<u32, u32, u32, u32> U32x4() const;
[[nodiscard]] std::tuple<s32, s32> S32x2() const;
[[nodiscard]] std::tuple<s32, s32, s32> S32x3() const;
[[nodiscard]] std::tuple<s32, s32, s32, s32> S32x4() const;
[[nodiscard]] std::tuple<f32, f32> F32x2() const;
[[nodiscard]] std::tuple<f32, f32, f32> F32x3() const;
[[nodiscard]] std::tuple<f32, f32, f32, f32> F32x4() const;
[[nodiscard]] std::tuple<f64, f64> F64x2() const;
[[nodiscard]] std::tuple<f64, f64, f64> F64x3() const;
[[nodiscard]] std::tuple<f64, f64, f64, f64> F64x4() const;
[[nodiscard]] std::tuple<u32, u32> U32x2() const noexcept;
[[nodiscard]] std::tuple<u32, u32, u32> U32x3() const noexcept;
[[nodiscard]] std::tuple<u32, u32, u32, u32> U32x4() const noexcept;
[[nodiscard]] std::tuple<s32, s32> S32x2() const noexcept;
[[nodiscard]] std::tuple<s32, s32, s32> S32x3() const noexcept;
[[nodiscard]] std::tuple<s32, s32, s32, s32> S32x4() const noexcept;
[[nodiscard]] std::tuple<f32, f32> F32x2() const noexcept;
[[nodiscard]] std::tuple<f32, f32, f32> F32x3() const noexcept;
[[nodiscard]] std::tuple<f32, f32, f32, f32> F32x4() const noexcept;
[[nodiscard]] std::tuple<f64, f64> F64x2() const noexcept;
[[nodiscard]] std::tuple<f64, f64, f64> F64x3() const noexcept;
[[nodiscard]] std::tuple<f64, f64, f64, f64> 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 <IR::Type NewType, bool NewSigned, IR::Type OldType, bool OldSigned>
[[nodiscard]] static ImmValue Convert(const ImmValue& in) noexcept;
ImmValue& operator++() noexcept;
ImmValue& operator--() noexcept;
template <IR::Type Type, bool IsSigned>
[[nodiscard]] static ImmValue Add(const ImmValue& a, const ImmValue& b) noexcept;
[[nodiscard]] ImmValue operator-() const noexcept;
[[nodiscard]] ImmValue operator+() const noexcept;
template <IR::Type Type, bool IsSigned>
[[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 <IR::Type Type, bool IsSigned>
[[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 <IR::Type Type, bool IsSigned>
[[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 <IR::Type Type, bool IsSigned>
[[nodiscard]] static ImmValue Mod(const ImmValue& a, const ImmValue& b) noexcept;
static bool IsSupportedValue(const IR::Value& value) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue And(const ImmValue& a, const ImmValue& b) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Or(const ImmValue& a, const ImmValue& b) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Xor(const ImmValue& a, const ImmValue& b) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue LShift(const ImmValue& a, const ImmValue& shift) noexcept;
template <IR::Type Type, bool IsSigned>
[[nodiscard]] static ImmValue RShift(const ImmValue& a, const ImmValue& shift) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Not(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Neg(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Abs(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Recip(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Sqrt(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Rsqrt(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Sin(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Cos(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Exp2(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Ldexp(const ImmValue& in, const ImmValue& exp) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Log2(const ImmValue& in) noexcept;
template <IR::Type Type, bool IsSigned>
[[nodiscard]] static ImmValue Min(const ImmValue& a, const ImmValue& b) noexcept;
template <IR::Type Type, bool IsSigned>
[[nodiscard]] static ImmValue Max(const ImmValue& a, const ImmValue& b) noexcept;
template <IR::Type Type, bool IsSigned>
[[nodiscard]] static ImmValue Clamp(const ImmValue& in, const ImmValue& min,
const ImmValue& max) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Floor(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Ceil(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Round(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Trunc(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Fract(const ImmValue& in) noexcept;
template <IR::Type Type>
[[nodiscard]] static ImmValue Fma(const ImmValue& a, const ImmValue& b,
const ImmValue& c) noexcept;
template <IR::Type Type>
[[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<Value, 4> imm_values;
friend class std::hash<ImmValue>;
};
static_assert(std::is_trivially_copyable_v<ImmValue>);
template <IR::Type type_, bool is_signed_>
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 <IR::Type other_type, bool other_signed>
requires((other_type & type_) != IR::Type::Void && other_signed == is_signed_)
explicit(false) TypedImmValue(const TypedImmValue<other_type, other_signed>& 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<u32, u32> ImmValue::U32x2() const {
ASSERT(type == Type::U32x2 && !is_signed);
inline std::tuple<u32, u32> ImmValue::U32x2() const noexcept {
return {imm_values[0].imm_u32, imm_values[1].imm_u32};
}
inline std::tuple<u32, u32, u32> ImmValue::U32x3() const {
ASSERT(type == Type::U32x3 && !is_signed);
inline std::tuple<u32, u32, u32> ImmValue::U32x3() const noexcept {
return {imm_values[0].imm_u32, imm_values[1].imm_u32, imm_values[2].imm_u32};
}
inline std::tuple<u32, u32, u32, u32> ImmValue::U32x4() const {
ASSERT(type == Type::U32x4 && !is_signed);
inline std::tuple<u32, u32, u32, u32> 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<s32, s32> ImmValue::S32x2() const {
ASSERT(type == Type::U32x2 && is_signed);
inline std::tuple<s32, s32> ImmValue::S32x2() const noexcept {
return {imm_values[0].imm_s32, imm_values[1].imm_s32};
}
inline std::tuple<s32, s32, s32> ImmValue::S32x3() const {
ASSERT(type == Type::U32x3 && is_signed);
inline std::tuple<s32, s32, s32> ImmValue::S32x3() const noexcept {
return {imm_values[0].imm_s32, imm_values[1].imm_s32, imm_values[2].imm_s32};
}
inline std::tuple<s32, s32, s32, s32> ImmValue::S32x4() const {
ASSERT(type == Type::U32x4 && is_signed);
inline std::tuple<s32, s32, s32, s32> 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<f32, f32> ImmValue::F32x2() const {
ASSERT(type == Type::F32x2 && is_signed);
inline std::tuple<f32, f32> ImmValue::F32x2() const noexcept {
return {imm_values[0].imm_f32, imm_values[1].imm_f32};
}
inline std::tuple<f32, f32, f32> ImmValue::F32x3() const {
ASSERT(type == Type::F32x3 && is_signed);
inline std::tuple<f32, f32, f32> ImmValue::F32x3() const noexcept {
return {imm_values[0].imm_f32, imm_values[1].imm_f32, imm_values[2].imm_f32};
}
inline std::tuple<f32, f32, f32, f32> ImmValue::F32x4() const {
ASSERT(type == Type::F32x4 && is_signed);
inline std::tuple<f32, f32, f32, f32> 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<f64, f64> ImmValue::F64x2() const {
ASSERT(type == Type::F64x2 && is_signed);
inline std::tuple<f64, f64> ImmValue::F64x2() const noexcept {
return {imm_values[0].imm_f64, imm_values[1].imm_f64};
}
inline std::tuple<f64, f64, f64> ImmValue::F64x3() const {
ASSERT(type == Type::F64x3 && is_signed);
inline std::tuple<f64, f64, f64> ImmValue::F64x3() const noexcept {
return {imm_values[0].imm_f64, imm_values[1].imm_f64, imm_values[2].imm_f64};
}
inline std::tuple<f64, f64, f64, f64> ImmValue::F64x4() const {
ASSERT(type == Type::F64x4 && is_signed);
inline std::tuple<f64, f64, f64, f64> 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<Shader::IR::ImmValue> {
std::size_t operator()(const Shader::IR::ImmValue& value) const;
struct hash<Shader::IR::ComputeValue::ImmValue> {
std::size_t operator()(const Shader::IR::ComputeValue::ImmValue& value) const;
};
} // namespace std