From 3cd1e0ee8f52ca856cb33dee92dce840ae625d83 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 27 Mar 2020 18:17:25 -0700 Subject: [PATCH] Adds new vector ops to the interpreter --- .../Core/Interpreter/InterpreterCore.cpp | 298 +++++++++++++++--- 1 file changed, 260 insertions(+), 38 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index b6c195365..d89295e1b 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -1999,6 +1999,17 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { } \ break; \ } + #define DO_VECTOR_PAIR_OP(size, type, func) \ + case size: { \ + auto *Dst_d = reinterpret_cast(Tmp); \ + auto *Src1_d = reinterpret_cast(Src1); \ + auto *Src2_d = reinterpret_cast(Src2); \ + for (uint8_t i = 0; i < Elements; ++i) { \ + Dst_d[i] = func(Src1_d[i*2], Src1_d[i*2 + 1]); \ + Dst_d[i+Elements] = func(Src2_d[i*2], Src2_d[i*2 + 1]); \ + } \ + break; \ + } #define DO_VECTOR_SCALAR_OP(size, type, func)\ case size: { \ auto *Dst_d = reinterpret_cast(Tmp); \ @@ -2201,6 +2212,35 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { memcpy(GDP, Tmp, Op->RegisterSize); break; } + case IR::OP_VSQSUB: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + uint8_t Tmp[16]; + + uint8_t Elements = Op->RegisterSize / Op->ElementSize; + + auto Func = [](auto a, auto b) { + __int128_t res = a - b; + if (res < std::numeric_limits::min()) + return std::numeric_limits::min(); + + if (res > std::numeric_limits::max()) + return std::numeric_limits::max(); + return (decltype(a))res; + }; + + switch (Op->ElementSize) { + DO_VECTOR_OP(1, int8_t, Func) + DO_VECTOR_OP(2, int16_t, Func) + DO_VECTOR_OP(4, int32_t, Func) + DO_VECTOR_OP(8, int64_t, Func) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VFADD: { auto Op = IROp->C(); void *Src1 = GetSrc(Op->Header.Args[0]); @@ -2235,6 +2275,25 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { memcpy(GDP, Tmp, Op->RegisterSize); break; } + case IR::OP_VADDP: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + uint8_t Tmp[16]; + + uint8_t Elements = Op->RegisterSize / Op->ElementSize; + + auto Func = [](auto a, auto b) { return a + b; }; + switch (Op->ElementSize) { + DO_VECTOR_PAIR_OP(1, uint8_t, Func) + DO_VECTOR_PAIR_OP(2, uint16_t, Func) + DO_VECTOR_PAIR_OP(4, uint32_t, Func) + DO_VECTOR_PAIR_OP(8, uint64_t, Func) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } case IR::OP_VFMUL: { auto Op = IROp->C(); void *Src1 = GetSrc(Op->Header.Args[0]); @@ -2351,22 +2410,32 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { memcpy(GDP, Tmp, Op->RegisterSize); break; } - #define DO_VECTOR_1SRC_2TYPE_OP(size, type, type2, func, max) \ + #define DO_VECTOR_1SRC_2TYPE_OP(size, type, type2, func, min, max) \ case size: { \ auto *Dst_d = reinterpret_cast(Tmp); \ auto *Src_d = reinterpret_cast(Src); \ for (uint8_t i = 0; i < Elements; ++i) { \ - Dst_d[i] = (type)func(Src_d[i], max); \ + Dst_d[i] = (type)func(Src_d[i], min, max); \ } \ break; \ } - #define DO_VECTOR_1SRC_2TYPE_OP_TOP(size, type, type2, func, max) \ + #define DO_VECTOR_1SRC_2TYPE_OP_TOP(size, type, type2, func, min, max) \ case size: { \ auto *Dst_d = reinterpret_cast(Tmp); \ auto *Src_d = reinterpret_cast(Src2); \ memcpy(Dst_d, Src1, Elements * sizeof(type2));\ for (uint8_t i = 0; i < Elements; ++i) { \ - Dst_d[i+Elements] = (type)func(Src_d[i], max); \ + Dst_d[i+Elements] = (type)func(Src_d[i], min, max); \ + } \ + break; \ + } + + #define DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(size, type, type2, func, min, max) \ + case size: { \ + auto *Dst_d = reinterpret_cast(Tmp); \ + auto *Src_d = reinterpret_cast(Src); \ + for (uint8_t i = 0; i < Elements; ++i) { \ + Dst_d[i] = (type)func(Src_d[i+Elements], min, max); \ } \ break; \ } @@ -2380,18 +2449,98 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { } \ break; \ } + #define DO_VECTOR_2SRC_2TYPE_OP_TOP_SRC(size, type, type2, func) \ + case size: { \ + auto *Dst_d = reinterpret_cast(Tmp); \ + auto *Src1_d = reinterpret_cast(Src1); \ + auto *Src2_d = reinterpret_cast(Src2); \ + for (uint8_t i = 0; i < Elements; ++i) { \ + Dst_d[i] = (type)func((type)Src1_d[i+Elements], (type)Src2_d[i+Elements]); \ + } \ + break; \ + } - case IR::OP_VSQXTUN: { - auto Op = IROp->C(); + case IR::OP_VUSHRNI: { + auto Op = IROp->C(); void *Src = GetSrc(Op->Header.Args[0]); + uint8_t BitShift = Op->BitShift; + uint8_t Tmp[16]{}; + + uint8_t Elements = Op->RegisterSize / Op->ElementSize; + + auto Func = [BitShift](auto a, auto min, auto max) { return BitShift >= (sizeof(a) * 8) ? 0 : a >> BitShift; }; + switch (Op->ElementSize) { + DO_VECTOR_1SRC_2TYPE_OP(2, uint8_t, uint16_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, uint16_t, uint32_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(8, uint32_t, uint64_t, Func, 0, 0) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VUSHRNI2: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + uint8_t BitShift = Op->BitShift; uint8_t Tmp[16]; uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return std::max(std::min(a, (decltype(a))max), (decltype(a))0); }; + auto Func = [BitShift](auto a, auto min, auto max) { return BitShift >= (sizeof(a) * 8) ? 0 : a >> BitShift; }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(2, uint8_t, int16_t, Func, (1 << 8) - 1) - DO_VECTOR_1SRC_2TYPE_OP(4, uint16_t, int32_t, Func, (1 << 16) - 1) + DO_VECTOR_1SRC_2TYPE_OP_TOP(2, uint8_t, uint16_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP_TOP(4, uint16_t, uint32_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP_TOP(8, uint32_t, uint64_t, Func, 0, 0) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VSQXTN: { + auto Op = IROp->C(); + void *Src = GetSrc(Op->Header.Args[0]); + uint8_t Tmp[16]{}; + + uint8_t Elements = Op->RegisterSize / Op->ElementSize; + + auto Func = [](auto a, auto min, auto max) { return std::max(std::min(a, (decltype(a))max), (decltype(a))min); }; + switch (Op->ElementSize) { + DO_VECTOR_1SRC_2TYPE_OP(2, int8_t, int16_t, Func, std::numeric_limits::min(), std::numeric_limits::max()) + DO_VECTOR_1SRC_2TYPE_OP(4, int16_t, int32_t, Func, std::numeric_limits::min(), std::numeric_limits::max()) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VSQXTN2: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + uint8_t Tmp[16]{}; + + uint8_t Elements = Op->RegisterSize / Op->ElementSize; + + auto Func = [](auto a, auto min, auto max) { return std::max(std::min(a, (decltype(a))max), (decltype(a))min); }; + switch (Op->ElementSize) { + DO_VECTOR_1SRC_2TYPE_OP_TOP(2, int8_t, int16_t, Func, std::numeric_limits::min(), std::numeric_limits::max()) + DO_VECTOR_1SRC_2TYPE_OP_TOP(4, int16_t, int32_t, Func, std::numeric_limits::min(), std::numeric_limits::max()) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VSQXTUN: { + auto Op = IROp->C(); + void *Src = GetSrc(Op->Header.Args[0]); + uint8_t Tmp[16]{}; + + uint8_t Elements = Op->RegisterSize / Op->ElementSize; + + auto Func = [](auto a, auto min, auto max) { return std::max(std::min(a, (decltype(a))max), (decltype(a))min); }; + switch (Op->ElementSize) { + DO_VECTOR_1SRC_2TYPE_OP(2, uint8_t, int16_t, Func, 0, (1 << 8) - 1) + DO_VECTOR_1SRC_2TYPE_OP(4, uint16_t, int32_t, Func, 0, (1 << 16) - 1) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -2401,14 +2550,14 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { auto Op = IROp->C(); void *Src1 = GetSrc(Op->Header.Args[0]); void *Src2 = GetSrc(Op->Header.Args[1]); - uint8_t Tmp[16]; + uint8_t Tmp[16]{}; uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return std::max(std::min(a, (decltype(a))max), (decltype(a))0); }; + auto Func = [](auto a, auto min, auto max) { return std::max(std::min(a, (decltype(a))max), (decltype(a))min); }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP_TOP(2, uint8_t, int16_t, Func, (1 << 8) - 1) - DO_VECTOR_1SRC_2TYPE_OP_TOP(4, uint16_t, int32_t, Func, (1 << 16) - 1) + DO_VECTOR_1SRC_2TYPE_OP_TOP(2, uint8_t, int16_t, Func, 0, (1 << 8) - 1) + DO_VECTOR_1SRC_2TYPE_OP_TOP(4, uint16_t, int32_t, Func, 0, (1 << 16) - 1) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -2421,10 +2570,10 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return a; }; + auto Func = [](auto a, auto min, auto max) { return a; }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(4, float, uint32_t, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(8, double, uint64_t, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, float, uint32_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(8, double, uint64_t, Func, 0, 0) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -2437,10 +2586,10 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return a; }; + auto Func = [](auto a, auto min, auto max) { return a; }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(4, float, int32_t, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(8, double, int64_t, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, float, int32_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(8, double, int64_t, Func, 0, 0) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -2453,10 +2602,10 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return a; }; + auto Func = [](auto a, auto min, auto max) { return a; }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(4, uint32_t, float, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(8, uint64_t, double, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, uint32_t, float, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(8, uint64_t, double, Func, 0, 0) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -2469,10 +2618,10 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return a; }; + auto Func = [](auto a, auto min, auto max) { return a; }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(4, int32_t, float, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(8, int64_t, double, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, int32_t, float, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(8, int64_t, double, Func, 0, 0) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -2554,18 +2703,73 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { memcpy(GDP, Tmp, Op->RegisterSize); break; } + case IR::OP_VUMULL2: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + + uint8_t Tmp[16]; + + uint8_t Elements = Op->RegisterSize / (Op->ElementSize << 1); + + auto Func = [](auto a, auto b) { return a * b; }; + switch (Op->ElementSize) { + DO_VECTOR_2SRC_2TYPE_OP_TOP_SRC(1, uint16_t, uint8_t, Func) + DO_VECTOR_2SRC_2TYPE_OP_TOP_SRC(2, uint32_t, uint16_t, Func) + DO_VECTOR_2SRC_2TYPE_OP_TOP_SRC(4, uint64_t, uint32_t, Func) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VSMULL2: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + + uint8_t Tmp[16]; + + uint8_t Elements = Op->RegisterSize / (Op->ElementSize << 1); + + auto Func = [](auto a, auto b) { return a * b; }; + switch (Op->ElementSize) { + DO_VECTOR_2SRC_2TYPE_OP_TOP_SRC(1, int16_t, int8_t, Func) + DO_VECTOR_2SRC_2TYPE_OP_TOP_SRC(2, int32_t, int16_t, Func) + DO_VECTOR_2SRC_2TYPE_OP_TOP_SRC(4, int64_t, int32_t, Func) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } case IR::OP_VSXTL: { auto Op = IROp->C(); void *Src = GetSrc(Op->Header.Args[0]); - uint8_t Tmp[16]; + uint8_t Tmp[16]{}; uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return a; }; + auto Func = [](auto a, auto min, auto max) { return a; }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(1, int16_t, int8_t, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(2, int32_t, int16_t, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(4, int64_t, int32_t, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(1, int16_t, int8_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(2, int32_t, int16_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, int64_t, int32_t, Func, 0, 0) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VSXTL2: { + auto Op = IROp->C(); + void *Src = GetSrc(Op->Header.Args[0]); + uint8_t Tmp[16]; + + uint8_t Elements = Op->RegisterSize / (Op->ElementSize << 1); + + auto Func = [](auto a, auto min, auto max) { return a; }; + switch (Op->ElementSize) { + DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(1, int16_t, int8_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(2, int32_t, int16_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(4, int64_t, int32_t, Func, 0, 0) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -2574,15 +2778,33 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { case IR::OP_VUXTL: { auto Op = IROp->C(); void *Src = GetSrc(Op->Header.Args[0]); - uint8_t Tmp[16]; + uint8_t Tmp[16]{}; uint8_t Elements = Op->RegisterSize / Op->ElementSize; - auto Func = [](auto a, auto max) { return a; }; + auto Func = [](auto a, auto min, auto max) { return a; }; switch (Op->ElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(1, uint16_t, uint8_t, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(2, uint32_t, uint16_t, Func, 0) - DO_VECTOR_1SRC_2TYPE_OP(4, uint64_t, uint32_t, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(1, uint16_t, uint8_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(2, uint32_t, uint16_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, uint64_t, uint32_t, Func, 0, 0) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } + case IR::OP_VUXTL2: { + auto Op = IROp->C(); + void *Src = GetSrc(Op->Header.Args[0]); + + uint8_t Tmp[16]; + + uint8_t Elements = Op->RegisterSize / (Op->ElementSize << 1); + + auto Func = [](auto a, auto min, auto max) { return a; }; + switch (Op->ElementSize) { + DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(1, uint16_t, uint8_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(2, uint32_t, uint16_t, Func, 0, 0) + DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(4, uint64_t, uint32_t, Func, 0, 0) default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; } memcpy(GDP, Tmp, Op->RegisterSize); @@ -3221,19 +3443,19 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { uint16_t Conv = (Op->DstElementSize << 8) | Op->SrcElementSize; - auto Func = [](auto a, auto max) { return a; }; + auto Func = [](auto a, auto min, auto max) { return a; }; switch (Conv) { case 0x0804: { // Double <- float uint8_t Elements = Op->RegisterSize / Op->SrcElementSize; switch (Op->SrcElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(4, double, float, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(4, double, float, Func, 0, 0) } break; } case 0x0408: { // Float <- Double uint8_t Elements = Op->RegisterSize / Op->SrcElementSize; switch (Op->SrcElementSize) { - DO_VECTOR_1SRC_2TYPE_OP(8, float, double, Func, 0) + DO_VECTOR_1SRC_2TYPE_OP(8, float, double, Func, 0, 0) } break;