diff --git a/rpcsx/gpu/Cache.cpp b/rpcsx/gpu/Cache.cpp index aa54562e4..f6b2271e4 100644 --- a/rpcsx/gpu/Cache.cpp +++ b/rpcsx/gpu/Cache.cpp @@ -453,20 +453,16 @@ Cache::ShaderResources::eval(ir::InstructionId instId, case 8: result = readPointer(address); break; - case 12: - result = readPointer(address); - break; - case 16: - result = readPointer(address); - break; - case 32: - result = readPointer>(address); - break; - case 64: - result = readPointer>(address); - break; + default: - rx::die("unexpected pointer load size {}", loadSize); + rx::dieIf(loadSize % sizeof(std::uint32_t), "unaligned load size {}", + loadSize); + + for (std::int32_t offset = 0; offset < loadSize; + offset += sizeof(std::uint32_t)) { + result.add(readPointer(address + offset)); + } + break; } return result; @@ -2368,7 +2364,7 @@ Cache::Shader Cache::GraphicsTag::getShader( std::bit_cast(context.paClVports[slot.data].zScale); break; case gcn::ConfigType::PsInputVGpr: - if (slot.data > psVgprInput.size()) { + if (slot.data >= psVgprInput.size()) { configPtr[index] = ~0; } else { configPtr[index] = std::bit_cast(psVgprInput[slot.data]); diff --git a/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp index e02f8f44e..bb9c5d72f 100644 --- a/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp +++ b/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp @@ -2,33 +2,156 @@ #include "Vector.hpp" #include "ir/Value.hpp" +#include "rx/align.hpp" +#include "rx/die.hpp" +#include #include #include -#include +#include +#include +#include +#include namespace shader::eval { struct Value { - using Storage = std::variant< - std::nullptr_t, std::int8_t, std::int16_t, std::int32_t, std::int64_t, - std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t, float16_t, - float32_t, float64_t, u8vec2, u8vec3, u8vec4, i8vec2, i8vec3, i8vec4, - u16vec2, u16vec3, u16vec4, i16vec2, i16vec3, i16vec4, u32vec2, u32vec3, - u32vec4, i32vec2, i32vec3, i32vec4, u64vec2, u64vec3, u64vec4, i64vec2, - i64vec3, i64vec4, f32vec2, f32vec3, f32vec4, f64vec2, f64vec3, f64vec4, - f16vec2, f16vec3, f16vec4, bool, bvec2, bvec3, bvec4, - std::array, std::array>; - static constexpr auto StorageSize = std::variant_size_v; - Storage storage; + using Types = std::tuple; + + static constexpr auto kMaxElementCount = 32; + static constexpr auto kMaxTypeAlignment = [] { + auto impl = [](std::index_sequence) { + std::size_t result = 1; + ((result = std::max(alignof(std::tuple_element_t), result)), + ...); + return result; + }; + return impl(std::make_index_sequence>{}); + }(); + static constexpr auto kMaxTypeSize = [] { + auto impl = [](std::index_sequence) { + std::size_t result = 1; + ((result = std::max(sizeof(std::tuple_element_t), result)), + ...); + return result; + }; + return rx::alignUp( + impl(std::make_index_sequence>{}), + kMaxTypeAlignment); + }(); + + template static consteval std::size_t getTypeIndex() { + auto impl = [](std::index_sequence) { + std::size_t result = -1; + ((result = + std::is_same_v> ? I : result), + ...); + return result; + }; + return impl(std::make_index_sequence>{}); + } + + static constexpr auto StorageSize = std::tuple_size_v; + + template >>> + RT visit(T &&cb) const { + static constexpr auto table = [] { + std::array> + result; + + auto impl = [&](std::index_sequence) { + ((result[I] = [](void *cb, const char *data, + std::uint32_t count) -> RT { + return (*reinterpret_cast(cb))(std::span( + reinterpret_cast *>(data), + count)); + }), + ...); + }; + + impl(std::make_index_sequence>{}); + + return result; + }(); + + return table[mTypeIndex](&cb, mData, mCount); + } + + [[nodiscard]] std::size_t getConstituentSize() const { + return visit([](auto values) -> std::size_t { + if constexpr (std::is_same_v) { + return 0; + } else { + return sizeof(values[0]); + } + }); + } explicit operator bool() const { return !empty(); } - bool empty() const { return storage.index() == 0; } + [[nodiscard]] bool empty() const { + return mCount == 0 || mTypeIndex == getTypeIndex(); + } + [[nodiscard]] std::size_t size() const { return mCount; } - Value() : storage(nullptr) {} + Value() = default; + + template + requires(getTypeIndex() < std::tuple_size_v && + (std::is_same_v && ...)) + Value(FT firstValue, T... value) { + add(firstValue); + (add(value), ...); + } + + void add(const Value &value) { + if (value.mCount != 1) { + mTypeIndex = getTypeIndex(); + mCount = 1; + return; + } + + if (mCount == 0) { + mTypeIndex = value.mTypeIndex; + mCount = 1; + std::memcpy(mData, value.mData, kMaxTypeSize); + return; + } + + rx::dieIf(mCount >= kMaxElementCount, "storage too small"); + + if (mTypeIndex != value.mTypeIndex) { + mTypeIndex = getTypeIndex(); + mCount = 1; + return; + } + + auto index = mCount++; + auto elemSize = getConstituentSize(); + std::memcpy(mData + elemSize * index, value.mData, kMaxTypeSize); + } template - Value(T &&value) - requires requires { Storage(std::forward(value)); } - : storage(std::forward(value)) {} + requires(getTypeIndex() < std::tuple_size_v) + void add(T value) { + if (mCount == 0) { + mTypeIndex = getTypeIndex(); + mCount = 1; + *getData() = value; + return; + } + + rx::dieIf(mCount >= kMaxElementCount, "storage too small"); + + if (mTypeIndex != getTypeIndex()) { + mTypeIndex = getTypeIndex(); + mCount = 1; + return; + } + + getData()[mCount++] = value; + } static Value compositeConstruct(ir::Value type, std::span constituents); @@ -52,21 +175,43 @@ struct Value { std::optional sExtScalar() const; template - requires requires { std::get(storage); } - T get() const { - return std::get(storage); + requires(getTypeIndex() < std::tuple_size_v) + [[nodiscard]] const T &get(std::size_t index = 0) const { + rx::dieIf(mTypeIndex != getTypeIndex(), + "eval::Value::get(): invalid type"); + rx::dieIf(index >= std::tuple_size_v, + "eval::Value::get(): invalid index"); + return getData()[index]; + } + + template + requires(I < std::tuple_size_v) + [[nodiscard]] const std::tuple_element_t & + get(std::size_t index = 0) const { + rx::dieIf(mTypeIndex != I, "eval::Value::get(): invalid type"); + rx::dieIf(index >= std::tuple_size_v, + "eval::Value::get(): invalid index"); + return getData>()[index]; } template - requires requires { std::get(storage); } - std::optional as() const { - if (auto result = std::get_if(&storage)) { - return *result; + requires(getTypeIndex() < std::tuple_size_v) + [[nodiscard]] std::optional as(std::size_t index = 0) const { + rx::dieIf(index >= std::tuple_size_v, + "eval::Value::as(): invalid index"); + if (mTypeIndex == getTypeIndex()) { + return getData()[index]; } return std::nullopt; } + template + requires(getTypeIndex() < std::tuple_size_v) + [[nodiscard]] bool is() const { + return mTypeIndex == getTypeIndex(); + } + Value operator+(const Value &rhs) const; Value operator-(const Value &rhs) const; Value operator*(const Value &rhs) const; @@ -89,5 +234,17 @@ struct Value { Value operator-() const; Value operator~() const; Value operator!() const; + + std::size_t index() const { return mTypeIndex; } + +private: + template T *getData() { return reinterpret_cast(mData); } + template const T *getData() const { + return reinterpret_cast(mData); + } + + std::uint32_t mTypeIndex = 0; + std::uint32_t mCount = 0; + alignas(kMaxTypeAlignment) char mData[kMaxTypeSize * kMaxElementCount]; }; } // namespace shader::eval diff --git a/rpcsx/gpu/lib/gcn-shader/src/eval.cpp b/rpcsx/gpu/lib/gcn-shader/src/eval.cpp index a634427ac..16c283c9a 100644 --- a/rpcsx/gpu/lib/gcn-shader/src/eval.cpp +++ b/rpcsx/gpu/lib/gcn-shader/src/eval.cpp @@ -2,132 +2,15 @@ #include "dialect.hpp" #include "ir.hpp" #include -#include +#include using namespace shader; -template consteval bool testVisitCond() { - if constexpr (std::is_same_v) { - return true; - } else { - return Cond{}(std::remove_cvref_t{}...); - } -}; - -template consteval bool testVisitCond() { - if constexpr (U >= eval::Value::StorageSize) { - return false; - } else if constexpr (std::is_same_v) { - return true; - } else { - return Cond{}(std::variant_alternative_t{}); - } -}; - -template -constexpr eval::Value visitImpl(const eval::Value &variant, auto &&fn) { - -#define DEFINE_CASE(N) \ - case I + N: \ - if constexpr (testVisitCond()) { \ - return std::forward(fn)(std::get(variant.storage)); \ - } else { \ - return {}; \ - } - - switch (variant.storage.index()) { - DEFINE_CASE(0); - DEFINE_CASE(1); - DEFINE_CASE(2); - DEFINE_CASE(3); - DEFINE_CASE(4); - DEFINE_CASE(5); - DEFINE_CASE(6); - DEFINE_CASE(7); - DEFINE_CASE(8); - DEFINE_CASE(9); - DEFINE_CASE(10); - DEFINE_CASE(11); - DEFINE_CASE(12); - DEFINE_CASE(13); - DEFINE_CASE(14); - DEFINE_CASE(15); - DEFINE_CASE(16); - DEFINE_CASE(17); - DEFINE_CASE(18); - DEFINE_CASE(19); - DEFINE_CASE(20); - DEFINE_CASE(21); - DEFINE_CASE(22); - DEFINE_CASE(23); - DEFINE_CASE(24); - DEFINE_CASE(25); - DEFINE_CASE(26); - DEFINE_CASE(27); - DEFINE_CASE(28); - DEFINE_CASE(29); - DEFINE_CASE(30); - DEFINE_CASE(31); - DEFINE_CASE(32); - DEFINE_CASE(33); - DEFINE_CASE(34); - DEFINE_CASE(35); - DEFINE_CASE(36); - DEFINE_CASE(37); - DEFINE_CASE(38); - DEFINE_CASE(39); - DEFINE_CASE(40); - DEFINE_CASE(41); - DEFINE_CASE(42); - DEFINE_CASE(43); - DEFINE_CASE(44); - DEFINE_CASE(45); - DEFINE_CASE(46); - DEFINE_CASE(47); - DEFINE_CASE(48); - DEFINE_CASE(49); - DEFINE_CASE(50); - DEFINE_CASE(51); - DEFINE_CASE(52); - DEFINE_CASE(53); - DEFINE_CASE(54); - DEFINE_CASE(55); - DEFINE_CASE(56); - DEFINE_CASE(57); - DEFINE_CASE(58); - DEFINE_CASE(59); - DEFINE_CASE(60); - DEFINE_CASE(61); - DEFINE_CASE(62); - DEFINE_CASE(63); - } -#undef DEFINE_CASE - - constexpr auto NextIndex = I + 64; - - if constexpr (NextIndex < eval::Value::StorageSize) { - return visitImpl(std::forward(fn), - std::forward(variant)); - } - - return {}; -} - -template -constexpr eval::Value visitScalarType(ir::Value type, Cb &&cb) - requires requires { - { std::forward(cb)(int{}) } -> std::same_as; - } -{ - auto invoke = [&](auto type) -> eval::Value { - if constexpr (testVisitCond>()) { - return std::forward(cb)(type); - } - return {}; - }; - +template +constexpr bool invokeWithType(ir::Value type, T &&invoke) { if (type == ir::spv::OpTypeBool) { - return invoke(bool{}); + invoke(bool{}); + return true; } if (type == ir::spv::OpTypeInt) { @@ -136,213 +19,106 @@ constexpr eval::Value visitScalarType(ir::Value type, Cb &&cb) switch (*type.getOperand(0).getAsInt32()) { case 8: if (isSigned) { - return invoke(std::int8_t{}); + invoke(std::int8_t{}); + return true; } - return invoke(std::uint8_t{}); + invoke(std::uint8_t{}); + return true; case 16: if (isSigned) { - return invoke(std::int16_t{}); + invoke(std::int16_t{}); + return true; } - return invoke(std::uint16_t{}); + invoke(std::uint16_t{}); + return true; case 32: if (isSigned) { - return invoke(std::int32_t{}); + invoke(std::int32_t{}); + return true; } - return invoke(std::uint32_t{}); + invoke(std::uint32_t{}); + return true; case 64: if (isSigned) { - return invoke(std::int64_t{}); + invoke(std::int64_t{}); + return true; } - return invoke(std::uint64_t{}); + invoke(std::uint64_t{}); + return true; } - return {}; + return false; } if (type == ir::spv::OpTypeFloat) { switch (*type.getOperand(0).getAsInt32()) { case 16: - return invoke(shader::float16_t{}); + invoke(shader::float16_t{}); + return true; case 32: - return invoke(shader::float32_t{}); + invoke(shader::float32_t{}); + return true; case 64: - return invoke(shader::float64_t{}); + invoke(shader::float64_t{}); + return true; } - return {}; + return false; } - return {}; -} - -template -constexpr eval::Value visitType(ir::Value type, Cb &&cb) - requires requires { - { std::forward(cb)(int{}) } -> std::same_as; - } -{ - if (type == ir::spv::OpTypeInt || type == ir::spv::OpTypeFloat || - type == ir::spv::OpTypeBool) { - return visitScalarType(type, cb); - } - - auto invoke = [&](auto type) -> eval::Value { - if constexpr (testVisitCond>()) { - return std::forward(cb)(type); - } else { - return {}; - } - }; - if (type == ir::spv::OpTypeVector) { - switch (*type.getOperand(1).getAsInt32()) { - case 2: - return visitScalarType( - type.getOperand(0).getAsValue(), - [&](T) { return invoke(shader::Vector{}); }); - - case 3: - return visitScalarType( - type.getOperand(0).getAsValue(), - [&](T) { return invoke(shader::Vector{}); }); - - case 4: - return visitScalarType( - type.getOperand(0).getAsValue(), - [&](T) { return invoke(shader::Vector{}); }); - } - - return {}; + return invokeWithType(type.getOperand(0).getAsValue(), + std::forward(invoke)); } - return {}; + return false; } -template -eval::Value visit(const eval::Value &value, Cb &&cb) { - using VisitCond = decltype([](auto &&storage) { - using T = std::remove_cvref_t; - if constexpr (std::is_same_v) { - return false; - } else { - return testVisitCond(); - } +static constexpr std::size_t getIrTypeIndex(ir::Value type) { + std::size_t result = 0; + + invokeWithType(type, [&](auto type) { + result = eval::Value::getTypeIndex(); }); - return visitImpl(value, std::forward(cb)); + return result; } -template -eval::Value visit2(auto &&cond, const eval::Value &value, Cb &&cb) { - if constexpr (cond()) { - return visitImpl(value, std::forward(cb)); - } else { - return {}; +static constexpr std::size_t getIrTypeConstituents(ir::Value type) { + if (type == ir::spv::OpTypeVector) { + return *type.getOperand(1).getAsInt32(); } + + return 1; } -template -eval::Value visitWithType(const eval::Value &value, ir::Value type, Cb &&cb) { - using ValueVisitCond = decltype([](auto storage) { - if constexpr (std::is_same_v) { - return false; - } else { - return testVisitCond(); - } - }); - - return visitImpl(value, [&](auto &&value) -> eval::Value { - return visitType(type, [&](auto type) -> eval::Value { - if constexpr (testVisitCond()) { - return std::forward(cb)(type, value); - } else { - return {}; - } - }); - }); -} - -namespace { -template struct ComponentTypeImpl { - using type = T; -}; - -template struct ComponentTypeImpl> { - using type = T; -}; - -template -struct ComponentTypeImpl> { - using type = T; -}; - -template struct MakeSignedImpl { - using type = std::make_signed_t; -}; - -template struct MakeSignedImpl> { - using type = Vector, N>; -}; -template struct MakeUnsignedImpl { - using type = std::make_unsigned_t; -}; - -template struct MakeUnsignedImpl> { - using type = Vector, N>; -}; -} // namespace - -template using ComponentType = typename ComponentTypeImpl::type; -template using MakeSigned = typename MakeSignedImpl::type; -template using MakeUnsigned = typename MakeUnsignedImpl::type; - -template constexpr std::size_t Components = 1; -template -constexpr std::size_t Components> = N; -template -constexpr std::size_t Components> = N; - -template constexpr bool IsArray = false; -template -constexpr bool IsArray> = true; - eval::Value eval::Value::compositeConstruct(ir::Value type, std::span constituents) { - using Cond = - decltype([](auto type) { return Components > 1; }); + if (getIrTypeConstituents(type) != constituents.size()) { + return {}; + } - return visitType(type, [&](auto type) -> Value { - constexpr std::size_t N = Components; - if (N != constituents.size()) { - return {}; - } + auto typeIndex = getIrTypeIndex(type); - decltype(type) result; + eval::Value result; + for (auto &elem : constituents) { + result.add(elem); + } - for (std::size_t i = 0; i < N; ++i) { - if (auto value = constituents[i].as>()) { - result[i] = *value; - } else { - return {}; - } - } + if (result.index() != typeIndex) { + return {}; + } - return result; - }); + return result; } eval::Value eval::Value::compositeExtract(const Value &index) const { - using Cond = - decltype([](auto type) { return Components > 1; }); - auto optIndexInt = index.zExtScalar(); if (!optIndexInt) { return {}; @@ -350,321 +126,249 @@ eval::Value eval::Value::compositeExtract(const Value &index) const { auto indexInt = *optIndexInt; - return visit(*this, [&](auto &&value) -> Value { - using ValueType = std::remove_cvref_t; - constexpr std::size_t N = Components; + if (indexInt >= size()) { + return {}; + } - if (indexInt >= N) { - return {}; - } - - return value[indexInt]; - }); + eval::Value result; + result.mTypeIndex = mTypeIndex; + result.mCount = 1; + std::memcpy(result.mData, mData + indexInt * getConstituentSize(), + kMaxTypeSize); + return result; } eval::Value eval::Value::isNan() const { - using Cond = decltype([](auto type) { - return std::is_floating_point_v> && - !IsArray; - }); + return visit([](auto value) { + eval::Value result; - return visit(*this, [](auto &&value) -> Value { - constexpr std::size_t N = Components>; - - if constexpr (N == 1) { - return std::isnan(value); - } else { - Vector result; - for (std::size_t i = 0; i < N; ++i) { - result[i] = std::isnan(value[i]); + if constexpr (std::is_floating_point_v< + typename decltype(value)::value_type>) { + for (std::size_t i = 0; i < value.size(); ++i) { + result.add(std::isnan(value[i])); } - return result; } + + return result; }); } eval::Value eval::Value::isInf() const { - using Cond = decltype([](auto type) { - return std::is_floating_point_v> && - !IsArray; - }); + return visit([](auto value) { + eval::Value result; - return visit(*this, [](auto &&value) -> Value { - constexpr std::size_t N = Components>; - - if constexpr (N == 1) { - return std::isinf(value); - } else { - Vector result; - for (std::size_t i = 0; i < N; ++i) { - result[i] = std::isinf(value[i]); + if constexpr (std::is_floating_point_v< + typename decltype(value)::value_type>) { + for (std::size_t i = 0; i < value.size(); ++i) { + result.add(std::isinf(value[i])); } - return result; } + + return result; }); } eval::Value eval::Value::isFinite() const { - using Cond = decltype([](auto type) { - return std::is_floating_point_v>; - }); + return visit([](auto value) { + eval::Value result; - return visit(*this, [](auto &&value) -> Value { - constexpr std::size_t N = Components>; - - if constexpr (N == 1) { - return std::isfinite(value); - } else { - Vector result; - for (std::size_t i = 0; i < N; ++i) { - result[i] = std::isfinite(value[i]); + if constexpr (std::is_floating_point_v< + typename decltype(value)::value_type>) { + for (std::size_t i = 0; i < value.size(); ++i) { + result.add(std::isfinite(value[i])); } - return result; } + + return result; }); } eval::Value eval::Value::makeUnsigned() const { - using Cond = decltype([](auto type) { - return std::is_integral_v> && - !std::is_same_v, bool> && - !IsArray; - }); + return visit([](auto value) { + eval::Value result; + using value_type = typename decltype(value)::value_type; - return visit(*this, [](auto &&value) -> Value { - constexpr std::size_t N = Components>; - using T = std::make_unsigned_t< - ComponentType>>; - - if constexpr (N == 1) { - return static_cast(value); - } else { - Vector result; - for (std::size_t i = 0; i < N; ++i) { - result[i] = static_cast(value[i]); + if constexpr (std::is_integral_v && + !std::is_same_v) { + for (std::size_t i = 0; i < value.size(); ++i) { + result.add(static_cast>(value[i])); } - return result; } + + return result; }); } eval::Value eval::Value::makeSigned() const { - using Cond = decltype([](auto type) { - return std::is_integral_v> && - !std::is_same_v, bool> && - !IsArray; - }); + return visit([](auto value) { + eval::Value result; + using value_type = typename decltype(value)::value_type; - return visit(*this, [](auto &&value) -> Value { - constexpr std::size_t N = Components>; - using T = - std::make_signed_t>>; - - if constexpr (N == 1) { - return static_cast(value); - } else { - Vector result; - for (std::size_t i = 0; i < N; ++i) { - result[i] = static_cast(value[i]); + if constexpr (std::is_integral_v && + !std::is_same_v) { + for (std::size_t i = 0; i < value.size(); ++i) { + result.add(static_cast>(value[i])); } - return result; } + + return result; }); } eval::Value eval::Value::all() const { - using Cond = decltype([](auto type) { - return std::is_same_v, bool> && - (Components > 1) && !IsArray; - }); - - return visit(*this, [](auto &&value) { - constexpr std::size_t N = Components>; - for (std::size_t i = 0; i < N; ++i) { - if (!value[i]) { - return false; + return visit([](auto value) { + if constexpr (std::is_same_v) { + for (std::size_t i = 0; i < value.size(); ++i) { + if (!value[i]) { + return eval::Value(false); + } } + return eval::Value(true); } - return true; + + return eval::Value(); }); } eval::Value eval::Value::any() const { - using Cond = decltype([](auto type) { - return std::is_same_v, bool> && - (Components > 1) && !IsArray; - }); - - return visit(*this, [](auto &&value) { - constexpr std::size_t N = Components>; - for (std::size_t i = 0; i < N; ++i) { - if (value[i]) { - return true; + return visit([](auto value) { + if constexpr (std::is_same_v) { + for (std::size_t i = 0; i < value.size(); ++i) { + if (value[i]) { + return eval::Value(true); + } } + return eval::Value(false); } - return false; + + return eval::Value(); }); } eval::Value eval::Value::select(const Value &trueValue, const Value &falseValue) const { - using Cond = decltype([](auto type) consteval { - return std::is_same_v, bool> && - !IsArray; - }); + auto optCond = as(); + if (!optCond) { + return {}; + } - return visit(*this, [&](auto &&cond) -> Value { - using CondType = std::remove_cvref_t; - using TrueCond = decltype([](auto type) consteval { - return Components == Components; - }); - - return visit(trueValue, [&](auto &&trueValue) { - using TrueValue = std::remove_cvref_t; - using FalseCond = decltype([](auto type) { - return std::is_same_v>; - }); - - return visit(falseValue, [&](auto &&falseValue) -> Value { - if constexpr (std::is_same_v>) { - constexpr std::size_t N = Components; - - if constexpr (N == 1) { - return cond ? trueValue : falseValue; - } else { - Vector result; - for (std::size_t i = 0; i < N; ++i) { - result[i] = cond[i] ? trueValue[i] : falseValue[i]; - } - return result; - } - } else { - return {}; - } - }); - }); - }); + auto cond = *optCond; + return cond ? trueValue : falseValue; } eval::Value eval::Value::iConvert(ir::Value type, bool isSigned) const { - using Cond = decltype([](auto type) { - using Type = std::remove_cvref_t; + eval::Value result; - return std::is_integral_v> && - !std::is_same_v> && - !IsArray; - }); - - using PairCond = decltype([](auto lhs, auto rhs) { - using Lhs = decltype(lhs); - using Rhs = decltype(rhs); - - return !std::is_same_v && Components == Components; - }); - - return visitWithType( - *this, type, [&](auto type, auto &&value) -> Value { - using Type = std::remove_cvref_t; - using ValueType = std::remove_cvref_t; - if (isSigned) { - return static_cast(static_cast>(value)); - } else { - return static_cast(static_cast>(value)); + (isSigned ? makeSigned() : makeUnsigned()).visit([&](auto value) { + invokeWithType(type, [&](auto type) { + if constexpr (std::is_integral_v && + !std::is_same_v && + std::is_integral_v && + !std::is_same_v) { + for (auto item : value) { + result.add(static_cast(item)); } - }); + } + }); + }); + + return result; } eval::Value eval::Value::fConvert(ir::Value type) const { - using Cond = decltype([](auto type) { - return std::is_floating_point_v> && - !IsArray; + eval::Value result; + + visit([&](auto value) { + invokeWithType(type, [&](auto type) { + if constexpr (std::is_floating_point_v && + std::is_floating_point_v< + typename decltype(value)::value_type>) { + for (auto item : value) { + result.add(static_cast(item)); + } + } + }); }); - using PairCond = decltype([](auto lhs, auto rhs) { - using Lhs = decltype(lhs); - using Rhs = decltype(rhs); - - return !std::is_same_v && Components == Components; - }); - - return visitWithType( - *this, type, [&](auto type, auto &&value) -> Value { - using Type = std::remove_cvref_t; - return static_cast(value); - }); + return result; } eval::Value eval::Value::bitcast(ir::Value type) const { - using Cond = decltype([](auto type, auto value) { - using Type = std::remove_cvref_t; + eval::Value result; - return sizeof(type) == sizeof(value); + auto resultTypeElemCount = getIrTypeConstituents(type); + visit([&](auto value) { + invokeWithType(type, [&](auto resultType) { + if (value.size_bytes() == sizeof(resultType) * resultTypeElemCount) { + result.mTypeIndex = getIrTypeIndex(type); + result.mCount = resultTypeElemCount; + std::memcpy(result.mData, value.data(), value.size_bytes()); + } + }); }); - return visitWithType( - *this, type, [](auto type, auto &&value) -> Value { - return std::bit_cast(value); - }); + return result; } std::optional eval::Value::zExtScalar() const { - using Cond = decltype([](auto type) { - return std::is_integral_v> && - !std::is_same_v, bool> && - Components == 1 && !IsArray; - }); - - auto result = visit(*this, [&](auto value) -> Value { - return static_cast( - static_cast>(value)); - }); - - if (result) { - return result.as(); + if (empty() || size() != 1) { + return {}; } - return {}; + return makeUnsigned().visit([](auto value) -> std::optional { + if constexpr (std::is_integral_v) { + return static_cast(value[0]); + } else { + return {}; + } + }); } std::optional eval::Value::sExtScalar() const { - using Cond = decltype([](auto type) { - return std::is_integral_v> && - !std::is_same_v, bool> && - Components == 1 && !IsArray; - }); - - auto result = visit(*this, [&](auto value) -> Value { - return static_cast( - static_cast>(value)); - }); - - if (result) { - return result.as(); + if (empty() || size() != 1) { + return {}; } - return {}; + return makeSigned().visit([](auto value) -> std::optional { + if constexpr (std::is_integral_v) { + return static_cast(value[0]); + } else { + return {}; + } + }); } #define DEFINE_BINARY_OP(OP) \ eval::Value eval::Value::operator OP(const Value &rhs) const { \ - using LhsCond = decltype([](auto &&lhs) { return true; }); \ - return visit(*this, [&](Lhs &&lhs) -> Value { \ - using RhsCond = decltype([](auto &&rhs) { \ - return requires(Lhs lhs) { static_cast(lhs OP rhs); }; \ - }); \ - return visit(rhs, [&](auto &&rhs) -> Value { \ - return static_cast(lhs OP rhs); \ + if (index() != rhs.index() || size() != rhs.size()) { \ + return {}; \ + } \ + eval::Value result; \ + visit([&](auto lhsValues) { \ + rhs.visit([&](auto rhsValues) { \ + if constexpr (requires { lhsValues[0] OP rhsValues[0]; }) { \ + if constexpr (std::is_same_v) { \ + for (std::size_t i = 0; i < lhsValues.size(); ++i) { \ + result.add(lhsValues[i] OP rhsValues[i]); \ + } \ + } \ + } \ }); \ }); \ + return result; \ } #define DEFINE_UNARY_OP(OP) \ eval::Value eval::Value::operator OP() const { \ - using Cond = decltype([](auto rhs) { \ - return requires { static_cast(OP rhs); }; \ - }); \ - return visit(*this, [&](auto &&rhs) -> Value { \ - return static_cast(OP rhs); \ + eval::Value result; \ + visit([&](auto values) { \ + if constexpr (requires { OP values[0]; }) { \ + for (std::size_t i = 0; i < values.size(); ++i) { \ + result.add(OP values[i]); \ + } \ + } \ }); \ + return result; \ } DEFINE_BINARY_OP(+);