diff --git a/External/FEXCore/Source/CMakeLists.txt b/External/FEXCore/Source/CMakeLists.txt index d534350c6..558967ca2 100644 --- a/External/FEXCore/Source/CMakeLists.txt +++ b/External/FEXCore/Source/CMakeLists.txt @@ -107,7 +107,7 @@ set (SRCS Interface/Core/Dispatcher/Dispatcher.cpp Interface/Core/Dispatcher/X86Dispatcher.cpp Interface/Core/Dispatcher/Arm64Dispatcher.cpp - Interface/Core/Interpreter/InterpreterFallbacks.cpp + Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp Interface/Core/X86Tables/BaseTables.cpp Interface/Core/X86Tables/DDDTables.cpp Interface/Core/X86Tables/EVEXTables.cpp diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp index d0d9247b0..0569d465a 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp @@ -8,7 +8,7 @@ $end_info$ #include "Interface/Core/Interpreter/InterpreterOps.h" #include "Interface/Core/Interpreter/InterpreterDefines.h" -#include "F80Ops.h" +#include "Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h" #include @@ -417,24 +417,6 @@ DEF_OP(F64SCALE) { memcpy(GDP, &Tmp, sizeof(double)); } -DEF_OP(VPCMPESTRX) { - const auto Op = IROp->C(); - const auto Is64Bit = Op->GPRSize == 8; - - const auto RAX = *GetSrc(Data->SSAData, Op->RAX); - const auto RDX = *GetSrc(Data->SSAData, Op->RDX);; - const auto LHS = *GetSrc<__uint128_t*>(Data->SSAData, Op->LHS); - const auto RHS = *GetSrc<__uint128_t*>(Data->SSAData, Op->RHS); - - // We can be cheeky and encode the size at bit 8 to save a parameter - const auto Control = Op->Control | (uint16_t(Is64Bit) << 8); - - const auto Result = OpHandlers::handle(RAX, RDX, LHS, RHS, Control); - - memset(GDP, 0, sizeof(uint64_t)); - memcpy(GDP, &Result, sizeof(Result)); -} - #undef DEF_OP } // namespace FEXCore::CPU diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h new file mode 100644 index 000000000..efea1a24c --- /dev/null +++ b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h @@ -0,0 +1,395 @@ +#pragma once +#include "Common/SoftFloat.h" +#include "Common/SoftFloat-3e/softfloat.h" + +#include + +#include "Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h" + +namespace FEXCore::CPU { +template<> +struct OpHandlers { + static X80SoftFloat handle4(float src) { + return src; + } + + static X80SoftFloat handle8(double src) { + return src; + } +}; + +template<> +struct OpHandlers { + template + static uint64_t handle(X80SoftFloat Src1, X80SoftFloat Src2) { + bool eq, lt, nan; + uint64_t ResultFlags = 0; + + X80SoftFloat::FCMP(Src1, Src2, &eq, <, &nan); + if (Flags & (1 << IR::FCMP_FLAG_LT) && + lt) { + ResultFlags |= (1 << IR::FCMP_FLAG_LT); + } + if (Flags & (1 << IR::FCMP_FLAG_UNORDERED) && + nan) { + ResultFlags |= (1 << IR::FCMP_FLAG_UNORDERED); + } + if (Flags & (1 << IR::FCMP_FLAG_EQ) && + eq) { + ResultFlags |= (1 << IR::FCMP_FLAG_EQ); + } + return ResultFlags; + } +}; + +template<> +struct OpHandlers { + static float handle4(X80SoftFloat src) { + return src; + } + + static double handle8(X80SoftFloat src) { + return src; + } +}; + +template<> +struct OpHandlers { + static int16_t handle2(X80SoftFloat src) { + return src; + } + + static int32_t handle4(X80SoftFloat src) { + return src; + } + + static int64_t handle8(X80SoftFloat src) { + return src; + } + + static int16_t handle2t(X80SoftFloat src) { + auto rv = extF80_to_i32(src, softfloat_round_minMag, false); + + if (rv > INT16_MAX) { + return INT16_MAX; + } else if (rv < INT16_MIN) { + return INT16_MIN; + } else { + return rv; + } + } + + static int32_t handle4t(X80SoftFloat src) { + return extF80_to_i32(src, softfloat_round_minMag, false); + } + + static int64_t handle8t(X80SoftFloat src) { + return extF80_to_i64(src, softfloat_round_minMag, false); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle2(int16_t src) { + return src; + } + + static X80SoftFloat handle4(int32_t src) { + return src; + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::FRNDINT(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::F2XM1(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::FTAN(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::FSQRT(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::FSIN(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::FCOS(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::FXTRACT_EXP(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + return X80SoftFloat::FXTRACT_SIG(Src1); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FADD(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FSUB(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FMUL(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FDIV(Src1, Src2); + } +}; + + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FYL2X(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FATAN(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FREM1(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FREM(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { + return X80SoftFloat::FSCALE(Src1, Src2); + } +}; + +template<> +struct OpHandlers { + static double handle(double src) { + return sin(src); + } +}; + +template<> +struct OpHandlers { + static double handle(double src) { + return cos(src); + } +}; + +template<> +struct OpHandlers { + static double handle(double src) { + return tan(src); + } +}; + +template<> +struct OpHandlers { + static double handle(double src) { + return exp2(src) - 1.0; + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return atan2(src1, src2); + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return fmod(src1, src2); + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return remainder(src1, src2); + } +}; + + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return src2 * log2(src1); + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + double trunc = (double)(int64_t)(src2); //truncate + return src1 * exp2(trunc); + } +}; + + + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src1) { + bool Negative = Src1.Sign; + + Src1 = X80SoftFloat::FRNDINT(Src1); + + // Clear the Sign bit + Src1.Sign = 0; + + uint64_t Tmp = Src1; + X80SoftFloat Rv; + uint8_t *BCD = reinterpret_cast(&Rv); + memset(BCD, 0, 10); + + for (size_t i = 0; i < 9; ++i) { + if (Tmp == 0) { + // Nothing left? Just leave + break; + } + // Extract the lower 100 values + uint8_t Digit = Tmp % 100; + + // Now divide it for the next iteration + Tmp /= 100; + + uint8_t UpperNibble = Digit / 10; + uint8_t LowerNibble = Digit % 10; + + // Now store the BCD + BCD[i] = (UpperNibble << 4) | LowerNibble; + } + + // Set negative flag once converted to x87 + BCD[9] = Negative ? 0x80 : 0; + + return Rv; + } +}; + +template<> +struct OpHandlers { + static X80SoftFloat handle(X80SoftFloat Src) { + uint8_t *Src1 = reinterpret_cast(&Src); + uint64_t BCD{}; + // We walk through each uint8_t and pull out the BCD encoding + // Each 4bit split is a digit + // Only 0-9 is supported, A-F results in undefined data + // | 4 bit | 4 bit | + // | 10s place | 1s place | + // EG 0x48 = 48 + // EG 0x4847 = 4847 + // This gives us an 18digit value encoded in BCD + // The last byte lets us know if it negative or not + for (size_t i = 0; i < 9; ++i) { + uint8_t Digit = Src1[8 - i]; + // First shift our last value over + BCD *= 100; + + // Add the tens place digit + BCD += (Digit >> 4) * 10; + + // Add the ones place digit + BCD += Digit & 0xF; + } + + // Set negative flag once converted to x87 + bool Negative = Src1[9] & 0x80; + X80SoftFloat Tmp; + + Tmp = BCD; + Tmp.Sign = Negative; + return Tmp; + } +}; + +template<> +struct OpHandlers { + static void handle(uint16_t NewFCW) { + + auto PC = (NewFCW >> 8) & 3; + switch(PC) { + case 0: extF80_roundingPrecision = 32; break; + case 2: extF80_roundingPrecision = 64; break; + case 3: extF80_roundingPrecision = 80; break; + case 1: LOGMAN_MSG_A_FMT("Invalid x87 precision mode, {}", PC); + } + + auto RC = (NewFCW >> 10) & 3; + switch(RC) { + case 0: + softfloat_roundingMode = softfloat_round_near_even; + break; + case 1: + softfloat_roundingMode = softfloat_round_min; + break; + case 2: + softfloat_roundingMode = softfloat_round_max; + break; + case 3: + softfloat_roundingMode = softfloat_round_minMag; + break; + } + } +}; + +} // namespace FEXCore::CPU diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h new file mode 100644 index 000000000..a35b732e8 --- /dev/null +++ b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h @@ -0,0 +1,75 @@ +#pragma once + +#include + +namespace FEXCore::IR { +enum IROps : uint8_t; +} + +namespace FEXCore::CPU { + +// Base template for fallback handling. +// +// Registering and hooking up fallback is currently like so: +// +// 1. Go to InterpreterFallbacks.cpp and create a template specialization of +// the GetFallbackInfo member function. +// +// This member function should reasonably define what the fallback you're +// going to create will take as parameters and return as a result. For example: +// +// template<> +// FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(double), Core::FallbackHandlerIndex Index) { +// return {FABI_F80_F64, (void*)fn, Index}; +// } +// +// Defines info about a fallback that takes a double as an argument and +// returns a X80SoftFloat instance. +// +// You will also want to define a new FallbackHandlerIndex enum member and use it +// to set up the new info handler into the Info array in FillFallbackIndexPointers. +// +// 1.1. (potentially optional). Define a new ABI element in the FallbackAPI enum. +// This ABI enum value will be used to tell the JITs how to handle the fallback +// properly. These enum values specify the return type followed by its argument types. +// +// So, FABI_I64_F80_F80, for example indicates that the function will behave like a +// function as if were defined as: +// +// uint64_t fn(X80SoftFloat, X80SoftFloat) +// +// 1.2. (potentially optional). If you needed to define a new enum ABI type like in 1.1, then +// you need to add the handling for it in the JITs, which can be found in the respective +// JIT's JIT.cpp file in a function called Op_Unhandled +// +// You need to add a new case to the ABI switch statement using the new ABI type +// and do the necessary moving of data from register-allocated JIT parameters +// into that platform's registers that respects the calling convention. After this is +// done, most of the necessary background boilerplate is finished. +// +// 2. Now, make a specialization of this class with a member function named 'handle()' +// that takes the same parameters as the ones described in the fallback info function +// specialization. +// +// For example, if you have the fallback info from the example in step 1, it would be: +// +// template <> +// struct OpHandlers { +// static X80SoftFloat handle(double src) { +// return ...; +// } +// }; +// +// 3. Fill out the behavior of the OpHandler specialization to perform what you would like +// the fallback to do. +// +// 4. Add an implementation of the IR op to the Interpreter that passes through to the +// OpHandler implementation. +// +// 5. Done. +// +template +struct OpHandlers { +}; + +} // namespace FEXCore::CPU diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp similarity index 99% rename from External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp rename to External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp index a43230911..2eace11dc 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp @@ -1,6 +1,8 @@ -#include "FEXCore/Core/CoreState.h" +#include + #include "Interface/Core/Interpreter/InterpreterOps.h" -#include "Interface/Core/Interpreter/F80Ops.h" +#include "Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h" +#include "Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h" #include #include diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h similarity index 59% rename from External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h rename to External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h index 8971575d8..6e2a976f2 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h +++ b/External/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h @@ -1,399 +1,16 @@ #pragma once -#include "Common/SoftFloat.h" -#include "Common/SoftFloat-3e/softfloat.h" + +#include +#include +#include +#include +#include #include +#include "Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h" + namespace FEXCore::CPU { -template -struct OpHandlers { - -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle4(float src) { - return src; - } - - static X80SoftFloat handle8(double src) { - return src; - } -}; - -template<> -struct OpHandlers { - template - static uint64_t handle(X80SoftFloat Src1, X80SoftFloat Src2) { - bool eq, lt, nan; - uint64_t ResultFlags = 0; - - X80SoftFloat::FCMP(Src1, Src2, &eq, <, &nan); - if (Flags & (1 << IR::FCMP_FLAG_LT) && - lt) { - ResultFlags |= (1 << IR::FCMP_FLAG_LT); - } - if (Flags & (1 << IR::FCMP_FLAG_UNORDERED) && - nan) { - ResultFlags |= (1 << IR::FCMP_FLAG_UNORDERED); - } - if (Flags & (1 << IR::FCMP_FLAG_EQ) && - eq) { - ResultFlags |= (1 << IR::FCMP_FLAG_EQ); - } - return ResultFlags; - } -}; - -template<> -struct OpHandlers { - static float handle4(X80SoftFloat src) { - return src; - } - - static double handle8(X80SoftFloat src) { - return src; - } -}; - -template<> -struct OpHandlers { - static int16_t handle2(X80SoftFloat src) { - return src; - } - - static int32_t handle4(X80SoftFloat src) { - return src; - } - - static int64_t handle8(X80SoftFloat src) { - return src; - } - - static int16_t handle2t(X80SoftFloat src) { - auto rv = extF80_to_i32(src, softfloat_round_minMag, false); - - if (rv > INT16_MAX) { - return INT16_MAX; - } else if (rv < INT16_MIN) { - return INT16_MIN; - } else { - return rv; - } - } - - static int32_t handle4t(X80SoftFloat src) { - return extF80_to_i32(src, softfloat_round_minMag, false); - } - - static int64_t handle8t(X80SoftFloat src) { - return extF80_to_i64(src, softfloat_round_minMag, false); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle2(int16_t src) { - return src; - } - - static X80SoftFloat handle4(int32_t src) { - return src; - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::FRNDINT(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::F2XM1(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::FTAN(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::FSQRT(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::FSIN(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::FCOS(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::FXTRACT_EXP(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - return X80SoftFloat::FXTRACT_SIG(Src1); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FADD(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FSUB(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FMUL(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FDIV(Src1, Src2); - } -}; - - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FYL2X(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FATAN(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FREM1(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FREM(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1, X80SoftFloat Src2) { - return X80SoftFloat::FSCALE(Src1, Src2); - } -}; - -template<> -struct OpHandlers { - static double handle(double src) { - return sin(src); - } -}; - -template<> -struct OpHandlers { - static double handle(double src) { - return cos(src); - } -}; - -template<> -struct OpHandlers { - static double handle(double src) { - return tan(src); - } -}; - -template<> -struct OpHandlers { - static double handle(double src) { - return exp2(src) - 1.0; - } -}; - -template<> -struct OpHandlers { - static double handle(double src1, double src2) { - return atan2(src1, src2); - } -}; - -template<> -struct OpHandlers { - static double handle(double src1, double src2) { - return fmod(src1, src2); - } -}; - -template<> -struct OpHandlers { - static double handle(double src1, double src2) { - return remainder(src1, src2); - } -}; - - -template<> -struct OpHandlers { - static double handle(double src1, double src2) { - return src2 * log2(src1); - } -}; - -template<> -struct OpHandlers { - static double handle(double src1, double src2) { - double trunc = (double)(int64_t)(src2); //truncate - return src1 * exp2(trunc); - } -}; - - - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src1) { - bool Negative = Src1.Sign; - - Src1 = X80SoftFloat::FRNDINT(Src1); - - // Clear the Sign bit - Src1.Sign = 0; - - uint64_t Tmp = Src1; - X80SoftFloat Rv; - uint8_t *BCD = reinterpret_cast(&Rv); - memset(BCD, 0, 10); - - for (size_t i = 0; i < 9; ++i) { - if (Tmp == 0) { - // Nothing left? Just leave - break; - } - // Extract the lower 100 values - uint8_t Digit = Tmp % 100; - - // Now divide it for the next iteration - Tmp /= 100; - - uint8_t UpperNibble = Digit / 10; - uint8_t LowerNibble = Digit % 10; - - // Now store the BCD - BCD[i] = (UpperNibble << 4) | LowerNibble; - } - - // Set negative flag once converted to x87 - BCD[9] = Negative ? 0x80 : 0; - - return Rv; - } -}; - -template<> -struct OpHandlers { - static X80SoftFloat handle(X80SoftFloat Src) { - uint8_t *Src1 = reinterpret_cast(&Src); - uint64_t BCD{}; - // We walk through each uint8_t and pull out the BCD encoding - // Each 4bit split is a digit - // Only 0-9 is supported, A-F results in undefined data - // | 4 bit | 4 bit | - // | 10s place | 1s place | - // EG 0x48 = 48 - // EG 0x4847 = 4847 - // This gives us an 18digit value encoded in BCD - // The last byte lets us know if it negative or not - for (size_t i = 0; i < 9; ++i) { - uint8_t Digit = Src1[8 - i]; - // First shift our last value over - BCD *= 100; - - // Add the tens place digit - BCD += (Digit >> 4) * 10; - - // Add the ones place digit - BCD += Digit & 0xF; - } - - // Set negative flag once converted to x87 - bool Negative = Src1[9] & 0x80; - X80SoftFloat Tmp; - - Tmp = BCD; - Tmp.Sign = Negative; - return Tmp; - } -}; - -template<> -struct OpHandlers { - static void handle(uint16_t NewFCW) { - - auto PC = (NewFCW >> 8) & 3; - switch(PC) { - case 0: extF80_roundingPrecision = 32; break; - case 2: extF80_roundingPrecision = 64; break; - case 3: extF80_roundingPrecision = 80; break; - case 1: LOGMAN_MSG_A_FMT("Invalid x87 precision mode, {}", PC); - } - - auto RC = (NewFCW >> 10) & 3; - switch(RC) { - case 0: - softfloat_roundingMode = softfloat_round_near_even; - break; - case 1: - softfloat_roundingMode = softfloat_round_min; - break; - case 2: - softfloat_roundingMode = softfloat_round_max; - break; - case 3: - softfloat_roundingMode = softfloat_round_minMag; - break; - } - } -}; template<> struct OpHandlers { @@ -739,4 +356,4 @@ struct OpHandlers { } }; -} +} // namespace FEXCore::CPU diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp index 4030cadec..61a3f4cc8 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp @@ -2,7 +2,6 @@ #include "Interface/Core/CPUID.h" #include "InterpreterDefines.h" #include "InterpreterOps.h" -#include "F80Ops.h" #ifdef _M_ARM_64 #include "Interface/Core/ArchHelpers/Arm64.h" diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/VectorOps.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/VectorOps.cpp index 3c8728b1f..66ce688d6 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/VectorOps.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/VectorOps.cpp @@ -8,6 +8,8 @@ $end_info$ #include "Interface/Core/Interpreter/InterpreterOps.h" #include "Interface/Core/Interpreter/InterpreterDefines.h" +#include "Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h" + #include #include @@ -2276,6 +2278,24 @@ DEF_OP(VRev64) { memcpy(GDP, Tmp, OpSize); } +DEF_OP(VPCMPESTRX) { + const auto Op = IROp->C(); + const auto Is64Bit = Op->GPRSize == 8; + + const auto RAX = *GetSrc(Data->SSAData, Op->RAX); + const auto RDX = *GetSrc(Data->SSAData, Op->RDX);; + const auto LHS = *GetSrc<__uint128_t*>(Data->SSAData, Op->LHS); + const auto RHS = *GetSrc<__uint128_t*>(Data->SSAData, Op->RHS); + + // We can be cheeky and encode the size at bit 8 to save a parameter + const auto Control = Op->Control | (uint16_t(Is64Bit) << 8); + + const auto Result = OpHandlers::handle(RAX, RDX, LHS, RHS, Control); + + memset(GDP, 0, sizeof(uint64_t)); + memcpy(GDP, &Result, sizeof(Result)); +} + #undef DEF_OP } // namespace FEXCore::CPU