diff --git a/FEXCore/Source/Common/BitSet.h b/FEXCore/Source/Common/BitSet.h index 0649665c8..ce3002580 100644 --- a/FEXCore/Source/Common/BitSet.h +++ b/FEXCore/Source/Common/BitSet.h @@ -18,7 +18,7 @@ struct BitSet final { constexpr static size_t MinimumSize = sizeof(ElementType); constexpr static size_t MinimumSizeBits = sizeof(ElementType) * 8; - ElementType *Memory; + ElementType* Memory; void Allocate(size_t Elements) { size_t AllocateSize = AlignUp(Elements, MinimumSizeBits) / MinimumSize; LOGMAN_THROW_AA_FMT((AllocateSize * MinimumSize) >= Elements, "Fail"); @@ -62,11 +62,10 @@ struct BitSetView final { constexpr static size_t MinimumSize = sizeof(ElementType); constexpr static size_t MinimumSizeBits = sizeof(ElementType) * 8; - ElementType *Memory; + ElementType* Memory; - void GetView(BitSet &Set, uint64_t ElementOffset) { - LOGMAN_THROW_AA_FMT((ElementOffset % MinimumSize) == 0, - "Bitset view offset needs to be aligned to size of backing element"); + void GetView(BitSet& Set, uint64_t ElementOffset) { + LOGMAN_THROW_AA_FMT((ElementOffset % MinimumSize) == 0, "Bitset view offset needs to be aligned to size of backing element"); Memory = &Set.Memory[ElementOffset / MinimumSizeBits]; } diff --git a/FEXCore/Source/Common/JitSymbols.cpp b/FEXCore/Source/Common/JitSymbols.cpp index 662215c0d..79e3ff31f 100644 --- a/FEXCore/Source/Common/JitSymbols.cpp +++ b/FEXCore/Source/Common/JitSymbols.cpp @@ -7,133 +7,142 @@ #include namespace FEXCore { - JITSymbols::JITSymbols() { - } +JITSymbols::JITSymbols() {} - JITSymbols::~JITSymbols() { - if (fd != -1) { - close(fd); - } +JITSymbols::~JITSymbols() { + if (fd != -1) { + close(fd); } +} - void JITSymbols::InitFile() { - // We can't use FILE here since we must be robust against forking processes closing our FD from under us. +void JITSymbols::InitFile() { + // We can't use FILE here since we must be robust against forking processes closing our FD from under us. #ifdef __ANDROID__ - // Android simpleperf looks in /data/local/tmp instead of /tmp - const auto PerfMap = fextl::fmt::format("/data/local/tmp/perf-{}.map", getpid()); + // Android simpleperf looks in /data/local/tmp instead of /tmp + const auto PerfMap = fextl::fmt::format("/data/local/tmp/perf-{}.map", getpid()); #else - const auto PerfMap = fextl::fmt::format("/tmp/perf-{}.map", getpid()); + const auto PerfMap = fextl::fmt::format("/tmp/perf-{}.map", getpid()); #endif - fd = open(PerfMap.c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644); + fd = open(PerfMap.c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644); +} + +void JITSymbols::RegisterNamedRegion(const void* HostAddr, uint32_t CodeSize, std::string_view Name) { + if (fd == -1) { + return; } - void JITSymbols::RegisterNamedRegion(const void *HostAddr, uint32_t CodeSize, std::string_view Name) { - if (fd == -1) return; + // Linux perf format is very straightforward + // ` \n` + const auto Buffer = fextl::fmt::format("{} {:x} {}\n", HostAddr, CodeSize, Name); + auto Result = write(fd, Buffer.c_str(), Buffer.size()); + if (Result == -1 && errno == EBADF) { + fd = -1; + } +} - // Linux perf format is very straightforward - // ` \n` - const auto Buffer = fextl::fmt::format("{} {:x} {}\n", HostAddr, CodeSize, Name); - auto Result = write(fd, Buffer.c_str(), Buffer.size()); - if (Result == -1 && errno == EBADF) { - fd = -1; - } +void JITSymbols::RegisterJITSpace(const void* HostAddr, uint32_t CodeSize) { + if (fd == -1) { + return; } - void JITSymbols::RegisterJITSpace(const void *HostAddr, uint32_t CodeSize) { - if (fd == -1) return; + // Linux perf format is very straightforward + // ` \n` + const auto Buffer = fextl::fmt::format("{} {:x} FEXJIT\n", HostAddr, CodeSize); + auto Result = write(fd, Buffer.c_str(), Buffer.size()); + if (Result == -1 && errno == EBADF) { + fd = -1; + } +} - // Linux perf format is very straightforward - // ` \n` - const auto Buffer = fextl::fmt::format("{} {:x} FEXJIT\n", HostAddr, CodeSize); - auto Result = write(fd, Buffer.c_str(), Buffer.size()); - if (Result == -1 && errno == EBADF) { - fd = -1; - } +// Buffered JIT symbols. +void JITSymbols::Register(Core::JITSymbolBuffer* Buffer, const void* HostAddr, uint64_t GuestAddr, uint32_t CodeSize) { + if (fd == -1) { + return; } - // Buffered JIT symbols. - void JITSymbols::Register(Core::JITSymbolBuffer *Buffer, const void *HostAddr, uint64_t GuestAddr, uint32_t CodeSize) { - if (fd == -1) return; + // Calculate remaining sizes. + const auto RemainingSize = Buffer->BUFFER_SIZE - Buffer->Offset; + const auto CurrentBufferOffset = &Buffer->Buffer[Buffer->Offset]; - // Calculate remaining sizes. - const auto RemainingSize = Buffer->BUFFER_SIZE - Buffer->Offset; - const auto CurrentBufferOffset = &Buffer->Buffer[Buffer->Offset]; + // Linux perf format is very straightforward + // ` \n` + const auto FMTResult = fmt::format_to_n(CurrentBufferOffset, RemainingSize, "{} {:x} JIT_0x{:x}_{}\n", HostAddr, CodeSize, GuestAddr, HostAddr); + if (FMTResult.out >= &Buffer->Buffer[Buffer->BUFFER_SIZE]) { + // Couldn't fit, need to force a write. + WriteBuffer(Buffer, true); + // Rerun + Register(Buffer, HostAddr, GuestAddr, CodeSize); + return; + } - // Linux perf format is very straightforward - // ` \n` - const auto FMTResult = fmt::format_to_n(CurrentBufferOffset, RemainingSize, "{} {:x} JIT_0x{:x}_{}\n", HostAddr, CodeSize, GuestAddr, HostAddr); - if (FMTResult.out >= &Buffer->Buffer[Buffer->BUFFER_SIZE]) { - // Couldn't fit, need to force a write. - WriteBuffer(Buffer, true); - // Rerun - Register(Buffer, HostAddr, GuestAddr, CodeSize); + Buffer->Offset += FMTResult.size; + WriteBuffer(Buffer); +} + +void JITSymbols::Register(Core::JITSymbolBuffer* Buffer, const void* HostAddr, uint32_t CodeSize, std::string_view Name, uintptr_t Offset) { + if (fd == -1) { + return; + } + + // Calculate remaining sizes. + const auto RemainingSize = Buffer->BUFFER_SIZE - Buffer->Offset; + const auto CurrentBufferOffset = &Buffer->Buffer[Buffer->Offset]; + + // Linux perf format is very straightforward + // ` \n` + const auto FMTResult = + fmt::format_to_n(CurrentBufferOffset, RemainingSize, "{} {:x} {}+0x{:x} ({})\n", HostAddr, CodeSize, Name, Offset, HostAddr); + if (FMTResult.out >= &Buffer->Buffer[Buffer->BUFFER_SIZE]) { + // Couldn't fit, need to force a write. + WriteBuffer(Buffer, true); + // Rerun + Register(Buffer, HostAddr, CodeSize, Name, Offset); + return; + } + + Buffer->Offset += FMTResult.size; + WriteBuffer(Buffer); +} + +void JITSymbols::RegisterNamedRegion(Core::JITSymbolBuffer* Buffer, const void* HostAddr, uint32_t CodeSize, std::string_view Name) { + if (fd == -1) { + return; + } + + // Calculate remaining sizes. + const auto RemainingSize = Buffer->BUFFER_SIZE - Buffer->Offset; + const auto CurrentBufferOffset = &Buffer->Buffer[Buffer->Offset]; + + // Linux perf format is very straightforward + // ` \n` + const auto FMTResult = fmt::format_to_n(CurrentBufferOffset, RemainingSize, "{} {:x} {}\n", HostAddr, CodeSize, Name); + if (FMTResult.out >= &Buffer->Buffer[Buffer->BUFFER_SIZE]) { + // Couldn't fit, need to force a write. + WriteBuffer(Buffer, true); + // Rerun + RegisterNamedRegion(Buffer, HostAddr, CodeSize, Name); + return; + } + + Buffer->Offset += FMTResult.size; + WriteBuffer(Buffer); +} + +void JITSymbols::WriteBuffer(Core::JITSymbolBuffer* Buffer, bool ForceWrite) { + auto Now = std::chrono::steady_clock::now(); + if (!ForceWrite) { + if (((Buffer->LastWrite - Now) < Buffer->MAXIMUM_THRESHOLD) && Buffer->Offset < Buffer->NEEDS_WRITE_DISTANCE) { + // Still buffering, no need to write. return; } - - Buffer->Offset += FMTResult.size; - WriteBuffer(Buffer); } - void JITSymbols::Register(Core::JITSymbolBuffer *Buffer, const void *HostAddr, uint32_t CodeSize, std::string_view Name, uintptr_t Offset) { - if (fd == -1) return; - - // Calculate remaining sizes. - const auto RemainingSize = Buffer->BUFFER_SIZE - Buffer->Offset; - const auto CurrentBufferOffset = &Buffer->Buffer[Buffer->Offset]; - - // Linux perf format is very straightforward - // ` \n` - const auto FMTResult = fmt::format_to_n(CurrentBufferOffset, RemainingSize, "{} {:x} {}+0x{:x} ({})\n", HostAddr, CodeSize, Name, Offset, HostAddr); - if (FMTResult.out >= &Buffer->Buffer[Buffer->BUFFER_SIZE]) { - // Couldn't fit, need to force a write. - WriteBuffer(Buffer, true); - // Rerun - Register(Buffer, HostAddr, CodeSize, Name, Offset); - return; - } - - Buffer->Offset += FMTResult.size; - WriteBuffer(Buffer); + Buffer->LastWrite = Now; + auto Result = write(fd, Buffer->Buffer, Buffer->Offset); + if (Result == -1 && errno == EBADF) { + fd = -1; } - void JITSymbols::RegisterNamedRegion(Core::JITSymbolBuffer *Buffer, const void *HostAddr, uint32_t CodeSize, std::string_view Name) { - if (fd == -1) return; - - // Calculate remaining sizes. - const auto RemainingSize = Buffer->BUFFER_SIZE - Buffer->Offset; - const auto CurrentBufferOffset = &Buffer->Buffer[Buffer->Offset]; - - // Linux perf format is very straightforward - // ` \n` - const auto FMTResult = fmt::format_to_n(CurrentBufferOffset, RemainingSize, "{} {:x} {}\n", HostAddr, CodeSize, Name); - if (FMTResult.out >= &Buffer->Buffer[Buffer->BUFFER_SIZE]) { - // Couldn't fit, need to force a write. - WriteBuffer(Buffer, true); - // Rerun - RegisterNamedRegion(Buffer, HostAddr, CodeSize, Name); - return; - } - - Buffer->Offset += FMTResult.size; - WriteBuffer(Buffer); - } - - void JITSymbols::WriteBuffer(Core::JITSymbolBuffer *Buffer, bool ForceWrite) { - auto Now = std::chrono::steady_clock::now(); - if (!ForceWrite) { - if (((Buffer->LastWrite - Now) < Buffer->MAXIMUM_THRESHOLD) && - Buffer->Offset < Buffer->NEEDS_WRITE_DISTANCE) { - // Still buffering, no need to write. - return; - } - } - - Buffer->LastWrite = Now; - auto Result = write(fd, Buffer->Buffer, Buffer->Offset); - if (Result == -1 && errno == EBADF) { - fd = -1; - } - - Buffer->Offset = 0; - } + Buffer->Offset = 0; +} } // namespace FEXCore diff --git a/FEXCore/Source/Common/JitSymbols.h b/FEXCore/Source/Common/JitSymbols.h index dd984ff2c..4e7aa3249 100644 --- a/FEXCore/Source/Common/JitSymbols.h +++ b/FEXCore/Source/Common/JitSymbols.h @@ -17,20 +17,20 @@ public: ~JITSymbols(); void InitFile(); - void RegisterNamedRegion(const void *HostAddr, uint32_t CodeSize, std::string_view Name); - void RegisterJITSpace(const void *HostAddr, uint32_t CodeSize); + void RegisterNamedRegion(const void* HostAddr, uint32_t CodeSize, std::string_view Name); + void RegisterJITSpace(const void* HostAddr, uint32_t CodeSize); // Allocate JIT buffer. static fextl::unique_ptr AllocateBuffer() { return fextl::make_unique(); } - void Register(Core::JITSymbolBuffer *Buffer, const void *HostAddr, uint64_t GuestAddr, uint32_t CodeSize); - void Register(Core::JITSymbolBuffer *Buffer, const void *HostAddr, uint32_t CodeSize, std::string_view Name, uintptr_t Offset); - void RegisterNamedRegion(Core::JITSymbolBuffer *Buffer, const void *HostAddr, uint32_t CodeSize, std::string_view Name); + void Register(Core::JITSymbolBuffer* Buffer, const void* HostAddr, uint64_t GuestAddr, uint32_t CodeSize); + void Register(Core::JITSymbolBuffer* Buffer, const void* HostAddr, uint32_t CodeSize, std::string_view Name, uintptr_t Offset); + void RegisterNamedRegion(Core::JITSymbolBuffer* Buffer, const void* HostAddr, uint32_t CodeSize, std::string_view Name); private: - int fd{-1}; - void WriteBuffer(Core::JITSymbolBuffer *Buffer, bool ForceWrite = false); + int fd {-1}; + void WriteBuffer(Core::JITSymbolBuffer* Buffer, bool ForceWrite = false); }; -} +} // namespace FEXCore diff --git a/FEXCore/Source/Common/SoftFloat.h b/FEXCore/Source/Common/SoftFloat.h index 597497ecb..96bf4f042 100644 --- a/FEXCore/Source/Common/SoftFloat.h +++ b/FEXCore/Source/Common/SoftFloat.h @@ -45,13 +45,13 @@ struct FEX_PACKED X80SoftFloat { uint16_t Exponent : 15; uint16_t Sign : 1; - X80SoftFloat() { memset(this, 0, sizeof(*this)); } + X80SoftFloat() { + memset(this, 0, sizeof(*this)); + } X80SoftFloat(uint16_t _Sign, uint16_t _Exponent, uint64_t _Significand) : Significand {_Significand} , Exponent {_Exponent} - , Sign {_Sign} - { - } + , Sign {_Sign} {} fextl::string str() const { fextl::ostringstream string; @@ -63,21 +63,19 @@ struct FEX_PACKED X80SoftFloat { } // Ops - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FADD(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FADD(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st1 fldt %[lhs]; # st0 faddp; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -85,21 +83,19 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FSUB(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FSUB(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st1 fldt %[lhs]; # st0 fsubp; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -107,21 +103,19 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FMUL(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FMUL(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st1 fldt %[lhs]; # st0 fmulp; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -129,21 +123,19 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FDIV(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FDIV(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st1 fldt %[lhs]; # st0 fdivp; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -151,11 +143,10 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FREM(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FREM(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { #if defined(DEBUG_X86_FLOAT) BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st1 fldt %[lhs]; # st0 @@ -163,10 +154,9 @@ struct FEX_PACKED X80SoftFloat { fstpt %[result]; ffreep %%st(0); )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -174,11 +164,10 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FREM1(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FREM1(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { #if defined(DEBUG_X86_FLOAT) BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st1 fldt %[lhs]; # st0 @@ -186,10 +175,9 @@ struct FEX_PACKED X80SoftFloat { fstpt %[result]; ffreep %%st(0); )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -197,30 +185,27 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FRNDINT(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FRNDINT(const X80SoftFloat& lhs) { return extF80_roundToInt(lhs, softfloat_roundingMode, false); } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FRNDINT(X80SoftFloat const &lhs, uint_fast8_t RoundMode) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FRNDINT(const X80SoftFloat& lhs, uint_fast8_t RoundMode) { return extF80_roundToInt(lhs, RoundMode, false); } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FXTRACT_SIG(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FXTRACT_SIG(const X80SoftFloat& lhs) { #if defined(DEBUG_X86_FLOAT) BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; # st0 fxtract; fstpt %[result]; ffreep %%st(0); )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs) + : "st", "st(1)"); return Result; #else @@ -231,20 +216,19 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FXTRACT_EXP(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FXTRACT_EXP(const X80SoftFloat& lhs) { #if defined(DEBUG_X86_FLOAT) BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; # st0 fxtract; ffreep %%st(0); fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs) + : "st", "st(1)"); return Result; #else @@ -253,19 +237,17 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static void FCMP(X80SoftFloat const &lhs, X80SoftFloat const &rhs, bool *eq, bool *lt, bool *nan) { + FEXCORE_PRESERVE_ALL_ATTR static void FCMP(const X80SoftFloat& lhs, const X80SoftFloat& rhs, bool* eq, bool* lt, bool* nan) { *eq = extF80_eq(lhs, rhs); *lt = extF80_lt(lhs, rhs); *nan = IsNan(lhs) || IsNan(rhs); } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FSCALE(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FSCALE(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { WARN_ONCE_FMT("x87: Application used FSCALE which may have accuracy problems"); #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st1 fldt %[lhs]; # st0 @@ -273,10 +255,9 @@ struct FEX_PACKED X80SoftFloat { fstpt %[result]; ffreep %%st(0); )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -289,20 +270,19 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat F2XM1(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat F2XM1(const X80SoftFloat& lhs) { WARN_ONCE_FMT("x87: Application used F2XM1 which may have accuracy problems"); #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; # st0 f2xm1; # st0 = 2^st(0) - 1 fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - : "st"); + : [result] "=m"(Result) + : [lhs] "m"(lhs) + : "st"); return Result; #else @@ -313,22 +293,20 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FYL2X(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FYL2X(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { WARN_ONCE_FMT("x87: Application used FYL2X which may have accuracy problems"); #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[rhs]; # st(1) fldt %[lhs]; # st(0) fyl2x; # st(1) * log2l(st(0)) fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -339,22 +317,20 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FATAN(X80SoftFloat const &lhs, X80SoftFloat const &rhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FATAN(const X80SoftFloat& lhs, const X80SoftFloat& rhs) { WARN_ONCE_FMT("x87: Application used FATAN which may have accuracy problems"); #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; fldt %[rhs]; fpatan; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - , [rhs] "m" (rhs) - : "st", "st(1)"); + : [result] "=m"(Result) + : [lhs] "m"(lhs), [rhs] "m"(rhs) + : "st", "st(1)"); return Result; #else @@ -365,21 +341,20 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FTAN(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FTAN(const X80SoftFloat& lhs) { WARN_ONCE_FMT("x87: Application used FTAN which may have accuracy problems"); #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; # st0 fptan; ffreep %%st(0); fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - : "st"); + : [result] "=m"(Result) + : [lhs] "m"(lhs) + : "st"); return Result; #else @@ -389,20 +364,19 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FSIN(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FSIN(const X80SoftFloat& lhs) { WARN_ONCE_FMT("x87: Application used FSIN which may have accuracy problems"); #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; # st0 fsin; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - : "st"); + : [result] "=m"(Result) + : [lhs] "m"(lhs) + : "st"); return Result; #else @@ -412,20 +386,19 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FCOS(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FCOS(const X80SoftFloat& lhs) { WARN_ONCE_FMT("x87: Application used FCOS which may have accuracy problems"); #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; # st0 fcos; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - : "st"); + : [result] "=m"(Result) + : [lhs] "m"(lhs) + : "st"); return Result; #else @@ -435,19 +408,18 @@ struct FEX_PACKED X80SoftFloat { #endif } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat FSQRT(X80SoftFloat const &lhs) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FSQRT(const X80SoftFloat& lhs) { #ifdef DEBUG_X86_FLOAT BIGFLOAT Result; - asm (R"( + asm(R"( fninit; fldt %[lhs]; # st0 fsqrt; fstpt %[result]; )" - : [result] "=m" (Result) - : [lhs] "m" (lhs) - : "st"); + : [result] "=m"(Result) + : [lhs] "m"(lhs) + : "st"); return Result; #else @@ -471,7 +443,7 @@ struct FEX_PACKED X80SoftFloat { const float128_t Result = extF80_to_f128(*this); return FEXCore::BitCast(Result); #else - BIGFLOAT result{}; + BIGFLOAT result {}; memcpy(&result, this, sizeof(result)); return result; #endif @@ -570,19 +542,17 @@ struct FEX_PACKED X80SoftFloat { } operator extFloat80_t() const { - extFloat80_t Result{}; + extFloat80_t Result {}; Result.signif = Significand; Result.signExp = Exponent | (Sign << 15); return Result; } - static bool IsNan(X80SoftFloat const &lhs) { - return (lhs.Exponent == 0x7FFF) && - (lhs.Significand & IntegerBit) && - (lhs.Significand & Bottom62Significand); + static bool IsNan(const X80SoftFloat& lhs) { + return (lhs.Exponent == 0x7FFF) && (lhs.Significand & IntegerBit) && (lhs.Significand & Bottom62Significand); } - static bool SignBit(X80SoftFloat const &lhs) { + static bool SignBit(const X80SoftFloat& lhs) { return lhs.Sign; } diff --git a/FEXCore/Source/Common/StringConv.h b/FEXCore/Source/Common/StringConv.h index b1c4842f0..7a39a80bb 100644 --- a/FEXCore/Source/Common/StringConv.h +++ b/FEXCore/Source/Common/StringConv.h @@ -7,44 +7,51 @@ #include namespace FEXCore::StrConv { - [[maybe_unused]] static bool Conv(std::string_view Value, bool *Result) { - *Result = std::strtoull(Value.data(), nullptr, 0); - return true; - } - - [[maybe_unused]] static bool Conv(std::string_view Value, uint8_t *Result) { - *Result = std::strtoul(Value.data(), nullptr, 0); - return true; - } - - [[maybe_unused]] static bool Conv(std::string_view Value, uint16_t *Result) { - *Result = std::strtoul(Value.data(), nullptr, 0); - return true; - } - - [[maybe_unused]] static bool Conv(std::string_view Value, uint32_t *Result) { - *Result = std::strtoul(Value.data(), nullptr, 0); - return true; - } - - [[maybe_unused]] static bool Conv(std::string_view Value, int32_t *Result) { - *Result = std::strtol(Value.data(), nullptr, 0); - return true; - } - - [[maybe_unused]] static bool Conv(std::string_view Value, uint64_t *Result) { - *Result = std::strtoull(Value.data(), nullptr, 0); - return true; - } - template ::value, T>> - [[maybe_unused]] static bool Conv(std::string_view Value, T *Result) { - *Result = static_cast(std::stoull(Value.data(), nullptr, 0)); - return true; - } - - [[maybe_unused]] static bool Conv(std::string_view Value, fextl::string *Result) { - *Result = Value; - return true; - } +[[maybe_unused]] +static bool Conv(std::string_view Value, bool* Result) { + *Result = std::strtoull(Value.data(), nullptr, 0); + return true; } + +[[maybe_unused]] +static bool Conv(std::string_view Value, uint8_t* Result) { + *Result = std::strtoul(Value.data(), nullptr, 0); + return true; +} + +[[maybe_unused]] +static bool Conv(std::string_view Value, uint16_t* Result) { + *Result = std::strtoul(Value.data(), nullptr, 0); + return true; +} + +[[maybe_unused]] +static bool Conv(std::string_view Value, uint32_t* Result) { + *Result = std::strtoul(Value.data(), nullptr, 0); + return true; +} + +[[maybe_unused]] +static bool Conv(std::string_view Value, int32_t* Result) { + *Result = std::strtol(Value.data(), nullptr, 0); + return true; +} + +[[maybe_unused]] +static bool Conv(std::string_view Value, uint64_t* Result) { + *Result = std::strtoull(Value.data(), nullptr, 0); + return true; +} +template::value, T>> +[[maybe_unused]] +static bool Conv(std::string_view Value, T* Result) { + *Result = static_cast(std::stoull(Value.data(), nullptr, 0)); + return true; +} + +[[maybe_unused]] +static bool Conv(std::string_view Value, fextl::string* Result) { + *Result = Value; + return true; +} +} // namespace FEXCore::StrConv diff --git a/FEXCore/Source/Interface/Config/Config.cpp b/FEXCore/Source/Interface/Config/Config.cpp index 339539951..96f7dc3c9 100644 --- a/FEXCore/Source/Interface/Config/Config.cpp +++ b/FEXCore/Source/Interface/Config/Config.cpp @@ -29,7 +29,7 @@ #include namespace FEXCore::Context { - class Context; +class Context; } namespace FEXCore::Config { @@ -40,490 +40,464 @@ namespace DefaultValues { #define OPT_STRARRAY(group, enum, json, default) OPT_STR(group, enum, json, default) #define OPT_STRENUM(group, enum, json, default) const uint64_t P(enum) = FEXCore::ToUnderlying(P(default)); #include +} // namespace DefaultValues + +enum Paths { + PATH_DATA_DIR = 0, + PATH_CONFIG_DIR_LOCAL, + PATH_CONFIG_DIR_GLOBAL, + PATH_CONFIG_FILE_LOCAL, + PATH_CONFIG_FILE_GLOBAL, + PATH_CONFIG_TELEMETRY_FOLDER, + PATH_LAST, +}; +static std::array Paths; + +void SetDataDirectory(const std::string_view Path) { + Paths[PATH_DATA_DIR] = Path; } - enum Paths { - PATH_DATA_DIR = 0, - PATH_CONFIG_DIR_LOCAL, - PATH_CONFIG_DIR_GLOBAL, - PATH_CONFIG_FILE_LOCAL, - PATH_CONFIG_FILE_GLOBAL, - PATH_CONFIG_TELEMETRY_FOLDER, - PATH_LAST, - }; - static std::array Paths; +void SetConfigDirectory(const std::string_view Path, bool Global) { + Paths[PATH_CONFIG_DIR_LOCAL + Global] = Path; +} - void SetDataDirectory(const std::string_view Path) { - Paths[PATH_DATA_DIR] = Path; +void SetConfigFileLocation(const std::string_view Path, bool Global) { + Paths[PATH_CONFIG_FILE_LOCAL + Global] = Path; +} + +const fextl::string& GetTelemetryDirectory() { + auto& Path = Paths[PATH_CONFIG_TELEMETRY_FOLDER]; + if (Path.empty()) { + FEX_CONFIG_OPT(TelemetryDirectory, TELEMETRYDIRECTORY); + if (!TelemetryDirectory().empty()) { + Path = TelemetryDirectory; + Path += "/"; + } else { + Path = Config::GetDataDirectory() + "Telemetry/"; + } } - void SetConfigDirectory(const std::string_view Path, bool Global) { - Paths[PATH_CONFIG_DIR_LOCAL + Global] = Path; + return Path; +} + +const fextl::string& GetDataDirectory() { + return Paths[PATH_DATA_DIR]; +} + +const fextl::string& GetConfigDirectory(bool Global) { + return Paths[PATH_CONFIG_DIR_LOCAL + Global]; +} + +const fextl::string& GetConfigFileLocation(bool Global) { + return Paths[PATH_CONFIG_FILE_LOCAL + Global]; +} + +fextl::string GetApplicationConfig(const std::string_view Program, bool Global) { + fextl::string ConfigFile = GetConfigDirectory(Global); + + if (!Global && !FHU::Filesystem::Exists(ConfigFile) && !FHU::Filesystem::CreateDirectories(ConfigFile)) { + LogMan::Msg::DFmt("Couldn't create config directory: '{}'", ConfigFile); + // Let's go local in this case + return fextl::fmt::format("./{}.json", Program); } - void SetConfigFileLocation(const std::string_view Path, bool Global) { - Paths[PATH_CONFIG_FILE_LOCAL + Global] = Path; + ConfigFile += "AppConfig/"; + + // Attempt to create the local folder if it doesn't exist + if (!Global && !FHU::Filesystem::Exists(ConfigFile) && !FHU::Filesystem::CreateDirectories(ConfigFile)) { + // Let's go local in this case + return fextl::fmt::format("./{}.json", Program); } - fextl::string const& GetTelemetryDirectory() { - auto &Path = Paths[PATH_CONFIG_TELEMETRY_FOLDER]; - if (Path.empty()) { - FEX_CONFIG_OPT(TelemetryDirectory, TELEMETRYDIRECTORY); - if (!TelemetryDirectory().empty()) { - Path = TelemetryDirectory; - Path += "/"; - } - else { - Path = Config::GetDataDirectory() + "Telemetry/"; + return fextl::fmt::format("{}{}.json", ConfigFile, Program); +} + +void SetConfig(FEXCore::Context::Context* CTX, ConfigOption Option, uint64_t Config) {} + +void SetConfig(FEXCore::Context::Context* CTX, ConfigOption Option, const fextl::string& Config) {} + +uint64_t GetConfig(FEXCore::Context::Context* CTX, ConfigOption Option) { + return 0; +} + +static fextl::map> ConfigLayers; +static FEXCore::Config::Layer* Meta {}; + +constexpr std::array LoadOrder = { + FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN, FEXCore::Config::LayerType::LAYER_MAIN, + FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP, FEXCore::Config::LayerType::LAYER_GLOBAL_APP, + FEXCore::Config::LayerType::LAYER_LOCAL_STEAM_APP, FEXCore::Config::LayerType::LAYER_LOCAL_APP, + FEXCore::Config::LayerType::LAYER_ARGUMENTS, FEXCore::Config::LayerType::LAYER_USER_OVERRIDE, + FEXCore::Config::LayerType::LAYER_ENVIRONMENT, FEXCore::Config::LayerType::LAYER_TOP}; + +Layer::Layer(const LayerType _Type) + : Type {_Type} {} + +Layer::~Layer() {} + +class MetaLayer final : public FEXCore::Config::Layer { +public: + MetaLayer(const LayerType _Type) + : FEXCore::Config::Layer(_Type) {} + ~MetaLayer() {} + void Load(); + +private: + void MergeConfigMap(const LayerOptions& Options); + void MergeEnvironmentVariables(const ConfigOption& Option, const LayerValue& Value); +}; + +void MetaLayer::Load() { + OptionMap.clear(); + + for (auto CurrentLayer = LoadOrder.begin(); CurrentLayer != LoadOrder.end(); ++CurrentLayer) { + auto it = ConfigLayers.find(*CurrentLayer); + if (it != ConfigLayers.end() && *CurrentLayer != Type) { + // Merge this layer's options to this layer + MergeConfigMap(it->second->GetOptionMap()); + } + } +} + + +void MetaLayer::MergeEnvironmentVariables(const ConfigOption& Option, const LayerValue& Value) { + // Environment variables need a bit of additional work + // We want to merge the arrays rather than overwrite entirely + auto MetaEnvironment = OptionMap.find(Option); + if (MetaEnvironment == OptionMap.end()) { + // Doesn't exist, just insert + OptionMap.insert_or_assign(Option, Value); + return; + } + + // If an environment variable exists in both current meta and in the incoming layer then the meta layer value is overwritten + fextl::unordered_map LookupMap; + const auto AddToMap = [&LookupMap](const FEXCore::Config::LayerValue& Value) { + for (const auto& EnvVar : Value) { + const auto ItEq = EnvVar.find_first_of('='); + if (ItEq == fextl::string::npos) { + // Broken environment variable + // Skip + continue; } + auto Key = fextl::string(EnvVar.begin(), EnvVar.begin() + ItEq); + auto Value = fextl::string(EnvVar.begin() + ItEq + 1, EnvVar.end()); + + // Add the key to the map, overwriting whatever previous value was there + LookupMap.insert_or_assign(std::move(Key), std::move(Value)); } - - return Path; - } - - fextl::string const& GetDataDirectory() { - return Paths[PATH_DATA_DIR]; - } - - fextl::string const& GetConfigDirectory(bool Global) { - return Paths[PATH_CONFIG_DIR_LOCAL + Global]; - } - - fextl::string const& GetConfigFileLocation(bool Global) { - return Paths[PATH_CONFIG_FILE_LOCAL + Global]; - } - - fextl::string GetApplicationConfig(const std::string_view Program, bool Global) { - fextl::string ConfigFile = GetConfigDirectory(Global); - - if (!Global && - !FHU::Filesystem::Exists(ConfigFile) && - !FHU::Filesystem::CreateDirectories(ConfigFile)) { - LogMan::Msg::DFmt("Couldn't create config directory: '{}'", ConfigFile); - // Let's go local in this case - return fextl::fmt::format("./{}.json", Program); - } - - ConfigFile += "AppConfig/"; - - // Attempt to create the local folder if it doesn't exist - if (!Global && - !FHU::Filesystem::Exists(ConfigFile) && - !FHU::Filesystem::CreateDirectories(ConfigFile)) { - // Let's go local in this case - return fextl::fmt::format("./{}.json", Program); - } - - return fextl::fmt::format("{}{}.json", ConfigFile, Program); - } - - void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, uint64_t Config) { - } - - void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, fextl::string const &Config) { - } - - uint64_t GetConfig(FEXCore::Context::Context *CTX, ConfigOption Option) { - return 0; - } - - static fextl::map> ConfigLayers; - static FEXCore::Config::Layer *Meta{}; - - constexpr std::array LoadOrder = { - FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN, - FEXCore::Config::LayerType::LAYER_MAIN, - FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP, - FEXCore::Config::LayerType::LAYER_GLOBAL_APP, - FEXCore::Config::LayerType::LAYER_LOCAL_STEAM_APP, - FEXCore::Config::LayerType::LAYER_LOCAL_APP, - FEXCore::Config::LayerType::LAYER_ARGUMENTS, - FEXCore::Config::LayerType::LAYER_USER_OVERRIDE, - FEXCore::Config::LayerType::LAYER_ENVIRONMENT, - FEXCore::Config::LayerType::LAYER_TOP }; - Layer::Layer(const LayerType _Type) - : Type {_Type} { + AddToMap(MetaEnvironment->second); + AddToMap(Value); + + // Now with the two layers merged in the map + // Add all the values to the option + Erase(Option); + for (auto& Val : LookupMap) { + // Set will emplace multiple options in to its list + Set(Option, Val.first + "=" + Val.second); } +} - Layer::~Layer() { - } - - class MetaLayer final : public FEXCore::Config::Layer { - public: - MetaLayer(const LayerType _Type) - : FEXCore::Config::Layer (_Type) { - } - ~MetaLayer() { - } - void Load(); - - private: - void MergeConfigMap(const LayerOptions &Options); - void MergeEnvironmentVariables(ConfigOption const &Option, LayerValue const &Value); - }; - - void MetaLayer::Load() { - OptionMap.clear(); - - for (auto CurrentLayer = LoadOrder.begin(); CurrentLayer != LoadOrder.end(); ++CurrentLayer) { - auto it = ConfigLayers.find(*CurrentLayer); - if (it != ConfigLayers.end() && *CurrentLayer != Type) { - // Merge this layer's options to this layer - MergeConfigMap(it->second->GetOptionMap()); - } +void MetaLayer::MergeConfigMap(const LayerOptions& Options) { + // Insert this layer's options, overlaying previous options that exist here + for (auto& it : Options) { + if (it.first == FEXCore::Config::ConfigOption::CONFIG_ENV || it.first == FEXCore::Config::ConfigOption::CONFIG_HOSTENV) { + MergeEnvironmentVariables(it.first, it.second); + } else { + OptionMap.insert_or_assign(it.first, it.second); } } +} +void Initialize() { + AddLayer(fextl::make_unique(FEXCore::Config::LayerType::LAYER_TOP)); + Meta = ConfigLayers.begin()->second.get(); +} - void MetaLayer::MergeEnvironmentVariables(ConfigOption const &Option, LayerValue const &Value) { - // Environment variables need a bit of additional work - // We want to merge the arrays rather than overwrite entirely - auto MetaEnvironment = OptionMap.find(Option); - if (MetaEnvironment == OptionMap.end()) { - // Doesn't exist, just insert - OptionMap.insert_or_assign(Option, Value); - return; - } +void Shutdown() { + ConfigLayers.clear(); + Meta = nullptr; +} - // If an environment variable exists in both current meta and in the incoming layer then the meta layer value is overwritten - fextl::unordered_map LookupMap; - const auto AddToMap = [&LookupMap](FEXCore::Config::LayerValue const &Value) { - for (const auto &EnvVar : Value) { - const auto ItEq = EnvVar.find_first_of('='); - if (ItEq == fextl::string::npos) { - // Broken environment variable - // Skip - continue; - } - auto Key = fextl::string(EnvVar.begin(), EnvVar.begin() + ItEq); - auto Value = fextl::string(EnvVar.begin() + ItEq + 1, EnvVar.end()); - - // Add the key to the map, overwriting whatever previous value was there - LookupMap.insert_or_assign(std::move(Key), std::move(Value)); - } - }; - - AddToMap(MetaEnvironment->second); - AddToMap(Value); - - // Now with the two layers merged in the map - // Add all the values to the option - Erase(Option); - for (auto &Val : LookupMap) { - // Set will emplace multiple options in to its list - Set(Option, Val.first + "=" + Val.second); +void Load() { + for (auto CurrentLayer = LoadOrder.begin(); CurrentLayer != LoadOrder.end(); ++CurrentLayer) { + auto it = ConfigLayers.find(*CurrentLayer); + if (it != ConfigLayers.end()) { + it->second->Load(); } } +} - void MetaLayer::MergeConfigMap(const LayerOptions &Options) { - // Insert this layer's options, overlaying previous options that exist here - for (auto &it : Options) { - if (it.first == FEXCore::Config::ConfigOption::CONFIG_ENV || - it.first == FEXCore::Config::ConfigOption::CONFIG_HOSTENV) { - MergeEnvironmentVariables(it.first, it.second); - } - else { - OptionMap.insert_or_assign(it.first, it.second); - } - } - } - - void Initialize() { - AddLayer(fextl::make_unique(FEXCore::Config::LayerType::LAYER_TOP)); - Meta = ConfigLayers.begin()->second.get(); - } - - void Shutdown() { - ConfigLayers.clear(); - Meta = nullptr; - } - - void Load() { - for (auto CurrentLayer = LoadOrder.begin(); CurrentLayer != LoadOrder.end(); ++CurrentLayer) { - auto it = ConfigLayers.find(*CurrentLayer); - if (it != ConfigLayers.end()) { - it->second->Load(); - } - } - } - - fextl::string ExpandPath(fextl::string const &ContainerPrefix, fextl::string PathName) { - if (PathName.empty()) { - return {}; - } - - - // Expand home if it exists - if (FHU::Filesystem::IsRelative(PathName)) { - fextl::string Home = getenv("HOME") ?: ""; - // Home expansion only works if it is the first character - // This matches bash behaviour - if (PathName.at(0) == '~') { - PathName.replace(0, 1, Home); - return PathName; - } - - // Expand relative path to absolute - char ExistsTempPath[PATH_MAX]; - char *RealPath = FHU::Filesystem::Absolute(PathName.c_str(), ExistsTempPath); - if (RealPath) { - PathName = RealPath; - } - - // Only return if it exists - if (FHU::Filesystem::Exists(PathName)) { - return PathName; - } - } - else { - // If the containerprefix and pathname isn't empty - // Then we check if the pathname exists in our current namespace - // If the path DOESN'T exist but DOES exist with the prefix applied - // then redirect to the prefix - // - // This might not be expected behaviour for some edge cases but since - // all paths aren't mounted inside the container, then it'll be fine - // - // Main catch case for this is the default thunk install folders - // HostThunks: $CMAKE_INSTALL_PREFIX/lib/fex-emu/HostThunks/ - // GuestThunks: $CMAKE_INSTALL_PREFIX/share/fex-emu/GuestThunks/ - if (!ContainerPrefix.empty() && !PathName.empty()) { - if (!FHU::Filesystem::Exists(PathName)) { - auto ContainerPath = ContainerPrefix + PathName; - if (FHU::Filesystem::Exists(ContainerPath)) { - return ContainerPath; - } - } - } - } +fextl::string ExpandPath(const fextl::string& ContainerPrefix, fextl::string PathName) { + if (PathName.empty()) { return {}; } - constexpr char ContainerManager[] = "/run/host/container-manager"; - fextl::string FindContainer() { - // We only support pressure-vessel at the moment - if (FHU::Filesystem::Exists(ContainerManager)) { - fextl::vector Manager{}; - if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { - // Trim the whitespace, may contain a newline - fextl::string ManagerStr = Manager.data(); - ManagerStr = FEXCore::StringUtils::Trim(ManagerStr); - return ManagerStr; - } + // Expand home if it exists + if (FHU::Filesystem::IsRelative(PathName)) { + fextl::string Home = getenv("HOME") ?: ""; + // Home expansion only works if it is the first character + // This matches bash behaviour + if (PathName.at(0) == '~') { + PathName.replace(0, 1, Home); + return PathName; } - return {}; - } - fextl::string FindContainerPrefix() { - // We only support pressure-vessel at the moment - if (FHU::Filesystem::Exists(ContainerManager)) { - fextl::vector Manager{}; - if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { - // Trim the whitespace, may contain a newline - fextl::string ManagerStr = Manager.data(); - ManagerStr = FEXCore::StringUtils::Trim(ManagerStr); - if (strncmp(ManagerStr.data(), "pressure-vessel", Manager.size()) == 0) { - // We are running inside of pressure vessel - // Our $CMAKE_INSTALL_PREFIX paths are now inside of /run/host/$CMAKE_INSTALL_PREFIX - return "/run/host/"; + // Expand relative path to absolute + char ExistsTempPath[PATH_MAX]; + char* RealPath = FHU::Filesystem::Absolute(PathName.c_str(), ExistsTempPath); + if (RealPath) { + PathName = RealPath; + } + + // Only return if it exists + if (FHU::Filesystem::Exists(PathName)) { + return PathName; + } + } else { + // If the containerprefix and pathname isn't empty + // Then we check if the pathname exists in our current namespace + // If the path DOESN'T exist but DOES exist with the prefix applied + // then redirect to the prefix + // + // This might not be expected behaviour for some edge cases but since + // all paths aren't mounted inside the container, then it'll be fine + // + // Main catch case for this is the default thunk install folders + // HostThunks: $CMAKE_INSTALL_PREFIX/lib/fex-emu/HostThunks/ + // GuestThunks: $CMAKE_INSTALL_PREFIX/share/fex-emu/GuestThunks/ + if (!ContainerPrefix.empty() && !PathName.empty()) { + if (!FHU::Filesystem::Exists(PathName)) { + auto ContainerPath = ContainerPrefix + PathName; + if (FHU::Filesystem::Exists(ContainerPath)) { + return ContainerPath; } } } - return {}; } + return {}; +} - void ReloadMetaLayer() { - Meta->Load(); +constexpr char ContainerManager[] = "/run/host/container-manager"; - // Do configuration option fix ups after everything is reloaded - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_CORE)) { - // Sanitize Core option - FEX_CONFIG_OPT(Core, CORE); +fextl::string FindContainer() { + // We only support pressure-vessel at the moment + if (FHU::Filesystem::Exists(ContainerManager)) { + fextl::vector Manager {}; + if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { + // Trim the whitespace, may contain a newline + fextl::string ManagerStr = Manager.data(); + ManagerStr = FEXCore::StringUtils::Trim(ManagerStr); + return ManagerStr; + } + } + return {}; +} + +fextl::string FindContainerPrefix() { + // We only support pressure-vessel at the moment + if (FHU::Filesystem::Exists(ContainerManager)) { + fextl::vector Manager {}; + if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { + // Trim the whitespace, may contain a newline + fextl::string ManagerStr = Manager.data(); + ManagerStr = FEXCore::StringUtils::Trim(ManagerStr); + if (strncmp(ManagerStr.data(), "pressure-vessel", Manager.size()) == 0) { + // We are running inside of pressure vessel + // Our $CMAKE_INSTALL_PREFIX paths are now inside of /run/host/$CMAKE_INSTALL_PREFIX + return "/run/host/"; + } + } + } + return {}; +} + +void ReloadMetaLayer() { + Meta->Load(); + + // Do configuration option fix ups after everything is reloaded + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_CORE)) { + // Sanitize Core option + FEX_CONFIG_OPT(Core, CORE); #if (_M_X86_64) - constexpr uint32_t MaxCoreNumber = 1; + constexpr uint32_t MaxCoreNumber = 1; #else - constexpr uint32_t MaxCoreNumber = 0; + constexpr uint32_t MaxCoreNumber = 0; #endif - if (Core > MaxCoreNumber) { - // Sanitize the core option by setting the core to the JIT if invalid - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_CORE, fextl::fmt::format("{}", static_cast(FEXCore::Config::CONFIG_IRJIT))); + if (Core > MaxCoreNumber) { + // Sanitize the core option by setting the core to the JIT if invalid + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_CORE, fextl::fmt::format("{}", static_cast(FEXCore::Config::CONFIG_IRJIT))); + } + } + + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_CACHEOBJECTCODECOMPILATION)) { + FEX_CONFIG_OPT(CacheObjectCodeCompilation, CACHEOBJECTCODECOMPILATION); + FEX_CONFIG_OPT(Core, CORE); + } + + fextl::string ContainerPrefix {FindContainerPrefix()}; + auto ExpandPathIfExists = [&ContainerPrefix](FEXCore::Config::ConfigOption Config, fextl::string PathName) { + auto NewPath = ExpandPath(ContainerPrefix, PathName); + if (!NewPath.empty()) { + FEXCore::Config::EraseSet(Config, NewPath); + } + }; + + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_ROOTFS)) { + FEX_CONFIG_OPT(PathName, ROOTFS); + auto ExpandedString = ExpandPath(ContainerPrefix, PathName()); + if (!ExpandedString.empty()) { + // Adjust the path if it ended up being relative + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, ExpandedString); + } else if (!PathName().empty()) { + // If the filesystem doesn't exist then let's see if it exists in the fex-emu folder + fextl::string NamedRootFS = GetDataDirectory() + "RootFS/" + PathName(); + if (FHU::Filesystem::Exists(NamedRootFS)) { + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, NamedRootFS); } } - - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_CACHEOBJECTCODECOMPILATION)) { - FEX_CONFIG_OPT(CacheObjectCodeCompilation, CACHEOBJECTCODECOMPILATION); - FEX_CONFIG_OPT(Core, CORE); - } - - fextl::string ContainerPrefix { FindContainerPrefix() }; - auto ExpandPathIfExists = [&ContainerPrefix](FEXCore::Config::ConfigOption Config, fextl::string PathName) { - auto NewPath = ExpandPath(ContainerPrefix, PathName); - if (!NewPath.empty()) { - FEXCore::Config::EraseSet(Config, NewPath); - } - }; - - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_ROOTFS)) { - FEX_CONFIG_OPT(PathName, ROOTFS); - auto ExpandedString = ExpandPath(ContainerPrefix,PathName()); - if (!ExpandedString.empty()) { - // Adjust the path if it ended up being relative - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, ExpandedString); - } - else if (!PathName().empty()) { - // If the filesystem doesn't exist then let's see if it exists in the fex-emu folder - fextl::string NamedRootFS = GetDataDirectory() + "RootFS/" + PathName(); - if (FHU::Filesystem::Exists(NamedRootFS)) { - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, NamedRootFS); - } + } + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_THUNKHOSTLIBS)) { + FEX_CONFIG_OPT(PathName, THUNKHOSTLIBS); + ExpandPathIfExists(FEXCore::Config::CONFIG_THUNKHOSTLIBS, PathName()); + } + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_THUNKGUESTLIBS)) { + FEX_CONFIG_OPT(PathName, THUNKGUESTLIBS); + ExpandPathIfExists(FEXCore::Config::CONFIG_THUNKGUESTLIBS, PathName()); + } + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_THUNKCONFIG)) { + FEX_CONFIG_OPT(PathName, THUNKCONFIG); + auto ExpandedString = ExpandPath(ContainerPrefix, PathName()); + if (!ExpandedString.empty()) { + // Adjust the path if it ended up being relative + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_THUNKCONFIG, ExpandedString); + } else if (!PathName().empty()) { + // If the filesystem doesn't exist then let's see if it exists in the fex-emu folder + fextl::string NamedConfig = GetDataDirectory() + "ThunkConfigs/" + PathName(); + if (FHU::Filesystem::Exists(NamedConfig)) { + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_THUNKCONFIG, NamedConfig); } } - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_THUNKHOSTLIBS)) { - FEX_CONFIG_OPT(PathName, THUNKHOSTLIBS); - ExpandPathIfExists(FEXCore::Config::CONFIG_THUNKHOSTLIBS, PathName()); - } - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_THUNKGUESTLIBS)) { - FEX_CONFIG_OPT(PathName, THUNKGUESTLIBS); - ExpandPathIfExists(FEXCore::Config::CONFIG_THUNKGUESTLIBS, PathName()); - } - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_THUNKCONFIG)) { - FEX_CONFIG_OPT(PathName, THUNKCONFIG); - auto ExpandedString = ExpandPath(ContainerPrefix, PathName()); - if (!ExpandedString.empty()) { - // Adjust the path if it ended up being relative - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_THUNKCONFIG, ExpandedString); - } - else if (!PathName().empty()) { - // If the filesystem doesn't exist then let's see if it exists in the fex-emu folder - fextl::string NamedConfig = GetDataDirectory() + "ThunkConfigs/" + PathName(); - if (FHU::Filesystem::Exists(NamedConfig)) { - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_THUNKCONFIG, NamedConfig); - } - } - } - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_OUTPUTLOG)) { - FEX_CONFIG_OPT(PathName, OUTPUTLOG); - if (PathName() != "stdout" && PathName() != "stderr" && PathName() != "server") { - ExpandPathIfExists(FEXCore::Config::CONFIG_OUTPUTLOG, PathName()); - } - } - - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_DUMPIR) && - !FEXCore::Config::Exists(FEXCore::Config::CONFIG_PASSMANAGERDUMPIR)) { - // If DumpIR is set but no PassManagerDumpIR configuration is set, then default to `afteropt` - FEX_CONFIG_OPT(PathName, DUMPIR); - if (PathName() != "no") { - EraseSet(FEXCore::Config::ConfigOption::CONFIG_PASSMANAGERDUMPIR, fextl::fmt::format("{}", static_cast(FEXCore::Config::PassManagerDumpIR::AFTEROPT))); - } - } - - if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_SINGLESTEP)) { - // Single stepping also enforces single instruction size blocks - Set(FEXCore::Config::ConfigOption::CONFIG_MAXINST, "1"); + } + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_OUTPUTLOG)) { + FEX_CONFIG_OPT(PathName, OUTPUTLOG); + if (PathName() != "stdout" && PathName() != "stderr" && PathName() != "server") { + ExpandPathIfExists(FEXCore::Config::CONFIG_OUTPUTLOG, PathName()); } } - void AddLayer(fextl::unique_ptr _Layer) { - ConfigLayers.emplace(_Layer->GetLayerType(), std::move(_Layer)); - } - - bool Exists(ConfigOption Option) { - return Meta->OptionExists(Option); - } - - std::optional All(ConfigOption Option) { - return Meta->All(Option); - } - - std::optional Get(ConfigOption Option) { - return Meta->Get(Option); - } - - void Set(ConfigOption Option, std::string_view Data) { - Meta->Set(Option, Data); - } - - void Erase(ConfigOption Option) { - Meta->Erase(Option); - } - - void EraseSet(ConfigOption Option, std::string_view Data) { - Meta->EraseSet(Option, Data); - } - - template - T Value::Get(FEXCore::Config::ConfigOption Option) { - T Result; - auto Value = FEXCore::Config::Get(Option); - - if (!FEXCore::StrConv::Conv(**Value, &Result)) { - LOGMAN_MSG_A_FMT("Attempted to convert invalid value"); - } - return Result; - } - - template - T Value::GetIfExists(FEXCore::Config::ConfigOption Option, T Default) { - T Result; - auto Value = FEXCore::Config::Get(Option); - - if (Value && FEXCore::StrConv::Conv(**Value, &Result)) { - return Result; - } - else { - return Default; + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_DUMPIR) && !FEXCore::Config::Exists(FEXCore::Config::CONFIG_PASSMANAGERDUMPIR)) { + // If DumpIR is set but no PassManagerDumpIR configuration is set, then default to `afteropt` + FEX_CONFIG_OPT(PathName, DUMPIR); + if (PathName() != "no") { + EraseSet(FEXCore::Config::ConfigOption::CONFIG_PASSMANAGERDUMPIR, + fextl::fmt::format("{}", static_cast(FEXCore::Config::PassManagerDumpIR::AFTEROPT))); } } - template<> - fextl::string Value::GetIfExists(FEXCore::Config::ConfigOption Option, fextl::string Default) { - auto Value = FEXCore::Config::Get(Option); - if (Value) { - return **Value; - } - else { - return Default; - } + if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_SINGLESTEP)) { + // Single stepping also enforces single instruction size blocks + Set(FEXCore::Config::ConfigOption::CONFIG_MAXINST, "1"); } - - template<> - fextl::string Value::GetIfExists(FEXCore::Config::ConfigOption Option, std::string_view Default) { - auto Value = FEXCore::Config::Get(Option); - if (Value) { - return **Value; - } - else { - return fextl::string(Default); - } - } - - template bool Value::GetIfExists(FEXCore::Config::ConfigOption Option, bool Default); - template int8_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int8_t Default); - template uint8_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint8_t Default); - template int16_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int16_t Default); - template uint16_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint16_t Default); - template int32_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int32_t Default); - template uint32_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint32_t Default); - template int64_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int64_t Default); - template uint64_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint64_t Default); - - // Constructor - template Value::Value(FEXCore::Config::ConfigOption _Option, fextl::string Default); - template Value::Value(FEXCore::Config::ConfigOption _Option, bool Default); - template Value::Value(FEXCore::Config::ConfigOption _Option, uint8_t Default); - template Value::Value(FEXCore::Config::ConfigOption _Option, uint64_t Default); - - template - void Value::GetListIfExists(FEXCore::Config::ConfigOption Option, fextl::list *List) { - auto Value = FEXCore::Config::All(Option); - List->clear(); - if (Value) { - *List = **Value; - } - } - template void Value::GetListIfExists(FEXCore::Config::ConfigOption Option, fextl::list *List); } +void AddLayer(fextl::unique_ptr _Layer) { + ConfigLayers.emplace(_Layer->GetLayerType(), std::move(_Layer)); +} + +bool Exists(ConfigOption Option) { + return Meta->OptionExists(Option); +} + +std::optional All(ConfigOption Option) { + return Meta->All(Option); +} + +std::optional Get(ConfigOption Option) { + return Meta->Get(Option); +} + +void Set(ConfigOption Option, std::string_view Data) { + Meta->Set(Option, Data); +} + +void Erase(ConfigOption Option) { + Meta->Erase(Option); +} + +void EraseSet(ConfigOption Option, std::string_view Data) { + Meta->EraseSet(Option, Data); +} + +template +T Value::Get(FEXCore::Config::ConfigOption Option) { + T Result; + auto Value = FEXCore::Config::Get(Option); + + if (!FEXCore::StrConv::Conv(**Value, &Result)) { + LOGMAN_MSG_A_FMT("Attempted to convert invalid value"); + } + return Result; +} + +template +T Value::GetIfExists(FEXCore::Config::ConfigOption Option, T Default) { + T Result; + auto Value = FEXCore::Config::Get(Option); + + if (Value && FEXCore::StrConv::Conv(**Value, &Result)) { + return Result; + } else { + return Default; + } +} + +template<> +fextl::string Value::GetIfExists(FEXCore::Config::ConfigOption Option, fextl::string Default) { + auto Value = FEXCore::Config::Get(Option); + if (Value) { + return **Value; + } else { + return Default; + } +} + +template<> +fextl::string Value::GetIfExists(FEXCore::Config::ConfigOption Option, std::string_view Default) { + auto Value = FEXCore::Config::Get(Option); + if (Value) { + return **Value; + } else { + return fextl::string(Default); + } +} + +template bool Value::GetIfExists(FEXCore::Config::ConfigOption Option, bool Default); +template int8_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int8_t Default); +template uint8_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint8_t Default); +template int16_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int16_t Default); +template uint16_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint16_t Default); +template int32_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int32_t Default); +template uint32_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint32_t Default); +template int64_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, int64_t Default); +template uint64_t Value::GetIfExists(FEXCore::Config::ConfigOption Option, uint64_t Default); + +// Constructor +template Value::Value(FEXCore::Config::ConfigOption _Option, fextl::string Default); +template Value::Value(FEXCore::Config::ConfigOption _Option, bool Default); +template Value::Value(FEXCore::Config::ConfigOption _Option, uint8_t Default); +template Value::Value(FEXCore::Config::ConfigOption _Option, uint64_t Default); + +template +void Value::GetListIfExists(FEXCore::Config::ConfigOption Option, fextl::list* List) { + auto Value = FEXCore::Config::All(Option); + List->clear(); + if (Value) { + *List = **Value; + } +} +template void Value::GetListIfExists(FEXCore::Config::ConfigOption Option, fextl::list* List); +} // namespace FEXCore::Config diff --git a/FEXCore/Source/Interface/Context/Context.cpp b/FEXCore/Source/Interface/Context/Context.cpp index 3f728e9e7..0d5f252e7 100644 --- a/FEXCore/Source/Interface/Context/Context.cpp +++ b/FEXCore/Source/Interface/Context/Context.cpp @@ -13,61 +13,61 @@ #include namespace FEXCore::Context { - void InitializeStaticTables(OperatingMode Mode) { - X86Tables::InitializeInfoTables(Mode); - IR::InstallOpcodeHandlers(Mode); - } - - fextl::unique_ptr FEXCore::Context::Context::CreateNewContext() { - return fextl::make_unique(); - } - - void FEXCore::Context::ContextImpl::SetExitHandler(ExitHandler handler) { - CustomExitHandler = std::move(handler); - } - - ExitHandler FEXCore::Context::ContextImpl::GetExitHandler() const { - return CustomExitHandler; - } - - void FEXCore::Context::ContextImpl::CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) { - CompileBlock(Thread->CurrentFrame, GuestRIP); - } - - void FEXCore::Context::ContextImpl::CompileRIPCount(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, uint64_t MaxInst) { - CompileBlock(Thread->CurrentFrame, GuestRIP, MaxInst); - } - - void FEXCore::Context::ContextImpl::SetCustomCPUBackendFactory(CustomCPUFactoryType Factory) { - CustomCPUFactory = std::move(Factory); - } - - HostFeatures FEXCore::Context::ContextImpl::GetHostFeatures() const { - return HostFeatures; - } - - void FEXCore::Context::ContextImpl::SetSignalDelegator(FEXCore::SignalDelegator *_SignalDelegation) { - SignalDelegation = _SignalDelegation; - } - - void FEXCore::Context::ContextImpl::SetSyscallHandler(FEXCore::HLE::SyscallHandler *Handler) { - SyscallHandler = Handler; - SourcecodeResolver = Handler->GetSourcecodeResolver(); - } - - FEXCore::CPUID::FunctionResults FEXCore::Context::ContextImpl::RunCPUIDFunction(uint32_t Function, uint32_t Leaf) { - return CPUID.RunFunction(Function, Leaf); - } - - FEXCore::CPUID::XCRResults FEXCore::Context::ContextImpl::RunXCRFunction(uint32_t Function) { - return CPUID.RunXCRFunction(Function); - } - - FEXCore::CPUID::FunctionResults FEXCore::Context::ContextImpl::RunCPUIDFunctionName(uint32_t Function, uint32_t Leaf, uint32_t CPU) { - return CPUID.RunFunctionName(Function, Leaf, CPU); - } - - bool FEXCore::Context::ContextImpl::IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState *Thread, uintptr_t Address) const { - return Thread->CPUBackend->IsAddressInCodeBuffer(Address); - } +void InitializeStaticTables(OperatingMode Mode) { + X86Tables::InitializeInfoTables(Mode); + IR::InstallOpcodeHandlers(Mode); } + +fextl::unique_ptr FEXCore::Context::Context::CreateNewContext() { + return fextl::make_unique(); +} + +void FEXCore::Context::ContextImpl::SetExitHandler(ExitHandler handler) { + CustomExitHandler = std::move(handler); +} + +ExitHandler FEXCore::Context::ContextImpl::GetExitHandler() const { + return CustomExitHandler; +} + +void FEXCore::Context::ContextImpl::CompileRIP(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP) { + CompileBlock(Thread->CurrentFrame, GuestRIP); +} + +void FEXCore::Context::ContextImpl::CompileRIPCount(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, uint64_t MaxInst) { + CompileBlock(Thread->CurrentFrame, GuestRIP, MaxInst); +} + +void FEXCore::Context::ContextImpl::SetCustomCPUBackendFactory(CustomCPUFactoryType Factory) { + CustomCPUFactory = std::move(Factory); +} + +HostFeatures FEXCore::Context::ContextImpl::GetHostFeatures() const { + return HostFeatures; +} + +void FEXCore::Context::ContextImpl::SetSignalDelegator(FEXCore::SignalDelegator* _SignalDelegation) { + SignalDelegation = _SignalDelegation; +} + +void FEXCore::Context::ContextImpl::SetSyscallHandler(FEXCore::HLE::SyscallHandler* Handler) { + SyscallHandler = Handler; + SourcecodeResolver = Handler->GetSourcecodeResolver(); +} + +FEXCore::CPUID::FunctionResults FEXCore::Context::ContextImpl::RunCPUIDFunction(uint32_t Function, uint32_t Leaf) { + return CPUID.RunFunction(Function, Leaf); +} + +FEXCore::CPUID::XCRResults FEXCore::Context::ContextImpl::RunXCRFunction(uint32_t Function) { + return CPUID.RunXCRFunction(Function); +} + +FEXCore::CPUID::FunctionResults FEXCore::Context::ContextImpl::RunCPUIDFunctionName(uint32_t Function, uint32_t Leaf, uint32_t CPU) { + return CPUID.RunFunctionName(Function, Leaf, CPU); +} + +bool FEXCore::Context::ContextImpl::IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState* Thread, uintptr_t Address) const { + return Thread->CPUBackend->IsAddressInCodeBuffer(Address); +} +} // namespace FEXCore::Context diff --git a/FEXCore/Source/Interface/Context/Context.h b/FEXCore/Source/Interface/Context/Context.h index c6c9e80bd..435ecd0f4 100644 --- a/FEXCore/Source/Interface/Context/Context.h +++ b/FEXCore/Source/Interface/Context/Context.h @@ -46,362 +46,376 @@ namespace CodeSerialize { namespace CPU { class Arm64JITCore; class Dispatcher; -} +} // namespace CPU namespace HLE { -struct SyscallArguments; -class SyscallHandler; -class SourcecodeResolver; -struct SourcecodeMap; -} -} + struct SyscallArguments; + class SyscallHandler; + class SourcecodeResolver; + struct SourcecodeMap; +} // namespace HLE +} // namespace FEXCore namespace FEXCore::IR { - class RegisterAllocationData; - class IRListView; +class RegisterAllocationData; +class IRListView; namespace Validation { class IRValidation; } -} +} // namespace FEXCore::IR namespace FEXCore::Context { - enum CoreRunningMode { - MODE_RUN = 0, - MODE_SINGLESTEP = 1, - }; +enum CoreRunningMode { + MODE_RUN = 0, + MODE_SINGLESTEP = 1, +}; - struct ExitFunctionLinkData { - uint64_t HostBranch; - uint64_t GuestRIP; - }; +struct ExitFunctionLinkData { + uint64_t HostBranch; + uint64_t GuestRIP; +}; - using BlockDelinkerFunc = void(*)(FEXCore::Core::CpuStateFrame *Frame, FEXCore::Context::ExitFunctionLinkData *Record); - constexpr uint32_t TSC_SCALE = 128; - constexpr uint32_t TSC_SCALE_MAXIMUM = 1'000'000'000; ///< 1Ghz +using BlockDelinkerFunc = void (*)(FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record); +constexpr uint32_t TSC_SCALE = 128; +constexpr uint32_t TSC_SCALE_MAXIMUM = 1'000'000'000; ///< 1Ghz - class ContextImpl final : public FEXCore::Context::Context { - public: - // Context base class implementation. - bool InitCore() override; +class ContextImpl final : public FEXCore::Context::Context { +public: + // Context base class implementation. + bool InitCore() override; - void SetExitHandler(ExitHandler handler) override; - ExitHandler GetExitHandler() const override; + void SetExitHandler(ExitHandler handler) override; + ExitHandler GetExitHandler() const override; - ExitReason RunUntilExit(FEXCore::Core::InternalThreadState *Thread) override; + ExitReason RunUntilExit(FEXCore::Core::InternalThreadState* Thread) override; - void ExecuteThread(FEXCore::Core::InternalThreadState *Thread) override; + void ExecuteThread(FEXCore::Core::InternalThreadState* Thread) override; - void CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) override; - void CompileRIPCount(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, uint64_t MaxInst) override; + void CompileRIP(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP) override; + void CompileRIPCount(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, uint64_t MaxInst) override; - void SetCustomCPUBackendFactory(CustomCPUFactoryType Factory) override; + void SetCustomCPUBackendFactory(CustomCPUFactoryType Factory) override; - HostFeatures GetHostFeatures() const override; + HostFeatures GetHostFeatures() const override; - void HandleCallback(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP) override; + void HandleCallback(FEXCore::Core::InternalThreadState* Thread, uint64_t RIP) override; - uint64_t RestoreRIPFromHostPC(FEXCore::Core::InternalThreadState *Thread, uint64_t HostPC) override; - uint32_t ReconstructCompactedEFLAGS(FEXCore::Core::InternalThreadState *Thread, bool WasInJIT, uint64_t *HostGPRs, uint64_t PSTATE) override; - void SetFlagsFromCompactedEFLAGS(FEXCore::Core::InternalThreadState *Thread, uint32_t EFLAGS) override; + uint64_t RestoreRIPFromHostPC(FEXCore::Core::InternalThreadState* Thread, uint64_t HostPC) override; + uint32_t ReconstructCompactedEFLAGS(FEXCore::Core::InternalThreadState* Thread, bool WasInJIT, uint64_t* HostGPRs, uint64_t PSTATE) override; + void SetFlagsFromCompactedEFLAGS(FEXCore::Core::InternalThreadState* Thread, uint32_t EFLAGS) override; - /** - * @brief Used to create FEX thread objects in preparation for creating a true OS thread. Does set a TID or PID. - * - * @param InitialRIP The starting RIP of this thread - * @param StackPointer The starting RSP of this thread - * @param NewThreadState The initial thread state to setup for our state, if inheriting. - * @param ParentTID The PID that was the parent thread that created this - * - * @return The InternalThreadState object that tracks all of the emulated thread's state - * - * Usecases: - * Parent thread Creation: - * - Thread = CreateThread(InitialRIP, InitialStack, nullptr, 0); - * - CTX->RunUntilExit(Thread); - * OS thread Creation: - * - Thread = CreateThread(0, 0, NewState, PPID); - * - Thread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg); - * - ThreadHandler calls `CTX->ExecutionThread(Thread)` - * OS fork (New thread created with a clone of thread state): - * - clone{2, 3} - * - Thread = CreateThread(0, 0, CopyOfThreadState, PPID); - * - ExecutionThread(Thread); // Starts executing without creating another host thread - * Thunk callback executing guest code from native host thread - * - Thread = CreateThread(0, 0, NewState, PPID); - * - InitializeThreadTLSData(Thread); - * - HandleCallback(Thread, RIP); - */ + /** + * @brief Used to create FEX thread objects in preparation for creating a true OS thread. Does set a TID or PID. + * + * @param InitialRIP The starting RIP of this thread + * @param StackPointer The starting RSP of this thread + * @param NewThreadState The initial thread state to setup for our state, if inheriting. + * @param ParentTID The PID that was the parent thread that created this + * + * @return The InternalThreadState object that tracks all of the emulated thread's state + * + * Usecases: + * Parent thread Creation: + * - Thread = CreateThread(InitialRIP, InitialStack, nullptr, 0); + * - CTX->RunUntilExit(Thread); + * OS thread Creation: + * - Thread = CreateThread(0, 0, NewState, PPID); + * - Thread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg); + * - ThreadHandler calls `CTX->ExecutionThread(Thread)` + * OS fork (New thread created with a clone of thread state): + * - clone{2, 3} + * - Thread = CreateThread(0, 0, CopyOfThreadState, PPID); + * - ExecutionThread(Thread); // Starts executing without creating another host thread + * Thunk callback executing guest code from native host thread + * - Thread = CreateThread(0, 0, NewState, PPID); + * - InitializeThreadTLSData(Thread); + * - HandleCallback(Thread, RIP); + */ - FEXCore::Core::InternalThreadState* CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID) override; + FEXCore::Core::InternalThreadState* + CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState, uint64_t ParentTID) override; - // Public for threading - void ExecutionThread(FEXCore::Core::InternalThreadState *Thread) override; + // Public for threading + void ExecutionThread(FEXCore::Core::InternalThreadState* Thread) override; - /** - * @brief Destroys this FEX thread object and stops tracking it internally - * - * @param Thread The internal FEX thread state object - */ - void DestroyThread(FEXCore::Core::InternalThreadState *Thread, bool NeedsTLSUninstall) override; + /** + * @brief Destroys this FEX thread object and stops tracking it internally + * + * @param Thread The internal FEX thread state object + */ + void DestroyThread(FEXCore::Core::InternalThreadState* Thread, bool NeedsTLSUninstall) override; #ifndef _WIN32 - void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) override; - void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child) override; + void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) override; + void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child) override; #endif - void SetSignalDelegator(FEXCore::SignalDelegator *SignalDelegation) override; - void SetSyscallHandler(FEXCore::HLE::SyscallHandler *Handler) override; + void SetSignalDelegator(FEXCore::SignalDelegator* SignalDelegation) override; + void SetSyscallHandler(FEXCore::HLE::SyscallHandler* Handler) override; - FEXCore::CPUID::FunctionResults RunCPUIDFunction(uint32_t Function, uint32_t Leaf) override; - FEXCore::CPUID::XCRResults RunXCRFunction(uint32_t Function) override; - FEXCore::CPUID::FunctionResults RunCPUIDFunctionName(uint32_t Function, uint32_t Leaf, uint32_t CPU) override; + FEXCore::CPUID::FunctionResults RunCPUIDFunction(uint32_t Function, uint32_t Leaf) override; + FEXCore::CPUID::XCRResults RunXCRFunction(uint32_t Function) override; + FEXCore::CPUID::FunctionResults RunCPUIDFunctionName(uint32_t Function, uint32_t Leaf, uint32_t CPU) override; - FEXCore::IR::AOTIRCacheEntry *LoadAOTIRCacheEntry(const fextl::string& Name) override; - void UnloadAOTIRCacheEntry(FEXCore::IR::AOTIRCacheEntry *Entry) override; + FEXCore::IR::AOTIRCacheEntry* LoadAOTIRCacheEntry(const fextl::string& Name) override; + void UnloadAOTIRCacheEntry(FEXCore::IR::AOTIRCacheEntry* Entry) override; - void SetAOTIRLoader(AOTIRLoaderCBFn CacheReader) override { - IRCaptureCache.SetAOTIRLoader(std::move(CacheReader)); - } - void SetAOTIRWriter(AOTIRWriterCBFn CacheWriter) override { - IRCaptureCache.SetAOTIRWriter(std::move(CacheWriter)); - } - void SetAOTIRRenamer(AOTIRRenamerCBFn CacheRenamer) override { - IRCaptureCache.SetAOTIRRenamer(std::move(CacheRenamer)); - } + void SetAOTIRLoader(AOTIRLoaderCBFn CacheReader) override { + IRCaptureCache.SetAOTIRLoader(std::move(CacheReader)); + } + void SetAOTIRWriter(AOTIRWriterCBFn CacheWriter) override { + IRCaptureCache.SetAOTIRWriter(std::move(CacheWriter)); + } + void SetAOTIRRenamer(AOTIRRenamerCBFn CacheRenamer) override { + IRCaptureCache.SetAOTIRRenamer(std::move(CacheRenamer)); + } - void FinalizeAOTIRCache() override { - IRCaptureCache.FinalizeAOTIRCache(); - } - void WriteFilesWithCode(AOTIRCodeFileWriterFn Writer) override { - IRCaptureCache.WriteFilesWithCode(Writer); - } + void FinalizeAOTIRCache() override { + IRCaptureCache.FinalizeAOTIRCache(); + } + void WriteFilesWithCode(AOTIRCodeFileWriterFn Writer) override { + IRCaptureCache.WriteFilesWithCode(Writer); + } - void ClearCodeCache(FEXCore::Core::InternalThreadState *Thread) override; - void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) override; - void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length, CodeRangeInvalidationFn callback) override; - FEXCore::ForkableSharedMutex &GetCodeInvalidationMutex() override { - return CodeInvalidationMutex; - } + void ClearCodeCache(FEXCore::Core::InternalThreadState* Thread) override; + void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) override; + void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length, CodeRangeInvalidationFn callback) override; + FEXCore::ForkableSharedMutex& GetCodeInvalidationMutex() override { + return CodeInvalidationMutex; + } - void MarkMemoryShared(FEXCore::Core::InternalThreadState *Thread) override; + void MarkMemoryShared(FEXCore::Core::InternalThreadState* Thread) override; - void ConfigureAOTGen(FEXCore::Core::InternalThreadState *Thread, fextl::set *ExternalBranches, uint64_t SectionMaxAddress) override; + void ConfigureAOTGen(FEXCore::Core::InternalThreadState* Thread, fextl::set* ExternalBranches, uint64_t SectionMaxAddress) override; - bool IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState *Thread, uintptr_t Address) const override; + bool IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState* Thread, uintptr_t Address) const override; - // returns false if a handler was already registered - CustomIRResult AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void *Creator = nullptr, void *Data = nullptr); + // returns false if a handler was already registered + CustomIRResult AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void* Creator = nullptr, void* Data = nullptr); - void AppendThunkDefinitions(fextl::vector const& Definitions) override; + void AppendThunkDefinitions(const fextl::vector& Definitions) override; - public: - friend class FEXCore::HLE::SyscallHandler; - #ifdef JIT_ARM64 - friend class FEXCore::CPU::Arm64JITCore; - #endif +public: + friend class FEXCore::HLE::SyscallHandler; +#ifdef JIT_ARM64 + friend class FEXCore::CPU::Arm64JITCore; +#endif - friend class FEXCore::IR::Validation::IRValidation; + friend class FEXCore::IR::Validation::IRValidation; - struct { - CoreRunningMode RunningMode {CoreRunningMode::MODE_RUN}; - uint64_t VirtualMemSize{1ULL << 36}; + struct { + CoreRunningMode RunningMode {CoreRunningMode::MODE_RUN}; + uint64_t VirtualMemSize {1ULL << 36}; - // this is for internal use - bool ValidateIRarser { false }; + // this is for internal use + bool ValidateIRarser {false}; - // Used if the JIT needs to have its interrupt fault code emitted. - bool NeedsPendingInterruptFaultCheck { false }; + // Used if the JIT needs to have its interrupt fault code emitted. + bool NeedsPendingInterruptFaultCheck {false}; - FEX_CONFIG_OPT(Multiblock, MULTIBLOCK); - FEX_CONFIG_OPT(SingleStepConfig, SINGLESTEP); - FEX_CONFIG_OPT(GdbServer, GDBSERVER); - FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); - FEX_CONFIG_OPT(TSOEnabled, TSOENABLED); - FEX_CONFIG_OPT(TSOAutoMigration, TSOAUTOMIGRATION); - FEX_CONFIG_OPT(ABILocalFlags, ABILOCALFLAGS); - FEX_CONFIG_OPT(AOTIRCapture, AOTIRCAPTURE); - FEX_CONFIG_OPT(AOTIRGenerate, AOTIRGENERATE); - FEX_CONFIG_OPT(AOTIRLoad, AOTIRLOAD); - FEX_CONFIG_OPT(SMCChecks, SMCCHECKS); - FEX_CONFIG_OPT(Core, CORE); - FEX_CONFIG_OPT(MaxInstPerBlock, MAXINST); - FEX_CONFIG_OPT(RootFSPath, ROOTFS); - FEX_CONFIG_OPT(ThunkHostLibsPath, THUNKHOSTLIBS); - FEX_CONFIG_OPT(ThunkHostLibsPath32, THUNKHOSTLIBS32); - FEX_CONFIG_OPT(ThunkConfigFile, THUNKCONFIG); - FEX_CONFIG_OPT(GlobalJITNaming, GLOBALJITNAMING); - FEX_CONFIG_OPT(LibraryJITNaming, LIBRARYJITNAMING); - FEX_CONFIG_OPT(BlockJITNaming, BLOCKJITNAMING); - FEX_CONFIG_OPT(GDBSymbols, GDBSYMBOLS); - FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); - FEX_CONFIG_OPT(CacheObjectCodeCompilation, CACHEOBJECTCODECOMPILATION); - FEX_CONFIG_OPT(x87ReducedPrecision, X87REDUCEDPRECISION); - FEX_CONFIG_OPT(DisableTelemetry, DISABLETELEMETRY); - FEX_CONFIG_OPT(DisableVixlIndirectCalls, DISABLE_VIXL_INDIRECT_RUNTIME_CALLS); - FEX_CONFIG_OPT(SmallTSCScale, SMALLTSCSCALE); - } Config; + FEX_CONFIG_OPT(Multiblock, MULTIBLOCK); + FEX_CONFIG_OPT(SingleStepConfig, SINGLESTEP); + FEX_CONFIG_OPT(GdbServer, GDBSERVER); + FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); + FEX_CONFIG_OPT(TSOEnabled, TSOENABLED); + FEX_CONFIG_OPT(TSOAutoMigration, TSOAUTOMIGRATION); + FEX_CONFIG_OPT(ABILocalFlags, ABILOCALFLAGS); + FEX_CONFIG_OPT(AOTIRCapture, AOTIRCAPTURE); + FEX_CONFIG_OPT(AOTIRGenerate, AOTIRGENERATE); + FEX_CONFIG_OPT(AOTIRLoad, AOTIRLOAD); + FEX_CONFIG_OPT(SMCChecks, SMCCHECKS); + FEX_CONFIG_OPT(Core, CORE); + FEX_CONFIG_OPT(MaxInstPerBlock, MAXINST); + FEX_CONFIG_OPT(RootFSPath, ROOTFS); + FEX_CONFIG_OPT(ThunkHostLibsPath, THUNKHOSTLIBS); + FEX_CONFIG_OPT(ThunkHostLibsPath32, THUNKHOSTLIBS32); + FEX_CONFIG_OPT(ThunkConfigFile, THUNKCONFIG); + FEX_CONFIG_OPT(GlobalJITNaming, GLOBALJITNAMING); + FEX_CONFIG_OPT(LibraryJITNaming, LIBRARYJITNAMING); + FEX_CONFIG_OPT(BlockJITNaming, BLOCKJITNAMING); + FEX_CONFIG_OPT(GDBSymbols, GDBSYMBOLS); + FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); + FEX_CONFIG_OPT(CacheObjectCodeCompilation, CACHEOBJECTCODECOMPILATION); + FEX_CONFIG_OPT(x87ReducedPrecision, X87REDUCEDPRECISION); + FEX_CONFIG_OPT(DisableTelemetry, DISABLETELEMETRY); + FEX_CONFIG_OPT(DisableVixlIndirectCalls, DISABLE_VIXL_INDIRECT_RUNTIME_CALLS); + FEX_CONFIG_OPT(SmallTSCScale, SMALLTSCSCALE); + } Config; - std::atomic_bool CoreShuttingDown{false}; + std::atomic_bool CoreShuttingDown {false}; - FEXCore::ForkableSharedMutex CodeInvalidationMutex; + FEXCore::ForkableSharedMutex CodeInvalidationMutex; - FEXCore::HostFeatures HostFeatures; - // CPUID depends on HostFeatures so needs to be initialized after that. - FEXCore::CPUIDEmu CPUID; - FEXCore::HLE::SyscallHandler *SyscallHandler{}; - FEXCore::HLE::SourcecodeResolver *SourcecodeResolver{}; - fextl::unique_ptr ThunkHandler; - fextl::unique_ptr Dispatcher; + FEXCore::HostFeatures HostFeatures; + // CPUID depends on HostFeatures so needs to be initialized after that. + FEXCore::CPUIDEmu CPUID; + FEXCore::HLE::SyscallHandler* SyscallHandler {}; + FEXCore::HLE::SourcecodeResolver* SourcecodeResolver {}; + fextl::unique_ptr ThunkHandler; + fextl::unique_ptr Dispatcher; - CustomCPUFactoryType CustomCPUFactory; - FEXCore::Context::ExitHandler CustomExitHandler; + CustomCPUFactoryType CustomCPUFactory; + FEXCore::Context::ExitHandler CustomExitHandler; #ifdef BLOCKSTATS - fextl::unique_ptr BlockData; + fextl::unique_ptr BlockData; #endif - SignalDelegator *SignalDelegation{}; - X86GeneratedCode X86CodeGen; + SignalDelegator* SignalDelegation {}; + X86GeneratedCode X86CodeGen; - ContextImpl(); - ~ContextImpl(); + ContextImpl(); + ~ContextImpl(); - static void ThreadRemoveCodeEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP); - static void ThreadAddBlockLink(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestDestination, FEXCore::Context::ExitFunctionLinkData *HostLink, const BlockDelinkerFunc &delinker); + static void ThreadRemoveCodeEntry(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP); + static void ThreadAddBlockLink(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestDestination, + FEXCore::Context::ExitFunctionLinkData* HostLink, const BlockDelinkerFunc& delinker); - template - static uint64_t ThreadExitFunctionLink(FEXCore::Core::CpuStateFrame *Frame, ExitFunctionLinkData *Record) { - auto Thread = Frame->Thread; - auto lk = GuardSignalDeferringSection(static_cast(Thread->CTX)->CodeInvalidationMutex, Thread); + template + static uint64_t ThreadExitFunctionLink(FEXCore::Core::CpuStateFrame* Frame, ExitFunctionLinkData* Record) { + auto Thread = Frame->Thread; + auto lk = GuardSignalDeferringSection(static_cast(Thread->CTX)->CodeInvalidationMutex, Thread); - return Fn(Frame, Record); - } + return Fn(Frame, Record); + } - // Wrapper which takes CpuStateFrame instead of InternalThreadState and unique_locks CodeInvalidationMutex - // Must be called from owning thread - static void ThreadRemoveCodeEntryFromJit(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP) { - auto Thread = Frame->Thread; + // Wrapper which takes CpuStateFrame instead of InternalThreadState and unique_locks CodeInvalidationMutex + // Must be called from owning thread + static void ThreadRemoveCodeEntryFromJit(FEXCore::Core::CpuStateFrame* Frame, uint64_t GuestRIP) { + auto Thread = Frame->Thread; - LOGMAN_THROW_A_FMT(Thread->ThreadManager.GetTID() == FHU::Syscalls::gettid(), "Must be called from owning thread {}, not {}", Thread->ThreadManager.GetTID(), FHU::Syscalls::gettid()); - auto lk = GuardSignalDeferringSection(static_cast(Thread->CTX)->CodeInvalidationMutex, Thread); + LOGMAN_THROW_A_FMT(Thread->ThreadManager.GetTID() == FHU::Syscalls::gettid(), "Must be called from owning thread {}, not {}", + Thread->ThreadManager.GetTID(), FHU::Syscalls::gettid()); + auto lk = GuardSignalDeferringSection(static_cast(Thread->CTX)->CodeInvalidationMutex, Thread); - ThreadRemoveCodeEntry(Thread, GuestRIP); - } + ThreadRemoveCodeEntry(Thread, GuestRIP); + } - void RemoveCustomIREntrypoint(uintptr_t Entrypoint); + void RemoveCustomIREntrypoint(uintptr_t Entrypoint); - struct GenerateIRResult { - FEXCore::IR::IRListView* IRList; - FEXCore::IR::RegisterAllocationData::UniquePtr RAData; - uint64_t TotalInstructions; - uint64_t TotalInstructionsLength; - uint64_t StartAddr; - uint64_t Length; - }; - [[nodiscard]] GenerateIRResult GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, bool ExtendedDebugInfo, uint64_t MaxInst); - - struct CompileCodeResult { - void* CompiledCode; - FEXCore::IR::IRListView* IRData; - FEXCore::Core::DebugData* DebugData; - FEXCore::IR::RegisterAllocationData::UniquePtr RAData; - bool GeneratedIR; - uint64_t StartAddr; - uint64_t Length; - }; - [[nodiscard]] CompileCodeResult CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, uint64_t MaxInst = 0); - uintptr_t CompileBlock(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP, uint64_t MaxInst = 0); - - // Used for thread creation from syscalls - /** - * @brief Initializes TID, PID and TLS data for a thread - * - * @param Thread The internal FEX thread state object - */ - void InitializeThreadTLSData(FEXCore::Core::InternalThreadState *Thread); - - void CopyMemoryMapping(FEXCore::Core::InternalThreadState *ParentThread, FEXCore::Core::InternalThreadState *ChildThread); - - uint8_t GetGPRSize() const { return Config.Is64BitMode ? 8 : 4; } - - FEXCore::JITSymbols Symbols; - - void GetVDSOSigReturn(VDSOSigReturn *VDSOPointers) override { - if (VDSOPointers->VDSO_kernel_sigreturn == nullptr) { - VDSOPointers->VDSO_kernel_sigreturn = reinterpret_cast(X86CodeGen.sigreturn_32); - } - - if (VDSOPointers->VDSO_kernel_rt_sigreturn == nullptr) { - VDSOPointers->VDSO_kernel_rt_sigreturn = reinterpret_cast(X86CodeGen.rt_sigreturn_32); - } - } - - FEXCore::Utils::PooledAllocatorVirtual OpDispatcherAllocator; - FEXCore::Utils::PooledAllocatorVirtual FrontendAllocator; - - // If Atomic-based TSO emulation is enabled or not. - bool IsAtomicTSOEnabled() const { return AtomicTSOEmulationEnabled; } - - void SetHardwareTSOSupport(bool HardwareTSOSupported) override { - SupportsHardwareTSO = HardwareTSOSupported; - UpdateAtomicTSOEmulationConfig(); - } - - // Returns if Software TSO emulation is required. - // NOTE: This doesn't necessary return if Atomic-based TSO is currently enabled. - // This will still return true if on a single thread and TSO is currently disabled. - // - // This is to ensure that if early initialization checks CPU features and TSO /could/ be enabled, that - // we return consistent results. - // - // To check if Atomic TSO is currently enabled in the JIT, use `IsAtomicTSOEnabled` instead. - bool SoftwareTSORequired() const { - if (SupportsHardwareTSO) return false; - - return Config.TSOEnabled; - } - - void EnableExitOnHLT() override { ExitOnHLT = true; } - - bool ExitOnHLTEnabled() const { return ExitOnHLT; } - - FEXCore::CPU::CPUBackendFeatures BackendFeatures; - - protected: - void UpdateAtomicTSOEmulationConfig() { - if (SupportsHardwareTSO) { - // If the hardware supports TSO then we don't need to emulate it through atomics. - AtomicTSOEmulationEnabled = false; - } - else { - // Atomic TSO emulation only enabled if the config option is enabled. - AtomicTSOEmulationEnabled = (IsMemoryShared || !Config.TSOAutoMigration) && Config.TSOEnabled; - } - } - - private: - /** - * @brief Initializes the JIT compilers for the thread - * - * @param State The internal FEX thread state object - * - * InitializeCompiler is called inside of CreateThread, so you likely don't need this - */ - void InitializeCompiler(FEXCore::Core::InternalThreadState* Thread); - - void AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr); - - IR::AOTIRCaptureCache IRCaptureCache; - fextl::unique_ptr CodeObjectCacheService; - - bool StartPaused = false; - bool IsMemoryShared = false; - bool SupportsHardwareTSO = false; - bool AtomicTSOEmulationEnabled = true; - bool ExitOnHLT = false; - FEX_CONFIG_OPT(AppFilename, APP_FILENAME); - - std::shared_mutex CustomIRMutex; - std::atomic HasCustomIRHandlers{}; - fextl::unordered_map> CustomIRHandlers; + struct GenerateIRResult { + FEXCore::IR::IRListView* IRList; + FEXCore::IR::RegisterAllocationData::UniquePtr RAData; + uint64_t TotalInstructions; + uint64_t TotalInstructionsLength; + uint64_t StartAddr; + uint64_t Length; }; -} + [[nodiscard]] + GenerateIRResult GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, bool ExtendedDebugInfo, uint64_t MaxInst); + + struct CompileCodeResult { + void* CompiledCode; + FEXCore::IR::IRListView* IRData; + FEXCore::Core::DebugData* DebugData; + FEXCore::IR::RegisterAllocationData::UniquePtr RAData; + bool GeneratedIR; + uint64_t StartAddr; + uint64_t Length; + }; + [[nodiscard]] + CompileCodeResult CompileCode(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, uint64_t MaxInst = 0); + uintptr_t CompileBlock(FEXCore::Core::CpuStateFrame* Frame, uint64_t GuestRIP, uint64_t MaxInst = 0); + + // Used for thread creation from syscalls + /** + * @brief Initializes TID, PID and TLS data for a thread + * + * @param Thread The internal FEX thread state object + */ + void InitializeThreadTLSData(FEXCore::Core::InternalThreadState* Thread); + + void CopyMemoryMapping(FEXCore::Core::InternalThreadState* ParentThread, FEXCore::Core::InternalThreadState* ChildThread); + + uint8_t GetGPRSize() const { + return Config.Is64BitMode ? 8 : 4; + } + + FEXCore::JITSymbols Symbols; + + void GetVDSOSigReturn(VDSOSigReturn* VDSOPointers) override { + if (VDSOPointers->VDSO_kernel_sigreturn == nullptr) { + VDSOPointers->VDSO_kernel_sigreturn = reinterpret_cast(X86CodeGen.sigreturn_32); + } + + if (VDSOPointers->VDSO_kernel_rt_sigreturn == nullptr) { + VDSOPointers->VDSO_kernel_rt_sigreturn = reinterpret_cast(X86CodeGen.rt_sigreturn_32); + } + } + + FEXCore::Utils::PooledAllocatorVirtual OpDispatcherAllocator; + FEXCore::Utils::PooledAllocatorVirtual FrontendAllocator; + + // If Atomic-based TSO emulation is enabled or not. + bool IsAtomicTSOEnabled() const { + return AtomicTSOEmulationEnabled; + } + + void SetHardwareTSOSupport(bool HardwareTSOSupported) override { + SupportsHardwareTSO = HardwareTSOSupported; + UpdateAtomicTSOEmulationConfig(); + } + + // Returns if Software TSO emulation is required. + // NOTE: This doesn't necessary return if Atomic-based TSO is currently enabled. + // This will still return true if on a single thread and TSO is currently disabled. + // + // This is to ensure that if early initialization checks CPU features and TSO /could/ be enabled, that + // we return consistent results. + // + // To check if Atomic TSO is currently enabled in the JIT, use `IsAtomicTSOEnabled` instead. + bool SoftwareTSORequired() const { + if (SupportsHardwareTSO) { + return false; + } + + return Config.TSOEnabled; + } + + void EnableExitOnHLT() override { + ExitOnHLT = true; + } + + bool ExitOnHLTEnabled() const { + return ExitOnHLT; + } + + FEXCore::CPU::CPUBackendFeatures BackendFeatures; + +protected: + void UpdateAtomicTSOEmulationConfig() { + if (SupportsHardwareTSO) { + // If the hardware supports TSO then we don't need to emulate it through atomics. + AtomicTSOEmulationEnabled = false; + } else { + // Atomic TSO emulation only enabled if the config option is enabled. + AtomicTSOEmulationEnabled = (IsMemoryShared || !Config.TSOAutoMigration) && Config.TSOEnabled; + } + } + +private: + /** + * @brief Initializes the JIT compilers for the thread + * + * @param State The internal FEX thread state object + * + * InitializeCompiler is called inside of CreateThread, so you likely don't need this + */ + void InitializeCompiler(FEXCore::Core::InternalThreadState* Thread); + + void AddBlockMapping(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, void* Ptr); + + IR::AOTIRCaptureCache IRCaptureCache; + fextl::unique_ptr CodeObjectCacheService; + + bool StartPaused = false; + bool IsMemoryShared = false; + bool SupportsHardwareTSO = false; + bool AtomicTSOEmulationEnabled = true; + bool ExitOnHLT = false; + FEX_CONFIG_OPT(AppFilename, APP_FILENAME); + + std::shared_mutex CustomIRMutex; + std::atomic HasCustomIRHandlers {}; + fextl::unordered_map> CustomIRHandlers; +}; +} // namespace FEXCore::Context diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp index 102bb95c7..c62318726 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp +++ b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp @@ -32,24 +32,31 @@ namespace x64 { #ifndef _M_ARM_64EC // All but x19 and x29 are caller saved constexpr std::array SRA = { - FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, - FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, - FEXCore::ARMEmitter::Reg::r8, FEXCore::ARMEmitter::Reg::r9, - FEXCore::ARMEmitter::Reg::r10, FEXCore::ARMEmitter::Reg::r11, - FEXCore::ARMEmitter::Reg::r12, FEXCore::ARMEmitter::Reg::r13, - FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r15, - FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, - FEXCore::ARMEmitter::Reg::r19, FEXCore::ARMEmitter::Reg::r29, + FEXCore::ARMEmitter::Reg::r4, + FEXCore::ARMEmitter::Reg::r5, + FEXCore::ARMEmitter::Reg::r6, + FEXCore::ARMEmitter::Reg::r7, + FEXCore::ARMEmitter::Reg::r8, + FEXCore::ARMEmitter::Reg::r9, + FEXCore::ARMEmitter::Reg::r10, + FEXCore::ARMEmitter::Reg::r11, + FEXCore::ARMEmitter::Reg::r12, + FEXCore::ARMEmitter::Reg::r13, + FEXCore::ARMEmitter::Reg::r14, + FEXCore::ARMEmitter::Reg::r15, + FEXCore::ARMEmitter::Reg::r16, + FEXCore::ARMEmitter::Reg::r17, + FEXCore::ARMEmitter::Reg::r19, + FEXCore::ARMEmitter::Reg::r29, // PF/AF must be last. - REG_PF, REG_AF, + REG_PF, + REG_AF, }; constexpr std::array RA = { // All these callee saved - FEXCore::ARMEmitter::Reg::r20, FEXCore::ARMEmitter::Reg::r21, - FEXCore::ARMEmitter::Reg::r22, FEXCore::ARMEmitter::Reg::r23, - FEXCore::ARMEmitter::Reg::r24, FEXCore::ARMEmitter::Reg::r25, - FEXCore::ARMEmitter::Reg::r30, + FEXCore::ARMEmitter::Reg::r20, FEXCore::ARMEmitter::Reg::r21, FEXCore::ARMEmitter::Reg::r22, FEXCore::ARMEmitter::Reg::r23, + FEXCore::ARMEmitter::Reg::r24, FEXCore::ARMEmitter::Reg::r25, FEXCore::ARMEmitter::Reg::r30, }; constexpr std::array, 3> RAPair = {{ @@ -60,48 +67,47 @@ namespace x64 { // All are caller saved constexpr std::array SRAFPR = { - FEXCore::ARMEmitter::VReg::v16, FEXCore::ARMEmitter::VReg::v17, - FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19, - FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21, - FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23, - FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, - FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, - FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, - FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31 - }; + FEXCore::ARMEmitter::VReg::v16, FEXCore::ARMEmitter::VReg::v17, FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19, + FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21, FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23, + FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, + FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31}; // v8..v15 = (lower 64bits) Callee saved constexpr std::array RAFPR = { // v0 ~ v1 are used as temps. // FEXCore::ARMEmitter::VReg::v0, FEXCore::ARMEmitter::VReg::v1, - FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, - FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, - FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, - FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, - FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, - FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, + FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, + FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, + FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15, }; #else - constexpr std::array SRA = { - FEXCore::ARMEmitter::Reg::r8, FEXCore::ARMEmitter::Reg::r0, - FEXCore::ARMEmitter::Reg::r1, FEXCore::ARMEmitter::Reg::r27, + constexpr std::array SRA = { + FEXCore::ARMEmitter::Reg::r8, + FEXCore::ARMEmitter::Reg::r0, + FEXCore::ARMEmitter::Reg::r1, + FEXCore::ARMEmitter::Reg::r27, // SP's register location isn't specified by the ARM64EC ABI, we choose to use r23 - FEXCore::ARMEmitter::Reg::r23, FEXCore::ARMEmitter::Reg::r29, - FEXCore::ARMEmitter::Reg::r25, FEXCore::ARMEmitter::Reg::r26, - FEXCore::ARMEmitter::Reg::r2, FEXCore::ARMEmitter::Reg::r3, - FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, - FEXCore::ARMEmitter::Reg::r19, FEXCore::ARMEmitter::Reg::r20, - FEXCore::ARMEmitter::Reg::r21, FEXCore::ARMEmitter::Reg::r22, - REG_PF, REG_AF, + FEXCore::ARMEmitter::Reg::r23, + FEXCore::ARMEmitter::Reg::r29, + FEXCore::ARMEmitter::Reg::r25, + FEXCore::ARMEmitter::Reg::r26, + FEXCore::ARMEmitter::Reg::r2, + FEXCore::ARMEmitter::Reg::r3, + FEXCore::ARMEmitter::Reg::r4, + FEXCore::ARMEmitter::Reg::r5, + FEXCore::ARMEmitter::Reg::r19, + FEXCore::ARMEmitter::Reg::r20, + FEXCore::ARMEmitter::Reg::r21, + FEXCore::ARMEmitter::Reg::r22, + REG_PF, + REG_AF, }; constexpr std::array RA = { - FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, - FEXCore::ARMEmitter::Reg::r14,FEXCore::ARMEmitter::Reg::r15, - FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, - FEXCore::ARMEmitter::Reg::r30, + FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r15, + FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, FEXCore::ARMEmitter::Reg::r30, }; constexpr std::array, 3> RAPair = {{ @@ -111,142 +117,131 @@ namespace x64 { }}; constexpr std::array SRAFPR = { - FEXCore::ARMEmitter::VReg::v0, FEXCore::ARMEmitter::VReg::v1, - FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, - FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, - FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, - FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, - FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, - FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, - FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15, + FEXCore::ARMEmitter::VReg::v0, FEXCore::ARMEmitter::VReg::v1, FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, + FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, + FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, + FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15, }; constexpr std::array RAFPR = { - FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19, - FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21, - FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23, - FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, - FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, - FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, - FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31 - }; + FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19, FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21, + FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23, FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, + FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, + FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31}; #endif // I wish this could get constexpr generated from SRA's definition but impossible until libstdc++12, libc++15. // SRA GPRs that need to be spilled when calling a function with `preserve_all` ABI. constexpr std::array PreserveAll_SRA = { - FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, - FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, - FEXCore::ARMEmitter::Reg::r8, - FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, + FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, + FEXCore::ARMEmitter::Reg::r8, FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, }; - constexpr uint32_t PreserveAll_SRAMask = { - []() -> uint32_t { - uint32_t Mask{}; - for (auto Reg : PreserveAll_SRA) { - switch (Reg.Idx()) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 16: - case 17: - Mask |= (1U << Reg.Idx()); - break; - default: break; - } + constexpr uint32_t PreserveAll_SRAMask = {[]() -> uint32_t { + uint32_t Mask {}; + for (auto Reg : PreserveAll_SRA) { + switch (Reg.Idx()) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 16: + case 17: Mask |= (1U << Reg.Idx()); break; + default: break; } + } - return Mask; - }() - }; + return Mask; + }()}; // Dynamic GPRs constexpr std::array PreserveAll_Dynamic = { // Only LR needs to get saved. - FEXCore::ARMEmitter::Reg::r30 - }; + FEXCore::ARMEmitter::Reg::r30}; // SRA FPRs that need to be spilled when calling a function with `preserve_all` ABI. constexpr std::array PreserveAll_SRAFPR = { // None. }; - constexpr uint32_t PreserveAll_SRAFPRMask = { - []() -> uint32_t { - uint32_t Mask{}; - for (auto Reg : PreserveAll_SRAFPR) { - Mask |= (1U << Reg.Idx()); - } - return Mask; - }() - }; + constexpr uint32_t PreserveAll_SRAFPRMask = {[]() -> uint32_t { + uint32_t Mask {}; + for (auto Reg : PreserveAll_SRAFPR) { + Mask |= (1U << Reg.Idx()); + } + return Mask; + }()}; // Dynamic FPRs // - v0-v7 constexpr std::array PreserveAll_DynamicFPR = { // v0 ~ v1 are temps - FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, - FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, - FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, + FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, FEXCore::ARMEmitter::VReg::v4, + FEXCore::ARMEmitter::VReg::v5, FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, }; // SRA FPRs that need to be spilled when the host supports SVE-256bit with `preserve_all` ABI. // This is /all/ of the SRA registers constexpr std::array PreserveAll_SRAFPRSVE = SRAFPR; - constexpr uint32_t PreserveAll_SRAFPRSVEMask = { - []() -> uint32_t { - uint32_t Mask{}; - for (auto Reg : PreserveAll_SRAFPRSVE) { - Mask |= (1U << Reg.Idx()); - } - return Mask; - }() - }; + constexpr uint32_t PreserveAll_SRAFPRSVEMask = {[]() -> uint32_t { + uint32_t Mask {}; + for (auto Reg : PreserveAll_SRAFPRSVE) { + Mask |= (1U << Reg.Idx()); + } + return Mask; + }()}; // Dynamic FPRs when the host supports SVE-256bit. constexpr std::array PreserveAll_DynamicFPRSVE = { // v0 ~ v1 are used as temps. - FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, - FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, - FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, - FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, - FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, - FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, + FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, + FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, + FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15, }; -} +} // namespace x64 namespace x32 { // All but x19 and x29 are caller saved constexpr std::array SRA = { - FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, - FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, - FEXCore::ARMEmitter::Reg::r8, FEXCore::ARMEmitter::Reg::r9, - FEXCore::ARMEmitter::Reg::r10, FEXCore::ARMEmitter::Reg::r11, + FEXCore::ARMEmitter::Reg::r4, + FEXCore::ARMEmitter::Reg::r5, + FEXCore::ARMEmitter::Reg::r6, + FEXCore::ARMEmitter::Reg::r7, + FEXCore::ARMEmitter::Reg::r8, + FEXCore::ARMEmitter::Reg::r9, + FEXCore::ARMEmitter::Reg::r10, + FEXCore::ARMEmitter::Reg::r11, // PF/AF must be last. - REG_PF, REG_AF, + REG_PF, + REG_AF, }; constexpr std::array RA = { // All these callee saved - FEXCore::ARMEmitter::Reg::r20, FEXCore::ARMEmitter::Reg::r21, - FEXCore::ARMEmitter::Reg::r22, FEXCore::ARMEmitter::Reg::r23, - FEXCore::ARMEmitter::Reg::r24, FEXCore::ARMEmitter::Reg::r25, + FEXCore::ARMEmitter::Reg::r20, + FEXCore::ARMEmitter::Reg::r21, + FEXCore::ARMEmitter::Reg::r22, + FEXCore::ARMEmitter::Reg::r23, + FEXCore::ARMEmitter::Reg::r24, + FEXCore::ARMEmitter::Reg::r25, // Registers only available on 32-bit // All these are caller saved (except for r19). - FEXCore::ARMEmitter::Reg::r12, FEXCore::ARMEmitter::Reg::r13, - FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r15, - FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, - FEXCore::ARMEmitter::Reg::r29, FEXCore::ARMEmitter::Reg::r30, + FEXCore::ARMEmitter::Reg::r12, + FEXCore::ARMEmitter::Reg::r13, + FEXCore::ARMEmitter::Reg::r14, + FEXCore::ARMEmitter::Reg::r15, + FEXCore::ARMEmitter::Reg::r16, + FEXCore::ARMEmitter::Reg::r17, + FEXCore::ARMEmitter::Reg::r29, + FEXCore::ARMEmitter::Reg::r30, FEXCore::ARMEmitter::Reg::r19, }; @@ -264,10 +259,8 @@ namespace x32 { // All are caller saved constexpr std::array SRAFPR = { - FEXCore::ARMEmitter::VReg::v16, FEXCore::ARMEmitter::VReg::v17, - FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19, - FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21, - FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23, + FEXCore::ARMEmitter::VReg::v16, FEXCore::ARMEmitter::VReg::v17, FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19, + FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21, FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23, }; // v8..v15 = (lower 64bits) Callee saved @@ -275,118 +268,94 @@ namespace x32 { // v0 ~ v1 are used as temps. // FEXCore::ARMEmitter::VReg::v0, FEXCore::ARMEmitter::VReg::v1, - FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, - FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, - FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, - FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, - FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, - FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, + FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, + FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, + FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15, - FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, - FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, - FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, - FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31 - }; + FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, + FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31}; // I wish this could get constexpr generated from SRA's definition but impossible until libstdc++12, libc++15. // SRA GPRs that need to be spilled when calling a function with `preserve_all` ABI. constexpr std::array PreserveAll_SRA = { - FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, - FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, - FEXCore::ARMEmitter::Reg::r8, + FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, FEXCore::ARMEmitter::Reg::r6, + FEXCore::ARMEmitter::Reg::r7, FEXCore::ARMEmitter::Reg::r8, }; - constexpr uint32_t PreserveAll_SRAMask = { - []() -> uint32_t { - uint32_t Mask{}; - for (auto Reg : PreserveAll_SRA) { - switch (Reg.Idx()) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 16: - case 17: - Mask |= (1U << Reg.Idx()); - break; - default: break; - } + constexpr uint32_t PreserveAll_SRAMask = {[]() -> uint32_t { + uint32_t Mask {}; + for (auto Reg : PreserveAll_SRA) { + switch (Reg.Idx()) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 16: + case 17: Mask |= (1U << Reg.Idx()); break; + default: break; } + } - return Mask; - }() - }; + return Mask; + }()}; // Dynamic GPRs constexpr std::array PreserveAll_Dynamic = { - FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, - FEXCore::ARMEmitter::Reg::r30 - }; + FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, FEXCore::ARMEmitter::Reg::r30}; // SRA FPRs that need to be spilled when calling a function with `preserve_all` ABI. constexpr std::array PreserveAll_SRAFPR = { // None. }; - constexpr uint32_t PreserveAll_SRAFPRMask = { - []() -> uint32_t { - uint32_t Mask{}; - for (auto Reg : PreserveAll_SRAFPR) { - Mask |= (1U << Reg.Idx()); - } - return Mask; - }() - }; + constexpr uint32_t PreserveAll_SRAFPRMask = {[]() -> uint32_t { + uint32_t Mask {}; + for (auto Reg : PreserveAll_SRAFPR) { + Mask |= (1U << Reg.Idx()); + } + return Mask; + }()}; // Dynamic FPRs // - v0-v7 constexpr std::array PreserveAll_DynamicFPR = { // v0 ~ v1 are temps - FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, - FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, - FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, + FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, FEXCore::ARMEmitter::VReg::v4, + FEXCore::ARMEmitter::VReg::v5, FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, }; // SRA FPRs that need to be spilled when the host supports SVE-256bit with `preserve_all` ABI. // This is /all/ of the SRA registers constexpr std::array PreserveAll_SRAFPRSVE = SRAFPR; - constexpr uint32_t PreserveAll_SRAFPRSVEMask = { - []() -> uint32_t { - uint32_t Mask{}; - for (auto Reg : PreserveAll_SRAFPRSVE) { - Mask |= (1U << Reg.Idx()); - } - return Mask; - }() - }; + constexpr uint32_t PreserveAll_SRAFPRSVEMask = {[]() -> uint32_t { + uint32_t Mask {}; + for (auto Reg : PreserveAll_SRAFPRSVE) { + Mask |= (1U << Reg.Idx()); + } + return Mask; + }()}; // Dynamic FPRs when the host supports SVE-256bit. constexpr std::array PreserveAll_DynamicFPRSVE = { // v0 ~ v1 are used as temps. - FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, - FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, - FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, - FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, - FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, - FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, + FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3, FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, + FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, + FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15, - FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, - FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, - FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, - FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31 - }; -} + FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, + FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31}; +} // namespace x32 // We want vixl to not allocate a default buffer. Jit and dispatcher will manually create one. -Arm64Emitter::Arm64Emitter(FEXCore::Context::ContextImpl *ctx, void* EmissionPtr, size_t size) +Arm64Emitter::Arm64Emitter(FEXCore::Context::ContextImpl* ctx, void* EmissionPtr, size_t size) : Emitter(static_cast(EmissionPtr), size) , EmitterCTX {ctx} #ifdef VIXL_SIMULATOR @@ -422,8 +391,7 @@ Arm64Emitter::Arm64Emitter(FEXCore::Context::ContextImpl *ctx, void* EmissionPtr #ifdef _M_ARM_64EC ConfiguredDynamicRegisterBase = std::span(x64::RA.begin(), 7); #endif - } - else { + } else { ConfiguredDynamicRegisterBase = std::span(x32::RA.begin() + 6, 8); StaticRegisters = x32::SRA; @@ -439,11 +407,13 @@ void Arm64Emitter::LoadConstant(ARMEmitter::Size s, ARMEmitter::Register Reg, ui bool Is64Bit = s == ARMEmitter::Size::i64Bit; int Segments = Is64Bit ? 4 : 2; - if (Is64Bit && ((~Constant)>> 16) == 0) { + if (Is64Bit && ((~Constant) >> 16) == 0) { movn(s, Reg, (~Constant) & 0xFFFF); if (NOPPad) { - nop(); nop(); nop(); + nop(); + nop(); + nop(); } return; } @@ -459,12 +429,14 @@ void Arm64Emitter::LoadConstant(ARMEmitter::Size s, ARMEmitter::Register Reg, ui movn(s, Reg.W(), (~Constant) & 0xFFFF); if (NOPPad) { - nop(); nop(); nop(); + nop(); + nop(); + nop(); } return; } - int RequiredMoveSegments{}; + int RequiredMoveSegments {}; // Count the number of move segments // We only want to use ADRP+ADD if we have more than 1 segment @@ -483,7 +455,9 @@ void Arm64Emitter::LoadConstant(ARMEmitter::Size s, ARMEmitter::Register Reg, ui if (IsImm) { orr(s, Reg, ARMEmitter::Reg::zr, Constant); if (NOPPad) { - nop(); nop(); nop(); + nop(); + nop(); + nop(); } return; } @@ -507,23 +481,20 @@ void Arm64Emitter::LoadConstant(ARMEmitter::Size s, ARMEmitter::Register Reg, ui // If this is 4k page aligned then we only need ADRP if ((AlignedOffset & 0xFFF) == 0) { adrp(Reg, AlignedOffset >> 12); - } - else { + } else { // If the constant is within 1MB of PC then we can still use ADR to load in a single instruction // 21-bit signed integer here int64_t SmallOffset = static_cast(Constant) - static_cast(PC); if (vixl::IsInt21(SmallOffset)) { adr(Reg, SmallOffset); - } - else { + } else { // Need to use ADRP + ADD adrp(Reg, AlignedOffset >> 12); add(s, Reg, Reg, Constant & 0xFFF); NumMoves = 2; } } - } - else { + } else { int CurrentSegment = 0; for (; CurrentSegment < Segments; ++CurrentSegment) { uint16_t Part = (Constant >> (CurrentSegment * 16)) & 0xFFFF; @@ -569,18 +540,14 @@ void Arm64Emitter::PushCalleeSavedRegisters() { {ARMEmitter::XReg::x29, ARMEmitter::XReg::x30}, }}; - for (auto &RegPair : CalleeSaved) { + for (auto& RegPair : CalleeSaved) { stp(RegPair.first, RegPair.second, ARMEmitter::Reg::rsp, -16); } // Additionally we need to store the lower 64bits of v8-v15 // Here's a fun thing, we can use two ST4 instructions to store everything // We just need a single sub to sp before that - const std::array< - std::tuple, 2> FPRs = {{ + const std::array< std::tuple, 2> FPRs = {{ {ARMEmitter::DReg::d8, ARMEmitter::DReg::d9, ARMEmitter::DReg::d10, ARMEmitter::DReg::d11}, {ARMEmitter::DReg::d12, ARMEmitter::DReg::d13, ARMEmitter::DReg::d14, ARMEmitter::DReg::d15}, }}; @@ -591,37 +558,21 @@ void Arm64Emitter::PushCalleeSavedRegisters() { // We just saved x19 so it is safe add(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r19, ARMEmitter::Reg::rsp, 0); - for (auto &RegQuad : FPRs) { - st4(ARMEmitter::SubRegSize::i64Bit, - std::get<0>(RegQuad), - std::get<1>(RegQuad), - std::get<2>(RegQuad), - std::get<3>(RegQuad), - 0, - ARMEmitter::Reg::r19, - 32); + for (auto& RegQuad : FPRs) { + st4(ARMEmitter::SubRegSize::i64Bit, std::get<0>(RegQuad), std::get<1>(RegQuad), std::get<2>(RegQuad), std::get<3>(RegQuad), 0, + ARMEmitter::Reg::r19, 32); } } void Arm64Emitter::PopCalleeSavedRegisters() { - const std::array< - std::tuple, 2> FPRs = {{ + const std::array< std::tuple, 2> FPRs = {{ {ARMEmitter::DReg::d12, ARMEmitter::DReg::d13, ARMEmitter::DReg::d14, ARMEmitter::DReg::d15}, {ARMEmitter::DReg::d8, ARMEmitter::DReg::d9, ARMEmitter::DReg::d10, ARMEmitter::DReg::d11}, }}; - for (auto &RegQuad : FPRs) { - ld4(ARMEmitter::SubRegSize::i64Bit, - std::get<0>(RegQuad), - std::get<1>(RegQuad), - std::get<2>(RegQuad), - std::get<3>(RegQuad), - 0, - ARMEmitter::Reg::rsp, - 32); + for (auto& RegQuad : FPRs) { + ld4(ARMEmitter::SubRegSize::i64Bit, std::get<0>(RegQuad), std::get<1>(RegQuad), std::get<2>(RegQuad), std::get<3>(RegQuad), 0, + ARMEmitter::Reg::rsp, 32); } const fextl::vector> CalleeSaved = {{ @@ -633,7 +584,7 @@ void Arm64Emitter::PopCalleeSavedRegisters() { {ARMEmitter::XReg::x19, ARMEmitter::XReg::x20}, }}; - for (auto &RegPair : CalleeSaved) { + for (auto& RegPair : CalleeSaved) { ldp(RegPair.first, RegPair.second, ARMEmitter::Reg::rsp, 16); } } @@ -652,8 +603,8 @@ void Arm64Emitter::SpillStaticRegs(FEXCore::ARMEmitter::Register TmpReg, bool FP // FIZ(0): Flush Inputs to Zero mrs(TmpReg, ARMEmitter::SystemRegister::FPCR); bic(ARMEmitter::Size::i64Bit, TmpReg, TmpReg, - (1U << 2) | // NEP - (1U << 1)); // AH + (1U << 2) | // NEP + (1U << 1)); // AH msr(ARMEmitter::SystemRegister::FPCR, TmpReg); } #endif @@ -671,18 +622,15 @@ void Arm64Emitter::SpillStaticRegs(FEXCore::ARMEmitter::Register TmpReg, bool FP unsigned PFAFSpillMask = GPRSpillMask & PFAFMask; GPRSpillMask &= ~PFAFSpillMask; - for (size_t i = 0; i < StaticRegisters.size(); i+=2) { + for (size_t i = 0; i < StaticRegisters.size(); i += 2) { auto Reg1 = StaticRegisters[i]; - auto Reg2 = StaticRegisters[i+1]; - if (((1U << Reg1.Idx()) & GPRSpillMask) && - ((1U << Reg2.Idx()) & GPRSpillMask)) { + auto Reg2 = StaticRegisters[i + 1]; + if (((1U << Reg1.Idx()) & GPRSpillMask) && ((1U << Reg2.Idx()) & GPRSpillMask)) { stp(Reg1.X(), Reg2.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i])); - } - else if (((1U << Reg1.Idx()) & GPRSpillMask)) { + } else if (((1U << Reg1.Idx()) & GPRSpillMask)) { str(Reg1.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i])); - } - else if (((1U << Reg2.Idx()) & GPRSpillMask)) { - str(Reg2.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i+1])); + } else if (((1U << Reg2.Idx()) & GPRSpillMask)) { + str(Reg2.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i + 1])); } } @@ -716,21 +664,17 @@ void Arm64Emitter::SpillStaticRegs(FEXCore::ARMEmitter::Register TmpReg, bool FP const auto Reg4 = StaticFPRegisters[i + 3]; st1(Reg1.Q(), Reg2.Q(), Reg3.Q(), Reg4.Q(), TmpReg, 64); } - } - else { + } else { for (size_t i = 0; i < StaticFPRegisters.size(); i += 2) { const auto Reg1 = StaticFPRegisters[i]; const auto Reg2 = StaticFPRegisters[i + 1]; - if (((1U << Reg1.Idx()) & FPRSpillMask) && - ((1U << Reg2.Idx()) & FPRSpillMask)) { + if (((1U << Reg1.Idx()) & FPRSpillMask) && ((1U << Reg2.Idx()) & FPRSpillMask)) { stp(Reg1.Q(), Reg2.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i][0])); - } - else if (((1U << Reg1.Idx()) & FPRSpillMask)) { + } else if (((1U << Reg1.Idx()) & FPRSpillMask)) { str(Reg1.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i][0])); - } - else if (((1U << Reg2.Idx()) & FPRSpillMask)) { - str(Reg2.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i+1][0])); + } else if (((1U << Reg2.Idx()) & FPRSpillMask)) { + str(Reg2.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i + 1][0])); } } } @@ -741,7 +685,7 @@ void Arm64Emitter::SpillStaticRegs(FEXCore::ARMEmitter::Register TmpReg, bool FP void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRFillMask) { FEXCore::ARMEmitter::Register TmpReg = FEXCore::ARMEmitter::Reg::r0; LOGMAN_THROW_A_FMT(GPRFillMask != 0, "Must fill at least 1 GPR for a temp"); - [[maybe_unused]] bool FoundRegister{}; + [[maybe_unused]] bool FoundRegister {}; for (auto Reg : StaticRegisters) { if (((1U << Reg.Idx()) & GPRFillMask)) { TmpReg = Reg; @@ -765,8 +709,8 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF // Additional interesting AFP bits: // FIZ(0): Flush Inputs to Zero orr(ARMEmitter::Size::i64Bit, TmpReg, TmpReg, - (1U << 2) | // NEP - (1U << 1)); // AH + (1U << 2) | // NEP + (1U << 1)); // AH msr(ARMEmitter::SystemRegister::FPCR, TmpReg); } #endif @@ -811,21 +755,17 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF const auto Reg4 = StaticFPRegisters[i + 3]; ld1(Reg1.Q(), Reg2.Q(), Reg3.Q(), Reg4.Q(), TmpReg, 64); } - } - else { + } else { for (size_t i = 0; i < StaticFPRegisters.size(); i += 2) { const auto Reg1 = StaticFPRegisters[i]; const auto Reg2 = StaticFPRegisters[i + 1]; - if (((1U << Reg1.Idx()) & FPRFillMask) && - ((1U << Reg2.Idx()) & FPRFillMask)) { + if (((1U << Reg1.Idx()) & FPRFillMask) && ((1U << Reg2.Idx()) & FPRFillMask)) { ldp(Reg1.Q(), Reg2.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i][0])); - } - else if (((1U << Reg1.Idx()) & FPRFillMask)) { + } else if (((1U << Reg1.Idx()) & FPRFillMask)) { ldr(Reg1.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i][0])); - } - else if (((1U << Reg2.Idx()) & FPRFillMask)) { - ldr(Reg2.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i+1][0])); + } else if (((1U << Reg2.Idx()) & FPRFillMask)) { + ldr(Reg2.Q(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[i + 1][0])); } } } @@ -837,18 +777,15 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF uint32_t PFAFFillMask = GPRFillMask & PFAFMask; GPRFillMask &= ~PFAFMask; - for (size_t i = 0; i < StaticRegisters.size(); i+=2) { + for (size_t i = 0; i < StaticRegisters.size(); i += 2) { auto Reg1 = StaticRegisters[i]; - auto Reg2 = StaticRegisters[i+1]; - if (((1U << Reg1.Idx()) & GPRFillMask) && - ((1U << Reg2.Idx()) & GPRFillMask)) { + auto Reg2 = StaticRegisters[i + 1]; + if (((1U << Reg1.Idx()) & GPRFillMask) && ((1U << Reg2.Idx()) & GPRFillMask)) { ldp(Reg1.X(), Reg2.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i])); - } - else if ((1U << Reg1.Idx()) & GPRFillMask) { + } else if ((1U << Reg1.Idx()) & GPRFillMask) { ldr(Reg1.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i])); - } - else if ((1U << Reg2.Idx()) & GPRFillMask) { - ldr(Reg2.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i+1])); + } else if ((1U << Reg2.Idx()) & GPRFillMask) { + ldr(Reg2.X(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.gregs[i + 1])); } } @@ -880,8 +817,7 @@ void Arm64Emitter::PushVectorRegisters(FEXCore::ARMEmitter::Register TmpReg, boo st4b(Reg1.Z(), Reg2.Z(), Reg3.Z(), Reg4.Z(), PRED_TMP_32B, TmpReg, 0); add(ARMEmitter::Size::i64Bit, TmpReg, TmpReg, 32 * 4); } - } - else { + } else { size_t i = 0; for (; i < (VRegs.size() % 4); i += 2) { const auto Reg1 = VRegs[i]; @@ -965,8 +901,7 @@ void Arm64Emitter::PopGeneralRegisters(std::spanHostFeatures.SupportsAVX; const auto GPRSize = (ConfiguredDynamicRegisterBase.size() + 1) * Core::CPUState::GPR_REG_SIZE; - const auto FPRRegSize = CanUseSVE ? Core::CPUState::XMM_AVX_REG_SIZE - : Core::CPUState::XMM_SSE_REG_SIZE; + const auto FPRRegSize = CanUseSVE ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; const auto FPRSize = GeneralFPRegisters.size() * FPRRegSize; const uint64_t SPOffset = AlignUp(GPRSize + FPRSize, 16); @@ -1004,13 +939,12 @@ void Arm64Emitter::PopDynamicRegsAndLR() { void Arm64Emitter::SpillForPreserveAllABICall(FEXCore::ARMEmitter::Register TmpReg, bool FPRs) { const auto CanUseSVE = EmitterCTX->HostFeatures.SupportsAVX; - const auto FPRRegSize = CanUseSVE ? Core::CPUState::XMM_AVX_REG_SIZE - : Core::CPUState::XMM_SSE_REG_SIZE; + const auto FPRRegSize = CanUseSVE ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; - std::span DynamicGPRs{}; - std::span DynamicFPRs{}; - uint32_t PreserveSRAMask{}; - uint32_t PreserveSRAFPRMask{}; + std::span DynamicGPRs {}; + std::span DynamicFPRs {}; + uint32_t PreserveSRAMask {}; + uint32_t PreserveSRAFPRMask {}; if (EmitterCTX->Config.Is64BitMode()) { DynamicGPRs = x64::PreserveAll_Dynamic; DynamicFPRs = x64::PreserveAll_DynamicFPR; @@ -1021,8 +955,7 @@ void Arm64Emitter::SpillForPreserveAllABICall(FEXCore::ARMEmitter::Register TmpR DynamicFPRs = x64::PreserveAll_DynamicFPRSVE; PreserveSRAFPRMask = x64::PreserveAll_SRAFPRSVEMask; } - } - else { + } else { DynamicGPRs = x32::PreserveAll_Dynamic; DynamicFPRs = x32::PreserveAll_DynamicFPR; PreserveSRAMask = x32::PreserveAll_SRAMask; @@ -1056,10 +989,10 @@ void Arm64Emitter::SpillForPreserveAllABICall(FEXCore::ARMEmitter::Register TmpR void Arm64Emitter::FillForPreserveAllABICall(bool FPRs) { const auto CanUseSVE = EmitterCTX->HostFeatures.SupportsAVX; - std::span DynamicGPRs{}; - std::span DynamicFPRs{}; - uint32_t PreserveSRAMask{}; - uint32_t PreserveSRAFPRMask{}; + std::span DynamicGPRs {}; + std::span DynamicFPRs {}; + uint32_t PreserveSRAMask {}; + uint32_t PreserveSRAFPRMask {}; if (EmitterCTX->Config.Is64BitMode()) { DynamicGPRs = x64::PreserveAll_Dynamic; @@ -1071,8 +1004,7 @@ void Arm64Emitter::FillForPreserveAllABICall(bool FPRs) { DynamicFPRs = x64::PreserveAll_DynamicFPRSVE; PreserveSRAFPRMask = x64::PreserveAll_SRAFPRSVEMask; } - } - else { + } else { DynamicGPRs = x32::PreserveAll_Dynamic; DynamicFPRs = x32::PreserveAll_DynamicFPR; PreserveSRAMask = x32::PreserveAll_SRAMask; @@ -1101,4 +1033,4 @@ void Arm64Emitter::Align16B() { } } -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h index a21338ef2..b2e91c927 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h +++ b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h @@ -80,17 +80,17 @@ constexpr FEXCore::ARMEmitter::PRegister PRED_TMP_32B = FEXCore::ARMEmitter::PRe // be used by both Arm64 JIT and ARM64 Dispatcher class Arm64Emitter : public FEXCore::ARMEmitter::Emitter { protected: - Arm64Emitter(FEXCore::Context::ContextImpl *ctx, void* EmissionPtr = nullptr, size_t size = 0); + Arm64Emitter(FEXCore::Context::ContextImpl* ctx, void* EmissionPtr = nullptr, size_t size = 0); - FEXCore::Context::ContextImpl *EmitterCTX; + FEXCore::Context::ContextImpl* EmitterCTX; vixl::aarch64::CPU CPU; - std::span ConfiguredDynamicRegisterBase{}; - std::span StaticRegisters{}; - std::span GeneralRegisters{}; - std::span> GeneralPairRegisters{}; - std::span StaticFPRegisters{}; - std::span GeneralFPRegisters{}; + std::span ConfiguredDynamicRegisterBase {}; + std::span StaticRegisters {}; + std::span GeneralRegisters {}; + std::span> GeneralPairRegisters {}; + std::span StaticFPRegisters {}; + std::span GeneralFPRegisters {}; /** * @name Register Allocation @@ -152,8 +152,7 @@ protected: void SpillForABICall(bool SupportsPreserveAllABI, FEXCore::ARMEmitter::Register TmpReg, bool FPRs = true) { if (SupportsPreserveAllABI) { SpillForPreserveAllABICall(TmpReg, FPRs); - } - else { + } else { SpillStaticRegs(TmpReg, FPRs); PushDynamicRegsAndLR(TmpReg); } @@ -162,8 +161,7 @@ protected: void FillForABICall(bool SupportsPreserveAllABI, bool FPRs = true) { if (SupportsPreserveAllABI) { FillForPreserveAllABICall(FPRs); - } - else { + } else { PopDynamicRegsAndLR(); FillStaticRegs(FPRs); } @@ -185,8 +183,7 @@ protected: template void GenerateRuntimeCall(R (*Function)(P...)) { - uintptr_t SimulatorWrapperAddress = reinterpret_cast( - &(vixl::aarch64::Simulator::RuntimeCallStructHelper::Wrapper)); + uintptr_t SimulatorWrapperAddress = reinterpret_cast(&(vixl::aarch64::Simulator::RuntimeCallStructHelper::Wrapper)); uintptr_t FunctionAddress = reinterpret_cast(Function); @@ -204,8 +201,7 @@ protected: template void GenerateIndirectRuntimeCall(ARMEmitter::Register Reg) { - uintptr_t SimulatorWrapperAddress = reinterpret_cast( - &(vixl::aarch64::Simulator::RuntimeCallStructHelper::Wrapper)); + uintptr_t SimulatorWrapperAddress = reinterpret_cast(&(vixl::aarch64::Simulator::RuntimeCallStructHelper::Wrapper)); hlt(vixl::aarch64::kIndirectRuntimeCallOpcode); @@ -221,8 +217,8 @@ protected: template<> void GenerateIndirectRuntimeCall(ARMEmitter::Register Reg) { - uintptr_t SimulatorWrapperAddress = reinterpret_cast( - &(vixl::aarch64::Simulator::RuntimeCallStructHelper::Wrapper)); + uintptr_t SimulatorWrapperAddress = + reinterpret_cast(&(vixl::aarch64::Simulator::RuntimeCallStructHelper::Wrapper)); hlt(vixl::aarch64::kIndirectRuntimeCallOpcode); @@ -262,4 +258,4 @@ protected: #endif }; -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Buffer.h b/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Buffer.h index e9e5ecb2c..c04c15b38 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Buffer.h +++ b/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Buffer.h @@ -5,102 +5,102 @@ #include namespace FEXCore::ARMEmitter { - class Buffer { - public: - Buffer() { - SetBuffer(nullptr, 0); - } +class Buffer { +public: + Buffer() { + SetBuffer(nullptr, 0); + } - Buffer(uint8_t* Base, uint64_t BaseSize) { - SetBuffer(Base, BaseSize); - } + Buffer(uint8_t* Base, uint64_t BaseSize) { + SetBuffer(Base, BaseSize); + } - void SetBuffer(uint8_t* Base, uint64_t BaseSize) { - BufferBase = Base; - CurrentOffset = BufferBase; - Size = BaseSize; - } + void SetBuffer(uint8_t* Base, uint64_t BaseSize) { + BufferBase = Base; + CurrentOffset = BufferBase; + Size = BaseSize; + } - void dc8(uint8_t Data) { - decltype(Data) *Memory = reinterpret_cast(CurrentOffset); - *Memory = Data; - CurrentOffset += sizeof(Data); - } + void dc8(uint8_t Data) { + decltype(Data)* Memory = reinterpret_cast(CurrentOffset); + *Memory = Data; + CurrentOffset += sizeof(Data); + } - void dc16(uint16_t Data) { - decltype(Data) *Memory = reinterpret_cast(CurrentOffset); - *Memory = Data; - CurrentOffset += sizeof(Data); - } + void dc16(uint16_t Data) { + decltype(Data)* Memory = reinterpret_cast(CurrentOffset); + *Memory = Data; + CurrentOffset += sizeof(Data); + } - void dc32(uint32_t Data) { - decltype(Data) *Memory = reinterpret_cast(CurrentOffset); - *Memory = Data; - CurrentOffset += sizeof(Data); - } + void dc32(uint32_t Data) { + decltype(Data)* Memory = reinterpret_cast(CurrentOffset); + *Memory = Data; + CurrentOffset += sizeof(Data); + } - void dc64(uint64_t Data) { - decltype(Data) *Memory = reinterpret_cast(CurrentOffset); - *Memory = Data; - CurrentOffset += sizeof(Data); - } - void EmitString(const char *String) { - const auto StringLength = strlen(String); - memcpy(CurrentOffset, String, StringLength); - CurrentOffset += StringLength; - } + void dc64(uint64_t Data) { + decltype(Data)* Memory = reinterpret_cast(CurrentOffset); + *Memory = Data; + CurrentOffset += sizeof(Data); + } + void EmitString(const char* String) { + const auto StringLength = strlen(String); + memcpy(CurrentOffset, String, StringLength); + CurrentOffset += StringLength; + } - void Align() { - // Align the buffer to instruction size - auto CurrentAlignment = reinterpret_cast(CurrentOffset) & 0b11; - if (!CurrentAlignment) { - return; - } - CurrentOffset += 4 - CurrentAlignment; - } + void Align() { + // Align the buffer to instruction size + auto CurrentAlignment = reinterpret_cast(CurrentOffset) & 0b11; + if (!CurrentAlignment) { + return; + } + CurrentOffset += 4 - CurrentAlignment; + } - template - T GetCursorAddress() const { - return reinterpret_cast(CurrentOffset); - } + template + T GetCursorAddress() const { + return reinterpret_cast(CurrentOffset); + } - static void ClearICache(void* Begin, std::size_t Length) { - __builtin___clear_cache(static_cast(Begin), static_cast(Begin) + Length); - } + static void ClearICache(void* Begin, std::size_t Length) { + __builtin___clear_cache(static_cast(Begin), static_cast(Begin) + Length); + } - size_t GetCursorOffset() const { - return static_cast(CurrentOffset - BufferBase); - } + size_t GetCursorOffset() const { + return static_cast(CurrentOffset - BufferBase); + } - uint8_t *GetBufferBase() const { - return BufferBase; - } + uint8_t* GetBufferBase() const { + return BufferBase; + } - void CursorIncrement(size_t Size) { - CurrentOffset += Size; - } + void CursorIncrement(size_t Size) { + CurrentOffset += Size; + } - void SetCursorOffset(size_t Offset) { - CurrentOffset = BufferBase + Offset; - } + void SetCursorOffset(size_t Offset) { + CurrentOffset = BufferBase + Offset; + } - uint64_t GetBufferSize() const { - return Size; - } + uint64_t GetBufferSize() const { + return Size; + } - template - size_t GetCursorOffsetFromAddress(const T* Address) const { - return static_cast(reinterpret_cast(Address) - BufferBase); - } + template + size_t GetCursorOffsetFromAddress(const T* Address) const { + return static_cast(reinterpret_cast(Address) - BufferBase); + } - protected: +protected: - void ResetBuffer() { - CurrentOffset = BufferBase; - } + void ResetBuffer() { + CurrentOffset = BufferBase; + } - uint8_t* BufferBase; - uint8_t* CurrentOffset; - uint64_t Size; - }; -} + uint8_t* BufferBase; + uint8_t* CurrentOffset; + uint64_t Size; +}; +} // namespace FEXCore::ARMEmitter diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h b/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h index babb1801f..d102e6436 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h +++ b/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h @@ -57,727 +57,709 @@ * the right instruction. */ namespace FEXCore::ARMEmitter { - /* - * This `Size` enum is used for most ALU operations. - * These follow the AArch64 encoding style in most cases. - */ - enum class Size : uint32_t { - i32Bit = 0, - i64Bit, +/* + * This `Size` enum is used for most ALU operations. + * These follow the AArch64 encoding style in most cases. + */ +enum class Size : uint32_t { + i32Bit = 0, + i64Bit, +}; + +// This allows us to get the `Size` enum in bits. +[[nodiscard]] +constexpr size_t RegSizeInBits(Size size) { + return size_t {32} << FEXCore::ToUnderlying(size); +} + +/* This `SubRegSize` enum is used for most ASIMD operations. + * These follow the AArch64 encoding style in most cases. + */ +enum class SubRegSize : uint32_t { + i8Bit = 0b00, + i16Bit = 0b01, + i32Bit = 0b10, + i64Bit = 0b11, + i128Bit = 0b100, +}; + +// This allows us to get the `SubRegSize` in bits. +[[nodiscard]] +constexpr size_t SubRegSizeInBits(SubRegSize size) { + return size_t {8} << FEXCore::ToUnderlying(size); +} + +/* This `ScalarRegSize` enum is used for most scalar float + * operations. + * + * This is specifically duplicated from `SubRegSize` to have strongly + * typed functions. + * + * `ScalarRegSize` specifically doesn't have `i128Bit` because scalar operations + * can't operate at 128-bit. + */ +enum class ScalarRegSize : uint32_t { + i8Bit = 0b00, + i16Bit = 0b01, + i32Bit = 0b10, + i64Bit = 0b11, +}; + +// This allows us to get the `ScalarRegSize` in bits. +[[nodiscard]] +constexpr size_t ScalarRegSizeInBits(ScalarRegSize size) { + return size_t {8} << FEXCore::ToUnderlying(size); +} + +/* This `VectorRegSizePair` union allows us to have an overlapping type + * to select a scalar operation or a vector depending on which operation + * we pass in. + * Useful in FEX's vector operations that behave as scalar or vector + * depending on various factors. But since the operation will have the sa,e + * element size, we want to choose the operation more easily + */ +union VectorRegSizePair { + ScalarRegSize Scalar; + SubRegSize Vector; +}; + +// This allows us to create a `VectorRegSizePair` union. +[[nodiscard]] +constexpr VectorRegSizePair ToVectorSizePair(SubRegSize size) { + return VectorRegSizePair {.Vector = size}; +} +[[nodiscard]] +constexpr VectorRegSizePair ToVectorSizePair(ScalarRegSize size) { + return VectorRegSizePair {.Scalar = size}; +} + +// This `ShiftType` enum is used for ALU shift-register encoded instructions. +enum class ShiftType : uint32_t { + LSL = 0, + LSR, + ASR, + ROR, +}; + +// This `ExtendedType` enum is used for ALU extended-register encoded instructions. +enum class ExtendedType : uint32_t { + UXTB = 0b000, + UXTH = 0b001, + UXTW = 0b010, + UXTX = 0b011, + SXTB = 0b100, + SXTH = 0b101, + SXTW = 0b110, + SXTX = 0b111, + LSL_32 = UXTW, + LSL_64 = UXTX, +}; + +// This `Condition` enum is used for various conditional instructions. +enum class Condition : uint32_t { + // Meaning: Int - Float + CC_EQ = 0, // Equal - Equal + CC_NE, // Not Eq - Not Eq or unordered + CC_CS, // Carry set - Greater than, equal, or unordered + CC_CC, // Carry clear - Less than + CC_MI, // Minus/Negative - Less than + CC_PL, // Plus, positive or zero - GT, equal, or unordered + CC_VS, // Overflow - Unordered + CC_VC, // No Overflow - Ordered + CC_HI, // Unsigned higher - GT, or unordered + CC_LS, // Unsigned lower or same - LT or EQ + CC_GE, // Signed GT or EQ - GT or EQ + CC_LT, // Signed LT - LT or Unordered + CC_GT, // Signed GT - GT + CC_LE, // Signed LT or EQ - LT, EQ, or Unordered + CC_AL, // Always - Always + CC_NV, // Always - Always + + // Aliases + CC_HS = CC_CS, + CC_LO = CC_CC, +}; + +/* + * This `StatusFlags` enum is used for conditional compare encoded instructions. + * These directly encode to the `nzcv` flags. + */ +enum class StatusFlags : uint32_t { + None = 0, + Flag_V = 0b0001, + Flag_C = 0b0010, + Flag_Z = 0b0100, + Flag_N = 0b1000, + + Flag_NZCV = Flag_N | Flag_Z | Flag_C | Flag_V, +}; + + +/* + * This `IndexType` enum is used for load-store instructions. + * Not all load-store instructions use this, so the user needs to be careful. + */ +enum class IndexType { + POST, + OFFSET, + PRE, + + UNPRIVILEGED, +}; + +// Used with adr and scalar + vector load/store variants to denote +// a modifier operation. +enum class SVEModType : uint8_t { + MOD_UXTW, + MOD_SXTW, + MOD_LSL, + MOD_NONE, +}; + +/* This `SVEMemOperand` class is used for the helper SVE load-store instructions. + * Load-store instructions are quite expressive, so having a helper that handles these differences is worth it. + */ +class SVEMemOperand final { +public: + enum class Type { + ScalarPlusScalar, + ScalarPlusImm, + ScalarPlusVector, + VectorPlusImm, }; - // This allows us to get the `Size` enum in bits. + SVEMemOperand(XRegister rn, XRegister rm = XReg::zr) + : rn {rn} + , MemType {Type::ScalarPlusScalar} + , MetaType {.ScalarScalarType { + .rm = rm, + }} {} + SVEMemOperand(XRegister rn, int32_t imm = 0) + : rn {rn} + , MemType {Type::ScalarPlusImm} + , MetaType {.ScalarImmType { + .Imm = imm, + }} {} + SVEMemOperand(XRegister rn, ZRegister zm, SVEModType mod = SVEModType::MOD_NONE, uint8_t scale = 0) + : rn {rn} + , MemType {Type::ScalarPlusVector} + , MetaType {.ScalarVectorType { + .zm = zm, + .mod = mod, + .scale = scale, + }} {} + SVEMemOperand(ZRegister zn, uint32_t imm) + : rn {Register {zn.Idx()}} + , MemType {Type::VectorPlusImm} + , MetaType {.VectorImmType { + .Imm = imm, + }} {} + [[nodiscard]] - constexpr size_t RegSizeInBits(Size size) { - return size_t{32} << FEXCore::ToUnderlying(size); - } - - /* This `SubRegSize` enum is used for most ASIMD operations. - * These follow the AArch64 encoding style in most cases. - */ - enum class SubRegSize : uint32_t { - i8Bit = 0b00, - i16Bit = 0b01, - i32Bit = 0b10, - i64Bit = 0b11, - i128Bit = 0b100, - }; - - // This allows us to get the `SubRegSize` in bits. - [[nodiscard]] - constexpr size_t SubRegSizeInBits(SubRegSize size) { - return size_t{8} << FEXCore::ToUnderlying(size); - } - - /* This `ScalarRegSize` enum is used for most scalar float - * operations. - * - * This is specifically duplicated from `SubRegSize` to have strongly - * typed functions. - * - * `ScalarRegSize` specifically doesn't have `i128Bit` because scalar operations - * can't operate at 128-bit. - */ - enum class ScalarRegSize : uint32_t { - i8Bit = 0b00, - i16Bit = 0b01, - i32Bit = 0b10, - i64Bit = 0b11, - }; - - // This allows us to get the `ScalarRegSize` in bits. - [[nodiscard]] - constexpr size_t ScalarRegSizeInBits(ScalarRegSize size) { - return size_t{8} << FEXCore::ToUnderlying(size); - } - - /* This `VectorRegSizePair` union allows us to have an overlapping type - * to select a scalar operation or a vector depending on which operation - * we pass in. - * Useful in FEX's vector operations that behave as scalar or vector - * depending on various factors. But since the operation will have the sa,e - * element size, we want to choose the operation more easily - */ - union VectorRegSizePair { - ScalarRegSize Scalar; - SubRegSize Vector; - }; - - // This allows us to create a `VectorRegSizePair` union. - [[nodiscard]] - constexpr VectorRegSizePair ToVectorSizePair(SubRegSize size) { - return VectorRegSizePair {.Vector = size}; + bool IsScalarPlusScalar() const { + return MemType == Type::ScalarPlusScalar; } [[nodiscard]] - constexpr VectorRegSizePair ToVectorSizePair(ScalarRegSize size) { - return VectorRegSizePair {.Scalar = size}; + bool IsScalarPlusImm() const { + return MemType == Type::ScalarPlusImm; + } + [[nodiscard]] + bool IsScalarPlusVector() const { + return MemType == Type::ScalarPlusVector; + } + [[nodiscard]] + bool IsVectorPlusImm() const { + return MemType == Type::VectorPlusImm; } - // This `ShiftType` enum is used for ALU shift-register encoded instructions. - enum class ShiftType : uint32_t { - LSL = 0, - LSR, - ASR, - ROR, + union Data { + struct { + Register rm; + } ScalarScalarType; + + struct { + int32_t Imm; + } ScalarImmType; + + struct { + ZRegister zm; + SVEModType mod; + uint8_t scale; + } ScalarVectorType; + + struct { + // rn will be a ZRegister + uint32_t Imm; + } VectorImmType; }; - // This `ExtendedType` enum is used for ALU extended-register encoded instructions. - enum class ExtendedType : uint32_t { - UXTB = 0b000, - UXTH = 0b001, - UXTW = 0b010, - UXTX = 0b011, - SXTB = 0b100, - SXTH = 0b101, - SXTW = 0b110, - SXTX = 0b111, - LSL_32 = UXTW, - LSL_64 = UXTX, + Register rn; + Type MemType; + Data MetaType; +}; + +/* This `ExtendedMemOperand` class is used for the helper load-store instructions. + * Load-store instructions are quite expressive, so having a helper that handles these differences is worth it. + */ +class ExtendedMemOperand final { +public: + ExtendedMemOperand(XRegister rn, XRegister rm = XReg::zr, ExtendedType Option = ExtendedType::LSL_64, uint32_t Shift = 0) + : rn {rn} + , MetaType {.ExtendedType { + .Header = {.MemType = TYPE_EXTENDED}, + .rm = rm, + .Option = Option, + .Shift = Shift, + }} {} + ExtendedMemOperand(XRegister rn, IndexType Index = IndexType::OFFSET, int32_t Imm = 0) + : rn {rn} + , MetaType {.ImmType { + .Header = {.MemType = TYPE_IMM}, + .Index = Index, + .Imm = Imm, + }} {} + + Register rn; + enum Type { + TYPE_EXTENDED, + TYPE_IMM, + }; + struct HeaderStruct { + Type MemType; + }; + union { + HeaderStruct Header; + struct { + HeaderStruct Header; + Register rm; + ExtendedType Option; + uint32_t Shift; + } ExtendedType; + struct { + HeaderStruct Header; + IndexType Index; + int32_t Imm; + } ImmType; + } MetaType; +}; + +template +constexpr uint32_t GenSystemReg() { + return op0 << 19 | op1 << 16 | CRn << 12 | CRm << 8 | op2 << 5; +}; + +// This `SystemRegister` enum is used for the mrs/msr instructions. +enum class SystemRegister : uint32_t { + CTR_EL0 = GenSystemReg<0b11, 0b011, 0b0000, 0b0000, 0b001>(), + DCZID_EL0 = GenSystemReg<0b11, 0b011, 0b0000, 0b0000, 0b111>(), + TPIDR_EL0 = GenSystemReg<0b11, 0b011, 0b1101, 0b0000, 0b010>(), + RNDR = GenSystemReg<0b11, 0b011, 0b0010, 0b0100, 0b000>(), + RNDRRS = GenSystemReg<0b11, 0b011, 0b0010, 0b0100, 0b001>(), + NZCV = GenSystemReg<0b11, 0b011, 0b0100, 0b0010, 0b000>(), + FPCR = GenSystemReg<0b11, 0b011, 0b0100, 0b0100, 0b000>(), + CNTFRQ_EL0 = GenSystemReg<0b11, 0b011, 0b1110, 0b0000, 0b000>(), + CNTVCT_EL0 = GenSystemReg<0b11, 0b011, 0b1110, 0b0000, 0b010>(), +}; + +template +constexpr uint32_t GenDCReg() { + return op1 << 16 | CRm << 8 | op2 << 5; +}; + +// This `DataCacheOperation` enum is used for the dc instruction. +enum class DataCacheOperation : uint32_t { + IVAC = GenDCReg<0b000, 0b0110, 0b001>(), + ISW = GenDCReg<0b000, 0b0110, 0b010>(), + CSW = GenDCReg<0b000, 0b1010, 0b010>(), + CISW = GenDCReg<0b000, 0b1110, 0b010>(), + ZVA = GenDCReg<0b011, 0b0100, 0b001>(), + CVAC = GenDCReg<0b011, 0b1010, 0b001>(), + CVAU = GenDCReg<0b011, 0b1011, 0b001>(), + CIVAC = GenDCReg<0b011, 0b1110, 0b001>(), + + // MTE2 + IGVAC = GenDCReg<0b000, 0b0110, 0b011>(), + IGSW = GenDCReg<0b000, 0b0110, 0b100>(), + IGDVAC = GenDCReg<0b000, 0b0110, 0b101>(), + IGDSW = GenDCReg<0b000, 0b0110, 0b110>(), + CGSW = GenDCReg<0b000, 0b1010, 0b100>(), + CGDSW = GenDCReg<0b000, 0b1010, 0b110>(), + CIGSW = GenDCReg<0b000, 0b1110, 0b100>(), + CIGDSW = GenDCReg<0b000, 0b1110, 0b110>(), + + // MTE + GVA = GenDCReg<0b011, 0b0100, 0b011>(), + GZVA = GenDCReg<0b011, 0b0100, 0b100>(), + CGVAC = GenDCReg<0b011, 0b1010, 0b011>(), + CGDVAC = GenDCReg<0b011, 0b1010, 0b101>(), + CGVAP = GenDCReg<0b011, 0b1100, 0b011>(), + CGDVAP = GenDCReg<0b011, 0b1100, 0b101>(), + CGVADP = GenDCReg<0b011, 0b1101, 0b011>(), + CGDVADP = GenDCReg<0b011, 0b1101, 0b101>(), + CIGVAC = GenDCReg<0b011, 0b1110, 0b011>(), + CIGDVAC = GenDCReg<0b011, 0b1110, 0b101>(), + + // DPB + CVAP = GenDCReg<0b011, 0b1100, 0b001>(), + + // DPB2 + CVADP = GenDCReg<0b011, 0b1101, 0b001>(), +}; + +template +constexpr uint32_t GenHintBarrierReg() { + return CRm << 8 | op2 << 5; +} + +// This `HintRegister` enum is used for the hint instruction. +enum class HintRegister : uint32_t { + NOP = GenHintBarrierReg<0b0000, 0b000>(), + YIELD = GenHintBarrierReg<0b0000, 0b001>(), + WFE = GenHintBarrierReg<0b0000, 0b010>(), + WFI = GenHintBarrierReg<0b0000, 0b011>(), + SEV = GenHintBarrierReg<0b0000, 0b100>(), + SEVL = GenHintBarrierReg<0b0000, 0b101>(), + DGH = GenHintBarrierReg<0b0000, 0b110>(), + CSDB = GenHintBarrierReg<0b0010, 0b100>(), +}; + +// This `BarrierRegister` enum is used for the various barrier instructions. +enum class BarrierRegister : uint32_t { + CLREX = GenHintBarrierReg<0b0000, 0b010>(), + TCOMMIT = GenHintBarrierReg<0b0000, 0b011>(), + DSB = GenHintBarrierReg<0b0000, 0b100>(), + DMB = GenHintBarrierReg<0b0000, 0b101>(), + ISB = GenHintBarrierReg<0b0000, 0b110>(), + SB = GenHintBarrierReg<0b0000, 0b111>(), +}; + +// This `BarrierScope` enum is used for the dsb/dmb instructions. +enum class BarrierScope : uint32_t { + // Outer shareable + OSHLD = 0b0001, + OSHST = 0b0010, + OSH = 0b0011, + // Non shareable + NSHLD = 0b0101, + NSHST = 0b0110, + NSH = 0b0111, + // Inner shareable + ISHLD = 0b1001, + ISHST = 0b1010, + ISH = 0b1011, + // Full System visibility + LD = 0b1101, + ST = 0b1110, + SY = 0b1111, +}; + +// This `Prefetch` enum is used for prefetch instructions. +enum class Prefetch : uint32_t { + // Prefetch for load + PLDL1KEEP = 0b00000, + PLDL1STRM = 0b00001, + PLDL2KEEP = 0b00010, + PLDL2STRM = 0b00011, + PLDL3KEEP = 0b00100, + PLDL3STRM = 0b00101, + + // Preload instructions + PLIL1KEEP = 0b01000, + PLIL1STRM = 0b01001, + PLIL2KEEP = 0b01010, + PLIL2STRM = 0b01011, + PLIL3KEEP = 0b01100, + PLIL3STRM = 0b01101, + + // Preload for store + PSTL1KEEP = 0b10000, + PSTL1STRM = 0b10001, + PSTL2KEEP = 0b10010, + PSTL2STRM = 0b10011, + PSTL3KEEP = 0b10100, + PSTL3STRM = 0b10101, +}; + +// This `PredicatePattern` enun is used for some SVE instructions. +enum class PredicatePattern : uint32_t { + SVE_POW2 = 0b00000, + SVE_VL1 = 0b00001, + SVE_VL2 = 0b00010, + SVE_VL3 = 0b00011, + SVE_VL4 = 0b00100, + SVE_VL5 = 0b00101, + SVE_VL6 = 0b00110, + SVE_VL7 = 0b00111, + SVE_VL8 = 0b01000, + SVE_VL16 = 0b01001, + SVE_VL32 = 0b01010, + SVE_VL64 = 0b01011, + SVE_VL128 = 0b01100, + SVE_VL256 = 0b01101, + SVE_MUL4 = 0b11101, + SVE_MUL3 = 0b11110, + SVE_ALL = 0b11111, +}; + +// Used with SVE FP immediate arithmetic instructions +enum class SVEFAddSubImm : uint32_t { + _0_5, + _1_0, +}; +enum class SVEFMulImm : uint32_t { + _0_5, + _2_0, +}; +enum class SVEFMaxMinImm : uint32_t { + _0_0, + _1_0, +}; + +/* This `BackwardLabel` struct used for retaining a location for PC-Relative instructions. + * This is specifically a label for a target that is logically `below` an instruction that uses it. + * Which means that a branch would jump backwards. + */ +struct BackwardLabel { + uint8_t* Location {}; +}; + +/* This `SingleUseForwardLabel` struct used for retaining a location for PC-Relative instructions. + * This is specifically a label for a target that is logically `above` an instruction that uses it. + * Which means that a branch would jump forwards. + * + * The `ForwardLabel` struct can be bound to multiple instructions, so it needs a vector for each bind instruction type. + */ +struct SingleUseForwardLabel { + enum class InstType { + UNKNOWN, + ADR, + ADRP, + B, + BC, + TEST_BRANCH, + RELATIVE_LOAD, + LONG_ADDRESS_GEN, + }; + uint8_t* Location {}; + InstType Type = InstType::UNKNOWN; +}; + +struct ForwardLabel { + fextl::vector Insts {}; +}; + +/* This `BiDirectionalLabel` struct used for retaining a location for PC-Relative instructions. + * This is specifically a label for a target that is in either direction of an instruction that uses it. + * Which means a branch could jump backwards or forwards depending on situation. + */ +struct BiDirectionalLabel { + BackwardLabel Backward; + ForwardLabel Forward; +}; + +static inline void AddLocationToLabel(SingleUseForwardLabel* Label, SingleUseForwardLabel&& Location) { + LOGMAN_THROW_A_FMT(Label->Type == SingleUseForwardLabel::InstType::UNKNOWN, "Trying to bind a SingleUseForwardLabel to multiple " + "locations. Use ForwardLabel instead."); + *Label = std::move(Location); +} + +static inline void AddLocationToLabel(ForwardLabel* Label, SingleUseForwardLabel&& Location) { + Label->Insts.emplace_back(std::move(Location)); +} + +// Some FCMA ASIMD instructions support a rotation argument. +enum class Rotation : uint32_t { + ROTATE_0 = 0b00, + ROTATE_90 = 0b01, + ROTATE_180 = 0b10, + ROTATE_270 = 0b11, +}; + +// Concept for contraining some instructions to accept only an XRegister or WRegister. +// Particularly for operations that differ encodings depending on which one is used. +template +concept IsXOrWRegister = std::is_same_v || std::is_same_v; + +// Whether or not a given set of vector registers are sequential +// in increasing order as far as the register file is concerned (modulo its size) +// +// For example, a set of registers like: +// +// v1, v2, v3 and +// v31, v0, v1 +// +// would both be considered sequential sequences, and some instructions in particular +// limit register lists to these kind of sequences. +// +template +constexpr bool AreVectorsSequential(T first, const Args&... args) { + // Ensure we always have a pair of registers to compare against. + static_assert(sizeof...(args) >= 1, "Number of arguments must be greater than 1"); + + const auto fn = [](auto& lhs, const auto& rhs) { + const auto result = ((lhs.Idx() + 1) % 32) == rhs.Idx(); + lhs = rhs; + return result; }; - // This `Condition` enum is used for various conditional instructions. - enum class Condition : uint32_t { - // Meaning: Int - Float - CC_EQ = 0, // Equal - Equal - CC_NE, // Not Eq - Not Eq or unordered - CC_CS, // Carry set - Greater than, equal, or unordered - CC_CC, // Carry clear - Less than - CC_MI, // Minus/Negative - Less than - CC_PL, // Plus, positive or zero - GT, equal, or unordered - CC_VS, // Overflow - Unordered - CC_VC, // No Overflow - Ordered - CC_HI, // Unsigned higher - GT, or unordered - CC_LS, // Unsigned lower or same - LT or EQ - CC_GE, // Signed GT or EQ - GT or EQ - CC_LT, // Signed LT - LT or Unordered - CC_GT, // Signed GT - GT - CC_LE, // Signed LT or EQ - LT, EQ, or Unordered - CC_AL, // Always - Always - CC_NV, // Always - Always + return (fn(first, args) && ...); +} - // Aliases - CC_HS = CC_CS, - CC_LO = CC_CC, - }; +// This is an emitter that is designed around the smallest code bloat as possible. +// Eschewing most developer convenience in order to keep code as small as possible. - /* - * This `StatusFlags` enum is used for conditional compare encoded instructions. - * These directly encode to the `nzcv` flags. - */ - enum class StatusFlags : uint32_t { - None = 0, - Flag_V = 0b0001, - Flag_C = 0b0010, - Flag_Z = 0b0100, - Flag_N = 0b1000, +// Choices: +// - Size of ops passed as an argument rather than template to let the compiler use csel instead of branching. +// - Registers are unsized so they can be passed in a GPR and not need conversion operations +class Emitter : public FEXCore::ARMEmitter::Buffer { +public: + Emitter() = default; - Flag_NZCV = Flag_N | Flag_Z | Flag_C | Flag_V, - }; + Emitter(uint8_t* Base, uint64_t BaseSize) + : Buffer(Base, BaseSize) {} - - /* - * This `IndexType` enum is used for load-store instructions. - * Not all load-store instructions use this, so the user needs to be careful. - */ - enum class IndexType { - POST, - OFFSET, - PRE, - - UNPRIVILEGED, - }; - - // Used with adr and scalar + vector load/store variants to denote - // a modifier operation. - enum class SVEModType : uint8_t { - MOD_UXTW, - MOD_SXTW, - MOD_LSL, - MOD_NONE, - }; - - /* This `SVEMemOperand` class is used for the helper SVE load-store instructions. - * Load-store instructions are quite expressive, so having a helper that handles these differences is worth it. - */ - class SVEMemOperand final { - public: - enum class Type { - ScalarPlusScalar, - ScalarPlusImm, - ScalarPlusVector, - VectorPlusImm, - }; - - SVEMemOperand(XRegister rn, XRegister rm = XReg::zr) - : rn {rn} - , MemType{Type::ScalarPlusScalar} - , MetaType { - .ScalarScalarType { - .rm = rm, - } - } {} - SVEMemOperand(XRegister rn, int32_t imm = 0) - : rn {rn} - , MemType{Type::ScalarPlusImm} - , MetaType { - .ScalarImmType { - .Imm = imm, - } - } {} - SVEMemOperand(XRegister rn, ZRegister zm, SVEModType mod = SVEModType::MOD_NONE, uint8_t scale = 0) - : rn{rn} - , MemType{Type::ScalarPlusVector} - , MetaType { - .ScalarVectorType { - .zm = zm, - .mod = mod, - .scale = scale, - } - } {} - SVEMemOperand(ZRegister zn, uint32_t imm) - : rn{Register{zn.Idx()}} - , MemType{Type::VectorPlusImm} - , MetaType { - .VectorImmType{ - .Imm = imm, - } - } {} - - [[nodiscard]] bool IsScalarPlusScalar() const { - return MemType == Type::ScalarPlusScalar; - } - [[nodiscard]] bool IsScalarPlusImm() const { - return MemType == Type::ScalarPlusImm; - } - [[nodiscard]] bool IsScalarPlusVector() const { - return MemType == Type::ScalarPlusVector; - } - [[nodiscard]] bool IsVectorPlusImm() const { - return MemType == Type::VectorPlusImm; - } - - union Data { - struct { - Register rm; - } ScalarScalarType; - - struct { - int32_t Imm; - } ScalarImmType; - - struct { - ZRegister zm; - SVEModType mod; - uint8_t scale; - } ScalarVectorType; - - struct { - // rn will be a ZRegister - uint32_t Imm; - } VectorImmType; - }; - - Register rn; - Type MemType; - Data MetaType; - }; - - /* This `ExtendedMemOperand` class is used for the helper load-store instructions. - * Load-store instructions are quite expressive, so having a helper that handles these differences is worth it. - */ - class ExtendedMemOperand final { - public: - ExtendedMemOperand(XRegister rn, XRegister rm = XReg::zr, ExtendedType Option = ExtendedType::LSL_64, uint32_t Shift = 0) - : rn {rn} - , MetaType { - .ExtendedType { - .Header = { .MemType = TYPE_EXTENDED }, - .rm = rm, - .Option = Option, - .Shift = Shift, - } - } {} - ExtendedMemOperand(XRegister rn, IndexType Index = IndexType::OFFSET, int32_t Imm = 0) - : rn {rn} - , MetaType { - .ImmType { - .Header = { .MemType = TYPE_IMM }, - .Index = Index, - .Imm = Imm, - } - } {} - - Register rn; - enum Type { - TYPE_EXTENDED, - TYPE_IMM, - }; - struct HeaderStruct { - Type MemType; - }; - union { - HeaderStruct Header; - struct { - HeaderStruct Header; - Register rm; - ExtendedType Option; - uint32_t Shift; - } ExtendedType; - struct { - HeaderStruct Header; - IndexType Index; - int32_t Imm; - } ImmType; - } MetaType; - }; - - template - constexpr uint32_t GenSystemReg() { - return op0 << 19 | - op1 << 16 | - CRn << 12 | - CRm << 8 | - op2 << 5; - }; - - // This `SystemRegister` enum is used for the mrs/msr instructions. - enum class SystemRegister : uint32_t { - CTR_EL0 = GenSystemReg<0b11, 0b011, 0b0000, 0b0000, 0b001>(), - DCZID_EL0 = GenSystemReg<0b11, 0b011, 0b0000, 0b0000, 0b111>(), - TPIDR_EL0 = GenSystemReg<0b11, 0b011, 0b1101, 0b0000, 0b010>(), - RNDR = GenSystemReg<0b11, 0b011, 0b0010, 0b0100, 0b000>(), - RNDRRS = GenSystemReg<0b11, 0b011, 0b0010, 0b0100, 0b001>(), - NZCV = GenSystemReg<0b11, 0b011, 0b0100, 0b0010, 0b000>(), - FPCR = GenSystemReg<0b11, 0b011, 0b0100, 0b0100, 0b000>(), - CNTFRQ_EL0 = GenSystemReg<0b11, 0b011, 0b1110, 0b0000, 0b000>(), - CNTVCT_EL0 = GenSystemReg<0b11, 0b011, 0b1110, 0b0000, 0b010>(), - }; - - template - constexpr uint32_t GenDCReg() { - return op1 << 16 | - CRm << 8 | - op2 << 5; - }; - - // This `DataCacheOperation` enum is used for the dc instruction. - enum class DataCacheOperation : uint32_t { - IVAC = GenDCReg<0b000, 0b0110, 0b001>(), - ISW = GenDCReg<0b000, 0b0110, 0b010>(), - CSW = GenDCReg<0b000, 0b1010, 0b010>(), - CISW = GenDCReg<0b000, 0b1110, 0b010>(), - ZVA = GenDCReg<0b011, 0b0100, 0b001>(), - CVAC = GenDCReg<0b011, 0b1010, 0b001>(), - CVAU = GenDCReg<0b011, 0b1011, 0b001>(), - CIVAC = GenDCReg<0b011, 0b1110, 0b001>(), - - // MTE2 - IGVAC = GenDCReg<0b000, 0b0110, 0b011>(), - IGSW = GenDCReg<0b000, 0b0110, 0b100>(), - IGDVAC = GenDCReg<0b000, 0b0110, 0b101>(), - IGDSW = GenDCReg<0b000, 0b0110, 0b110>(), - CGSW = GenDCReg<0b000, 0b1010, 0b100>(), - CGDSW = GenDCReg<0b000, 0b1010, 0b110>(), - CIGSW = GenDCReg<0b000, 0b1110, 0b100>(), - CIGDSW = GenDCReg<0b000, 0b1110, 0b110>(), - - // MTE - GVA = GenDCReg<0b011, 0b0100, 0b011>(), - GZVA = GenDCReg<0b011, 0b0100, 0b100>(), - CGVAC = GenDCReg<0b011, 0b1010, 0b011>(), - CGDVAC = GenDCReg<0b011, 0b1010, 0b101>(), - CGVAP = GenDCReg<0b011, 0b1100, 0b011>(), - CGDVAP = GenDCReg<0b011, 0b1100, 0b101>(), - CGVADP = GenDCReg<0b011, 0b1101, 0b011>(), - CGDVADP = GenDCReg<0b011, 0b1101, 0b101>(), - CIGVAC = GenDCReg<0b011, 0b1110, 0b011>(), - CIGDVAC = GenDCReg<0b011, 0b1110, 0b101>(), - - // DPB - CVAP = GenDCReg<0b011, 0b1100, 0b001>(), - - // DPB2 - CVADP = GenDCReg<0b011, 0b1101, 0b001>(), - }; - - template - constexpr uint32_t GenHintBarrierReg() { - return CRm << 8 | - op2 << 5; + // Bind a backward label to an address. + // Address that is bound is the current emitter location. + void Bind(BackwardLabel* Label) { + LOGMAN_THROW_AA_FMT(Label->Location == nullptr, "Trying to bind a label twice"); + Label->Location = GetCursorAddress(); } - // This `HintRegister` enum is used for the hint instruction. - enum class HintRegister : uint32_t { - NOP = GenHintBarrierReg<0b0000, 0b000>(), - YIELD = GenHintBarrierReg<0b0000, 0b001>(), - WFE = GenHintBarrierReg<0b0000, 0b010>(), - WFI = GenHintBarrierReg<0b0000, 0b011>(), - SEV = GenHintBarrierReg<0b0000, 0b100>(), - SEVL = GenHintBarrierReg<0b0000, 0b101>(), - DGH = GenHintBarrierReg<0b0000, 0b110>(), - CSDB = GenHintBarrierReg<0b0010, 0b100>(), - }; + void Bind(const SingleUseForwardLabel* Label) { + uint8_t* CurrentAddress = GetCursorAddress(); + // Patch up the instructions + switch (Label->Type) { + case SingleUseForwardLabel::InstType::ADR: { + uint32_t* Instruction = reinterpret_cast(Label->Location); + int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); + LOGMAN_THROW_A_FMT(IsADRRange(Imm), "Unscaled offset too large"); + uint32_t InstMask = 0b11 << 29 | 0b1111'1111'1111'1111'111 << 5; + uint32_t Offset = static_cast(Imm) & 0x3F'FFFF; + uint32_t Inst = *Instruction & ~InstMask; + Inst |= (Offset & 0b11) << 29; + Inst |= (Offset >> 2) << 5; + *Instruction = Inst; + break; + } + case SingleUseForwardLabel::InstType::ADRP: { + uint32_t* Instruction = reinterpret_cast(Label->Location); + int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); + LOGMAN_THROW_A_FMT(IsADRPRange(Imm) && IsADRPAligned(Imm), "Unscaled offset too large"); + Imm >>= 12; + uint32_t InstMask = 0b11 << 29 | 0b1111'1111'1111'1111'111 << 5; + uint32_t Offset = static_cast(Imm) & 0x3F'FFFF; + uint32_t Inst = *Instruction & ~InstMask; + Inst |= (Offset & 0b11) << 29; + Inst |= (Offset >> 2) << 5; + *Instruction = Inst; + break; + } - // This `BarrierRegister` enum is used for the various barrier instructions. - enum class BarrierRegister : uint32_t { - CLREX = GenHintBarrierReg<0b0000, 0b010>(), - TCOMMIT = GenHintBarrierReg<0b0000, 0b011>(), - DSB = GenHintBarrierReg<0b0000, 0b100>(), - DMB = GenHintBarrierReg<0b0000, 0b101>(), - ISB = GenHintBarrierReg<0b0000, 0b110>(), - SB = GenHintBarrierReg<0b0000, 0b111>(), - }; + case SingleUseForwardLabel::InstType::B: { + uint32_t* Instruction = reinterpret_cast(Label->Location); + int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); + LOGMAN_THROW_A_FMT(Imm >= -134217728 && Imm <= 134217724 && ((Imm & 0b11) == 0), "Unscaled offset too large"); + Imm >>= 2; + uint32_t InstMask = 0x3FF'FFFF; + uint32_t Offset = static_cast(Imm) & InstMask; + uint32_t Inst = *Instruction & ~InstMask; + Inst |= Offset; + *Instruction = Inst; - // This `BarrierScope` enum is used for the dsb/dmb instructions. - enum class BarrierScope : uint32_t { - // Outer shareable - OSHLD = 0b0001, - OSHST = 0b0010, - OSH = 0b0011, - // Non shareable - NSHLD = 0b0101, - NSHST = 0b0110, - NSH = 0b0111, - // Inner shareable - ISHLD = 0b1001, - ISHST = 0b1010, - ISH = 0b1011, - // Full System visibility - LD = 0b1101, - ST = 0b1110, - SY = 0b1111, - }; + break; + } - // This `Prefetch` enum is used for prefetch instructions. - enum class Prefetch : uint32_t { - // Prefetch for load - PLDL1KEEP = 0b00000, - PLDL1STRM = 0b00001, - PLDL2KEEP = 0b00010, - PLDL2STRM = 0b00011, - PLDL3KEEP = 0b00100, - PLDL3STRM = 0b00101, + case SingleUseForwardLabel::InstType::TEST_BRANCH: { + uint32_t* Instruction = reinterpret_cast(Label->Location); + int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); + LOGMAN_THROW_A_FMT(Imm >= -32768 && Imm <= 32764 && ((Imm & 0b11) == 0), "Unscaled offset too large"); + Imm >>= 2; + uint32_t InstMask = 0x3FFF; + uint32_t Offset = static_cast(Imm) & InstMask; + uint32_t Inst = *Instruction & ~(InstMask << 5); + Inst |= Offset << 5; + *Instruction = Inst; - // Preload instructions - PLIL1KEEP = 0b01000, - PLIL1STRM = 0b01001, - PLIL2KEEP = 0b01010, - PLIL2STRM = 0b01011, - PLIL3KEEP = 0b01100, - PLIL3STRM = 0b01101, + break; + } + case SingleUseForwardLabel::InstType::BC: + case SingleUseForwardLabel::InstType::RELATIVE_LOAD: { + uint32_t* Instruction = reinterpret_cast(Label->Location); + int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); + LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large"); + Imm >>= 2; + uint32_t InstMask = 0x7'FFFF; + uint32_t Offset = static_cast(Imm) & InstMask; + uint32_t Inst = *Instruction & ~(InstMask << 5); + Inst |= Offset << 5; + *Instruction = Inst; + break; + } + case SingleUseForwardLabel::InstType::LONG_ADDRESS_GEN: { + uint32_t* Instructions = reinterpret_cast(Label->Location); + int64_t ImmInstOne = reinterpret_cast(CurrentAddress) - reinterpret_cast(&Instructions[0]); + int64_t ImmInstTwo = reinterpret_cast(CurrentAddress) - reinterpret_cast(&Instructions[1]); + auto OriginalOffset = GetCursorOffset(); - // Preload for store - PSTL1KEEP = 0b10000, - PSTL1STRM = 0b10001, - PSTL2KEEP = 0b10010, - PSTL2STRM = 0b10011, - PSTL3KEEP = 0b10100, - PSTL3STRM = 0b10101, - }; + auto InstOffset = GetCursorOffsetFromAddress(Instructions); + SetCursorOffset(InstOffset); - // This `PredicatePattern` enun is used for some SVE instructions. - enum class PredicatePattern : uint32_t { - SVE_POW2 = 0b00000, - SVE_VL1 = 0b00001, - SVE_VL2 = 0b00010, - SVE_VL3 = 0b00011, - SVE_VL4 = 0b00100, - SVE_VL5 = 0b00101, - SVE_VL6 = 0b00110, - SVE_VL7 = 0b00111, - SVE_VL8 = 0b01000, - SVE_VL16 = 0b01001, - SVE_VL32 = 0b01010, - SVE_VL64 = 0b01011, - SVE_VL128 = 0b01100, - SVE_VL256 = 0b01101, - SVE_MUL4 = 0b11101, - SVE_MUL3 = 0b11110, - SVE_ALL = 0b11111, - }; + // We encoded the destination register in to the first instruction space. + // Read it back. + ARMEmitter::Register DestReg(Instructions[0]); - // Used with SVE FP immediate arithmetic instructions - enum class SVEFAddSubImm : uint32_t { - _0_5, - _1_0, - }; - enum class SVEFMulImm : uint32_t { - _0_5, - _2_0, - }; - enum class SVEFMaxMinImm : uint32_t { - _0_0, - _1_0, - }; + if (IsADRRange(ImmInstTwo)) { + // If within ADR range from the second instruction, then we can emit NOP+ADR + nop(); + adr(DestReg, static_cast(ImmInstTwo) & 0x7FFF); + } else if (IsADRPRange(ImmInstOne)) { - /* This `BackwardLabel` struct used for retaining a location for PC-Relative instructions. - * This is specifically a label for a target that is logically `below` an instruction that uses it. - * Which means that a branch would jump backwards. - */ - struct BackwardLabel { - uint8_t *Location{}; - }; + // If within ADRP range from the first instruction, then we are /definitely/ in range for the second instruction. + // First check if we are in non-offset range for second instruction. + if (IsADRPAligned(reinterpret_cast(CurrentAddress))) { + // We can emit nop + adrp + nop(); + adrp(DestReg, static_cast(ImmInstTwo >> 12) & 0x7FFF); + } else { + // Not aligned, need adrp + add + adrp(DestReg, static_cast(ImmInstOne >> 12) & 0x7FFF); + add(ARMEmitter::Size::i64Bit, DestReg, DestReg, ImmInstOne & 0xFFF); + } + } else { + LOGMAN_MSG_A_FMT("Unscaled offset is too large"); + FEX_UNREACHABLE; + } - /* This `SingleUseForwardLabel` struct used for retaining a location for PC-Relative instructions. - * This is specifically a label for a target that is logically `above` an instruction that uses it. - * Which means that a branch would jump forwards. - * - * The `ForwardLabel` struct can be bound to multiple instructions, so it needs a vector for each bind instruction type. - */ - struct SingleUseForwardLabel { - enum class InstType { - UNKNOWN, - ADR, - ADRP, - B, - BC, - TEST_BRANCH, - RELATIVE_LOAD, - LONG_ADDRESS_GEN, - }; - uint8_t *Location{}; - InstType Type = InstType::UNKNOWN; - }; - - struct ForwardLabel { - fextl::vector Insts{}; - }; - - /* This `BiDirectionalLabel` struct used for retaining a location for PC-Relative instructions. - * This is specifically a label for a target that is in either direction of an instruction that uses it. - * Which means a branch could jump backwards or forwards depending on situation. - */ - struct BiDirectionalLabel { - BackwardLabel Backward; - ForwardLabel Forward; - }; - - static inline void AddLocationToLabel(SingleUseForwardLabel *Label, SingleUseForwardLabel&& Location) { - LOGMAN_THROW_A_FMT(Label->Type == SingleUseForwardLabel::InstType::UNKNOWN, "Trying to bind a SingleUseForwardLabel to multiple locations. Use ForwardLabel instead."); - *Label = std::move(Location); + SetCursorOffset(OriginalOffset); + break; + } + default: LOGMAN_MSG_A_FMT("Unexpected inst type in label fixup"); + } } - static inline void AddLocationToLabel(ForwardLabel *Label, SingleUseForwardLabel&& Location) { - Label->Insts.emplace_back(std::move(Location)); + // Bind a forward label to a location. + // This walks all the instructions in the label's vector. + // Then backpatching all instructions that have used the label. + template + void Bind(ForwardLabel* Label) { + if constexpr (WarnAboutEmpty) { + LOGMAN_THROW_A_FMT(Label->Insts.empty() == false, "Binding forward label that didn't have any instructions using it"); + } + for (auto& Inst : Label->Insts) { + Bind(&Inst); + } } - // Some FCMA ASIMD instructions support a rotation argument. - enum class Rotation : uint32_t { - ROTATE_0 = 0b00, - ROTATE_90 = 0b01, - ROTATE_180 = 0b10, - ROTATE_270 = 0b11, - }; - - // Concept for contraining some instructions to accept only an XRegister or WRegister. - // Particularly for operations that differ encodings depending on which one is used. - template - concept IsXOrWRegister = std::is_same_v || std::is_same_v; - - // Whether or not a given set of vector registers are sequential - // in increasing order as far as the register file is concerned (modulo its size) - // - // For example, a set of registers like: - // - // v1, v2, v3 and - // v31, v0, v1 - // - // would both be considered sequential sequences, and some instructions in particular - // limit register lists to these kind of sequences. - // - template - constexpr bool AreVectorsSequential(T first, const Args&... args) { - // Ensure we always have a pair of registers to compare against. - static_assert(sizeof...(args) >= 1, "Number of arguments must be greater than 1"); - - const auto fn = [](auto& lhs, const auto& rhs) { - const auto result = ((lhs.Idx() + 1) % 32) == rhs.Idx(); - lhs = rhs; - return result; - }; - - return (fn(first, args) && ...); + // Bind a bidirectional location to a location. + // Binds both forwards and backwards depending on how the label was used. + void Bind(BiDirectionalLabel* Label) { + if (!Label->Backward.Location) { + Bind(&Label->Backward); + } + Bind(&Label->Forward); } - // This is an emitter that is designed around the smallest code bloat as possible. - // Eschewing most developer convenience in order to keep code as small as possible. - - // Choices: - // - Size of ops passed as an argument rather than template to let the compiler use csel instead of branching. - // - Registers are unsized so they can be passed in a GPR and not need conversion operations - class Emitter : public FEXCore::ARMEmitter::Buffer { - public: - Emitter() = default; - - Emitter(uint8_t* Base, uint64_t BaseSize) - : Buffer (Base, BaseSize) { - } - - // Bind a backward label to an address. - // Address that is bound is the current emitter location. - void Bind(BackwardLabel *Label) { - LOGMAN_THROW_AA_FMT(Label->Location == nullptr, "Trying to bind a label twice"); - Label->Location = GetCursorAddress(); - } - - void Bind(const SingleUseForwardLabel *Label) { - uint8_t *CurrentAddress = GetCursorAddress(); - // Patch up the instructions - switch (Label->Type) { - case SingleUseForwardLabel::InstType::ADR: { - uint32_t *Instruction = reinterpret_cast(Label->Location); - int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); - LOGMAN_THROW_A_FMT(IsADRRange(Imm), "Unscaled offset too large"); - uint32_t InstMask = 0b11 << 29 | 0b1111'1111'1111'1111'111 << 5; - uint32_t Offset = static_cast(Imm) & 0x3F'FFFF; - uint32_t Inst = *Instruction & ~InstMask; - Inst |= (Offset & 0b11) << 29; - Inst |= (Offset >> 2) << 5; - *Instruction = Inst; - break; - } - case SingleUseForwardLabel::InstType::ADRP: { - uint32_t *Instruction = reinterpret_cast(Label->Location); - int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); - LOGMAN_THROW_A_FMT(IsADRPRange(Imm) && IsADRPAligned(Imm), "Unscaled offset too large"); - Imm >>= 12; - uint32_t InstMask = 0b11 << 29 | 0b1111'1111'1111'1111'111 << 5; - uint32_t Offset = static_cast(Imm) & 0x3F'FFFF; - uint32_t Inst = *Instruction & ~InstMask; - Inst |= (Offset & 0b11) << 29; - Inst |= (Offset >> 2) << 5; - *Instruction = Inst; - break; - } - - case SingleUseForwardLabel::InstType::B: { - uint32_t *Instruction = reinterpret_cast(Label->Location); - int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); - LOGMAN_THROW_A_FMT(Imm >= -134217728 && Imm <= 134217724 && ((Imm & 0b11) == 0), "Unscaled offset too large"); - Imm >>= 2; - uint32_t InstMask = 0x3FF'FFFF; - uint32_t Offset = static_cast(Imm) & InstMask; - uint32_t Inst = *Instruction & ~InstMask; - Inst |= Offset; - *Instruction = Inst; - - break; - } - - case SingleUseForwardLabel::InstType::TEST_BRANCH: { - uint32_t *Instruction = reinterpret_cast(Label->Location); - int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); - LOGMAN_THROW_A_FMT(Imm >= -32768 && Imm <= 32764 && ((Imm & 0b11) == 0), "Unscaled offset too large"); - Imm >>= 2; - uint32_t InstMask = 0x3FFF; - uint32_t Offset = static_cast(Imm) & InstMask; - uint32_t Inst = *Instruction & ~(InstMask << 5); - Inst |= Offset << 5; - *Instruction = Inst; - - break; - } - case SingleUseForwardLabel::InstType::BC: - case SingleUseForwardLabel::InstType::RELATIVE_LOAD: { - uint32_t *Instruction = reinterpret_cast(Label->Location); - int64_t Imm = reinterpret_cast(CurrentAddress) - reinterpret_cast(Instruction); - LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large"); - Imm >>= 2; - uint32_t InstMask = 0x7'FFFF; - uint32_t Offset = static_cast(Imm) & InstMask; - uint32_t Inst = *Instruction & ~(InstMask << 5); - Inst |= Offset << 5; - *Instruction = Inst; - break; - } - case SingleUseForwardLabel::InstType::LONG_ADDRESS_GEN: { - uint32_t *Instructions = reinterpret_cast(Label->Location); - int64_t ImmInstOne = reinterpret_cast(CurrentAddress) - reinterpret_cast(&Instructions[0]); - int64_t ImmInstTwo = reinterpret_cast(CurrentAddress) - reinterpret_cast(&Instructions[1]); - auto OriginalOffset = GetCursorOffset(); - - auto InstOffset = GetCursorOffsetFromAddress(Instructions); - SetCursorOffset(InstOffset); - - // We encoded the destination register in to the first instruction space. - // Read it back. - ARMEmitter::Register DestReg(Instructions[0]); - - if (IsADRRange(ImmInstTwo)) { - // If within ADR range from the second instruction, then we can emit NOP+ADR - nop(); - adr(DestReg, static_cast(ImmInstTwo) & 0x7FFF); - } - else if (IsADRPRange(ImmInstOne)) { - - // If within ADRP range from the first instruction, then we are /definitely/ in range for the second instruction. - // First check if we are in non-offset range for second instruction. - if (IsADRPAligned(reinterpret_cast(CurrentAddress))) { - // We can emit nop + adrp - nop(); - adrp(DestReg, static_cast(ImmInstTwo >> 12) & 0x7FFF); - } - else { - // Not aligned, need adrp + add - adrp(DestReg, static_cast(ImmInstOne >> 12) & 0x7FFF); - add(ARMEmitter::Size::i64Bit, DestReg, DestReg, ImmInstOne & 0xFFF); - } - } - else { - LOGMAN_MSG_A_FMT("Unscaled offset is too large"); - FEX_UNREACHABLE; - } - - SetCursorOffset(OriginalOffset); - break; - } - default: LOGMAN_MSG_A_FMT("Unexpected inst type in label fixup"); - } - } - - // Bind a forward label to a location. - // This walks all the instructions in the label's vector. - // Then backpatching all instructions that have used the label. - template - void Bind(ForwardLabel *Label) { - if constexpr (WarnAboutEmpty) { - LOGMAN_THROW_A_FMT(Label->Insts.empty() == false, "Binding forward label that didn't have any instructions using it"); - } - for (auto &Inst : Label->Insts) { - Bind(&Inst); - } - } - - // Bind a bidirectional location to a location. - // Binds both forwards and backwards depending on how the label was used. - void Bind(BiDirectionalLabel *Label) { - if (!Label->Backward.Location) { - Bind(&Label->Backward); - } - Bind(&Label->Forward); - } - - public: +public: // TODO: Implement SME when it matters. #include "Interface/Core/ArchHelpers/CodeEmitter/ALUOps.inl" #include "Interface/Core/ArchHelpers/CodeEmitter/BranchOps.inl" @@ -787,64 +769,64 @@ namespace FEXCore::ARMEmitter { #include "Interface/Core/ArchHelpers/CodeEmitter/ASIMDOps.inl" #include "Interface/Core/ArchHelpers/CodeEmitter/SVEOps.inl" - private: - template - uint32_t Encode_ra(T Reg) const { - return Reg.Idx() << 10; - } - uint32_t Encode_ra(uint32_t Reg) const { - return Reg << 10; - } - template - uint32_t Encode_rt2(T Reg) const { - return Reg.Idx() << 10; - } - template<> - uint32_t Encode_rt2(uint32_t Reg) const { - return Reg << 10; - } - template - uint32_t Encode_rm(T Reg) const { - return Reg.Idx() << 16; - } - uint32_t Encode_rm(uint32_t Reg) const { - return Reg << 16; - } - template - uint32_t Encode_rs(T Reg) const { - return Reg.Idx() << 16; - } - uint32_t Encode_rs(uint32_t Reg) const { - return Reg << 16; - } - template - uint32_t Encode_rn(T Reg) const { - return Reg.Idx() << 5; - } - uint32_t Encode_rn(uint32_t Reg) const { - return Reg << 5; - } - template - uint32_t Encode_rd(T Reg) const { - return Reg.Idx(); - } - uint32_t Encode_rd(uint32_t Reg) const { - return Reg; - } - template - uint32_t Encode_rt(T Reg) const { - return Reg.Idx(); - } - template<> - uint32_t Encode_rt(Prefetch Reg) const { - return FEXCore::ToUnderlying(Reg); - } - uint32_t Encode_rt(uint32_t Reg) const { - return Reg; - } - template - uint32_t Encode_pd(T Reg) const { - return FEXCore::ToUnderlying(Reg); - } - }; -} +private: + template + uint32_t Encode_ra(T Reg) const { + return Reg.Idx() << 10; + } + uint32_t Encode_ra(uint32_t Reg) const { + return Reg << 10; + } + template + uint32_t Encode_rt2(T Reg) const { + return Reg.Idx() << 10; + } + template<> + uint32_t Encode_rt2(uint32_t Reg) const { + return Reg << 10; + } + template + uint32_t Encode_rm(T Reg) const { + return Reg.Idx() << 16; + } + uint32_t Encode_rm(uint32_t Reg) const { + return Reg << 16; + } + template + uint32_t Encode_rs(T Reg) const { + return Reg.Idx() << 16; + } + uint32_t Encode_rs(uint32_t Reg) const { + return Reg << 16; + } + template + uint32_t Encode_rn(T Reg) const { + return Reg.Idx() << 5; + } + uint32_t Encode_rn(uint32_t Reg) const { + return Reg << 5; + } + template + uint32_t Encode_rd(T Reg) const { + return Reg.Idx(); + } + uint32_t Encode_rd(uint32_t Reg) const { + return Reg; + } + template + uint32_t Encode_rt(T Reg) const { + return Reg.Idx(); + } + template<> + uint32_t Encode_rt(Prefetch Reg) const { + return FEXCore::ToUnderlying(Reg); + } + uint32_t Encode_rt(uint32_t Reg) const { + return Reg; + } + template + uint32_t Encode_pd(T Reg) const { + return FEXCore::ToUnderlying(Reg); + } +}; +} // namespace FEXCore::ARMEmitter diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Registers.h b/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Registers.h index 9d07a0fb9..5d3f9abc3 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Registers.h +++ b/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Registers.h @@ -7,1021 +7,1021 @@ #include namespace FEXCore::ARMEmitter { - class WRegister; - class XRegister; +class WRegister; +class XRegister; - /* Unsized GPR register class - * This class doesn't imply a size when used - */ - class Register { - public: - Register() = delete; - constexpr explicit Register(uint32_t Idx) - : Index {Idx} {} +/* Unsized GPR register class + * This class doesn't imply a size when used + */ +class Register { +public: + Register() = delete; + constexpr explicit Register(uint32_t Idx) + : Index {Idx} {} - friend constexpr auto operator<=>(const Register&, const Register&) = default; + friend constexpr auto operator<=>(const Register&, const Register&) = default; - constexpr uint32_t Idx() const { - return Index; - } - constexpr WRegister W() const; - constexpr XRegister X() const; + constexpr uint32_t Idx() const { + return Index; + } + constexpr WRegister W() const; + constexpr XRegister X() const; - private: - uint32_t Index; - }; - static_assert(sizeof(Register) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); +private: + uint32_t Index; +}; +static_assert(sizeof(Register) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); - /* 32-bit GPR register class. - * This class will imply a 32-bit register size being used. - */ - class WRegister { - public: - WRegister() = delete; - constexpr explicit WRegister(uint32_t Idx) - : Index {Idx} {} +/* 32-bit GPR register class. + * This class will imply a 32-bit register size being used. + */ +class WRegister { +public: + WRegister() = delete; + constexpr explicit WRegister(uint32_t Idx) + : Index {Idx} {} - friend constexpr auto operator<=>(const WRegister&, const WRegister&) = default; + friend constexpr auto operator<=>(const WRegister&, const WRegister&) = default; - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator Register() const { - return Register(Index); - } - constexpr XRegister X() const; - constexpr Register R() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(Register) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - /* 64-bit GPR register class. - * This class will imply a 64-bit register size being used. - */ - class XRegister { - public: - XRegister() = delete; - constexpr explicit XRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const XRegister&, const XRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator Register() const { - return Register(Index); - } - constexpr WRegister W() const; - constexpr Register R() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(Register) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - inline constexpr WRegister Register::W() const { - return WRegister{Index}; + constexpr uint32_t Idx() const { + return Index; } - inline constexpr XRegister Register::X() const { - return XRegister{Index}; + constexpr operator Register() const { + return Register(Index); + } + constexpr XRegister X() const; + constexpr Register R() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(Register) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +/* 64-bit GPR register class. + * This class will imply a 64-bit register size being used. + */ +class XRegister { +public: + XRegister() = delete; + constexpr explicit XRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const XRegister&, const XRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - inline constexpr XRegister WRegister::X() const { - return XRegister{Index}; + constexpr operator Register() const { + return Register(Index); + } + constexpr WRegister W() const; + constexpr Register R() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(Register) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +inline constexpr WRegister Register::W() const { + return WRegister {Index}; +} + +inline constexpr XRegister Register::X() const { + return XRegister {Index}; +} + +inline constexpr XRegister WRegister::X() const { + return XRegister {Index}; +} + +inline constexpr Register WRegister::R() const { + return *this; +} + +inline constexpr WRegister XRegister::W() const { + return WRegister {Index}; +} + +inline constexpr Register XRegister::R() const { + return *this; +} + +// Namespace containing all unsized GPR register objects. +namespace Reg { + constexpr static Register r0(0); + constexpr static Register r1(1); + constexpr static Register r2(2); + constexpr static Register r3(3); + constexpr static Register r4(4); + constexpr static Register r5(5); + constexpr static Register r6(6); + constexpr static Register r7(7); + constexpr static Register r8(8); + constexpr static Register r9(9); + constexpr static Register r10(10); + constexpr static Register r11(11); + constexpr static Register r12(12); + constexpr static Register r13(13); + constexpr static Register r14(14); + constexpr static Register r15(15); + constexpr static Register r16(16); + constexpr static Register r17(17); + constexpr static Register r18(18); + constexpr static Register r19(19); + constexpr static Register r20(20); + constexpr static Register r21(21); + constexpr static Register r22(22); + constexpr static Register r23(23); + constexpr static Register r24(24); + constexpr static Register r25(25); + constexpr static Register r26(26); + constexpr static Register r27(27); + constexpr static Register r28(28); + constexpr static Register r29(29); + constexpr static Register r30(30); + constexpr static Register r31(31); + + // Named registers + constexpr static Register ip0(16); + constexpr static Register ip1(17); + + constexpr static Register fp(29); + constexpr static Register lr(30); + constexpr static Register rsp(31); + constexpr static Register zr(31); +} // namespace Reg + +// Namespace containing all 64-bit GPR register objects. +namespace XReg { + constexpr static XRegister x0(0); + constexpr static XRegister x1(1); + constexpr static XRegister x2(2); + constexpr static XRegister x3(3); + constexpr static XRegister x4(4); + constexpr static XRegister x5(5); + constexpr static XRegister x6(6); + constexpr static XRegister x7(7); + constexpr static XRegister x8(8); + constexpr static XRegister x9(9); + constexpr static XRegister x10(10); + constexpr static XRegister x11(11); + constexpr static XRegister x12(12); + constexpr static XRegister x13(13); + constexpr static XRegister x14(14); + constexpr static XRegister x15(15); + constexpr static XRegister x16(16); + constexpr static XRegister x17(17); + constexpr static XRegister x18(18); + constexpr static XRegister x19(19); + constexpr static XRegister x20(20); + constexpr static XRegister x21(21); + constexpr static XRegister x22(22); + constexpr static XRegister x23(23); + constexpr static XRegister x24(24); + constexpr static XRegister x25(25); + constexpr static XRegister x26(26); + constexpr static XRegister x27(27); + constexpr static XRegister x28(28); + constexpr static XRegister x29(29); + constexpr static XRegister x30(30); + constexpr static XRegister x31(31); + + // Named registers + constexpr static XRegister ip0(16); + constexpr static XRegister ip1(17); + + constexpr static XRegister fp(29); + constexpr static XRegister lr(30); + constexpr static XRegister rsp(31); + constexpr static XRegister zr(31); +} // namespace XReg + +// Namespace containing all 32-bit GPR register objects. +namespace WReg { + constexpr static WRegister w0(0); + constexpr static WRegister w1(1); + constexpr static WRegister w2(2); + constexpr static WRegister w3(3); + constexpr static WRegister w4(4); + constexpr static WRegister w5(5); + constexpr static WRegister w6(6); + constexpr static WRegister w7(7); + constexpr static WRegister w8(8); + constexpr static WRegister w9(9); + constexpr static WRegister w10(10); + constexpr static WRegister w11(11); + constexpr static WRegister w12(12); + constexpr static WRegister w13(13); + constexpr static WRegister w14(14); + constexpr static WRegister w15(15); + constexpr static WRegister w16(16); + constexpr static WRegister w17(17); + constexpr static WRegister w18(18); + constexpr static WRegister w19(19); + constexpr static WRegister w20(20); + constexpr static WRegister w21(21); + constexpr static WRegister w22(22); + constexpr static WRegister w23(23); + constexpr static WRegister w24(24); + constexpr static WRegister w25(25); + constexpr static WRegister w26(26); + constexpr static WRegister w27(27); + constexpr static WRegister w28(28); + constexpr static WRegister w29(29); + constexpr static WRegister w30(30); + constexpr static WRegister w31(31); + + // Named registers + constexpr static WRegister ip0(16); + constexpr static WRegister ip1(17); + + constexpr static WRegister fp(29); + constexpr static WRegister lr(30); + constexpr static WRegister rsp(31); + constexpr static WRegister zr(31); +} // namespace WReg + +class VRegister; +class BRegister; +class HRegister; +class SRegister; +class DRegister; +class QRegister; +class ZRegister; + +/* Unsized ASIMD register class + * This class doesn't imply a size when used, nor implies Vector or Scalar. + * It does imply that this instruction isn't using the register for SVE. + */ +class VRegister { +public: + VRegister() = delete; + constexpr explicit VRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const VRegister&, const VRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - inline constexpr Register WRegister::R() const { - return *this; + constexpr BRegister B() const; + constexpr HRegister H() const; + constexpr SRegister S() const; + constexpr DRegister D() const; + constexpr QRegister Q() const; + constexpr ZRegister Z() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(VRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +/* 8-bit ASIMD register class + * This class implies 8-bit scalar register. + */ +class BRegister { +public: + BRegister() = delete; + constexpr explicit BRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const BRegister&, const BRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - inline constexpr WRegister XRegister::W() const { - return WRegister{Index}; - } - - inline constexpr Register XRegister::R() const { - return *this; - } - - // Namespace containing all unsized GPR register objects. - namespace Reg { - constexpr static Register r0(0); - constexpr static Register r1(1); - constexpr static Register r2(2); - constexpr static Register r3(3); - constexpr static Register r4(4); - constexpr static Register r5(5); - constexpr static Register r6(6); - constexpr static Register r7(7); - constexpr static Register r8(8); - constexpr static Register r9(9); - constexpr static Register r10(10); - constexpr static Register r11(11); - constexpr static Register r12(12); - constexpr static Register r13(13); - constexpr static Register r14(14); - constexpr static Register r15(15); - constexpr static Register r16(16); - constexpr static Register r17(17); - constexpr static Register r18(18); - constexpr static Register r19(19); - constexpr static Register r20(20); - constexpr static Register r21(21); - constexpr static Register r22(22); - constexpr static Register r23(23); - constexpr static Register r24(24); - constexpr static Register r25(25); - constexpr static Register r26(26); - constexpr static Register r27(27); - constexpr static Register r28(28); - constexpr static Register r29(29); - constexpr static Register r30(30); - constexpr static Register r31(31); - - // Named registers - constexpr static Register ip0(16); - constexpr static Register ip1(17); - - constexpr static Register fp(29); - constexpr static Register lr(30); - constexpr static Register rsp(31); - constexpr static Register zr(31); - } - - // Namespace containing all 64-bit GPR register objects. - namespace XReg { - constexpr static XRegister x0(0); - constexpr static XRegister x1(1); - constexpr static XRegister x2(2); - constexpr static XRegister x3(3); - constexpr static XRegister x4(4); - constexpr static XRegister x5(5); - constexpr static XRegister x6(6); - constexpr static XRegister x7(7); - constexpr static XRegister x8(8); - constexpr static XRegister x9(9); - constexpr static XRegister x10(10); - constexpr static XRegister x11(11); - constexpr static XRegister x12(12); - constexpr static XRegister x13(13); - constexpr static XRegister x14(14); - constexpr static XRegister x15(15); - constexpr static XRegister x16(16); - constexpr static XRegister x17(17); - constexpr static XRegister x18(18); - constexpr static XRegister x19(19); - constexpr static XRegister x20(20); - constexpr static XRegister x21(21); - constexpr static XRegister x22(22); - constexpr static XRegister x23(23); - constexpr static XRegister x24(24); - constexpr static XRegister x25(25); - constexpr static XRegister x26(26); - constexpr static XRegister x27(27); - constexpr static XRegister x28(28); - constexpr static XRegister x29(29); - constexpr static XRegister x30(30); - constexpr static XRegister x31(31); - - // Named registers - constexpr static XRegister ip0(16); - constexpr static XRegister ip1(17); - - constexpr static XRegister fp(29); - constexpr static XRegister lr(30); - constexpr static XRegister rsp(31); - constexpr static XRegister zr(31); - } - - // Namespace containing all 32-bit GPR register objects. - namespace WReg { - constexpr static WRegister w0(0); - constexpr static WRegister w1(1); - constexpr static WRegister w2(2); - constexpr static WRegister w3(3); - constexpr static WRegister w4(4); - constexpr static WRegister w5(5); - constexpr static WRegister w6(6); - constexpr static WRegister w7(7); - constexpr static WRegister w8(8); - constexpr static WRegister w9(9); - constexpr static WRegister w10(10); - constexpr static WRegister w11(11); - constexpr static WRegister w12(12); - constexpr static WRegister w13(13); - constexpr static WRegister w14(14); - constexpr static WRegister w15(15); - constexpr static WRegister w16(16); - constexpr static WRegister w17(17); - constexpr static WRegister w18(18); - constexpr static WRegister w19(19); - constexpr static WRegister w20(20); - constexpr static WRegister w21(21); - constexpr static WRegister w22(22); - constexpr static WRegister w23(23); - constexpr static WRegister w24(24); - constexpr static WRegister w25(25); - constexpr static WRegister w26(26); - constexpr static WRegister w27(27); - constexpr static WRegister w28(28); - constexpr static WRegister w29(29); - constexpr static WRegister w30(30); - constexpr static WRegister w31(31); - - // Named registers - constexpr static WRegister ip0(16); - constexpr static WRegister ip1(17); - - constexpr static WRegister fp(29); - constexpr static WRegister lr(30); - constexpr static WRegister rsp(31); - constexpr static WRegister zr(31); - } - - class VRegister; - class BRegister; - class HRegister; - class SRegister; - class DRegister; - class QRegister; - class ZRegister; - - /* Unsized ASIMD register class - * This class doesn't imply a size when used, nor implies Vector or Scalar. - * It does imply that this instruction isn't using the register for SVE. - */ - class VRegister { - public: - VRegister() = delete; - constexpr explicit VRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const VRegister&, const VRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr BRegister B() const; - constexpr HRegister H() const; - constexpr SRegister S() const; - constexpr DRegister D() const; - constexpr QRegister Q() const; - constexpr ZRegister Z() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(VRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - /* 8-bit ASIMD register class - * This class implies 8-bit scalar register. - */ - class BRegister { - public: - BRegister() = delete; - constexpr explicit BRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const BRegister&, const BRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator VRegister() const { - return VRegister(Index); - } - constexpr BRegister V() const; - constexpr HRegister H() const; - constexpr SRegister S() const; - constexpr DRegister D() const; - constexpr QRegister Q() const; - constexpr ZRegister Z() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(BRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - /* 16-bit ASIMD register class - * This class implies 16-bit scalar register. - */ - class HRegister { - public: - HRegister() = delete; - constexpr explicit HRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const HRegister&, const HRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator VRegister() const { - return VRegister(Index); - } - constexpr HRegister V() const; - constexpr BRegister B() const; - constexpr SRegister S() const; - constexpr DRegister D() const; - constexpr QRegister Q() const; - constexpr ZRegister Z() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(HRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - /* 32-bit ASIMD register class - * This class implies 32-bit scalar register. - */ - class SRegister { - public: - SRegister() = delete; - constexpr explicit SRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const SRegister&, const SRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator VRegister() const { - return VRegister(Index); - } - constexpr SRegister V() const; - constexpr BRegister B() const; - constexpr HRegister H() const; - constexpr DRegister D() const; - constexpr QRegister Q() const; - constexpr ZRegister Z() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(SRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - /* 64-bit ASIMD register class - * This class doesn't imply Vector or Scalar. - * Associated with operating the instruction at 64-bit. - */ - class DRegister { - public: - DRegister() = delete; - constexpr explicit DRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const DRegister&, const DRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator VRegister() const { - return VRegister(Index); - } - constexpr DRegister V() const; - constexpr BRegister B() const; - constexpr HRegister H() const; - constexpr SRegister S() const; - constexpr QRegister Q() const; - constexpr ZRegister Z() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(DRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - /* 128-bit ASIMD register class - * This class doesn't imply Vector or Scalar. - * Associated with operating the instruction at 128-bit. - */ - class QRegister { - public: - QRegister() = delete; - constexpr explicit QRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const QRegister&, const QRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator VRegister() const { - return VRegister(Index); - } - constexpr QRegister V() const; - constexpr BRegister B() const; - constexpr HRegister H() const; - constexpr SRegister S() const; - constexpr DRegister D() const; - constexpr ZRegister Z() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(QRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - /* Unsized SVE register class. - * This class explicitly implies the instruction will operate using SVE. - */ - class ZRegister { - public: - ZRegister() = delete; - constexpr explicit ZRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const ZRegister&, const ZRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr VRegister V() const; - constexpr BRegister B() const; - constexpr HRegister H() const; - constexpr SRegister S() const; - constexpr DRegister D() const; - constexpr QRegister Q() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(ZRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - // VRegister - inline constexpr BRegister VRegister::B() const { - return BRegister{Index}; - } - inline constexpr HRegister VRegister::H() const { - return HRegister{Index}; - } - inline constexpr SRegister VRegister::S() const { - return SRegister{Index}; - } - inline constexpr DRegister VRegister::D() const { - return DRegister{Index}; - } - inline constexpr QRegister VRegister::Q() const { - return QRegister{Index}; - } - inline constexpr ZRegister VRegister::Z() const { - return ZRegister{Index}; - } - - // BRegister - inline constexpr BRegister BRegister::V() const { - return *this; - } - inline constexpr HRegister BRegister::H() const { - return HRegister{Index}; - } - inline constexpr SRegister BRegister::S() const { - return SRegister{Index}; - } - inline constexpr DRegister BRegister::D() const { - return DRegister{Index}; - } - inline constexpr QRegister BRegister::Q() const { - return QRegister{Index}; - } - inline constexpr ZRegister BRegister::Z() const { - return ZRegister{Index}; - } - - // HRegister - inline constexpr HRegister HRegister::V() const { - return *this; - } - inline constexpr BRegister HRegister::B() const { - return BRegister{Index}; - } - inline constexpr SRegister HRegister::S() const { - return SRegister{Index}; - } - inline constexpr DRegister HRegister::D() const { - return DRegister{Index}; - } - inline constexpr QRegister HRegister::Q() const { - return QRegister{Index}; - } - inline constexpr ZRegister HRegister::Z() const { - return ZRegister{Index}; - } - - // SRegister - inline constexpr SRegister SRegister::V() const { - return *this; - } - inline constexpr BRegister SRegister::B() const { - return BRegister{Index}; - } - inline constexpr HRegister SRegister::H() const { - return HRegister{Index}; - } - inline constexpr DRegister SRegister::D() const { - return DRegister{Index}; - } - inline constexpr QRegister SRegister::Q() const { - return QRegister{Index}; - } - inline constexpr ZRegister SRegister::Z() const { - return ZRegister{Index}; - } - - // DRegister - inline constexpr DRegister DRegister::V() const { - return DRegister{Index}; - } - inline constexpr BRegister DRegister::B() const { - return BRegister{Index}; - } - inline constexpr HRegister DRegister::H() const { - return HRegister{Index}; - } - inline constexpr SRegister DRegister::S() const { - return SRegister{Index}; - } - inline constexpr QRegister DRegister::Q() const { - return QRegister{Index}; - } - inline constexpr ZRegister DRegister::Z() const { - return ZRegister{Index}; - } - - // QRegister - inline constexpr QRegister QRegister::V() const { - return *this; - } - inline constexpr BRegister QRegister::B() const { - return BRegister{Index}; - } - inline constexpr HRegister QRegister::H() const { - return HRegister{Index}; - } - inline constexpr SRegister QRegister::S() const { - return SRegister{Index}; - } - inline constexpr DRegister QRegister::D() const { - return DRegister{Index}; - } - inline constexpr ZRegister QRegister::Z() const { - return ZRegister{Index}; - } - - // ZRegister - inline constexpr VRegister ZRegister::V() const { + constexpr operator VRegister() const { return VRegister(Index); } - inline constexpr BRegister ZRegister::B() const { - return BRegister(Index); - } - inline constexpr HRegister ZRegister::H() const { - return HRegister(Index); - } - inline constexpr SRegister ZRegister::S() const { - return SRegister(Index); - } - inline constexpr DRegister ZRegister::D() const { - return DRegister(Index); - } - inline constexpr QRegister ZRegister::Q() const { - return QRegister(Index); + constexpr BRegister V() const; + constexpr HRegister H() const; + constexpr SRegister S() const; + constexpr DRegister D() const; + constexpr QRegister Q() const; + constexpr ZRegister Z() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(BRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +/* 16-bit ASIMD register class + * This class implies 16-bit scalar register. + */ +class HRegister { +public: + HRegister() = delete; + constexpr explicit HRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const HRegister&, const HRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - // Namespace containing all unsized ASIMD register objects. - namespace VReg { - constexpr static VRegister v0(0); - constexpr static VRegister v1(1); - constexpr static VRegister v2(2); - constexpr static VRegister v3(3); - constexpr static VRegister v4(4); - constexpr static VRegister v5(5); - constexpr static VRegister v6(6); - constexpr static VRegister v7(7); - constexpr static VRegister v8(8); - constexpr static VRegister v9(9); - constexpr static VRegister v10(10); - constexpr static VRegister v11(11); - constexpr static VRegister v12(12); - constexpr static VRegister v13(13); - constexpr static VRegister v14(14); - constexpr static VRegister v15(15); - constexpr static VRegister v16(16); - constexpr static VRegister v17(17); - constexpr static VRegister v18(18); - constexpr static VRegister v19(19); - constexpr static VRegister v20(20); - constexpr static VRegister v21(21); - constexpr static VRegister v22(22); - constexpr static VRegister v23(23); - constexpr static VRegister v24(24); - constexpr static VRegister v25(25); - constexpr static VRegister v26(26); - constexpr static VRegister v27(27); - constexpr static VRegister v28(28); - constexpr static VRegister v29(29); - constexpr static VRegister v30(30); - constexpr static VRegister v31(31); + constexpr operator VRegister() const { + return VRegister(Index); + } + constexpr HRegister V() const; + constexpr BRegister B() const; + constexpr SRegister S() const; + constexpr DRegister D() const; + constexpr QRegister Q() const; + constexpr ZRegister Z() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(HRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +/* 32-bit ASIMD register class + * This class implies 32-bit scalar register. + */ +class SRegister { +public: + SRegister() = delete; + constexpr explicit SRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const SRegister&, const SRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - // Namespace containing all 8-bit ASIMD register objects. - namespace BReg { - constexpr static BRegister b0(0); - constexpr static BRegister b1(1); - constexpr static BRegister b2(2); - constexpr static BRegister b3(3); - constexpr static BRegister b4(4); - constexpr static BRegister b5(5); - constexpr static BRegister b6(6); - constexpr static BRegister b7(7); - constexpr static BRegister b8(8); - constexpr static BRegister b9(9); - constexpr static BRegister b10(10); - constexpr static BRegister b11(11); - constexpr static BRegister b12(12); - constexpr static BRegister b13(13); - constexpr static BRegister b14(14); - constexpr static BRegister b15(15); - constexpr static BRegister b16(16); - constexpr static BRegister b17(17); - constexpr static BRegister b18(18); - constexpr static BRegister b19(19); - constexpr static BRegister b20(20); - constexpr static BRegister b21(21); - constexpr static BRegister b22(22); - constexpr static BRegister b23(23); - constexpr static BRegister b24(24); - constexpr static BRegister b25(25); - constexpr static BRegister b26(26); - constexpr static BRegister b27(27); - constexpr static BRegister b28(28); - constexpr static BRegister b29(29); - constexpr static BRegister b30(30); - constexpr static BRegister b31(31); + constexpr operator VRegister() const { + return VRegister(Index); + } + constexpr SRegister V() const; + constexpr BRegister B() const; + constexpr HRegister H() const; + constexpr DRegister D() const; + constexpr QRegister Q() const; + constexpr ZRegister Z() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(SRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +/* 64-bit ASIMD register class + * This class doesn't imply Vector or Scalar. + * Associated with operating the instruction at 64-bit. + */ +class DRegister { +public: + DRegister() = delete; + constexpr explicit DRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const DRegister&, const DRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - // Namespace containing all 16-bit ASIMD register objects. - namespace HReg { - constexpr static HRegister h0(0); - constexpr static HRegister h1(1); - constexpr static HRegister h2(2); - constexpr static HRegister h3(3); - constexpr static HRegister h4(4); - constexpr static HRegister h5(5); - constexpr static HRegister h6(6); - constexpr static HRegister h7(7); - constexpr static HRegister h8(8); - constexpr static HRegister h9(9); - constexpr static HRegister h10(10); - constexpr static HRegister h11(11); - constexpr static HRegister h12(12); - constexpr static HRegister h13(13); - constexpr static HRegister h14(14); - constexpr static HRegister h15(15); - constexpr static HRegister h16(16); - constexpr static HRegister h17(17); - constexpr static HRegister h18(18); - constexpr static HRegister h19(19); - constexpr static HRegister h20(20); - constexpr static HRegister h21(21); - constexpr static HRegister h22(22); - constexpr static HRegister h23(23); - constexpr static HRegister h24(24); - constexpr static HRegister h25(25); - constexpr static HRegister h26(26); - constexpr static HRegister h27(27); - constexpr static HRegister h28(28); - constexpr static HRegister h29(29); - constexpr static HRegister h30(30); - constexpr static HRegister h31(31); + constexpr operator VRegister() const { + return VRegister(Index); + } + constexpr DRegister V() const; + constexpr BRegister B() const; + constexpr HRegister H() const; + constexpr SRegister S() const; + constexpr QRegister Q() const; + constexpr ZRegister Z() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(DRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +/* 128-bit ASIMD register class + * This class doesn't imply Vector or Scalar. + * Associated with operating the instruction at 128-bit. + */ +class QRegister { +public: + QRegister() = delete; + constexpr explicit QRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const QRegister&, const QRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - // Namespace containing all 32-bit ASIMD register objects. - namespace SReg { - constexpr static SRegister s0(0); - constexpr static SRegister s1(1); - constexpr static SRegister s2(2); - constexpr static SRegister s3(3); - constexpr static SRegister s4(4); - constexpr static SRegister s5(5); - constexpr static SRegister s6(6); - constexpr static SRegister s7(7); - constexpr static SRegister s8(8); - constexpr static SRegister s9(9); - constexpr static SRegister s10(10); - constexpr static SRegister s11(11); - constexpr static SRegister s12(12); - constexpr static SRegister s13(13); - constexpr static SRegister s14(14); - constexpr static SRegister s15(15); - constexpr static SRegister s16(16); - constexpr static SRegister s17(17); - constexpr static SRegister s18(18); - constexpr static SRegister s19(19); - constexpr static SRegister s20(20); - constexpr static SRegister s21(21); - constexpr static SRegister s22(22); - constexpr static SRegister s23(23); - constexpr static SRegister s24(24); - constexpr static SRegister s25(25); - constexpr static SRegister s26(26); - constexpr static SRegister s27(27); - constexpr static SRegister s28(28); - constexpr static SRegister s29(29); - constexpr static SRegister s30(30); - constexpr static SRegister s31(31); + constexpr operator VRegister() const { + return VRegister(Index); + } + constexpr QRegister V() const; + constexpr BRegister B() const; + constexpr HRegister H() const; + constexpr SRegister S() const; + constexpr DRegister D() const; + constexpr ZRegister Z() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(QRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +/* Unsized SVE register class. + * This class explicitly implies the instruction will operate using SVE. + */ +class ZRegister { +public: + ZRegister() = delete; + constexpr explicit ZRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const ZRegister&, const ZRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; } - // Namespace containing all 64-bit ASIMD register objects. - namespace DReg { - constexpr static DRegister d0(0); - constexpr static DRegister d1(1); - constexpr static DRegister d2(2); - constexpr static DRegister d3(3); - constexpr static DRegister d4(4); - constexpr static DRegister d5(5); - constexpr static DRegister d6(6); - constexpr static DRegister d7(7); - constexpr static DRegister d8(8); - constexpr static DRegister d9(9); - constexpr static DRegister d10(10); - constexpr static DRegister d11(11); - constexpr static DRegister d12(12); - constexpr static DRegister d13(13); - constexpr static DRegister d14(14); - constexpr static DRegister d15(15); - constexpr static DRegister d16(16); - constexpr static DRegister d17(17); - constexpr static DRegister d18(18); - constexpr static DRegister d19(19); - constexpr static DRegister d20(20); - constexpr static DRegister d21(21); - constexpr static DRegister d22(22); - constexpr static DRegister d23(23); - constexpr static DRegister d24(24); - constexpr static DRegister d25(25); - constexpr static DRegister d26(26); - constexpr static DRegister d27(27); - constexpr static DRegister d28(28); - constexpr static DRegister d29(29); - constexpr static DRegister d30(30); - constexpr static DRegister d31(31); - } + constexpr VRegister V() const; + constexpr BRegister B() const; + constexpr HRegister H() const; + constexpr SRegister S() const; + constexpr DRegister D() const; + constexpr QRegister Q() const; - // Namespace containing all 128-bit ASIMD register objects. - namespace QReg { - constexpr static QRegister q0(0); - constexpr static QRegister q1(1); - constexpr static QRegister q2(2); - constexpr static QRegister q3(3); - constexpr static QRegister q4(4); - constexpr static QRegister q5(5); - constexpr static QRegister q6(6); - constexpr static QRegister q7(7); - constexpr static QRegister q8(8); - constexpr static QRegister q9(9); - constexpr static QRegister q10(10); - constexpr static QRegister q11(11); - constexpr static QRegister q12(12); - constexpr static QRegister q13(13); - constexpr static QRegister q14(14); - constexpr static QRegister q15(15); - constexpr static QRegister q16(16); - constexpr static QRegister q17(17); - constexpr static QRegister q18(18); - constexpr static QRegister q19(19); - constexpr static QRegister q20(20); - constexpr static QRegister q21(21); - constexpr static QRegister q22(22); - constexpr static QRegister q23(23); - constexpr static QRegister q24(24); - constexpr static QRegister q25(25); - constexpr static QRegister q26(26); - constexpr static QRegister q27(27); - constexpr static QRegister q28(28); - constexpr static QRegister q29(29); - constexpr static QRegister q30(30); - constexpr static QRegister q31(31); - } +private: + uint32_t Index; +}; +static_assert(sizeof(ZRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); - // Namespace containing all unsigned SVE register objects. - namespace ZReg { - constexpr static ZRegister z0(0); - constexpr static ZRegister z1(1); - constexpr static ZRegister z2(2); - constexpr static ZRegister z3(3); - constexpr static ZRegister z4(4); - constexpr static ZRegister z5(5); - constexpr static ZRegister z6(6); - constexpr static ZRegister z7(7); - constexpr static ZRegister z8(8); - constexpr static ZRegister z9(9); - constexpr static ZRegister z10(10); - constexpr static ZRegister z11(11); - constexpr static ZRegister z12(12); - constexpr static ZRegister z13(13); - constexpr static ZRegister z14(14); - constexpr static ZRegister z15(15); - constexpr static ZRegister z16(16); - constexpr static ZRegister z17(17); - constexpr static ZRegister z18(18); - constexpr static ZRegister z19(19); - constexpr static ZRegister z20(20); - constexpr static ZRegister z21(21); - constexpr static ZRegister z22(22); - constexpr static ZRegister z23(23); - constexpr static ZRegister z24(24); - constexpr static ZRegister z25(25); - constexpr static ZRegister z26(26); - constexpr static ZRegister z27(27); - constexpr static ZRegister z28(28); - constexpr static ZRegister z29(29); - constexpr static ZRegister z30(30); - constexpr static ZRegister z31(31); - } - - // Zero-cost FPR->GPR - inline constexpr Register ToReg(HRegister Reg) { - return Register(Reg.Idx()); - } - inline constexpr Register ToReg(SRegister Reg) { - return Register(Reg.Idx()); - } - inline constexpr Register ToReg(DRegister Reg) { - return Register(Reg.Idx()); - } - inline constexpr Register ToReg(VRegister Reg) { - return Register(Reg.Idx()); - } - - // Zero-cost GPR->FPR - inline constexpr VRegister ToVReg(Register Reg) { - return VRegister(Reg.Idx()); - } - inline constexpr VRegister ToVReg(XRegister Reg) { - return VRegister(Reg.Idx()); - } - inline constexpr VRegister ToVReg(WRegister Reg) { - return VRegister(Reg.Idx()); - } - - class PRegisterZero; - class PRegisterMerge; - - /* Unsized predicate register for SVE. - * This is unsized because of how SVE operates. - */ - class PRegister { - public: - PRegister() = delete; - constexpr PRegister(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const PRegister&, const PRegister&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr PRegisterZero Zeroing() const; - constexpr PRegisterMerge Merging() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(PRegister) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - // Unsized predicate register for SVE with zeroing semantics. - class PRegisterZero { - public: - PRegisterZero() = delete; - constexpr PRegisterZero(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const PRegisterZero&, const PRegisterZero&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator PRegister() const { - return PRegister(Index); - } - constexpr PRegister P() const { - return PRegister(Index); - } - constexpr PRegisterMerge Merging() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(PRegisterZero) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - // Unsized predicate register for SVE with merging semantics. - class PRegisterMerge { - public: - PRegisterMerge() = delete; - constexpr PRegisterMerge(uint32_t Idx) - : Index {Idx} {} - - friend constexpr auto operator<=>(const PRegisterMerge&, const PRegisterMerge&) = default; - - constexpr uint32_t Idx() const { - return Index; - } - - constexpr operator PRegister() const { - return PRegister(Index); - } - constexpr PRegister P() const { - return PRegister(Index); - } - constexpr PRegisterZero Zeroing() const; - - private: - uint32_t Index; - }; - static_assert(sizeof(PRegisterZero) == sizeof(uint32_t), "Needs to be uint32_t"); - static_assert(std::is_trivial_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "Needs to be standard"); - - // PRegister - inline constexpr PRegisterZero PRegister::Zeroing() const { - return PRegisterZero(Idx()); - } - inline constexpr PRegisterMerge PRegister::Merging() const { - return PRegisterMerge(Idx()); - } - - // PRegisterZero - inline constexpr PRegisterMerge PRegisterZero::Merging() const { - return PRegisterMerge(Idx()); - } - - // PRegisterMerge - inline constexpr PRegisterZero PRegisterMerge::Zeroing() const { - return PRegisterZero(Idx()); - } - - // Namespace containing all unsigned SVE predicate register objects. - namespace PReg { - constexpr static PRegister p0(0); - constexpr static PRegister p1(1); - constexpr static PRegister p2(2); - constexpr static PRegister p3(3); - constexpr static PRegister p4(4); - constexpr static PRegister p5(5); - constexpr static PRegister p6(6); - constexpr static PRegister p7(7); - constexpr static PRegister p8(8); - constexpr static PRegister p9(9); - constexpr static PRegister p10(10); - constexpr static PRegister p11(11); - constexpr static PRegister p12(12); - constexpr static PRegister p13(13); - constexpr static PRegister p14(14); - constexpr static PRegister p15(15); - } - - /* `OpType` enum describes how some SVE instructions operate if they support both forms. - * Not all SVE instructions support this. - */ - enum class OpType : uint32_t { - Destructive = 0, - Constructive, - }; +// VRegister +inline constexpr BRegister VRegister::B() const { + return BRegister {Index}; } +inline constexpr HRegister VRegister::H() const { + return HRegister {Index}; +} +inline constexpr SRegister VRegister::S() const { + return SRegister {Index}; +} +inline constexpr DRegister VRegister::D() const { + return DRegister {Index}; +} +inline constexpr QRegister VRegister::Q() const { + return QRegister {Index}; +} +inline constexpr ZRegister VRegister::Z() const { + return ZRegister {Index}; +} + +// BRegister +inline constexpr BRegister BRegister::V() const { + return *this; +} +inline constexpr HRegister BRegister::H() const { + return HRegister {Index}; +} +inline constexpr SRegister BRegister::S() const { + return SRegister {Index}; +} +inline constexpr DRegister BRegister::D() const { + return DRegister {Index}; +} +inline constexpr QRegister BRegister::Q() const { + return QRegister {Index}; +} +inline constexpr ZRegister BRegister::Z() const { + return ZRegister {Index}; +} + +// HRegister +inline constexpr HRegister HRegister::V() const { + return *this; +} +inline constexpr BRegister HRegister::B() const { + return BRegister {Index}; +} +inline constexpr SRegister HRegister::S() const { + return SRegister {Index}; +} +inline constexpr DRegister HRegister::D() const { + return DRegister {Index}; +} +inline constexpr QRegister HRegister::Q() const { + return QRegister {Index}; +} +inline constexpr ZRegister HRegister::Z() const { + return ZRegister {Index}; +} + +// SRegister +inline constexpr SRegister SRegister::V() const { + return *this; +} +inline constexpr BRegister SRegister::B() const { + return BRegister {Index}; +} +inline constexpr HRegister SRegister::H() const { + return HRegister {Index}; +} +inline constexpr DRegister SRegister::D() const { + return DRegister {Index}; +} +inline constexpr QRegister SRegister::Q() const { + return QRegister {Index}; +} +inline constexpr ZRegister SRegister::Z() const { + return ZRegister {Index}; +} + +// DRegister +inline constexpr DRegister DRegister::V() const { + return DRegister {Index}; +} +inline constexpr BRegister DRegister::B() const { + return BRegister {Index}; +} +inline constexpr HRegister DRegister::H() const { + return HRegister {Index}; +} +inline constexpr SRegister DRegister::S() const { + return SRegister {Index}; +} +inline constexpr QRegister DRegister::Q() const { + return QRegister {Index}; +} +inline constexpr ZRegister DRegister::Z() const { + return ZRegister {Index}; +} + +// QRegister +inline constexpr QRegister QRegister::V() const { + return *this; +} +inline constexpr BRegister QRegister::B() const { + return BRegister {Index}; +} +inline constexpr HRegister QRegister::H() const { + return HRegister {Index}; +} +inline constexpr SRegister QRegister::S() const { + return SRegister {Index}; +} +inline constexpr DRegister QRegister::D() const { + return DRegister {Index}; +} +inline constexpr ZRegister QRegister::Z() const { + return ZRegister {Index}; +} + +// ZRegister +inline constexpr VRegister ZRegister::V() const { + return VRegister(Index); +} +inline constexpr BRegister ZRegister::B() const { + return BRegister(Index); +} +inline constexpr HRegister ZRegister::H() const { + return HRegister(Index); +} +inline constexpr SRegister ZRegister::S() const { + return SRegister(Index); +} +inline constexpr DRegister ZRegister::D() const { + return DRegister(Index); +} +inline constexpr QRegister ZRegister::Q() const { + return QRegister(Index); +} + +// Namespace containing all unsized ASIMD register objects. +namespace VReg { + constexpr static VRegister v0(0); + constexpr static VRegister v1(1); + constexpr static VRegister v2(2); + constexpr static VRegister v3(3); + constexpr static VRegister v4(4); + constexpr static VRegister v5(5); + constexpr static VRegister v6(6); + constexpr static VRegister v7(7); + constexpr static VRegister v8(8); + constexpr static VRegister v9(9); + constexpr static VRegister v10(10); + constexpr static VRegister v11(11); + constexpr static VRegister v12(12); + constexpr static VRegister v13(13); + constexpr static VRegister v14(14); + constexpr static VRegister v15(15); + constexpr static VRegister v16(16); + constexpr static VRegister v17(17); + constexpr static VRegister v18(18); + constexpr static VRegister v19(19); + constexpr static VRegister v20(20); + constexpr static VRegister v21(21); + constexpr static VRegister v22(22); + constexpr static VRegister v23(23); + constexpr static VRegister v24(24); + constexpr static VRegister v25(25); + constexpr static VRegister v26(26); + constexpr static VRegister v27(27); + constexpr static VRegister v28(28); + constexpr static VRegister v29(29); + constexpr static VRegister v30(30); + constexpr static VRegister v31(31); +} // namespace VReg + +// Namespace containing all 8-bit ASIMD register objects. +namespace BReg { + constexpr static BRegister b0(0); + constexpr static BRegister b1(1); + constexpr static BRegister b2(2); + constexpr static BRegister b3(3); + constexpr static BRegister b4(4); + constexpr static BRegister b5(5); + constexpr static BRegister b6(6); + constexpr static BRegister b7(7); + constexpr static BRegister b8(8); + constexpr static BRegister b9(9); + constexpr static BRegister b10(10); + constexpr static BRegister b11(11); + constexpr static BRegister b12(12); + constexpr static BRegister b13(13); + constexpr static BRegister b14(14); + constexpr static BRegister b15(15); + constexpr static BRegister b16(16); + constexpr static BRegister b17(17); + constexpr static BRegister b18(18); + constexpr static BRegister b19(19); + constexpr static BRegister b20(20); + constexpr static BRegister b21(21); + constexpr static BRegister b22(22); + constexpr static BRegister b23(23); + constexpr static BRegister b24(24); + constexpr static BRegister b25(25); + constexpr static BRegister b26(26); + constexpr static BRegister b27(27); + constexpr static BRegister b28(28); + constexpr static BRegister b29(29); + constexpr static BRegister b30(30); + constexpr static BRegister b31(31); +} // namespace BReg + +// Namespace containing all 16-bit ASIMD register objects. +namespace HReg { + constexpr static HRegister h0(0); + constexpr static HRegister h1(1); + constexpr static HRegister h2(2); + constexpr static HRegister h3(3); + constexpr static HRegister h4(4); + constexpr static HRegister h5(5); + constexpr static HRegister h6(6); + constexpr static HRegister h7(7); + constexpr static HRegister h8(8); + constexpr static HRegister h9(9); + constexpr static HRegister h10(10); + constexpr static HRegister h11(11); + constexpr static HRegister h12(12); + constexpr static HRegister h13(13); + constexpr static HRegister h14(14); + constexpr static HRegister h15(15); + constexpr static HRegister h16(16); + constexpr static HRegister h17(17); + constexpr static HRegister h18(18); + constexpr static HRegister h19(19); + constexpr static HRegister h20(20); + constexpr static HRegister h21(21); + constexpr static HRegister h22(22); + constexpr static HRegister h23(23); + constexpr static HRegister h24(24); + constexpr static HRegister h25(25); + constexpr static HRegister h26(26); + constexpr static HRegister h27(27); + constexpr static HRegister h28(28); + constexpr static HRegister h29(29); + constexpr static HRegister h30(30); + constexpr static HRegister h31(31); +} // namespace HReg + +// Namespace containing all 32-bit ASIMD register objects. +namespace SReg { + constexpr static SRegister s0(0); + constexpr static SRegister s1(1); + constexpr static SRegister s2(2); + constexpr static SRegister s3(3); + constexpr static SRegister s4(4); + constexpr static SRegister s5(5); + constexpr static SRegister s6(6); + constexpr static SRegister s7(7); + constexpr static SRegister s8(8); + constexpr static SRegister s9(9); + constexpr static SRegister s10(10); + constexpr static SRegister s11(11); + constexpr static SRegister s12(12); + constexpr static SRegister s13(13); + constexpr static SRegister s14(14); + constexpr static SRegister s15(15); + constexpr static SRegister s16(16); + constexpr static SRegister s17(17); + constexpr static SRegister s18(18); + constexpr static SRegister s19(19); + constexpr static SRegister s20(20); + constexpr static SRegister s21(21); + constexpr static SRegister s22(22); + constexpr static SRegister s23(23); + constexpr static SRegister s24(24); + constexpr static SRegister s25(25); + constexpr static SRegister s26(26); + constexpr static SRegister s27(27); + constexpr static SRegister s28(28); + constexpr static SRegister s29(29); + constexpr static SRegister s30(30); + constexpr static SRegister s31(31); +} // namespace SReg + +// Namespace containing all 64-bit ASIMD register objects. +namespace DReg { + constexpr static DRegister d0(0); + constexpr static DRegister d1(1); + constexpr static DRegister d2(2); + constexpr static DRegister d3(3); + constexpr static DRegister d4(4); + constexpr static DRegister d5(5); + constexpr static DRegister d6(6); + constexpr static DRegister d7(7); + constexpr static DRegister d8(8); + constexpr static DRegister d9(9); + constexpr static DRegister d10(10); + constexpr static DRegister d11(11); + constexpr static DRegister d12(12); + constexpr static DRegister d13(13); + constexpr static DRegister d14(14); + constexpr static DRegister d15(15); + constexpr static DRegister d16(16); + constexpr static DRegister d17(17); + constexpr static DRegister d18(18); + constexpr static DRegister d19(19); + constexpr static DRegister d20(20); + constexpr static DRegister d21(21); + constexpr static DRegister d22(22); + constexpr static DRegister d23(23); + constexpr static DRegister d24(24); + constexpr static DRegister d25(25); + constexpr static DRegister d26(26); + constexpr static DRegister d27(27); + constexpr static DRegister d28(28); + constexpr static DRegister d29(29); + constexpr static DRegister d30(30); + constexpr static DRegister d31(31); +} // namespace DReg + +// Namespace containing all 128-bit ASIMD register objects. +namespace QReg { + constexpr static QRegister q0(0); + constexpr static QRegister q1(1); + constexpr static QRegister q2(2); + constexpr static QRegister q3(3); + constexpr static QRegister q4(4); + constexpr static QRegister q5(5); + constexpr static QRegister q6(6); + constexpr static QRegister q7(7); + constexpr static QRegister q8(8); + constexpr static QRegister q9(9); + constexpr static QRegister q10(10); + constexpr static QRegister q11(11); + constexpr static QRegister q12(12); + constexpr static QRegister q13(13); + constexpr static QRegister q14(14); + constexpr static QRegister q15(15); + constexpr static QRegister q16(16); + constexpr static QRegister q17(17); + constexpr static QRegister q18(18); + constexpr static QRegister q19(19); + constexpr static QRegister q20(20); + constexpr static QRegister q21(21); + constexpr static QRegister q22(22); + constexpr static QRegister q23(23); + constexpr static QRegister q24(24); + constexpr static QRegister q25(25); + constexpr static QRegister q26(26); + constexpr static QRegister q27(27); + constexpr static QRegister q28(28); + constexpr static QRegister q29(29); + constexpr static QRegister q30(30); + constexpr static QRegister q31(31); +} // namespace QReg + +// Namespace containing all unsigned SVE register objects. +namespace ZReg { + constexpr static ZRegister z0(0); + constexpr static ZRegister z1(1); + constexpr static ZRegister z2(2); + constexpr static ZRegister z3(3); + constexpr static ZRegister z4(4); + constexpr static ZRegister z5(5); + constexpr static ZRegister z6(6); + constexpr static ZRegister z7(7); + constexpr static ZRegister z8(8); + constexpr static ZRegister z9(9); + constexpr static ZRegister z10(10); + constexpr static ZRegister z11(11); + constexpr static ZRegister z12(12); + constexpr static ZRegister z13(13); + constexpr static ZRegister z14(14); + constexpr static ZRegister z15(15); + constexpr static ZRegister z16(16); + constexpr static ZRegister z17(17); + constexpr static ZRegister z18(18); + constexpr static ZRegister z19(19); + constexpr static ZRegister z20(20); + constexpr static ZRegister z21(21); + constexpr static ZRegister z22(22); + constexpr static ZRegister z23(23); + constexpr static ZRegister z24(24); + constexpr static ZRegister z25(25); + constexpr static ZRegister z26(26); + constexpr static ZRegister z27(27); + constexpr static ZRegister z28(28); + constexpr static ZRegister z29(29); + constexpr static ZRegister z30(30); + constexpr static ZRegister z31(31); +} // namespace ZReg + +// Zero-cost FPR->GPR +inline constexpr Register ToReg(HRegister Reg) { + return Register(Reg.Idx()); +} +inline constexpr Register ToReg(SRegister Reg) { + return Register(Reg.Idx()); +} +inline constexpr Register ToReg(DRegister Reg) { + return Register(Reg.Idx()); +} +inline constexpr Register ToReg(VRegister Reg) { + return Register(Reg.Idx()); +} + +// Zero-cost GPR->FPR +inline constexpr VRegister ToVReg(Register Reg) { + return VRegister(Reg.Idx()); +} +inline constexpr VRegister ToVReg(XRegister Reg) { + return VRegister(Reg.Idx()); +} +inline constexpr VRegister ToVReg(WRegister Reg) { + return VRegister(Reg.Idx()); +} + +class PRegisterZero; +class PRegisterMerge; + +/* Unsized predicate register for SVE. + * This is unsized because of how SVE operates. + */ +class PRegister { +public: + PRegister() = delete; + constexpr PRegister(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const PRegister&, const PRegister&) = default; + + constexpr uint32_t Idx() const { + return Index; + } + + constexpr PRegisterZero Zeroing() const; + constexpr PRegisterMerge Merging() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(PRegister) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +// Unsized predicate register for SVE with zeroing semantics. +class PRegisterZero { +public: + PRegisterZero() = delete; + constexpr PRegisterZero(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const PRegisterZero&, const PRegisterZero&) = default; + + constexpr uint32_t Idx() const { + return Index; + } + + constexpr operator PRegister() const { + return PRegister(Index); + } + constexpr PRegister P() const { + return PRegister(Index); + } + constexpr PRegisterMerge Merging() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(PRegisterZero) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +// Unsized predicate register for SVE with merging semantics. +class PRegisterMerge { +public: + PRegisterMerge() = delete; + constexpr PRegisterMerge(uint32_t Idx) + : Index {Idx} {} + + friend constexpr auto operator<=>(const PRegisterMerge&, const PRegisterMerge&) = default; + + constexpr uint32_t Idx() const { + return Index; + } + + constexpr operator PRegister() const { + return PRegister(Index); + } + constexpr PRegister P() const { + return PRegister(Index); + } + constexpr PRegisterZero Zeroing() const; + +private: + uint32_t Index; +}; +static_assert(sizeof(PRegisterZero) == sizeof(uint32_t), "Needs to be uint32_t"); +static_assert(std::is_trivial_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "Needs to be standard"); + +// PRegister +inline constexpr PRegisterZero PRegister::Zeroing() const { + return PRegisterZero(Idx()); +} +inline constexpr PRegisterMerge PRegister::Merging() const { + return PRegisterMerge(Idx()); +} + +// PRegisterZero +inline constexpr PRegisterMerge PRegisterZero::Merging() const { + return PRegisterMerge(Idx()); +} + +// PRegisterMerge +inline constexpr PRegisterZero PRegisterMerge::Zeroing() const { + return PRegisterZero(Idx()); +} + +// Namespace containing all unsigned SVE predicate register objects. +namespace PReg { + constexpr static PRegister p0(0); + constexpr static PRegister p1(1); + constexpr static PRegister p2(2); + constexpr static PRegister p3(3); + constexpr static PRegister p4(4); + constexpr static PRegister p5(5); + constexpr static PRegister p6(6); + constexpr static PRegister p7(7); + constexpr static PRegister p8(8); + constexpr static PRegister p9(9); + constexpr static PRegister p10(10); + constexpr static PRegister p11(11); + constexpr static PRegister p12(12); + constexpr static PRegister p13(13); + constexpr static PRegister p14(14); + constexpr static PRegister p15(15); +} // namespace PReg + +/* `OpType` enum describes how some SVE instructions operate if they support both forms. + * Not all SVE instructions support this. + */ +enum class OpType : uint32_t { + Destructive = 0, + Constructive, +}; +} // namespace FEXCore::ARMEmitter diff --git a/FEXCore/Source/Interface/Core/BlockSamplingData.cpp b/FEXCore/Source/Interface/Core/BlockSamplingData.cpp index c4c6cb098..660863306 100644 --- a/FEXCore/Source/Interface/Core/BlockSamplingData.cpp +++ b/FEXCore/Source/Interface/Core/BlockSamplingData.cpp @@ -6,48 +6,46 @@ #include namespace FEXCore { - void BlockSamplingData::DumpBlockData() { - std::fstream Output; - Output.open("output.csv", std::fstream::out | std::fstream::binary); +void BlockSamplingData::DumpBlockData() { + std::fstream Output; + Output.open("output.csv", std::fstream::out | std::fstream::binary); - if (!Output.is_open()) - return; - - Output << "Entry, Min, Max, Total, Calls, Average" << std::endl; - - for (auto it : SamplingMap) { - if (!it.second->TotalCalls) - continue; - - Output << "0x" << std::hex << it.first - << ", " << std::dec << it.second->Min - << ", " << std::dec << it.second->Max - << ", " << std::dec << it.second->TotalTime - << ", " << std::dec << it.second->TotalCalls - << ", " << std::dec << ((double)it.second->TotalTime / (double)it.second->TotalCalls) - << std::endl; - } - Output.close(); - LogMan::Msg::DFmt("Dumped {} blocks of sampling data", SamplingMap.size()); + if (!Output.is_open()) { + return; } - BlockSamplingData::BlockData *BlockSamplingData::GetBlockData(uint64_t RIP) { - auto it = SamplingMap.find(RIP); - if (it != SamplingMap.end()) { - return it->second; - } - BlockData *NewData = new BlockData{}; - memset(NewData, 0, sizeof(BlockData)); - NewData->Min = ~0ULL; - SamplingMap[RIP] = NewData; - return NewData; - } + Output << "Entry, Min, Max, Total, Calls, Average" << std::endl; - BlockSamplingData::~BlockSamplingData() { - DumpBlockData(); - for (auto it : SamplingMap) { - delete it.second; + for (auto it : SamplingMap) { + if (!it.second->TotalCalls) { + continue; } - SamplingMap.clear(); + + Output << "0x" << std::hex << it.first << ", " << std::dec << it.second->Min << ", " << std::dec << it.second->Max << ", " << std::dec + << it.second->TotalTime << ", " << std::dec << it.second->TotalCalls << ", " << std::dec + << ((double)it.second->TotalTime / (double)it.second->TotalCalls) << std::endl; } + Output.close(); + LogMan::Msg::DFmt("Dumped {} blocks of sampling data", SamplingMap.size()); } + +BlockSamplingData::BlockData* BlockSamplingData::GetBlockData(uint64_t RIP) { + auto it = SamplingMap.find(RIP); + if (it != SamplingMap.end()) { + return it->second; + } + BlockData* NewData = new BlockData {}; + memset(NewData, 0, sizeof(BlockData)); + NewData->Min = ~0ULL; + SamplingMap[RIP] = NewData; + return NewData; +} + +BlockSamplingData::~BlockSamplingData() { + DumpBlockData(); + for (auto it : SamplingMap) { + delete it.second; + } + SamplingMap.clear(); +} +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/BlockSamplingData.h b/FEXCore/Source/Interface/Core/BlockSamplingData.h index e1d29dec5..8460d832d 100644 --- a/FEXCore/Source/Interface/Core/BlockSamplingData.h +++ b/FEXCore/Source/Interface/Core/BlockSamplingData.h @@ -14,7 +14,7 @@ public: uint64_t TotalCalls; }; - BlockData *GetBlockData(uint64_t RIP); + BlockData* GetBlockData(uint64_t RIP); ~BlockSamplingData(); void DumpBlockData(); @@ -22,4 +22,4 @@ public: private: std::unordered_map SamplingMap; }; -} +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/CPUBackend.cpp b/FEXCore/Source/Interface/Core/CPUBackend.cpp index 0ff4e6918..23e2d6995 100644 --- a/FEXCore/Source/Interface/Core/CPUBackend.cpp +++ b/FEXCore/Source/Interface/Core/CPUBackend.cpp @@ -12,355 +12,326 @@ namespace FEXCore { namespace CPU { -constexpr static uint64_t NamedVectorConstants[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX][2] = { - {0x0003'0002'0001'0000ULL, 0x0007'0006'0005'0004ULL}, // NAMED_VECTOR_INCREMENTAL_U16_INDEX - {0x000B'000A'0009'0008ULL, 0x000F'000E'000D'000CULL}, // NAMED_VECTOR_INCREMENTAL_U16_INDEX_UPPER - {0x0000'0000'8000'0000ULL, 0x0000'0000'8000'0000ULL}, // NAMED_VECTOR_PADDSUBPS_INVERT - {0x0000'0000'8000'0000ULL, 0x0000'0000'8000'0000ULL}, // NAMED_VECTOR_PADDSUBPS_INVERT_UPPER - {0x8000'0000'0000'0000ULL, 0x0000'0000'0000'0000ULL}, // NAMED_VECTOR_PADDSUBPD_INVERT - {0x8000'0000'0000'0000ULL, 0x0000'0000'0000'0000ULL}, // NAMED_VECTOR_PADDSUBPD_INVERT_UPPER - {0x0000'0001'0000'0000ULL, 0x0000'0003'0000'0002ULL}, // NAMED_VECTOR_MOVMSKPS_SHIFT - {0x040B'0E01'0B0E'0104ULL, 0x0C03'0609'0306'090CULL}, // NAMED_VECTOR_AESKEYGENASSIST_SWIZZLE - {0x0706'0504'FFFF'FFFFULL, 0xFFFF'FFFF'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_0110B - {0x0706'0504'0302'0100ULL, 0xFFFF'FFFF'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_0111B - {0xFFFF'FFFF'0302'0100ULL, 0x0F0E'0D0C'FFFF'FFFFULL}, // NAMED_VECTOR_BLENDPS_1001B - {0x0706'0504'0302'0100ULL, 0x0F0E'0D0C'FFFF'FFFFULL}, // NAMED_VECTOR_BLENDPS_1011B - {0xFFFF'FFFF'0302'0100ULL, 0x0F0E'0D0C'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_1101B - {0x0706'0504'FFFF'FFFFULL, 0x0F0E'0D0C'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_1110B - {0x8040'2010'0804'0201ULL, 0x8040'2010'0804'0201ULL}, // NAMED_VECTOR_MOVMASKB - {0x8040'2010'0804'0201ULL, 0x8040'2010'0804'0201ULL}, // NAMED_VECTOR_MOVMASKB_UPPER - {0x8000'0000'0000'0000ULL, 0x0000'0000'0000'3FFFULL}, // NAMED_VECTOR_X87_ONE - {0xD49A'784B'CD1B'8AFEULL, 0x0000'0000'0000'4000ULL}, // NAMED_VECTOR_X87_LOG2_10 - {0xB8AA'3B29'5C17'F0BCULL, 0x0000'0000'0000'3FFFULL}, // NAMED_VECTOR_X87_LOG2_E - {0xC90F'DAA2'2168'C235ULL, 0x0000'0000'0000'4000ULL}, // NAMED_VECTOR_X87_PI - {0x9A20'9A84'FBCF'F799ULL, 0x0000'0000'0000'3FFDULL}, // NAMED_VECTOR_X87_LOG10_2 - {0xB172'17F7'D1CF'79ACULL, 0x0000'0000'0000'3FFEULL}, // NAMED_VECTOR_X87_LOG_2 -}; - -constexpr static auto PSHUFLW_LUT { -[]() consteval { - struct LUTType { - uint64_t Val[2]; - }; - // Expectation for this LUT is to simulate PSHUFLW with ARM's TBL (single register) instruction - // PSHUFLW behaviour: - // 16-bit words in [63:48], [47:32], [31:16], [15:0] are selected using the 8-bit Index. - // For 128-bit PSHUFLW, bits [127:64] are identity copied. - constexpr uint64_t IdentityCopyUpper = 0x0f'0e'0d'0c'0b'0a'09'08; - std::array TotalLUT{}; - uint64_t WordSelection[4] = { - 0x01'00, - 0x03'02, - 0x05'04, - 0x07'06, - }; - for (size_t i = 0; i < 256; ++i) { - auto &LUT = TotalLUT[i]; - const auto Word0 = (i >> 0) & 0b11; - const auto Word1 = (i >> 2) & 0b11; - const auto Word2 = (i >> 4) & 0b11; - const auto Word3 = (i >> 6) & 0b11; - - LUT.Val[0] = - (WordSelection[Word0] << 0) | - (WordSelection[Word1] << 16) | - (WordSelection[Word2] << 32) | - (WordSelection[Word3] << 48); - - LUT.Val[1] = IdentityCopyUpper; - } - return TotalLUT; -}() -}; - -constexpr static auto PSHUFHW_LUT { -[]() consteval { - struct LUTType { - uint64_t Val[2]; - }; - // Expectation for this LUT is to simulate PSHUFHW with ARM's TBL (single register) instruction - // PSHUFHW behaviour: - // 16-bit words in [127:112], [111:96], [95:80], [79:64] are selected using the 8-bit Index. - // Incoming words come from bits [127:64] of the source. - // Bits [63:0] are identity copied. - constexpr uint64_t IdentityCopyLower = 0x07'06'05'04'03'02'01'00; - std::array TotalLUT{}; - uint64_t WordSelection[4] = { - 0x09'08, - 0x0b'0a, - 0x0d'0c, - 0x0f'0e, - }; - for (size_t i = 0; i < 256; ++i) { - auto &LUT = TotalLUT[i]; - const auto Word0 = (i >> 0) & 0b11; - const auto Word1 = (i >> 2) & 0b11; - const auto Word2 = (i >> 4) & 0b11; - const auto Word3 = (i >> 6) & 0b11; - - LUT.Val[0] = IdentityCopyLower; - - LUT.Val[1] = - (WordSelection[Word0] << 0) | - (WordSelection[Word1] << 16) | - (WordSelection[Word2] << 32) | - (WordSelection[Word3] << 48); - - } - return TotalLUT; -}() -}; - -constexpr static auto PSHUFD_LUT { -[]() consteval { - struct LUTType { - uint64_t Val[2]; - }; - // Expectation for this LUT is to simulate PSHUFD with ARM's TBL (single register) instruction - // PSHUFD behaviour: - // 32-bit words in [127:96], [95:64], [63:32], [31:0] are selected using the 8-bit Index. - std::array TotalLUT{}; - uint64_t WordSelection[4] = { - 0x03'02'01'00, - 0x07'06'05'04, - 0x0b'0a'09'08, - 0x0f'0e'0d'0c, - }; - for (size_t i = 0; i < 256; ++i) { - auto &LUT = TotalLUT[i]; - const auto Word0 = (i >> 0) & 0b11; - const auto Word1 = (i >> 2) & 0b11; - const auto Word2 = (i >> 4) & 0b11; - const auto Word3 = (i >> 6) & 0b11; - - LUT.Val[0] = - (WordSelection[Word0] << 0) | - (WordSelection[Word1] << 32); - - LUT.Val[1] = - (WordSelection[Word2] << 0) | - (WordSelection[Word3] << 32); - } - return TotalLUT; -}() -}; - -constexpr static auto SHUFPS_LUT { -[]() consteval { - struct LUTType { - uint64_t Val[2]; - }; - // 32-bit words in [127:96], [95:64], [63:32], [31:0] are selected using the 8-bit Index. - // Expectation for this LUT is to simulate SHUFPS with ARM's TBL (two register) instruction. - // SHUFPS behaviour: - // Two 32-bits words from each source are selected from each source in the lower and upper halves of the 128-bit destination. - // Dest[31:0] = Src1[] - // Dest[63:32] = Src1[] - // Dest[95:64] = Src2[] - // Dest[127:96] = Src2[] - - std::array TotalLUT{}; - const uint64_t WordSelectionSrc1[4] = { - 0x03'02'01'00, - 0x07'06'05'04, - 0x0b'0a'09'08, - 0x0f'0e'0d'0c, + constexpr static uint64_t NamedVectorConstants[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX][2] = { + {0x0003'0002'0001'0000ULL, 0x0007'0006'0005'0004ULL}, // NAMED_VECTOR_INCREMENTAL_U16_INDEX + {0x000B'000A'0009'0008ULL, 0x000F'000E'000D'000CULL}, // NAMED_VECTOR_INCREMENTAL_U16_INDEX_UPPER + {0x0000'0000'8000'0000ULL, 0x0000'0000'8000'0000ULL}, // NAMED_VECTOR_PADDSUBPS_INVERT + {0x0000'0000'8000'0000ULL, 0x0000'0000'8000'0000ULL}, // NAMED_VECTOR_PADDSUBPS_INVERT_UPPER + {0x8000'0000'0000'0000ULL, 0x0000'0000'0000'0000ULL}, // NAMED_VECTOR_PADDSUBPD_INVERT + {0x8000'0000'0000'0000ULL, 0x0000'0000'0000'0000ULL}, // NAMED_VECTOR_PADDSUBPD_INVERT_UPPER + {0x0000'0001'0000'0000ULL, 0x0000'0003'0000'0002ULL}, // NAMED_VECTOR_MOVMSKPS_SHIFT + {0x040B'0E01'0B0E'0104ULL, 0x0C03'0609'0306'090CULL}, // NAMED_VECTOR_AESKEYGENASSIST_SWIZZLE + {0x0706'0504'FFFF'FFFFULL, 0xFFFF'FFFF'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_0110B + {0x0706'0504'0302'0100ULL, 0xFFFF'FFFF'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_0111B + {0xFFFF'FFFF'0302'0100ULL, 0x0F0E'0D0C'FFFF'FFFFULL}, // NAMED_VECTOR_BLENDPS_1001B + {0x0706'0504'0302'0100ULL, 0x0F0E'0D0C'FFFF'FFFFULL}, // NAMED_VECTOR_BLENDPS_1011B + {0xFFFF'FFFF'0302'0100ULL, 0x0F0E'0D0C'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_1101B + {0x0706'0504'FFFF'FFFFULL, 0x0F0E'0D0C'0B0A'0908ULL}, // NAMED_VECTOR_BLENDPS_1110B + {0x8040'2010'0804'0201ULL, 0x8040'2010'0804'0201ULL}, // NAMED_VECTOR_MOVMASKB + {0x8040'2010'0804'0201ULL, 0x8040'2010'0804'0201ULL}, // NAMED_VECTOR_MOVMASKB_UPPER + {0x8000'0000'0000'0000ULL, 0x0000'0000'0000'3FFFULL}, // NAMED_VECTOR_X87_ONE + {0xD49A'784B'CD1B'8AFEULL, 0x0000'0000'0000'4000ULL}, // NAMED_VECTOR_X87_LOG2_10 + {0xB8AA'3B29'5C17'F0BCULL, 0x0000'0000'0000'3FFFULL}, // NAMED_VECTOR_X87_LOG2_E + {0xC90F'DAA2'2168'C235ULL, 0x0000'0000'0000'4000ULL}, // NAMED_VECTOR_X87_PI + {0x9A20'9A84'FBCF'F799ULL, 0x0000'0000'0000'3FFDULL}, // NAMED_VECTOR_X87_LOG10_2 + {0xB172'17F7'D1CF'79ACULL, 0x0000'0000'0000'3FFEULL}, // NAMED_VECTOR_X87_LOG_2 }; - // Src2 needs to offset each byte index by 16-bytes to pull from the second source. - const uint64_t WordSelectionSrc2[4] = { - 0x03'02'01'00 + (0x10101010), - 0x07'06'05'04 + (0x10101010), - 0x0b'0a'09'08 + (0x10101010), - 0x0f'0e'0d'0c + (0x10101010), - }; - - for (size_t i = 0; i < 256; ++i) { - auto &LUT = TotalLUT[i]; - const auto Word0 = (i >> 0) & 0b11; - const auto Word1 = (i >> 2) & 0b11; - const auto Word2 = (i >> 4) & 0b11; - const auto Word3 = (i >> 6) & 0b11; - - LUT.Val[0] = - (WordSelectionSrc1[Word0] << 0) | - (WordSelectionSrc1[Word1] << 32); - - LUT.Val[1] = - (WordSelectionSrc2[Word2] << 0) | - (WordSelectionSrc2[Word3] << 32); - } - return TotalLUT; -}() -}; - -constexpr static auto DPPS_MASK { -[]() consteval { - struct LUTType { - uint32_t Val[4]; - }; - - std::array TotalLUT{}; - for (size_t i = 0; i < TotalLUT.size(); ++i) { - auto &LUT = TotalLUT[i]; - constexpr auto GetLUT = [](size_t i, size_t Index) { - if (i & (1U << Index)) { - return -1U; - } - return 0U; + constexpr static auto PSHUFLW_LUT {[]() consteval { + struct LUTType { + uint64_t Val[2]; }; - - LUT.Val[0] = GetLUT(i, 0); - LUT.Val[1] = GetLUT(i, 1); - LUT.Val[2] = GetLUT(i, 2); - LUT.Val[3] = GetLUT(i, 3); - } - return TotalLUT; -}() -}; - -constexpr static auto DPPD_MASK { -[]() consteval { - struct LUTType { - uint64_t Val[2]; - }; - - std::array TotalLUT{}; - for (size_t i = 0; i < TotalLUT.size(); ++i) { - auto &LUT = TotalLUT[i]; - constexpr auto GetLUT = [](size_t i, size_t Index) { - if (i & (1U << Index)) { - return -1ULL; - } - return 0ULL; + // Expectation for this LUT is to simulate PSHUFLW with ARM's TBL (single register) instruction + // PSHUFLW behaviour: + // 16-bit words in [63:48], [47:32], [31:16], [15:0] are selected using the 8-bit Index. + // For 128-bit PSHUFLW, bits [127:64] are identity copied. + constexpr uint64_t IdentityCopyUpper = 0x0f'0e'0d'0c'0b'0a'09'08; + std::array TotalLUT {}; + uint64_t WordSelection[4] = { + 0x01'00, + 0x03'02, + 0x05'04, + 0x07'06, }; + for (size_t i = 0; i < 256; ++i) { + auto& LUT = TotalLUT[i]; + const auto Word0 = (i >> 0) & 0b11; + const auto Word1 = (i >> 2) & 0b11; + const auto Word2 = (i >> 4) & 0b11; + const auto Word3 = (i >> 6) & 0b11; - LUT.Val[0] = GetLUT(i, 0); - LUT.Val[1] = GetLUT(i, 1); - } - return TotalLUT; -}() -}; + LUT.Val[0] = (WordSelection[Word0] << 0) | (WordSelection[Word1] << 16) | (WordSelection[Word2] << 32) | (WordSelection[Word3] << 48); -constexpr static auto PBLENDW_LUT { -[]() consteval { - struct LUTType { - uint16_t Val[8]; - }; - // 16-bit words in [127:112], [111:96], [95:80], [79:64], [63:48], [47:32], [31:16], [15:0] are selected using 8-bit swizzle. - // Expectation for this LUT is to simulate PBLENDW with ARM's TBX (one register) instruction. - // PBLENDW behaviour: - // 16-bit words from the source is moved in to the destination based on the bit in the swizzle. - // Dest[15:0] = Swizzle[0] ? Src[15:0] : Dest[15:0] - // Dest[31:16] = Swizzle[1] ? Src[31:16] : Dest[31:16] - // Dest[47:32] = Swizzle[2] ? Src[47:32] : Dest[47:32] - // Dest[63:48] = Swizzle[3] ? Src[63:48] : Dest[63:48] - // Dest[79:64] = Swizzle[4] ? Src[79:64] : Dest[79:64] - // Dest[95:80] = Swizzle[5] ? Src[95:80] : Dest[95:80] - // Dest[111:96] = Swizzle[6] ? Src[111:96] : Dest[111:96] - // Dest[127:112] = Swizzle[7] ? Src[127:112] : Dest[127:112] - - std::array TotalLUT{}; - const uint16_t WordSelectionSrc[8] = { - 0x01'00, - 0x03'02, - 0x05'04, - 0x07'06, - 0x09'08, - 0x0B'0A, - 0x0D'0C, - 0x0F'0E, - }; - - constexpr uint16_t OriginalDest = 0xFF'FF; - - for (size_t i = 0; i < 256; ++i) { - auto &LUT = TotalLUT[i]; - for (size_t j = 0; j < 8; ++j) { - LUT.Val[j] = ((i >> j) & 1) ? WordSelectionSrc[j] : OriginalDest; + LUT.Val[1] = IdentityCopyUpper; } - } - return TotalLUT; -}() -}; + return TotalLUT; + }()}; -CPUBackend::CPUBackend(FEXCore::Core::InternalThreadState *ThreadState, size_t InitialCodeSize, size_t MaxCodeSize) - : ThreadState(ThreadState), InitialCodeSize(InitialCodeSize), MaxCodeSize(MaxCodeSize) { + constexpr static auto PSHUFHW_LUT {[]() consteval { + struct LUTType { + uint64_t Val[2]; + }; + // Expectation for this LUT is to simulate PSHUFHW with ARM's TBL (single register) instruction + // PSHUFHW behaviour: + // 16-bit words in [127:112], [111:96], [95:80], [79:64] are selected using the 8-bit Index. + // Incoming words come from bits [127:64] of the source. + // Bits [63:0] are identity copied. + constexpr uint64_t IdentityCopyLower = 0x07'06'05'04'03'02'01'00; + std::array TotalLUT {}; + uint64_t WordSelection[4] = { + 0x09'08, + 0x0b'0a, + 0x0d'0c, + 0x0f'0e, + }; + for (size_t i = 0; i < 256; ++i) { + auto& LUT = TotalLUT[i]; + const auto Word0 = (i >> 0) & 0b11; + const auto Word1 = (i >> 2) & 0b11; + const auto Word2 = (i >> 4) & 0b11; + const auto Word3 = (i >> 6) & 0b11; - auto &Common = ThreadState->CurrentFrame->Pointers.Common; + LUT.Val[0] = IdentityCopyLower; - // Initialize named vector constants. - for (size_t i = 0; i < FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX; ++i) { - Common.NamedVectorConstantPointers[i] = reinterpret_cast(NamedVectorConstants[i]); - } + LUT.Val[1] = (WordSelection[Word0] << 0) | (WordSelection[Word1] << 16) | (WordSelection[Word2] << 32) | (WordSelection[Word3] << 48); + } + return TotalLUT; + }()}; - // Copy named vector constants. - memcpy(Common.NamedVectorConstants, NamedVectorConstants, sizeof(NamedVectorConstants)); + constexpr static auto PSHUFD_LUT {[]() consteval { + struct LUTType { + uint64_t Val[2]; + }; + // Expectation for this LUT is to simulate PSHUFD with ARM's TBL (single register) instruction + // PSHUFD behaviour: + // 32-bit words in [127:96], [95:64], [63:32], [31:0] are selected using the 8-bit Index. + std::array TotalLUT {}; + uint64_t WordSelection[4] = { + 0x03'02'01'00, + 0x07'06'05'04, + 0x0b'0a'09'08, + 0x0f'0e'0d'0c, + }; + for (size_t i = 0; i < 256; ++i) { + auto& LUT = TotalLUT[i]; + const auto Word0 = (i >> 0) & 0b11; + const auto Word1 = (i >> 2) & 0b11; + const auto Word2 = (i >> 4) & 0b11; + const auto Word3 = (i >> 6) & 0b11; - // Initialize Indexed named vector constants. - Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFLW] = reinterpret_cast(PSHUFLW_LUT.data()); - Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFHW] = reinterpret_cast(PSHUFHW_LUT.data()); - Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD] = reinterpret_cast(PSHUFD_LUT.data()); - Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_SHUFPS] = reinterpret_cast(SHUFPS_LUT.data()); - Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_DPPS_MASK] = reinterpret_cast(DPPS_MASK.data()); - Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_DPPD_MASK] = reinterpret_cast(DPPD_MASK.data()); - Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PBLENDW] = reinterpret_cast(PBLENDW_LUT.data()); + LUT.Val[0] = (WordSelection[Word0] << 0) | (WordSelection[Word1] << 32); + + LUT.Val[1] = (WordSelection[Word2] << 0) | (WordSelection[Word3] << 32); + } + return TotalLUT; + }()}; + + constexpr static auto SHUFPS_LUT {[]() consteval { + struct LUTType { + uint64_t Val[2]; + }; + // 32-bit words in [127:96], [95:64], [63:32], [31:0] are selected using the 8-bit Index. + // Expectation for this LUT is to simulate SHUFPS with ARM's TBL (two register) instruction. + // SHUFPS behaviour: + // Two 32-bits words from each source are selected from each source in the lower and upper halves of the 128-bit destination. + // Dest[31:0] = Src1[] + // Dest[63:32] = Src1[] + // Dest[95:64] = Src2[] + // Dest[127:96] = Src2[] + + std::array TotalLUT {}; + const uint64_t WordSelectionSrc1[4] = { + 0x03'02'01'00, + 0x07'06'05'04, + 0x0b'0a'09'08, + 0x0f'0e'0d'0c, + }; + + // Src2 needs to offset each byte index by 16-bytes to pull from the second source. + const uint64_t WordSelectionSrc2[4] = { + 0x03'02'01'00 + (0x10101010), + 0x07'06'05'04 + (0x10101010), + 0x0b'0a'09'08 + (0x10101010), + 0x0f'0e'0d'0c + (0x10101010), + }; + + for (size_t i = 0; i < 256; ++i) { + auto& LUT = TotalLUT[i]; + const auto Word0 = (i >> 0) & 0b11; + const auto Word1 = (i >> 2) & 0b11; + const auto Word2 = (i >> 4) & 0b11; + const auto Word3 = (i >> 6) & 0b11; + + LUT.Val[0] = (WordSelectionSrc1[Word0] << 0) | (WordSelectionSrc1[Word1] << 32); + + LUT.Val[1] = (WordSelectionSrc2[Word2] << 0) | (WordSelectionSrc2[Word3] << 32); + } + return TotalLUT; + }()}; + + constexpr static auto DPPS_MASK {[]() consteval { + struct LUTType { + uint32_t Val[4]; + }; + + std::array TotalLUT {}; + for (size_t i = 0; i < TotalLUT.size(); ++i) { + auto& LUT = TotalLUT[i]; + constexpr auto GetLUT = [](size_t i, size_t Index) { + if (i & (1U << Index)) { + return -1U; + } + return 0U; + }; + + LUT.Val[0] = GetLUT(i, 0); + LUT.Val[1] = GetLUT(i, 1); + LUT.Val[2] = GetLUT(i, 2); + LUT.Val[3] = GetLUT(i, 3); + } + return TotalLUT; + }()}; + + constexpr static auto DPPD_MASK {[]() consteval { + struct LUTType { + uint64_t Val[2]; + }; + + std::array TotalLUT {}; + for (size_t i = 0; i < TotalLUT.size(); ++i) { + auto& LUT = TotalLUT[i]; + constexpr auto GetLUT = [](size_t i, size_t Index) { + if (i & (1U << Index)) { + return -1ULL; + } + return 0ULL; + }; + + LUT.Val[0] = GetLUT(i, 0); + LUT.Val[1] = GetLUT(i, 1); + } + return TotalLUT; + }()}; + + constexpr static auto PBLENDW_LUT {[]() consteval { + struct LUTType { + uint16_t Val[8]; + }; + // 16-bit words in [127:112], [111:96], [95:80], [79:64], [63:48], [47:32], [31:16], [15:0] are selected using 8-bit swizzle. + // Expectation for this LUT is to simulate PBLENDW with ARM's TBX (one register) instruction. + // PBLENDW behaviour: + // 16-bit words from the source is moved in to the destination based on the bit in the swizzle. + // Dest[15:0] = Swizzle[0] ? Src[15:0] : Dest[15:0] + // Dest[31:16] = Swizzle[1] ? Src[31:16] : Dest[31:16] + // Dest[47:32] = Swizzle[2] ? Src[47:32] : Dest[47:32] + // Dest[63:48] = Swizzle[3] ? Src[63:48] : Dest[63:48] + // Dest[79:64] = Swizzle[4] ? Src[79:64] : Dest[79:64] + // Dest[95:80] = Swizzle[5] ? Src[95:80] : Dest[95:80] + // Dest[111:96] = Swizzle[6] ? Src[111:96] : Dest[111:96] + // Dest[127:112] = Swizzle[7] ? Src[127:112] : Dest[127:112] + + std::array TotalLUT {}; + const uint16_t WordSelectionSrc[8] = { + 0x01'00, 0x03'02, 0x05'04, 0x07'06, 0x09'08, 0x0B'0A, 0x0D'0C, 0x0F'0E, + }; + + constexpr uint16_t OriginalDest = 0xFF'FF; + + for (size_t i = 0; i < 256; ++i) { + auto& LUT = TotalLUT[i]; + for (size_t j = 0; j < 8; ++j) { + LUT.Val[j] = ((i >> j) & 1) ? WordSelectionSrc[j] : OriginalDest; + } + } + return TotalLUT; + }()}; + + CPUBackend::CPUBackend(FEXCore::Core::InternalThreadState* ThreadState, size_t InitialCodeSize, size_t MaxCodeSize) + : ThreadState(ThreadState) + , InitialCodeSize(InitialCodeSize) + , MaxCodeSize(MaxCodeSize) { + + auto& Common = ThreadState->CurrentFrame->Pointers.Common; + + // Initialize named vector constants. + for (size_t i = 0; i < FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX; ++i) { + Common.NamedVectorConstantPointers[i] = reinterpret_cast(NamedVectorConstants[i]); + } + + // Copy named vector constants. + memcpy(Common.NamedVectorConstants, NamedVectorConstants, sizeof(NamedVectorConstants)); + + // Initialize Indexed named vector constants. + Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFLW] = + reinterpret_cast(PSHUFLW_LUT.data()); + Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFHW] = + reinterpret_cast(PSHUFHW_LUT.data()); + Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD] = + reinterpret_cast(PSHUFD_LUT.data()); + Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_SHUFPS] = + reinterpret_cast(SHUFPS_LUT.data()); + Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_DPPS_MASK] = + reinterpret_cast(DPPS_MASK.data()); + Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_DPPD_MASK] = + reinterpret_cast(DPPD_MASK.data()); + Common.IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PBLENDW] = + reinterpret_cast(PBLENDW_LUT.data()); #ifndef FEX_DISABLE_TELEMETRY - // Fill in telemetry values - for (size_t i = 0; i < FEXCore::Telemetry::TYPE_LAST; ++i) { - auto &Telem = FEXCore::Telemetry::GetTelemetryValue(static_cast(i)); - Common.TelemetryValueAddresses[i] = reinterpret_cast(Telem.GetAddr()); - } + // Fill in telemetry values + for (size_t i = 0; i < FEXCore::Telemetry::TYPE_LAST; ++i) { + auto& Telem = FEXCore::Telemetry::GetTelemetryValue(static_cast(i)); + Common.TelemetryValueAddresses[i] = reinterpret_cast(Telem.GetAddr()); + } #endif -} - -CPUBackend::~CPUBackend() { - for (auto CodeBuffer : CodeBuffers) { - FreeCodeBuffer(CodeBuffer); } - CodeBuffers.clear(); -} -auto CPUBackend::GetEmptyCodeBuffer() -> CodeBuffer * { - if (ThreadState->CurrentFrame->SignalHandlerRefCounter == 0) { - if (CodeBuffers.empty()) { + CPUBackend::~CPUBackend() { + for (auto CodeBuffer : CodeBuffers) { + FreeCodeBuffer(CodeBuffer); + } + CodeBuffers.clear(); + } + + auto CPUBackend::GetEmptyCodeBuffer() -> CodeBuffer* { + if (ThreadState->CurrentFrame->SignalHandlerRefCounter == 0) { + if (CodeBuffers.empty()) { + auto NewCodeBuffer = AllocateNewCodeBuffer(InitialCodeSize); + EmplaceNewCodeBuffer(NewCodeBuffer); + } else { + if (CodeBuffers.size() > 1) { + // If we have more than one code buffer we are tracking then walk them and delete + // This is a cleanup step + for (size_t i = 1; i < CodeBuffers.size(); i++) { + FreeCodeBuffer(CodeBuffers[i]); + } + CodeBuffers.resize(1); + } + // Set the current code buffer to the initial + CurrentCodeBuffer = &CodeBuffers[0]; + + if (CurrentCodeBuffer->Size != MaxCodeSize) { + FreeCodeBuffer(*CurrentCodeBuffer); + + // Resize the code buffer and reallocate our code size + CurrentCodeBuffer->Size *= 1.5; + CurrentCodeBuffer->Size = std::min(CurrentCodeBuffer->Size, MaxCodeSize); + + *CurrentCodeBuffer = AllocateNewCodeBuffer(CurrentCodeBuffer->Size); + } + } + } else { + // We have signal handlers that have generated code + // This means that we can not safely clear the code at this point in time + // Allocate some new code buffers that we can switch over to instead auto NewCodeBuffer = AllocateNewCodeBuffer(InitialCodeSize); EmplaceNewCodeBuffer(NewCodeBuffer); - } else { - if (CodeBuffers.size() > 1) { - // If we have more than one code buffer we are tracking then walk them and delete - // This is a cleanup step - for (size_t i = 1; i < CodeBuffers.size(); i++) { - FreeCodeBuffer(CodeBuffers[i]); - } - CodeBuffers.resize(1); - } - // Set the current code buffer to the initial - CurrentCodeBuffer = &CodeBuffers[0]; - - if (CurrentCodeBuffer->Size != MaxCodeSize) { - FreeCodeBuffer(*CurrentCodeBuffer); - - // Resize the code buffer and reallocate our code size - CurrentCodeBuffer->Size *= 1.5; - CurrentCodeBuffer->Size = std::min(CurrentCodeBuffer->Size, MaxCodeSize); - - *CurrentCodeBuffer = AllocateNewCodeBuffer(CurrentCodeBuffer->Size); - } } - } else { - // We have signal handlers that have generated code - // This means that we can not safely clear the code at this point in time - // Allocate some new code buffers that we can switch over to instead - auto NewCodeBuffer = AllocateNewCodeBuffer(InitialCodeSize); - EmplaceNewCodeBuffer(NewCodeBuffer); + + return CurrentCodeBuffer; } - return CurrentCodeBuffer; -} - -auto CPUBackend::AllocateNewCodeBuffer(size_t Size) -> CodeBuffer { + auto CPUBackend::AllocateNewCodeBuffer(size_t Size) -> CodeBuffer { #ifndef _WIN32 // MDWE (Memory-Deny-Write-Execute) is a new Linux 6.3 feature. // It's equivalent to systemd's `MemoryDenyWriteExecute` but implemented entirely in the kernel. @@ -380,40 +351,39 @@ auto CPUBackend::AllocateNewCodeBuffer(size_t Size) -> CodeBuffer { #ifndef PR_GET_MDWE #define PR_GET_MDWE 66 #endif - int MDWE = ::prctl(PR_GET_MDWE, 0, 0, 0, 0); - if (MDWE != -1 && MDWE != 0) { - LogMan::Msg::EFmt("MDWE was set to 0x{:x} which means FEX can't allocate executable memory", MDWE); - } + int MDWE = ::prctl(PR_GET_MDWE, 0, 0, 0, 0); + if (MDWE != -1 && MDWE != 0) { + LogMan::Msg::EFmt("MDWE was set to 0x{:x} which means FEX can't allocate executable memory", MDWE); + } #endif - CodeBuffer Buffer; - Buffer.Size = Size; - Buffer.Ptr = static_cast( - FEXCore::Allocator::VirtualAlloc(Buffer.Size, true)); - LOGMAN_THROW_AA_FMT(!!Buffer.Ptr, "Couldn't allocate code buffer"); + CodeBuffer Buffer; + Buffer.Size = Size; + Buffer.Ptr = static_cast(FEXCore::Allocator::VirtualAlloc(Buffer.Size, true)); + LOGMAN_THROW_AA_FMT(!!Buffer.Ptr, "Couldn't allocate code buffer"); - if (static_cast(ThreadState->CTX)->Config.GlobalJITNaming()) { - static_cast(ThreadState->CTX)->Symbols.RegisterJITSpace(Buffer.Ptr, Buffer.Size); - } - return Buffer; -} - -void CPUBackend::FreeCodeBuffer(CodeBuffer Buffer) { - FEXCore::Allocator::VirtualFree(Buffer.Ptr, Buffer.Size); -} - -bool CPUBackend::IsAddressInCodeBuffer(uintptr_t Address) const { - for (auto &Buffer: CodeBuffers) { - auto start = (uintptr_t)Buffer.Ptr; - auto end = start + Buffer.Size; - - if (Address >= start && Address < end) { - return true; + if (static_cast(ThreadState->CTX)->Config.GlobalJITNaming()) { + static_cast(ThreadState->CTX)->Symbols.RegisterJITSpace(Buffer.Ptr, Buffer.Size); } + return Buffer; } - return false; -} + void CPUBackend::FreeCodeBuffer(CodeBuffer Buffer) { + FEXCore::Allocator::VirtualFree(Buffer.Ptr, Buffer.Size); + } -} -} + bool CPUBackend::IsAddressInCodeBuffer(uintptr_t Address) const { + for (auto& Buffer : CodeBuffers) { + auto start = (uintptr_t)Buffer.Ptr; + auto end = start + Buffer.Size; + + if (Address >= start && Address < end) { + return true; + } + } + + return false; + } + +} // namespace CPU +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/CPUBackend.h b/FEXCore/Source/Interface/Core/CPUBackend.h index dd34561cf..1711ac656 100644 --- a/FEXCore/Source/Interface/Core/CPUBackend.h +++ b/FEXCore/Source/Interface/Core/CPUBackend.h @@ -20,14 +20,14 @@ namespace FEXCore { namespace IR { class IRListView; class RegisterAllocationData; -} +} // namespace IR namespace Core { struct DebugData; struct ThreadState; struct CpuStateFrame; struct InternalThreadState; -} +} // namespace Core namespace CodeSerialize { struct CodeObjectFileSection; @@ -43,21 +43,22 @@ namespace CPU { class CPUBackend { public: struct CodeBuffer { - uint8_t *Ptr; + uint8_t* Ptr; size_t Size; }; /** * @param InitialCodeSize - Initial size for the code buffers * @param MaxCodeSize - Max size for the code buffers - */ - CPUBackend(FEXCore::Core::InternalThreadState *ThreadState, size_t InitialCodeSize, size_t MaxCodeSize); + */ + CPUBackend(FEXCore::Core::InternalThreadState* ThreadState, size_t InitialCodeSize, size_t MaxCodeSize); virtual ~CPUBackend(); /** * @return The name of this backend */ - [[nodiscard]] virtual fextl::string GetName() = 0; + [[nodiscard]] + virtual fextl::string GetName() = 0; struct CompiledCode { // Where this code block begins. @@ -137,10 +138,9 @@ namespace CPU { * * @return Information about the compiled code block. */ - [[nodiscard]] virtual CompiledCode CompileCode(uint64_t Entry, - FEXCore::IR::IRListView const *IR, - FEXCore::Core::DebugData *DebugData, - FEXCore::IR::RegisterAllocationData *RAData) = 0; + [[nodiscard]] + virtual CompiledCode CompileCode(uint64_t Entry, const FEXCore::IR::IRListView* IR, FEXCore::Core::DebugData* DebugData, + FEXCore::IR::RegisterAllocationData* RAData) = 0; /** * @brief Relocates a block of code from the JIT code object cache @@ -150,14 +150,18 @@ namespace CPU { * * @return An executable function pointer relocated from the cache object */ - [[nodiscard]] virtual void *RelocateJITObjectCode(uint64_t Entry, CodeSerialize::CodeObjectFileSection const *SerializationData) { return nullptr; } + [[nodiscard]] + virtual void* RelocateJITObjectCode(uint64_t Entry, const CodeSerialize::CodeObjectFileSection* SerializationData) { + return nullptr; + } /** * @brief Function for mapping memory in to the CPUBackend's visible space. Allows setting up virtual mappings if required * * @return Currently unused */ - [[nodiscard]] virtual void *MapRegion(void *HostPtr, uint64_t GuestPtr, uint64_t Size) = 0; + [[nodiscard]] + virtual void* MapRegion(void* HostPtr, uint64_t GuestPtr, uint64_t Size) = 0; /** * @brief Lets FEXCore know if this CPUBackend needs IR and DebugData for CompileCode @@ -168,7 +172,8 @@ namespace CPU { * * @return true if it needs the IR */ - [[nodiscard]] virtual bool NeedsOpDispatch() = 0; + [[nodiscard]] + virtual bool NeedsOpDispatch() = 0; virtual void ClearCache() {} @@ -184,13 +189,14 @@ namespace CPU { // to be able to handle a 256-bit vector store to a slot. constexpr static uint32_t MaxSpillSlotSize = 32; - FEXCore::Core::InternalThreadState *ThreadState; + FEXCore::Core::InternalThreadState* ThreadState; size_t InitialCodeSize, MaxCodeSize; - [[nodiscard]] CodeBuffer *GetEmptyCodeBuffer(); + [[nodiscard]] + CodeBuffer* GetEmptyCodeBuffer(); // This is the current code buffer that we are tracking - CodeBuffer *CurrentCodeBuffer{}; + CodeBuffer* CurrentCodeBuffer {}; private: CodeBuffer AllocateNewCodeBuffer(size_t Size); @@ -202,8 +208,8 @@ namespace CPU { // This is the array of code buffers. Unless signals force us to keep more than // buffer, there will be only one entry here - fextl::vector CodeBuffers{}; + fextl::vector CodeBuffers {}; }; -} -} +} // namespace CPU +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/CPUID.cpp b/FEXCore/Source/Interface/Core/CPUID.cpp index 50315f1cd..dcc5c9001 100644 --- a/FEXCore/Source/Interface/Core/CPUID.cpp +++ b/FEXCore/Source/Interface/Core/CPUID.cpp @@ -71,53 +71,50 @@ namespace ProductNames { static const char ARM_Icestorm[] = "Apple Icestorm"; #else #endif -} +} // namespace ProductNames static uint32_t GetCPUID() { - uint32_t CPU{}; + uint32_t CPU {}; FHU::Syscalls::getcpu(&CPU, nullptr); return CPU; } #ifdef CPUID_AMD -constexpr uint32_t FAMILY_IDENTIFIER = - 0 | // Stepping - (0xA << 4) | // Model - (0xF << 8) | // Family ID - (0 << 12) | // Processor type - (0 << 16) | // Extended model ID - (1 << 20); // Extended family ID +constexpr uint32_t FAMILY_IDENTIFIER = 0 | // Stepping + (0xA << 4) | // Model + (0xF << 8) | // Family ID + (0 << 12) | // Processor type + (0 << 16) | // Extended model ID + (1 << 20); // Extended family ID #else -constexpr uint32_t FAMILY_IDENTIFIER = - 0 | // Stepping - (0x7 << 4) | // Model - (0x6 << 8) | // Family ID - (0 << 12) | // Processor type - (1 << 16) | // Extended model ID - (0x0 << 20); // Extended family ID +constexpr uint32_t FAMILY_IDENTIFIER = 0 | // Stepping + (0x7 << 4) | // Model + (0x6 << 8) | // Family ID + (0 << 12) | // Processor type + (1 << 16) | // Extended model ID + (0x0 << 20); // Extended family ID #endif #ifdef _M_ARM_64 uint32_t GetCycleCounterFrequency() { - uint64_t Result{}; - __asm("mrs %[Res], CNTFRQ_EL0" - : [Res] "=r" (Result)); + uint64_t Result {}; + __asm("mrs %[Res], CNTFRQ_EL0" : [Res] "=r"(Result)); return Result; } void CPUIDEmu::SetupHostHybridFlag() { PerCPUData.resize(Cores); - uint64_t MIDR{}; + uint64_t MIDR {}; for (size_t i = 0; i < Cores; ++i) { - std::error_code ec{}; + std::error_code ec {}; fextl::string MIDRPath = fextl::fmt::format("/sys/devices/system/cpu/cpu{}/regs/identification/midr_el1", i); std::array Data; // Needs to be a fixed size since depending on kernel it will try to read a full page of data and fail // Only read 18 bytes for a 64bit value prefixed with 0x if (FEXCore::FileLoading::LoadFileToBuffer(MIDRPath, Data) == sizeof(Data)) { - uint64_t NewMIDR{}; + uint64_t NewMIDR {}; std::string_view MIDRView(Data.data(), sizeof(Data)); if (FEXCore::StrConv::Conv(MIDRView, &NewMIDR)) { if (MIDR != 0 && MIDR != NewMIDR) { @@ -137,7 +134,7 @@ void CPUIDEmu::SetupHostHybridFlag() { uint8_t Implementer; uint16_t Part; bool DefaultBig; // Defaults to a big core - const char *ProductName{}; + const char* ProductName {}; }; // CPU priority order @@ -147,32 +144,32 @@ void CPUIDEmu::SetupHostHybridFlag() { // Typically big CPU cores {0x61, 0x023, 1, ProductNames::ARM_Firestorm}, // Apple M1 Firestorm - {0x41, 0xd82, 1, ProductNames::ARM_X4}, // X4 - {0x41, 0xd81, 1, ProductNames::ARM_A720}, // A720 - {0x41, 0xd4e, 1, ProductNames::ARM_X3}, // X3 - {0x41, 0xd4d, 1, ProductNames::ARM_A715}, // A715 - {0x41, 0xd4f, 1, ProductNames::ARM_V2}, // V2 - {0x41, 0xd49, 1, ProductNames::ARM_N2}, // N2 - {0x41, 0xd4b, 1, ProductNames::ARM_A78C}, // A78C - {0x41, 0xd4a, 1, ProductNames::ARM_E1}, // E1 - {0x41, 0xd49, 1, ProductNames::ARM_N2}, // N2 - {0x41, 0xd48, 1, ProductNames::ARM_X2}, // X2 - {0x41, 0xd47, 1, ProductNames::ARM_A710}, // A710 - {0x41, 0xd4C, 1, ProductNames::ARM_X1C}, // X1C - {0x41, 0xd44, 1, ProductNames::ARM_X1}, // X1 - {0x41, 0xd42, 1, ProductNames::ARM_A78AE}, // A78AE - {0x41, 0xd41, 1, ProductNames::ARM_A78}, // A78 - {0x41, 0xd40, 1, ProductNames::ARM_V1}, // V1 - {0x41, 0xd0e, 1, ProductNames::ARM_A76AE}, // A76AE - {0x41, 0xd0d, 1, ProductNames::ARM_A77}, // A77 - {0x41, 0xd0c, 1, ProductNames::ARM_N1}, // N1 - {0x41, 0xd0b, 1, ProductNames::ARM_A76}, // A76 + {0x41, 0xd82, 1, ProductNames::ARM_X4}, // X4 + {0x41, 0xd81, 1, ProductNames::ARM_A720}, // A720 + {0x41, 0xd4e, 1, ProductNames::ARM_X3}, // X3 + {0x41, 0xd4d, 1, ProductNames::ARM_A715}, // A715 + {0x41, 0xd4f, 1, ProductNames::ARM_V2}, // V2 + {0x41, 0xd49, 1, ProductNames::ARM_N2}, // N2 + {0x41, 0xd4b, 1, ProductNames::ARM_A78C}, // A78C + {0x41, 0xd4a, 1, ProductNames::ARM_E1}, // E1 + {0x41, 0xd49, 1, ProductNames::ARM_N2}, // N2 + {0x41, 0xd48, 1, ProductNames::ARM_X2}, // X2 + {0x41, 0xd47, 1, ProductNames::ARM_A710}, // A710 + {0x41, 0xd4C, 1, ProductNames::ARM_X1C}, // X1C + {0x41, 0xd44, 1, ProductNames::ARM_X1}, // X1 + {0x41, 0xd42, 1, ProductNames::ARM_A78AE}, // A78AE + {0x41, 0xd41, 1, ProductNames::ARM_A78}, // A78 + {0x41, 0xd40, 1, ProductNames::ARM_V1}, // V1 + {0x41, 0xd0e, 1, ProductNames::ARM_A76AE}, // A76AE + {0x41, 0xd0d, 1, ProductNames::ARM_A77}, // A77 + {0x41, 0xd0c, 1, ProductNames::ARM_N1}, // N1 + {0x41, 0xd0b, 1, ProductNames::ARM_A76}, // A76 {0x51, 0x804, 1, ProductNames::ARM_Kryo400}, // Kryo 4xx Gold (A76 based) - {0x41, 0xd0a, 1, ProductNames::ARM_A75}, // A75 + {0x41, 0xd0a, 1, ProductNames::ARM_A75}, // A75 {0x51, 0x802, 1, ProductNames::ARM_Kryo300}, // Kryo 3xx Gold (A75 based) - {0x41, 0xd09, 1, ProductNames::ARM_A73}, // A73 + {0x41, 0xd09, 1, ProductNames::ARM_A73}, // A73 {0x51, 0x800, 1, ProductNames::ARM_Kryo200}, // Kryo 2xx Gold (A73 based) - {0x41, 0xd08, 1, ProductNames::ARM_A72}, // A72 + {0x41, 0xd08, 1, ProductNames::ARM_A72}, // A72 {0x4e, 0x004, 1, ProductNames::ARM_Carmel}, // Carmel @@ -183,27 +180,26 @@ void CPUIDEmu::SetupHostHybridFlag() { // Typically Little CPU cores {0x61, 0x022, 0, ProductNames::ARM_Icestorm}, // Apple M1 Icestorm - {0x41, 0xd80, 0, ProductNames::ARM_A520}, // A520 - {0x41, 0xd46, 0, ProductNames::ARM_A510}, // A510 - {0x41, 0xd06, 0, ProductNames::ARM_A65}, // A65 - {0x41, 0xd05, 0, ProductNames::ARM_A55}, // A55 + {0x41, 0xd80, 0, ProductNames::ARM_A520}, // A520 + {0x41, 0xd46, 0, ProductNames::ARM_A510}, // A510 + {0x41, 0xd06, 0, ProductNames::ARM_A65}, // A65 + {0x41, 0xd05, 0, ProductNames::ARM_A55}, // A55 {0x51, 0x805, 0, ProductNames::ARM_Kryo400S}, // Kryo 4xx/5xx Silver (A55 based) {0x51, 0x803, 0, ProductNames::ARM_Kryo300S}, // Kryo 3xx Silver (A55 based) - {0x41, 0xd03, 0, ProductNames::ARM_A53}, // A53 + {0x41, 0xd03, 0, ProductNames::ARM_A53}, // A53 {0x51, 0x801, 0, ProductNames::ARM_Kryo200S}, // Kryo 2xx Silver (A53 based) - {0x41, 0xd04, 0, ProductNames::ARM_A35}, // A35 + {0x41, 0xd04, 0, ProductNames::ARM_A35}, // A35 {0x41, 0, 0, ProductNames::ARM_UNKNOWN}, // Invalid CPU or Apple CPU inside Parallels VM - {0x0, 0, 0, ProductNames::ARM_UNKNOWN}, // Invalid starting point is lowest ranked + {0x0, 0, 0, ProductNames::ARM_UNKNOWN}, // Invalid starting point is lowest ranked }}; auto FindDefinedMIDR = [](uint32_t MIDR) -> const CPUMIDR* { uint8_t Implementer = MIDR >> 24; uint16_t Part = (MIDR >> 4) & 0xFFF; - for (auto &MIDROption : CPUMIDRs) { - if (MIDROption.Implementer == Implementer && - MIDROption.Part == Part) { + for (auto& MIDROption : CPUMIDRs) { + if (MIDROption.Implementer == Implementer && MIDROption.Part == Part) { return &MIDROption; } } @@ -224,12 +220,10 @@ void CPUIDEmu::SetupHostHybridFlag() { // Found one if (MIDROption->DefaultBig) { BigCores.emplace_back(MIDROption); - } - else { + } else { LittleCores.emplace_back(MIDROption); } - } - else { + } else { // If we didn't insert this MIDR then claim it is a little core. LittleCores.emplace_back(&CPUMIDRs.back()); } @@ -246,11 +240,8 @@ void CPUIDEmu::SetupHostHybridFlag() { // Walk our list of CPUMIDRs to find the most little core for (size_t j = LowestMIDRIdx; j < CPUMIDRs.size(); ++j) { - auto &MIDROption = CPUMIDRs[i]; - if ((MIDROption.Implementer == Implementer && - MIDROption.Part == Part) || - (MIDROption.Implementer == 0 && - MIDROption.Part == 0)) { + auto& MIDROption = CPUMIDRs[i]; + if ((MIDROption.Implementer == Implementer && MIDROption.Part == Part) || (MIDROption.Implementer == 0 && MIDROption.Part == 0)) { LowestMIDRIdx = j; LowestMIDR = MIDR; @@ -261,13 +252,12 @@ void CPUIDEmu::SetupHostHybridFlag() { // Now we WILL have found a big core to demote to little status // Demote them - std::erase_if(BigCores, [&LittleCores, LowestMIDR](auto *Entry) { + std::erase_if(BigCores, [&LittleCores, LowestMIDR](auto* Entry) { // Demote by erase copy to little array uint8_t Implementer = LowestMIDR >> 24; uint16_t Part = (LowestMIDR >> 4) & 0xFFF; - if (Entry->Implementer == Implementer && - Entry->Part == Part) { + if (Entry->Implementer == Implementer && Entry->Part == Part) { // Add it to the BigCore list LittleCores.emplace_back(Entry); return true; @@ -281,13 +271,12 @@ void CPUIDEmu::SetupHostHybridFlag() { // Grab the first core, consider it as little, move everything else to Big uint32_t LittleMIDR = PerCPUData[0].MIDR; // Now walk the little cores and move them to Big if they don't match - std::erase_if(LittleCores, [&BigCores, LittleMIDR](auto *Entry) { + std::erase_if(LittleCores, [&BigCores, LittleMIDR](auto* Entry) { // You're promoted now uint8_t Implementer = LittleMIDR >> 24; uint16_t Part = (LittleMIDR >> 4) & 0xFFF; - if (Entry->Implementer != Implementer || - Entry->Part != Part) { + if (Entry->Implementer != Implementer || Entry->Part != Part) { // Add it to the BigCore list BigCores.emplace_back(Entry); return true; @@ -297,15 +286,14 @@ void CPUIDEmu::SetupHostHybridFlag() { } // Now walk the per CPU data one more time and set if it is big or little - for (auto &Data : PerCPUData) { + for (auto& Data : PerCPUData) { uint8_t Implementer = Data.MIDR >> 24; uint16_t Part = (Data.MIDR >> 4) & 0xFFF; - bool FoundBig{}; - const CPUMIDR *MIDR{}; + bool FoundBig {}; + const CPUMIDR* MIDR {}; for (auto Big : BigCores) { - if (Big->Implementer == Implementer && - Big->Part == Part) { + if (Big->Implementer == Implementer && Big->Part == Part) { FoundBig = true; MIDR = Big; break; @@ -314,8 +302,7 @@ void CPUIDEmu::SetupHostHybridFlag() { if (!FoundBig) { for (auto Little : LittleCores) { - if (Little->Implementer == Implementer && - Little->Part == Part) { + if (Little->Implementer == Implementer && Little->Part == Part) { MIDR = Little; break; } @@ -325,13 +312,11 @@ void CPUIDEmu::SetupHostHybridFlag() { Data.IsBig = FoundBig; if (MIDR) { Data.ProductName = MIDR->ProductName ?: ProductNames::ARM_UNKNOWN; - } - else { + } else { Data.ProductName = ProductNames::ARM_UNKNOWN; } } - } - else { + } else { // If we aren't hybrid then just claim everything is big for (size_t i = 0; i < Cores; ++i) { uint32_t MIDR = PerCPUData[i].MIDR; @@ -340,8 +325,7 @@ void CPUIDEmu::SetupHostHybridFlag() { PerCPUData[i].IsBig = true; if (MIDROption) { PerCPUData[i].ProductName = MIDROption->ProductName ?: ProductNames::ARM_UNKNOWN; - } - else { + } else { PerCPUData[i].ProductName = ProductNames::ARM_UNKNOWN; } } @@ -353,8 +337,7 @@ uint32_t GetCycleCounterFrequency() { return 0; } -void CPUIDEmu::SetupHostHybridFlag() { -} +void CPUIDEmu::SetupHostHybridFlag() {} #endif @@ -373,21 +356,21 @@ void CPUIDEmu::SetupFeatures() { } #define ENABLE_DISABLE_OPTION(FeatureName, name, enum_name) \ - do { \ + do { \ const bool Disable##name = (CPUIDFeatures() & FEXCore::Config::CPUID::DISABLE##enum_name) != 0; \ - const bool Enable##name = (CPUIDFeatures() & FEXCore::Config::CPUID::ENABLE##enum_name) != 0; \ - LogMan::Throw::AFmt(!(Disable##name && Enable##name), "Disabling and Enabling CPU feature (" #name ") is mutually exclusive"); \ - const bool AlreadyEnabled = Features.FeatureName; \ - const bool Result = (AlreadyEnabled | Enable##name) & !Disable##name; \ - Features.FeatureName = Result; \ - } while (0) + const bool Enable##name = (CPUIDFeatures() & FEXCore::Config::CPUID::ENABLE##enum_name) != 0; \ + LogMan::Throw::AFmt(!(Disable##name && Enable##name), "Disabling and Enabling CPU feature (" #name ") is mutually exclusive"); \ + const bool AlreadyEnabled = Features.FeatureName; \ + const bool Result = (AlreadyEnabled | Enable##name) & !Disable##name; \ + Features.FeatureName = Result; \ + } while (0) ENABLE_DISABLE_OPTION(SHA, SHA, SHA); #undef ENABLE_DISABLE_OPTION } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_0h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; // EBX, EDX, ECX become the manufacturer id string #ifdef CPUID_AMD @@ -406,116 +389,106 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_0h(uint32_t Leaf) const { // Processor Info and Features bits FEXCore::CPUID::FunctionResults CPUIDEmu::Function_01h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; // Hypervisor bit is normally set but some applications have issues with it. uint32_t Hypervisor = HideHypervisorBit() ? 0 : 1; Res.eax = FAMILY_IDENTIFIER; - Res.ebx = 0 | // Brand index - (8 << 8) | // Cache line size in bytes - (Cores << 16) | // Number of addressable IDs for the logical cores in the physical CPU - (0 << 24); // Local APIC ID + Res.ebx = 0 | // Brand index + (8 << 8) | // Cache line size in bytes + (Cores << 16) | // Number of addressable IDs for the logical cores in the physical CPU + (0 << 24); // Local APIC ID - Res.ecx = - (1 << 0) | // SSE3 - (CTX->HostFeatures.SupportsPMULL_128Bit << 1) | // PCLMULQDQ - (1 << 2) | // DS area supports 64bit layout - (1 << 3) | // MWait - (0 << 4) | // DS-CPL - (0 << 5) | // VMX - (0 << 6) | // SMX - (0 << 7) | // Intel SpeedStep - (1 << 8) | // Thermal Monitor 2 - (1 << 9) | // SSSE3 - (0 << 10) | // L1 context ID - (0 << 11) | // Silicon debug - (0 << 12) | // FMA3 - (1 << 13) | // CMPXCHG16B - (0 << 14) | // xTPR update control - (0 << 15) | // Perfmon and debug capability - (0 << 16) | // Reserved - (0 << 17) | // Process-context identifiers - (0 << 18) | // Prefetching from memory mapped device - (1 << 19) | // SSE4.1 - (CTX->HostFeatures.SupportsCRC << 20) | // SSE4.2 - (0 << 21) | // X2APIC - (1 << 22) | // MOVBE - (1 << 23) | // POPCNT - (0 << 24) | // APIC TSC-Deadline - (CTX->HostFeatures.SupportsAES << 25) | // AES - (SupportsAVX() << 26) | // XSAVE - (SupportsAVX() << 27) | // OSXSAVE - (SupportsAVX() << 28) | // AVX - (0 << 29) | // F16C - (CTX->HostFeatures.SupportsRAND << 30) | // RDRAND - (Hypervisor << 31); + Res.ecx = (1 << 0) | // SSE3 + (CTX->HostFeatures.SupportsPMULL_128Bit << 1) | // PCLMULQDQ + (1 << 2) | // DS area supports 64bit layout + (1 << 3) | // MWait + (0 << 4) | // DS-CPL + (0 << 5) | // VMX + (0 << 6) | // SMX + (0 << 7) | // Intel SpeedStep + (1 << 8) | // Thermal Monitor 2 + (1 << 9) | // SSSE3 + (0 << 10) | // L1 context ID + (0 << 11) | // Silicon debug + (0 << 12) | // FMA3 + (1 << 13) | // CMPXCHG16B + (0 << 14) | // xTPR update control + (0 << 15) | // Perfmon and debug capability + (0 << 16) | // Reserved + (0 << 17) | // Process-context identifiers + (0 << 18) | // Prefetching from memory mapped device + (1 << 19) | // SSE4.1 + (CTX->HostFeatures.SupportsCRC << 20) | // SSE4.2 + (0 << 21) | // X2APIC + (1 << 22) | // MOVBE + (1 << 23) | // POPCNT + (0 << 24) | // APIC TSC-Deadline + (CTX->HostFeatures.SupportsAES << 25) | // AES + (SupportsAVX() << 26) | // XSAVE + (SupportsAVX() << 27) | // OSXSAVE + (SupportsAVX() << 28) | // AVX + (0 << 29) | // F16C + (CTX->HostFeatures.SupportsRAND << 30) | // RDRAND + (Hypervisor << 31); - Res.edx = - (1 << 0) | // FPU - (1 << 1) | // Virtual 8086 mode enhancements - (0 << 2) | // Debugging extensions - (0 << 3) | // Page size extension - (1 << 4) | // RDTSC supported - (1 << 5) | // MSR supported - (1 << 6) | // PAE - (1 << 7) | // Machine Check exception - (1 << 8) | // CMPXCHG8B - (1 << 9) | // APIC on-chip - (0 << 10) | // Reserved - (1 << 11) | // SYSENTER/SYSEXIT - (1 << 12) | // Memory Type Range registers, MTRRs are supported - (1 << 13) | // Page Global bit - (1 << 14) | // Machine Check architecture - (1 << 15) | // CMOV - (1 << 16) | // Page Attribute Table - (1 << 17) | // 36bit page size extension - (0 << 18) | // Processor serial number - (1 << 19) | // CLFLUSH - (0 << 20) | // Reserved - (0 << 21) | // Debug store - (0 << 22) | // Thermal monitor and software controled clock - (1 << 23) | // MMX - (1 << 24) | // FXSAVE/FXRSTOR - (1 << 25) | // SSE - (1 << 26) | // SSE2 - (0 << 27) | // Self Snoop - (1 << 28) | // Max APIC IDs reserved field is valid - (1 << 29) | // Thermal monitor - (0 << 30) | // Reserved - (0 << 31); // Pending break enable + Res.edx = (1 << 0) | // FPU + (1 << 1) | // Virtual 8086 mode enhancements + (0 << 2) | // Debugging extensions + (0 << 3) | // Page size extension + (1 << 4) | // RDTSC supported + (1 << 5) | // MSR supported + (1 << 6) | // PAE + (1 << 7) | // Machine Check exception + (1 << 8) | // CMPXCHG8B + (1 << 9) | // APIC on-chip + (0 << 10) | // Reserved + (1 << 11) | // SYSENTER/SYSEXIT + (1 << 12) | // Memory Type Range registers, MTRRs are supported + (1 << 13) | // Page Global bit + (1 << 14) | // Machine Check architecture + (1 << 15) | // CMOV + (1 << 16) | // Page Attribute Table + (1 << 17) | // 36bit page size extension + (0 << 18) | // Processor serial number + (1 << 19) | // CLFLUSH + (0 << 20) | // Reserved + (0 << 21) | // Debug store + (0 << 22) | // Thermal monitor and software controled clock + (1 << 23) | // MMX + (1 << 24) | // FXSAVE/FXRSTOR + (1 << 25) | // SSE + (1 << 26) | // SSE2 + (0 << 27) | // Self Snoop + (1 << 28) | // Max APIC IDs reserved field is valid + (1 << 29) | // Thermal monitor + (0 << 30) | // Reserved + (0 << 31); // Pending break enable return Res; } // 2: Cache and TLB information FEXCore::CPUID::FunctionResults CPUIDEmu::Function_02h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; // returns default values from i7 model 1Ah Res.eax = 0x1 | // Number of iterations needed for all descriptors - (0x5A << 8) | - (0x03 << 16) | - (0x55 << 24); + (0x5A << 8) | (0x03 << 16) | (0x55 << 24); - Res.ebx = 0xE4 | - (0xB2 << 8) | - (0xF0 << 16) | - (0 << 24); + Res.ebx = 0xE4 | (0xB2 << 8) | (0xF0 << 16) | (0 << 24); Res.ecx = 0; // null descriptors - Res.edx = 0x2C | - (0x21 << 8) | - (0xCA << 16) | - (0x09 << 24); + Res.edx = 0x2C | (0x21 << 8) | (0xCA << 16) | (0x09 << 24); return Res; } // 4: Deterministic cache parameters for each level FEXCore::CPUID::FunctionResults CPUIDEmu::Function_04h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; constexpr uint32_t CacheType_Data = 1; constexpr uint32_t CacheType_Instruction = 2; constexpr uint32_t CacheType_Unified = 3; @@ -524,111 +497,100 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_04h(uint32_t Leaf) const { // Report L1D uint32_t CoreCount = Cores - 1; - Res.eax = CacheType_Data | // Cache type - (0b001 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (0 << 14) | // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) - (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package + Res.eax = CacheType_Data | // Cache type + (0b001 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (0 << 14) | // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) + (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 32KB Res.ecx = 63; // Number of sets - 1 : Claiming 64 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1) | // Cache inclusiveness - Includes lower caches - (0 << 2); // Complex cache indexing - 0: Direct, 1: Complex - } - else if (Leaf == 1) { + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1) | // Cache inclusiveness - Includes lower caches + (0 << 2); // Complex cache indexing - 0: Direct, 1: Complex + } else if (Leaf == 1) { // Report L1I uint32_t CoreCount = Cores - 1; Res.eax = CacheType_Instruction | // Cache type - (0b001 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (0 << 14) | // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) - (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package + (0b001 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (0 << 14) | // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) + (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 32KB Res.ecx = 63; // Number of sets - 1 : Claiming 64 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1) | // Cache inclusiveness - Includes lower caches - (0 << 2); // Complex cache indexing - 0: Direct, 1: Complex - } - else if (Leaf == 2) { + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1) | // Cache inclusiveness - Includes lower caches + (0 << 2); // Complex cache indexing - 0: Direct, 1: Complex + } else if (Leaf == 2) { // Report L2 uint32_t CoreCount = Cores - 1; Res.eax = CacheType_Unified | // Cache type - (0b010 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (0 << 14) | // Maximum number of addressable IDs for logical processors sharing this cache - (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package + (0b010 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (0 << 14) | // Maximum number of addressable IDs for logical processors sharing this cache + (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 512KB Res.ecx = 0x3FF; // Number of sets - 1 : Claiming 1024 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1) | // Cache inclusiveness - Includes lower caches - (0 << 2); // Complex cache indexing - 0: Direct, 1: Complex - } - else if (Leaf == 3) { + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1) | // Cache inclusiveness - Includes lower caches + (0 << 2); // Complex cache indexing - 0: Direct, 1: Complex + } else if (Leaf == 3) { // Report L3 uint32_t CoreCount = Cores - 1; Res.eax = CacheType_Unified | // Cache type - (0b011 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (CoreCount << 14) | // Maximum number of addressable IDs for logical processors sharing this cache - (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package + (0b011 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (CoreCount << 14) | // Maximum number of addressable IDs for logical processors sharing this cache + (CoreCount << 26); // Maximum number of addressable IDs for processor cores in the physical package - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 8MB Res.ecx = 0x4000; // Number of sets - 1 : Claiming 16384 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1) | // Cache inclusiveness - Includes lower caches - (1 << 2); // Complex cache indexing - 0: Direct, 1: Complex + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1) | // Cache inclusiveness - Includes lower caches + (1 << 2); // Complex cache indexing - 0: Direct, 1: Complex } return Res; } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_06h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; Res.eax = (1 << 2); // Always running APIC Res.ecx = (0 << 3); // Intel performance energy bias preference (EPB) return Res; } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_07h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; if (Leaf == 0) { // Disable Enhanced REP MOVS when TSO is enabled. // vcruntime140 memmove will use `rep movsb` in this case which completely destroys perf in Hades(appId 1145360) @@ -637,107 +599,104 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_07h(uint32_t Leaf) const { // Number of subfunctions Res.eax = 0x0; - Res.ebx = - (1 << 0) | // FS/GS support - (0 << 1) | // TSC adjust MSR - (0 << 2) | // SGX - (SupportsAVX() << 3) | // BMI1 - (0 << 4) | // Intel Hardware Lock Elison - (0 << 5) | // AVX2 support - (1 << 6) | // FPU data pointer updated only on exception - (1 << 7) | // SMEP support - (SupportsAVX() << 8) | // BMI2 - (SupportsEnhancedREPMOVS << 9) | // Enhanced REP MOVSB/STOSB - (1 << 10) | // INVPCID for system software control of process-context - (0 << 11) | // Restricted transactional memory - (0 << 12) | // Intel resource directory technology Monitoring - (1 << 13) | // Deprecates FPU CS and DS - (0 << 14) | // Intel MPX - (0 << 15) | // Intel Resource Directory Technology Allocation - (0 << 16) | // Reserved - (0 << 17) | // Reserved - (CTX->HostFeatures.SupportsRAND << 18) | // RDSEED - (1 << 19) | // ADCX and ADOX instructions - (0 << 20) | // SMAP Supervisor mode access prevention and CLAC/STAC instructions - (0 << 21) | // Reserved - (0 << 22) | // Reserved - (1 << 23) | // CLFLUSHOPT instruction - (CTX->HostFeatures.SupportsCLWB << 24) | // CLWB instruction - (0 << 25) | // Intel processor trace - (0 << 26) | // Reserved - (0 << 27) | // Reserved - (0 << 28) | // Reserved - (Features.SHA << 29) | // SHA instructions - (0 << 30) | // Reserved - (0 << 31); // Reserved + Res.ebx = (1 << 0) | // FS/GS support + (0 << 1) | // TSC adjust MSR + (0 << 2) | // SGX + (SupportsAVX() << 3) | // BMI1 + (0 << 4) | // Intel Hardware Lock Elison + (0 << 5) | // AVX2 support + (1 << 6) | // FPU data pointer updated only on exception + (1 << 7) | // SMEP support + (SupportsAVX() << 8) | // BMI2 + (SupportsEnhancedREPMOVS << 9) | // Enhanced REP MOVSB/STOSB + (1 << 10) | // INVPCID for system software control of process-context + (0 << 11) | // Restricted transactional memory + (0 << 12) | // Intel resource directory technology Monitoring + (1 << 13) | // Deprecates FPU CS and DS + (0 << 14) | // Intel MPX + (0 << 15) | // Intel Resource Directory Technology Allocation + (0 << 16) | // Reserved + (0 << 17) | // Reserved + (CTX->HostFeatures.SupportsRAND << 18) | // RDSEED + (1 << 19) | // ADCX and ADOX instructions + (0 << 20) | // SMAP Supervisor mode access prevention and CLAC/STAC instructions + (0 << 21) | // Reserved + (0 << 22) | // Reserved + (1 << 23) | // CLFLUSHOPT instruction + (CTX->HostFeatures.SupportsCLWB << 24) | // CLWB instruction + (0 << 25) | // Intel processor trace + (0 << 26) | // Reserved + (0 << 27) | // Reserved + (0 << 28) | // Reserved + (Features.SHA << 29) | // SHA instructions + (0 << 30) | // Reserved + (0 << 31); // Reserved - Res.ecx = - (1 << 0) | // PREFETCHWT1 - (0 << 1) | // AVX512VBMI - (0 << 2) | // Usermode instruction prevention - (0 << 3) | // Protection keys for user mode pages - (0 << 4) | // OS protection keys - (0 << 5) | // waitpkg - (0 << 6) | // AVX512_VBMI2 - (0 << 7) | // CET shadow stack - (0 << 8) | // GFNI - (0 << 9) | // VAES - (0 << 10) | // VPCLMULQDQ - (0 << 11) | // AVX512_VNNI - (0 << 12) | // AVX512_BITALG - (0 << 13) | // Intel Total Memory Encryption - (0 << 14) | // AVX512_VPOPCNTDQ - (0 << 15) | // Reserved - (0 << 16) | // 5 Level page tables - (0 << 17) | // MPX MAWAU - (0 << 18) | // MPX MAWAU - (0 << 19) | // MPX MAWAU - (0 << 20) | // MPX MAWAU - (0 << 21) | // MPX MAWAU - (1 << 22) | // RDPID Read Processor ID - (0 << 23) | // Reserved - (0 << 24) | // Reserved - (0 << 25) | // CLDEMOTE - (0 << 26) | // Reserved - (0 << 27) | // MOVDIRI - (0 << 28) | // MOVDIR64B - (0 << 29) | // Reserved - (0 << 30) | // SGX Launch configuration - (0 << 31); // Reserved + Res.ecx = (1 << 0) | // PREFETCHWT1 + (0 << 1) | // AVX512VBMI + (0 << 2) | // Usermode instruction prevention + (0 << 3) | // Protection keys for user mode pages + (0 << 4) | // OS protection keys + (0 << 5) | // waitpkg + (0 << 6) | // AVX512_VBMI2 + (0 << 7) | // CET shadow stack + (0 << 8) | // GFNI + (0 << 9) | // VAES + (0 << 10) | // VPCLMULQDQ + (0 << 11) | // AVX512_VNNI + (0 << 12) | // AVX512_BITALG + (0 << 13) | // Intel Total Memory Encryption + (0 << 14) | // AVX512_VPOPCNTDQ + (0 << 15) | // Reserved + (0 << 16) | // 5 Level page tables + (0 << 17) | // MPX MAWAU + (0 << 18) | // MPX MAWAU + (0 << 19) | // MPX MAWAU + (0 << 20) | // MPX MAWAU + (0 << 21) | // MPX MAWAU + (1 << 22) | // RDPID Read Processor ID + (0 << 23) | // Reserved + (0 << 24) | // Reserved + (0 << 25) | // CLDEMOTE + (0 << 26) | // Reserved + (0 << 27) | // MOVDIRI + (0 << 28) | // MOVDIR64B + (0 << 29) | // Reserved + (0 << 30) | // SGX Launch configuration + (0 << 31); // Reserved - Res.edx = - (0 << 0) | // Reserved - (0 << 1) | // Reserved - (0 << 2) | // AVX512_4VNNIW - (0 << 3) | // AVX512_4FMAPS - (1 << 4) | // Fast Short Rep Mov - (0 << 5) | // Reserved - (0 << 6) | // Reserved - (0 << 7) | // Reserved - (0 << 8) | // AVX512_VP2INTERSECT - (0 << 9) | // SRBDS_CTRL (Special Register Buffer Data Sampling Mitigations) - (0 << 10) | // VERW clears CPU buffers - (0 << 11) | // Reserved - (0 << 12) | // Reserved - (0 << 13) | // TSX Force Abort (TSX will force abort if attempted) - (0 << 14) | // SERIALIZE instruction - ((Hybrid ? 1U : 0U) << 15) | // Hybrid - (0 << 16) | // TSXLDTRK (TSX Suspend load address tracking) - Allows untracked memory loads inside TSX region - (0 << 17) | // Reserved - (0 << 18) | // Intel PCONFIG - (0 << 19) | // Intel Architectural LBR - (0 << 20) | // Intel CET - (0 << 21) | // Reserved - (0 << 22) | // AMX-BF16 - Tile computation on bfloat16 - (0 << 23) | // AVX512_FP16 - FP16 AVX512 instructions - (0 << 24) | // AMX-tile - If AMX is implemented - (0 << 25) | // AMX-int8 - AMX on 8-bit integers - (0 << 26) | // IBRS_IBPB - Speculation control - (0 << 27) | // STIBP - Single Thread Indirect Branch Predictor, Part of IBC - (0 << 28) | // L1D Flush - (0 << 29) | // Arch capabilities - Speculative side channel mitigations - (0 << 30) | // Arch capabilities - MSR module specific - (0 << 31); // SSBD - Speculative Store Bypass Disable + Res.edx = (0 << 0) | // Reserved + (0 << 1) | // Reserved + (0 << 2) | // AVX512_4VNNIW + (0 << 3) | // AVX512_4FMAPS + (1 << 4) | // Fast Short Rep Mov + (0 << 5) | // Reserved + (0 << 6) | // Reserved + (0 << 7) | // Reserved + (0 << 8) | // AVX512_VP2INTERSECT + (0 << 9) | // SRBDS_CTRL (Special Register Buffer Data Sampling Mitigations) + (0 << 10) | // VERW clears CPU buffers + (0 << 11) | // Reserved + (0 << 12) | // Reserved + (0 << 13) | // TSX Force Abort (TSX will force abort if attempted) + (0 << 14) | // SERIALIZE instruction + ((Hybrid ? 1U : 0U) << 15) | // Hybrid + (0 << 16) | // TSXLDTRK (TSX Suspend load address tracking) - Allows untracked memory loads inside TSX region + (0 << 17) | // Reserved + (0 << 18) | // Intel PCONFIG + (0 << 19) | // Intel Architectural LBR + (0 << 20) | // Intel CET + (0 << 21) | // Reserved + (0 << 22) | // AMX-BF16 - Tile computation on bfloat16 + (0 << 23) | // AVX512_FP16 - FP16 AVX512 instructions + (0 << 24) | // AMX-tile - If AMX is implemented + (0 << 25) | // AMX-int8 - AMX on 8-bit integers + (0 << 26) | // IBRS_IBPB - Speculation control + (0 << 27) | // STIBP - Single Thread Indirect Branch Predictor, Part of IBC + (0 << 28) | // L1D Flush + (0 << 29) | // Arch capabilities - Speculative side channel mitigations + (0 << 30) | // Arch capabilities - MSR module specific + (0 << 31); // SSBD - Speculative Store Bypass Disable } return Res; @@ -745,19 +704,18 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_07h(uint32_t Leaf) const { FEXCore::CPUID::FunctionResults CPUIDEmu::Function_0Dh(uint32_t Leaf) const { // Leaf 0 - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; uint32_t XFeatureSupportedSizeMax = SupportsAVX() ? 0x0000'0340 : 0x0000'0240; // XFeatureEnabledSizeMax: Legacy Header + FPU/SSE + AVX if (Leaf == 0) { // XFeatureSupportedMask[31:0] - Res.eax = - (1 << 0) | // X87 support - (1 << 1) | // 128-bit SSE support - (SupportsAVX() << 2) | // 256-bit AVX support - (0b00 << 3) | // MPX State - (0b000 << 5) | // AVX-512 state - (0 << 8) | // "Used for IA32_XSS" ... Used for what? - (0 << 9); // PKRU state + Res.eax = (1 << 0) | // X87 support + (1 << 1) | // 128-bit SSE support + (SupportsAVX() << 2) | // 256-bit AVX support + (0b00 << 3) | // MPX State + (0b000 << 5) | // AVX-512 state + (0 << 8) | // "Used for IA32_XSS" ... Used for what? + (0 << 9); // PKRU state // EBX and ECX doesn't need to match if a feature is supported but not enabled Res.ebx = XFeatureSupportedSizeMax; @@ -765,28 +723,24 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_0Dh(uint32_t Leaf) const { // XFeatureSupportedMask[63:32] Res.edx = 0; // Upper 32-bits of XFeatureSupportedMask - } - else if (Leaf == 1) { - Res.eax = - (0 << 0) | // XSAVEOPT - (0 << 1) | // XSAVEC (and XRSTOR) - (0 << 2) | // XGETBV - XGETBV with ECX=1 supported - (0 << 3); // XSAVES - XSAVES, XRSTORS, and IA32_XSS supported + } else if (Leaf == 1) { + Res.eax = (0 << 0) | // XSAVEOPT + (0 << 1) | // XSAVEC (and XRSTOR) + (0 << 2) | // XGETBV - XGETBV with ECX=1 supported + (0 << 3); // XSAVES - XSAVES, XRSTORS, and IA32_XSS supported // Same information as Leaf 0 for ebx Res.ebx = XFeatureSupportedSizeMax; // Lower supported 32bits of IA32_XSS MSR. IA32_XSS[n] can only be set to 1 if ECX[n] is 1 - Res.ecx = - (0b0000'0000 << 0) | // Used for XCR0 - (0 << 8) | // PT state - (0 << 9); // Used for XCR0 + Res.ecx = (0b0000'0000 << 0) | // Used for XCR0 + (0 << 8) | // PT state + (0 << 9); // Used for XCR0 // Upper supported 32bits of IA32_XSS MSR. IA32_XSS[n+32] can only be set to 1 if EDX[n] is 1 // Entirely reserved atm Res.edx = 0; - } - else if (Leaf == 2) { + } else if (Leaf == 2) { Res.eax = SupportsAVX() ? 0x0000'0100 : 0; // YmmSaveStateSize Res.ebx = SupportsAVX() ? 0x0000'0240 : 0; // YmmSaveStateOffset @@ -798,7 +752,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_0Dh(uint32_t Leaf) const { } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_15h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; // TSC frequency = ECX * EBX / EAX uint32_t FrequencyHz = GetCycleCounterFrequency(); if (FrequencyHz) { @@ -810,10 +764,10 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_15h(uint32_t Leaf) const { } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_1Ah(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; if (Hybrid) { uint32_t CPU = GetCPUID(); - auto &Data = PerCPUData[CPU]; + auto& Data = PerCPUData[CPU]; // 0x40 is a big CPU // 0x20 is a little CPU Res.eax |= (Data.IsBig ? 0x40 : 0x20) << 24; @@ -823,7 +777,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_1Ah(uint32_t Leaf) const { // Hypervisor CPUID information leaf FEXCore::CPUID::FunctionResults CPUIDEmu::Function_4000_0000h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; // Maximum supported hypervisor leafs // We only expose the information leaf // @@ -845,7 +799,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_4000_0000h(uint32_t Leaf) con // Hypervisor CPUID information leaf FEXCore::CPUID::FunctionResults CPUIDEmu::Function_4000_0001h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; if (Leaf == 0) { // EAX[3:0] Is the host architecture that FEX is running under #ifdef _M_X86_64 @@ -864,7 +818,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_4000_0001h(uint32_t Leaf) con // Highest extended function implemented FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0000h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; Res.eax = 0x8000001F; // EBX, EDX, ECX become the manufacturer id string @@ -890,88 +844,84 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0001h(uint32_t Leaf) con #else constexpr uint32_t SUPPORTS_RDTSCP = 1; #endif - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; Res.eax = FAMILY_IDENTIFIER; - Res.ecx = - (1 << 0) | // LAHF/SAHF - (1 << 1) | // 0 = Single core product, 1 = multi core product - (0 << 2) | // SVM - (1 << 3) | // Extended APIC register space - (0 << 4) | // LOCK MOV CR0 means MOV CR8 - (1 << 5) | // ABM instructions - (0 << 6) | // SSE4a - (0 << 7) | // Misaligned SSE mode - (1 << 8) | // PREFETCHW - (0 << 9) | // OS visible workaround support - (0 << 10) | // Instruction based sampling support - (0 << 11) | // XOP - (0 << 12) | // SKINIT - (0 << 13) | // Watchdog timer support - (0 << 14) | // Reserved - (0 << 15) | // Lightweight profiling support - (0 << 16) | // FMA4 - (1 << 17) | // Translation cache extension - (0 << 18) | // Reserved - (0 << 19) | // Reserved - (0 << 20) | // Reserved - (0 << 21) | // Reserved - (0 << 22) | // Topology extensions support - (0 << 23) | // Core performance counter extensions - (0 << 24) | // NB performance counter extensions - (0 << 25) | // Reserved - (0 << 26) | // Data breakpoints extensions - (0 << 27) | // Performance TSC - (0 << 28) | // L2 perf counter extensions - (0 << 29) | // Reserved - (0 << 30) | // Reserved - (0 << 31); // Reserved + Res.ecx = (1 << 0) | // LAHF/SAHF + (1 << 1) | // 0 = Single core product, 1 = multi core product + (0 << 2) | // SVM + (1 << 3) | // Extended APIC register space + (0 << 4) | // LOCK MOV CR0 means MOV CR8 + (1 << 5) | // ABM instructions + (0 << 6) | // SSE4a + (0 << 7) | // Misaligned SSE mode + (1 << 8) | // PREFETCHW + (0 << 9) | // OS visible workaround support + (0 << 10) | // Instruction based sampling support + (0 << 11) | // XOP + (0 << 12) | // SKINIT + (0 << 13) | // Watchdog timer support + (0 << 14) | // Reserved + (0 << 15) | // Lightweight profiling support + (0 << 16) | // FMA4 + (1 << 17) | // Translation cache extension + (0 << 18) | // Reserved + (0 << 19) | // Reserved + (0 << 20) | // Reserved + (0 << 21) | // Reserved + (0 << 22) | // Topology extensions support + (0 << 23) | // Core performance counter extensions + (0 << 24) | // NB performance counter extensions + (0 << 25) | // Reserved + (0 << 26) | // Data breakpoints extensions + (0 << 27) | // Performance TSC + (0 << 28) | // L2 perf counter extensions + (0 << 29) | // Reserved + (0 << 30) | // Reserved + (0 << 31); // Reserved - Res.edx = - (1 << 0) | // FPU - (1 << 1) | // Virtual mode extensions - (1 << 2) | // Debugging extensions - (1 << 3) | // Page size extensions - (1 << 4) | // TSC - (1 << 5) | // MSR support - (1 << 6) | // PAE - (1 << 7) | // Machine Check Exception - (1 << 8) | // CMPXCHG8B - (1 << 9) | // APIC - (0 << 10) | // Reserved - (1 << 11) | // SYSCALL/SYSRET - (1 << 12) | // MTRR - (1 << 13) | // Page global extension - (1 << 14) | // Machine Check architecture - (1 << 15) | // CMOV - (1 << 16) | // Page attribute table - (1 << 17) | // Page-size extensions - (0 << 18) | // Reserved - (0 << 19) | // Reserved - (1 << 20) | // NX - (0 << 21) | // Reserved - (1 << 22) | // MMXExt - (1 << 23) | // MMX - (1 << 24) | // FXSAVE/FXRSTOR - (1 << 25) | // FXSAVE/FXRSTOR Optimizations - (0 << 26) | // 1 gigabit pages - (SUPPORTS_RDTSCP << 27) | // RDTSCP - (0 << 28) | // Reserved - (1 << 29) | // Long Mode - (1 << 30) | // 3DNow! Extensions - (1 << 31); // 3DNow! + Res.edx = (1 << 0) | // FPU + (1 << 1) | // Virtual mode extensions + (1 << 2) | // Debugging extensions + (1 << 3) | // Page size extensions + (1 << 4) | // TSC + (1 << 5) | // MSR support + (1 << 6) | // PAE + (1 << 7) | // Machine Check Exception + (1 << 8) | // CMPXCHG8B + (1 << 9) | // APIC + (0 << 10) | // Reserved + (1 << 11) | // SYSCALL/SYSRET + (1 << 12) | // MTRR + (1 << 13) | // Page global extension + (1 << 14) | // Machine Check architecture + (1 << 15) | // CMOV + (1 << 16) | // Page attribute table + (1 << 17) | // Page-size extensions + (0 << 18) | // Reserved + (0 << 19) | // Reserved + (1 << 20) | // NX + (0 << 21) | // Reserved + (1 << 22) | // MMXExt + (1 << 23) | // MMX + (1 << 24) | // FXSAVE/FXRSTOR + (1 << 25) | // FXSAVE/FXRSTOR Optimizations + (0 << 26) | // 1 gigabit pages + (SUPPORTS_RDTSCP << 27) | // RDTSCP + (0 << 28) | // Reserved + (1 << 29) | // Long Mode + (1 << 30) | // 3DNow! Extensions + (1 << 31); // 3DNow! return Res; } -constexpr char ProcessorBrand[32] = { - GIT_DESCRIBE_STRING -}; +constexpr char ProcessorBrand[32] = {GIT_DESCRIBE_STRING}; constexpr ssize_t DESCRIBE_STR_SIZE = std::char_traits::length(GIT_DESCRIBE_STRING); static_assert(DESCRIBE_STR_SIZE < 32); -//Processor brand string +// Processor brand string FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0002h(uint32_t Leaf) const { return Function_8000_0002h(Leaf, GetCPUID()); } @@ -985,140 +935,126 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0004h(uint32_t Leaf) con } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0002h(uint32_t Leaf, uint32_t CPU) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; memset(&Res, ' ', sizeof(FEXCore::CPUID::FunctionResults)); - memcpy(&Res, &ProcessorBrand[0], std::min(ssize_t{16L}, DESCRIBE_STR_SIZE)); + memcpy(&Res, &ProcessorBrand[0], std::min(ssize_t {16L}, DESCRIBE_STR_SIZE)); return Res; } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0003h(uint32_t Leaf, uint32_t CPU) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; memset(&Res, ' ', sizeof(FEXCore::CPUID::FunctionResults)); - memcpy(&Res, &ProcessorBrand[16], std::max(ssize_t{0L}, DESCRIBE_STR_SIZE - 16)); + memcpy(&Res, &ProcessorBrand[16], std::max(ssize_t {0L}, DESCRIBE_STR_SIZE - 16)); return Res; } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0004h(uint32_t Leaf, uint32_t CPU) const { - FEXCore::CPUID::FunctionResults Res{}; - auto &Data = PerCPUData[CPU]; + FEXCore::CPUID::FunctionResults Res {}; + auto& Data = PerCPUData[CPU]; memcpy(&Res, Data.ProductName, std::min(strlen(Data.ProductName), sizeof(FEXCore::CPUID::FunctionResults))); return Res; } // L1 Cache and TLB identifiers FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0005h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; // L1 TLB Information for 2MB and 4MB pages - Res.eax = - (64 << 0) | // Number of TLB instruction entries - (255 << 8) | // instruction TLB associativity type (full) - (64 << 16) | // Number of TLB data entries - (255 << 24); // data TLB associativity type (full) + Res.eax = (64 << 0) | // Number of TLB instruction entries + (255 << 8) | // instruction TLB associativity type (full) + (64 << 16) | // Number of TLB data entries + (255 << 24); // data TLB associativity type (full) // L1 TLB Information for 4KB pages - Res.ebx = - (64 << 0) | // Number of TLB instruction entries - (255 << 8) | // instruction TLB associativity type (full) - (64 << 16) | // Number of TLB data entries - (255 << 24); // data TLB associativity type (full) + Res.ebx = (64 << 0) | // Number of TLB instruction entries + (255 << 8) | // instruction TLB associativity type (full) + (64 << 16) | // Number of TLB data entries + (255 << 24); // data TLB associativity type (full) // L1 data cache identifiers - Res.ecx = - (64 << 0) | // L1 data cache size line in bytes - (1 << 8) | // L1 data cachelines per tag - (8 << 16) | // L1 data cache associativity - (32 << 24); // L1 data cache size in KB + Res.ecx = (64 << 0) | // L1 data cache size line in bytes + (1 << 8) | // L1 data cachelines per tag + (8 << 16) | // L1 data cache associativity + (32 << 24); // L1 data cache size in KB // L1 instruction cache identifiers - Res.edx = - (64 << 0) | // L1 instruction cache line size in bytes - (1 << 8) | // L1 instruction cachelines per tag - (4 << 16) | // L1 instruction cache associativity - (64 << 24); // L1 instruction cache size in KB + Res.edx = (64 << 0) | // L1 instruction cache line size in bytes + (1 << 8) | // L1 instruction cachelines per tag + (4 << 16) | // L1 instruction cache associativity + (64 << 24); // L1 instruction cache size in KB return Res; } // L2 Cache identifiers FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0006h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; // L2 TLB Information for 2MB and 4MB pages - Res.eax = - (1024 << 0) | // Number of TLB instruction entries - (6 << 12) | // instruction TLB associativity type - (1536 << 16) | // Number of TLB data entries - (3 << 28); // data TLB associativity type + Res.eax = (1024 << 0) | // Number of TLB instruction entries + (6 << 12) | // instruction TLB associativity type + (1536 << 16) | // Number of TLB data entries + (3 << 28); // data TLB associativity type // L2 TLB Information for 4KB pages - Res.ebx = - (1024 << 0) | // Number of TLB instruction entries - (6 << 12) | // instruction TLB associativity type - (1536 << 16) | // Number of TLB data entries - (5 << 28); // data TLB associativity type + Res.ebx = (1024 << 0) | // Number of TLB instruction entries + (6 << 12) | // instruction TLB associativity type + (1536 << 16) | // Number of TLB data entries + (5 << 28); // data TLB associativity type // L2 cache identifiers - Res.ecx = - (64 << 0) | // cacheline size - (1 << 8) | // cachelines per tag - (6 << 12) | // cache associativity - (512 << 16); // L2 cache size in KB + Res.ecx = (64 << 0) | // cacheline size + (1 << 8) | // cachelines per tag + (6 << 12) | // cache associativity + (512 << 16); // L2 cache size in KB // L3 cache identifiers - Res.edx = - (64 << 0) | // cacheline size - (1 << 8) | // cachelines per tag - (6 << 12) | // cache associativity - (16 << 18); // L2 cache size in KB + Res.edx = (64 << 0) | // cacheline size + (1 << 8) | // cachelines per tag + (6 << 12) | // cache associativity + (16 << 18); // L2 cache size in KB return Res; } // Advanced power management FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0007h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; Res.eax = (1 << 2); // APIC timer not affected by p-state - Res.edx = - (1 << 8); // Invariant TSC + Res.edx = (1 << 8); // Invariant TSC return Res; } // Virtual and physical address sizes FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0008h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; - Res.eax = - (48 << 0) | // PhysAddrSize = 48-bit - (48 << 8) | // LinAddrSize = 48-bit - (0 << 16); // GuestPhysAddrSize == PhysAddrSize + FEXCore::CPUID::FunctionResults Res {}; + Res.eax = (48 << 0) | // PhysAddrSize = 48-bit + (48 << 8) | // LinAddrSize = 48-bit + (0 << 16); // GuestPhysAddrSize == PhysAddrSize - Res.ebx = - (0 << 2) | // XSaveErPtr: Saving and restoring error pointers - (0 << 1) | // IRPerf: Instructions retired count support - (CTX->HostFeatures.SupportsCLZERO << 0); // CLZERO support + Res.ebx = (0 << 2) | // XSaveErPtr: Saving and restoring error pointers + (0 << 1) | // IRPerf: Instructions retired count support + (CTX->HostFeatures.SupportsCLZERO << 0); // CLZERO support uint32_t CoreCount = Cores - 1; - Res.ecx = - (0 << 16) | // PerfTscSize: Performance timestamp count size - ((uint32_t)std::log2(CoreCount + 1) << 12) | // ApicIdSize: Number of bits in ApicID - (CoreCount << 0); // Count count subtract one + Res.ecx = (0 << 16) | // PerfTscSize: Performance timestamp count size + ((uint32_t)std::log2(CoreCount + 1) << 12) | // ApicIdSize: Number of bits in ApicID + (CoreCount << 0); // Count count subtract one return Res; } // TLB 1GB page identifiers FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0019h(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; - Res.eax = - (0xF << 28) | // L1 DTLB associativity for 1GB pages - (64 << 16) | // L1 DTLB entry count for 1GB pages - (0xF << 12) | // L1 ITLB associativity for 1GB pages - (64 << 0); // L1 ITLB entry count for 1GB pages + FEXCore::CPUID::FunctionResults Res {}; + Res.eax = (0xF << 28) | // L1 DTLB associativity for 1GB pages + (64 << 16) | // L1 DTLB entry count for 1GB pages + (0xF << 12) | // L1 ITLB associativity for 1GB pages + (64 << 0); // L1 ITLB entry count for 1GB pages - Res.ebx = - (0 << 28) | // L2 DTLB associativity for 1GB pages - (0 << 16) | // L2 DTLB entry count for 1GB pages - (0 << 12) | // L2 ITLB associativity for 1GB pages - (0 << 0); // L2 ITLB entry count for 1GB pages + Res.ebx = (0 << 28) | // L2 DTLB associativity for 1GB pages + (0 << 16) | // L2 DTLB entry count for 1GB pages + (0 << 12) | // L2 ITLB associativity for 1GB pages + (0 << 0); // L2 ITLB entry count for 1GB pages return Res; } @@ -1127,7 +1063,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_001Dh(uint32_t Leaf) con // This is nearly a copy of CPUID function 4h // There are some minor changes though - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; constexpr uint32_t CacheType_Data = 1; constexpr uint32_t CacheType_Instruction = 2; constexpr uint32_t CacheType_Unified = 3; @@ -1135,97 +1071,86 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_001Dh(uint32_t Leaf) con if (Leaf == 0) { // Report L1D Res.eax = CacheType_Data | // Cache type - (0b001 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (0 << 14); // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) + (0b001 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (0 << 14); // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 32KB Res.ecx = 63; // Number of sets - 1 : Claiming 64 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1); // Cache inclusiveness - Includes lower caches - } - else if (Leaf == 1) { + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1); // Cache inclusiveness - Includes lower caches + } else if (Leaf == 1) { // Report L1I Res.eax = CacheType_Instruction | // Cache type - (0b001 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (0 << 14); // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) + (0b001 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (0 << 14); // Maximum number of addressable IDs for logical processors sharing this cache (With SMT this would be 1) - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 32KB Res.ecx = 63; // Number of sets - 1 : Claiming 64 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1); // Cache inclusiveness - Includes lower caches - } - else if (Leaf == 2) { + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1); // Cache inclusiveness - Includes lower caches + } else if (Leaf == 2) { // Report L2 Res.eax = CacheType_Unified | // Cache type - (0b010 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (0 << 14); // Maximum number of addressable IDs for logical processors sharing this cache + (0b010 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (0 << 14); // Maximum number of addressable IDs for logical processors sharing this cache - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 512KB Res.ecx = 0x3FF; // Number of sets - 1 : Claiming 1024 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1); // Cache inclusiveness - Includes lower caches - } - else if (Leaf == 3) { + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1); // Cache inclusiveness - Includes lower caches + } else if (Leaf == 3) { // Report L3 uint32_t CoreCount = Cores - 1; Res.eax = CacheType_Unified | // Cache type - (0b011 << 5) | // Cache level - (1 << 8) | // Self initializing cache level - (0 << 9) | // Fully associative - (CoreCount << 14); // Maximum number of addressable IDs for logical processors sharing this cache + (0b011 << 5) | // Cache level + (1 << 8) | // Self initializing cache level + (0 << 9) | // Fully associative + (CoreCount << 14); // Maximum number of addressable IDs for logical processors sharing this cache - Res.ebx = - (63 << 0) | // Line Size - 1 : Claiming 64 byte - (0 << 12) | // Physical Line partitions - (7 << 22); // Associativity - 1 : Claiming 8 way + Res.ebx = (63 << 0) | // Line Size - 1 : Claiming 64 byte + (0 << 12) | // Physical Line partitions + (7 << 22); // Associativity - 1 : Claiming 8 way // 8MB Res.ecx = 0x4000; // Number of sets - 1 : Claiming 16384 sets - Res.edx = - (0 << 0) | // Write-back invalidate - (0 << 1); // Cache inclusiveness - Includes lower caches + Res.edx = (0 << 0) | // Write-back invalidate + (0 << 1); // Cache inclusiveness - Includes lower caches } return Res; } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_Reserved(uint32_t Leaf) const { - FEXCore::CPUID::FunctionResults Res{}; + FEXCore::CPUID::FunctionResults Res {}; return Res; } FEXCore::CPUID::XCRResults CPUIDEmu::XCRFunction_0h() const { // This just returns XCR0 - FEXCore::CPUID::XCRResults Res{ + FEXCore::CPUID::XCRResults Res { .eax = static_cast(XCR0), .edx = static_cast(XCR0 >> 32), }; @@ -1233,7 +1158,7 @@ FEXCore::CPUID::XCRResults CPUIDEmu::XCRFunction_0h() const { return Res; } -CPUIDEmu::CPUIDEmu(FEXCore::Context::ContextImpl const *ctx) +CPUIDEmu::CPUIDEmu(const FEXCore::Context::ContextImpl* ctx) : CTX {ctx} { Cores = FEXCore::CPUInfo::CalculateNumberOfCPUs(); @@ -1242,5 +1167,4 @@ CPUIDEmu::CPUIDEmu(FEXCore::Context::ContextImpl const *ctx) SetupFeatures(); } -} - +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/CPUID.h b/FEXCore/Source/Interface/Core/CPUID.h index 47cede6b9..98e0e626f 100644 --- a/FEXCore/Source/Interface/Core/CPUID.h +++ b/FEXCore/Source/Interface/Core/CPUID.h @@ -30,7 +30,7 @@ private: constexpr static uint32_t CPUID_VENDOR_AMD3 = 0x444D4163; // "cAMD" public: - CPUIDEmu(FEXCore::Context::ContextImpl const *ctx); + CPUIDEmu(const FEXCore::Context::ContextImpl* ctx); // X86 cacheline size effectively has to be hardcoded to 64 // if we report anything differently then applications are likely to break @@ -58,12 +58,13 @@ public: } FEXCore::CPUID::FunctionResults RunFunctionName(uint32_t Function, uint32_t Leaf, uint32_t CPU) const { - if (Function == 0x8000'0002U) + if (Function == 0x8000'0002U) { return Function_8000_0002h(Leaf, CPU % PerCPUData.size()); - else if (Function == 0x8000'0003U) + } else if (Function == 0x8000'0003U) { return Function_8000_0003h(Leaf, CPU % PerCPUData.size()); - else + } else { return Function_8000_0004h(Leaf, CPU % PerCPUData.size()); + } } FEXCore::CPUID::XCRResults RunXCRFunction(uint32_t Function) const { @@ -113,9 +114,9 @@ public: } private: - FEXCore::Context::ContextImpl const *CTX; - bool Hybrid{}; - uint32_t Cores{}; + const FEXCore::Context::ContextImpl* CTX; + bool Hybrid {}; + uint32_t Cores {}; FEX_CONFIG_OPT(HideHypervisorBit, HIDEHYPERVISORBIT); FEX_CONFIG_OPT(SmallTSCScale, SMALLTSCSCALE); @@ -148,10 +149,7 @@ private: .SHA = 1, }; - uint64_t XCR0 { - XCR0_X87 | - XCR0_SSE - }; + uint64_t XCR0 {XCR0_X87 | XCR0_SSE}; uint32_t SupportsAVX() const { return (XCR0 & XCR0_AVX) ? 1 : 0; @@ -160,13 +158,13 @@ private: using FunctionHandler = FEXCore::CPUID::FunctionResults (CPUIDEmu::*)(uint32_t Leaf) const; struct CPUData { - const char *ProductName{}; + const char* ProductName {}; #ifdef _M_ARM_64 - uint32_t MIDR{}; + uint32_t MIDR {}; #endif - bool IsBig{}; + bool IsBig {}; }; - fextl::vector PerCPUData{}; + fextl::vector PerCPUData {}; // Functions FEXCore::CPUID::FunctionResults Function_0h(uint32_t Leaf) const; @@ -277,74 +275,74 @@ private: static constexpr std::array Primary_Constant = {{ // 0: Highest function parameter and ID - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 1: Processor info - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 2: Cache and TLB info - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 3: Serial Number(previously), now reserved - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #ifndef CPUID_AMD // 4: Deterministic cache parameters for each level - { SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT}, #else // 4: Reserved - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #endif // 5: Monitor/mwait - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 6: Thermal and power management - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 7: Extended feature flags - { SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT}, // 0x08: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 9: Direct Cache Access information - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x0A: Architectural performance monitoring - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x0B: Extended topology enumeration - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x0C: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x0D: Processor extended state enumeration - { SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT}, // 0x0E: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x0F: Intel RDT monitoring - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x10: Intel RDT allocation enumeration - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x12: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x12: Intel SGX capability enumeration - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x13: Reserved - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x14: Intel Processor trace - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #ifndef CPUID_AMD // 0x15: Timestamp counter information // Doesn't exist on AMD hardware - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #else // 0x15: Reserved - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #endif // 0x16: Processor frequency information - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x17: SoC vendor attribute enumeration - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x18: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x19: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #ifndef CPUID_AMD // 0x1A: Hybrid Information Sub-leaf - { SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #else // 0x1A: Reserved - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #endif }}; @@ -357,9 +355,9 @@ private: static constexpr std::array Hypervisor_Constant = {{ // Hypervisor CPUID information leaf - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // FEX-Emu specific leaf - { SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT}, }}; static constexpr std::array Extended = { @@ -439,79 +437,79 @@ private: static constexpr std::array Extended_Constant = {{ // Largest extended function number - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // Processor vendor - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // Processor brand string - { SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // Processor brand string continued - { SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // Processor brand string continued - { SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::NONCONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #ifdef CPUID_AMD // 0x8000'0005: L1 Cache and TLB identifiers - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #else // 0x8000'0005: Reserved - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #endif // 0x8000'0006: L2 Cache identifiers - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0007: Advanced power management information - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0008: Virtual and physical address sizes - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0009: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'000A: SVM Revision - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'000B: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'000C: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'000D: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'000E: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'000F: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0010: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0011: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0012: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0013: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0014: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0015: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0016: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0017: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0018: Reserved? - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'0019: TLB 1GB page identifiers - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'001A: Performance optimization identifiers - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'001B: Instruction based sampling identifiers - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'001C: Lightweight profiling capabilities - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #ifdef CPUID_AMD // 0x8000'001D: Cache properties - { SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NEEDSLEAFCONSTANT}, #else // 0x8000'001D: Reserved - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, #endif // 0x8000'001E: Extended APIC ID - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, // 0x8000'001F: AMD Secure Encryption - { SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT }, + {SupportsConstant::CONSTANT, NeedsLeafConstant::NOLEAFCONSTANT}, }}; }; -} +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index 0f195965c..55c7d53e3 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -75,956 +75,935 @@ $end_info$ #include namespace FEXCore::Context { - ContextImpl::ContextImpl() +ContextImpl::ContextImpl() : CPUID {this} , IRCaptureCache {this} { #ifdef BLOCKSTATS - BlockData = std::make_unique(); + BlockData = std::make_unique(); #endif - if (Config.CacheObjectCodeCompilation() != FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE) { - CodeObjectCacheService = fextl::make_unique(this); - } - if (!Config.Is64BitMode()) { - // When operating in 32-bit mode, the virtual memory we care about is only the lower 32-bits. - Config.VirtualMemSize = 1ULL << 32; - } - - if (Config.BlockJITNaming() || - Config.GlobalJITNaming() || - Config.LibraryJITNaming()) { - // Only initialize symbols file if enabled. Ensures we don't pollute /tmp with empty files. - Symbols.InitFile(); - } - - if (FEXCore::GetCycleCounterFrequency() >= FEXCore::Context::TSC_SCALE_MAXIMUM) { - Config.SmallTSCScale = false; - } - - // Track atomic TSO emulation configuration. - UpdateAtomicTSOEmulationConfig(); + if (Config.CacheObjectCodeCompilation() != FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE) { + CodeObjectCacheService = fextl::make_unique(this); + } + if (!Config.Is64BitMode()) { + // When operating in 32-bit mode, the virtual memory we care about is only the lower 32-bits. + Config.VirtualMemSize = 1ULL << 32; } - ContextImpl::~ContextImpl() { - { - if (CodeObjectCacheService) { - CodeObjectCacheService->Shutdown(); - } - } + if (Config.BlockJITNaming() || Config.GlobalJITNaming() || Config.LibraryJITNaming()) { + // Only initialize symbols file if enabled. Ensures we don't pollute /tmp with empty files. + Symbols.InitFile(); } - uint64_t ContextImpl::RestoreRIPFromHostPC(FEXCore::Core::InternalThreadState *Thread, uint64_t HostPC) { - const auto Frame = Thread->CurrentFrame; - const uint64_t BlockBegin = Frame->State.InlineJITBlockHeader; - auto InlineHeader = reinterpret_cast(BlockBegin); + if (FEXCore::GetCycleCounterFrequency() >= FEXCore::Context::TSC_SCALE_MAXIMUM) { + Config.SmallTSCScale = false; + } - if (InlineHeader) { - auto InlineTail = reinterpret_cast(Frame->State.InlineJITBlockHeader + InlineHeader->OffsetToBlockTail); - auto RIPEntries = reinterpret_cast(Frame->State.InlineJITBlockHeader + InlineHeader->OffsetToBlockTail + InlineTail->OffsetToRIPEntries); + // Track atomic TSO emulation configuration. + UpdateAtomicTSOEmulationConfig(); +} - // Check if the host PC is currently within a code block. - // If it is then RIP can be reconstructed from the beginning of the code block. - // This is currently as close as FEX can get RIP reconstructions. - if (HostPC >= reinterpret_cast(BlockBegin) && - HostPC < reinterpret_cast(BlockBegin + InlineTail->Size)) { +ContextImpl::~ContextImpl() { + { + if (CodeObjectCacheService) { + CodeObjectCacheService->Shutdown(); + } + } +} - // Reconstruct RIP from JIT entries for this block. - uint64_t StartingHostPC = BlockBegin; - uint64_t StartingGuestRIP = InlineTail->RIP; +uint64_t ContextImpl::RestoreRIPFromHostPC(FEXCore::Core::InternalThreadState* Thread, uint64_t HostPC) { + const auto Frame = Thread->CurrentFrame; + const uint64_t BlockBegin = Frame->State.InlineJITBlockHeader; + auto InlineHeader = reinterpret_cast(BlockBegin); - for (uint32_t i = 0; i < InlineTail->NumberOfRIPEntries; ++i) { - const auto &RIPEntry = RIPEntries[i]; - if (HostPC >= (StartingHostPC + RIPEntry.HostPCOffset)) { - // We are beyond this entry, keep going forward. - StartingHostPC += RIPEntry.HostPCOffset; - StartingGuestRIP += RIPEntry.GuestRIPOffset; - } - else { - // Passed where the Host PC is at. Break now. - break; - } + if (InlineHeader) { + auto InlineTail = reinterpret_cast(Frame->State.InlineJITBlockHeader + InlineHeader->OffsetToBlockTail); + auto RIPEntries = reinterpret_cast( + Frame->State.InlineJITBlockHeader + InlineHeader->OffsetToBlockTail + InlineTail->OffsetToRIPEntries); + + // Check if the host PC is currently within a code block. + // If it is then RIP can be reconstructed from the beginning of the code block. + // This is currently as close as FEX can get RIP reconstructions. + if (HostPC >= reinterpret_cast(BlockBegin) && HostPC < reinterpret_cast(BlockBegin + InlineTail->Size)) { + + // Reconstruct RIP from JIT entries for this block. + uint64_t StartingHostPC = BlockBegin; + uint64_t StartingGuestRIP = InlineTail->RIP; + + for (uint32_t i = 0; i < InlineTail->NumberOfRIPEntries; ++i) { + const auto& RIPEntry = RIPEntries[i]; + if (HostPC >= (StartingHostPC + RIPEntry.HostPCOffset)) { + // We are beyond this entry, keep going forward. + StartingHostPC += RIPEntry.HostPCOffset; + StartingGuestRIP += RIPEntry.GuestRIPOffset; + } else { + // Passed where the Host PC is at. Break now. + break; } - return StartingGuestRIP; } + return StartingGuestRIP; } - - // Fallback to what is stored in the RIP currently. - return Frame->State.rip; } - uint32_t ContextImpl::ReconstructCompactedEFLAGS(FEXCore::Core::InternalThreadState *Thread, bool WasInJIT, uint64_t *HostGPRs, uint64_t PSTATE) { - const auto Frame = Thread->CurrentFrame; - uint32_t EFLAGS{}; + // Fallback to what is stored in the RIP currently. + return Frame->State.rip; +} - // Currently these flags just map 1:1 inside of the resulting value. - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_EFLAG_BITS; ++i) { - switch (i) { - case X86State::RFLAG_CF_RAW_LOC: - case X86State::RFLAG_PF_RAW_LOC: - case X86State::RFLAG_AF_RAW_LOC: - case X86State::RFLAG_ZF_RAW_LOC: - case X86State::RFLAG_SF_RAW_LOC: - case X86State::RFLAG_OF_RAW_LOC: - case X86State::RFLAG_DF_RAW_LOC: - // Intentionally do nothing. - // These contain multiple bits which can corrupt other members when compacted. - break; - default: - EFLAGS |= uint32_t{Frame->State.flags[i]} << i; - break; - } - } +uint32_t ContextImpl::ReconstructCompactedEFLAGS(FEXCore::Core::InternalThreadState* Thread, bool WasInJIT, uint64_t* HostGPRs, uint64_t PSTATE) { + const auto Frame = Thread->CurrentFrame; + uint32_t EFLAGS {}; - uint32_t Packed_NZCV{}; - if (WasInJIT) { - // If we were in the JIT then NZCV is in the CPU's PSTATE object. - // Packed in to the same bit locations as RFLAG_NZCV_LOC. - Packed_NZCV = PSTATE; - - // If we were in the JIT then PF and AF are in registers. - // Move them to the CPUState frame now. - Frame->State.pf_raw = HostGPRs[CPU::REG_PF.Idx()]; - Frame->State.af_raw = HostGPRs[CPU::REG_AF.Idx()]; - } - else { - // If we were not in the JIT then the NZCV state is stored in the CPUState RFLAG_NZCV_LOC. - // SF/ZF/CF/OF are packed in a 32-bit value in RFLAG_NZCV_LOC. - memcpy(&Packed_NZCV, &Frame->State.flags[X86State::RFLAG_NZCV_LOC], sizeof(Packed_NZCV)); - } - - uint32_t OF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_OF_RAW_LOC)) & 1; - uint32_t CF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_CF_RAW_LOC)) & 1; - uint32_t ZF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_ZF_RAW_LOC)) & 1; - uint32_t SF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_SF_RAW_LOC)) & 1; - - // Pack in to EFLAGS - EFLAGS |= OF << X86State::RFLAG_OF_RAW_LOC; - EFLAGS |= CF << X86State::RFLAG_CF_RAW_LOC; - EFLAGS |= ZF << X86State::RFLAG_ZF_RAW_LOC; - EFLAGS |= SF << X86State::RFLAG_SF_RAW_LOC; - - // PF calculation is deferred, calculate it now. - // Popcount the 8-bit flag and then extract the lower bit. - uint32_t PFByte = Frame->State.pf_raw & 0xff; - uint32_t PF = std::popcount(PFByte ^ 1) & 1; - EFLAGS |= PF << X86State::RFLAG_PF_RAW_LOC; - - // AF calculation is deferred, calculate it now. - // XOR with PF byte and extract bit 4. - uint32_t AF = ((Frame->State.af_raw ^ PFByte) & (1 << 4)) ? 1 : 0; - EFLAGS |= AF << X86State::RFLAG_AF_RAW_LOC; - - // DF is pretransformed, undo the transform from 1/-1 back to 0/1 - uint8_t DFByte = Frame->State.flags[X86State::RFLAG_DF_RAW_LOC]; - if (DFByte & 0x80) - EFLAGS |= 1 << X86State::RFLAG_DF_RAW_LOC; - - return EFLAGS; - } - - void ContextImpl::SetFlagsFromCompactedEFLAGS(FEXCore::Core::InternalThreadState *Thread, uint32_t EFLAGS) { - const auto Frame = Thread->CurrentFrame; - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_EFLAG_BITS; ++i) { - switch (i) { - case X86State::RFLAG_OF_RAW_LOC: - case X86State::RFLAG_CF_RAW_LOC: - case X86State::RFLAG_ZF_RAW_LOC: - case X86State::RFLAG_SF_RAW_LOC: - // Intentionally do nothing. - break; - case X86State::RFLAG_AF_RAW_LOC: - // AF stored in bit 4 in our internal representation. It is also - // XORed with byte 4 of the PF byte, but we write that as zero here so - // we don't need any special handling for that. - Frame->State.af_raw = (EFLAGS & (1U << i)) ? (1 << 4) : 0; - break; - case X86State::RFLAG_PF_RAW_LOC: - // PF is inverted in our internal representation. - Frame->State.pf_raw = (EFLAGS & (1U << i)) ? 0 : 1; - break; - case X86State::RFLAG_DF_RAW_LOC: - // DF is encoded as 1/-1 - Frame->State.flags[i] = (EFLAGS & (1U << i)) ? 0xff : 1; - break; - default: - Frame->State.flags[i] = (EFLAGS & (1U << i)) ? 1 : 0; - break; - } - } - - // Calculate packed NZCV - uint32_t Packed_NZCV{}; - Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_OF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_OF_RAW_LOC) : 0; - Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_CF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_CF_RAW_LOC) : 0; - Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_ZF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_ZF_RAW_LOC) : 0; - Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_SF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_SF_RAW_LOC) : 0; - memcpy(&Frame->State.flags[X86State::RFLAG_NZCV_LOC], &Packed_NZCV, sizeof(Packed_NZCV)); - - // Reserved, Read-As-1, Write-as-1 - Frame->State.flags[X86State::RFLAG_RESERVED_LOC] = 1; - // Interrupt Flag. Can't be written by CPL-3 userland. - Frame->State.flags[X86State::RFLAG_IF_LOC] = 1; - } - - bool ContextImpl::InitCore() { - // Initialize the CPU core signal handlers & DispatcherConfig - switch (Config.Core) { - case FEXCore::Config::CONFIG_IRJIT: - BackendFeatures = FEXCore::CPU::GetArm64JITBackendFeatures(); + // Currently these flags just map 1:1 inside of the resulting value. + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_EFLAG_BITS; ++i) { + switch (i) { + case X86State::RFLAG_CF_RAW_LOC: + case X86State::RFLAG_PF_RAW_LOC: + case X86State::RFLAG_AF_RAW_LOC: + case X86State::RFLAG_ZF_RAW_LOC: + case X86State::RFLAG_SF_RAW_LOC: + case X86State::RFLAG_OF_RAW_LOC: + case X86State::RFLAG_DF_RAW_LOC: + // Intentionally do nothing. + // These contain multiple bits which can corrupt other members when compacted. break; - case FEXCore::Config::CONFIG_CUSTOM: - // Do nothing + default: EFLAGS |= uint32_t {Frame->State.flags[i]} << i; break; + } + } + + uint32_t Packed_NZCV {}; + if (WasInJIT) { + // If we were in the JIT then NZCV is in the CPU's PSTATE object. + // Packed in to the same bit locations as RFLAG_NZCV_LOC. + Packed_NZCV = PSTATE; + + // If we were in the JIT then PF and AF are in registers. + // Move them to the CPUState frame now. + Frame->State.pf_raw = HostGPRs[CPU::REG_PF.Idx()]; + Frame->State.af_raw = HostGPRs[CPU::REG_AF.Idx()]; + } else { + // If we were not in the JIT then the NZCV state is stored in the CPUState RFLAG_NZCV_LOC. + // SF/ZF/CF/OF are packed in a 32-bit value in RFLAG_NZCV_LOC. + memcpy(&Packed_NZCV, &Frame->State.flags[X86State::RFLAG_NZCV_LOC], sizeof(Packed_NZCV)); + } + + uint32_t OF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_OF_RAW_LOC)) & 1; + uint32_t CF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_CF_RAW_LOC)) & 1; + uint32_t ZF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_ZF_RAW_LOC)) & 1; + uint32_t SF = (Packed_NZCV >> IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_SF_RAW_LOC)) & 1; + + // Pack in to EFLAGS + EFLAGS |= OF << X86State::RFLAG_OF_RAW_LOC; + EFLAGS |= CF << X86State::RFLAG_CF_RAW_LOC; + EFLAGS |= ZF << X86State::RFLAG_ZF_RAW_LOC; + EFLAGS |= SF << X86State::RFLAG_SF_RAW_LOC; + + // PF calculation is deferred, calculate it now. + // Popcount the 8-bit flag and then extract the lower bit. + uint32_t PFByte = Frame->State.pf_raw & 0xff; + uint32_t PF = std::popcount(PFByte ^ 1) & 1; + EFLAGS |= PF << X86State::RFLAG_PF_RAW_LOC; + + // AF calculation is deferred, calculate it now. + // XOR with PF byte and extract bit 4. + uint32_t AF = ((Frame->State.af_raw ^ PFByte) & (1 << 4)) ? 1 : 0; + EFLAGS |= AF << X86State::RFLAG_AF_RAW_LOC; + + // DF is pretransformed, undo the transform from 1/-1 back to 0/1 + uint8_t DFByte = Frame->State.flags[X86State::RFLAG_DF_RAW_LOC]; + if (DFByte & 0x80) { + EFLAGS |= 1 << X86State::RFLAG_DF_RAW_LOC; + } + + return EFLAGS; +} + +void ContextImpl::SetFlagsFromCompactedEFLAGS(FEXCore::Core::InternalThreadState* Thread, uint32_t EFLAGS) { + const auto Frame = Thread->CurrentFrame; + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_EFLAG_BITS; ++i) { + switch (i) { + case X86State::RFLAG_OF_RAW_LOC: + case X86State::RFLAG_CF_RAW_LOC: + case X86State::RFLAG_ZF_RAW_LOC: + case X86State::RFLAG_SF_RAW_LOC: + // Intentionally do nothing. break; - default: - LogMan::Msg::EFmt("Unknown core configuration"); - return false; - } - - Dispatcher = FEXCore::CPU::Dispatcher::Create(this); - - // Set up the SignalDelegator config since core is initialized. - FEXCore::SignalDelegator::SignalDelegatorConfig SignalConfig { - .SupportsAVX = HostFeatures.SupportsAVX, - - .DispatcherBegin = Dispatcher->Start, - .DispatcherEnd = Dispatcher->End, - - .AbsoluteLoopTopAddress = Dispatcher->AbsoluteLoopTopAddress, - .AbsoluteLoopTopAddressFillSRA = Dispatcher->AbsoluteLoopTopAddressFillSRA, - .SignalHandlerReturnAddress = Dispatcher->SignalHandlerReturnAddress, - .SignalHandlerReturnAddressRT = Dispatcher->SignalHandlerReturnAddressRT, - - .PauseReturnInstruction = Dispatcher->PauseReturnInstruction, - .ThreadPauseHandlerAddressSpillSRA = Dispatcher->ThreadPauseHandlerAddressSpillSRA, - .ThreadPauseHandlerAddress = Dispatcher->ThreadPauseHandlerAddress, - - // Stop handlers. - .ThreadStopHandlerAddressSpillSRA = Dispatcher->ThreadStopHandlerAddressSpillSRA, - .ThreadStopHandlerAddress = Dispatcher->ThreadStopHandlerAddress, - - // SRA information. - .SRAGPRCount = Dispatcher->GetSRAGPRCount(), - .SRAFPRCount = Dispatcher->GetSRAFPRCount(), - }; - - Dispatcher->GetSRAGPRMapping(SignalConfig.SRAGPRMapping); - Dispatcher->GetSRAFPRMapping(SignalConfig.SRAFPRMapping); - - // Give this configuration to the SignalDelegator. - SignalDelegation->SetConfig(SignalConfig); - -#ifndef _WIN32 - ThunkHandler = FEXCore::ThunkHandler::Create(); -#else - // WIN32 always needs the interrupt fault check to be enabled. - Config.NeedsPendingInterruptFaultCheck = true; -#endif - - if (Config.GdbServer) { - // If gdbserver is enabled then this needs to be enabled. - Config.NeedsPendingInterruptFaultCheck = true; - // FEX needs to start paused when gdb is enabled. - StartPaused = true; - } - - return true; - } - - void ContextImpl::HandleCallback(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP) { - static_cast(Thread->CTX)->Dispatcher->ExecuteJITCallback(Thread->CurrentFrame, RIP); - } - - FEXCore::Context::ExitReason ContextImpl::RunUntilExit(FEXCore::Core::InternalThreadState *Thread) { - ExecutionThread(Thread); - while(true) { - auto reason = Thread->ExitReason; - - // Don't return if a custom exit handling the exit - if (!CustomExitHandler || reason == ExitReason::EXIT_SHUTDOWN) { - return reason; - } - } - } - - void ContextImpl::ExecuteThread(FEXCore::Core::InternalThreadState *Thread) { - Dispatcher->ExecuteDispatch(Thread->CurrentFrame); - } - - - void ContextImpl::InitializeThreadTLSData(FEXCore::Core::InternalThreadState *Thread) { - // Let's do some initial bookkeeping here - Thread->ThreadManager.TID = FHU::Syscalls::gettid(); - Thread->ThreadManager.PID = ::getpid(); - - if (ThunkHandler) { - ThunkHandler->RegisterTLSState(Thread); - } -#ifndef _WIN32 - Alloc::OSAllocator::RegisterTLSData(Thread); -#endif - } - - void ContextImpl::InitializeCompiler(FEXCore::Core::InternalThreadState* Thread) { - Thread->OpDispatcher = fextl::make_unique(this); - Thread->OpDispatcher->SetMultiblock(Config.Multiblock); - Thread->LookupCache = fextl::make_unique(this); - Thread->FrontendDecoder = fextl::make_unique(this); - Thread->PassManager = fextl::make_unique(); - - Thread->CurrentFrame->Pointers.Common.L1Pointer = Thread->LookupCache->GetL1Pointer(); - Thread->CurrentFrame->Pointers.Common.L2Pointer = Thread->LookupCache->GetPagePointer(); - - Dispatcher->InitThreadPointers(Thread); - - Thread->CTX = this; - - Thread->PassManager->AddDefaultPasses(this, Config.Core == FEXCore::Config::CONFIG_IRJIT); - Thread->PassManager->AddDefaultValidationPasses(); - - Thread->PassManager->RegisterSyscallHandler(SyscallHandler); - - // Create CPU backend - switch (Config.Core) { - case FEXCore::Config::CONFIG_IRJIT: - Thread->PassManager->InsertRegisterAllocationPass(HostFeatures.SupportsAVX); - Thread->CPUBackend = FEXCore::CPU::CreateArm64JITCore(this, Thread); + case X86State::RFLAG_AF_RAW_LOC: + // AF stored in bit 4 in our internal representation. It is also + // XORed with byte 4 of the PF byte, but we write that as zero here so + // we don't need any special handling for that. + Frame->State.af_raw = (EFLAGS & (1U << i)) ? (1 << 4) : 0; break; - case FEXCore::Config::CONFIG_CUSTOM: - Thread->CPUBackend = CustomCPUFactory(this, Thread); + case X86State::RFLAG_PF_RAW_LOC: + // PF is inverted in our internal representation. + Frame->State.pf_raw = (EFLAGS & (1U << i)) ? 0 : 1; break; - default: - ERROR_AND_DIE_FMT("Unknown core configuration"); + case X86State::RFLAG_DF_RAW_LOC: + // DF is encoded as 1/-1 + Frame->State.flags[i] = (EFLAGS & (1U << i)) ? 0xff : 1; break; - } - - Thread->PassManager->Finalize(); - } - - FEXCore::Core::InternalThreadState* ContextImpl::CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID) { - FEXCore::Core::InternalThreadState *Thread = new FEXCore::Core::InternalThreadState{}; - - Thread->CurrentFrame->State.gregs[X86State::REG_RSP] = StackPointer; - Thread->CurrentFrame->State.rip = InitialRIP; - - // Copy over the new thread state to the new object - if (NewThreadState) { - memcpy(&Thread->CurrentFrame->State, NewThreadState, sizeof(FEXCore::Core::CPUState)); - } - - // Set up the thread manager state - Thread->ThreadManager.parent_tid = ParentTID; - Thread->CurrentFrame->Thread = Thread; - - InitializeCompiler(Thread); - - Thread->CurrentFrame->State.DeferredSignalRefCount.Store(0); - Thread->CurrentFrame->State.DeferredSignalFaultAddress = reinterpret_cast*>(FEXCore::Allocator::VirtualAlloc(4096)); - - if (Config.BlockJITNaming() || - Config.GlobalJITNaming() || - Config.LibraryJITNaming()) { - // Allocate a JIT symbol buffer only if enabled. - Thread->SymbolBuffer = JITSymbols::AllocateBuffer(); - } - - return Thread; - } - - void ContextImpl::DestroyThread(FEXCore::Core::InternalThreadState *Thread, bool NeedsTLSUninstall) { - if (NeedsTLSUninstall) { -#ifndef _WIN32 - Alloc::OSAllocator::UninstallTLSData(Thread); -#endif - } - - FEXCore::Allocator::VirtualFree(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096); - delete Thread; - } - -#ifndef _WIN32 - void ContextImpl::UnlockAfterFork(FEXCore::Core::InternalThreadState *LiveThread, bool Child) { - Allocator::UnlockAfterFork(LiveThread, Child); - - if (Child) { - CodeInvalidationMutex.StealAndDropActiveLocks(); - } - else { - CodeInvalidationMutex.unlock(); - return; + default: Frame->State.flags[i] = (EFLAGS & (1U << i)) ? 1 : 0; break; } } - void ContextImpl::LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) { - CodeInvalidationMutex.lock(); - Allocator::LockBeforeFork(Thread); - } -#endif + // Calculate packed NZCV + uint32_t Packed_NZCV {}; + Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_OF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_OF_RAW_LOC) : 0; + Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_CF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_CF_RAW_LOC) : 0; + Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_ZF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_ZF_RAW_LOC) : 0; + Packed_NZCV |= (EFLAGS & (1U << X86State::RFLAG_SF_RAW_LOC)) ? 1U << IR::OpDispatchBuilder::IndexNZCV(X86State::RFLAG_SF_RAW_LOC) : 0; + memcpy(&Frame->State.flags[X86State::RFLAG_NZCV_LOC], &Packed_NZCV, sizeof(Packed_NZCV)); - void ContextImpl::AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr) { - Thread->LookupCache->AddBlockMapping(Address, Ptr); + // Reserved, Read-As-1, Write-as-1 + Frame->State.flags[X86State::RFLAG_RESERVED_LOC] = 1; + // Interrupt Flag. Can't be written by CPL-3 userland. + Frame->State.flags[X86State::RFLAG_IF_LOC] = 1; +} + +bool ContextImpl::InitCore() { + // Initialize the CPU core signal handlers & DispatcherConfig + switch (Config.Core) { + case FEXCore::Config::CONFIG_IRJIT: BackendFeatures = FEXCore::CPU::GetArm64JITBackendFeatures(); break; + case FEXCore::Config::CONFIG_CUSTOM: + // Do nothing + break; + default: LogMan::Msg::EFmt("Unknown core configuration"); return false; } - void ContextImpl::ClearCodeCache(FEXCore::Core::InternalThreadState *Thread) { - FEXCORE_PROFILE_INSTANT("ClearCodeCache"); + Dispatcher = FEXCore::CPU::Dispatcher::Create(this); - { - // Ensure the Code Object Serialization service has fully serialized this thread's data before clearing the cache - // Use the thread's object cache ref counter for this - CodeSerialize::CodeObjectSerializeService::WaitForEmptyJobQueue(&Thread->ObjectCacheRefCounter); - } - std::lock_guard lk(Thread->LookupCache->WriteLock); + // Set up the SignalDelegator config since core is initialized. + FEXCore::SignalDelegator::SignalDelegatorConfig SignalConfig { + .SupportsAVX = HostFeatures.SupportsAVX, - Thread->LookupCache->ClearCache(); - Thread->CPUBackend->ClearCache(); - } + .DispatcherBegin = Dispatcher->Start, + .DispatcherEnd = Dispatcher->End, - static void IRDumper(FEXCore::Core::InternalThreadState *Thread, IR::IREmitter *IREmitter, uint64_t GuestRIP, IR::RegisterAllocationData* RA) { - FEXCore::File::File FD = FEXCore::File::File::GetStdERR(); - fextl::stringstream out; - auto NewIR = IREmitter->ViewIR(); - FEXCore::IR::Dump(&out, &NewIR, RA); - fextl::fmt::print(FD, "IR-ShouldDump-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", GuestRIP, out.str()); + .AbsoluteLoopTopAddress = Dispatcher->AbsoluteLoopTopAddress, + .AbsoluteLoopTopAddressFillSRA = Dispatcher->AbsoluteLoopTopAddressFillSRA, + .SignalHandlerReturnAddress = Dispatcher->SignalHandlerReturnAddress, + .SignalHandlerReturnAddressRT = Dispatcher->SignalHandlerReturnAddressRT, + + .PauseReturnInstruction = Dispatcher->PauseReturnInstruction, + .ThreadPauseHandlerAddressSpillSRA = Dispatcher->ThreadPauseHandlerAddressSpillSRA, + .ThreadPauseHandlerAddress = Dispatcher->ThreadPauseHandlerAddress, + + // Stop handlers. + .ThreadStopHandlerAddressSpillSRA = Dispatcher->ThreadStopHandlerAddressSpillSRA, + .ThreadStopHandlerAddress = Dispatcher->ThreadStopHandlerAddress, + + // SRA information. + .SRAGPRCount = Dispatcher->GetSRAGPRCount(), + .SRAFPRCount = Dispatcher->GetSRAFPRCount(), }; - static void ValidateIR(ContextImpl *ctx, IR::IREmitter *IREmitter) { - // Convert to text, Parse, Convert to text again and make sure the texts match - fextl::stringstream out; - static auto compaction = IR::CreateIRCompaction(ctx->OpDispatcherAllocator); - compaction->Run(IREmitter); - auto NewIR = IREmitter->ViewIR(); - Dump(&out, &NewIR, nullptr); - out.seekg(0); - FEXCore::Utils::PooledAllocatorMalloc Allocator; - auto reparsed = IR::Parse(Allocator, out); - if (reparsed == nullptr) { - LOGMAN_MSG_A_FMT("Failed to parse IR\n"); - } else { - fextl::stringstream out2; - auto NewIR2 = reparsed->ViewIR(); - Dump(&out2, &NewIR2, nullptr); - if (out.str() != out2.str()) { - LogMan::Msg::IFmt("one:\n {}", out.str()); - LogMan::Msg::IFmt("two:\n {}", out2.str()); - LOGMAN_MSG_A_FMT("Parsed IR doesn't match\n"); - } - } - } + Dispatcher->GetSRAGPRMapping(SignalConfig.SRAGPRMapping); + Dispatcher->GetSRAFPRMapping(SignalConfig.SRAFPRMapping); - ContextImpl::GenerateIRResult ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, bool ExtendedDebugInfo, uint64_t MaxInst) { - FEXCORE_PROFILE_SCOPED("GenerateIR"); + // Give this configuration to the SignalDelegator. + SignalDelegation->SetConfig(SignalConfig); - Thread->OpDispatcher->ReownOrClaimBuffer(); - Thread->OpDispatcher->ResetWorkingList(); - - uint64_t TotalInstructions {0}; - uint64_t TotalInstructionsLength {0}; - - bool HasCustomIR{}; - - if (HasCustomIRHandlers.load(std::memory_order_relaxed)) { - std::shared_lock lk(CustomIRMutex); - auto Handler = CustomIRHandlers.find(GuestRIP); - if (Handler != CustomIRHandlers.end()) { - TotalInstructions = 1; - TotalInstructionsLength = 1; - std::get<0>(Handler->second)(GuestRIP, Thread->OpDispatcher.get()); - HasCustomIR = true; - } - } - - if (!HasCustomIR) { - uint8_t const *GuestCode{}; - GuestCode = reinterpret_cast(GuestRIP); - - bool HadDispatchError {false}; - - Thread->FrontendDecoder->DecodeInstructionsAtEntry(GuestCode, GuestRIP, MaxInst, [Thread](uint64_t BlockEntry, uint64_t Start, uint64_t Length) { - if (Thread->LookupCache->AddBlockExecutableRange(BlockEntry, Start, Length)) { - static_cast(Thread->CTX)->SyscallHandler->MarkGuestExecutableRange(Thread, Start, Length); - } - }); - - auto BlockInfo = Thread->FrontendDecoder->GetDecodedBlockInfo(); - auto CodeBlocks = &BlockInfo->Blocks; - - Thread->OpDispatcher->BeginFunction(GuestRIP, CodeBlocks, BlockInfo->TotalInstructionCount); - - const uint8_t GPRSize = GetGPRSize(); - - for (size_t j = 0; j < CodeBlocks->size(); ++j) { - FEXCore::Frontend::Decoder::DecodedBlocks const &Block = CodeBlocks->at(j); - // Set the block entry point - Thread->OpDispatcher->SetNewBlockIfChanged(Block.Entry); - - uint64_t BlockInstructionsLength {}; - - // Reset any block-specific state - Thread->OpDispatcher->StartNewBlock(); - - uint64_t InstsInBlock = Block.NumInstructions; - - for (size_t i = 0; i < InstsInBlock; ++i) { - FEXCore::X86Tables::X86InstInfo const* TableInfo {nullptr}; - FEXCore::X86Tables::DecodedInst const* DecodedInfo {nullptr}; - - TableInfo = Block.DecodedInstructions[i].TableInfo; - DecodedInfo = &Block.DecodedInstructions[i]; - bool IsLocked = DecodedInfo->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK; - - if (ExtendedDebugInfo || Thread->OpDispatcher->CanHaveSideEffects(TableInfo, DecodedInfo)) { - Thread->OpDispatcher->_GuestOpcode(Block.Entry + BlockInstructionsLength - GuestRIP); - } - - if (Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) { - auto ExistingCodePtr = reinterpret_cast(Block.Entry + BlockInstructionsLength); - - auto CodeChanged = Thread->OpDispatcher->_ValidateCode(ExistingCodePtr[0], ExistingCodePtr[1], (uintptr_t)ExistingCodePtr - GuestRIP, DecodedInfo->InstSize); - - auto InvalidateCodeCond = Thread->OpDispatcher->CondJump(CodeChanged); - - auto CurrentBlock = Thread->OpDispatcher->GetCurrentBlock(); - auto CodeWasChangedBlock = Thread->OpDispatcher->CreateNewCodeBlockAtEnd(); - Thread->OpDispatcher->SetTrueJumpTarget(InvalidateCodeCond, CodeWasChangedBlock); - - Thread->OpDispatcher->SetCurrentCodeBlock(CodeWasChangedBlock); - Thread->OpDispatcher->_ThreadRemoveCodeEntry(); - Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(IR::SizeToOpSize(GPRSize), Block.Entry + BlockInstructionsLength - GuestRIP)); - - auto NextOpBlock = Thread->OpDispatcher->CreateNewCodeBlockAfter(CurrentBlock); - - Thread->OpDispatcher->SetFalseJumpTarget(InvalidateCodeCond, NextOpBlock); - Thread->OpDispatcher->SetCurrentCodeBlock(NextOpBlock); - } - - if (TableInfo && TableInfo->OpcodeDispatcher) { - auto Fn = TableInfo->OpcodeDispatcher; - Thread->OpDispatcher->ResetHandledLock(); - Thread->OpDispatcher->ResetDecodeFailure(); - std::invoke(Fn, Thread->OpDispatcher, DecodedInfo); - if (Thread->OpDispatcher->HadDecodeFailure()) { - HadDispatchError = true; - } - else { - if (Thread->OpDispatcher->HasHandledLock() != IsLocked) { - HadDispatchError = true; - LogMan::Msg::EFmt("Missing LOCK HANDLER at 0x{:x}{{'{}'}}", Block.Entry + BlockInstructionsLength, TableInfo->Name ?: "UND"); - } - BlockInstructionsLength += DecodedInfo->InstSize; - TotalInstructionsLength += DecodedInfo->InstSize; - ++TotalInstructions; - } - } - else { - if (TableInfo) { - LogMan::Msg::EFmt("Invalid or Unknown instruction: {} 0x{:x}", TableInfo->Name ?: "UND", Block.Entry - GuestRIP); - } - // Invalid instruction - Thread->OpDispatcher->InvalidOp(DecodedInfo); - Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(IR::SizeToOpSize(GPRSize), Block.Entry - GuestRIP)); - } - - const bool NeedsBlockEnd = (HadDispatchError && TotalInstructions > 0) || - (Thread->OpDispatcher->NeedsBlockEnder() && i + 1 == InstsInBlock); - - // If we had a dispatch error then leave early - if (HadDispatchError && TotalInstructions == 0) { - // Couldn't handle any instruction in op dispatcher - Thread->OpDispatcher->ResetWorkingList(); - return { nullptr, nullptr, 0, 0, 0, 0 }; - } - - if (NeedsBlockEnd) { - const uint8_t GPRSize = GetGPRSize(); - - // We had some instructions. Early exit - Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(IR::SizeToOpSize(GPRSize), Block.Entry + BlockInstructionsLength - GuestRIP)); - break; - } - - - if (Thread->OpDispatcher->FinishOp(DecodedInfo->PC + DecodedInfo->InstSize, i + 1 == InstsInBlock)) { - break; - } - } - } - - Thread->OpDispatcher->Finalize(); - - Thread->FrontendDecoder->DelayedDisownBuffer(); - } - - IR::IREmitter *IREmitter = Thread->OpDispatcher.get(); - - auto ShouldDump = Thread->OpDispatcher->ShouldDumpIR(); - // Debug - { - if (ShouldDump) { - IRDumper(Thread, IREmitter, GuestRIP, nullptr); - } - - if (static_cast(Thread->CTX)->Config.ValidateIRarser) { - ValidateIR(this, IREmitter); - } - } - - // Run the passmanager over the IR from the dispatcher - Thread->PassManager->Run(IREmitter); - - // Debug - { - if (ShouldDump) { - IRDumper(Thread, IREmitter, GuestRIP, Thread->PassManager->HasPass("RA") ? Thread->PassManager->GetPass("RA")->GetAllocationData() : nullptr); - } - } - - auto RAData = Thread->PassManager->HasPass("RA") ? Thread->PassManager->GetPass("RA")->PullAllocationData() : nullptr; - auto IRList = IREmitter->CreateIRCopy(); - - IREmitter->DelayedDisownBuffer(); - - return { - .IRList = IRList, - .RAData = std::move(RAData), - .TotalInstructions = TotalInstructions, - .TotalInstructionsLength = TotalInstructionsLength, - .StartAddr = Thread->FrontendDecoder->DecodedMinAddress, - .Length = Thread->FrontendDecoder->DecodedMaxAddress - Thread->FrontendDecoder->DecodedMinAddress, - }; - } - - ContextImpl::CompileCodeResult ContextImpl::CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, uint64_t MaxInst) { - FEXCore::IR::IRListView *IRList {}; - FEXCore::Core::DebugData *DebugData {}; - FEXCore::IR::RegisterAllocationData::UniquePtr RAData {}; - bool GeneratedIR {}; - uint64_t StartAddr {}; - uint64_t Length {}; - - // JIT Code object cache lookup - if (CodeObjectCacheService) { - auto CodeCacheEntry = CodeObjectCacheService->FetchCodeObjectFromCache(GuestRIP); - if (CodeCacheEntry) { - auto CompiledCode = Thread->CPUBackend->RelocateJITObjectCode(GuestRIP, CodeCacheEntry); - if (CompiledCode) { - return { - .CompiledCode = CompiledCode, - .IRData = nullptr, // No IR data generated - .DebugData = nullptr, // nullptr here ensures that code serialization doesn't occur on from cache read - .RAData = nullptr, // No RA data generated - .GeneratedIR = false, // nullptr here ensures IR cache mechanisms won't run - .StartAddr = 0, // Unused - .Length = 0, // Unused - }; - } - } - } - - if (SourcecodeResolver && Config.GDBSymbols()) { - auto AOTIRCacheEntry = SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); - if (AOTIRCacheEntry.Entry && !AOTIRCacheEntry.Entry->ContainsCode) { - AOTIRCacheEntry.Entry->SourcecodeMap = - SourcecodeResolver->GenerateMap(AOTIRCacheEntry.Entry->Filename, AOTIRCacheEntry.Entry->FileId); - } - } - - // AOT IR bookkeeping and cache - { - auto [IRCopy, RACopy, DebugDataCopy, _StartAddr, _Length, _GeneratedIR] = IRCaptureCache.PreGenerateIRFetch(Thread, GuestRIP, IRList); - if (_GeneratedIR) { - // Setup pointers to internal structures - IRList = IRCopy; - RAData = std::move(RACopy); - DebugData = DebugDataCopy; - StartAddr = _StartAddr; - Length = _Length; - GeneratedIR = _GeneratedIR; - } - } - - if (IRList == nullptr) { - // Generate IR + Meta Info - auto [IRCopy, RACopy, TotalInstructions, TotalInstructionsLength, _StartAddr, _Length] = GenerateIR(Thread, GuestRIP, Config.GDBSymbols(), MaxInst); - - // Setup pointers to internal structures - IRList = IRCopy; - RAData = std::move(RACopy); - DebugData = new FEXCore::Core::DebugData(); - StartAddr = _StartAddr; - Length = _Length; - - // These blocks aren't already in the cache - GeneratedIR = true; - } - - if (IRList == nullptr) { - return {}; - } - // Attempt to get the CPU backend to compile this code - return { - // FEX currently throws away the CPUBackend::CompiledCode object other than the entrypoint - // In the future with code caching getting wired up, we will pass the rest of the data forward. - // TODO: Pass the data forward when code caching is wired up to this. - .CompiledCode = Thread->CPUBackend->CompileCode(GuestRIP, IRList, DebugData, RAData.get()).BlockEntry, - .IRData = IRList, - .DebugData = DebugData, - .RAData = std::move(RAData), - .GeneratedIR = GeneratedIR, - .StartAddr = StartAddr, - .Length = Length, - }; - } - - uintptr_t ContextImpl::CompileBlock(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP, uint64_t MaxInst) { - FEXCORE_PROFILE_SCOPED("CompileBlock"); - auto Thread = Frame->Thread; - -#ifdef _M_ARM_64EC - // If the target PC is EC code, mark it in the L2 and return straight to the dispatcher - // so it can handle the call/return. - if (Thread->LookupCache->CheckPageEC(GuestRIP)) { - return GuestRIP; - } +#ifndef _WIN32 + ThunkHandler = FEXCore::ThunkHandler::Create(); +#else + // WIN32 always needs the interrupt fault check to be enabled. + Config.NeedsPendingInterruptFaultCheck = true; #endif - // Invalidate might take a unique lock on this, to guarantee that during invalidation no code gets compiled - auto lk = GuardSignalDeferringSection(CodeInvalidationMutex, Thread); - - // Is the code in the cache? - // The backends only check L1 and L2, not L3 - if (auto HostCode = Thread->LookupCache->FindBlock(GuestRIP)) { - return HostCode; - } - - void *CodePtr {}; - FEXCore::IR::IRListView *IRList {}; - FEXCore::Core::DebugData *DebugData {}; - - bool GeneratedIR {}; - uint64_t StartAddr {}, Length {}; - - auto [Code, IR, Data, RAData, Generated, _StartAddr, _Length] = CompileCode(Thread, GuestRIP, MaxInst); - CodePtr = Code; - IRList = IR; - DebugData = Data; - GeneratedIR = Generated; - StartAddr = _StartAddr; - Length = _Length; - - if (CodePtr == nullptr) { - return 0; - } - - // The core managed to compile the code. - if (Config.BlockJITNaming()) { - auto FragmentBasePtr = reinterpret_cast(CodePtr); - - if (DebugData) { - auto GuestRIPLookup = SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); - - if (DebugData->Subblocks.size()) { - for (auto& Subblock: DebugData->Subblocks) { - auto BlockBasePtr = FragmentBasePtr + Subblock.HostCodeOffset; - if (GuestRIPLookup.Entry) { - Symbols.Register(Thread->SymbolBuffer.get(), BlockBasePtr, DebugData->HostCodeSize, GuestRIPLookup.Entry->Filename, GuestRIP - GuestRIPLookup.VAFileStart); - } else { - Symbols.Register(Thread->SymbolBuffer.get(), BlockBasePtr, GuestRIP, Subblock.HostCodeSize); - } - } - } else { - if (GuestRIPLookup.Entry) { - Symbols.Register(Thread->SymbolBuffer.get(), FragmentBasePtr, DebugData->HostCodeSize, GuestRIPLookup.Entry->Filename, GuestRIP - GuestRIPLookup.VAFileStart); - } else { - Symbols.Register(Thread->SymbolBuffer.get(), FragmentBasePtr, GuestRIP, DebugData->HostCodeSize); - } - } - } - } - - // Tell the object cache service to serialize the code if enabled - if (CodeObjectCacheService && - Config.CacheObjectCodeCompilation == FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READWRITE && - DebugData) { - CodeObjectCacheService->AsyncAddSerializationJob(fextl::make_unique( - CodeSerialize::AsyncJobHandler::SerializationJobData { - .GuestRIP = GuestRIP, - .GuestCodeLength = Length, - .GuestCodeHash = 0, - .HostCodeBegin = CodePtr, - .HostCodeLength = DebugData->HostCodeSize, - .HostCodeHash = 0, - .ThreadJobRefCount = &Thread->ObjectCacheRefCounter, - .Relocations = std::move(*DebugData->Relocations), - } - )); - } - - // Clear any relocations that might have been generated - Thread->CPUBackend->ClearRelocations(); - - if (IRCaptureCache.PostCompileCode( - Thread, - CodePtr, - GuestRIP, - StartAddr, - Length, - std::move(RAData), - IRList, - DebugData, - GeneratedIR)) { - // Early exit - return (uintptr_t)CodePtr; - } - - // Insert to lookup cache - // Pages containing this block are added via AddBlockExecutableRange before each page gets accessed in the frontend - AddBlockMapping(Thread, GuestRIP, CodePtr); - - return (uintptr_t)CodePtr; + if (Config.GdbServer) { + // If gdbserver is enabled then this needs to be enabled. + Config.NeedsPendingInterruptFaultCheck = true; + // FEX needs to start paused when gdb is enabled. + StartPaused = true; } - void ContextImpl::ExecutionThread(FEXCore::Core::InternalThreadState *Thread) { - Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_WAITING; + return true; +} - InitializeThreadTLSData(Thread); +void ContextImpl::HandleCallback(FEXCore::Core::InternalThreadState* Thread, uint64_t RIP) { + static_cast(Thread->CTX)->Dispatcher->ExecuteJITCallback(Thread->CurrentFrame, RIP); +} - // Now notify the thread that we are initialized - Thread->ThreadWaiting.NotifyAll(); +FEXCore::Context::ExitReason ContextImpl::RunUntilExit(FEXCore::Core::InternalThreadState* Thread) { + ExecutionThread(Thread); + while (true) { + auto reason = Thread->ExitReason; - if (StartPaused || Thread->StartPaused) { - // Parent thread doesn't need to wait to run - Thread->StartRunning.Wait(); + // Don't return if a custom exit handling the exit + if (!CustomExitHandler || reason == ExitReason::EXIT_SHUTDOWN) { + return reason; } + } +} - if (!Thread->RunningEvents.EarlyExit.load()) { - Thread->RunningEvents.WaitingToStart = false; +void ContextImpl::ExecuteThread(FEXCore::Core::InternalThreadState* Thread) { + Dispatcher->ExecuteDispatch(Thread->CurrentFrame); +} - Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_NONE; - Thread->RunningEvents.Running = true; +void ContextImpl::InitializeThreadTLSData(FEXCore::Core::InternalThreadState* Thread) { + // Let's do some initial bookkeeping here + Thread->ThreadManager.TID = FHU::Syscalls::gettid(); + Thread->ThreadManager.PID = ::getpid(); - static_cast(Thread->CTX)->Dispatcher->ExecuteDispatch(Thread->CurrentFrame); + if (ThunkHandler) { + ThunkHandler->RegisterTLSState(Thread); + } +#ifndef _WIN32 + Alloc::OSAllocator::RegisterTLSData(Thread); +#endif +} - Thread->RunningEvents.Running = false; - } +void ContextImpl::InitializeCompiler(FEXCore::Core::InternalThreadState* Thread) { + Thread->OpDispatcher = fextl::make_unique(this); + Thread->OpDispatcher->SetMultiblock(Config.Multiblock); + Thread->LookupCache = fextl::make_unique(this); + Thread->FrontendDecoder = fextl::make_unique(this); + Thread->PassManager = fextl::make_unique(); - { - // Ensure the Code Object Serialization service has fully serialized this thread's data before clearing the cache - // Use the thread's object cache ref counter for this - CodeSerialize::CodeObjectSerializeService::WaitForEmptyJobQueue(&Thread->ObjectCacheRefCounter); - } + Thread->CurrentFrame->Pointers.Common.L1Pointer = Thread->LookupCache->GetL1Pointer(); + Thread->CurrentFrame->Pointers.Common.L2Pointer = Thread->LookupCache->GetPagePointer(); - // If it is the parent thread that died then just leave - FEX_TODO("This doesn't make sense when the parent thread doesn't outlive its children"); + Dispatcher->InitThreadPointers(Thread); - if (Thread->ThreadManager.parent_tid == 0) { - CoreShuttingDown.store(true); - Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_SHUTDOWN; + Thread->CTX = this; - if (CustomExitHandler) { - CustomExitHandler(Thread->ThreadManager.TID, Thread->ExitReason); - } - } + Thread->PassManager->AddDefaultPasses(this, Config.Core == FEXCore::Config::CONFIG_IRJIT); + Thread->PassManager->AddDefaultValidationPasses(); + Thread->PassManager->RegisterSyscallHandler(SyscallHandler); + + // Create CPU backend + switch (Config.Core) { + case FEXCore::Config::CONFIG_IRJIT: + Thread->PassManager->InsertRegisterAllocationPass(HostFeatures.SupportsAVX); + Thread->CPUBackend = FEXCore::CPU::CreateArm64JITCore(this, Thread); + break; + case FEXCore::Config::CONFIG_CUSTOM: Thread->CPUBackend = CustomCPUFactory(this, Thread); break; + default: ERROR_AND_DIE_FMT("Unknown core configuration"); break; + } + + Thread->PassManager->Finalize(); +} + +FEXCore::Core::InternalThreadState* +ContextImpl::CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState, uint64_t ParentTID) { + FEXCore::Core::InternalThreadState* Thread = new FEXCore::Core::InternalThreadState {}; + + Thread->CurrentFrame->State.gregs[X86State::REG_RSP] = StackPointer; + Thread->CurrentFrame->State.rip = InitialRIP; + + // Copy over the new thread state to the new object + if (NewThreadState) { + memcpy(&Thread->CurrentFrame->State, NewThreadState, sizeof(FEXCore::Core::CPUState)); + } + + // Set up the thread manager state + Thread->ThreadManager.parent_tid = ParentTID; + Thread->CurrentFrame->Thread = Thread; + + InitializeCompiler(Thread); + + Thread->CurrentFrame->State.DeferredSignalRefCount.Store(0); + Thread->CurrentFrame->State.DeferredSignalFaultAddress = + reinterpret_cast*>(FEXCore::Allocator::VirtualAlloc(4096)); + + if (Config.BlockJITNaming() || Config.GlobalJITNaming() || Config.LibraryJITNaming()) { + // Allocate a JIT symbol buffer only if enabled. + Thread->SymbolBuffer = JITSymbols::AllocateBuffer(); + } + + return Thread; +} + +void ContextImpl::DestroyThread(FEXCore::Core::InternalThreadState* Thread, bool NeedsTLSUninstall) { + if (NeedsTLSUninstall) { #ifndef _WIN32 Alloc::OSAllocator::UninstallTLSData(Thread); #endif } - static void InvalidateGuestThreadCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) { - std::lock_guard lk(Thread->LookupCache->WriteLock); + FEXCore::Allocator::VirtualFree(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096); + delete Thread; +} - auto lower = Thread->LookupCache->CodePages.lower_bound(Start >> 12); - auto upper = Thread->LookupCache->CodePages.upper_bound((Start + Length - 1) >> 12); +#ifndef _WIN32 +void ContextImpl::UnlockAfterFork(FEXCore::Core::InternalThreadState* LiveThread, bool Child) { + Allocator::UnlockAfterFork(LiveThread, Child); - for (auto it = lower; it != upper; it++) { - for (auto Address: it->second) { - ContextImpl::ThreadRemoveCodeEntry(Thread, Address); - } - it->second.clear(); - } - } - - void ContextImpl::InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) { - InvalidateGuestThreadCodeRange(Thread, Start, Length); - } - - void ContextImpl::InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length, CodeRangeInvalidationFn CallAfter) { - InvalidateGuestThreadCodeRange(Thread, Start, Length); - CallAfter(Start, Length); - } - - void ContextImpl::MarkMemoryShared(FEXCore::Core::InternalThreadState *Thread) { - if (!IsMemoryShared) { - IsMemoryShared = true; - UpdateAtomicTSOEmulationConfig(); - - if (Config.TSOAutoMigration) { - // Only the lookup cache is cleared here, so that old code can keep running until next compilation - std::lock_guard lkLookupCache(Thread->LookupCache->WriteLock); - Thread->LookupCache->ClearCache(); - } - } - } - - void ContextImpl::ThreadAddBlockLink(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestDestination, FEXCore::Context::ExitFunctionLinkData *HostLink, const FEXCore::Context::BlockDelinkerFunc &delinker) { - auto lk = GuardSignalDeferringSection(static_cast(Thread->CTX)->CodeInvalidationMutex, Thread); - - Thread->LookupCache->AddBlockLink(GuestDestination, HostLink, delinker); - } - - void ContextImpl::ThreadRemoveCodeEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) { - LogMan::Throw::AFmt(static_cast(Thread->CTX)->CodeInvalidationMutex.try_lock() == false, "CodeInvalidationMutex needs to be unique_locked here"); - - std::lock_guard lk(Thread->LookupCache->WriteLock); - - Thread->LookupCache->Erase(Thread->CurrentFrame, GuestRIP); - } - - CustomIRResult ContextImpl::AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void *Creator, void *Data) { - LOGMAN_THROW_A_FMT(Config.Is64BitMode || !(Entrypoint >> 32), "64-bit Entrypoint in 32-bit mode {:x}", Entrypoint); - - std::unique_lock lk(CustomIRMutex); - - auto InsertedIterator = CustomIRHandlers.emplace(Entrypoint, std::tuple(Handler, Creator, Data)); - HasCustomIRHandlers = true; - - if (!InsertedIterator.second) { - const auto &[fn, Creator, Data] = InsertedIterator.first->second; - return CustomIRResult(std::move(lk), Creator, Data); - } else { - lk.unlock(); - return CustomIRResult(std::move(lk), 0, 0); - } - } - - void ContextImpl::RemoveCustomIREntrypoint(uintptr_t Entrypoint) { - LOGMAN_THROW_A_FMT(Config.Is64BitMode || !(Entrypoint >> 32), "64-bit Entrypoint in 32-bit mode {:x}", Entrypoint); - - std::scoped_lock lk(CustomIRMutex); - - InvalidateGuestCodeRange(nullptr, Entrypoint, 1, [this](uint64_t Entrypoint, uint64_t) { - CustomIRHandlers.erase(Entrypoint); - }); - - HasCustomIRHandlers = !CustomIRHandlers.empty(); - } - - IR::AOTIRCacheEntry *ContextImpl::LoadAOTIRCacheEntry(const fextl::string &filename) { - auto rv = IRCaptureCache.LoadAOTIRCacheEntry(filename); - return rv; - } - - void ContextImpl::UnloadAOTIRCacheEntry(IR::AOTIRCacheEntry *Entry) { - IRCaptureCache.UnloadAOTIRCacheEntry(Entry); - } - - void ContextImpl::AppendThunkDefinitions(fextl::vector const& Definitions) { - if (ThunkHandler) { - ThunkHandler->AppendThunkDefinitions(Definitions); - } - } - - void ContextImpl::ConfigureAOTGen(FEXCore::Core::InternalThreadState *Thread, fextl::set *ExternalBranches, uint64_t SectionMaxAddress) { - Thread->FrontendDecoder->SetExternalBranches(ExternalBranches); - Thread->FrontendDecoder->SetSectionMaxAddress(SectionMaxAddress); + if (Child) { + CodeInvalidationMutex.StealAndDropActiveLocks(); + } else { + CodeInvalidationMutex.unlock(); + return; } } + +void ContextImpl::LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) { + CodeInvalidationMutex.lock(); + Allocator::LockBeforeFork(Thread); +} +#endif + +void ContextImpl::AddBlockMapping(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, void* Ptr) { + Thread->LookupCache->AddBlockMapping(Address, Ptr); +} + +void ContextImpl::ClearCodeCache(FEXCore::Core::InternalThreadState* Thread) { + FEXCORE_PROFILE_INSTANT("ClearCodeCache"); + + { + // Ensure the Code Object Serialization service has fully serialized this thread's data before clearing the cache + // Use the thread's object cache ref counter for this + CodeSerialize::CodeObjectSerializeService::WaitForEmptyJobQueue(&Thread->ObjectCacheRefCounter); + } + std::lock_guard lk(Thread->LookupCache->WriteLock); + + Thread->LookupCache->ClearCache(); + Thread->CPUBackend->ClearCache(); +} + +static void IRDumper(FEXCore::Core::InternalThreadState* Thread, IR::IREmitter* IREmitter, uint64_t GuestRIP, IR::RegisterAllocationData* RA) { + FEXCore::File::File FD = FEXCore::File::File::GetStdERR(); + fextl::stringstream out; + auto NewIR = IREmitter->ViewIR(); + FEXCore::IR::Dump(&out, &NewIR, RA); + fextl::fmt::print(FD, "IR-ShouldDump-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", GuestRIP, out.str()); +}; + +static void ValidateIR(ContextImpl* ctx, IR::IREmitter* IREmitter) { + // Convert to text, Parse, Convert to text again and make sure the texts match + fextl::stringstream out; + static auto compaction = IR::CreateIRCompaction(ctx->OpDispatcherAllocator); + compaction->Run(IREmitter); + auto NewIR = IREmitter->ViewIR(); + Dump(&out, &NewIR, nullptr); + out.seekg(0); + FEXCore::Utils::PooledAllocatorMalloc Allocator; + auto reparsed = IR::Parse(Allocator, out); + if (reparsed == nullptr) { + LOGMAN_MSG_A_FMT("Failed to parse IR\n"); + } else { + fextl::stringstream out2; + auto NewIR2 = reparsed->ViewIR(); + Dump(&out2, &NewIR2, nullptr); + if (out.str() != out2.str()) { + LogMan::Msg::IFmt("one:\n {}", out.str()); + LogMan::Msg::IFmt("two:\n {}", out2.str()); + LOGMAN_MSG_A_FMT("Parsed IR doesn't match\n"); + } + } +} + +ContextImpl::GenerateIRResult +ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, bool ExtendedDebugInfo, uint64_t MaxInst) { + FEXCORE_PROFILE_SCOPED("GenerateIR"); + + Thread->OpDispatcher->ReownOrClaimBuffer(); + Thread->OpDispatcher->ResetWorkingList(); + + uint64_t TotalInstructions {0}; + uint64_t TotalInstructionsLength {0}; + + bool HasCustomIR {}; + + if (HasCustomIRHandlers.load(std::memory_order_relaxed)) { + std::shared_lock lk(CustomIRMutex); + auto Handler = CustomIRHandlers.find(GuestRIP); + if (Handler != CustomIRHandlers.end()) { + TotalInstructions = 1; + TotalInstructionsLength = 1; + std::get<0>(Handler->second)(GuestRIP, Thread->OpDispatcher.get()); + HasCustomIR = true; + } + } + + if (!HasCustomIR) { + const uint8_t* GuestCode {}; + GuestCode = reinterpret_cast(GuestRIP); + + bool HadDispatchError {false}; + + Thread->FrontendDecoder->DecodeInstructionsAtEntry(GuestCode, GuestRIP, MaxInst, + [Thread](uint64_t BlockEntry, uint64_t Start, uint64_t Length) { + if (Thread->LookupCache->AddBlockExecutableRange(BlockEntry, Start, Length)) { + static_cast(Thread->CTX)->SyscallHandler->MarkGuestExecutableRange(Thread, Start, Length); + } + }); + + auto BlockInfo = Thread->FrontendDecoder->GetDecodedBlockInfo(); + auto CodeBlocks = &BlockInfo->Blocks; + + Thread->OpDispatcher->BeginFunction(GuestRIP, CodeBlocks, BlockInfo->TotalInstructionCount); + + const uint8_t GPRSize = GetGPRSize(); + + for (size_t j = 0; j < CodeBlocks->size(); ++j) { + const FEXCore::Frontend::Decoder::DecodedBlocks& Block = CodeBlocks->at(j); + // Set the block entry point + Thread->OpDispatcher->SetNewBlockIfChanged(Block.Entry); + + uint64_t BlockInstructionsLength {}; + + // Reset any block-specific state + Thread->OpDispatcher->StartNewBlock(); + + uint64_t InstsInBlock = Block.NumInstructions; + + for (size_t i = 0; i < InstsInBlock; ++i) { + const FEXCore::X86Tables::X86InstInfo* TableInfo {nullptr}; + const FEXCore::X86Tables::DecodedInst* DecodedInfo {nullptr}; + + TableInfo = Block.DecodedInstructions[i].TableInfo; + DecodedInfo = &Block.DecodedInstructions[i]; + bool IsLocked = DecodedInfo->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK; + + if (ExtendedDebugInfo || Thread->OpDispatcher->CanHaveSideEffects(TableInfo, DecodedInfo)) { + Thread->OpDispatcher->_GuestOpcode(Block.Entry + BlockInstructionsLength - GuestRIP); + } + + if (Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) { + auto ExistingCodePtr = reinterpret_cast(Block.Entry + BlockInstructionsLength); + + auto CodeChanged = Thread->OpDispatcher->_ValidateCode(ExistingCodePtr[0], ExistingCodePtr[1], + (uintptr_t)ExistingCodePtr - GuestRIP, DecodedInfo->InstSize); + + auto InvalidateCodeCond = Thread->OpDispatcher->CondJump(CodeChanged); + + auto CurrentBlock = Thread->OpDispatcher->GetCurrentBlock(); + auto CodeWasChangedBlock = Thread->OpDispatcher->CreateNewCodeBlockAtEnd(); + Thread->OpDispatcher->SetTrueJumpTarget(InvalidateCodeCond, CodeWasChangedBlock); + + Thread->OpDispatcher->SetCurrentCodeBlock(CodeWasChangedBlock); + Thread->OpDispatcher->_ThreadRemoveCodeEntry(); + Thread->OpDispatcher->_ExitFunction( + Thread->OpDispatcher->_EntrypointOffset(IR::SizeToOpSize(GPRSize), Block.Entry + BlockInstructionsLength - GuestRIP)); + + auto NextOpBlock = Thread->OpDispatcher->CreateNewCodeBlockAfter(CurrentBlock); + + Thread->OpDispatcher->SetFalseJumpTarget(InvalidateCodeCond, NextOpBlock); + Thread->OpDispatcher->SetCurrentCodeBlock(NextOpBlock); + } + + if (TableInfo && TableInfo->OpcodeDispatcher) { + auto Fn = TableInfo->OpcodeDispatcher; + Thread->OpDispatcher->ResetHandledLock(); + Thread->OpDispatcher->ResetDecodeFailure(); + std::invoke(Fn, Thread->OpDispatcher, DecodedInfo); + if (Thread->OpDispatcher->HadDecodeFailure()) { + HadDispatchError = true; + } else { + if (Thread->OpDispatcher->HasHandledLock() != IsLocked) { + HadDispatchError = true; + LogMan::Msg::EFmt("Missing LOCK HANDLER at 0x{:x}{{'{}'}}", Block.Entry + BlockInstructionsLength, TableInfo->Name ?: "UND"); + } + BlockInstructionsLength += DecodedInfo->InstSize; + TotalInstructionsLength += DecodedInfo->InstSize; + ++TotalInstructions; + } + } else { + if (TableInfo) { + LogMan::Msg::EFmt("Invalid or Unknown instruction: {} 0x{:x}", TableInfo->Name ?: "UND", Block.Entry - GuestRIP); + } + // Invalid instruction + Thread->OpDispatcher->InvalidOp(DecodedInfo); + Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(IR::SizeToOpSize(GPRSize), Block.Entry - GuestRIP)); + } + + const bool NeedsBlockEnd = + (HadDispatchError && TotalInstructions > 0) || (Thread->OpDispatcher->NeedsBlockEnder() && i + 1 == InstsInBlock); + + // If we had a dispatch error then leave early + if (HadDispatchError && TotalInstructions == 0) { + // Couldn't handle any instruction in op dispatcher + Thread->OpDispatcher->ResetWorkingList(); + return {nullptr, nullptr, 0, 0, 0, 0}; + } + + if (NeedsBlockEnd) { + const uint8_t GPRSize = GetGPRSize(); + + // We had some instructions. Early exit + Thread->OpDispatcher->_ExitFunction( + Thread->OpDispatcher->_EntrypointOffset(IR::SizeToOpSize(GPRSize), Block.Entry + BlockInstructionsLength - GuestRIP)); + break; + } + + + if (Thread->OpDispatcher->FinishOp(DecodedInfo->PC + DecodedInfo->InstSize, i + 1 == InstsInBlock)) { + break; + } + } + } + + Thread->OpDispatcher->Finalize(); + + Thread->FrontendDecoder->DelayedDisownBuffer(); + } + + IR::IREmitter* IREmitter = Thread->OpDispatcher.get(); + + auto ShouldDump = Thread->OpDispatcher->ShouldDumpIR(); + // Debug + { + if (ShouldDump) { + IRDumper(Thread, IREmitter, GuestRIP, nullptr); + } + + if (static_cast(Thread->CTX)->Config.ValidateIRarser) { + ValidateIR(this, IREmitter); + } + } + + // Run the passmanager over the IR from the dispatcher + Thread->PassManager->Run(IREmitter); + + // Debug + { + if (ShouldDump) { + IRDumper(Thread, IREmitter, GuestRIP, + Thread->PassManager->HasPass("RA") ? Thread->PassManager->GetPass("RA")->GetAllocationData() : nullptr); + } + } + + auto RAData = Thread->PassManager->HasPass("RA") ? Thread->PassManager->GetPass("RA")->PullAllocationData() : nullptr; + auto IRList = IREmitter->CreateIRCopy(); + + IREmitter->DelayedDisownBuffer(); + + return { + .IRList = IRList, + .RAData = std::move(RAData), + .TotalInstructions = TotalInstructions, + .TotalInstructionsLength = TotalInstructionsLength, + .StartAddr = Thread->FrontendDecoder->DecodedMinAddress, + .Length = Thread->FrontendDecoder->DecodedMaxAddress - Thread->FrontendDecoder->DecodedMinAddress, + }; +} + +ContextImpl::CompileCodeResult ContextImpl::CompileCode(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, uint64_t MaxInst) { + FEXCore::IR::IRListView* IRList {}; + FEXCore::Core::DebugData* DebugData {}; + FEXCore::IR::RegisterAllocationData::UniquePtr RAData {}; + bool GeneratedIR {}; + uint64_t StartAddr {}; + uint64_t Length {}; + + // JIT Code object cache lookup + if (CodeObjectCacheService) { + auto CodeCacheEntry = CodeObjectCacheService->FetchCodeObjectFromCache(GuestRIP); + if (CodeCacheEntry) { + auto CompiledCode = Thread->CPUBackend->RelocateJITObjectCode(GuestRIP, CodeCacheEntry); + if (CompiledCode) { + return { + .CompiledCode = CompiledCode, + .IRData = nullptr, // No IR data generated + .DebugData = nullptr, // nullptr here ensures that code serialization doesn't occur on from cache read + .RAData = nullptr, // No RA data generated + .GeneratedIR = false, // nullptr here ensures IR cache mechanisms won't run + .StartAddr = 0, // Unused + .Length = 0, // Unused + }; + } + } + } + + if (SourcecodeResolver && Config.GDBSymbols()) { + auto AOTIRCacheEntry = SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); + if (AOTIRCacheEntry.Entry && !AOTIRCacheEntry.Entry->ContainsCode) { + AOTIRCacheEntry.Entry->SourcecodeMap = SourcecodeResolver->GenerateMap(AOTIRCacheEntry.Entry->Filename, AOTIRCacheEntry.Entry->FileId); + } + } + + // AOT IR bookkeeping and cache + { + auto [IRCopy, RACopy, DebugDataCopy, _StartAddr, _Length, _GeneratedIR] = IRCaptureCache.PreGenerateIRFetch(Thread, GuestRIP, IRList); + if (_GeneratedIR) { + // Setup pointers to internal structures + IRList = IRCopy; + RAData = std::move(RACopy); + DebugData = DebugDataCopy; + StartAddr = _StartAddr; + Length = _Length; + GeneratedIR = _GeneratedIR; + } + } + + if (IRList == nullptr) { + // Generate IR + Meta Info + auto [IRCopy, RACopy, TotalInstructions, TotalInstructionsLength, _StartAddr, _Length] = + GenerateIR(Thread, GuestRIP, Config.GDBSymbols(), MaxInst); + + // Setup pointers to internal structures + IRList = IRCopy; + RAData = std::move(RACopy); + DebugData = new FEXCore::Core::DebugData(); + StartAddr = _StartAddr; + Length = _Length; + + // These blocks aren't already in the cache + GeneratedIR = true; + } + + if (IRList == nullptr) { + return {}; + } + // Attempt to get the CPU backend to compile this code + return { + // FEX currently throws away the CPUBackend::CompiledCode object other than the entrypoint + // In the future with code caching getting wired up, we will pass the rest of the data forward. + // TODO: Pass the data forward when code caching is wired up to this. + .CompiledCode = Thread->CPUBackend->CompileCode(GuestRIP, IRList, DebugData, RAData.get()).BlockEntry, + .IRData = IRList, + .DebugData = DebugData, + .RAData = std::move(RAData), + .GeneratedIR = GeneratedIR, + .StartAddr = StartAddr, + .Length = Length, + }; +} + +uintptr_t ContextImpl::CompileBlock(FEXCore::Core::CpuStateFrame* Frame, uint64_t GuestRIP, uint64_t MaxInst) { + FEXCORE_PROFILE_SCOPED("CompileBlock"); + auto Thread = Frame->Thread; + +#ifdef _M_ARM_64EC + // If the target PC is EC code, mark it in the L2 and return straight to the dispatcher + // so it can handle the call/return. + if (Thread->LookupCache->CheckPageEC(GuestRIP)) { + return GuestRIP; + } +#endif + + // Invalidate might take a unique lock on this, to guarantee that during invalidation no code gets compiled + auto lk = GuardSignalDeferringSection(CodeInvalidationMutex, Thread); + + // Is the code in the cache? + // The backends only check L1 and L2, not L3 + if (auto HostCode = Thread->LookupCache->FindBlock(GuestRIP)) { + return HostCode; + } + + void* CodePtr {}; + FEXCore::IR::IRListView* IRList {}; + FEXCore::Core::DebugData* DebugData {}; + + bool GeneratedIR {}; + uint64_t StartAddr {}, Length {}; + + auto [Code, IR, Data, RAData, Generated, _StartAddr, _Length] = CompileCode(Thread, GuestRIP, MaxInst); + CodePtr = Code; + IRList = IR; + DebugData = Data; + GeneratedIR = Generated; + StartAddr = _StartAddr; + Length = _Length; + + if (CodePtr == nullptr) { + return 0; + } + + // The core managed to compile the code. + if (Config.BlockJITNaming()) { + auto FragmentBasePtr = reinterpret_cast(CodePtr); + + if (DebugData) { + auto GuestRIPLookup = SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); + + if (DebugData->Subblocks.size()) { + for (auto& Subblock : DebugData->Subblocks) { + auto BlockBasePtr = FragmentBasePtr + Subblock.HostCodeOffset; + if (GuestRIPLookup.Entry) { + Symbols.Register(Thread->SymbolBuffer.get(), BlockBasePtr, DebugData->HostCodeSize, GuestRIPLookup.Entry->Filename, + GuestRIP - GuestRIPLookup.VAFileStart); + } else { + Symbols.Register(Thread->SymbolBuffer.get(), BlockBasePtr, GuestRIP, Subblock.HostCodeSize); + } + } + } else { + if (GuestRIPLookup.Entry) { + Symbols.Register(Thread->SymbolBuffer.get(), FragmentBasePtr, DebugData->HostCodeSize, GuestRIPLookup.Entry->Filename, + GuestRIP - GuestRIPLookup.VAFileStart); + } else { + Symbols.Register(Thread->SymbolBuffer.get(), FragmentBasePtr, GuestRIP, DebugData->HostCodeSize); + } + } + } + } + + // Tell the object cache service to serialize the code if enabled + if (CodeObjectCacheService && Config.CacheObjectCodeCompilation == FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READWRITE && DebugData) { + CodeObjectCacheService->AsyncAddSerializationJob( + fextl::make_unique(CodeSerialize::AsyncJobHandler::SerializationJobData { + .GuestRIP = GuestRIP, + .GuestCodeLength = Length, + .GuestCodeHash = 0, + .HostCodeBegin = CodePtr, + .HostCodeLength = DebugData->HostCodeSize, + .HostCodeHash = 0, + .ThreadJobRefCount = &Thread->ObjectCacheRefCounter, + .Relocations = std::move(*DebugData->Relocations), + })); + } + + // Clear any relocations that might have been generated + Thread->CPUBackend->ClearRelocations(); + + if (IRCaptureCache.PostCompileCode(Thread, CodePtr, GuestRIP, StartAddr, Length, std::move(RAData), IRList, DebugData, GeneratedIR)) { + // Early exit + return (uintptr_t)CodePtr; + } + + // Insert to lookup cache + // Pages containing this block are added via AddBlockExecutableRange before each page gets accessed in the frontend + AddBlockMapping(Thread, GuestRIP, CodePtr); + + return (uintptr_t)CodePtr; +} + +void ContextImpl::ExecutionThread(FEXCore::Core::InternalThreadState* Thread) { + Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_WAITING; + + InitializeThreadTLSData(Thread); + + // Now notify the thread that we are initialized + Thread->ThreadWaiting.NotifyAll(); + + if (StartPaused || Thread->StartPaused) { + // Parent thread doesn't need to wait to run + Thread->StartRunning.Wait(); + } + + if (!Thread->RunningEvents.EarlyExit.load()) { + Thread->RunningEvents.WaitingToStart = false; + + Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_NONE; + + Thread->RunningEvents.Running = true; + + static_cast(Thread->CTX)->Dispatcher->ExecuteDispatch(Thread->CurrentFrame); + + Thread->RunningEvents.Running = false; + } + + { + // Ensure the Code Object Serialization service has fully serialized this thread's data before clearing the cache + // Use the thread's object cache ref counter for this + CodeSerialize::CodeObjectSerializeService::WaitForEmptyJobQueue(&Thread->ObjectCacheRefCounter); + } + + // If it is the parent thread that died then just leave + FEX_TODO("This doesn't make sense when the parent thread doesn't outlive its children"); + + if (Thread->ThreadManager.parent_tid == 0) { + CoreShuttingDown.store(true); + Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_SHUTDOWN; + + if (CustomExitHandler) { + CustomExitHandler(Thread->ThreadManager.TID, Thread->ExitReason); + } + } + +#ifndef _WIN32 + Alloc::OSAllocator::UninstallTLSData(Thread); +#endif +} + +static void InvalidateGuestThreadCodeRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) { + std::lock_guard lk(Thread->LookupCache->WriteLock); + + auto lower = Thread->LookupCache->CodePages.lower_bound(Start >> 12); + auto upper = Thread->LookupCache->CodePages.upper_bound((Start + Length - 1) >> 12); + + for (auto it = lower; it != upper; it++) { + for (auto Address : it->second) { + ContextImpl::ThreadRemoveCodeEntry(Thread, Address); + } + it->second.clear(); + } +} + +void ContextImpl::InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) { + InvalidateGuestThreadCodeRange(Thread, Start, Length); +} + +void ContextImpl::InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length, + CodeRangeInvalidationFn CallAfter) { + InvalidateGuestThreadCodeRange(Thread, Start, Length); + CallAfter(Start, Length); +} + +void ContextImpl::MarkMemoryShared(FEXCore::Core::InternalThreadState* Thread) { + if (!IsMemoryShared) { + IsMemoryShared = true; + UpdateAtomicTSOEmulationConfig(); + + if (Config.TSOAutoMigration) { + // Only the lookup cache is cleared here, so that old code can keep running until next compilation + std::lock_guard lkLookupCache(Thread->LookupCache->WriteLock); + Thread->LookupCache->ClearCache(); + } + } +} + +void ContextImpl::ThreadAddBlockLink(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestDestination, + FEXCore::Context::ExitFunctionLinkData* HostLink, const FEXCore::Context::BlockDelinkerFunc& delinker) { + auto lk = GuardSignalDeferringSection(static_cast(Thread->CTX)->CodeInvalidationMutex, Thread); + + Thread->LookupCache->AddBlockLink(GuestDestination, HostLink, delinker); +} + +void ContextImpl::ThreadRemoveCodeEntry(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP) { + LogMan::Throw::AFmt(static_cast(Thread->CTX)->CodeInvalidationMutex.try_lock() == false, "CodeInvalidationMutex needs to " + "be unique_locked here"); + + std::lock_guard lk(Thread->LookupCache->WriteLock); + + Thread->LookupCache->Erase(Thread->CurrentFrame, GuestRIP); +} + +CustomIRResult ContextImpl::AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void* Creator, void* Data) { + LOGMAN_THROW_A_FMT(Config.Is64BitMode || !(Entrypoint >> 32), "64-bit Entrypoint in 32-bit mode {:x}", Entrypoint); + + std::unique_lock lk(CustomIRMutex); + + auto InsertedIterator = CustomIRHandlers.emplace(Entrypoint, std::tuple(Handler, Creator, Data)); + HasCustomIRHandlers = true; + + if (!InsertedIterator.second) { + const auto& [fn, Creator, Data] = InsertedIterator.first->second; + return CustomIRResult(std::move(lk), Creator, Data); + } else { + lk.unlock(); + return CustomIRResult(std::move(lk), 0, 0); + } +} + +void ContextImpl::RemoveCustomIREntrypoint(uintptr_t Entrypoint) { + LOGMAN_THROW_A_FMT(Config.Is64BitMode || !(Entrypoint >> 32), "64-bit Entrypoint in 32-bit mode {:x}", Entrypoint); + + std::scoped_lock lk(CustomIRMutex); + + InvalidateGuestCodeRange(nullptr, Entrypoint, 1, [this](uint64_t Entrypoint, uint64_t) { CustomIRHandlers.erase(Entrypoint); }); + + HasCustomIRHandlers = !CustomIRHandlers.empty(); +} + +IR::AOTIRCacheEntry* ContextImpl::LoadAOTIRCacheEntry(const fextl::string& filename) { + auto rv = IRCaptureCache.LoadAOTIRCacheEntry(filename); + return rv; +} + +void ContextImpl::UnloadAOTIRCacheEntry(IR::AOTIRCacheEntry* Entry) { + IRCaptureCache.UnloadAOTIRCacheEntry(Entry); +} + +void ContextImpl::AppendThunkDefinitions(const fextl::vector& Definitions) { + if (ThunkHandler) { + ThunkHandler->AppendThunkDefinitions(Definitions); + } +} + +void ContextImpl::ConfigureAOTGen(FEXCore::Core::InternalThreadState* Thread, fextl::set* ExternalBranches, uint64_t SectionMaxAddress) { + Thread->FrontendDecoder->SetExternalBranches(ExternalBranches); + Thread->FrontendDecoder->SetSectionMaxAddress(SectionMaxAddress); +} +} // namespace FEXCore::Context diff --git a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp index 6d03baa43..879249967 100644 --- a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp +++ b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp @@ -25,13 +25,13 @@ namespace FEXCore::CPU { -static void SleepThread(FEXCore::Context::ContextImpl *CTX, FEXCore::Core::CpuStateFrame *Frame) { +static void SleepThread(FEXCore::Context::ContextImpl* CTX, FEXCore::Core::CpuStateFrame* Frame) { CTX->SyscallHandler->SleepThread(CTX, Frame); } constexpr size_t MAX_DISPATCHER_CODE_SIZE = 4096 * 2; -Dispatcher::Dispatcher(FEXCore::Context::ContextImpl *ctx) +Dispatcher::Dispatcher(FEXCore::Context::ContextImpl* ctx) : Arm64Emitter(ctx, FEXCore::Allocator::VirtualAlloc(MAX_DISPATCHER_CODE_SIZE, true), MAX_DISPATCHER_CODE_SIZE) , CTX {ctx} { EmitDispatcher(); @@ -85,9 +85,9 @@ void Dispatcher::EmitDispatcher() { // We want to ensure that we are 16 byte aligned at the top of this loop Align16B(); - ARMEmitter::BiDirectionalLabel FullLookup{}; - ARMEmitter::BiDirectionalLabel CallBlock{}; - ARMEmitter::BackwardLabel LoopTop{}; + ARMEmitter::BiDirectionalLabel FullLookup {}; + ARMEmitter::BiDirectionalLabel CallBlock {}; + ARMEmitter::BackwardLabel LoopTop {}; Bind(&LoopTop); AbsoluteLoopTopAddress = GetCursorAddress(); @@ -103,7 +103,7 @@ void Dispatcher::EmitDispatcher() { ldr(TMP1, STATE_PTR(CpuStateFrame, Pointers.Common.L1Pointer)); and_(ARMEmitter::Size::i64Bit, TMP4, RipReg.R(), LookupCache::L1_ENTRIES_MASK); - add(ARMEmitter::Size::i64Bit, TMP1, TMP1, TMP4, ARMEmitter::ShiftType::LSL , 4); + add(ARMEmitter::Size::i64Bit, TMP1, TMP1, TMP4, ARMEmitter::ShiftType::LSL, 4); ldp(TMP4, TMP1, TMP1, 0); sub(ARMEmitter::Size::i64Bit, TMP1, TMP1, RipReg); cbnz(ARMEmitter::Size::i64Bit, TMP1, &FullLookup); @@ -121,8 +121,7 @@ void Dispatcher::EmitDispatcher() { uint64_t VirtualMemorySize = CTX->Config.VirtualMemSize; if (std::popcount(VirtualMemorySize) == 1) { and_(ARMEmitter::Size::i64Bit, TMP4, RipReg.R(), VirtualMemorySize - 1); - } - else { + } else { LoadConstant(ARMEmitter::Size::i64Bit, TMP4, VirtualMemorySize); and_(ARMEmitter::Size::i64Bit, TMP4, RipReg.R(), TMP4); } @@ -210,9 +209,8 @@ void Dispatcher::EmitDispatcher() { ldr(ARMEmitter::XReg::x2, STATE_PTR(CpuStateFrame, Pointers.Common.ExitFunctionLink)); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r2); - } - else { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r2); + } else { blr(ARMEmitter::Reg::r2); } @@ -254,9 +252,8 @@ void Dispatcher::EmitDispatcher() { ldr(ARMEmitter::XReg::x4, &l_CompileBlock); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r4); - } - else { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r4); + } else { blr(ARMEmitter::Reg::r4); // { CTX, Frame, RIP, MaxInst } } @@ -302,7 +299,7 @@ void Dispatcher::EmitDispatcher() { { // Guest SIGTRAP handler // Needs to be distinct from the SignalHandlerReturnAddress - GuestSignal_SIGTRAP = GetCursorAddress(); + GuestSignal_SIGTRAP = GetCursorAddress(); SpillStaticRegs(TMP1); @@ -325,8 +322,7 @@ void Dispatcher::EmitDispatcher() { add(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::rsp, ARMEmitter::Reg::r0, 0); PopCalleeSavedRegisters(); ret(); - } - else { + } else { LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r1, 0); ldr(ARMEmitter::XReg::x1, ARMEmitter::Reg::r1); } @@ -345,9 +341,8 @@ void Dispatcher::EmitDispatcher() { mov(ARMEmitter::XReg::x1, STATE); ldr(ARMEmitter::XReg::x2, &l_Sleep); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r2); - } - else { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r2); + } else { blr(ARMEmitter::Reg::r2); } @@ -422,8 +417,7 @@ void Dispatcher::EmitDispatcher() { ldr(ARMEmitter::XReg::x3, R, Offset); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { + } else { blr(ARMEmitter::Reg::r3); } // Result is now in x0 @@ -480,23 +474,23 @@ void Dispatcher::EmitDispatcher() { } #ifdef VIXL_SIMULATOR -void Dispatcher::ExecuteDispatch(FEXCore::Core::CpuStateFrame *Frame) { +void Dispatcher::ExecuteDispatch(FEXCore::Core::CpuStateFrame* Frame) { Simulator.WriteXRegister(0, reinterpret_cast(Frame)); - Simulator.RunFrom(reinterpret_cast(DispatchPtr)); + Simulator.RunFrom(reinterpret_cast< const vixl::aarch64::Instruction*>(DispatchPtr)); } -void Dispatcher::ExecuteJITCallback(FEXCore::Core::CpuStateFrame *Frame, uint64_t RIP) { +void Dispatcher::ExecuteJITCallback(FEXCore::Core::CpuStateFrame* Frame, uint64_t RIP) { Simulator.WriteXRegister(0, reinterpret_cast(Frame)); Simulator.WriteXRegister(1, RIP); - Simulator.RunFrom(reinterpret_cast(CallbackPtr)); + Simulator.RunFrom(reinterpret_cast< const vixl::aarch64::Instruction*>(CallbackPtr)); } #endif -void Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState *Thread) { +void Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState* Thread) { // Setup dispatcher specific pointers that need to be accessed from JIT code { - auto &Common = Thread->CurrentFrame->Pointers.Common; + auto& Common = Thread->CurrentFrame->Pointers.Common; Common.DispatcherLoopTop = AbsoluteLoopTopAddress; Common.DispatcherLoopTopFillSRA = AbsoluteLoopTopAddressFillSRA; @@ -509,7 +503,7 @@ void Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState *Thread) Common.SignalReturnHandler = SignalHandlerReturnAddress; Common.SignalReturnHandlerRT = SignalHandlerReturnAddressRT; - auto &AArch64 = Thread->CurrentFrame->Pointers.AArch64; + auto& AArch64 = Thread->CurrentFrame->Pointers.AArch64; AArch64.LUDIVHandler = LUDIVHandlerAddress; AArch64.LDIVHandler = LDIVHandlerAddress; AArch64.LUREMHandler = LUREMHandlerAddress; @@ -517,8 +511,8 @@ void Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState *Thread) } } -fextl::unique_ptr Dispatcher::Create(FEXCore::Context::ContextImpl *CTX) { +fextl::unique_ptr Dispatcher::Create(FEXCore::Context::ContextImpl* CTX) { return fextl::make_unique(CTX); } -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h index b8f9e47cc..78cd7213d 100644 --- a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h +++ b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h @@ -23,7 +23,7 @@ struct GuestSigAction; namespace FEXCore::Core { struct CpuStateFrame; struct InternalThreadState; -} +} // namespace FEXCore::Core namespace FEXCore::Context { class ContextImpl; @@ -31,51 +31,50 @@ class ContextImpl; namespace FEXCore::CPU { -#define STATE_PTR(STATE_TYPE, FIELD) \ - STATE.R(), offsetof(FEXCore::Core::STATE_TYPE, FIELD) +#define STATE_PTR(STATE_TYPE, FIELD) STATE.R(), offsetof(FEXCore::Core::STATE_TYPE, FIELD) class Dispatcher final : public Arm64Emitter { public: - static fextl::unique_ptr Create(FEXCore::Context::ContextImpl *CTX); + static fextl::unique_ptr Create(FEXCore::Context::ContextImpl* CTX); - Dispatcher(FEXCore::Context::ContextImpl *ctx); + Dispatcher(FEXCore::Context::ContextImpl* ctx); ~Dispatcher(); /** * @name Dispatch Helper functions * @{ */ - uint64_t ThreadStopHandlerAddress{}; - uint64_t ThreadStopHandlerAddressSpillSRA{}; - uint64_t AbsoluteLoopTopAddress{}; - uint64_t AbsoluteLoopTopAddressFillSRA{}; - uint64_t ThreadPauseHandlerAddress{}; - uint64_t ThreadPauseHandlerAddressSpillSRA{}; - uint64_t ExitFunctionLinkerAddress{}; - uint64_t SignalHandlerReturnAddress{}; - uint64_t SignalHandlerReturnAddressRT{}; - uint64_t GuestSignal_SIGILL{}; - uint64_t GuestSignal_SIGTRAP{}; - uint64_t GuestSignal_SIGSEGV{}; - uint64_t IntCallbackReturnAddress{}; + uint64_t ThreadStopHandlerAddress {}; + uint64_t ThreadStopHandlerAddressSpillSRA {}; + uint64_t AbsoluteLoopTopAddress {}; + uint64_t AbsoluteLoopTopAddressFillSRA {}; + uint64_t ThreadPauseHandlerAddress {}; + uint64_t ThreadPauseHandlerAddressSpillSRA {}; + uint64_t ExitFunctionLinkerAddress {}; + uint64_t SignalHandlerReturnAddress {}; + uint64_t SignalHandlerReturnAddressRT {}; + uint64_t GuestSignal_SIGILL {}; + uint64_t GuestSignal_SIGTRAP {}; + uint64_t GuestSignal_SIGSEGV {}; + uint64_t IntCallbackReturnAddress {}; - uint64_t PauseReturnInstruction{}; + uint64_t PauseReturnInstruction {}; /** @} */ - uint64_t Start{}; - uint64_t End{}; + uint64_t Start {}; + uint64_t End {}; - void InitThreadPointers(FEXCore::Core::InternalThreadState *Thread); + void InitThreadPointers(FEXCore::Core::InternalThreadState* Thread); #ifdef VIXL_SIMULATOR - void ExecuteDispatch(FEXCore::Core::CpuStateFrame *Frame) ; - void ExecuteJITCallback(FEXCore::Core::CpuStateFrame *Frame, uint64_t RIP); + void ExecuteDispatch(FEXCore::Core::CpuStateFrame* Frame); + void ExecuteJITCallback(FEXCore::Core::CpuStateFrame* Frame, uint64_t RIP); #else - void ExecuteDispatch(FEXCore::Core::CpuStateFrame *Frame) { + void ExecuteDispatch(FEXCore::Core::CpuStateFrame* Frame) { DispatchPtr(Frame); } - void ExecuteJITCallback(FEXCore::Core::CpuStateFrame *Frame, uint64_t RIP) { + void ExecuteJITCallback(FEXCore::Core::CpuStateFrame* Frame, uint64_t RIP) { CallbackPtr(Frame, RIP); } #endif @@ -103,21 +102,21 @@ public: } protected: - FEXCore::Context::ContextImpl *CTX; + FEXCore::Context::ContextImpl* CTX; - using AsmDispatch = void(*)(FEXCore::Core::CpuStateFrame *Frame); - using JITCallback = void(*)(FEXCore::Core::CpuStateFrame *Frame, uint64_t RIP); + using AsmDispatch = void (*)(FEXCore::Core::CpuStateFrame* Frame); + using JITCallback = void (*)(FEXCore::Core::CpuStateFrame* Frame, uint64_t RIP); AsmDispatch DispatchPtr; JITCallback CallbackPtr; private: // Long division helpers - uint64_t LUDIVHandlerAddress{}; - uint64_t LDIVHandlerAddress{}; - uint64_t LUREMHandlerAddress{}; - uint64_t LREMHandlerAddress{}; + uint64_t LUDIVHandlerAddress {}; + uint64_t LDIVHandlerAddress {}; + uint64_t LUREMHandlerAddress {}; + uint64_t LREMHandlerAddress {}; void EmitDispatcher(); }; -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/Frontend.cpp b/FEXCore/Source/Interface/Core/Frontend.cpp index 60a86d7b9..eafab66c4 100644 --- a/FEXCore/Source/Interface/Core/Frontend.cpp +++ b/FEXCore/Source/Interface/Core/Frontend.cpp @@ -33,22 +33,10 @@ static uint32_t MapModRMToReg(uint8_t REX, uint8_t bits, bool HighBits, bool Has static constexpr GPRArray GPR8BitHighIndexes = { // Classical ordering? - FEXCore::X86State::REG_RAX, - FEXCore::X86State::REG_RCX, - FEXCore::X86State::REG_RDX, - FEXCore::X86State::REG_RBX, - FEXCore::X86State::REG_RAX, - FEXCore::X86State::REG_RCX, - FEXCore::X86State::REG_RDX, - FEXCore::X86State::REG_RBX, - FEXCore::X86State::REG_R8, - FEXCore::X86State::REG_R9, - FEXCore::X86State::REG_R10, - FEXCore::X86State::REG_R11, - FEXCore::X86State::REG_R12, - FEXCore::X86State::REG_R13, - FEXCore::X86State::REG_R14, - FEXCore::X86State::REG_R15, + FEXCore::X86State::REG_RAX, FEXCore::X86State::REG_RCX, FEXCore::X86State::REG_RDX, FEXCore::X86State::REG_RBX, + FEXCore::X86State::REG_RAX, FEXCore::X86State::REG_RCX, FEXCore::X86State::REG_RDX, FEXCore::X86State::REG_RBX, + FEXCore::X86State::REG_R8, FEXCore::X86State::REG_R9, FEXCore::X86State::REG_R10, FEXCore::X86State::REG_R11, + FEXCore::X86State::REG_R12, FEXCore::X86State::REG_R13, FEXCore::X86State::REG_R14, FEXCore::X86State::REG_R15, }; uint8_t Offset = (REX << 3) | bits; @@ -59,11 +47,9 @@ static uint32_t MapModRMToReg(uint8_t REX, uint8_t bits, bool HighBits, bool Has if (HasXMM) { return FEXCore::X86State::REG_XMM_0 + Offset; - } - else if (HasMM) { + } else if (HasMM) { return FEXCore::X86State::REG_MM_0 + Offset; - } - else if (!(HighBits && !HasREX)) { + } else if (!(HighBits && !HasREX)) { return FEXCore::X86State::REG_RAX + Offset; } @@ -78,11 +64,10 @@ static uint32_t MapVEXToReg(uint8_t vvvv, bool HasXMM) { } } -Decoder::Decoder(FEXCore::Context::ContextImpl *ctx) +Decoder::Decoder(FEXCore::Context::ContextImpl* ctx) : CTX {ctx} - , OSABI { ctx->SyscallHandler ? ctx->SyscallHandler->GetOSABI() : FEXCore::HLE::SyscallOSABI::OS_UNKNOWN } - , PoolObject {ctx->FrontendAllocator, sizeof(FEXCore::X86Tables::DecodedInst) * DefaultDecodedBufferSize} { -} + , OSABI {ctx->SyscallHandler ? ctx->SyscallHandler->GetOSABI() : FEXCore::HLE::SyscallOSABI::OS_UNKNOWN} + , PoolObject {ctx->FrontendAllocator, sizeof(FEXCore::X86Tables::DecodedInst) * DefaultDecodedBufferSize} {} Decoder::~Decoder() { PoolObject.UnclaimBuffer(); @@ -108,7 +93,7 @@ uint64_t Decoder::ReadData(uint8_t Size) { std::memcpy(&Res, &InstStream[InstructionSize], Size); #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - for(size_t i = 0; i < Size; ++i) { + for (size_t i = 0; i < Size; ++i) { ReadByte(); } #else @@ -118,7 +103,7 @@ uint64_t Decoder::ReadData(uint8_t Size) { return Res; } -void Decoder::DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM) { +void Decoder::DecodeModRM_16(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM) { // 16bit modrm behaves similar to SIB but encoded directly in modrm // mod != 0b11 case // RM | Result @@ -139,13 +124,11 @@ void Decoder::DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModR // if mod = 0b10 // All encodings gain 16bit displacement // 0b110 = [BP] + disp16 - uint32_t Literal{}; - uint8_t DisplacementSize{}; - if ((ModRM.mod == 0 && ModRM.rm == 0b110) || - ModRM.mod == 0b10) { + uint32_t Literal {}; + uint8_t DisplacementSize {}; + if ((ModRM.mod == 0 && ModRM.rm == 0b110) || ModRM.mod == 0b10) { DisplacementSize = 2; - } - else if (ModRM.mod == 0b01) { + } else if (ModRM.mod == 0b01) { DisplacementSize = 1; } if (DisplacementSize) { @@ -200,29 +183,25 @@ void Decoder::DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModR Operand->Data.SIB.Index = it.Index; } -void Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM) { - uint8_t Displacement{}; +void Decoder::DecodeModRM_64(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM) { + uint8_t Displacement {}; // Do we have an offset? if (ModRM.mod == 0b01) { Displacement = 1; - } - else if (ModRM.mod == 0b10) { + } else if (ModRM.mod == 0b10) { Displacement = 4; - } - else if (ModRM.mod == 0 && ModRM.rm == 0b101) { + } else if (ModRM.mod == 0 && ModRM.rm == 0b101) { Displacement = 4; } // Calculate SIB - bool HasSIB = ((ModRM.mod != 0b11) && - (ModRM.rm == 0b100)); + bool HasSIB = ((ModRM.mod != 0b11) && (ModRM.rm == 0b100)); if (HasSIB) { FEXCore::X86Tables::SIBDecoded SIB; if (DecodeInst->DecodedSIB) { SIB.Hex = DecodeInst->SIB; - } - else { + } else { // Haven't yet grabbed SIB, pull it now DecodeInst->SIB = ReadByte(); SIB.Hex = DecodeInst->SIB; @@ -250,7 +229,7 @@ void Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModR const uint8_t BaseREX = (DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B) != 0 ? 1 : 0; Operand->Data.SIB.Index = MapModRMToReg(IndexREX, SIB.index, false, false, IsIndexVector, false, 0b100); - Operand->Data.SIB.Base = MapModRMToReg(BaseREX, SIB.base, false, false, false, false, ModRM.mod == 0 ? 0b101 : 16); + Operand->Data.SIB.Base = MapModRMToReg(BaseREX, SIB.base, false, false, false, false, ModRM.mod == 0 ? 0b101 : 16); } LOGMAN_THROW_AA_FMT(Displacement <= 4, "Number of bytes should be <= 4 for literal src"); @@ -262,8 +241,7 @@ void Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModR } Operand->Data.SIB.Offset = Literal; } - } - else if (ModRM.mod == 0) { + } else if (ModRM.mod == 0) { // Explained in Table 1-14. "Operand Addressing Using ModRM and SIB Bytes" if (ModRM.rm == 0b101) { // 32bit Displacement @@ -271,14 +249,12 @@ void Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModR Operand->Type = DecodedOperand::OpType::RIPRelative; Operand->Data.RIPLiteral.Value.u = Literal; - } - else { + } else { // Register-direct addressing Operand->Type = DecodedOperand::OpType::GPRDirect; Operand->Data.GPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, false, false, false, false); } - } - else { + } else { uint8_t DisplacementSize = ModRM.mod == 1 ? 1 : 4; uint32_t Literal = ReadData(DisplacementSize); if (DisplacementSize == 1) { @@ -291,7 +267,7 @@ void Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModR } } -bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, DecodedHeader Options) { +bool Decoder::NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op, DecodedHeader Options) { DecodeInst->OP = Op; DecodeInst->TableInfo = Info; @@ -305,42 +281,41 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, return false; } - LOGMAN_THROW_AA_FMT(!(Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P), - "Group Ops should have been decoded before this!"); + LOGMAN_THROW_AA_FMT(!(Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P), "Group Ops " + "should have " + "been decoded " + "before this!"); - uint8_t DestSize{}; - const bool HasWideningDisplacement = (FEXCore::X86Tables::DecodeFlags::GetOpAddr(DecodeInst->Flags, 0) & FEXCore::X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST) != 0 || - (Options.w && CTX->Config.Is64BitMode); - const bool HasNarrowingDisplacement = (FEXCore::X86Tables::DecodeFlags::GetOpAddr(DecodeInst->Flags, 0) & FEXCore::X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST) != 0; + uint8_t DestSize {}; + const bool HasWideningDisplacement = + (FEXCore::X86Tables::DecodeFlags::GetOpAddr(DecodeInst->Flags, 0) & FEXCore::X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST) != 0 || + (Options.w && CTX->Config.Is64BitMode); + const bool HasNarrowingDisplacement = + (FEXCore::X86Tables::DecodeFlags::GetOpAddr(DecodeInst->Flags, 0) & FEXCore::X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST) != 0; const bool HasXMMFlags = (Info->Flags & InstFlags::FLAGS_XMM_FLAGS) != 0; - bool HasXMMSrc = HasXMMFlags && - !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_SRC_GPR) && - !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_SRC); - bool HasXMMDst = HasXMMFlags && - !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_DST_GPR) && - !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_DST); - bool HasMMSrc = HasXMMFlags && - !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_SRC_GPR) && - HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_SRC); - bool HasMMDst = HasXMMFlags && - !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_DST_GPR) && - HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_DST); + bool HasXMMSrc = + HasXMMFlags && !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_SRC_GPR) && !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_SRC); + bool HasXMMDst = + HasXMMFlags && !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_DST_GPR) && !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_DST); + bool HasMMSrc = + HasXMMFlags && !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_SRC_GPR) && HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_SRC); + bool HasMMDst = + HasXMMFlags && !HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_DST_GPR) && HAS_XMM_SUBFLAG(Info->Flags, InstFlags::FLAGS_SF_MMX_DST); // Is ModRM present via explicit instruction encoded or REX? const bool HasMODRM = !!(Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_MODRM); const bool HasREX = !!(DecodeInst->Flags & DecodeFlags::FLAG_REX_PREFIX); - const bool Has16BitAddressing = !CTX->Config.Is64BitMode && - DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE; + const bool Has16BitAddressing = !CTX->Config.Is64BitMode && DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE; // This is used for ModRM register modification // For both modrm.reg and modrm.rm(when mod == 0b11) when value is >= 0b100 // then it changes from expected registers to the high 8bits of the lower registers // Bit annoying to support // In the case of no modrm (REX in byte situation) then it is unaffected - bool Is8BitSrc{}; - bool Is8BitDest{}; + bool Is8BitSrc {}; + bool Is8BitDest {}; // If we require ModRM and haven't decoded it yet, do it now // Some instructions have to read modrm upfront, others do it later @@ -359,12 +334,10 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_8BIT); DestSize = 1; Is8BitDest = true; - } - else if (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_16BIT) { + } else if (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_16BIT) { DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_16BIT); DestSize = 2; - } - else if (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_128BIT) { + } else if (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_128BIT) { if (Options.L) { DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_256BIT); DestSize = 32; @@ -372,28 +345,21 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_128BIT); DestSize = 16; } - } - else if (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_256BIT) { + } else if (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_256BIT) { DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_256BIT); DestSize = 32; - } - else if (HasNarrowingDisplacement && - (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_DEF || - DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { + } else if (HasNarrowingDisplacement && + (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_DEF || DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { // See table 1-2. Operand-Size Overrides for this decoding // If the default operating mode is 32bit and we have the operand size flag then the operating size drops to 16bit DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_16BIT); DestSize = 2; - } - else if ( - (HasXMMDst || HasMMDst || CTX->Config.Is64BitMode) && - (HasWideningDisplacement || - DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BIT || - DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { + } else if ((HasXMMDst || HasMMDst || CTX->Config.Is64BitMode) && + (HasWideningDisplacement || DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BIT || + DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_64BIT); DestSize = 8; - } - else { + } else { DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_32BIT); DestSize = 4; } @@ -402,50 +368,41 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, if (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_8BIT) { DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_8BIT); Is8BitSrc = true; - } - else if (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_16BIT) { + } else if (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_16BIT) { DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_16BIT); - } - else if (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_128BIT) { + } else if (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_128BIT) { if (Options.L) { DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_256BIT); } else { DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_128BIT); } - } - else if (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_256BIT) { + } else if (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_256BIT) { DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_256BIT); - } - else if (HasNarrowingDisplacement && - (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_DEF || - SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { + } else if (HasNarrowingDisplacement && + (SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_DEF || SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { // See table 1-2. Operand-Size Overrides for this decoding // If the default operating mode is 32bit and we have the operand size flag then the operating size drops to 16bit DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_16BIT); - } - else if ( - (HasXMMSrc || HasMMSrc || CTX->Config.Is64BitMode) && - (HasWideningDisplacement || - SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BIT || - SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { + } else if ((HasXMMSrc || HasMMSrc || CTX->Config.Is64BitMode) && + (HasWideningDisplacement || SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BIT || + SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) { DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_64BIT); - } - else { + } else { DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_32BIT); } } - auto *CurrentDest = &DecodeInst->Dest; + auto* CurrentDest = &DecodeInst->Dest; if (HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_DST_RAX) || HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_DST_RDX)) { // Some instructions hardcode their destination as RAX CurrentDest->Type = DecodedOperand::OpType::GPR; CurrentDest->Data.GPR.HighBits = false; - CurrentDest->Data.GPR.GPR = HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_DST_RAX) ? FEXCore::X86State::REG_RAX : FEXCore::X86State::REG_RDX; + CurrentDest->Data.GPR.GPR = + HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_DST_RAX) ? FEXCore::X86State::REG_RAX : FEXCore::X86State::REG_RDX; CurrentDest = &DecodeInst->Src[0]; - } - else if (HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_REX_IN_BYTE)) { + } else if (HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_REX_IN_BYTE)) { LOGMAN_THROW_AA_FMT(!HasMODRM, "This instruction shouldn't have ModRM!"); // If the REX is in the byte that means the lower nibble of the OP contains the destination GPR @@ -454,10 +411,12 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, // If there is a REX prefix then that allows extended GPR usage CurrentDest->Type = DecodedOperand::OpType::GPR; DecodeInst->Dest.Data.GPR.HighBits = (Is8BitDest && !HasREX && (Op & 0b111) >= 0b100); - CurrentDest->Data.GPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, Op & 0b111, Is8BitDest, HasREX, false, false); + CurrentDest->Data.GPR.GPR = + MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, Op & 0b111, Is8BitDest, HasREX, false, false); - if (CurrentDest->Data.GPR.GPR == FEXCore::X86State::REG_INVALID) + if (CurrentDest->Data.GPR.GPR == FEXCore::X86State::REG_INVALID) { return false; + } } uint8_t Bytes = Info->MoreBytes; @@ -469,13 +428,13 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, Bytes >>= 1; } - if ((Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_MEM_OFFSET) && - (DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE)) { + if ((Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_MEM_OFFSET) && (DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE)) { // If we have a memory offset and have the address size override then divide it just like narrowing displacement Bytes >>= 1; } - auto ModRMOperand = [&](FEXCore::X86Tables::DecodedOperand &GPR, FEXCore::X86Tables::DecodedOperand &NonGPR, bool HasXMMGPR, bool HasXMMNonGPR, bool HasMMGPR, bool HasMMNonGPR, bool GPR8Bit, bool NonGPR8Bit) { + auto ModRMOperand = [&](FEXCore::X86Tables::DecodedOperand& GPR, FEXCore::X86Tables::DecodedOperand& NonGPR, bool HasXMMGPR, + bool HasXMMNonGPR, bool HasMMGPR, bool HasMMNonGPR, bool GPR8Bit, bool NonGPR8Bit) { FEXCore::X86Tables::ModRMDecoded ModRM; ModRM.Hex = DecodeInst->ModRM; @@ -484,19 +443,21 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, GPR.Data.GPR.HighBits = (GPR8Bit && ModRM.reg >= 0b100 && !HasREX); GPR.Data.GPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_R ? 1 : 0, ModRM.reg, GPR8Bit, HasREX, HasXMMGPR, HasMMGPR); - if (GPR.Data.GPR.GPR == FEXCore::X86State::REG_INVALID) + if (GPR.Data.GPR.GPR == FEXCore::X86State::REG_INVALID) { return false; + } // ModRM.mod == 0b11 == Register // ModRM.Mod != 0b11 == Register-direct addressing if (ModRM.mod == 0b11) { NonGPR.Type = DecodedOperand::OpType::GPR; NonGPR.Data.GPR.HighBits = (NonGPR8Bit && ModRM.rm >= 0b100 && !HasREX); - NonGPR.Data.GPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, NonGPR8Bit, HasREX, HasXMMNonGPR, HasMMNonGPR); - if (NonGPR.Data.GPR.GPR == FEXCore::X86State::REG_INVALID) + NonGPR.Data.GPR.GPR = + MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, NonGPR8Bit, HasREX, HasXMMNonGPR, HasMMNonGPR); + if (NonGPR.Data.GPR.GPR == FEXCore::X86State::REG_INVALID) { return false; - } - else { + } + } else { // Only decode if we haven't pre-decoded if (NonGPR.IsNone()) { auto Disp = DecodeModRMs_Disp[Has16BitAddressing]; @@ -523,12 +484,13 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, if (Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_MODRM) { if (Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SF_MOD_DST) { - if (!ModRMOperand(DecodeInst->Src[CurrentSrc], DecodeInst->Dest, HasXMMSrc, HasXMMDst, HasMMSrc, HasMMDst, Is8BitSrc, Is8BitDest)) + if (!ModRMOperand(DecodeInst->Src[CurrentSrc], DecodeInst->Dest, HasXMMSrc, HasXMMDst, HasMMSrc, HasMMDst, Is8BitSrc, Is8BitDest)) { return false; - } - else { - if (!ModRMOperand(DecodeInst->Dest, DecodeInst->Src[CurrentSrc], HasXMMDst, HasXMMSrc, HasMMDst, HasMMSrc, Is8BitDest, Is8BitSrc)) + } + } else { + if (!ModRMOperand(DecodeInst->Dest, DecodeInst->Src[CurrentSrc], HasXMMDst, HasXMMSrc, HasMMDst, HasMMSrc, Is8BitDest, Is8BitSrc)) { return false; + } } ++CurrentSrc; } @@ -545,8 +507,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, DecodeInst->Src[CurrentSrc].Data.GPR.HighBits = false; DecodeInst->Src[CurrentSrc].Data.GPR.GPR = FEXCore::X86State::REG_RAX; ++CurrentSrc; - } - else if (HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_SRC_RCX)) { + } else if (HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_SRC_RCX)) { DecodeInst->Src[CurrentSrc].Type = DecodedOperand::OpType::GPR; DecodeInst->Src[CurrentSrc].Data.GPR.HighBits = false; DecodeInst->Src[CurrentSrc].Data.GPR.GPR = FEXCore::X86State::REG_RCX; @@ -566,15 +527,13 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, uint64_t Literal = ReadData(Bytes); - if ((Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SRC_SEXT) || - (DecodeFlags::GetSizeDstFlags(DecodeInst->Flags) == DecodeFlags::SIZE_64BIT && Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SRC_SEXT64BIT)) { + if ((Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SRC_SEXT) || (DecodeFlags::GetSizeDstFlags(DecodeInst->Flags) == DecodeFlags::SIZE_64BIT && + Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SRC_SEXT64BIT)) { if (Bytes == 1) { Literal = static_cast(Literal); - } - else if (Bytes == 2) { + } else if (Bytes == 2) { Literal = static_cast(Literal); - } - else { + } else { Literal = static_cast(Literal); } DecodeInst->Src[CurrentSrc].Data.Literal.Size = DestSize; @@ -585,13 +544,13 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, DecodeInst->Src[CurrentSrc].Data.Literal.Value = Literal; } - LOGMAN_THROW_AA_FMT(Bytes == 0, "Inst at 0x{:x}: 0x{:04x} '{}' Had an instruction of size {} with {} remaining", - DecodeInst->PC, DecodeInst->OP, DecodeInst->TableInfo->Name ?: "UND", InstructionSize, Bytes); + LOGMAN_THROW_AA_FMT(Bytes == 0, "Inst at 0x{:x}: 0x{:04x} '{}' Had an instruction of size {} with {} remaining", DecodeInst->PC, + DecodeInst->OP, DecodeInst->TableInfo->Name ?: "UND", InstructionSize, Bytes); DecodeInst->InstSize = InstructionSize; return true; } -bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op) { +bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op) { DecodeInst->OP = Op; DecodeInst->TableInfo = Info; @@ -605,15 +564,12 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 return false; } - LOGMAN_THROW_AA_FMT(Info->Type != FEXCore::X86Tables::TYPE_REX_PREFIX, - "REX PREFIX should have been decoded before this!"); + LOGMAN_THROW_AA_FMT(Info->Type != FEXCore::X86Tables::TYPE_REX_PREFIX, "REX PREFIX should have been decoded before this!"); // A normal instruction is the most likely. if (Info->Type == FEXCore::X86Tables::TYPE_INST) [[likely]] { return NormalOp(Info, Op); - } - else if (Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && - Info->Type <= FEXCore::X86Tables::TYPE_GROUP_11) { + } else if (Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_11) { uint8_t ModRMByte = ReadByte(); DecodeInst->ModRM = ModRMByte; DecodeInst->DecodedModRM = true; @@ -625,9 +581,7 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 Op = OPD(Info->Type, Info->MoreBytes, ModRM.reg); return NormalOp(&PrimaryInstGroupOps[Op], Op); #undef OPD - } - else if (Info->Type >= FEXCore::X86Tables::TYPE_GROUP_6 && - Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P) { + } else if (Info->Type >= FEXCore::X86Tables::TYPE_GROUP_6 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P) { #define OPD(group, prefix, Reg) (((group - FEXCore::X86Tables::TYPE_GROUP_6) << 5) | (prefix) << 3 | (Reg)) constexpr uint16_t PF_NONE = 0; constexpr uint16_t PF_F3 = 1; @@ -635,12 +589,13 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 constexpr uint16_t PF_F2 = 3; uint16_t PrefixType = PF_NONE; - if (DecodeInst->LastEscapePrefix == 0xF3) + if (DecodeInst->LastEscapePrefix == 0xF3) { PrefixType = PF_F3; - else if (DecodeInst->LastEscapePrefix == 0xF2) + } else if (DecodeInst->LastEscapePrefix == 0xF2) { PrefixType = PF_F2; - else if (DecodeInst->LastEscapePrefix == 0x66) + } else if (DecodeInst->LastEscapePrefix == 0x66) { PrefixType = PF_66; + } // We have ModRM uint8_t ModRMByte = ReadByte(); @@ -651,31 +606,22 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 ModRM.Hex = DecodeInst->ModRM; uint16_t LocalOp = OPD(Info->Type, PrefixType, ModRM.reg); - FEXCore::X86Tables::X86InstInfo *LocalInfo = &SecondInstGroupOps[LocalOp]; + FEXCore::X86Tables::X86InstInfo* LocalInfo = &SecondInstGroupOps[LocalOp]; #undef OPD if (LocalInfo->Type == FEXCore::X86Tables::TYPE_SECOND_GROUP_MODRM) { // Everything in this group is privileged instructions aside from XGETBV constexpr std::array RegToField = { - 255, - 0, - 1, - 2, - 255, - 255, - 255, - 3, + 255, 0, 1, 2, 255, 255, 255, 3, }; uint8_t Field = RegToField[ModRM.reg]; LOGMAN_THROW_AA_FMT(Field != 255, "Invalid field selected!"); LocalOp = (Field << 3) | ModRM.rm; return NormalOp(&SecondModRMTableOps[LocalOp], LocalOp); - } - else { + } else { return NormalOp(&SecondInstGroupOps[LocalOp], LocalOp); } - } - else if (Info->Type == FEXCore::X86Tables::TYPE_X87_TABLE_PREFIX) { + } else if (Info->Type == FEXCore::X86Tables::TYPE_X87_TABLE_PREFIX) { // We have ModRM uint8_t ModRMByte = ReadByte(); DecodeInst->ModRM = ModRMByte; @@ -683,13 +629,12 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 uint16_t X87Op = ((Op - 0xD8) << 8) | ModRMByte; return NormalOp(&X87Ops[X87Op], X87Op); - } - else if (Info->Type == FEXCore::X86Tables::TYPE_VEX_TABLE_PREFIX) { + } else if (Info->Type == FEXCore::X86Tables::TYPE_VEX_TABLE_PREFIX) { FEXCORE_TELEMETRY_SET(VEXOpTelem, 1); uint16_t map_select = 1; uint16_t pp = 0; const uint8_t Byte1 = ReadByte(); - DecodedHeader options{}; + DecodedHeader options {}; if ((Byte1 & 0b10000000) == 0) { LOGMAN_THROW_A_FMT(CTX->Config.Is64BitMode, "VEX.R shouldn't be 0 in 32-bit mode!"); @@ -700,8 +645,7 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 pp = Byte1 & 0b11; options.vvvv = 15 - ((Byte1 & 0b01111000) >> 3); options.L = (Byte1 & 0b100) != 0; - } - else { // 0xC4 = Three byte VEX + } else { // 0xC4 = Three byte VEX const uint8_t Byte2 = ReadByte(); pp = Byte2 & 0b11; map_select = Byte1 & 0b11111; @@ -726,18 +670,17 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 Op = OPD(map_select, pp, VEXOp); #undef OPD - FEXCore::X86Tables::X86InstInfo *LocalInfo = &VEXTableOps[Op]; + FEXCore::X86Tables::X86InstInfo* LocalInfo = &VEXTableOps[Op]; - if (LocalInfo->Type >= FEXCore::X86Tables::TYPE_VEX_GROUP_12 && - LocalInfo->Type <= FEXCore::X86Tables::TYPE_VEX_GROUP_17) { - FEXCORE_TELEMETRY_SET(VEXOpTelem, 1); - // We have ModRM - uint8_t ModRMByte = ReadByte(); - DecodeInst->ModRM = ModRMByte; - DecodeInst->DecodedModRM = true; + if (LocalInfo->Type >= FEXCore::X86Tables::TYPE_VEX_GROUP_12 && LocalInfo->Type <= FEXCore::X86Tables::TYPE_VEX_GROUP_17) { + FEXCORE_TELEMETRY_SET(VEXOpTelem, 1); + // We have ModRM + uint8_t ModRMByte = ReadByte(); + DecodeInst->ModRM = ModRMByte; + DecodeInst->DecodedModRM = true; - FEXCore::X86Tables::ModRMDecoded ModRM; - ModRM.Hex = DecodeInst->ModRM; + FEXCore::X86Tables::ModRMDecoded ModRM; + ModRM.Hex = DecodeInst->ModRM; #define OPD(group, pp, opcode) (((group - TYPE_VEX_GROUP_12) << 4) | (pp << 3) | (opcode)) Op = OPD(LocalInfo->Type, pp, ModRM.reg); @@ -746,8 +689,7 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 } else { return NormalOp(LocalInfo, Op, options); } - } - else if (Info->Type == FEXCore::X86Tables::TYPE_GROUP_EVEX) { + } else if (Info->Type == FEXCore::X86Tables::TYPE_GROUP_EVEX) { FEXCORE_TELEMETRY_SET(EVEXOpTelem, 1); /* uint8_t P1 = */ ReadByte(); @@ -769,15 +711,17 @@ bool Decoder::DecodeInstruction(uint64_t PC) { memset(DecodeInst, 0, sizeof(DecodedInst)); DecodeInst->PC = PC; - for(;;) { - if (InstructionSize >= MAX_INST_SIZE) + for (;;) { + if (InstructionSize >= MAX_INST_SIZE) { return false; + } uint8_t Op = ReadByte(); switch (Op) { - case 0x0F: {// Escape Op + case 0x0F: { // Escape Op uint8_t EscapeOp = ReadByte(); switch (EscapeOp) { - case 0x0F: [[unlikely]] { // 3DNow! + case 0x0F: + [[unlikely]] { // 3DNow! // 3DNow! Instruction Encoding: 0F 0F [ModRM] [SIB] [Displacement] [Opcode] // Decode ModRM uint8_t ModRMByte = ReadByte(); @@ -787,8 +731,7 @@ bool Decoder::DecodeInstruction(uint64_t PC) { FEXCore::X86Tables::ModRMDecoded ModRM; ModRM.Hex = DecodeInst->ModRM; - const bool Has16BitAddressing = !CTX->Config.Is64BitMode && - DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE; + const bool Has16BitAddressing = !CTX->Config.Is64BitMode && DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE; // All 3DNow! instructions have the second argument as the rm handler // We need to decode it upfront to get the displacement out of the way @@ -800,55 +743,58 @@ bool Decoder::DecodeInstruction(uint64_t PC) { // Take a peek at the op just past the displacement uint8_t LocalOp = ReadByte(); return NormalOpHeader(&FEXCore::X86Tables::DDDNowOps[LocalOp], LocalOp); - break; + break; } - case 0x38: { // F38 Table! - constexpr uint16_t PF_38_NONE = 0; - constexpr uint16_t PF_38_66 = (1U << 0); - constexpr uint16_t PF_38_F2 = (1U << 1); - constexpr uint16_t PF_38_F3 = (1U << 2); + case 0x38: { // F38 Table! + constexpr uint16_t PF_38_NONE = 0; + constexpr uint16_t PF_38_66 = (1U << 0); + constexpr uint16_t PF_38_F2 = (1U << 1); + constexpr uint16_t PF_38_F3 = (1U << 2); - uint16_t Prefix = PF_38_NONE; - if (DecodeInst->Flags & DecodeFlags::FLAG_OPERAND_SIZE) { - Prefix |= PF_38_66; - } - if (DecodeInst->Flags & DecodeFlags::FLAG_REPNE_PREFIX) { - Prefix |= PF_38_F2; - } - if (DecodeInst->Flags & DecodeFlags::FLAG_REP_PREFIX) { - Prefix |= PF_38_F3; - } - - uint16_t LocalOp = (Prefix << 8) | ReadByte(); - - bool NoOverlay66 = (FEXCore::X86Tables::H0F38TableOps[LocalOp].Flags & InstFlags::FLAGS_NO_OVERLAY66) != 0; - if (DecodeInst->LastEscapePrefix == 0x66 && NoOverlay66) { // Operand Size - // Remove prefix so it doesn't effect calculations. - // This is only an escape prefix rather than modifier now - DecodeInst->Flags &= ~DecodeFlags::FLAG_OPERAND_SIZE; - DecodeFlags::PopOpAddrIf(&DecodeInst->Flags, DecodeFlags::FLAG_OPERAND_SIZE_LAST); - } - - return NormalOpHeader(&FEXCore::X86Tables::H0F38TableOps[LocalOp], LocalOp); - break; + uint16_t Prefix = PF_38_NONE; + if (DecodeInst->Flags & DecodeFlags::FLAG_OPERAND_SIZE) { + Prefix |= PF_38_66; } - case 0x3A: { // F3A Table! - constexpr uint16_t PF_3A_NONE = 0; - constexpr uint16_t PF_3A_66 = (1 << 0); - constexpr uint16_t PF_3A_REX = (1 << 1); - - uint16_t Prefix = PF_3A_NONE; - if (DecodeInst->LastEscapePrefix == 0x66) // Operand Size - Prefix = PF_3A_66; - - if (DecodeInst->Flags & DecodeFlags::FLAG_REX_WIDENING) - Prefix |= PF_3A_REX; - - uint16_t LocalOp = (Prefix << 8) | ReadByte(); - return NormalOpHeader(&FEXCore::X86Tables::H0F3ATableOps[LocalOp], LocalOp); - break; + if (DecodeInst->Flags & DecodeFlags::FLAG_REPNE_PREFIX) { + Prefix |= PF_38_F2; } - default: [[likely]] { // Two byte table! + if (DecodeInst->Flags & DecodeFlags::FLAG_REP_PREFIX) { + Prefix |= PF_38_F3; + } + + uint16_t LocalOp = (Prefix << 8) | ReadByte(); + + bool NoOverlay66 = (FEXCore::X86Tables::H0F38TableOps[LocalOp].Flags & InstFlags::FLAGS_NO_OVERLAY66) != 0; + if (DecodeInst->LastEscapePrefix == 0x66 && NoOverlay66) { // Operand Size + // Remove prefix so it doesn't effect calculations. + // This is only an escape prefix rather than modifier now + DecodeInst->Flags &= ~DecodeFlags::FLAG_OPERAND_SIZE; + DecodeFlags::PopOpAddrIf(&DecodeInst->Flags, DecodeFlags::FLAG_OPERAND_SIZE_LAST); + } + + return NormalOpHeader(&FEXCore::X86Tables::H0F38TableOps[LocalOp], LocalOp); + break; + } + case 0x3A: { // F3A Table! + constexpr uint16_t PF_3A_NONE = 0; + constexpr uint16_t PF_3A_66 = (1 << 0); + constexpr uint16_t PF_3A_REX = (1 << 1); + + uint16_t Prefix = PF_3A_NONE; + if (DecodeInst->LastEscapePrefix == 0x66) { // Operand Size + Prefix = PF_3A_66; + } + + if (DecodeInst->Flags & DecodeFlags::FLAG_REX_WIDENING) { + Prefix |= PF_3A_REX; + } + + uint16_t LocalOp = (Prefix << 8) | ReadByte(); + return NormalOpHeader(&FEXCore::X86Tables::H0F3ATableOps[LocalOp], LocalOp); + break; + } + default: + [[likely]] { // Two byte table! // x86-64 abuses three legacy prefixes to extend the table encodings // 0x66 - Operand Size prefix // 0xF2 - REPNE prefix @@ -861,42 +807,38 @@ bool Decoder::DecodeInstruction(uint64_t PC) { if (NoOverlay) { // This section of the table ignores prefix extention return NormalOpHeader(&FEXCore::X86Tables::SecondBaseOps[EscapeOp], EscapeOp); - } - else if (DecodeInst->LastEscapePrefix == 0xF3) { // REP + } else if (DecodeInst->LastEscapePrefix == 0xF3) { // REP // Remove prefix so it doesn't effect calculations. // This is only an escape prefix rather tan modifier now DecodeInst->Flags &= ~DecodeFlags::FLAG_REP_PREFIX; return NormalOpHeader(&FEXCore::X86Tables::RepModOps[EscapeOp], EscapeOp); - } - else if (DecodeInst->LastEscapePrefix == 0xF2) { // REPNE + } else if (DecodeInst->LastEscapePrefix == 0xF2) { // REPNE // Remove prefix so it doesn't effect calculations. // This is only an escape prefix rather tan modifier now DecodeInst->Flags &= ~DecodeFlags::FLAG_REPNE_PREFIX; return NormalOpHeader(&FEXCore::X86Tables::RepNEModOps[EscapeOp], EscapeOp); - } - else if (DecodeInst->LastEscapePrefix == 0x66 && !NoOverlay66) { // Operand Size + } else if (DecodeInst->LastEscapePrefix == 0x66 && !NoOverlay66) { // Operand Size // Remove prefix so it doesn't effect calculations. // This is only an escape prefix rather tan modifier now DecodeInst->Flags &= ~DecodeFlags::FLAG_OPERAND_SIZE; DecodeFlags::PopOpAddrIf(&DecodeInst->Flags, DecodeFlags::FLAG_OPERAND_SIZE_LAST); return NormalOpHeader(&FEXCore::X86Tables::OpSizeModOps[EscapeOp], EscapeOp); - } - else { + } else { return NormalOpHeader(&FEXCore::X86Tables::SecondBaseOps[EscapeOp], EscapeOp); } - break; + break; } } - break; + break; } case 0x66: // Operand Size prefix DecodeInst->Flags |= DecodeFlags::FLAG_OPERAND_SIZE; DecodeInst->LastEscapePrefix = Op; DecodeFlags::PushOpAddr(&DecodeInst->Flags, DecodeFlags::FLAG_OPERAND_SIZE_LAST); - break; + break; case 0x67: // Address Size override prefix DecodeInst->Flags |= DecodeFlags::FLAG_ADDRESS_SIZE; - break; + break; case 0x26: // ES legacy prefix if (!CTX->Config.Is64BitMode) { DecodeInst->Flags |= DecodeFlags::FLAG_ES_PREFIX; @@ -920,56 +862,59 @@ bool Decoder::DecodeInstruction(uint64_t PC) { DecodeInst->Flags |= DecodeFlags::FLAG_DS_PREFIX; } break; - break; + break; case 0xF0: // LOCK prefix DecodeInst->Flags |= DecodeFlags::FLAG_LOCK; - break; + break; case 0xF2: // REPNE prefix DecodeInst->Flags |= DecodeFlags::FLAG_REPNE_PREFIX; DecodeInst->LastEscapePrefix = Op; - break; + break; case 0xF3: // REP prefix DecodeInst->Flags |= DecodeFlags::FLAG_REP_PREFIX; DecodeInst->LastEscapePrefix = Op; - break; + break; case 0x64: // FS prefix DecodeInst->Flags |= DecodeFlags::FLAG_FS_PREFIX; - break; + break; case 0x65: // GS prefix DecodeInst->Flags |= DecodeFlags::FLAG_GS_PREFIX; - break; - default: [[likely]] { // Default base table - auto Info = &FEXCore::X86Tables::BaseOps[Op]; + break; + default: + [[likely]] { // Default base table + auto Info = &FEXCore::X86Tables::BaseOps[Op]; - if (Info->Type == FEXCore::X86Tables::TYPE_REX_PREFIX) { - LOGMAN_THROW_A_FMT(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode"); - DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX; + if (Info->Type == FEXCore::X86Tables::TYPE_REX_PREFIX) { + LOGMAN_THROW_A_FMT(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode"); + DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX; - // Widening displacement - if (Op & 0b1000) { - DecodeInst->Flags |= DecodeFlags::FLAG_REX_WIDENING; - DecodeFlags::PushOpAddr(&DecodeInst->Flags, DecodeFlags::FLAG_WIDENING_SIZE_LAST); + // Widening displacement + if (Op & 0b1000) { + DecodeInst->Flags |= DecodeFlags::FLAG_REX_WIDENING; + DecodeFlags::PushOpAddr(&DecodeInst->Flags, DecodeFlags::FLAG_WIDENING_SIZE_LAST); + } + + // XGPR_B bit set + if (Op & 0b0001) { + DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_B; + } + + // XGPR_X bit set + if (Op & 0b0010) { + DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_X; + } + + // XGPR_R bit set + if (Op & 0b0100) { + DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_R; + } + } else { + return NormalOpHeader(Info, Op); } - // XGPR_B bit set - if (Op & 0b0001) - DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_B; - - // XGPR_X bit set - if (Op & 0b0010) - DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_X; - - // XGPR_R bit set - if (Op & 0b0100) - DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_R; - } else { - return NormalOpHeader(Info, Op); + break; } - - break; } - } - } if (DecodeInst->Dest.IsGPR()) { @@ -980,8 +925,9 @@ bool Decoder::DecodeInstruction(uint64_t PC) { } void Decoder::BranchTargetInMultiblockRange() { - if (!CTX->Config.Multiblock) + if (!CTX->Config.Multiblock) { return; + } // If the RIP setting is conditional AND within our symbol range then it can be considered for multiblock uint64_t TargetRIP = 0; @@ -989,32 +935,30 @@ void Decoder::BranchTargetInMultiblockRange() { bool Conditional = true; switch (DecodeInst->OP) { - case 0x70 ... 0x7F: // Conditional JUMP - case 0x80 ... 0x8F: { // More conditional - // Source is a literal - // auto RIPOffset = LoadSource(Op, Op->Src[0], Op->Flags); - // auto RIPTargetConst = _Constant(Op->PC + Op->InstSize); - // Target offset is PC + InstSize + Literal - LOGMAN_THROW_A_FMT(DecodeInst->Src[0].IsLiteral(), "Had wrong operand type"); - TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].Data.Literal.Value; + case 0x70 ... 0x7F: // Conditional JUMP + case 0x80 ... 0x8F: { // More conditional + // Source is a literal + // auto RIPOffset = LoadSource(Op, Op->Src[0], Op->Flags); + // auto RIPTargetConst = _Constant(Op->PC + Op->InstSize); + // Target offset is PC + InstSize + Literal + LOGMAN_THROW_A_FMT(DecodeInst->Src[0].IsLiteral(), "Had wrong operand type"); + TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].Data.Literal.Value; break; + } + case 0xE9: + case 0xEB: // Both are unconditional JMP instructions + LOGMAN_THROW_A_FMT(DecodeInst->Src[0].IsLiteral(), "Had wrong operand type"); + TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].Data.Literal.Value; + Conditional = false; + break; + case 0xE8: // Call - Immediate target, We don't want to inline calls + if (ExternalBranches) { + ExternalBranches->insert(DecodeInst->PC + DecodeInst->InstSize); } - case 0xE9: - case 0xEB: // Both are unconditional JMP instructions - LOGMAN_THROW_A_FMT(DecodeInst->Src[0].IsLiteral(), "Had wrong operand type"); - TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].Data.Literal.Value; - Conditional = false; - break; - case 0xE8: // Call - Immediate target, We don't want to inline calls - if (ExternalBranches) { - ExternalBranches->insert(DecodeInst->PC + DecodeInst->InstSize); - } - [[fallthrough]]; - case 0xC2: // RET imm - case 0xC3: // RET - default: - return; - break; + [[fallthrough]]; + case 0xC2: // RET imm + case 0xC3: // RET + default: return; break; } if (GPRSize == 4) { @@ -1075,13 +1019,11 @@ bool Decoder::BranchTargetCanContinue(bool FinalInstruction) const { return false; } -const uint8_t *Decoder::AdjustAddrForSpecialRegion(uint8_t const* _InstStream, uint64_t EntryPoint, uint64_t RIP) { +const uint8_t* Decoder::AdjustAddrForSpecialRegion(const uint8_t* _InstStream, uint64_t EntryPoint, uint64_t RIP) { constexpr uint64_t VSyscall_Base = 0xFFFF'FFFF'FF60'0000ULL; constexpr uint64_t VSyscall_End = VSyscall_Base + 0x1000; - if (OSABI == FEXCore::HLE::SyscallOSABI::OS_LINUX64 && - RIP >= VSyscall_Base && - RIP < VSyscall_End) { + if (OSABI == FEXCore::HLE::SyscallOSABI::OS_LINUX64 && RIP >= VSyscall_Base && RIP < VSyscall_End) { // VSyscall // This doesn't exist on AArch64 and on x86_64 hosts this is emulated with faults to a region mapped with --xp permissions // Offset 0: vgettimeofday @@ -1094,7 +1036,8 @@ const uint8_t *Decoder::AdjustAddrForSpecialRegion(uint8_t const* _InstStream, u return _InstStream - EntryPoint + RIP; } -void Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC, uint64_t MaxInst, std::function AddContainedCodePage) { +void Decoder::DecodeInstructionsAtEntry(const uint8_t* _InstStream, uint64_t PC, uint64_t MaxInst, + std::function AddContainedCodePage) { FEXCORE_PROFILE_SCOPED("DecodeInstructions"); BlockInfo.TotalInstructionCount = 0; BlockInfo.Blocks.clear(); @@ -1111,7 +1054,7 @@ void Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC, EntryPoint = PC; InstStream = _InstStream; - uint64_t TotalInstructions{}; + uint64_t TotalInstructions {}; // If we don't have symbols available then we become a bit optimistic about multiblock ranges if (!SymbolAvailable) { @@ -1128,7 +1071,7 @@ void Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC, uint64_t CurrentCodePage = PC & FEXCore::Utils::FEX_PAGE_MASK; - fextl::set CodePages = { CurrentCodePage }; + fextl::set CodePages = {CurrentCodePage}; AddContainedCodePage(PC, CurrentCodePage, FEXCore::Utils::FEX_PAGE_SIZE); @@ -1140,12 +1083,12 @@ void Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC, auto BlockDecodeIt = BlocksToDecode.begin(); uint64_t RIPToDecode = *BlockDecodeIt; BlockInfo.Blocks.emplace_back(); - DecodedBlocks &CurrentBlockDecoding = BlockInfo.Blocks.back(); + DecodedBlocks& CurrentBlockDecoding = BlockInfo.Blocks.back(); CurrentBlockDecoding.Entry = RIPToDecode; uint64_t PCOffset = 0; - uint64_t BlockNumberOfInstructions{}; + uint64_t BlockNumberOfInstructions {}; uint64_t BlockStartOffset = DecodedSize; // Do a bit of pointer math to figure out where we are in code @@ -1192,15 +1135,12 @@ void Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC, } bool CanContinue = false; - if (!(DecodeInst->TableInfo->Flags & - (FEXCore::X86Tables::InstFlags::FLAGS_BLOCK_END | FEXCore::X86Tables::InstFlags::FLAGS_SETS_RIP))) { + if (!(DecodeInst->TableInfo->Flags & (FEXCore::X86Tables::InstFlags::FLAGS_BLOCK_END | FEXCore::X86Tables::InstFlags::FLAGS_SETS_RIP))) { // If this isn't a block ender then we can keep going regardless CanContinue = true; } - bool FinalInstruction = DecodedSize >= MaxInst || - DecodedSize >= DefaultDecodedBufferSize || - TotalInstructions >= MaxInst; + bool FinalInstruction = DecodedSize >= MaxInst || DecodedSize >= DefaultDecodedBufferSize || TotalInstructions >= MaxInst; if (DecodeInst->TableInfo->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SETS_RIP) { // If we have multiblock enabled @@ -1234,10 +1174,10 @@ void Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC, } // sort for better branching - std::sort(BlockInfo.Blocks.begin(), BlockInfo.Blocks.end(), [](const FEXCore::Frontend::Decoder::DecodedBlocks& a, const FEXCore::Frontend::Decoder::DecodedBlocks& b) { + std::sort(BlockInfo.Blocks.begin(), BlockInfo.Blocks.end(), + [](const FEXCore::Frontend::Decoder::DecodedBlocks& a, const FEXCore::Frontend::Decoder::DecodedBlocks& b) { return a.Entry < b.Entry; }); } -} - +} // namespace FEXCore::Frontend diff --git a/FEXCore/Source/Interface/Core/Frontend.h b/FEXCore/Source/Interface/Core/Frontend.h index 6f0eab8ef..6a54142a0 100644 --- a/FEXCore/Source/Interface/Core/Frontend.h +++ b/FEXCore/Source/Interface/Core/Frontend.h @@ -21,10 +21,10 @@ class Decoder final { public: // New Frontend decoding struct DecodedBlocks final { - uint64_t Entry{}; - uint64_t NumInstructions{}; - FEXCore::X86Tables::DecodedInst *DecodedInstructions; - bool HasInvalidInstruction{}; + uint64_t Entry {}; + uint64_t NumInstructions {}; + FEXCore::X86Tables::DecodedInst* DecodedInstructions; + bool HasInvalidInstruction {}; }; struct DecodedBlockInformation final { @@ -32,19 +32,24 @@ public: fextl::vector Blocks; }; - Decoder(FEXCore::Context::ContextImpl *ctx); + Decoder(FEXCore::Context::ContextImpl* ctx); ~Decoder(); - void DecodeInstructionsAtEntry(uint8_t const* InstStream, uint64_t PC, uint64_t MaxInst, std::function AddContainedCodePage); + void DecodeInstructionsAtEntry(const uint8_t* InstStream, uint64_t PC, uint64_t MaxInst, + std::function AddContainedCodePage); - DecodedBlockInformation const *GetDecodedBlockInfo() const { + const DecodedBlockInformation* GetDecodedBlockInfo() const { return &BlockInfo; } uint64_t DecodedMinAddress {}; uint64_t DecodedMaxAddress {~0ULL}; - void SetSectionMaxAddress(uint64_t v) { SectionMaxAddress = v; } - void SetExternalBranches(fextl::set *v) { ExternalBranches = v; } + void SetSectionMaxAddress(uint64_t v) { + SectionMaxAddress = v; + } + void SetExternalBranches(fextl::set* v) { + ExternalBranches = v; + } void DelayedDisownBuffer() { PoolObject.DelayedDisownBuffer(); @@ -59,8 +64,8 @@ private: bool L; // VEX.L bit (if set then 256 bit operation, if unset then scalar or 128-bit operation) }; - FEXCore::Context::ContextImpl *CTX; - const FEXCore::HLE::SyscallOSABI OSABI{}; + FEXCore::Context::ContextImpl* CTX; + const FEXCore::HLE::SyscallOSABI OSABI {}; bool DecodeInstruction(uint64_t PC); @@ -70,22 +75,24 @@ private: uint8_t ReadByte(); uint8_t PeekByte(uint8_t Offset) const; uint64_t ReadData(uint8_t Size); - void SkipBytes(uint8_t Size) { InstructionSize += Size; } + void SkipBytes(uint8_t Size) { + InstructionSize += Size; + } - bool NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, DecodedHeader Options = {}); - bool NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op); + bool NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op, DecodedHeader Options = {}); + bool NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op); static constexpr size_t DefaultDecodedBufferSize = 0x10000; - FEXCore::X86Tables::DecodedInst *DecodedBuffer{}; + FEXCore::X86Tables::DecodedInst* DecodedBuffer {}; Utils::FixedSizePooledAllocation PoolObject; size_t DecodedSize {}; - uint8_t const *InstStream; + const uint8_t* InstStream; static constexpr size_t MAX_INST_SIZE = 15; uint8_t InstructionSize; std::array Instruction; - FEXCore::X86Tables::DecodedInst *DecodeInst; + FEXCore::X86Tables::DecodedInst* DecodeInst; // This is for multiblock data tracking bool SymbolAvailable {false}; @@ -99,21 +106,21 @@ private: DecodedBlockInformation BlockInfo; fextl::set BlocksToDecode; fextl::set HasBlocks; - fextl::set *ExternalBranches {nullptr}; + fextl::set* ExternalBranches {nullptr}; // ModRM rm decoding - using DecodeModRMPtr = void (FEXCore::Frontend::Decoder::*)(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM); - void DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM); - void DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM); + using DecodeModRMPtr = void (FEXCore::Frontend::Decoder::*)(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM); + void DecodeModRM_16(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM); + void DecodeModRM_64(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM); - static constexpr std::array DecodeModRMs_Disp{ + static constexpr std::array DecodeModRMs_Disp { &FEXCore::Frontend::Decoder::DecodeModRM_64, &FEXCore::Frontend::Decoder::DecodeModRM_16, }; - const uint8_t *AdjustAddrForSpecialRegion(uint8_t const* _InstStream, uint64_t EntryPoint, uint64_t RIP); + const uint8_t* AdjustAddrForSpecialRegion(const uint8_t* _InstStream, uint64_t EntryPoint, uint64_t RIP); FEXCORE_TELEMETRY_INIT(VEXOpTelem, TYPE_USES_VEX_OPS); FEXCORE_TELEMETRY_INIT(EVEXOpTelem, TYPE_USES_EVEX_OPS); }; -} +} // namespace FEXCore::Frontend diff --git a/FEXCore/Source/Interface/Core/HostFeatures.cpp b/FEXCore/Source/Interface/Core/HostFeatures.cpp index e5f2dda37..c55dd7867 100644 --- a/FEXCore/Source/Interface/Core/HostFeatures.cpp +++ b/FEXCore/Source/Interface/Core/HostFeatures.cpp @@ -28,23 +28,21 @@ namespace FEXCore { [[maybe_unused]] constexpr uint32_t DCZID_BS_MASK = 0b0'1111; #ifdef _M_ARM_64 -[[maybe_unused]] static uint32_t GetDCZID() { - uint64_t Result{}; - __asm("mrs %[Res], DCZID_EL0" - : [Res] "=r" (Result)); +[[maybe_unused]] +static uint32_t GetDCZID() { + uint64_t Result {}; + __asm("mrs %[Res], DCZID_EL0" : [Res] "=r"(Result)); return Result; } static uint32_t GetFPCR() { - uint64_t Result{}; - __asm ("mrs %[Res], FPCR" - : [Res] "=r" (Result)); + uint64_t Result {}; + __asm("mrs %[Res], FPCR" : [Res] "=r"(Result)); return Result; } static void SetFPCR(uint64_t Value) { - __asm ("msr FPCR, %[Value]" - :: [Value] "r" (Value)); + __asm("msr FPCR, %[Value]" ::[Value] "r"(Value)); } #else static uint32_t GetDCZID() { @@ -53,7 +51,7 @@ static uint32_t GetDCZID() { } #endif -static void OverrideFeatures(HostFeatures *Features) { +static void OverrideFeatures(HostFeatures* Features) { // Override features if the user has specifically called for it. FEX_CONFIG_OPT(HostFeatures, HOSTFEATURES); if (!HostFeatures()) { @@ -62,19 +60,19 @@ static void OverrideFeatures(HostFeatures *Features) { } #define ENABLE_DISABLE_OPTION(FeatureName, name, enum_name) \ - do { \ - const bool Disable##name = (HostFeatures() & FEXCore::Config::HostFeatures::DISABLE##enum_name) != 0; \ - const bool Enable##name = (HostFeatures() & FEXCore::Config::HostFeatures::ENABLE##enum_name) != 0; \ - LogMan::Throw::AFmt(!(Disable##name && Enable##name), "Disabling and Enabling CPU feature (" #name ") is mutually exclusive"); \ - const bool AlreadyEnabled = Features->FeatureName; \ - const bool Result = (AlreadyEnabled | Enable##name) & !Disable##name; \ - Features->FeatureName = Result; \ - } while (0) + do { \ + const bool Disable##name = (HostFeatures() & FEXCore::Config::HostFeatures::DISABLE##enum_name) != 0; \ + const bool Enable##name = (HostFeatures() & FEXCore::Config::HostFeatures::ENABLE##enum_name) != 0; \ + LogMan::Throw::AFmt(!(Disable##name && Enable##name), "Disabling and Enabling CPU feature (" #name ") is mutually exclusive"); \ + const bool AlreadyEnabled = Features->FeatureName; \ + const bool Result = (AlreadyEnabled | Enable##name) & !Disable##name; \ + Features->FeatureName = Result; \ + } while (0) #define GET_SINGLE_OPTION(name, enum_name) \ - const bool Disable##name = (HostFeatures() & FEXCore::Config::HostFeatures::DISABLE##enum_name) != 0; \ - const bool Enable##name = (HostFeatures() & FEXCore::Config::HostFeatures::ENABLE##enum_name) != 0; \ - LogMan::Throw::AFmt(!(Disable##name && Enable##name), "Disabling and Enabling CPU feature (" #name ") is mutually exclusive"); + const bool Disable##name = (HostFeatures() & FEXCore::Config::HostFeatures::DISABLE##enum_name) != 0; \ + const bool Enable##name = (HostFeatures() & FEXCore::Config::HostFeatures::ENABLE##enum_name) != 0; \ + LogMan::Throw::AFmt(!(Disable##name && Enable##name), "Disabling and Enabling CPU feature (" #name ") is mutually exclusive"); ENABLE_DISABLE_OPTION(SupportsAVX, AVX, AVX); ENABLE_DISABLE_OPTION(SupportsAVX2, AVX2, AVX2); @@ -102,8 +100,7 @@ static void OverrideFeatures(HostFeatures *Features) { Features->SupportsCRC = true; Features->SupportsSHA = true; Features->SupportsPMULL_128Bit = true; - } - else if (DisableCrypto) { + } else if (DisableCrypto) { Features->SupportsAES = false; Features->SupportsCRC = false; Features->SupportsSHA = false; @@ -127,8 +124,7 @@ HostFeatures::HostFeatures() { SupportsAES = Features.Has(vixl::CPUFeatures::Feature::kAES); SupportsCRC = Features.Has(vixl::CPUFeatures::Feature::kCRC32); - SupportsSHA = Features.Has(vixl::CPUFeatures::Feature::kSHA1) && - Features.Has(vixl::CPUFeatures::Feature::kSHA2); + SupportsSHA = Features.Has(vixl::CPUFeatures::Feature::kSHA1) && Features.Has(vixl::CPUFeatures::Feature::kSHA2); SupportsAtomics = Features.Has(vixl::CPUFeatures::Feature::kAtomics); SupportsRAND = Features.Has(vixl::CPUFeatures::Feature::kRNG); @@ -151,8 +147,7 @@ HostFeatures::HostFeatures() { SupportsAVX = true; #else SupportsSVE = Features.Has(vixl::CPUFeatures::Feature::kSVE); - SupportsAVX = Features.Has(vixl::CPUFeatures::Feature::kSVE2) && - vixl::aarch64::CPU::ReadSVEVectorLengthInBits() >= 256; + SupportsAVX = Features.Has(vixl::CPUFeatures::Feature::kSVE2) && vixl::aarch64::CPU::ReadSVEVectorLengthInBits() >= 256; #endif // TODO: AVX2 is currently unsupported. Disable until the remaining features are implemented. SupportsAVX2 = false; @@ -173,21 +168,19 @@ HostFeatures::HostFeatures() { // We need to get the CPU's cache line size // We expect sane targets that have correct cacheline sizes across clusters uint64_t CTR; - __asm volatile ("mrs %[ctr], ctr_el0" - : [ctr] "=r"(CTR)); + __asm volatile("mrs %[ctr], ctr_el0" : [ctr] "=r"(CTR)); DCacheLineSize = 4 << ((CTR >> 16) & 0xF); ICacheLineSize = 4 << (CTR & 0xF); // Test if this CPU supports float exception trapping by attempting to enable // On unsupported these bits are architecturally defined as RAZ/WI - constexpr uint32_t ExceptionEnableTraps = - (1U << 8) | // Invalid Operation float exception trap enable - (1U << 9) | // Divide by zero float exception trap enable - (1U << 10) | // Overflow float exception trap enable - (1U << 11) | // Underflow float exception trap enable - (1U << 12) | // Inexact float exception trap enable - (1U << 15); // Input Denormal float exception trap enable + constexpr uint32_t ExceptionEnableTraps = (1U << 8) | // Invalid Operation float exception trap enable + (1U << 9) | // Divide by zero float exception trap enable + (1U << 10) | // Overflow float exception trap enable + (1U << 11) | // Underflow float exception trap enable + (1U << 12) | // Inexact float exception trap enable + (1U << 15); // Input Denormal float exception trap enable uint32_t OriginalFPCR = GetFPCR(); uint32_t FPCR = OriginalFPCR | ExceptionEnableTraps; @@ -222,7 +215,7 @@ HostFeatures::HostFeatures() { ICacheLineSize = 64U; #if !defined(VIXL_SIMULATOR) - Xbyak::util::Cpu X86Features{}; + Xbyak::util::Cpu X86Features {}; SupportsAES = X86Features.has(Xbyak::util::Cpu::tAESNI); SupportsCRC = X86Features.has(Xbyak::util::Cpu::tSSE42); SupportsRAND = X86Features.has(Xbyak::util::Cpu::tRDRAND) && X86Features.has(Xbyak::util::Cpu::tRDSEED); @@ -256,4 +249,4 @@ HostFeatures::HostFeatures() { SupportsPreserveAllABI = FEXCORE_HAS_PRESERVE_ALL_ATTR; OverrideFeatures(this); } -} +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h index 7bc5ce745..9f03d2305 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h +++ b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/F80Fallbacks.h @@ -6,43 +6,32 @@ #include "Interface/IR/IR.h" namespace FEXCore::CPU { -FEXCORE_PRESERVE_ALL_ATTR -static void LoadDeferredFCW(uint16_t NewFCW) { +FEXCORE_PRESERVE_ALL_ATTR static void LoadDeferredFCW(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); + 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; + 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 { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle4(uint16_t NewFCW, float src) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle4(uint16_t NewFCW, float src) { LoadDeferredFCW(NewFCW); return src; } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle8(uint16_t NewFCW, double src) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle8(uint16_t NewFCW, double src) { LoadDeferredFCW(NewFCW); return src; } @@ -51,24 +40,20 @@ struct OpHandlers { template<> struct OpHandlers { template - FEXCORE_PRESERVE_ALL_ATTR - static uint64_t handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static uint64_t handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); bool eq, lt, nan; uint64_t ResultFlags = 0; X80SoftFloat::FCMP(Src1, Src2, &eq, <, &nan); - if (Flags & (1 << IR::FCMP_FLAG_LT) && - lt) { + if (Flags & (1 << IR::FCMP_FLAG_LT) && lt) { ResultFlags |= (1 << IR::FCMP_FLAG_LT); } - if (Flags & (1 << IR::FCMP_FLAG_UNORDERED) && - nan) { + if (Flags & (1 << IR::FCMP_FLAG_UNORDERED) && nan) { ResultFlags |= (1 << IR::FCMP_FLAG_UNORDERED); } - if (Flags & (1 << IR::FCMP_FLAG_EQ) && - eq) { + if (Flags & (1 << IR::FCMP_FLAG_EQ) && eq) { ResultFlags |= (1 << IR::FCMP_FLAG_EQ); } return ResultFlags; @@ -77,14 +62,12 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static float handle4(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static float handle4(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); return src; } - FEXCORE_PRESERVE_ALL_ATTR - static double handle8(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static double handle8(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); return src; } @@ -92,26 +75,22 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static int16_t handle2(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static int16_t handle2(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); return src; } - FEXCORE_PRESERVE_ALL_ATTR - static int32_t handle4(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static int32_t handle4(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); return src; } - FEXCORE_PRESERVE_ALL_ATTR - static int64_t handle8(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static int64_t handle8(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); return src; } - FEXCORE_PRESERVE_ALL_ATTR - static int16_t handle2t(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static int16_t handle2t(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); auto rv = extF80_to_i32(src, softfloat_round_minMag, false); @@ -124,14 +103,12 @@ struct OpHandlers { } } - FEXCORE_PRESERVE_ALL_ATTR - static int32_t handle4t(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static int32_t handle4t(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); return extF80_to_i32(src, softfloat_round_minMag, false); } - FEXCORE_PRESERVE_ALL_ATTR - static int64_t handle8t(uint16_t NewFCW, X80SoftFloat src) { + FEXCORE_PRESERVE_ALL_ATTR static int64_t handle8t(uint16_t NewFCW, X80SoftFloat src) { LoadDeferredFCW(NewFCW); return extF80_to_i64(src, softfloat_round_minMag, false); } @@ -139,14 +116,12 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle2(uint16_t NewFCW, int16_t src) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle2(uint16_t NewFCW, int16_t src) { LoadDeferredFCW(NewFCW); return src; } - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle4(uint16_t NewFCW, int32_t src) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle4(uint16_t NewFCW, int32_t src) { LoadDeferredFCW(NewFCW); return src; } @@ -154,8 +129,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FRNDINT(Src1); } @@ -163,8 +137,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::F2XM1(Src1); } @@ -172,8 +145,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FTAN(Src1); } @@ -181,8 +153,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FSQRT(Src1); } @@ -190,8 +161,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FSIN(Src1); } @@ -199,8 +169,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FCOS(Src1); } @@ -208,8 +177,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FXTRACT_EXP(Src1); } @@ -217,8 +185,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FXTRACT_SIG(Src1); } @@ -226,8 +193,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FADD(Src1, Src2); } @@ -235,8 +201,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FSUB(Src1, Src2); } @@ -244,8 +209,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FMUL(Src1, Src2); } @@ -253,8 +217,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FDIV(Src1, Src2); } @@ -262,8 +225,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FYL2X(Src1, Src2); } @@ -271,8 +233,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FATAN(Src1, Src2); } @@ -280,8 +241,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FREM1(Src1, Src2); } @@ -289,8 +249,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FREM(Src1, Src2); } @@ -298,8 +257,7 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1, X80SoftFloat Src2) { LoadDeferredFCW(NewFCW); return X80SoftFloat::FSCALE(Src1, Src2); } @@ -373,15 +331,14 @@ template<> struct OpHandlers { static double handle(uint16_t NewFCW, double src1, double src2) { LoadDeferredFCW(NewFCW); - double trunc = (double)(int64_t)(src2); //truncate + double trunc = (double)(int64_t)(src2); // truncate return src1 * exp2(trunc); } }; template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src1) { LoadDeferredFCW(NewFCW); bool Negative = Src1.Sign; @@ -392,7 +349,7 @@ struct OpHandlers { uint64_t Tmp = Src1; X80SoftFloat Rv; - uint8_t *BCD = reinterpret_cast(&Rv); + uint8_t* BCD = reinterpret_cast(&Rv); memset(BCD, 0, 10); for (size_t i = 0; i < 9; ++i) { @@ -422,11 +379,10 @@ struct OpHandlers { template<> struct OpHandlers { - FEXCORE_PRESERVE_ALL_ATTR - static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src) { + FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat handle(uint16_t NewFCW, X80SoftFloat Src) { LoadDeferredFCW(NewFCW); - uint8_t *Src1 = reinterpret_cast(&Src); - uint64_t BCD{}; + 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 diff --git a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h index 24dfdbd6a..ee65b65de 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h +++ b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h @@ -68,8 +68,7 @@ namespace FEXCore::CPU { // // 5. Done. // -template -struct OpHandlers { -}; +template +struct OpHandlers {}; } // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp index e20b7b99b..2587d8fce 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp +++ b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/InterpreterFallbacks.cpp @@ -10,23 +10,23 @@ namespace FEXCore::CPU { template -static FallbackInfo GetFallbackInfo(R(*fn)(Args...), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { +static FallbackInfo GetFallbackInfo(R (*fn)(Args...), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { return {FABI_UNKNOWN, (void*)fn, HandlerIndex, false}; } template<> -FallbackInfo GetFallbackInfo(double(*fn)(uint16_t, double), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { +FallbackInfo GetFallbackInfo(double (*fn)(uint16_t, double), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { return {FABI_F64_I16_F64, (void*)fn, HandlerIndex, false}; } template<> -FallbackInfo GetFallbackInfo(double(*fn)(uint16_t, double,double), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { +FallbackInfo GetFallbackInfo(double (*fn)(uint16_t, double, double), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { return {FABI_F64_I16_F64_F64, (void*)fn, HandlerIndex, false}; } -void InterpreterOps::FillFallbackIndexPointers(uint64_t *Info) { - Info[Core::OPINDEX_F80CVTTO_4] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle4); - Info[Core::OPINDEX_F80CVTTO_8] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle8); +void InterpreterOps::FillFallbackIndexPointers(uint64_t* Info) { + Info[Core::OPINDEX_F80CVTTO_4] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle4); + Info[Core::OPINDEX_F80CVTTO_8] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle8); Info[Core::OPINDEX_F80CVT_4] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle4); Info[Core::OPINDEX_F80CVT_8] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle8); Info[Core::OPINDEX_F80CVTINT_2] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle2); @@ -55,8 +55,8 @@ void InterpreterOps::FillFallbackIndexPointers(uint64_t *Info) { Info[Core::OPINDEX_F80COS] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); Info[Core::OPINDEX_F80XTRACT_EXP] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); Info[Core::OPINDEX_F80XTRACT_SIG] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); - Info[Core::OPINDEX_F80BCDSTORE] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); - Info[Core::OPINDEX_F80BCDLOAD] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); + Info[Core::OPINDEX_F80BCDSTORE] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); + Info[Core::OPINDEX_F80BCDLOAD] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); // Binary Info[Core::OPINDEX_F80ADD] = reinterpret_cast(&FEXCore::CPU::OpHandlers::handle); @@ -87,124 +87,121 @@ void InterpreterOps::FillFallbackIndexPointers(uint64_t *Info) { bool InterpreterOps::GetFallbackHandler(bool SupportsPreserveAllABI, const IR::IROp_Header* IROp, FallbackInfo* Info) { uint8_t OpSize = IROp->Size; - switch(IROp->Op) { - case IR::OP_F80CVTTO: { - auto Op = IROp->C(); + switch (IROp->Op) { + case IR::OP_F80CVTTO: { + auto Op = IROp->C(); - switch (Op->SrcSize) { - case 4: { - *Info = {FABI_F80_I16_F32, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVTTO_4, SupportsPreserveAllABI}; - return true; - } - case 8: { - *Info = {FABI_F80_I16_F64, (void*)&FEXCore::CPU::OpHandlers::handle8, Core::OPINDEX_F80CVTTO_8, SupportsPreserveAllABI}; - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; - } - case IR::OP_F80CVT: { - switch (OpSize) { - case 4: { - *Info = {FABI_F32_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVT_4, SupportsPreserveAllABI}; - return true; - } - case 8: { - *Info = {FABI_F64_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle8, Core::OPINDEX_F80CVT_8, SupportsPreserveAllABI}; - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; - } - case IR::OP_F80CVTINT: { - auto Op = IROp->C(); - - switch (OpSize) { - case 2: { - if (Op->Truncate) { - *Info = {FABI_I16_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle2t, Core::OPINDEX_F80CVTINT_TRUNC2, SupportsPreserveAllABI}; - } - else { - *Info = {FABI_I16_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle2, Core::OPINDEX_F80CVTINT_2, SupportsPreserveAllABI}; - } - return true; - } - case 4: { - if (Op->Truncate) { - *Info = {FABI_I32_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle4t, Core::OPINDEX_F80CVTINT_TRUNC4, SupportsPreserveAllABI}; - } - else { - *Info = {FABI_I32_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVTINT_4, SupportsPreserveAllABI}; - } - return true; - } - case 8: { - if (Op->Truncate) { - *Info = {FABI_I64_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle8t, Core::OPINDEX_F80CVTINT_TRUNC8, SupportsPreserveAllABI}; - } - else { - *Info = {FABI_I64_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle8, Core::OPINDEX_F80CVTINT_8, SupportsPreserveAllABI}; - } - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; - } - case IR::OP_F80CMP: { - auto Op = IROp->C(); - - static constexpr std::array handlers{ - &FEXCore::CPU::OpHandlers::handle<0>, - &FEXCore::CPU::OpHandlers::handle<1>, - &FEXCore::CPU::OpHandlers::handle<2>, - &FEXCore::CPU::OpHandlers::handle<3>, - &FEXCore::CPU::OpHandlers::handle<4>, - &FEXCore::CPU::OpHandlers::handle<5>, - &FEXCore::CPU::OpHandlers::handle<6>, - &FEXCore::CPU::OpHandlers::handle<7>, - }; - - *Info = {FABI_I64_I16_F80_F80, (void*)handlers[Op->Flags], (Core::FallbackHandlerIndex)(Core::OPINDEX_F80CMP_0 + Op->Flags), SupportsPreserveAllABI}; + switch (Op->SrcSize) { + case 4: { + *Info = {FABI_F80_I16_F32, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVTTO_4, SupportsPreserveAllABI}; return true; } - - case IR::OP_F80CVTTOINT: { - auto Op = IROp->C(); - - switch (Op->SrcSize) { - case 2: { - *Info = {FABI_F80_I16_I16, (void*)&FEXCore::CPU::OpHandlers::handle2, Core::OPINDEX_F80CVTTOINT_2, SupportsPreserveAllABI}; - return true; - } - case 4: { - *Info = {FABI_F80_I16_I32, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVTTOINT_4, SupportsPreserveAllABI}; - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; + case 8: { + *Info = {FABI_F80_I16_F64, (void*)&FEXCore::CPU::OpHandlers::handle8, Core::OPINDEX_F80CVTTO_8, SupportsPreserveAllABI}; + return true; } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } + case IR::OP_F80CVT: { + switch (OpSize) { + case 4: { + *Info = {FABI_F32_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVT_4, SupportsPreserveAllABI}; + return true; + } + case 8: { + *Info = {FABI_F64_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle8, Core::OPINDEX_F80CVT_8, SupportsPreserveAllABI}; + return true; + } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } + case IR::OP_F80CVTINT: { + auto Op = IROp->C(); + + switch (OpSize) { + case 2: { + if (Op->Truncate) { + *Info = {FABI_I16_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle2t, Core::OPINDEX_F80CVTINT_TRUNC2, + SupportsPreserveAllABI}; + } else { + *Info = {FABI_I16_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle2, Core::OPINDEX_F80CVTINT_2, SupportsPreserveAllABI}; + } + return true; + } + case 4: { + if (Op->Truncate) { + *Info = {FABI_I32_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle4t, Core::OPINDEX_F80CVTINT_TRUNC4, + SupportsPreserveAllABI}; + } else { + *Info = {FABI_I32_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVTINT_4, SupportsPreserveAllABI}; + } + return true; + } + case 8: { + if (Op->Truncate) { + *Info = {FABI_I64_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle8t, Core::OPINDEX_F80CVTINT_TRUNC8, + SupportsPreserveAllABI}; + } else { + *Info = {FABI_I64_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle8, Core::OPINDEX_F80CVTINT_8, SupportsPreserveAllABI}; + } + return true; + } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } + case IR::OP_F80CMP: { + auto Op = IROp->C(); + + static constexpr std::array handlers { + &FEXCore::CPU::OpHandlers::handle<0>, &FEXCore::CPU::OpHandlers::handle<1>, + &FEXCore::CPU::OpHandlers::handle<2>, &FEXCore::CPU::OpHandlers::handle<3>, + &FEXCore::CPU::OpHandlers::handle<4>, &FEXCore::CPU::OpHandlers::handle<5>, + &FEXCore::CPU::OpHandlers::handle<6>, &FEXCore::CPU::OpHandlers::handle<7>, + }; + + *Info = {FABI_I64_I16_F80_F80, (void*)handlers[Op->Flags], (Core::FallbackHandlerIndex)(Core::OPINDEX_F80CMP_0 + Op->Flags), + SupportsPreserveAllABI}; + return true; + } + + case IR::OP_F80CVTTOINT: { + auto Op = IROp->C(); + + switch (Op->SrcSize) { + case 2: { + *Info = {FABI_F80_I16_I16, (void*)&FEXCore::CPU::OpHandlers::handle2, Core::OPINDEX_F80CVTTOINT_2, SupportsPreserveAllABI}; + return true; + } + case 4: { + *Info = {FABI_F80_I16_I32, (void*)&FEXCore::CPU::OpHandlers::handle4, Core::OPINDEX_F80CVTTOINT_4, SupportsPreserveAllABI}; + return true; + } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } #define COMMON_UNARY_X87_OP(OP) \ - case IR::OP_F80##OP: { \ - *Info = {FABI_F80_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F80##OP, SupportsPreserveAllABI}; \ - return true; \ - } + case IR::OP_F80##OP: { \ + *Info = {FABI_F80_I16_F80, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F80##OP, SupportsPreserveAllABI}; \ + return true; \ + } #define COMMON_BINARY_X87_OP(OP) \ - case IR::OP_F80##OP: { \ - *Info = {FABI_F80_I16_F80_F80, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F80##OP, SupportsPreserveAllABI}; \ - return true; \ - } + case IR::OP_F80##OP: { \ + *Info = {FABI_F80_I16_F80_F80, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F80##OP, SupportsPreserveAllABI}; \ + return true; \ + } #define COMMON_F64_OP(OP) \ - case IR::OP_F64##OP: { \ - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64##OP); \ - return true; \ - } + case IR::OP_F64##OP: { \ + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64##OP); \ + return true; \ + } // Unary COMMON_UNARY_X87_OP(ROUND) @@ -242,20 +239,20 @@ bool InterpreterOps::GetFallbackHandler(bool SupportsPreserveAllABI, const IR::I COMMON_F64_OP(FPREM) COMMON_F64_OP(SCALE) - // SSE4.2 Fallbacks - case IR::OP_VPCMPESTRX: - *Info = {FABI_I32_I64_I64_I128_I128_I16, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_VPCMPESTRX, SupportsPreserveAllABI}; - return true; - case IR::OP_VPCMPISTRX: - *Info = {FABI_I32_I128_I128_I16, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_VPCMPISTRX, SupportsPreserveAllABI}; - return true; + // SSE4.2 Fallbacks + case IR::OP_VPCMPESTRX: + *Info = {FABI_I32_I64_I64_I128_I128_I16, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_VPCMPESTRX, + SupportsPreserveAllABI}; + return true; + case IR::OP_VPCMPISTRX: + *Info = {FABI_I32_I128_I128_I16, (void*)&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_VPCMPISTRX, SupportsPreserveAllABI}; + return true; - default: - break; + default: break; } return false; } -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h index 1adb6a4dc..3f4c981f9 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h +++ b/FEXCore/Source/Interface/Core/Interpreter/Fallbacks/VectorFallbacks.h @@ -15,9 +15,9 @@ namespace FEXCore::CPU { template<> struct OpHandlers { enum class AggregationOp { - EqualAny = 0b00, - Ranges = 0b01, - EqualEach = 0b10, + EqualAny = 0b00, + Ranges = 0b01, + EqualEach = 0b10, EqualOrdered = 0b11, }; @@ -35,8 +35,7 @@ struct OpHandlers { NegativeMasked, }; - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t handle(uint64_t RAX, uint64_t RDX, __uint128_t lhs, __uint128_t rhs, uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t handle(uint64_t RAX, uint64_t RDX, __uint128_t lhs, __uint128_t rhs, uint16_t control) { // Subtract by 1 in order to make validity limits 0-based const auto valid_lhs = GetExplicitLength(RAX, control) - 1; const auto valid_rhs = GetExplicitLength(RDX, control) - 1; @@ -45,8 +44,7 @@ struct OpHandlers { } // Main PCMPXSTRX algorithm body. Allows for reuse with both implicit and explicit length variants. - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t MainBody(const __uint128_t& lhs, int valid_lhs, const __uint128_t& rhs, int valid_rhs, uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t MainBody(const __uint128_t& lhs, int valid_lhs, const __uint128_t& rhs, int valid_rhs, uint16_t control) { const uint32_t aggregation = PerformAggregation(lhs, valid_lhs, rhs, valid_rhs, control); const int32_t upper_limit = (16 >> (control & 1)) - 1; @@ -70,8 +68,7 @@ struct OpHandlers { return result | (flags << 16); } - FEXCORE_PRESERVE_ALL_ATTR - static int32_t GetExplicitLength(uint64_t reg, uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static int32_t GetExplicitLength(uint64_t reg, uint16_t control) { // Bit 8 controls whether or not the reg value is 64-bit or 32-bit. int64_t value = 0; if (((control >> 8) & 1) != 0) { @@ -94,62 +91,50 @@ struct OpHandlers { return std::abs(static_cast(value)); } - FEXCORE_PRESERVE_ALL_ATTR - static int32_t GetElement(const __uint128_t& vec, int32_t index, uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static int32_t GetElement(const __uint128_t& vec, int32_t index, uint16_t control) { const auto* vec_ptr = reinterpret_cast(&vec); // Control bits [1:0] define the data type being dealt with. switch (static_cast(control & 0b11)) { - case SourceData::U8: - return static_cast(vec_ptr[index]); + case SourceData::U8: return static_cast(vec_ptr[index]); case SourceData::U16: { - uint16_t value{}; + uint16_t value {}; std::memcpy(&value, vec_ptr + (sizeof(uint16_t) * static_cast(index)), sizeof(value)); return value; } - case SourceData::S8: - return static_cast(vec_ptr[index]); + case SourceData::S8: return static_cast(vec_ptr[index]); case SourceData::S16: default: { - int16_t value{}; + int16_t value {}; std::memcpy(&value, vec_ptr + (sizeof(int16_t) * static_cast(index)), sizeof(value)); return value; } } } - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t PerformAggregation(const __uint128_t& lhs, int32_t valid_lhs, - const __uint128_t& rhs, int32_t valid_rhs, - uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t + PerformAggregation(const __uint128_t& lhs, int32_t valid_lhs, const __uint128_t& rhs, int32_t valid_rhs, uint16_t control) { switch (static_cast((control >> 2) & 0b11)) { - case AggregationOp::EqualAny: - return HandleEqualAny(lhs, valid_lhs, rhs, valid_rhs, control); - case AggregationOp::Ranges: - return HandleRanges(lhs, valid_lhs, rhs, valid_rhs, control); - case AggregationOp::EqualEach: - return HandleEqualEach(lhs, valid_lhs, rhs, valid_rhs, control); + case AggregationOp::EqualAny: return HandleEqualAny(lhs, valid_lhs, rhs, valid_rhs, control); + case AggregationOp::Ranges: return HandleRanges(lhs, valid_lhs, rhs, valid_rhs, control); + case AggregationOp::EqualEach: return HandleEqualEach(lhs, valid_lhs, rhs, valid_rhs, control); case AggregationOp::EqualOrdered: - default: - return HandleEqualOrdered(lhs, valid_lhs, rhs, valid_rhs, control); + default: return HandleEqualOrdered(lhs, valid_lhs, rhs, valid_rhs, control); } } - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t HandlePolarity(uint32_t value, uint16_t control, int upper_limit, int valid_rhs) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t HandlePolarity(uint32_t value, uint16_t control, int upper_limit, int valid_rhs) { switch (static_cast((control >> 4) & 0b11)) { - case Polarity::Negative: - return value ^ ((2U << upper_limit) - 1); - case Polarity::NegativeMasked: - return value ^ ((1U << (valid_rhs + 1)) - 1); - case Polarity::Positive: - case Polarity::PositiveMasked: - default: - // Both positive masking and positive polarity are documented - // as both being equivalent to "IntRes2 = IntRes1", where IntRes1 - // is our 'value' parameter, so we don't need to do anything in - // these cases except return the same value. - return value; + case Polarity::Negative: return value ^ ((2U << upper_limit) - 1); + case Polarity::NegativeMasked: return value ^ ((1U << (valid_rhs + 1)) - 1); + case Polarity::Positive: + case Polarity::PositiveMasked: + default: + // Both positive masking and positive polarity are documented + // as both being equivalent to "IntRes2 = IntRes1", where IntRes1 + // is our 'value' parameter, so we don't need to do anything in + // these cases except return the same value. + return value; } } @@ -175,10 +160,8 @@ struct OpHandlers { // │ // 'c' match ────────┘ // - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t HandleEqualAny(const __uint128_t& lhs, int32_t valid_lhs, - const __uint128_t& rhs, int32_t valid_rhs, - uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t + HandleEqualAny(const __uint128_t& lhs, int32_t valid_lhs, const __uint128_t& rhs, int32_t valid_rhs, uint16_t control) { uint32_t result = 0; for (int j = valid_rhs; j >= 0; j--) { @@ -222,10 +205,8 @@ struct OpHandlers { // │ // 'Z' >= 'z' && 'A' <= 'z' ──────────┘ // - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t HandleRanges(const __uint128_t& lhs, int32_t valid_lhs, - const __uint128_t& rhs, int32_t valid_rhs, - uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t + HandleRanges(const __uint128_t& lhs, int32_t valid_lhs, const __uint128_t& rhs, int32_t valid_rhs, uint16_t control) { uint32_t result = 0; for (int j = valid_rhs; j >= 0; j--) { @@ -275,10 +256,8 @@ struct OpHandlers { // │ // 'a' == 'a' ──────────┘ // - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t HandleEqualEach(const __uint128_t& lhs, int32_t valid_lhs, - const __uint128_t& rhs, int32_t valid_rhs, - uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t + HandleEqualEach(const __uint128_t& lhs, int32_t valid_lhs, const __uint128_t& rhs, int32_t valid_rhs, uint16_t control) { const auto upper_limit = (16 >> (control & 1)) - 1; const auto max_valid = std::max(valid_lhs, valid_rhs); const auto min_valid = std::min(valid_lhs, valid_rhs); @@ -330,10 +309,8 @@ struct OpHandlers { // │ // At index 0 ──────────┘ // - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t HandleEqualOrdered(const __uint128_t& lhs, int32_t valid_lhs, - const __uint128_t& rhs, int32_t valid_rhs, - uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t + HandleEqualOrdered(const __uint128_t& lhs, int32_t valid_lhs, const __uint128_t& rhs, int32_t valid_rhs, uint16_t control) { const auto upper_limit = (16 >> (control & 1)) - 1; // Edge case! @@ -345,8 +322,7 @@ struct OpHandlers { } uint32_t result = 0; - const int initial = valid_rhs == upper_limit ? valid_rhs - : valid_rhs - valid_lhs; + const int initial = valid_rhs == upper_limit ? valid_rhs : valid_rhs - valid_lhs; for (int j = initial; j >= 0; j--) { result <<= 1; @@ -379,8 +355,7 @@ struct OpHandlers { // to be the max length possible for the given character size specified // in the control flags (16 characters for 8-bit, and 8 characters for 16-bit). // - FEXCORE_PRESERVE_ALL_ATTR - static uint32_t handle(__uint128_t lhs, __uint128_t rhs, uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static uint32_t handle(__uint128_t lhs, __uint128_t rhs, uint16_t control) { // Subtract by 1 in order to make validity limits 0-based const auto valid_lhs = GetImplicitLength(lhs, control) - 1; const auto valid_rhs = GetImplicitLength(rhs, control) - 1; @@ -388,8 +363,7 @@ struct OpHandlers { return OpHandlers::MainBody(lhs, valid_lhs, rhs, valid_rhs, control); } - FEXCORE_PRESERVE_ALL_ATTR - static int32_t GetImplicitLength(const __uint128_t& data, uint16_t control) { + FEXCORE_PRESERVE_ALL_ATTR static int32_t GetImplicitLength(const __uint128_t& data, uint16_t control) { const auto* data_u8 = reinterpret_cast(&data); const auto is_using_words = (control & 1) != 0; @@ -399,7 +373,7 @@ struct OpHandlers { const auto get_word = [data_u8](int32_t index) { const auto* src = data_u8 + (index * sizeof(uint16_t)); - uint16_t element{}; + uint16_t element {}; std::memcpy(&element, src, sizeof(uint16_t)); return element; }; diff --git a/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h b/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h index 7d3cf8895..aa53b130d 100644 --- a/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h +++ b/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h @@ -9,41 +9,41 @@ #include namespace FEXCore::IR { - class IRListView; - struct IROp_Header; -} +class IRListView; +struct IROp_Header; +} // namespace FEXCore::IR namespace FEXCore::CPU { - enum FallbackABI { - FABI_UNKNOWN, - FABI_F80_I16_F32, - FABI_F80_I16_F64, - FABI_F80_I16_I16, - FABI_F80_I16_I32, - FABI_F32_I16_F80, - FABI_F64_I16_F80, - FABI_F64_I16_F64, - FABI_F64_I16_F64_F64, - FABI_I16_I16_F80, - FABI_I32_I16_F80, - FABI_I64_I16_F80, - FABI_I64_I16_F80_F80, - FABI_F80_I16_F80, - FABI_F80_I16_F80_F80, - FABI_I32_I64_I64_I128_I128_I16, - FABI_I32_I128_I128_I16, - }; +enum FallbackABI { + FABI_UNKNOWN, + FABI_F80_I16_F32, + FABI_F80_I16_F64, + FABI_F80_I16_I16, + FABI_F80_I16_I32, + FABI_F32_I16_F80, + FABI_F64_I16_F80, + FABI_F64_I16_F64, + FABI_F64_I16_F64_F64, + FABI_I16_I16_F80, + FABI_I32_I16_F80, + FABI_I64_I16_F80, + FABI_I64_I16_F80_F80, + FABI_F80_I16_F80, + FABI_F80_I16_F80_F80, + FABI_I32_I64_I64_I128_I128_I16, + FABI_I32_I128_I128_I16, +}; - struct FallbackInfo { - FallbackABI ABI; - void *fn; - FEXCore::Core::FallbackHandlerIndex HandlerIndex; - bool SupportsPreserveAllABI; - }; +struct FallbackInfo { + FallbackABI ABI; + void* fn; + FEXCore::Core::FallbackHandlerIndex HandlerIndex; + bool SupportsPreserveAllABI; +}; - class InterpreterOps { - public: - static void FillFallbackIndexPointers(uint64_t *Info); - static bool GetFallbackHandler(bool SupportsPreserveAllABI, const IR::IROp_Header *IROp, FallbackInfo *Info); - }; +class InterpreterOps { +public: + static void FillFallbackIndexPointers(uint64_t* Info); + static bool GetFallbackHandler(bool SupportsPreserveAllABI, const IR::IROp_Header* IROp, FallbackInfo* Info); +}; } // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp index f10ba4cbe..056cf9d49 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp @@ -17,21 +17,19 @@ namespace FEXCore::CPU { #define GRD(Node) (IROp->Size <= 4 ? GetDst(Node) : GetDst(Node)) #define GRS(Node) (IROp->Size <= 4 ? GetReg(Node) : GetReg(Node)) -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(TruncElementPair) { auto Op = IROp->C(); switch (IROp->Size) { - case 4: { - auto Dst = GetRegPair(Node); - auto Src = GetRegPair(Op->Pair.ID()); - mov(ARMEmitter::Size::i32Bit, Dst.first, Src.first); - mov(ARMEmitter::Size::i32Bit, Dst.second, Src.second); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled Truncation size: {}", IROp->Size); - break; + case 4: { + auto Dst = GetRegPair(Node); + auto Src = GetRegPair(Op->Pair.ID()); + mov(ARMEmitter::Size::i32Bit, Dst.first, Src.first); + mov(ARMEmitter::Size::i32Bit, Dst.second, Src.second); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled Truncation size: {}", IROp->Size); break; } } @@ -56,11 +54,11 @@ DEF_OP(EntrypointOffset) { } DEF_OP(InlineConstant) { - //nop + // nop } DEF_OP(InlineEntrypointOffset) { - //nop + // nop } DEF_OP(CycleCounter) { @@ -358,7 +356,7 @@ DEF_OP(AXFlag) { ARMEmitter::Condition MapSelectCC(IR::CondClassType Cond) { switch (Cond.Val) { - case FEXCore::IR::COND_EQ: return ARMEmitter::Condition::CC_EQ; + case FEXCore::IR::COND_EQ: return ARMEmitter::Condition::CC_EQ; case FEXCore::IR::COND_NEQ: return ARMEmitter::Condition::CC_NE; case FEXCore::IR::COND_SGE: return ARMEmitter::Condition::CC_GE; case FEXCore::IR::COND_SLT: return ARMEmitter::Condition::CC_LT; @@ -370,17 +368,15 @@ ARMEmitter::Condition MapSelectCC(IR::CondClassType Cond) { case FEXCore::IR::COND_ULE: return ARMEmitter::Condition::CC_LS; case FEXCore::IR::COND_FLU: return ARMEmitter::Condition::CC_LT; case FEXCore::IR::COND_FGE: return ARMEmitter::Condition::CC_GE; - case FEXCore::IR::COND_FLEU:return ARMEmitter::Condition::CC_LE; + case FEXCore::IR::COND_FLEU: return ARMEmitter::Condition::CC_LE; case FEXCore::IR::COND_FGT: return ARMEmitter::Condition::CC_GT; - case FEXCore::IR::COND_FU: return ARMEmitter::Condition::CC_VS; + case FEXCore::IR::COND_FU: return ARMEmitter::Condition::CC_VS; case FEXCore::IR::COND_FNU: return ARMEmitter::Condition::CC_VC; case FEXCore::IR::COND_VS: case FEXCore::IR::COND_VC: case FEXCore::IR::COND_MI: return ARMEmitter::Condition::CC_MI; case FEXCore::IR::COND_PL: return ARMEmitter::Condition::CC_PL; - default: - LOGMAN_MSG_A_FMT("Unsupported compare type"); - return ARMEmitter::Condition::CC_NV; + default: LOGMAN_MSG_A_FMT("Unsupported compare type"); return ARMEmitter::Condition::CC_NV; } } @@ -427,10 +423,11 @@ DEF_OP(Neg) { LOGMAN_THROW_AA_FMT(OpSize == 4 || OpSize == 8, "Unsupported {} size: {}", __func__, OpSize); const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; - if (Op->Cond == FEXCore::IR::COND_AL) + if (Op->Cond == FEXCore::IR::COND_AL) { neg(EmitSize, GetReg(Node), GetReg(Op->Src.ID())); - else + } else { cneg(EmitSize, GetReg(Node), GetReg(Op->Src.ID()), MapSelectCC(Op->Cond)); + } } DEF_OP(Mul) { @@ -482,8 +479,7 @@ DEF_OP(Div) { Src1 = TMP1; Src2 = TMP2; - } - else if (OpSize == 2) { + } else if (OpSize == 2) { sxth(EmitSize, TMP1, Src1); sxth(EmitSize, TMP2, Src2); @@ -513,8 +509,7 @@ DEF_OP(UDiv) { Src1 = TMP1; Src2 = TMP2; - } - else if (OpSize == 2) { + } else if (OpSize == 2) { uxth(EmitSize, TMP1, Src1); uxth(EmitSize, TMP2, Src2); @@ -543,8 +538,7 @@ DEF_OP(Rem) { Src1 = TMP1; Src2 = TMP2; - } - else if (OpSize == 2) { + } else if (OpSize == 2) { sxth(EmitSize, TMP1, Src1); sxth(EmitSize, TMP2, Src2); @@ -573,8 +567,7 @@ DEF_OP(URem) { Src1 = TMP1; Src2 = TMP2; - } - else if (OpSize == 2) { + } else if (OpSize == 2) { uxth(EmitSize, TMP1, Src1); uxth(EmitSize, TMP2, Src2); @@ -601,8 +594,7 @@ DEF_OP(MulH) { sxtw(TMP2, Src2.W()); mul(ARMEmitter::Size::i32Bit, Dst, TMP1, TMP2); ubfx(ARMEmitter::Size::i32Bit, Dst, Dst, 32, 32); - } - else { + } else { smulh(Dst.X(), Src1.X(), Src2.X()); } } @@ -622,8 +614,7 @@ DEF_OP(UMulH) { uxtw(ARMEmitter::Size::i64Bit, TMP2, Src2); mul(ARMEmitter::Size::i64Bit, Dst, TMP1, TMP2); ubfx(ARMEmitter::Size::i64Bit, Dst, Dst, 32, 32); - } - else { + } else { umulh(Dst.X(), Src1.X(), Src2.X()); } } @@ -844,8 +835,7 @@ DEF_OP(Ashr) { if (IsInlineConstant(Op->Src2, &Const)) { if (OpSize >= 4) { asr(EmitSize, Dst, Src1, (unsigned int)Const); - } - else { + } else { sbfx(EmitSize, TMP1, Src1, 0, OpSize * 8); asr(EmitSize, Dst, TMP1, (unsigned int)Const); ubfx(EmitSize, Dst, Dst, 0, OpSize * 8); @@ -854,8 +844,7 @@ DEF_OP(Ashr) { const auto Src2 = GetReg(Op->Src2.ID()); if (OpSize >= 4) { asrv(EmitSize, Dst, Src1, Src2); - } - else { + } else { sbfx(EmitSize, TMP1, Src1, 0, OpSize * 8); asrv(EmitSize, Dst, TMP1, Src2); ubfx(EmitSize, Dst, Dst, 0, OpSize * 8); @@ -880,8 +869,9 @@ DEF_OP(ShiftFlags) { // Set the output outside the branch to avoid needing an extra leg of the // branch. We specifically do not hardcode the PF register anywhere (relying // on a tied SRA register instead) to avoid fighting with RA/RCLSE. - if (PFTemp != PFInput) + if (PFTemp != PFInput) { mov(ARMEmitter::Size::i64Bit, PFTemp, PFInput); + } ARMEmitter::SingleUseForwardLabel Done; cbz(EmitSize, Src2, &Done); @@ -919,8 +909,9 @@ DEF_OP(ShiftFlags) { if (CTX->HostFeatures.SupportsFlagM) { rmif(TMP1, 63, (1 << 1) /* C */); - if (SetOF) + if (SetOF) { rmif(TMP3, OpSize * 8 - 1, (1 << 0) /* V */); + } } else { mrs(TMP2, ARMEmitter::SystemRegister::NZCV); bfi(ARMEmitter::Size::i32Bit, TMP2, TMP1, 29 /* C */, 1); @@ -935,8 +926,9 @@ DEF_OP(ShiftFlags) { } // TODO: Make RA less dumb so this can't happen (e.g. with late-kill). - if (PFBlocked) + if (PFBlocked) { mov(ARMEmitter::Size::i64Bit, PFOutput, PFTemp); + } Bind(&Done); } @@ -1000,11 +992,11 @@ DEF_OP(PDep) { // So we have shadow as temporaries const auto Input = TMP1.R(); - const auto Mask = TMP2.R(); + const auto Mask = TMP2.R(); // these get used variously as scratch - const auto T0 = TMP3.R(); - const auto T1 = TMP4.R(); + const auto T0 = TMP3.R(); + const auto T1 = TMP4.R(); ARMEmitter::BackwardLabel NextBit; ARMEmitter::SingleUseForwardLabel Done; @@ -1050,8 +1042,8 @@ DEF_OP(PExt) { const auto Mask = GetReg(Op->Mask.ID()); const auto Dest = GetReg(Node); - const auto MaskReg = TMP1; - const auto BitReg = TMP2; + const auto MaskReg = TMP1; + const auto BitReg = TMP2; const auto ValueReg = TMP3; ARMEmitter::SingleUseForwardLabel EarlyExit; @@ -1094,64 +1086,60 @@ DEF_OP(LDiv) { // Each source is OpSize in size // So you can have up to a 128bit divide from x86-64 switch (OpSize) { - case 2: { - uxth(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 16, 16); - sxth(EmitSize, TMP2, Divisor); - sdiv(EmitSize, Dst, TMP1, TMP2); + case 2: { + uxth(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 16, 16); + sxth(EmitSize, TMP2, Divisor); + sdiv(EmitSize, Dst, TMP1, TMP2); break; - } - case 4: { - // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. - mov(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 32, 32); - sxtw(TMP2, Divisor.W()); - sdiv(EmitSize, Dst, TMP1, TMP2); + } + case 4: { + // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. + mov(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 32, 32); + sxtw(TMP2, Divisor.W()); + sdiv(EmitSize, Dst, TMP1, TMP2); break; + } + case 8: { + ARMEmitter::SingleUseForwardLabel Only64Bit {}; + ARMEmitter::SingleUseForwardLabel LongDIVRet {}; + + // Check if the upper bits match the top bit of the lower 64-bits + // Sign extend the top bit of lower bits + sbfx(EmitSize, TMP1, Lower, 63, 1); + eor(EmitSize, TMP1, TMP1, Upper); + + // If the sign bit matches then the result is zero + cbz(EmitSize, TMP1, &Only64Bit); + + // Long divide + { + mov(EmitSize, TMP1, Upper); + mov(EmitSize, TMP2, Lower); + mov(EmitSize, TMP3, Divisor); + + ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LDIVHandler)); + + str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); + blr(TMP4); + ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); + + // Move result to its destination register + mov(EmitSize, Dst, TMP1); + + // Skip 64-bit path + b(&LongDIVRet); } - case 8: { - ARMEmitter::SingleUseForwardLabel Only64Bit{}; - ARMEmitter::SingleUseForwardLabel LongDIVRet{}; - // Check if the upper bits match the top bit of the lower 64-bits - // Sign extend the top bit of lower bits - sbfx(EmitSize, TMP1, Lower, 63, 1); - eor(EmitSize, TMP1, TMP1, Upper); + Bind(&Only64Bit); + // 64-Bit only + { sdiv(EmitSize, Dst, Lower, Divisor); } - // If the sign bit matches then the result is zero - cbz(EmitSize, TMP1, &Only64Bit); - - // Long divide - { - mov(EmitSize, TMP1, Upper); - mov(EmitSize, TMP2, Lower); - mov(EmitSize, TMP3, Divisor); - - ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LDIVHandler)); - - str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); - blr(TMP4); - ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); - - // Move result to its destination register - mov(EmitSize, Dst, TMP1); - - // Skip 64-bit path - b(&LongDIVRet); - } - - Bind(&Only64Bit); - // 64-Bit only - { - sdiv(EmitSize, Dst, Lower, Divisor); - } - - Bind(&LongDIVRet); + Bind(&LongDIVRet); break; - } - default: - LOGMAN_MSG_A_FMT("Unknown LDIV Size: {}", OpSize); - break; + } + default: LOGMAN_MSG_A_FMT("Unknown LDIV Size: {}", OpSize); break; } } @@ -1168,58 +1156,54 @@ DEF_OP(LUDiv) { // Each source is OpSize in size // So you can have up to a 128bit divide from x86-64= switch (OpSize) { - case 2: { - uxth(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 16, 16); - udiv(EmitSize, Dst, TMP1, Divisor); + case 2: { + uxth(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 16, 16); + udiv(EmitSize, Dst, TMP1, Divisor); break; - } - case 4: { - // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. - mov(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 32, 32); - udiv(EmitSize, Dst, TMP1, Divisor); + } + case 4: { + // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. + mov(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 32, 32); + udiv(EmitSize, Dst, TMP1, Divisor); break; + } + case 8: { + ARMEmitter::SingleUseForwardLabel Only64Bit {}; + ARMEmitter::SingleUseForwardLabel LongDIVRet {}; + + // Check the upper bits for zero + // If the upper bits are zero then we can do a 64-bit divide + cbz(EmitSize, Upper, &Only64Bit); + + // Long divide + { + mov(EmitSize, TMP1, Upper); + mov(EmitSize, TMP2, Lower); + mov(EmitSize, TMP3, Divisor); + + ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LUDIVHandler)); + + str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); + blr(TMP4); + ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); + + // Move result to its destination register + mov(EmitSize, Dst, TMP1); + + // Skip 64-bit path + b(&LongDIVRet); } - case 8: { - ARMEmitter::SingleUseForwardLabel Only64Bit{}; - ARMEmitter::SingleUseForwardLabel LongDIVRet{}; - // Check the upper bits for zero - // If the upper bits are zero then we can do a 64-bit divide - cbz(EmitSize, Upper, &Only64Bit); + Bind(&Only64Bit); + // 64-Bit only + { udiv(EmitSize, Dst, Lower, Divisor); } - // Long divide - { - mov(EmitSize, TMP1, Upper); - mov(EmitSize, TMP2, Lower); - mov(EmitSize, TMP3, Divisor); - - ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LUDIVHandler)); - - str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); - blr(TMP4); - ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); - - // Move result to its destination register - mov(EmitSize, Dst, TMP1); - - // Skip 64-bit path - b(&LongDIVRet); - } - - Bind(&Only64Bit); - // 64-Bit only - { - udiv(EmitSize, Dst, Lower, Divisor); - } - - Bind(&LongDIVRet); + Bind(&LongDIVRet); break; - } - default: - LOGMAN_MSG_A_FMT("Unknown LUDIV Size: {}", OpSize); - break; + } + default: LOGMAN_MSG_A_FMT("Unknown LUDIV Size: {}", OpSize); break; } } @@ -1236,66 +1220,64 @@ DEF_OP(LRem) { // Each source is OpSize in size // So you can have up to a 128bit divide from x86-64 switch (OpSize) { - case 2: { - uxth(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 16, 16); - sxth(EmitSize, TMP2, Divisor); - sdiv(EmitSize, TMP3, TMP1, TMP2); - msub(EmitSize, Dst, TMP3, TMP2, TMP1); + case 2: { + uxth(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 16, 16); + sxth(EmitSize, TMP2, Divisor); + sdiv(EmitSize, TMP3, TMP1, TMP2); + msub(EmitSize, Dst, TMP3, TMP2, TMP1); break; - } - case 4: { - // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. - mov(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 32, 32); - sxtw(TMP3, Divisor.W()); - sdiv(EmitSize, TMP2, TMP1, TMP3); - msub(EmitSize, Dst, TMP2, TMP3, TMP1); + } + case 4: { + // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. + mov(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 32, 32); + sxtw(TMP3, Divisor.W()); + sdiv(EmitSize, TMP2, TMP1, TMP3); + msub(EmitSize, Dst, TMP2, TMP3, TMP1); break; + } + case 8: { + ARMEmitter::SingleUseForwardLabel Only64Bit {}; + ARMEmitter::SingleUseForwardLabel LongDIVRet {}; + + // Check if the upper bits match the top bit of the lower 64-bits + // Sign extend the top bit of lower bits + sbfx(EmitSize, TMP1, Lower, 63, 1); + eor(EmitSize, TMP1, TMP1, Upper); + + // If the sign bit matches then the result is zero + cbz(EmitSize, TMP1, &Only64Bit); + + // Long divide + { + mov(EmitSize, TMP1, Upper); + mov(EmitSize, TMP2, Lower); + mov(EmitSize, TMP3, Divisor); + + ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LREMHandler)); + + str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); + blr(TMP4); + ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); + + // Move result to its destination register + mov(EmitSize, Dst, TMP1); + + // Skip 64-bit path + b(&LongDIVRet); } - case 8: { - ARMEmitter::SingleUseForwardLabel Only64Bit{}; - ARMEmitter::SingleUseForwardLabel LongDIVRet{}; - // Check if the upper bits match the top bit of the lower 64-bits - // Sign extend the top bit of lower bits - sbfx(EmitSize, TMP1, Lower, 63, 1); - eor(EmitSize, TMP1, TMP1, Upper); - - // If the sign bit matches then the result is zero - cbz(EmitSize, TMP1, &Only64Bit); - - // Long divide - { - mov(EmitSize, TMP1, Upper); - mov(EmitSize, TMP2, Lower); - mov(EmitSize, TMP3, Divisor); - - ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LREMHandler)); - - str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); - blr(TMP4); - ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); - - // Move result to its destination register - mov(EmitSize, Dst, TMP1); - - // Skip 64-bit path - b(&LongDIVRet); - } - - Bind(&Only64Bit); - // 64-Bit only - { - sdiv(EmitSize, TMP1, Lower, Divisor); - msub(EmitSize, Dst, TMP1, Divisor, Lower); - } - Bind(&LongDIVRet); + Bind(&Only64Bit); + // 64-Bit only + { + sdiv(EmitSize, TMP1, Lower, Divisor); + msub(EmitSize, Dst, TMP1, Divisor, Lower); + } + Bind(&LongDIVRet); break; - } - default: - LOGMAN_MSG_A_FMT("Unknown LREM Size: {}", OpSize); - break; + } + default: LOGMAN_MSG_A_FMT("Unknown LREM Size: {}", OpSize); break; } } @@ -1312,61 +1294,59 @@ DEF_OP(LURem) { // Each source is OpSize in size // So you can have up to a 128bit divide from x86-64 switch (OpSize) { - case 2: { - uxth(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 16, 16); - udiv(EmitSize, TMP2, TMP1, Divisor); - msub(EmitSize, Dst, TMP2, Divisor, TMP1); + case 2: { + uxth(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 16, 16); + udiv(EmitSize, TMP2, TMP1, Divisor); + msub(EmitSize, Dst, TMP2, Divisor, TMP1); break; - } - case 4: { - // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. - mov(EmitSize, TMP1, Lower); - bfi(EmitSize, TMP1, Upper, 32, 32); - udiv(EmitSize, TMP2, TMP1, Divisor); - msub(EmitSize, Dst, TMP2, Divisor, TMP1); + } + case 4: { + // TODO: 32-bit operation should be guaranteed not to leave garbage in the upper bits. + mov(EmitSize, TMP1, Lower); + bfi(EmitSize, TMP1, Upper, 32, 32); + udiv(EmitSize, TMP2, TMP1, Divisor); + msub(EmitSize, Dst, TMP2, Divisor, TMP1); break; + } + case 8: { + ARMEmitter::SingleUseForwardLabel Only64Bit {}; + ARMEmitter::SingleUseForwardLabel LongDIVRet {}; + + // Check the upper bits for zero + // If the upper bits are zero then we can do a 64-bit divide + cbz(EmitSize, Upper, &Only64Bit); + + // Long divide + { + mov(EmitSize, TMP1, Upper); + mov(EmitSize, TMP2, Lower); + mov(EmitSize, TMP3, Divisor); + + ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LUREMHandler)); + + str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); + blr(TMP4); + ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); + + // Move result to its destination register + mov(EmitSize, Dst, TMP1); + + // Skip 64-bit path + b(&LongDIVRet); } - case 8: { - ARMEmitter::SingleUseForwardLabel Only64Bit{}; - ARMEmitter::SingleUseForwardLabel LongDIVRet{}; - // Check the upper bits for zero - // If the upper bits are zero then we can do a 64-bit divide - cbz(EmitSize, Upper, &Only64Bit); + Bind(&Only64Bit); + // 64-Bit only + { + udiv(EmitSize, TMP1, Lower, Divisor); + msub(EmitSize, Dst, TMP1, Divisor, Lower); + } - // Long divide - { - mov(EmitSize, TMP1, Upper); - mov(EmitSize, TMP2, Lower); - mov(EmitSize, TMP3, Divisor); - - ldr(TMP4, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.LUREMHandler)); - - str(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16); - blr(TMP4); - ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); - - // Move result to its destination register - mov(EmitSize, Dst, TMP1); - - // Skip 64-bit path - b(&LongDIVRet); - } - - Bind(&Only64Bit); - // 64-Bit only - { - udiv(EmitSize, TMP1, Lower, Divisor); - msub(EmitSize, Dst, TMP1, Divisor, Lower); - } - - Bind(&LongDIVRet); + Bind(&LongDIVRet); break; - } - default: - LOGMAN_MSG_A_FMT("Unknown LUREM Size: {}", OpSize); - break; + } + default: LOGMAN_MSG_A_FMT("Unknown LUREM Size: {}", OpSize); break; } } @@ -1391,30 +1371,30 @@ DEF_OP(Popcount) { const auto Src = GetReg(Op->Src.ID()); switch (OpSize) { - case 0x1: - fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src); - // only use lowest byte - cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); - break; - case 0x2: - fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src); - cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); - // only count two lowest bytes - addp(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D(), VTMP1.D()); - break; - case 0x4: - fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src); - cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); - // fmov has zero extended, unused bytes are zero - addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); - break; - case 0x8: - fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), Src); - cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); - // fmov has zero extended, unused bytes are zero - addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); - break; - default: LOGMAN_MSG_A_FMT("Unsupported Popcount size: {}", OpSize); + case 0x1: + fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src); + // only use lowest byte + cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); + break; + case 0x2: + fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src); + cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); + // only count two lowest bytes + addp(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D(), VTMP1.D()); + break; + case 0x4: + fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src); + cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); + // fmov has zero extended, unused bytes are zero + addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); + break; + case 0x8: + fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), Src); + cnt(FEXCore::ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); + // fmov has zero extended, unused bytes are zero + addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D()); + break; + default: LOGMAN_MSG_A_FMT("Unsupported Popcount size: {}", OpSize); } umov(Dst, VTMP1, 0); @@ -1433,15 +1413,13 @@ DEF_OP(FindLSB) { ubfx(EmitSize, TMP1, Src, 0, OpSize * 8); cmp(EmitSize, TMP1, 0); rbit(EmitSize, TMP1, TMP1); - } - else { + } else { rbit(EmitSize, TMP1, Src); cmp(EmitSize, Src, 0); } clz(EmitSize, Dst, TMP1); csinv(EmitSize, Dst, Dst, ARMEmitter::Reg::zr, ARMEmitter::Condition::CC_NE); - } DEF_OP(FindMSB) { @@ -1460,8 +1438,7 @@ DEF_OP(FindMSB) { lsl(EmitSize, Dst, Src, 16); orr(EmitSize, Dst, Dst, 0x8000); clz(EmitSize, Dst, Dst); - } - else { + } else { clz(EmitSize, Dst, Src); } @@ -1508,8 +1485,7 @@ DEF_OP(CountLeadingZeroes) { lsl(EmitSize, Dst, Src, 16); orr(EmitSize, Dst, Dst, 0x8000); clz(EmitSize, Dst, Dst); - } - else { + } else { clz(EmitSize, Dst, Src); } } @@ -1543,13 +1519,11 @@ DEF_OP(Bfi) { if (Dst == SrcDst) { // If Dst and SrcDst match then this turns in to a simple BFI instruction. bfi(EmitSize, Dst, Src, Op->lsb, Op->Width); - } - else if (Dst != Src) { + } else if (Dst != Src) { // If the destination isn't the source then we can move the DstSrc and insert directly. mov(EmitSize, Dst, SrcDst); bfi(EmitSize, Dst, Src, Op->lsb, Op->Width); - } - else { + } else { // Destination didn't match the dst source register. // TODO: Inefficient until FEX can have RA constraints here. mov(EmitSize, TMP1, SrcDst); @@ -1557,8 +1531,7 @@ DEF_OP(Bfi) { if (OpSize >= 4) { mov(EmitSize, Dst, TMP1.R()); - } - else { + } else { ubfx(EmitSize, Dst, TMP1, 0, OpSize * 8); } } @@ -1577,13 +1550,11 @@ DEF_OP(Bfxil) { if (Dst == SrcDst) { // If Dst and SrcDst match then this turns in to a single instruction. bfxil(EmitSize, Dst, Src, Op->lsb, Op->Width); - } - else if (Dst != Src) { + } else if (Dst != Src) { // If the destination isn't the source then we can move the DstSrc and insert directly. mov(EmitSize, Dst, SrcDst); bfxil(EmitSize, Dst, Src, Op->lsb, Op->Width); - } - else { + } else { // Destination didn't match the dst source register. // TODO: Inefficient until FEX can have RA constraints here. mov(EmitSize, TMP1, SrcDst); @@ -1597,8 +1568,7 @@ DEF_OP(Bfe) { LOGMAN_THROW_AA_FMT(IROp->Size <= 8, "OpSize is too large for BFE: {}", IROp->Size); LOGMAN_THROW_AA_FMT(Op->Width != 0, "Invalid BFE width of 0"); const uint8_t OpSize = IROp->Size; - const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit - : ARMEmitter::Size::i32Bit; + const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto Dst = GetReg(Node); const auto Src = GetReg(Op->Src.ID()); @@ -1636,20 +1606,18 @@ DEF_OP(Select) { if (IsGPR(Op->Cmp1.ID())) { const auto Src1 = GetReg(Op->Cmp1.ID()); - if (IsInlineConstant(Op->Cmp2, &Const)) + if (IsInlineConstant(Op->Cmp2, &Const)) { cmp(CompareEmitSize, Src1, Const); - else { + } else { const auto Src2 = GetReg(Op->Cmp2.ID()); cmp(CompareEmitSize, Src1, Src2); } - } - else if (IsGPRPair(Op->Cmp1.ID())) { + } else if (IsGPRPair(Op->Cmp1.ID())) { const auto Src1 = GetRegPair(Op->Cmp1.ID()); const auto Src2 = GetRegPair(Op->Cmp2.ID()); cmp(EmitSize, Src1.first, Src2.first); ccmp(EmitSize, Src1.second, Src2.second, ARMEmitter::StatusFlags::None, cc); - } - else if (IsFPR(Op->Cmp1.ID())) { + } else if (IsFPR(Op->Cmp1.ID())) { const auto Src1 = GetVReg(Op->Cmp1.ID()); const auto Src2 = GetVReg(Op->Cmp2.ID()); fcmp(Op->CompareSize == 8 ? ARMEmitter::ScalarRegSize::i64Bit : ARMEmitter::ScalarRegSize::i32Bit, Src1, Src2); @@ -1670,10 +1638,11 @@ DEF_OP(Select) { LOGMAN_MSG_A_FMT("Select: Unsupported compare inline parameters"); } - if (const_true == all_ones) + if (const_true == all_ones) { csetm(EmitSize, Dst, cc); - else + } else { cset(EmitSize, Dst, cc); + } } else { csel(EmitSize, Dst, GetReg(Op->TrueVal.ID()), GetReg(Op->FalseVal.ID()), cc); } @@ -1699,10 +1668,11 @@ DEF_OP(NZCVSelect) { LOGMAN_MSG_A_FMT("NZCVSelect: Unsupported constant"); } - if (const_true == all_ones) + if (const_true == all_ones) { csetm(EmitSize, Dst, cc); - else + } else { cset(EmitSize, Dst, cc); + } } else { csel(EmitSize, Dst, GetReg(Op->TrueVal.ID()), GetZeroableReg(Op->FalseVal), cc); } @@ -1724,21 +1694,11 @@ DEF_OP(VExtractToGPR) { const auto PerformMove = [&](const ARMEmitter::VRegister reg, int index) { switch (OpSize) { - case 1: - umov(Dst, Vector, index); - break; - case 2: - umov(Dst, Vector, index); - break; - case 4: - umov(Dst, Vector, index); - break; - case 8: - umov(Dst, Vector, index); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled ExtractElementSize: {}", OpSize); - break; + case 1: umov(Dst, Vector, index); break; + case 2: umov(Dst, Vector, index); break; + case 4: umov(Dst, Vector, index); break; + case 8: umov(Dst, Vector, index); break; + default: LOGMAN_MSG_A_FMT("Unhandled ExtractElementSize: {}", OpSize); break; } }; @@ -1748,13 +1708,9 @@ DEF_OP(VExtractToGPR) { // when acting on larger register sizes. PerformMove(Vector, Op->Index); } else { - LOGMAN_THROW_AA_FMT(HostSupportsSVE256, - "Host doesn't support SVE. Cannot perform 256-bit operation."); - LOGMAN_THROW_AA_FMT(Is256Bit, - "Can't perform 256-bit extraction with op side: {}", OpSize); - LOGMAN_THROW_AA_FMT(Offset < AVXRegBitSize, - "Trying to extract element outside bounds of register. Offset={}, Index={}", - Offset, Op->Index); + LOGMAN_THROW_AA_FMT(HostSupportsSVE256, "Host doesn't support SVE. Cannot perform 256-bit operation."); + LOGMAN_THROW_AA_FMT(Is256Bit, "Can't perform 256-bit extraction with op side: {}", OpSize); + LOGMAN_THROW_AA_FMT(Offset < AVXRegBitSize, "Trying to extract element outside bounds of register. Offset={}, Index={}", Offset, Op->Index); // We need to use the upper 128-bit lane, so lets move it down. // Inverting our dedicated predicate for 128-bit operations selects @@ -1767,17 +1723,11 @@ DEF_OP(VExtractToGPR) { // upper half of the vector. const auto SanitizedIndex = [OpSize, Op] { switch (OpSize) { - case 1: - return Op->Index - 16; - case 2: - return Op->Index - 8; - case 4: - return Op->Index - 4; - case 8: - return Op->Index - 2; - default: - LOGMAN_MSG_A_FMT("Unhandled OpSize: {}", OpSize); - return 0; + case 1: return Op->Index - 16; + case 2: return Op->Index - 8; + case 4: return Op->Index - 4; + case 8: return Op->Index - 2; + default: LOGMAN_MSG_A_FMT("Unhandled OpSize: {}", OpSize); return 0; } }(); @@ -1795,8 +1745,7 @@ DEF_OP(Float_ToGPR_ZS) { if (Op->SrcElementSize == 8) { fcvtzs(DestSize, Dst, Src.D()); - } - else { + } else { fcvtzs(DestSize, Dst, Src.S()); } } @@ -1811,8 +1760,7 @@ DEF_OP(Float_ToGPR_S) { if (Op->SrcElementSize == 8) { frinti(VTMP1.D(), Src.D()); fcvtzs(DestSize, Dst, VTMP1.D()); - } - else { + } else { frinti(VTMP1.S(), Src.S()); fcvtzs(DestSize, Dst, VTMP1.S()); } @@ -1830,4 +1778,4 @@ DEF_OP(FCmp) { #undef DEF_OP -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/Arm64Relocations.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/Arm64Relocations.cpp index f8c225f91..67f7fc4dc 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/Arm64Relocations.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/Arm64Relocations.cpp @@ -13,21 +13,19 @@ namespace FEXCore::CPU { uint64_t Arm64JITCore::GetNamedSymbolLiteral(FEXCore::CPU::RelocNamedSymbolLiteral::NamedSymbol Op) { switch (Op) { - case FEXCore::CPU::RelocNamedSymbolLiteral::NamedSymbol::SYMBOL_LITERAL_EXITFUNCTION_LINKER: - return ThreadState->CurrentFrame->Pointers.Common.ExitFunctionLinker; - break; - default: - ERROR_AND_DIE_FMT("Unknown named symbol literal: {}", static_cast(Op)); + case FEXCore::CPU::RelocNamedSymbolLiteral::NamedSymbol::SYMBOL_LITERAL_EXITFUNCTION_LINKER: + return ThreadState->CurrentFrame->Pointers.Common.ExitFunctionLinker; break; + default: ERROR_AND_DIE_FMT("Unknown named symbol literal: {}", static_cast(Op)); break; } return ~0ULL; } -void Arm64JITCore::InsertNamedThunkRelocation(ARMEmitter::Register Reg, const IR::SHA256Sum &Sum) { - Relocation MoveABI{}; +void Arm64JITCore::InsertNamedThunkRelocation(ARMEmitter::Register Reg, const IR::SHA256Sum& Sum) { + Relocation MoveABI {}; MoveABI.NamedThunkMove.Header.Type = FEXCore::CPU::RelocationTypes::RELOC_NAMED_THUNK_MOVE; // Offset is the offset from the entrypoint of the block - auto CurrentCursor = GetCursorAddress(); + auto CurrentCursor = GetCursorAddress(); MoveABI.NamedThunkMove.Offset = CurrentCursor - CodeData.BlockBegin; MoveABI.NamedThunkMove.Symbol = Sum; MoveABI.NamedThunkMove.RegisterIndex = Reg.Idx(); @@ -43,22 +41,25 @@ Arm64JITCore::NamedSymbolLiteralPair Arm64JITCore::InsertNamedSymbolLiteral(FEXC Arm64JITCore::NamedSymbolLiteralPair Lit { .Lit = Pointer, - .MoveABI = { - .NamedSymbolLiteral = { - .Header = { - .Type = FEXCore::CPU::RelocationTypes::RELOC_NAMED_SYMBOL_LITERAL, - }, - .Symbol = Op, - .Offset = 0, + .MoveABI = + { + .NamedSymbolLiteral = + { + .Header = + { + .Type = FEXCore::CPU::RelocationTypes::RELOC_NAMED_SYMBOL_LITERAL, + }, + .Symbol = Op, + .Offset = 0, + }, }, - }, }; return Lit; } -void Arm64JITCore::PlaceNamedSymbolLiteral(NamedSymbolLiteralPair &Lit) { +void Arm64JITCore::PlaceNamedSymbolLiteral(NamedSymbolLiteralPair& Lit) { // Offset is the offset from the entrypoint of the block - auto CurrentCursor = GetCursorAddress(); + auto CurrentCursor = GetCursorAddress(); Lit.MoveABI.NamedSymbolLiteral.Offset = CurrentCursor - CodeData.BlockBegin; Bind(&Lit.Loc); @@ -67,10 +68,10 @@ void Arm64JITCore::PlaceNamedSymbolLiteral(NamedSymbolLiteralPair &Lit) { } void Arm64JITCore::InsertGuestRIPMove(ARMEmitter::Register Reg, uint64_t Constant) { - Relocation MoveABI{}; + Relocation MoveABI {}; MoveABI.GuestRIPMove.Header.Type = FEXCore::CPU::RelocationTypes::RELOC_GUEST_RIP_MOVE; // Offset is the offset from the entrypoint of the block - auto CurrentCursor = GetCursorAddress(); + auto CurrentCursor = GetCursorAddress(); MoveABI.GuestRIPMove.Offset = CurrentCursor - CodeData.BlockBegin; MoveABI.GuestRIPMove.GuestRIP = Constant; MoveABI.GuestRIPMove.RegisterIndex = Reg.Idx(); @@ -79,54 +80,54 @@ void Arm64JITCore::InsertGuestRIPMove(ARMEmitter::Register Reg, uint64_t Constan Relocations.emplace_back(MoveABI); } -bool Arm64JITCore::ApplyRelocations(uint64_t GuestEntry, uint64_t CodeEntry, uint64_t CursorEntry, size_t NumRelocations, const char* EntryRelocations) { - size_t DataIndex{}; +bool Arm64JITCore::ApplyRelocations(uint64_t GuestEntry, uint64_t CodeEntry, uint64_t CursorEntry, size_t NumRelocations, + const char* EntryRelocations) { + size_t DataIndex {}; for (size_t j = 0; j < NumRelocations; ++j) { - const FEXCore::CPU::Relocation *Reloc = reinterpret_cast(&EntryRelocations[DataIndex]); + const FEXCore::CPU::Relocation* Reloc = reinterpret_cast(&EntryRelocations[DataIndex]); LOGMAN_THROW_AA_FMT((DataIndex % alignof(Relocation)) == 0, "Alignment of relocation wasn't adhered to"); switch (Reloc->Header.Type) { - case FEXCore::CPU::RelocationTypes::RELOC_NAMED_SYMBOL_LITERAL: { - uint64_t Pointer = GetNamedSymbolLiteral(Reloc->NamedSymbolLiteral.Symbol); - // Relocation occurs at the cursorEntry + offset relative to that cursor - SetCursorOffset(CursorEntry + Reloc->NamedSymbolLiteral.Offset); + case FEXCore::CPU::RelocationTypes::RELOC_NAMED_SYMBOL_LITERAL: { + uint64_t Pointer = GetNamedSymbolLiteral(Reloc->NamedSymbolLiteral.Symbol); + // Relocation occurs at the cursorEntry + offset relative to that cursor + SetCursorOffset(CursorEntry + Reloc->NamedSymbolLiteral.Offset); - // Generate a literal so we can place it - dc64(Pointer); + // Generate a literal so we can place it + dc64(Pointer); - DataIndex += sizeof(Reloc->NamedSymbolLiteral); - break; + DataIndex += sizeof(Reloc->NamedSymbolLiteral); + break; + } + case FEXCore::CPU::RelocationTypes::RELOC_NAMED_THUNK_MOVE: { + uint64_t Pointer = reinterpret_cast(EmitterCTX->ThunkHandler->LookupThunk(Reloc->NamedThunkMove.Symbol)); + if (Pointer == ~0ULL) { + return false; } - case FEXCore::CPU::RelocationTypes::RELOC_NAMED_THUNK_MOVE: { - uint64_t Pointer = reinterpret_cast(EmitterCTX->ThunkHandler->LookupThunk(Reloc->NamedThunkMove.Symbol)); - if (Pointer == ~0ULL) { - return false; - } - // Relocation occurs at the cursorEntry + offset relative to that cursor. - SetCursorOffset(CursorEntry + Reloc->NamedThunkMove.Offset); - LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Register(Reloc->NamedThunkMove.RegisterIndex), Pointer, true); - DataIndex += sizeof(Reloc->NamedThunkMove); - break; + // Relocation occurs at the cursorEntry + offset relative to that cursor. + SetCursorOffset(CursorEntry + Reloc->NamedThunkMove.Offset); + LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Register(Reloc->NamedThunkMove.RegisterIndex), Pointer, true); + DataIndex += sizeof(Reloc->NamedThunkMove); + break; + } + case FEXCore::CPU::RelocationTypes::RELOC_GUEST_RIP_MOVE: { + // XXX: Reenable once the JIT Object Cache is upstream + // XXX: Should spin the relocation list, create a list of guest RIP moves, and ask for them all once, reduces lock contention. + uint64_t Pointer = ~0ULL; // EmitterCTX->JITObjectCache->FindRelocatedRIP(Reloc->GuestRIPMove.GuestRIP); + if (Pointer == ~0ULL) { + return false; } - case FEXCore::CPU::RelocationTypes::RELOC_GUEST_RIP_MOVE: { - // XXX: Reenable once the JIT Object Cache is upstream - // XXX: Should spin the relocation list, create a list of guest RIP moves, and ask for them all once, reduces lock contention. - uint64_t Pointer = ~0ULL; // EmitterCTX->JITObjectCache->FindRelocatedRIP(Reloc->GuestRIPMove.GuestRIP); - if (Pointer == ~0ULL) { - return false; - } - // Relocation occurs at the cursorEntry + offset relative to that cursor. - SetCursorOffset(CursorEntry + Reloc->GuestRIPMove.Offset); - LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Register(Reloc->GuestRIPMove.RegisterIndex), Pointer, true); - DataIndex += sizeof(Reloc->GuestRIPMove); - break; - } + // Relocation occurs at the cursorEntry + offset relative to that cursor. + SetCursorOffset(CursorEntry + Reloc->GuestRIPMove.Offset); + LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Register(Reloc->GuestRIPMove.RegisterIndex), Pointer, true); + DataIndex += sizeof(Reloc->GuestRIPMove); + break; + } } } return true; } -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/AtomicOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/AtomicOps.cpp index 8cf864c7f..2613f5120 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/AtomicOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/AtomicOps.cpp @@ -11,7 +11,7 @@ $end_info$ #include "Interface/Core/JIT/Arm64/JITClass.h" namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(CASPair) { auto Op = IROp->C(); LOGMAN_THROW_AA_FMT(IROp->ElementSize == 4 || IROp->ElementSize == 8, "Wrong element size"); @@ -29,8 +29,7 @@ DEF_OP(CASPair) { caspal(EmitSize, TMP3, TMP4, Desired.first, Desired.second, MemSrc); mov(EmitSize, Dst.first, TMP3.R()); mov(EmitSize, Dst.second, TMP4.R()); - } - else { + } else { // Save NZCV so we don't have to mark this op as clobbering NZCV (the // SupportsAtomics does not clobber atomics and this !SupportsAtomics path // is so slow it's not worth the complexity of splitting the IR op.). We @@ -55,12 +54,12 @@ DEF_OP(CASPair) { b(&LoopExpected); - Bind(&LoopNotExpected); - mov(EmitSize, Dst.first, TMP2.R()); - mov(EmitSize, Dst.second, TMP3.R()); - // exclusive monitor needs to be cleared here - // Might have hit the case where ldaxr was hit but stlxr wasn't - clrex(); + Bind(&LoopNotExpected); + mov(EmitSize, Dst.first, TMP2.R()); + mov(EmitSize, Dst.second, TMP3.R()); + // exclusive monitor needs to be cleared here + // Might have hit the case where ldaxr was hit but stlxr wasn't + clrex(); Bind(&LoopExpected); // Restore @@ -82,16 +81,16 @@ DEF_OP(CAS) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { mov(EmitSize, TMP2, Expected); casal(SubEmitSize, TMP2, Desired, MemSrc); mov(EmitSize, GetReg(Node), TMP2.R()); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; ARMEmitter::SingleUseForwardLabel LoopNotExpected; ARMEmitter::SingleUseForwardLabel LoopExpected; @@ -99,11 +98,9 @@ DEF_OP(CAS) { ldaxr(SubEmitSize, TMP2, MemSrc); if (OpSize == 1) { cmp(EmitSize, TMP2, Expected, ARMEmitter::ExtendedType::UXTB, 0); - } - else if (OpSize == 2) { + } else if (OpSize == 2) { cmp(EmitSize, TMP2, Expected, ARMEmitter::ExtendedType::UXTH, 0); - } - else { + } else { cmp(EmitSize, TMP2, Expected); } b(ARMEmitter::Condition::CC_NE, &LoopNotExpected); @@ -112,11 +109,11 @@ DEF_OP(CAS) { mov(EmitSize, GetReg(Node), Expected); b(&LoopExpected); - Bind(&LoopNotExpected); - mov(EmitSize, GetReg(Node), TMP2.R()); - // exclusive monitor needs to be cleared here - // Might have hit the case where ldaxr was hit but stlxr wasn't - clrex(); + Bind(&LoopNotExpected); + mov(EmitSize, GetReg(Node), TMP2.R()); + // exclusive monitor needs to be cleared here + // Might have hit the case where ldaxr was hit but stlxr wasn't + clrex(); Bind(&LoopExpected); } } @@ -131,14 +128,14 @@ DEF_OP(AtomicAdd) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { staddl(SubEmitSize, Src, MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -158,15 +155,15 @@ DEF_OP(AtomicSub) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { neg(EmitSize, TMP2, Src); staddl(SubEmitSize, TMP2, MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -186,15 +183,15 @@ DEF_OP(AtomicAnd) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { mvn(EmitSize, TMP2, Src); stclrl(SubEmitSize, TMP2, MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -214,14 +211,14 @@ DEF_OP(AtomicCLR) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { stclrl(SubEmitSize, Src, MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -241,14 +238,14 @@ DEF_OP(AtomicOr) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { stsetl(SubEmitSize, Src, MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -268,14 +265,14 @@ DEF_OP(AtomicXor) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { steorl(SubEmitSize, Src, MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -294,9 +291,10 @@ DEF_OP(AtomicNeg) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); @@ -316,14 +314,14 @@ DEF_OP(AtomicSwap) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { ldswpal(SubEmitSize, Src, GetReg(Node), MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -343,14 +341,14 @@ DEF_OP(AtomicFetchAdd) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { ldaddal(SubEmitSize, Src, GetReg(Node), MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -371,15 +369,15 @@ DEF_OP(AtomicFetchSub) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { neg(EmitSize, TMP2, Src); ldaddal(SubEmitSize, TMP2, GetReg(Node), MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -400,15 +398,15 @@ DEF_OP(AtomicFetchAnd) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { mvn(EmitSize, TMP2, Src); ldclral(SubEmitSize, TMP2, GetReg(Node), MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -429,14 +427,14 @@ DEF_OP(AtomicFetchCLR) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { ldclral(SubEmitSize, Src, GetReg(Node), MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -457,14 +455,14 @@ DEF_OP(AtomicFetchOr) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { ldsetal(SubEmitSize, Src, GetReg(Node), MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -485,14 +483,14 @@ DEF_OP(AtomicFetchXor) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (CTX->HostFeatures.SupportsAtomics) { ldeoral(SubEmitSize, Src, GetReg(Node), MemSrc); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(SubEmitSize, TMP2, MemSrc); @@ -512,9 +510,10 @@ DEF_OP(AtomicFetchNeg) { const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto SubEmitSize = OpSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + OpSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + OpSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); @@ -538,8 +537,7 @@ DEF_OP(TelemetrySetValue) { if (CTX->HostFeatures.SupportsAtomics) { stsetl(ARMEmitter::SubRegSize::i64Bit, TMP1, TMP2); - } - else { + } else { ARMEmitter::BackwardLabel LoopTop; Bind(&LoopTop); ldaxr(ARMEmitter::SubRegSize::i64Bit, TMP3, TMP2); @@ -551,5 +549,4 @@ DEF_OP(TelemetrySetValue) { } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/BranchOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/BranchOps.cpp index a19fa265a..bb3e8e4f8 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/BranchOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/BranchOps.cpp @@ -19,7 +19,7 @@ $end_info$ #include namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(CallbackReturn) { // spill back to CTX @@ -103,7 +103,7 @@ DEF_OP(Jump) { static ARMEmitter::Condition MapBranchCC(IR::CondClassType Cond) { switch (Cond.Val) { - case FEXCore::IR::COND_EQ: return ARMEmitter::Condition::CC_EQ; + case FEXCore::IR::COND_EQ: return ARMEmitter::Condition::CC_EQ; case FEXCore::IR::COND_NEQ: return ARMEmitter::Condition::CC_NE; case FEXCore::IR::COND_SGE: return ARMEmitter::Condition::CC_GE; case FEXCore::IR::COND_SLT: return ARMEmitter::Condition::CC_LT; @@ -115,17 +115,15 @@ static ARMEmitter::Condition MapBranchCC(IR::CondClassType Cond) { case FEXCore::IR::COND_ULE: return ARMEmitter::Condition::CC_LS; case FEXCore::IR::COND_FLU: return ARMEmitter::Condition::CC_LT; case FEXCore::IR::COND_FGE: return ARMEmitter::Condition::CC_GE; - case FEXCore::IR::COND_FLEU:return ARMEmitter::Condition::CC_LE; + case FEXCore::IR::COND_FLEU: return ARMEmitter::Condition::CC_LE; case FEXCore::IR::COND_FGT: return ARMEmitter::Condition::CC_GT; - case FEXCore::IR::COND_FU: return ARMEmitter::Condition::CC_VS; + case FEXCore::IR::COND_FU: return ARMEmitter::Condition::CC_VS; case FEXCore::IR::COND_FNU: return ARMEmitter::Condition::CC_VC; case FEXCore::IR::COND_VS: case FEXCore::IR::COND_VC: - case FEXCore::IR::COND_MI: return ARMEmitter::Condition::CC_MI; - case FEXCore::IR::COND_PL: return ARMEmitter::Condition::CC_PL; - default: - LOGMAN_MSG_A_FMT("Unsupported compare type"); - return ARMEmitter::Condition::CC_NV; + case FEXCore::IR::COND_MI: return ARMEmitter::Condition::CC_MI; + case FEXCore::IR::COND_PL: return ARMEmitter::Condition::CC_PL; + default: LOGMAN_MSG_A_FMT("Unsupported compare type"); return ARMEmitter::Condition::CC_NV; } } @@ -144,13 +142,12 @@ DEF_OP(CondJump) { LOGMAN_THROW_A_FMT(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR"); LOGMAN_THROW_A_FMT(isConst && Const == 0, "CondJump: Expected 0 source"); - LOGMAN_THROW_A_FMT(Op->Cond.Val == FEXCore::IR::COND_EQ || - Op->Cond.Val == FEXCore::IR::COND_NEQ, - "CondJump: Expected simple condition"); + LOGMAN_THROW_A_FMT(Op->Cond.Val == FEXCore::IR::COND_EQ || Op->Cond.Val == FEXCore::IR::COND_NEQ, "CondJump: Expected simple " + "condition"); if (Op->Cond.Val == FEXCore::IR::COND_EQ) { cbz(Size, GetReg(Op->Cmp1.ID()), TrueTargetLabel); - } else { + } else { cbnz(Size, GetReg(Op->Cmp1.ID()), TrueTargetLabel); } @@ -190,7 +187,9 @@ DEF_OP(Syscall) { uint64_t SPOffset = AlignUp(FEXCore::HLE::SyscallArguments::MAX_ARGS * 8, 16); sub(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::rsp, ARMEmitter::Reg::rsp, SPOffset); for (uint32_t i = 0; i < FEXCore::HLE::SyscallArguments::MAX_ARGS; ++i) { - if (Op->Header.Args[i].IsInvalid()) continue; + if (Op->Header.Args[i].IsInvalid()) { + continue; + } str(GetReg(Op->Header.Args[i].ID()).X(), ARMEmitter::Reg::rsp, i * 8); } @@ -202,8 +201,7 @@ DEF_OP(Syscall) { add(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r2, ARMEmitter::Reg::rsp, 0); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { + } else { blr(ARMEmitter::Reg::r3); } @@ -241,20 +239,19 @@ DEF_OP(InlineSyscall) { // X6: Arg6 - Doesn't exist in x86-64 land. RA INTERSECT // One argument is removed from the SyscallArguments::MAX_ARGS since the first argument was syscall number - const static std::array RegArgs = {{ - ARMEmitter::XReg::x0, ARMEmitter::XReg::x1, ARMEmitter::XReg::x2, ARMEmitter::XReg::x3, ARMEmitter::XReg::x4, ARMEmitter::XReg::x5 - }}; + const static std::array RegArgs = { + {ARMEmitter::XReg::x0, ARMEmitter::XReg::x1, ARMEmitter::XReg::x2, ARMEmitter::XReg::x3, ARMEmitter::XReg::x4, ARMEmitter::XReg::x5}}; - bool Intersects{}; + bool Intersects {}; // We always need to spill x8 since we can't know if it is live at this SSA location uint32_t SpillMask = 1U << 8; - for (uint32_t i = 0; i < FEXCore::HLE::SyscallArguments::MAX_ARGS-1; ++i) { - if (Op->Header.Args[i].IsInvalid()) break; + for (uint32_t i = 0; i < FEXCore::HLE::SyscallArguments::MAX_ARGS - 1; ++i) { + if (Op->Header.Args[i].IsInvalid()) { + break; + } auto Reg = GetReg(Op->Header.Args[i].ID()); - if (Reg == ARMEmitter::Reg::r8 || - Reg == ARMEmitter::Reg::r4 || - Reg == ARMEmitter::Reg::r5) { + if (Reg == ARMEmitter::Reg::r8 || Reg == ARMEmitter::Reg::r4 || Reg == ARMEmitter::Reg::r5) { SpillMask |= (1U << Reg.Idx()); Intersects = true; @@ -278,8 +275,10 @@ DEF_OP(InlineSyscall) { const auto EmitSize = CTX->Config.Is64BitMode() ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; const auto EmitSubSize = CTX->Config.Is64BitMode() ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i32Bit; if (Intersects) { - for (uint32_t i = 0; i < FEXCore::HLE::SyscallArguments::MAX_ARGS-1; ++i) { - if (Op->Header.Args[i].IsInvalid()) break; + for (uint32_t i = 0; i < FEXCore::HLE::SyscallArguments::MAX_ARGS - 1; ++i) { + if (Op->Header.Args[i].IsInvalid()) { + break; + } auto Reg = GetReg(Op->Header.Args[i].ID()); // In the case of intersection with x4, x5, or x8 then these are currently SRA @@ -287,21 +286,19 @@ DEF_OP(InlineSyscall) { // Just load back from the context. Could be slightly smarter but this is fairly uncommon if (Reg == ARMEmitter::Reg::r8) { ldr(EmitSubSize, RegArgs[i].R(), STATE, offsetof(FEXCore::Core::CpuStateFrame, State.gregs[X86State::REG_RSP])); - } - else if (Reg == ARMEmitter::Reg::r4) { + } else if (Reg == ARMEmitter::Reg::r4) { ldr(EmitSubSize, RegArgs[i].R(), STATE, offsetof(FEXCore::Core::CpuStateFrame, State.gregs[X86State::REG_RAX])); - } - else if (Reg == ARMEmitter::Reg::r5) { + } else if (Reg == ARMEmitter::Reg::r5) { ldr(EmitSubSize, RegArgs[i].R(), STATE, offsetof(FEXCore::Core::CpuStateFrame, State.gregs[X86State::REG_RCX])); - } - else { + } else { mov(EmitSize, RegArgs[i].R(), Reg); } } - } - else { - for (uint32_t i = 0; i < FEXCore::HLE::SyscallArguments::MAX_ARGS-1; ++i) { - if (Op->Header.Args[i].IsInvalid()) break; + } else { + for (uint32_t i = 0; i < FEXCore::HLE::SyscallArguments::MAX_ARGS - 1; ++i) { + if (Op->Header.Args[i].IsInvalid()) { + break; + } mov(EmitSize, RegArgs[i].R(), GetReg(Op->Header.Args[i].ID())); } @@ -342,8 +339,7 @@ DEF_OP(Thunk) { LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r2, (uintptr_t)thunkFn); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { GenerateIndirectRuntimeCall(ARMEmitter::Reg::r2); - } - else { + } else { blr(ARMEmitter::Reg::r2); } @@ -354,7 +350,7 @@ DEF_OP(Thunk) { DEF_OP(ValidateCode) { auto Op = IROp->C(); - const auto *OldCode = (const uint8_t *)&Op->CodeOriginalLow; + const auto* OldCode = (const uint8_t*)&Op->CodeOriginalLow; int len = Op->CodeLength; int idx = 0; @@ -364,37 +360,33 @@ DEF_OP(ValidateCode) { const auto Dst = GetReg(Node); - while (len >= 8) - { + while (len >= 8) { ldr(ARMEmitter::XReg::x2, TMP1, idx); - LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint32_t *)(OldCode + idx)); + LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint32_t*)(OldCode + idx)); cmp(ARMEmitter::Size::i64Bit, TMP3, TMP4); csel(ARMEmitter::Size::i64Bit, Dst, Dst, TMP2, ARMEmitter::Condition::CC_EQ); len -= 8; idx += 8; } - while (len >= 4) - { + while (len >= 4) { ldr(ARMEmitter::WReg::w2, TMP1, idx); - LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint32_t *)(OldCode + idx)); + LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint32_t*)(OldCode + idx)); cmp(ARMEmitter::Size::i32Bit, TMP3, TMP4); csel(ARMEmitter::Size::i64Bit, Dst, Dst, TMP2, ARMEmitter::Condition::CC_EQ); len -= 4; idx += 4; } - while (len >= 2) - { + while (len >= 2) { ldrh(TMP3, TMP1, idx); - LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint16_t *)(OldCode + idx)); + LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint16_t*)(OldCode + idx)); cmp(ARMEmitter::Size::i32Bit, TMP3, TMP4); csel(ARMEmitter::Size::i64Bit, Dst, Dst, TMP2, ARMEmitter::Condition::CC_EQ); len -= 2; idx += 2; } - while (len >= 1) - { + while (len >= 1) { ldrb(TMP3, TMP1, idx); - LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint8_t *)(OldCode + idx)); + LoadConstant(ARMEmitter::Size::i64Bit, TMP4, *(const uint8_t*)(OldCode + idx)); cmp(ARMEmitter::Size::i32Bit, TMP3, TMP4); csel(ARMEmitter::Size::i64Bit, Dst, Dst, TMP2, ARMEmitter::Condition::CC_EQ); len -= 1; @@ -416,8 +408,7 @@ DEF_OP(ThreadRemoveCodeEntry) { ldr(ARMEmitter::XReg::x2, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.Common.ThreadRemoveCodeEntryFromJIT)); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { GenerateIndirectRuntimeCall(ARMEmitter::Reg::r2); - } - else { + } else { blr(ARMEmitter::Reg::r2); } FillStaticRegs(); @@ -448,8 +439,7 @@ DEF_OP(CPUID) { if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { GenerateIndirectRuntimeCall<__uint128_t, void*, uint64_t, uint64_t>(ARMEmitter::Reg::r3); - } - else { + } else { blr(ARMEmitter::Reg::r3); } @@ -465,7 +455,7 @@ DEF_OP(CPUID) { // Results are in x0, x1 // Results want to be in a i64v2 vector auto Dst = GetRegPair(Node); - mov(ARMEmitter::Size::i64Bit, Dst.first, TMP1); + mov(ARMEmitter::Size::i64Bit, Dst.first, TMP1); mov(ARMEmitter::Size::i64Bit, Dst.second, TMP2); } @@ -483,8 +473,7 @@ DEF_OP(XGetBV) { ldr(ARMEmitter::XReg::x2, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.Common.XCRFunction)); if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { GenerateIndirectRuntimeCall(ARMEmitter::Reg::r2); - } - else { + } else { blr(ARMEmitter::Reg::r2); } @@ -499,10 +488,9 @@ DEF_OP(XGetBV) { // Results are in x0 // Results want to be in a i32v2 vector auto Dst = GetRegPair(Node); - mov(ARMEmitter::Size::i32Bit, Dst.first, TMP1); + mov(ARMEmitter::Size::i32Bit, Dst.first, TMP1); lsr(ARMEmitter::Size::i64Bit, Dst.second, TMP1, 32); } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ConversionOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ConversionOps.cpp index 8a0f21846..7f77fbef6 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ConversionOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ConversionOps.cpp @@ -9,7 +9,7 @@ $end_info$ #include "Interface/Core/JIT/Arm64/JITClass.h" namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(VInsGPR) { const auto Op = IROp->C(); const auto OpSize = IROp->Size; @@ -20,9 +20,10 @@ DEF_OP(VInsGPR) { LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2 || ElementSize == 1, "Unexpected {} size", __func__); const auto SubEmitSize = ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; const auto ElementsPer128Bit = 16 / ElementSize; const auto Dst = GetVReg(Node); @@ -94,21 +95,17 @@ DEF_OP(VCastFromGPR) { auto Src = GetReg(Op->Src.ID()); switch (Op->Header.ElementSize) { - case 1: - uxtb(ARMEmitter::Size::i32Bit, TMP1, Src); - fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1); - break; - case 2: - uxth(ARMEmitter::Size::i32Bit, TMP1, Src); - fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1); - break; - case 4: - fmov(ARMEmitter::Size::i32Bit, Dst.S(), Src); - break; - case 8: - fmov(ARMEmitter::Size::i64Bit, Dst.D(), Src); - break; - default: LOGMAN_MSG_A_FMT("Unknown castGPR element size: {}", Op->Header.ElementSize); + case 1: + uxtb(ARMEmitter::Size::i32Bit, TMP1, Src); + fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1); + break; + case 2: + uxth(ARMEmitter::Size::i32Bit, TMP1, Src); + fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1); + break; + case 4: fmov(ARMEmitter::Size::i32Bit, Dst.S(), Src); break; + case 8: fmov(ARMEmitter::Size::i64Bit, Dst.D(), Src); break; + default: LOGMAN_MSG_A_FMT("Unknown castGPR element size: {}", Op->Header.ElementSize); } } @@ -122,14 +119,14 @@ DEF_OP(VDupFromGPR) { const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE; const auto ElementSize = IROp->ElementSize; - LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2 || ElementSize == 1, - "Unexpected {} element size: {}", __func__, ElementSize); + LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2 || ElementSize == 1, "Unexpected {} element size: {}", + __func__, ElementSize); - const auto SubEmitSize = - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubEmitSize = ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { dup(SubEmitSize, Dst.Z(), Src); @@ -148,34 +145,33 @@ DEF_OP(Float_FromGPR_S) { auto Src = GetReg(Op->Src.ID()); switch (Conv) { - case 0x0204: { // Half <- int32_t - scvtf(ARMEmitter::Size::i32Bit, Dst.H(), Src); - break; - } - case 0x0208: { // Half <- int64_t - scvtf(ARMEmitter::Size::i64Bit, Dst.H(), Src); - break; - } - case 0x0404: { // Float <- int32_t - scvtf(ARMEmitter::Size::i32Bit, Dst.S(), Src); - break; - } - case 0x0408: { // Float <- int64_t - scvtf(ARMEmitter::Size::i64Bit, Dst.S(), Src); - break; - } - case 0x0804: { // Double <- int32_t - scvtf(ARMEmitter::Size::i32Bit, Dst.D(), Src); - break; - } - case 0x0808: { // Double <- int64_t - scvtf(ARMEmitter::Size::i64Bit, Dst.D(), Src); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled conversion mask: Mask=0x{:04x}, ElementSize={}, SrcElementSize={}", - Conv, ElementSize, Op->SrcElementSize); - break; + case 0x0204: { // Half <- int32_t + scvtf(ARMEmitter::Size::i32Bit, Dst.H(), Src); + break; + } + case 0x0208: { // Half <- int64_t + scvtf(ARMEmitter::Size::i64Bit, Dst.H(), Src); + break; + } + case 0x0404: { // Float <- int32_t + scvtf(ARMEmitter::Size::i32Bit, Dst.S(), Src); + break; + } + case 0x0408: { // Float <- int64_t + scvtf(ARMEmitter::Size::i64Bit, Dst.S(), Src); + break; + } + case 0x0804: { // Double <- int32_t + scvtf(ARMEmitter::Size::i32Bit, Dst.D(), Src); + break; + } + case 0x0808: { // Double <- int64_t + scvtf(ARMEmitter::Size::i64Bit, Dst.D(), Src); + break; + } + default: + LOGMAN_MSG_A_FMT("Unhandled conversion mask: Mask=0x{:04x}, ElementSize={}, SrcElementSize={}", Conv, ElementSize, Op->SrcElementSize); + break; } } @@ -187,31 +183,31 @@ DEF_OP(Float_FToF) { auto Src = GetVReg(Op->Scalar.ID()); switch (Conv) { - case 0x0204: { // Half <- Float - fcvt(Dst.H(), Src.S()); - break; - } - case 0x0208: { // Half <- Double - fcvt(Dst.H(), Src.D()); - break; - } - case 0x0402: { // Float <- Half - fcvt(Dst.S(), Src.H()); - break; - } - case 0x0802: { // Double <- Half - fcvt(Dst.D(), Src.H()); - break; - } - case 0x0804: { // Double <- Float - fcvt(Dst.D(), Src.S()); - break; - } - case 0x0408: { // Float <- Double - fcvt(Dst.S(), Src.D()); - break; - } - default: LOGMAN_MSG_A_FMT("Unknown FCVT sizes: 0x{:x}", Conv); + case 0x0204: { // Half <- Float + fcvt(Dst.H(), Src.S()); + break; + } + case 0x0208: { // Half <- Double + fcvt(Dst.H(), Src.D()); + break; + } + case 0x0402: { // Float <- Half + fcvt(Dst.S(), Src.H()); + break; + } + case 0x0802: { // Double <- Half + fcvt(Dst.D(), Src.H()); + break; + } + case 0x0804: { // Double <- Float + fcvt(Dst.D(), Src.S()); + break; + } + case 0x0408: { // Float <- Double + fcvt(Dst.S(), Src.D()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown FCVT sizes: 0x{:x}", Conv); } } @@ -224,8 +220,9 @@ DEF_OP(Vector_SToF) { LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2, "Unexpected {} size", __func__); const auto SubEmitSize = ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : ARMEmitter::SubRegSize::i16Bit; + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ARMEmitter::SubRegSize::i16Bit; const auto Dst = GetVReg(Node); const auto Vector = GetVReg(Op->Vector.ID()); @@ -236,19 +233,15 @@ DEF_OP(Vector_SToF) { if (OpSize == ElementSize) { if (ElementSize == 8) { scvtf(ARMEmitter::ScalarRegSize::i64Bit, Dst.D(), Vector.D()); - } - else if (ElementSize == 4) { + } else if (ElementSize == 4) { scvtf(ARMEmitter::ScalarRegSize::i32Bit, Dst.S(), Vector.S()); - } - else { + } else { scvtf(ARMEmitter::ScalarRegSize::i16Bit, Dst.H(), Vector.H()); } - } - else { + } else { if (OpSize == 8) { scvtf(SubEmitSize, Dst.D(), Vector.D()); - } - else { + } else { scvtf(SubEmitSize, Dst.Q(), Vector.Q()); } } @@ -264,8 +257,9 @@ DEF_OP(Vector_FToZS) { LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2, "Unexpected {} size", __func__); const auto SubEmitSize = ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : ARMEmitter::SubRegSize::i16Bit; + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ARMEmitter::SubRegSize::i16Bit; const auto Dst = GetVReg(Node); const auto Vector = GetVReg(Op->Vector.ID()); @@ -276,19 +270,15 @@ DEF_OP(Vector_FToZS) { if (OpSize == ElementSize) { if (ElementSize == 8) { fcvtzs(ARMEmitter::ScalarRegSize::i64Bit, Dst.D(), Vector.D()); - } - else if (ElementSize == 4) { + } else if (ElementSize == 4) { fcvtzs(ARMEmitter::ScalarRegSize::i32Bit, Dst.S(), Vector.S()); - } - else { + } else { fcvtzs(ARMEmitter::ScalarRegSize::i16Bit, Dst.H(), Vector.H()); } - } - else { + } else { if (OpSize == 8) { fcvtzs(SubEmitSize, Dst.D(), Vector.D()); - } - else { + } else { fcvtzs(SubEmitSize, Dst.Q(), Vector.Q()); } } @@ -304,8 +294,9 @@ DEF_OP(Vector_FToS) { LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2, "Unexpected {} size", __func__); const auto SubEmitSize = ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : ARMEmitter::SubRegSize::i16Bit; + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ARMEmitter::SubRegSize::i16Bit; const auto Dst = GetVReg(Node); const auto Vector = GetVReg(Op->Vector.ID()); @@ -320,8 +311,7 @@ DEF_OP(Vector_FToS) { if (OpSize == 8) { frinti(SubEmitSize, Dst.D(), Vector.D()); fcvtzs(SubEmitSize, Dst.D(), Dst.D()); - } - else { + } else { frinti(SubEmitSize, Dst.Q(), Vector.Q()); fcvtzs(SubEmitSize, Dst.Q(), Dst.Q()); } @@ -338,8 +328,9 @@ DEF_OP(Vector_FToF) { LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2, "Unexpected {} size", __func__); const auto SubEmitSize = ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : ARMEmitter::SubRegSize::i16Bit; + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ARMEmitter::SubRegSize::i16Bit; const auto Dst = GetVReg(Node); const auto Vector = GetVReg(Op->Vector.ID()); @@ -361,45 +352,41 @@ DEF_OP(Vector_FToF) { const auto Mask = PRED_TMP_32B.Merging(); switch (Conv) { - case 0x0402: { // Float <- Half - zip1(FEXCore::ARMEmitter::SubRegSize::i16Bit, Dst.Z(), Vector.Z(), Vector.Z()); - fcvtlt(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Dst.Z()); - break; - } - case 0x0804: { // Double <- Float - zip1(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Vector.Z(), Vector.Z()); - fcvtlt(FEXCore::ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Dst.Z()); - break; - } - case 0x0204: { // Half <- Float - fcvtnt(FEXCore::ARMEmitter::SubRegSize::i16Bit, Dst.Z(), Mask, Vector.Z()); - uzp2(FEXCore::ARMEmitter::SubRegSize::i16Bit, Dst.Z(), Dst.Z(), Dst.Z()); - break; - } - case 0x0408: { // Float <- Double - fcvtnt(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Vector.Z()); - uzp2(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Dst.Z(), Dst.Z()); - break; - } - default: - LOGMAN_MSG_A_FMT("Unknown Vector_FToF Type : 0x{:04x}", Conv); - break; + case 0x0402: { // Float <- Half + zip1(FEXCore::ARMEmitter::SubRegSize::i16Bit, Dst.Z(), Vector.Z(), Vector.Z()); + fcvtlt(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Dst.Z()); + break; + } + case 0x0804: { // Double <- Float + zip1(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Vector.Z(), Vector.Z()); + fcvtlt(FEXCore::ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Dst.Z()); + break; + } + case 0x0204: { // Half <- Float + fcvtnt(FEXCore::ARMEmitter::SubRegSize::i16Bit, Dst.Z(), Mask, Vector.Z()); + uzp2(FEXCore::ARMEmitter::SubRegSize::i16Bit, Dst.Z(), Dst.Z(), Dst.Z()); + break; + } + case 0x0408: { // Float <- Double + fcvtnt(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Vector.Z()); + uzp2(FEXCore::ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Dst.Z(), Dst.Z()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown Vector_FToF Type : 0x{:04x}", Conv); break; } } else { switch (Conv) { - case 0x0402: // Float <- Half - case 0x0804: { // Double <- Float - fcvtl(SubEmitSize, Dst.D(), Vector.D()); - break; - } - case 0x0204: // Half <- Float - case 0x0408: { // Float <- Double - fcvtn(SubEmitSize, Dst.D(), Vector.D()); - break; - } - default: - LOGMAN_MSG_A_FMT("Unknown Vector_FToF Type : 0x{:04x}", Conv); - break; + case 0x0402: // Float <- Half + case 0x0804: { // Double <- Float + fcvtl(SubEmitSize, Dst.D(), Vector.D()); + break; + } + case 0x0204: // Half <- Float + case 0x0408: { // Float <- Double + fcvtn(SubEmitSize, Dst.D(), Vector.D()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown Vector_FToF Type : 0x{:04x}", Conv); break; } } } @@ -413,8 +400,9 @@ DEF_OP(Vector_FToI) { LOGMAN_THROW_AA_FMT(ElementSize == 8 || ElementSize == 4 || ElementSize == 2, "Unexpected {} size", __func__); const auto SubEmitSize = ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : ARMEmitter::SubRegSize::i16Bit; + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ARMEmitter::SubRegSize::i16Bit; const auto Dst = GetVReg(Node); const auto Vector = GetVReg(Op->Vector.ID()); @@ -423,82 +411,51 @@ DEF_OP(Vector_FToI) { const auto Mask = PRED_TMP_32B.Merging(); switch (Op->Round) { - case FEXCore::IR::Round_Nearest.Val: - frintn(SubEmitSize, Dst.Z(), Mask, Vector.Z()); - break; - case FEXCore::IR::Round_Negative_Infinity.Val: - frintm(SubEmitSize, Dst.Z(), Mask, Vector.Z()); - break; - case FEXCore::IR::Round_Positive_Infinity.Val: - frintp(SubEmitSize, Dst.Z(), Mask, Vector.Z()); - break; - case FEXCore::IR::Round_Towards_Zero.Val: - frintz(SubEmitSize, Dst.Z(), Mask, Vector.Z()); - break; - case FEXCore::IR::Round_Host.Val: - frinti(SubEmitSize, Dst.Z(), Mask, Vector.Z()); - break; + case FEXCore::IR::Round_Nearest.Val: frintn(SubEmitSize, Dst.Z(), Mask, Vector.Z()); break; + case FEXCore::IR::Round_Negative_Infinity.Val: frintm(SubEmitSize, Dst.Z(), Mask, Vector.Z()); break; + case FEXCore::IR::Round_Positive_Infinity.Val: frintp(SubEmitSize, Dst.Z(), Mask, Vector.Z()); break; + case FEXCore::IR::Round_Towards_Zero.Val: frintz(SubEmitSize, Dst.Z(), Mask, Vector.Z()); break; + case FEXCore::IR::Round_Host.Val: frinti(SubEmitSize, Dst.Z(), Mask, Vector.Z()); break; } } else { const auto IsScalar = ElementSize == OpSize; if (IsScalar) { - // Since we have multiple overloads of the same name (e.g. - // frinti having AdvSIMD, AdvSIMD scalar, and an SVE version), - // we can't just use a lambda without some seriously ugly casting. - // This is fairly self-contained otherwise. - #define ROUNDING_FN(name) \ - if (ElementSize == 2) { \ - name(Dst.H(), Vector.H()); \ - } else if (ElementSize == 4) { \ - name(Dst.S(), Vector.S()); \ - } else if (ElementSize == 8) { \ - name(Dst.D(), Vector.D()); \ - } else { \ - FEX_UNREACHABLE; \ - } +// Since we have multiple overloads of the same name (e.g. +// frinti having AdvSIMD, AdvSIMD scalar, and an SVE version), +// we can't just use a lambda without some seriously ugly casting. +// This is fairly self-contained otherwise. +#define ROUNDING_FN(name) \ + if (ElementSize == 2) { \ + name(Dst.H(), Vector.H()); \ + } else if (ElementSize == 4) { \ + name(Dst.S(), Vector.S()); \ + } else if (ElementSize == 8) { \ + name(Dst.D(), Vector.D()); \ + } else { \ + FEX_UNREACHABLE; \ + } switch (Op->Round) { - case IR::Round_Nearest.Val: - ROUNDING_FN(frintn); - break; - case IR::Round_Negative_Infinity.Val: - ROUNDING_FN(frintm); - break; - case IR::Round_Positive_Infinity.Val: - ROUNDING_FN(frintp); - break; - case IR::Round_Towards_Zero.Val: - ROUNDING_FN(frintz); - break; - case IR::Round_Host.Val: - ROUNDING_FN(frinti); - break; + case IR::Round_Nearest.Val: ROUNDING_FN(frintn); break; + case IR::Round_Negative_Infinity.Val: ROUNDING_FN(frintm); break; + case IR::Round_Positive_Infinity.Val: ROUNDING_FN(frintp); break; + case IR::Round_Towards_Zero.Val: ROUNDING_FN(frintz); break; + case IR::Round_Host.Val: ROUNDING_FN(frinti); break; } - #undef ROUNDING_FN +#undef ROUNDING_FN } else { switch (Op->Round) { - case FEXCore::IR::Round_Nearest.Val: - frintn(SubEmitSize, Dst.Q(), Vector.Q()); - break; - case FEXCore::IR::Round_Negative_Infinity.Val: - frintm(SubEmitSize, Dst.Q(), Vector.Q()); - break; - case FEXCore::IR::Round_Positive_Infinity.Val: - frintp(SubEmitSize, Dst.Q(), Vector.Q()); - break; - case FEXCore::IR::Round_Towards_Zero.Val: - frintz(SubEmitSize, Dst.Q(), Vector.Q()); - break; - case FEXCore::IR::Round_Host.Val: - frinti(SubEmitSize, Dst.Q(), Vector.Q()); - break; + case FEXCore::IR::Round_Nearest.Val: frintn(SubEmitSize, Dst.Q(), Vector.Q()); break; + case FEXCore::IR::Round_Negative_Infinity.Val: frintm(SubEmitSize, Dst.Q(), Vector.Q()); break; + case FEXCore::IR::Round_Positive_Infinity.Val: frintp(SubEmitSize, Dst.Q(), Vector.Q()); break; + case FEXCore::IR::Round_Towards_Zero.Val: frintz(SubEmitSize, Dst.Q(), Vector.Q()); break; + case FEXCore::IR::Round_Host.Val: frinti(SubEmitSize, Dst.Q(), Vector.Q()); break; } } } } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/EncryptionOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/EncryptionOps.cpp index ab6f59c69..c77129fec 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/EncryptionOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/EncryptionOps.cpp @@ -10,7 +10,7 @@ $end_info$ #include "Interface/IR/Passes/RegisterAllocationPass.h" namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(VAESImc) { auto Op = IROp->C(); @@ -26,8 +26,7 @@ DEF_OP(VAESEnc) { const auto State = GetVReg(Op->State.ID()); const auto ZeroReg = GetVReg(Op->ZeroReg.ID()); - LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, - "Currently only supports 128-bit operations."); + LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, "Currently only supports 128-bit operations."); if (Dst == State && Dst != Key) { // Optimal case in which Dst already contains the starting state. @@ -35,8 +34,7 @@ DEF_OP(VAESEnc) { aese(Dst.Q(), ZeroReg.Q()); aesmc(Dst.Q(), Dst.Q()); eor(Dst.Q(), Dst.Q(), Key.Q()); - } - else { + } else { mov(VTMP1.Q(), State.Q()); aese(VTMP1, ZeroReg.Q()); aesmc(VTMP1, VTMP1); @@ -53,16 +51,14 @@ DEF_OP(VAESEncLast) { const auto State = GetVReg(Op->State.ID()); const auto ZeroReg = GetVReg(Op->ZeroReg.ID()); - LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, - "Currently only supports 128-bit operations."); + LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, "Currently only supports 128-bit operations."); if (Dst == State && Dst != Key) { // Optimal case in which Dst already contains the starting state. // This matches the common case of XMM AES. aese(Dst.Q(), ZeroReg.Q()); eor(Dst.Q(), Dst.Q(), Key.Q()); - } - else { + } else { mov(VTMP1.Q(), State.Q()); aese(VTMP1, ZeroReg.Q()); eor(Dst.Q(), VTMP1.Q(), Key.Q()); @@ -78,8 +74,7 @@ DEF_OP(VAESDec) { const auto State = GetVReg(Op->State.ID()); const auto ZeroReg = GetVReg(Op->ZeroReg.ID()); - LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, - "Currently only supports 128-bit operations."); + LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, "Currently only supports 128-bit operations."); if (Dst == State && Dst != Key) { // Optimal case in which Dst already contains the starting state. @@ -87,8 +82,7 @@ DEF_OP(VAESDec) { aesd(Dst.Q(), ZeroReg.Q()); aesimc(Dst.Q(), Dst.Q()); eor(Dst.Q(), Dst.Q(), Key.Q()); - } - else { + } else { mov(VTMP1.Q(), State.Q()); aesd(VTMP1, ZeroReg.Q()); aesimc(VTMP1, VTMP1); @@ -105,16 +99,14 @@ DEF_OP(VAESDecLast) { const auto State = GetVReg(Op->State.ID()); const auto ZeroReg = GetVReg(Op->ZeroReg.ID()); - LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, - "Currently only supports 128-bit operations."); + LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, "Currently only supports 128-bit operations."); if (Dst == State && Dst != Key) { // Optimal case in which Dst already contains the starting state. // This matches the common case of XMM AES. aesd(Dst.Q(), ZeroReg.Q()); eor(Dst.Q(), Dst.Q(), Key.Q()); - } - else { + } else { mov(VTMP1.Q(), State.Q()); aesd(VTMP1, ZeroReg.Q()); eor(Dst.Q(), VTMP1.Q(), Key.Q()); @@ -149,8 +141,7 @@ DEF_OP(VAESKeyGenAssist) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, static_cast(Op->RCON) << 32); dup(ARMEmitter::SubRegSize::i64Bit, VTMP2.Q(), TMP1); eor(Dst.Q(), Dst.Q(), VTMP2.Q()); - } - else { + } else { tbl(Dst.Q(), Dst.Q(), Swizzle.Q()); } } @@ -163,19 +154,11 @@ DEF_OP(CRC32) { const auto Src2 = GetReg(Op->Src2.ID()); switch (Op->SrcSize) { - case 1: - crc32cb(Dst.W(), Src1.W(), Src2.W()); - break; - case 2: - crc32ch(Dst.W(), Src1.W(), Src2.W()); - break; - case 4: - crc32cw(Dst.W(), Src1.W(), Src2.W()); - break; - case 8: - crc32cx(Dst.X(), Src1.X(), Src2.X()); - break; - default: LOGMAN_MSG_A_FMT("Unknown CRC32 size: {}", Op->SrcSize); + case 1: crc32cb(Dst.W(), Src1.W(), Src2.W()); break; + case 2: crc32ch(Dst.W(), Src1.W(), Src2.W()); break; + case 4: crc32cw(Dst.W(), Src1.W(), Src2.W()); break; + case 8: crc32cx(Dst.X(), Src1.X(), Src2.X()); break; + default: LOGMAN_MSG_A_FMT("Unknown CRC32 size: {}", Op->SrcSize); } } @@ -197,8 +180,7 @@ DEF_OP(VSha256U0) { if (Dst == Src1) { sha256su0(Dst, Src2); - } - else { + } else { mov(VTMP1.Q(), Src1.Q()); sha256su0(VTMP1, Src2); mov(Dst.Q(), VTMP1.Q()); @@ -209,17 +191,14 @@ DEF_OP(PCLMUL) { const auto Op = IROp->C(); const auto OpSize = IROp->Size; - const auto Dst = GetVReg(Node); + const auto Dst = GetVReg(Node); const auto Src1 = GetVReg(Op->Src1.ID()); const auto Src2 = GetVReg(Op->Src2.ID()); - LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, - "Currently only supports 128-bit operations."); + LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE, "Currently only supports 128-bit operations."); switch (Op->Selector) { - case 0b00000000: - pmull(ARMEmitter::SubRegSize::i128Bit, Dst.D(), Src1.D(), Src2.D()); - break; + case 0b00000000: pmull(ARMEmitter::SubRegSize::i128Bit, Dst.D(), Src1.D(), Src2.D()); break; case 0b00000001: dup(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), Src1.Q(), 1); pmull(ARMEmitter::SubRegSize::i128Bit, Dst.D(), VTMP1.D(), Src2.D()); @@ -228,14 +207,10 @@ DEF_OP(PCLMUL) { dup(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), Src2.Q(), 1); pmull(ARMEmitter::SubRegSize::i128Bit, Dst.D(), VTMP1.D(), Src1.D()); break; - case 0b00010001: - pmull2(ARMEmitter::SubRegSize::i128Bit, Dst.Q(), Src1.Q(), Src2.Q()); - break; - default: - LOGMAN_MSG_A_FMT("Unknown PCLMUL selector: {}", Op->Selector); - break; + case 0b00010001: pmull2(ARMEmitter::SubRegSize::i128Bit, Dst.Q(), Src1.Q(), Src2.Q()); break; + default: LOGMAN_MSG_A_FMT("Unknown PCLMUL selector: {}", Op->Selector); break; } } #undef DEF_OP -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/FlagOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/FlagOps.cpp index 92ec9659b..b4d1e6d96 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/FlagOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/FlagOps.cpp @@ -8,12 +8,11 @@ $end_info$ #include "Interface/Core/JIT/Arm64/JITClass.h" namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(GetHostFlag) { auto Op = IROp->C(); ubfx(ARMEmitter::Size::i64Bit, GetReg(Node), GetReg(Op->Value.ID()), Op->Flag, 1); } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index 48cc9e04a..9db0e7c52 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -73,7 +73,7 @@ static void PrintValue(uint64_t Value) { static void PrintVectorValue(uint64_t Value, uint64_t ValueUpper) { LogMan::Msg::DFmt("Value: 0x{:016x}'{:016x}", ValueUpper, Value); } -} +} // namespace namespace FEXCore::CPU { @@ -118,379 +118,347 @@ void Arm64JITCore::Op_Unhandled(const IR::IROp_Header* IROp, IR::NodeID Node) { mov(Dst.W(), TMP1.W()); }; - switch(Info.ABI) { - case FABI_F80_I16_F32:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + switch (Info.ABI) { + case FABI_F80_I16_F32: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - const auto Src1 = GetVReg(IROp->Args[0].ID()); - fmov(ARMEmitter::SReg::s0, Src1.S()); - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall<__uint128_t, uint16_t, float>(ARMEmitter::Reg::r1); - } - else { - blr(ARMEmitter::Reg::r1); - } - - FillF80Result(); + const auto Src1 = GetVReg(IROp->Args[0].ID()); + fmov(ARMEmitter::SReg::s0, Src1.S()); + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall<__uint128_t, uint16_t, float>(ARMEmitter::Reg::r1); + } else { + blr(ARMEmitter::Reg::r1); } - break; - case FABI_F80_I16_F64:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + FillF80Result(); + } break; - const auto Src1 = GetVReg(IROp->Args[0].ID()); - mov(ARMEmitter::DReg::d0, Src1.D()); - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall<__uint128_t, uint16_t, double>(ARMEmitter::Reg::r1); - } - else { - blr(ARMEmitter::Reg::r1); - } + case FABI_F80_I16_F64: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - FillF80Result(); + const auto Src1 = GetVReg(IROp->Args[0].ID()); + mov(ARMEmitter::DReg::d0, Src1.D()); + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall<__uint128_t, uint16_t, double>(ARMEmitter::Reg::r1); + } else { + blr(ARMEmitter::Reg::r1); } - break; - case FABI_F80_I16_I16: - case FABI_F80_I16_I32: { - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + FillF80Result(); + } break; - const auto Src1 = GetReg(IROp->Args[0].ID()); - if (Info.ABI == FABI_F80_I16_I16) { - sxth(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r1, Src1); - } - else { - mov(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r1, Src1); - } - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - ldr(ARMEmitter::XReg::x2, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall<__uint128_t, uint16_t, uint32_t>(ARMEmitter::Reg::r2); - } - else { - blr(ARMEmitter::Reg::r2); - } + case FABI_F80_I16_I16: + case FABI_F80_I16_I32: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - FillF80Result(); + const auto Src1 = GetReg(IROp->Args[0].ID()); + if (Info.ABI == FABI_F80_I16_I16) { + sxth(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r1, Src1); + } else { + mov(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r1, Src1); } - break; - - case FABI_F32_I16_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - - const auto Src1 = GetVReg(IROp->Args[0].ID()); - - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); - - ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { - blr(ARMEmitter::Reg::r3); - } - - if (!TMP_ABIARGS) { - fmov(VTMP1.S(), ARMEmitter::SReg::s0); - } - FillForABICall(Info.SupportsPreserveAllABI, true); - - const auto Dst = GetVReg(Node); - fmov(Dst.S(), VTMP1.S()); + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + ldr(ARMEmitter::XReg::x2, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall<__uint128_t, uint16_t, uint32_t>(ARMEmitter::Reg::r2); + } else { + blr(ARMEmitter::Reg::r2); } - break; - case FABI_F64_I16_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + FillF80Result(); + } break; - const auto Src1 = GetVReg(IROp->Args[0].ID()); + case FABI_F32_I16_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); + const auto Src1 = GetVReg(IROp->Args[0].ID()); - ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { - blr(ARMEmitter::Reg::r3); - } + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); - FillF64Result(); + ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); + } else { + blr(ARMEmitter::Reg::r3); } - break; - case FABI_F64_I16_F64: { - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - - const auto Src1 = GetVReg(IROp->Args[0].ID()); - - mov(ARMEmitter::DReg::d0, Src1.D()); - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r1); - } - else { - blr(ARMEmitter::Reg::r1); - } - - FillF64Result(); + if (!TMP_ABIARGS) { + fmov(VTMP1.S(), ARMEmitter::SReg::s0); } - break; + FillForABICall(Info.SupportsPreserveAllABI, true); - case FABI_F64_I16_F64_F64: { - const auto Src1 = GetVReg(IROp->Args[0].ID()); - const auto Src2 = GetVReg(IROp->Args[1].ID()); + const auto Dst = GetVReg(Node); + fmov(Dst.S(), VTMP1.S()); + } break; - mov(VTMP1.D(), Src1.D()); - mov(VTMP2.D(), Src2.D()); + case FABI_F64_I16_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + const auto Src1 = GetVReg(IROp->Args[0].ID()); - if (!TMP_ABIARGS) { - mov(ARMEmitter::DReg::d0, VTMP1.D()); - mov(ARMEmitter::DReg::d1, VTMP2.D()); - } + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r1); - } - else { - blr(ARMEmitter::Reg::r1); - } - - FillF64Result(); + ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); + } else { + blr(ARMEmitter::Reg::r3); } - break; - case FABI_I16_I16_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + FillF64Result(); + } break; - const auto Src1 = GetVReg(IROp->Args[0].ID()); + case FABI_F64_I16_F64: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); + const auto Src1 = GetVReg(IROp->Args[0].ID()); - ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { - blr(ARMEmitter::Reg::r3); - } - - if (!TMP_ABIARGS) { - mov(TMP1, ARMEmitter::XReg::x0); - } - FillForABICall(Info.SupportsPreserveAllABI, true); - - const auto Dst = GetReg(Node); - sxth(ARMEmitter::Size::i64Bit, Dst, TMP1); + mov(ARMEmitter::DReg::d0, Src1.D()); + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r1); + } else { + blr(ARMEmitter::Reg::r1); } - break; - case FABI_I32_I16_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - const auto Src1 = GetVReg(IROp->Args[0].ID()); + FillF64Result(); + } break; - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); + case FABI_F64_I16_F64_F64: { + const auto Src1 = GetVReg(IROp->Args[0].ID()); + const auto Src2 = GetVReg(IROp->Args[1].ID()); - ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { - blr(ARMEmitter::Reg::r3); - } + mov(VTMP1.D(), Src1.D()); + mov(VTMP2.D(), Src2.D()); - FillI32Result(); + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + + if (!TMP_ABIARGS) { + mov(ARMEmitter::DReg::d0, VTMP1.D()); + mov(ARMEmitter::DReg::d1, VTMP2.D()); } - break; - case FABI_I64_I16_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - const auto Src1 = GetVReg(IROp->Args[0].ID()); - - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); - - ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { - blr(ARMEmitter::Reg::r3); - } - - if (!TMP_ABIARGS) { - mov(TMP1, ARMEmitter::XReg::x0); - } - FillForABICall(Info.SupportsPreserveAllABI, true); - - const auto Dst = GetReg(Node); - mov(ARMEmitter::Size::i64Bit, Dst, TMP1); + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + ldr(ARMEmitter::XReg::x1, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r1); + } else { + blr(ARMEmitter::Reg::r1); } - break; - case FABI_I64_I16_F80_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - const auto Src1 = GetVReg(IROp->Args[0].ID()); - const auto Src2 = GetVReg(IROp->Args[1].ID()); + FillF64Result(); + } break; - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); + case FABI_I16_I16_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - umov(ARMEmitter::Reg::r3, Src2, 0); - umov(ARMEmitter::Reg::r4, Src2, 4); + const auto Src1 = GetVReg(IROp->Args[0].ID()); - ldr(ARMEmitter::XReg::x5, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r5); - } - else { - blr(ARMEmitter::Reg::r5); - } + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); - if (!TMP_ABIARGS) { - mov(TMP1, ARMEmitter::XReg::x0); - } - FillForABICall(Info.SupportsPreserveAllABI, true); - - const auto Dst = GetReg(Node); - mov(ARMEmitter::Size::i64Bit, Dst, TMP1); + ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); + } else { + blr(ARMEmitter::Reg::r3); } - break; - case FABI_F80_I16_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - const auto Src1 = GetVReg(IROp->Args[0].ID()); - - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); - - ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall<__uint128_t, uint16_t, uint64_t, uint64_t>(ARMEmitter::Reg::r3); - } - else { - blr(ARMEmitter::Reg::r3); - } - - FillF80Result(); + if (!TMP_ABIARGS) { + mov(TMP1, ARMEmitter::XReg::x0); } - break; - case FABI_F80_I16_F80_F80:{ - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + FillForABICall(Info.SupportsPreserveAllABI, true); - const auto Src1 = GetVReg(IROp->Args[0].ID()); - const auto Src2 = GetVReg(IROp->Args[1].ID()); + const auto Dst = GetReg(Node); + sxth(ARMEmitter::Size::i64Bit, Dst, TMP1); + } break; + case FABI_I32_I16_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); - umov(ARMEmitter::Reg::r1, Src1, 0); - umov(ARMEmitter::Reg::r2, Src1, 4); + const auto Src1 = GetVReg(IROp->Args[0].ID()); - umov(ARMEmitter::Reg::r3, Src2, 0); - umov(ARMEmitter::Reg::r4, Src2, 4); + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); - ldr(ARMEmitter::XReg::x5, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall<__uint128_t, uint16_t, uint64_t, uint64_t, uint64_t, uint64_t>(ARMEmitter::Reg::r5); - } - else { - blr(ARMEmitter::Reg::r5); - } - - FillF80Result(); + ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); + } else { + blr(ARMEmitter::Reg::r3); } - break; - case FABI_I32_I64_I64_I128_I128_I16: { - const auto Op = IROp->C(); - const auto SrcRAX = GetReg(Op->RAX.ID()); - const auto SrcRDX = GetReg(Op->RDX.ID()); - mov(TMP1, SrcRAX.X()); - mov(TMP2, SrcRDX.X()); + FillI32Result(); + } break; + case FABI_I64_I16_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - SpillForABICall(Info.SupportsPreserveAllABI, TMP3, true); + const auto Src1 = GetVReg(IROp->Args[0].ID()); - const auto Control = Op->Control; + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); - const auto Src1 = GetVReg(Op->LHS.ID()); - const auto Src2 = GetVReg(Op->RHS.ID()); - - if (!TMP_ABIARGS) { - mov(ARMEmitter::XReg::x0, TMP1); - mov(ARMEmitter::XReg::x1, TMP2); - } - - umov(ARMEmitter::Reg::r2, Src1, 0); - umov(ARMEmitter::Reg::r3, Src1, 1); - - umov(ARMEmitter::Reg::r4, Src2, 0); - umov(ARMEmitter::Reg::r5, Src2, 1); - - movz(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r6, Control); - - ldr(ARMEmitter::XReg::x7, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r7); - } - else { - blr(ARMEmitter::Reg::r7); - } - - FillI32Result(); + ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); + } else { + blr(ARMEmitter::Reg::r3); } - break; - case FABI_I32_I128_I128_I16: { - SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); - const auto Op = IROp->C(); - - const auto Src1 = GetVReg(Op->LHS.ID()); - const auto Src2 = GetVReg(Op->RHS.ID()); - const auto Control = Op->Control; - - umov(ARMEmitter::Reg::r0, Src1, 0); - umov(ARMEmitter::Reg::r1, Src1, 1); - - umov(ARMEmitter::Reg::r2, Src2, 0); - umov(ARMEmitter::Reg::r3, Src2, 1); - - movz(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r4, Control); - - ldr(ARMEmitter::XReg::x5, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); - if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { - GenerateIndirectRuntimeCall(ARMEmitter::Reg::r5); - } - else { - blr(ARMEmitter::Reg::r5); - } - - FillI32Result(); + if (!TMP_ABIARGS) { + mov(TMP1, ARMEmitter::XReg::x0); } - break; - case FABI_UNKNOWN: - default: + FillForABICall(Info.SupportsPreserveAllABI, true); + + const auto Dst = GetReg(Node); + mov(ARMEmitter::Size::i64Bit, Dst, TMP1); + } break; + case FABI_I64_I16_F80_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + + const auto Src1 = GetVReg(IROp->Args[0].ID()); + const auto Src2 = GetVReg(IROp->Args[1].ID()); + + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); + + umov(ARMEmitter::Reg::r3, Src2, 0); + umov(ARMEmitter::Reg::r4, Src2, 4); + + ldr(ARMEmitter::XReg::x5, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r5); + } else { + blr(ARMEmitter::Reg::r5); + } + + if (!TMP_ABIARGS) { + mov(TMP1, ARMEmitter::XReg::x0); + } + FillForABICall(Info.SupportsPreserveAllABI, true); + + const auto Dst = GetReg(Node); + mov(ARMEmitter::Size::i64Bit, Dst, TMP1); + } break; + case FABI_F80_I16_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + + const auto Src1 = GetVReg(IROp->Args[0].ID()); + + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); + + ldr(ARMEmitter::XReg::x3, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall<__uint128_t, uint16_t, uint64_t, uint64_t>(ARMEmitter::Reg::r3); + } else { + blr(ARMEmitter::Reg::r3); + } + + FillF80Result(); + } break; + case FABI_F80_I16_F80_F80: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + + const auto Src1 = GetVReg(IROp->Args[0].ID()); + const auto Src2 = GetVReg(IROp->Args[1].ID()); + + ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW)); + umov(ARMEmitter::Reg::r1, Src1, 0); + umov(ARMEmitter::Reg::r2, Src1, 4); + + umov(ARMEmitter::Reg::r3, Src2, 0); + umov(ARMEmitter::Reg::r4, Src2, 4); + + ldr(ARMEmitter::XReg::x5, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall<__uint128_t, uint16_t, uint64_t, uint64_t, uint64_t, uint64_t>(ARMEmitter::Reg::r5); + } else { + blr(ARMEmitter::Reg::r5); + } + + FillF80Result(); + } break; + case FABI_I32_I64_I64_I128_I128_I16: { + const auto Op = IROp->C(); + const auto SrcRAX = GetReg(Op->RAX.ID()); + const auto SrcRDX = GetReg(Op->RDX.ID()); + + mov(TMP1, SrcRAX.X()); + mov(TMP2, SrcRDX.X()); + + SpillForABICall(Info.SupportsPreserveAllABI, TMP3, true); + + const auto Control = Op->Control; + + const auto Src1 = GetVReg(Op->LHS.ID()); + const auto Src2 = GetVReg(Op->RHS.ID()); + + if (!TMP_ABIARGS) { + mov(ARMEmitter::XReg::x0, TMP1); + mov(ARMEmitter::XReg::x1, TMP2); + } + + umov(ARMEmitter::Reg::r2, Src1, 0); + umov(ARMEmitter::Reg::r3, Src1, 1); + + umov(ARMEmitter::Reg::r4, Src2, 0); + umov(ARMEmitter::Reg::r5, Src2, 1); + + movz(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r6, Control); + + ldr(ARMEmitter::XReg::x7, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r7); + } else { + blr(ARMEmitter::Reg::r7); + } + + FillI32Result(); + } break; + case FABI_I32_I128_I128_I16: { + SpillForABICall(Info.SupportsPreserveAllABI, TMP1, true); + + const auto Op = IROp->C(); + + const auto Src1 = GetVReg(Op->LHS.ID()); + const auto Src2 = GetVReg(Op->RHS.ID()); + const auto Control = Op->Control; + + umov(ARMEmitter::Reg::r0, Src1, 0); + umov(ARMEmitter::Reg::r1, Src1, 1); + + umov(ARMEmitter::Reg::r2, Src2, 0); + umov(ARMEmitter::Reg::r3, Src2, 1); + + movz(ARMEmitter::Size::i32Bit, ARMEmitter::Reg::r4, Control); + + ldr(ARMEmitter::XReg::x5, STATE_PTR(CpuStateFrame, Pointers.Common.FallbackHandlerPointers[Info.HandlerIndex])); + if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { + GenerateIndirectRuntimeCall(ARMEmitter::Reg::r5); + } else { + blr(ARMEmitter::Reg::r5); + } + + FillI32Result(); + } break; + case FABI_UNKNOWN: + default: #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - LOGMAN_MSG_A_FMT("Unhandled IR Fallback ABI: {} {}", - FEXCore::IR::GetName(IROp->Op), ToUnderlying(Info.ABI)); + LOGMAN_MSG_A_FMT("Unhandled IR Fallback ABI: {} {}", FEXCore::IR::GetName(IROp->Op), ToUnderlying(Info.ABI)); #endif break; } @@ -498,9 +466,9 @@ void Arm64JITCore::Op_Unhandled(const IR::IROp_Header* IROp, IR::NodeID Node) { } -static void DirectBlockDelinker(FEXCore::Core::CpuStateFrame *Frame, FEXCore::Context::ExitFunctionLinkData *Record) { +static void DirectBlockDelinker(FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record) { auto LinkerAddress = Frame->Pointers.Common.ExitFunctionLinker; - uintptr_t branch = (uintptr_t)(Record) - 8; + uintptr_t branch = (uintptr_t)(Record)-8; FEXCore::ARMEmitter::Emitter emit((uint8_t*)(branch), 8); FEXCore::ARMEmitter::SingleUseForwardLabel l_BranchHost; emit.ldr(TMP1, &l_BranchHost); @@ -510,12 +478,12 @@ static void DirectBlockDelinker(FEXCore::Core::CpuStateFrame *Frame, FEXCore::Co FEXCore::ARMEmitter::Emitter::ClearICache((void*)branch, 8); } -static void IndirectBlockDelinker(FEXCore::Core::CpuStateFrame *Frame, FEXCore::Context::ExitFunctionLinkData *Record) { +static void IndirectBlockDelinker(FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record) { auto LinkerAddress = Frame->Pointers.Common.ExitFunctionLinker; Record->HostBranch = LinkerAddress; } -static uint64_t Arm64JITCore_ExitFunctionLink(FEXCore::Core::CpuStateFrame *Frame, FEXCore::Context::ExitFunctionLinkData *Record) { +static uint64_t Arm64JITCore_ExitFunctionLink(FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record) { auto Thread = Frame->Thread; auto GuestRip = Record->GuestRIP; @@ -526,9 +494,9 @@ static uint64_t Arm64JITCore_ExitFunctionLink(FEXCore::Core::CpuStateFrame *Fram return Frame->Pointers.Common.DispatcherLoopTop; } - uintptr_t branch = (uintptr_t)(Record) - 8; + uintptr_t branch = (uintptr_t)(Record)-8; - auto offset = HostCode/4 - branch/4; + auto offset = HostCode / 4 - branch / 4; if (vixl::IsInt26(offset)) { // optimal case - can branch directly // patch the code @@ -551,13 +519,13 @@ static uint64_t Arm64JITCore_ExitFunctionLink(FEXCore::Core::CpuStateFrame *Fram void Arm64JITCore::Op_NoOp(const IR::IROp_Header* IROp, IR::NodeID Node) {} -Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) +Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl* ctx, FEXCore::Core::InternalThreadState* Thread) : CPUBackend(Thread, INITIAL_CODE_SIZE, MAX_CODE_SIZE) , Arm64Emitter(ctx) - , HostSupportsSVE128{ctx->HostFeatures.SupportsSVE} - , HostSupportsSVE256{ctx->HostFeatures.SupportsAVX} - , HostSupportsRPRES{ctx->HostFeatures.SupportsRPRES} - , HostSupportsAFP{ctx->HostFeatures.SupportsAFP} + , HostSupportsSVE128 {ctx->HostFeatures.SupportsSVE} + , HostSupportsSVE256 {ctx->HostFeatures.SupportsAVX} + , HostSupportsRPRES {ctx->HostFeatures.SupportsRPRES} + , HostSupportsAFP {ctx->HostFeatures.SupportsAFP} , CTX {ctx} { RAPass = Thread->PassManager->GetPass("RA"); @@ -572,7 +540,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::In RAPass->AddRegisters(FEXCore::IR::ComplexClass, 1); for (uint32_t i = 0; i < GeneralPairRegisters.size(); ++i) { - RAPass->AddRegisterConflict(FEXCore::IR::GPRClass, i * 2, FEXCore::IR::GPRPairClass, i); + RAPass->AddRegisterConflict(FEXCore::IR::GPRClass, i * 2, FEXCore::IR::GPRPairClass, i); RAPass->AddRegisterConflict(FEXCore::IR::GPRClass, i * 2 + 1, FEXCore::IR::GPRPairClass, i); } @@ -580,7 +548,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::In // Set up pointers that the JIT needs to load // Common - auto &Common = ThreadState->CurrentFrame->Pointers.Common; + auto& Common = ThreadState->CurrentFrame->Pointers.Common; Common.PrintValue = reinterpret_cast(PrintValue); Common.PrintVectorValue = reinterpret_cast(PrintVectorValue); @@ -608,7 +576,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::In InterpreterOps::FillFallbackIndexPointers(Common.FallbackHandlerPointers); // Platform Specific - auto &AArch64 = ThreadState->CurrentFrame->Pointers.AArch64; + auto& AArch64 = ThreadState->CurrentFrame->Pointers.AArch64; AArch64.LUDIV = reinterpret_cast(LUDIV); AArch64.LDIV = reinterpret_cast(LDIV); @@ -623,8 +591,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::In if (ParanoidTSO()) { RT_LoadMemTSO = &Arm64JITCore::Op_ParanoidLoadMemTSO; RT_StoreMemTSO = &Arm64JITCore::Op_ParanoidStoreMemTSO; - } - else { + } else { RT_LoadMemTSO = &Arm64JITCore::Op_LoadMemTSO; RT_StoreMemTSO = &Arm64JITCore::Op_StoreMemTSO; } @@ -644,9 +611,7 @@ void Arm64JITCore::ClearCache() { EmitDetectionString(); } -Arm64JITCore::~Arm64JITCore() { - -} +Arm64JITCore::~Arm64JITCore() {} bool Arm64JITCore::IsInlineConstant(const IR::OrderedNodeWrapper& WNode, uint64_t* Value) const { auto OpHeader = IR->GetOp(WNode); @@ -703,10 +668,8 @@ bool Arm64JITCore::IsGPRPair(IR::NodeID Node) const { return Class == IR::GPRPairClass; } -CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, - FEXCore::IR::IRListView const *IR, - FEXCore::Core::DebugData *DebugData, - FEXCore::IR::RegisterAllocationData *RAData) { +CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, const FEXCore::IR::IRListView* IR, FEXCore::Core::DebugData* DebugData, + FEXCore::IR::RegisterAllocationData* RAData) { FEXCORE_PROFILE_SCOPED("Arm64::CompileCode"); JumpTargets.clear(); @@ -726,9 +689,9 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, CodeData.BlockBegin = GetCursorAddress(); // Put the code header at the start of the data block. - ARMEmitter::BackwardLabel JITCodeHeaderLabel{}; + ARMEmitter::BackwardLabel JITCodeHeaderLabel {}; Bind(&JITCodeHeaderLabel); - JITCodeHeader *CodeHeader = GetCursorAddress(); + JITCodeHeader* CodeHeader = GetCursorAddress(); CursorIncrement(sizeof(JITCodeHeader)); #ifdef VIXL_DISASSEMBLER @@ -765,11 +728,11 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, if (CTX->Config.NeedsPendingInterruptFaultCheck) { // Trigger a fault if there are any pending interrupts // Used only for suspend on WIN32 at the moment - strb(ARMEmitter::XReg::zr, STATE, offsetof(FEXCore::Core::InternalThreadState, InterruptFaultPage) - - offsetof(FEXCore::Core::InternalThreadState, BaseFrameState)); + strb(ARMEmitter::XReg::zr, STATE, + offsetof(FEXCore::Core::InternalThreadState, InterruptFaultPage) - offsetof(FEXCore::Core::InternalThreadState, BaseFrameState)); } - //LOGMAN_THROW_A_FMT(RAData->HasFullRA(), "Arm64 JIT only works with RA"); + // LOGMAN_THROW_A_FMT(RAData->HasFullRA(), "Arm64 JIT only works with RA"); SpillSlots = RAData->SpillSlots(); @@ -793,14 +756,13 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, LOGMAN_THROW_AA_FMT(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block"); #endif - auto BlockStartHostCode = GetCursorAddress(); + auto BlockStartHostCode = GetCursorAddress(); { const auto Node = IR->GetID(BlockNode); const auto IsTarget = JumpTargets.try_emplace(Node).first; // if there's a pending branch, and it is not fall-through - if (PendingTargetLabel && PendingTargetLabel != &IsTarget->second) - { + if (PendingTargetLabel && PendingTargetLabel != &IsTarget->second) { b(PendingTargetLabel); } PendingTargetLabel = nullptr; @@ -811,43 +773,40 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { const auto ID = IR->GetID(CodeNode); switch (IROp->Op) { -#define REGISTER_OP_RT(op, x) case FEXCore::IR::IROps::OP_##op: std::invoke(RT_##x, this, IROp, ID); break -#define REGISTER_OP(op, x) case FEXCore::IR::IROps::OP_##op: Op_##x(IROp, ID); break +#define REGISTER_OP_RT(op, x) \ + case FEXCore::IR::IROps::OP_##op: std::invoke(RT_##x, this, IROp, ID); break +#define REGISTER_OP(op, x) \ + case FEXCore::IR::IROps::OP_##op: Op_##x(IROp, ID); break #define IROP_DISPATCH_DISPATCH #include #undef REGISTER_OP - default: - Op_Unhandled(IROp, ID); - break; + default: Op_Unhandled(IROp, ID); break; } } if (DebugData) { - DebugData->Subblocks.push_back({ - static_cast(BlockStartHostCode - CodeData.BlockEntry), - static_cast(GetCursorAddress() - BlockStartHostCode) - }); + DebugData->Subblocks.push_back({static_cast(BlockStartHostCode - CodeData.BlockEntry), + static_cast(GetCursorAddress() - BlockStartHostCode)}); } } // Make sure last branch is generated. It certainly can't be eliminated here. - if (PendingTargetLabel) - { + if (PendingTargetLabel) { b(PendingTargetLabel); } PendingTargetLabel = nullptr; // CodeSize not including the tail data. - const uint64_t CodeOnlySize = GetCursorAddress() - CodeData.BlockBegin; + const uint64_t CodeOnlySize = GetCursorAddress() - CodeData.BlockBegin; // Add the JitCodeTail - auto JITBlockTailLocation = GetCursorAddress(); + auto JITBlockTailLocation = GetCursorAddress(); auto JITBlockTail = GetCursorAddress(); CursorIncrement(sizeof(JITCodeTail)); - auto JITRIPEntriesLocation = GetCursorAddress(); + auto JITRIPEntriesLocation = GetCursorAddress(); auto JITRIPEntries = GetCursorAddress(); CursorIncrement(sizeof(JITRIPReconstructEntries) * DebugData->GuestOpcodes.size()); @@ -866,8 +825,8 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, uintptr_t CurrentRIPOffset = 0; uint64_t CurrentPCOffset = 0; for (size_t i = 0; i < DebugData->GuestOpcodes.size(); i++) { - const auto &GuestOpcode = DebugData->GuestOpcodes[i]; - auto &RIPEntry = JITRIPEntries[i]; + const auto& GuestOpcode = DebugData->GuestOpcodes[i]; + auto& RIPEntry = JITRIPEntries[i]; RIPEntry.HostPCOffset = GuestOpcode.HostEntryOffset - CurrentPCOffset; RIPEntry.GuestRIPOffset = GuestOpcode.GuestEntryOffset - CurrentRIPOffset; CurrentPCOffset = GuestOpcode.HostEntryOffset; @@ -877,7 +836,7 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, CodeHeader->OffsetToBlockTail = JITBlockTailLocation - CodeData.BlockBegin; - CodeData.Size = GetCursorAddress() - CodeData.BlockBegin; + CodeData.Size = GetCursorAddress() - CodeData.BlockBegin; JITBlockTail->Size = CodeData.Size; @@ -932,7 +891,7 @@ void Arm64JITCore::ResetStack() { } } -fextl::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) { +fextl::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl* ctx, FEXCore::Core::InternalThreadState* Thread) { return fextl::make_unique(ctx, Thread); } @@ -944,4 +903,4 @@ CPUBackendFeatures GetArm64JITBackendFeatures() { }; } -} +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h b/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h index 319cf7239..3f8bd4aa2 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h @@ -30,50 +30,60 @@ $end_info$ #include namespace FEXCore::Core { - struct InternalThreadState; +struct InternalThreadState; } namespace FEXCore::CPU { -class Arm64JITCore final : public CPUBackend, public Arm64Emitter { +class Arm64JITCore final : public CPUBackend, public Arm64Emitter { public: - explicit Arm64JITCore(FEXCore::Context::ContextImpl *ctx, - FEXCore::Core::InternalThreadState *Thread); + explicit Arm64JITCore(FEXCore::Context::ContextImpl* ctx, FEXCore::Core::InternalThreadState* Thread); ~Arm64JITCore() override; - [[nodiscard]] fextl::string GetName() override { return "JIT"; } + [[nodiscard]] + fextl::string GetName() override { + return "JIT"; + } - [[nodiscard]] CPUBackend::CompiledCode CompileCode(uint64_t Entry, - FEXCore::IR::IRListView const *IR, - FEXCore::Core::DebugData *DebugData, - FEXCore::IR::RegisterAllocationData *RAData) override; + [[nodiscard]] + CPUBackend::CompiledCode CompileCode(uint64_t Entry, const FEXCore::IR::IRListView* IR, FEXCore::Core::DebugData* DebugData, + FEXCore::IR::RegisterAllocationData* RAData) override; - [[nodiscard]] void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; } + [[nodiscard]] + void* MapRegion(void* HostPtr, uint64_t, uint64_t) override { + return HostPtr; + } - [[nodiscard]] bool NeedsOpDispatch() override { return true; } + [[nodiscard]] + bool NeedsOpDispatch() override { + return true; + } void ClearCache() override; - void ClearRelocations() override { Relocations.clear(); } + void ClearRelocations() override { + Relocations.clear(); + } private: FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); FEX_CONFIG_OPT(VectorTSOEnabled, VECTORTSOENABLED); FEX_CONFIG_OPT(MemcpySetTSOEnabled, MEMCPYSETTSOENABLED); - const bool HostSupportsSVE128{}; - const bool HostSupportsSVE256{}; - const bool HostSupportsRPRES{}; - const bool HostSupportsAFP{}; + const bool HostSupportsSVE128 {}; + const bool HostSupportsSVE256 {}; + const bool HostSupportsRPRES {}; + const bool HostSupportsAFP {}; - ARMEmitter::BiDirectionalLabel *PendingTargetLabel; - FEXCore::Context::ContextImpl *CTX; - FEXCore::IR::IRListView const *IR; + ARMEmitter::BiDirectionalLabel* PendingTargetLabel; + FEXCore::Context::ContextImpl* CTX; + const FEXCore::IR::IRListView* IR; uint64_t Entry; - CPUBackend::CompiledCode CodeData{}; + CPUBackend::CompiledCode CodeData {}; fextl::map JumpTargets; - [[nodiscard]] FEXCore::ARMEmitter::Register GetReg(IR::NodeID Node) const { + [[nodiscard]] + FEXCore::ARMEmitter::Register GetReg(IR::NodeID Node) const { const auto Reg = GetPhys(Node); LOGMAN_THROW_AA_FMT(Reg.Class == IR::GPRFixedClass.Val || Reg.Class == IR::GPRClass.Val, "Unexpected Class: {}", Reg.Class); @@ -87,7 +97,8 @@ private: FEX_UNREACHABLE; } - [[nodiscard]] FEXCore::ARMEmitter::VRegister GetVReg(IR::NodeID Node) const { + [[nodiscard]] + FEXCore::ARMEmitter::VRegister GetVReg(IR::NodeID Node) const { const auto Reg = GetPhys(Node); LOGMAN_THROW_AA_FMT(Reg.Class == IR::FPRFixedClass.Val || Reg.Class == IR::FPRClass.Val, "Unexpected Class: {}", Reg.Class); @@ -101,7 +112,8 @@ private: FEX_UNREACHABLE; } - [[nodiscard]] std::pair GetRegPair(IR::NodeID Node) const { + [[nodiscard]] + std::pair GetRegPair(IR::NodeID Node) const { const auto Reg = GetPhys(Node); LOGMAN_THROW_AA_FMT(Reg.Class == IR::GPRPairClass.Val, "Unexpected Class: {}", Reg.Class); @@ -109,9 +121,11 @@ private: return GeneralPairRegisters[Reg.Reg]; } - [[nodiscard]] FEXCore::IR::RegisterClassType GetRegClass(IR::NodeID Node) const; + [[nodiscard]] + FEXCore::IR::RegisterClassType GetRegClass(IR::NodeID Node) const; - [[nodiscard]] IR::PhysicalRegister GetPhys(IR::NodeID Node) const { + [[nodiscard]] + IR::PhysicalRegister GetPhys(IR::NodeID Node) const { auto PhyReg = RAData->GetNodeRegister(Node); LOGMAN_THROW_A_FMT(!PhyReg.IsInvalid(), "Couldn't Allocate register for node: ssa{}. Class: {}", Node, PhyReg.Class); @@ -119,7 +133,8 @@ private: return PhyReg; } - [[nodiscard]] FEXCore::ARMEmitter::Register GetZeroableReg(IR::OrderedNodeWrapper Src) const { + [[nodiscard]] + FEXCore::ARMEmitter::Register GetZeroableReg(IR::OrderedNodeWrapper Src) const { uint64_t Const; if (IsInlineConstant(Src, &Const)) { LOGMAN_THROW_AA_FMT(Const == 0, "Only valid constant"); @@ -131,36 +146,38 @@ private: // Converts IR-base shift type to ARMEmitter shift type. // Will be a no-op, only a type conversion since the two definitions match. - [[nodiscard]] ARMEmitter::ShiftType ConvertIRShiftType(IR::ShiftType Shift) const { + [[nodiscard]] + ARMEmitter::ShiftType ConvertIRShiftType(IR::ShiftType Shift) const { return Shift == IR::ShiftType::LSL ? ARMEmitter::ShiftType::LSL : Shift == IR::ShiftType::LSR ? ARMEmitter::ShiftType::LSR : Shift == IR::ShiftType::ASR ? ARMEmitter::ShiftType::ASR : - ARMEmitter::ShiftType::ROR; + ARMEmitter::ShiftType::ROR; } - [[nodiscard]] bool IsFPR(IR::NodeID Node) const; - [[nodiscard]] bool IsGPR(IR::NodeID Node) const; - [[nodiscard]] bool IsGPRPair(IR::NodeID Node) const; + [[nodiscard]] + bool IsFPR(IR::NodeID Node) const; + [[nodiscard]] + bool IsGPR(IR::NodeID Node) const; + [[nodiscard]] + bool IsGPRPair(IR::NodeID Node) const; - [[nodiscard]] FEXCore::ARMEmitter::ExtendedMemOperand GenerateMemOperand(uint8_t AccessSize, - FEXCore::ARMEmitter::Register Base, - IR::OrderedNodeWrapper Offset, - IR::MemOffsetType OffsetType, - uint8_t OffsetScale); + [[nodiscard]] + FEXCore::ARMEmitter::ExtendedMemOperand GenerateMemOperand( + uint8_t AccessSize, FEXCore::ARMEmitter::Register Base, IR::OrderedNodeWrapper Offset, IR::MemOffsetType OffsetType, uint8_t OffsetScale); // NOTE: Will use TMP1 as a way to encode immediates that happen to fall outside // the limits of the scalar plus immediate variant of SVE load/stores. // // TMP1 is safe to use again once this memory operand is used with its // equivalent loads or stores that this was called for. - [[nodiscard]] FEXCore::ARMEmitter::SVEMemOperand GenerateSVEMemOperand(uint8_t AccessSize, - FEXCore::ARMEmitter::Register Base, - IR::OrderedNodeWrapper Offset, - IR::MemOffsetType OffsetType, - uint8_t OffsetScale); + [[nodiscard]] + FEXCore::ARMEmitter::SVEMemOperand GenerateSVEMemOperand(uint8_t AccessSize, FEXCore::ARMEmitter::Register Base, + IR::OrderedNodeWrapper Offset, IR::MemOffsetType OffsetType, uint8_t OffsetScale); - [[nodiscard]] bool IsInlineConstant(const IR::OrderedNodeWrapper& Node, uint64_t* Value = nullptr) const; - [[nodiscard]] bool IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode, uint64_t* Value) const; + [[nodiscard]] + bool IsInlineConstant(const IR::OrderedNodeWrapper& Node, uint64_t* Value = nullptr) const; + [[nodiscard]] + bool IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode, uint64_t* Value) const; struct LiveRange { uint32_t Begin; @@ -169,64 +186,64 @@ private: // This is purely a debugging aid for developers to see if they are in JIT code space when inspecting raw memory void EmitDetectionString(); - IR::RegisterAllocationPass *RAPass; - IR::RegisterAllocationData *RAData; - FEXCore::Core::DebugData *DebugData; + IR::RegisterAllocationPass* RAPass; + IR::RegisterAllocationData* RAData; + FEXCore::Core::DebugData* DebugData; void ResetStack(); /** * @name Relocations * @{ */ - uint64_t GetNamedSymbolLiteral(FEXCore::CPU::RelocNamedSymbolLiteral::NamedSymbol Op); + uint64_t GetNamedSymbolLiteral(FEXCore::CPU::RelocNamedSymbolLiteral::NamedSymbol Op); - /** - * @brief A literal pair relocation object for named symbol literals - */ - struct NamedSymbolLiteralPair { - ARMEmitter::ForwardLabel Loc; - uint64_t Lit; - Relocation MoveABI{}; - }; + /** + * @brief A literal pair relocation object for named symbol literals + */ + struct NamedSymbolLiteralPair { + ARMEmitter::ForwardLabel Loc; + uint64_t Lit; + Relocation MoveABI {}; + }; - /** - * @brief Inserts a thunk relocation - * - * @param Reg - The GPR to move the thunk handler in to - * @param Sum - The hash of the thunk - */ - void InsertNamedThunkRelocation(ARMEmitter::Register Reg, const IR::SHA256Sum &Sum); + /** + * @brief Inserts a thunk relocation + * + * @param Reg - The GPR to move the thunk handler in to + * @param Sum - The hash of the thunk + */ + void InsertNamedThunkRelocation(ARMEmitter::Register Reg, const IR::SHA256Sum& Sum); - /** - * @brief Inserts a guest GPR move relocation - * - * @param Reg - The GPR to move the guest RIP in to - * @param Constant - The guest RIP that will be relocated - */ - void InsertGuestRIPMove(ARMEmitter::Register Reg, uint64_t Constant); + /** + * @brief Inserts a guest GPR move relocation + * + * @param Reg - The GPR to move the guest RIP in to + * @param Constant - The guest RIP that will be relocated + */ + void InsertGuestRIPMove(ARMEmitter::Register Reg, uint64_t Constant); - /** - * @brief Inserts a named symbol as a literal in memory - * - * Need to use `PlaceNamedSymbolLiteral` with the return value to place the literal in the desired location - * - * @param Op The named symbol to place - * - * @return A temporary `NamedSymbolLiteralPair` - */ - NamedSymbolLiteralPair InsertNamedSymbolLiteral(FEXCore::CPU::RelocNamedSymbolLiteral::NamedSymbol Op); + /** + * @brief Inserts a named symbol as a literal in memory + * + * Need to use `PlaceNamedSymbolLiteral` with the return value to place the literal in the desired location + * + * @param Op The named symbol to place + * + * @return A temporary `NamedSymbolLiteralPair` + */ + NamedSymbolLiteralPair InsertNamedSymbolLiteral(FEXCore::CPU::RelocNamedSymbolLiteral::NamedSymbol Op); - /** - * @brief Place the named symbol literal relocation in memory - * - * @param Lit - Which literal to place - */ - void PlaceNamedSymbolLiteral(NamedSymbolLiteralPair &Lit); + /** + * @brief Place the named symbol literal relocation in memory + * + * @param Lit - Which literal to place + */ + void PlaceNamedSymbolLiteral(NamedSymbolLiteralPair& Lit); - fextl::vector Relocations; + fextl::vector Relocations; - ///< Relocation code loading - bool ApplyRelocations(uint64_t GuestEntry, uint64_t CodeEntry, uint64_t CursorEntry, size_t NumRelocations, const char* EntryRelocations); + ///< Relocation code loading + bool ApplyRelocations(uint64_t GuestEntry, uint64_t CodeEntry, uint64_t CursorEntry, size_t NumRelocations, const char* EntryRelocations); /** @} */ @@ -234,16 +251,18 @@ private: using OpType = void (Arm64JITCore::*)(const IR::IROp_Header* IROp, IR::NodeID Node); using ScalarBinaryOpCaller = std::function; - void VFScalarOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarBinaryOpCaller ScalarEmit, ARMEmitter::VRegister Dst, ARMEmitter::VRegister Vector1, ARMEmitter::VRegister Vector2); + void VFScalarOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarBinaryOpCaller ScalarEmit, + ARMEmitter::VRegister Dst, ARMEmitter::VRegister Vector1, ARMEmitter::VRegister Vector2); using ScalarUnaryOpCaller = std::function SrcVar)>; - void VFScalarUnaryOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarUnaryOpCaller ScalarEmit, ARMEmitter::VRegister Dst, ARMEmitter::VRegister Vector1, std::variant Vector2); + void VFScalarUnaryOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarUnaryOpCaller ScalarEmit, ARMEmitter::VRegister Dst, + ARMEmitter::VRegister Vector1, std::variant Vector2); // Runtime selection; // Load and store TSO memory style OpType RT_LoadMemTSO; OpType RT_StoreMemTSO; -#define DEF_OP(x) void Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) // Dynamic Dispatcher supporting operations DEF_OP(ParanoidLoadMemTSO); diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp index fe4bf03db..96daa0e6b 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp @@ -15,7 +15,7 @@ $end_info$ #include namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(LoadContext) { const auto Op = IROp->C(); @@ -25,49 +25,26 @@ DEF_OP(LoadContext) { auto Dst = GetReg(Node); switch (OpSize) { - case 1: - ldrb(Dst, STATE, Op->Offset); - break; - case 2: - ldrh(Dst, STATE, Op->Offset); - break; - case 4: - ldr(Dst.W(), STATE, Op->Offset); - break; - case 8: - ldr(Dst.X(), STATE, Op->Offset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadContext size: {}", OpSize); - break; + case 1: ldrb(Dst, STATE, Op->Offset); break; + case 2: ldrh(Dst, STATE, Op->Offset); break; + case 4: ldr(Dst.W(), STATE, Op->Offset); break; + case 8: ldr(Dst.X(), STATE, Op->Offset); break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadContext size: {}", OpSize); break; } - } - else { + } else { auto Dst = GetVReg(Node); switch (OpSize) { - case 1: - ldrb(Dst, STATE, Op->Offset); - break; - case 2: - ldrh(Dst, STATE, Op->Offset); - break; - case 4: - ldr(Dst.S(), STATE, Op->Offset); - break; - case 8: - ldr(Dst.D(), STATE, Op->Offset); - break; - case 16: - ldr(Dst.Q(), STATE, Op->Offset); - break; + case 1: ldrb(Dst, STATE, Op->Offset); break; + case 2: ldrh(Dst, STATE, Op->Offset); break; + case 4: ldr(Dst.S(), STATE, Op->Offset); break; + case 8: ldr(Dst.D(), STATE, Op->Offset); break; + case 16: ldr(Dst.Q(), STATE, Op->Offset); break; case 32: mov(TMP1, Op->Offset); ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), STATE, TMP1); break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadContext size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadContext size: {}", OpSize); break; } } } @@ -77,52 +54,29 @@ DEF_OP(StoreContext) { const auto OpSize = IROp->Size; if (Op->Class == FEXCore::IR::GPRClass) { - auto Src = GetReg(Op->Value.ID()); + auto Src = GetReg(Op->Value.ID()); switch (OpSize) { - case 1: - strb(Src, STATE, Op->Offset); - break; - case 2: - strh(Src, STATE, Op->Offset); - break; - case 4: - str(Src.W(), STATE, Op->Offset); - break; - case 8: - str(Src.X(), STATE, Op->Offset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreContext size: {}", OpSize); - break; + case 1: strb(Src, STATE, Op->Offset); break; + case 2: strh(Src, STATE, Op->Offset); break; + case 4: str(Src.W(), STATE, Op->Offset); break; + case 8: str(Src.X(), STATE, Op->Offset); break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreContext size: {}", OpSize); break; } - } - else { + } else { const auto Src = GetVReg(Op->Value.ID()); switch (OpSize) { - case 1: - strb(Src, STATE, Op->Offset); - break; - case 2: - strh(Src, STATE, Op->Offset); - break; - case 4: - str(Src.S(), STATE, Op->Offset); - break; - case 8: - str(Src.D(), STATE, Op->Offset); - break; - case 16: - str(Src.Q(), STATE, Op->Offset); - break; + case 1: strb(Src, STATE, Op->Offset); break; + case 2: strh(Src, STATE, Op->Offset); break; + case 4: str(Src.S(), STATE, Op->Offset); break; + case 8: str(Src.D(), STATE, Op->Offset); break; + case 16: str(Src.Q(), STATE, Op->Offset); break; case 32: mov(TMP1, Op->Offset); st1b(Src.Z(), PRED_TMP_32B, STATE, TMP1); break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreContext size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreContext size: {}", OpSize); break; } } } @@ -132,10 +86,11 @@ DEF_OP(LoadRegister) { const auto OpSize = IROp->Size; if (Op->Class == IR::GPRClass) { - const auto regId = - Op->Offset == offsetof(Core::CpuStateFrame, State.pf_raw) ? (StaticRegisters.size() - 2) : - Op->Offset == offsetof(Core::CpuStateFrame, State.af_raw) ? (StaticRegisters.size() - 1) : - (Op->Offset - offsetof(Core::CpuStateFrame, State.gregs[0])) / Core::CPUState::GPR_REG_SIZE; + const auto regId = Op->Offset == offsetof(Core::CpuStateFrame, State.pf_raw) ? + (StaticRegisters.size() - 2) : + Op->Offset == offsetof(Core::CpuStateFrame, State.af_raw) ? + (StaticRegisters.size() - 1) : + (Op->Offset - offsetof(Core::CpuStateFrame, State.gregs[0])) / Core::CPUState::GPR_REG_SIZE; const auto regOffs = Op->Offset & 7; @@ -144,27 +99,24 @@ DEF_OP(LoadRegister) { const auto reg = StaticRegisters[regId]; switch (OpSize) { - case 4: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); - if (GetReg(Node).Idx() != reg.Idx()) - mov(GetReg(Node).W(), reg.W()); - break; + case 4: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); + if (GetReg(Node).Idx() != reg.Idx()) { + mov(GetReg(Node).W(), reg.W()); + } + break; - case 8: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); - if (GetReg(Node).Idx() != reg.Idx()) { - mov(GetReg(Node).X(), reg.X()); - } - break; + case 8: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); + if (GetReg(Node).Idx() != reg.Idx()) { + mov(GetReg(Node).X(), reg.X()); + } + break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadRegister GPR size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadRegister GPR size: {}", OpSize); break; } - } - else if (Op->Class == IR::FPRClass) { - const auto regSize = HostSupportsSVE256 ? Core::CPUState::XMM_AVX_REG_SIZE - : Core::CPUState::XMM_SSE_REG_SIZE; + } else if (Op->Class == IR::FPRClass) { + const auto regSize = HostSupportsSVE256 ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; const auto regId = (Op->Offset - offsetof(Core::CpuStateFrame, State.xmm.avx.data[0][0])) / regSize; LOGMAN_THROW_A_FMT(regId < StaticFPRegisters.size(), "out of range regId"); @@ -192,116 +144,112 @@ DEF_OP(LoadRegister) { }; switch (OpSize) { - case 1: { - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); - dup(ARMEmitter::ScalarRegSize::i8Bit, host, guest, 0); - break; - } - case 2: { - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); - fmov(host.H(), guest.H()); - break; - } - case 4: { - LOGMAN_THROW_AA_FMT((regOffs & 3) == 0, "unexpected regOffs: {}", regOffs); - if (regOffs == 0) { - if (host.Idx() != guest.Idx()) { - fmov(host.S(), guest.S()); - } - } else { - const auto Predicate = LoadPredicate(); - - dup(FEXCore::ARMEmitter::SubRegSize::i32Bit, VTMP1.Z(), host.Z(), 0); - mov(FEXCore::ARMEmitter::SubRegSize::i32Bit, guest.Z(), Predicate, VTMP1.Z()); - - EmitData(1U << regOffs); - } - break; - } - - case 8: { - LOGMAN_THROW_AA_FMT((regOffs & 7) == 0, "unexpected regOffs: {}", regOffs); - if (regOffs == 0) { - if (host.Idx() != guest.Idx()) { - dup(ARMEmitter::ScalarRegSize::i64Bit, host, guest, 0); - } - } else { - const auto Predicate = LoadPredicate(); - - dup(FEXCore::ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), host.Z(), 0); - mov(FEXCore::ARMEmitter::SubRegSize::i64Bit, guest.Z(), Predicate, VTMP1.Z()); - - EmitData(1U << regOffs); - } - break; - } - - case 16: { - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + case 1: { + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + dup(ARMEmitter::ScalarRegSize::i8Bit, host, guest, 0); + break; + } + case 2: { + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + fmov(host.H(), guest.H()); + break; + } + case 4: { + LOGMAN_THROW_AA_FMT((regOffs & 3) == 0, "unexpected regOffs: {}", regOffs); + if (regOffs == 0) { if (host.Idx() != guest.Idx()) { - mov(host.Q(), guest.Q()); + fmov(host.S(), guest.S()); } - break; - } + } else { + const auto Predicate = LoadPredicate(); - case 32: { - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + dup(FEXCore::ARMEmitter::SubRegSize::i32Bit, VTMP1.Z(), host.Z(), 0); + mov(FEXCore::ARMEmitter::SubRegSize::i32Bit, guest.Z(), Predicate, VTMP1.Z()); + + EmitData(1U << regOffs); + } + break; + } + + case 8: { + LOGMAN_THROW_AA_FMT((regOffs & 7) == 0, "unexpected regOffs: {}", regOffs); + if (regOffs == 0) { if (host.Idx() != guest.Idx()) { - mov(ARMEmitter::SubRegSize::i64Bit, host.Z(), PRED_TMP_32B.Merging(), guest.Z()); + dup(ARMEmitter::ScalarRegSize::i64Bit, host, guest, 0); } - break; - } + } else { + const auto Predicate = LoadPredicate(); - default: - LOGMAN_MSG_A_FMT("Unhandled LoadRegister FPR size: {}", OpSize); - break; + dup(FEXCore::ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), host.Z(), 0); + mov(FEXCore::ARMEmitter::SubRegSize::i64Bit, guest.Z(), Predicate, VTMP1.Z()); + + EmitData(1U << regOffs); + } + break; + } + + case 16: { + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + if (host.Idx() != guest.Idx()) { + mov(host.Q(), guest.Q()); + } + break; + } + + case 32: { + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + if (host.Idx() != guest.Idx()) { + mov(ARMEmitter::SubRegSize::i64Bit, host.Z(), PRED_TMP_32B.Merging(), guest.Z()); + } + break; + } + + default: LOGMAN_MSG_A_FMT("Unhandled LoadRegister FPR size: {}", OpSize); break; } } else { const auto regOffs = Op->Offset & 15; switch (OpSize) { - case 1: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); - dup(ARMEmitter::ScalarRegSize::i8Bit, host, guest, 0); - break; + case 1: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + dup(ARMEmitter::ScalarRegSize::i8Bit, host, guest, 0); + break; - case 2: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); - fmov(host.H(), guest.H()); - break; + case 2: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + fmov(host.H(), guest.H()); + break; - case 4: - LOGMAN_THROW_AA_FMT((regOffs & 3) == 0, "unexpected regOffs: {}", regOffs); - if (regOffs == 0) { - if (host.Idx() != guest.Idx()) { - fmov(host.S(), guest.S()); - } - } else { - ins(ARMEmitter::SubRegSize::i32Bit, host, 0, guest, regOffs/4); - } - break; - - case 8: - LOGMAN_THROW_AA_FMT((regOffs & 7) == 0, "unexpected regOffs: {}", regOffs); - if (regOffs == 0) { - if (host.Idx() != guest.Idx()) { - dup(ARMEmitter::ScalarRegSize::i64Bit, host, guest, 0); - } - } else { - ins(ARMEmitter::SubRegSize::i64Bit, host, 0, guest, regOffs/8); - } - break; - - case 16: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + case 4: + LOGMAN_THROW_AA_FMT((regOffs & 3) == 0, "unexpected regOffs: {}", regOffs); + if (regOffs == 0) { if (host.Idx() != guest.Idx()) { - mov(host.Q(), guest.Q()); + fmov(host.S(), guest.S()); } - break; + } else { + ins(ARMEmitter::SubRegSize::i32Bit, host, 0, guest, regOffs / 4); + } + break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadRegister FPR size: {}", OpSize); - break; + case 8: + LOGMAN_THROW_AA_FMT((regOffs & 7) == 0, "unexpected regOffs: {}", regOffs); + if (regOffs == 0) { + if (host.Idx() != guest.Idx()) { + dup(ARMEmitter::ScalarRegSize::i64Bit, host, guest, 0); + } + } else { + ins(ARMEmitter::SubRegSize::i64Bit, host, 0, guest, regOffs / 8); + } + break; + + case 16: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + if (host.Idx() != guest.Idx()) { + mov(host.Q(), guest.Q()); + } + break; + + default: LOGMAN_MSG_A_FMT("Unhandled LoadRegister FPR size: {}", OpSize); break; } } } else { @@ -316,10 +264,11 @@ DEF_OP(StoreRegister) { if (Op->Class == IR::GPRClass) { const auto regOffs = Op->Offset & 7; - const auto regId = - Op->Offset == offsetof(Core::CpuStateFrame, State.pf_raw) ? (StaticRegisters.size() - 2) : - Op->Offset == offsetof(Core::CpuStateFrame, State.af_raw) ? (StaticRegisters.size() - 1) : - (Op->Offset - offsetof(Core::CpuStateFrame, State.gregs[0])) / Core::CPUState::GPR_REG_SIZE; + const auto regId = Op->Offset == offsetof(Core::CpuStateFrame, State.pf_raw) ? + (StaticRegisters.size() - 2) : + Op->Offset == offsetof(Core::CpuStateFrame, State.af_raw) ? + (StaticRegisters.size() - 1) : + (Op->Offset - offsetof(Core::CpuStateFrame, State.gregs[0])) / Core::CPUState::GPR_REG_SIZE; LOGMAN_THROW_A_FMT(regId < StaticRegisters.size(), "out of range regId"); @@ -327,26 +276,23 @@ DEF_OP(StoreRegister) { const auto Src = GetReg(Op->Value.ID()); switch (OpSize) { - case 4: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); - if (Src.Idx() != reg.Idx()) { - mov(ARMEmitter::Size::i32Bit, reg, Src); - } - break; - case 8: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); - if (Src.Idx() != reg.Idx()) { - mov(ARMEmitter::Size::i64Bit, reg, Src); - } - break; + case 4: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); + if (Src.Idx() != reg.Idx()) { + mov(ARMEmitter::Size::i32Bit, reg, Src); + } + break; + case 8: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); + if (Src.Idx() != reg.Idx()) { + mov(ARMEmitter::Size::i64Bit, reg, Src); + } + break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreRegister GPR size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreRegister GPR size: {}", OpSize); break; } } else if (Op->Class == IR::FPRClass) { - const auto regSize = HostSupportsSVE256 ? Core::CPUState::XMM_AVX_REG_SIZE - : Core::CPUState::XMM_SSE_REG_SIZE; + const auto regSize = HostSupportsSVE256 ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; const auto regId = (Op->Offset - offsetof(Core::CpuStateFrame, State.xmm.avx.data[0][0])) / regSize; LOGMAN_THROW_A_FMT(regId < StaticFPRegisters.size(), "regId out of range"); @@ -385,107 +331,101 @@ DEF_OP(StoreRegister) { }; switch (OpSize) { - case 1: { - LOGMAN_THROW_AA_FMT(regOffs <= 31, "unexpected reg index: {}", regOffs); + case 1: { + LOGMAN_THROW_AA_FMT(regOffs <= 31, "unexpected reg index: {}", regOffs); - const auto Predicate = LoadPredicate(); - dup(ARMEmitter::SubRegSize::i8Bit, VTMP1.Z(), host.Z(), 0); - mov(ARMEmitter::SubRegSize::i8Bit, guest.Z(), Predicate, VTMP1.Z()); + const auto Predicate = LoadPredicate(); + dup(ARMEmitter::SubRegSize::i8Bit, VTMP1.Z(), host.Z(), 0); + mov(ARMEmitter::SubRegSize::i8Bit, guest.Z(), Predicate, VTMP1.Z()); - EmitData(1U << regOffs); - break; + EmitData(1U << regOffs); + break; + } + + case 2: { + LOGMAN_THROW_AA_FMT((regOffs / 2) <= 15, "unexpected reg index: {}", regOffs / 2); + + const auto Predicate = LoadPredicate(); + dup(ARMEmitter::SubRegSize::i16Bit, VTMP1.Z(), host.Z(), 0); + mov(ARMEmitter::SubRegSize::i16Bit, guest.Z(), Predicate, VTMP1.Z()); + + EmitData(1U << regOffs); + break; + } + + case 4: { + LOGMAN_THROW_AA_FMT((regOffs / 4) <= 7, "unexpected reg index: {}", regOffs / 4); + + const auto Predicate = LoadPredicate(); + + dup(ARMEmitter::SubRegSize::i32Bit, VTMP1.Z(), host.Z(), 0); + mov(ARMEmitter::SubRegSize::i32Bit, guest.Z(), Predicate, VTMP1.Z()); + + EmitData(1U << regOffs); + break; + } + + case 8: { + LOGMAN_THROW_AA_FMT((regOffs / 8) <= 3, "unexpected reg index: {}", regOffs / 8); + + const auto Predicate = LoadPredicate(); + + dup(ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), host.Z(), 0); + mov(ARMEmitter::SubRegSize::i64Bit, guest.Z(), Predicate, VTMP1.Z()); + + EmitData(1U << regOffs); + break; + } + + case 16: { + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + if (guest.Idx() != host.Idx()) { + mov(guest.Q(), host.Q()); } + break; + } - case 2: { - LOGMAN_THROW_AA_FMT((regOffs / 2) <= 15, "unexpected reg index: {}", regOffs / 2); - - const auto Predicate = LoadPredicate(); - dup(ARMEmitter::SubRegSize::i16Bit, VTMP1.Z(), host.Z(), 0); - mov(ARMEmitter::SubRegSize::i16Bit, guest.Z(), Predicate, VTMP1.Z()); - - EmitData(1U << regOffs); - break; + case 32: { + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + if (guest.Idx() != host.Idx()) { + mov(ARMEmitter::SubRegSize::i64Bit, guest.Z(), PRED_TMP_32B.Merging(), host.Z()); } + break; + } - case 4: { - LOGMAN_THROW_AA_FMT((regOffs / 4) <= 7, "unexpected reg index: {}", regOffs / 4); - - const auto Predicate = LoadPredicate(); - - dup(ARMEmitter::SubRegSize::i32Bit, VTMP1.Z(), host.Z(), 0); - mov(ARMEmitter::SubRegSize::i32Bit, guest.Z(), Predicate, VTMP1.Z()); - - EmitData(1U << regOffs); - break; - } - - case 8: { - LOGMAN_THROW_AA_FMT((regOffs / 8) <= 3, "unexpected reg index: {}", regOffs / 8); - - const auto Predicate = LoadPredicate(); - - dup(ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), host.Z(), 0); - mov(ARMEmitter::SubRegSize::i64Bit, guest.Z(), Predicate, VTMP1.Z()); - - EmitData(1U << regOffs); - break; - } - - case 16: { - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); - if (guest.Idx() != host.Idx()) { - mov(guest.Q(), host.Q()); - } - break; - } - - case 32: { - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); - if (guest.Idx() != host.Idx()) { - mov(ARMEmitter::SubRegSize::i64Bit, guest.Z(), PRED_TMP_32B.Merging(), host.Z()); - } - break; - } - - default: - LOGMAN_MSG_A_FMT("Unhandled StoreRegister FPR size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreRegister FPR size: {}", OpSize); break; } } else { const auto regOffs = Op->Offset & 15; switch (OpSize) { - case 1: - ins(ARMEmitter::SubRegSize::i8Bit, guest, regOffs, host, 0); - break; + case 1: ins(ARMEmitter::SubRegSize::i8Bit, guest, regOffs, host, 0); break; - case 2: - LOGMAN_THROW_AA_FMT((regOffs & 1) == 0, "unexpected regOffs: {}", regOffs); - ins(ARMEmitter::SubRegSize::i16Bit, guest, regOffs / 2, host, 0); - break; + case 2: + LOGMAN_THROW_AA_FMT((regOffs & 1) == 0, "unexpected regOffs: {}", regOffs); + ins(ARMEmitter::SubRegSize::i16Bit, guest, regOffs / 2, host, 0); + break; - case 4: - LOGMAN_THROW_AA_FMT((regOffs & 3) == 0, "unexpected regOffs: {}", regOffs); - // XXX: This had a bug with insert of size 16bit - ins(ARMEmitter::SubRegSize::i32Bit, guest, regOffs / 4, host, 0); - break; + case 4: + LOGMAN_THROW_AA_FMT((regOffs & 3) == 0, "unexpected regOffs: {}", regOffs); + // XXX: This had a bug with insert of size 16bit + ins(ARMEmitter::SubRegSize::i32Bit, guest, regOffs / 4, host, 0); + break; - case 8: - LOGMAN_THROW_AA_FMT((regOffs & 7) == 0, "unexpected regOffs: {}", regOffs); - // XXX: This had a bug with insert of size 16bit - ins(ARMEmitter::SubRegSize::i64Bit, guest, regOffs / 8, host, 0); - break; + case 8: + LOGMAN_THROW_AA_FMT((regOffs & 7) == 0, "unexpected regOffs: {}", regOffs); + // XXX: This had a bug with insert of size 16bit + ins(ARMEmitter::SubRegSize::i64Bit, guest, regOffs / 8, host, 0); + break; - case 16: - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); - if (guest.Idx() != host.Idx()) { - mov(guest.Q(), host.Q()); - } - break; + case 16: + LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs: {}", regOffs); + if (guest.Idx() != host.Idx()) { + mov(guest.Q(), host.Q()); + } + break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreRegister FPR size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreRegister FPR size: {}", OpSize); break; } } } else { @@ -508,33 +448,18 @@ DEF_OP(LoadContextIndexed) { add(ARMEmitter::Size::i64Bit, TMP1, STATE, Index, FEXCore::ARMEmitter::ShiftType::LSL, FEXCore::ilog2(Op->Stride)); const auto Dst = GetReg(Node); switch (OpSize) { - case 1: - ldrb(Dst, TMP1, Op->BaseOffset); - break; - case 2: - ldrh(Dst, TMP1, Op->BaseOffset); - break; - case 4: - ldr(Dst.W(), TMP1, Op->BaseOffset); - break; - case 8: - ldr(Dst.X(), TMP1, Op->BaseOffset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed size: {}", OpSize); - break; + case 1: ldrb(Dst, TMP1, Op->BaseOffset); break; + case 2: ldrh(Dst, TMP1, Op->BaseOffset); break; + case 4: ldr(Dst.W(), TMP1, Op->BaseOffset); break; + case 8: ldr(Dst.X(), TMP1, Op->BaseOffset); break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed size: {}", OpSize); break; } break; } - case 16: - LOGMAN_MSG_A_FMT("Invalid Class load of size 16"); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed stride: {}", Op->Stride); - break; + case 16: LOGMAN_MSG_A_FMT("Invalid Class load of size 16"); break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed stride: {}", Op->Stride); break; } - } - else { + } else { switch (Op->Stride) { case 1: case 2: @@ -546,18 +471,10 @@ DEF_OP(LoadContextIndexed) { const auto Dst = GetVReg(Node); switch (OpSize) { - case 1: - ldrb(Dst, TMP1, Op->BaseOffset); - break; - case 2: - ldrh(Dst, TMP1, Op->BaseOffset); - break; - case 4: - ldr(Dst.S(), TMP1, Op->BaseOffset); - break; - case 8: - ldr(Dst.D(), TMP1, Op->BaseOffset); - break; + case 1: ldrb(Dst, TMP1, Op->BaseOffset); break; + case 2: ldrh(Dst, TMP1, Op->BaseOffset); break; + case 4: ldr(Dst.S(), TMP1, Op->BaseOffset); break; + case 8: ldr(Dst.D(), TMP1, Op->BaseOffset); break; case 16: if (Op->BaseOffset % 16 == 0) { ldr(Dst.Q(), TMP1, Op->BaseOffset); @@ -570,15 +487,11 @@ DEF_OP(LoadContextIndexed) { mov(TMP2, Op->BaseOffset); ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), TMP1, TMP2); break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed size: {}", OpSize); break; } break; } - default: - LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed stride: {}", Op->Stride); - break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadContextIndexed stride: {}", Op->Stride); break; } } } @@ -600,33 +513,18 @@ DEF_OP(StoreContextIndexed) { add(ARMEmitter::Size::i64Bit, TMP1, STATE, Index, FEXCore::ARMEmitter::ShiftType::LSL, FEXCore::ilog2(Op->Stride)); switch (OpSize) { - case 1: - strb(Value, TMP1, Op->BaseOffset); - break; - case 2: - strh(Value, TMP1, Op->BaseOffset); - break; - case 4: - str(Value.W(), TMP1, Op->BaseOffset); - break; - case 8: - str(Value.X(), TMP1, Op->BaseOffset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed size: {}", OpSize); - break; + case 1: strb(Value, TMP1, Op->BaseOffset); break; + case 2: strh(Value, TMP1, Op->BaseOffset); break; + case 4: str(Value.W(), TMP1, Op->BaseOffset); break; + case 8: str(Value.X(), TMP1, Op->BaseOffset); break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed size: {}", OpSize); break; } break; } - case 16: - LOGMAN_MSG_A_FMT("Invalid Class store of size 16"); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed stride: {}", Op->Stride); - break; + case 16: LOGMAN_MSG_A_FMT("Invalid Class store of size 16"); break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed stride: {}", Op->Stride); break; } - } - else { + } else { const auto Value = GetVReg(Op->Value.ID()); switch (Op->Stride) { @@ -639,18 +537,10 @@ DEF_OP(StoreContextIndexed) { add(ARMEmitter::Size::i64Bit, TMP1, STATE, Index, FEXCore::ARMEmitter::ShiftType::LSL, FEXCore::ilog2(Op->Stride)); switch (OpSize) { - case 1: - strb(Value, TMP1, Op->BaseOffset); - break; - case 2: - strh(Value, TMP1, Op->BaseOffset); - break; - case 4: - str(Value.S(), TMP1, Op->BaseOffset); - break; - case 8: - str(Value.D(), TMP1, Op->BaseOffset); - break; + case 1: strb(Value, TMP1, Op->BaseOffset); break; + case 2: strh(Value, TMP1, Op->BaseOffset); break; + case 4: str(Value.S(), TMP1, Op->BaseOffset); break; + case 8: str(Value.D(), TMP1, Op->BaseOffset); break; case 16: if (Op->BaseOffset % 16 == 0) { str(Value.Q(), TMP1, Op->BaseOffset); @@ -663,15 +553,11 @@ DEF_OP(StoreContextIndexed) { mov(TMP2, Op->BaseOffset); st1b(Value.Z(), PRED_TMP_32B, TMP1, TMP2); break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed size: {}", OpSize); break; } break; } - default: - LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed stride: {}", Op->Stride); - break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreContextIndexed stride: {}", Op->Stride); break; } } } @@ -688,8 +574,7 @@ DEF_OP(SpillRegister) { if (SlotOffset > LSByteMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); strb(Src, ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { strb(Src, ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -698,8 +583,7 @@ DEF_OP(SpillRegister) { if (SlotOffset > LSHalfMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); strh(Src, ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { strh(Src, ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -708,8 +592,7 @@ DEF_OP(SpillRegister) { if (SlotOffset > LSWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); str(Src.W(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { str(Src.W(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -718,15 +601,12 @@ DEF_OP(SpillRegister) { if (SlotOffset > LSDWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); str(Src.X(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { str(Src.X(), ARMEmitter::Reg::rsp, SlotOffset); } break; } - default: - LOGMAN_MSG_A_FMT("Unhandled SpillRegister size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled SpillRegister size: {}", OpSize); break; } } else if (Op->Class == FEXCore::IR::FPRClass) { const auto Src = GetVReg(Op->Value.ID()); @@ -736,8 +616,7 @@ DEF_OP(SpillRegister) { if (SlotOffset > LSWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); str(Src.S(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { str(Src.S(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -746,8 +625,7 @@ DEF_OP(SpillRegister) { if (SlotOffset > LSDWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); str(Src.D(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { str(Src.D(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -756,8 +634,7 @@ DEF_OP(SpillRegister) { if (SlotOffset > LSQWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); str(Src.Q(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { str(Src.Q(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -767,40 +644,33 @@ DEF_OP(SpillRegister) { st1b(Src.Z(), PRED_TMP_32B, ARMEmitter::Reg::rsp, TMP3); break; } - default: - LOGMAN_MSG_A_FMT("Unhandled SpillRegister size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled SpillRegister size: {}", OpSize); break; } } else if (Op->Class == FEXCore::IR::GPRPairClass) { const auto Src = GetRegPair(Op->Value.ID()); switch (OpSize) { - case 8: { - if (SlotOffset <= 252 && (SlotOffset & 0b11) == 0) { - stp(Src.first.W(), Src.second.W(), ARMEmitter::Reg::rsp, SlotOffset); - } - else { - add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); - stp(Src.first.W(), Src.second.W(), TMP1, 0); - } - break; + case 8: { + if (SlotOffset <= 252 && (SlotOffset & 0b11) == 0) { + stp(Src.first.W(), Src.second.W(), ARMEmitter::Reg::rsp, SlotOffset); + } else { + add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); + stp(Src.first.W(), Src.second.W(), TMP1, 0); } - - case 16: { - if (SlotOffset <= 504 && (SlotOffset & 0b111) == 0) { - stp(Src.first.X(), Src.second.X(), ARMEmitter::Reg::rsp, SlotOffset); - } - else { - add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); - stp(Src.first.X(), Src.second.X(), TMP1, 0); - } - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled SpillRegister(GPRPair) size: {}", OpSize); - break; + break; } - } - else { + + case 16: { + if (SlotOffset <= 504 && (SlotOffset & 0b111) == 0) { + stp(Src.first.X(), Src.second.X(), ARMEmitter::Reg::rsp, SlotOffset); + } else { + add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); + stp(Src.first.X(), Src.second.X(), TMP1, 0); + } + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled SpillRegister(GPRPair) size: {}", OpSize); break; + } + } else { LOGMAN_MSG_A_FMT("Unhandled SpillRegister class: {}", Op->Class.Val); } } @@ -817,8 +687,7 @@ DEF_OP(FillRegister) { if (SlotOffset > LSByteMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); ldrb(Dst, ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { ldrb(Dst, ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -827,8 +696,7 @@ DEF_OP(FillRegister) { if (SlotOffset > LSHalfMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); ldrh(Dst, ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { ldrh(Dst, ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -837,8 +705,7 @@ DEF_OP(FillRegister) { if (SlotOffset > LSWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); ldr(Dst.W(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { ldr(Dst.W(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -847,15 +714,12 @@ DEF_OP(FillRegister) { if (SlotOffset > LSDWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); ldr(Dst.X(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { ldr(Dst.X(), ARMEmitter::Reg::rsp, SlotOffset); } break; } - default: - LOGMAN_MSG_A_FMT("Unhandled FillRegister size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled FillRegister size: {}", OpSize); break; } } else if (Op->Class == FEXCore::IR::FPRClass) { const auto Dst = GetVReg(Node); @@ -865,8 +729,7 @@ DEF_OP(FillRegister) { if (SlotOffset > LSWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); ldr(Dst.S(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { ldr(Dst.S(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -875,8 +738,7 @@ DEF_OP(FillRegister) { if (SlotOffset > LSDWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); ldr(Dst.D(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { ldr(Dst.D(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -885,8 +747,7 @@ DEF_OP(FillRegister) { if (SlotOffset > LSQWordMaxUnsignedOffset) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, SlotOffset); ldr(Dst.Q(), ARMEmitter::Reg::rsp, TMP1.R(), ARMEmitter::ExtendedType::LSL_64, 0); - } - else { + } else { ldr(Dst.Q(), ARMEmitter::Reg::rsp, SlotOffset); } break; @@ -896,37 +757,31 @@ DEF_OP(FillRegister) { ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), ARMEmitter::Reg::rsp, TMP3); break; } - default: - LOGMAN_MSG_A_FMT("Unhandled FillRegister size: {}", OpSize); - break; + default: LOGMAN_MSG_A_FMT("Unhandled FillRegister size: {}", OpSize); break; } } else if (Op->Class == FEXCore::IR::GPRPairClass) { const auto Src = GetRegPair(Node); switch (OpSize) { - case 8: { - if (SlotOffset <= 252 && (SlotOffset & 0b11) == 0) { - ldp(Src.first.W(), Src.second.W(), ARMEmitter::Reg::rsp, SlotOffset); - } - else { - add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); - ldp(Src.first.W(), Src.second.W(), TMP1, 0); - } - break; + case 8: { + if (SlotOffset <= 252 && (SlotOffset & 0b11) == 0) { + ldp(Src.first.W(), Src.second.W(), ARMEmitter::Reg::rsp, SlotOffset); + } else { + add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); + ldp(Src.first.W(), Src.second.W(), TMP1, 0); } + break; + } - case 16: { - if (SlotOffset <= 504 && (SlotOffset & 0b111) == 0) { - ldp(Src.first.X(), Src.second.X(), ARMEmitter::Reg::rsp, SlotOffset); - } - else { - add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); - ldp(Src.first.X(), Src.second.X(), TMP1, 0); - } - break; + case 16: { + if (SlotOffset <= 504 && (SlotOffset & 0b111) == 0) { + ldp(Src.first.X(), Src.second.X(), ARMEmitter::Reg::rsp, SlotOffset); + } else { + add(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::rsp, SlotOffset); + ldp(Src.first.X(), Src.second.X(), TMP1, 0); } - default: - LOGMAN_MSG_A_FMT("Unhandled FillRegister(GPRPair) size: {}", OpSize); - break; + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled FillRegister(GPRPair) size: {}", OpSize); break; } } else { LOGMAN_MSG_A_FMT("Unhandled FillRegister class: {}", Op->Class.Val); @@ -957,9 +812,8 @@ DEF_OP(LoadFlag) { auto Op = IROp->C(); auto Dst = GetReg(Node); - LOGMAN_THROW_A_FMT(Op->Flag != X86State::RFLAG_PF_RAW_LOC && - Op->Flag != X86State::RFLAG_AF_RAW_LOC, - "PF/AF must be accessed as registers"); + LOGMAN_THROW_A_FMT(Op->Flag != X86State::RFLAG_PF_RAW_LOC && Op->Flag != X86State::RFLAG_AF_RAW_LOC, "PF/AF must be accessed as " + "registers"); ldrb(Dst, STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); } @@ -967,18 +821,14 @@ DEF_OP(LoadFlag) { DEF_OP(StoreFlag) { auto Op = IROp->C(); - LOGMAN_THROW_A_FMT(Op->Flag != X86State::RFLAG_PF_RAW_LOC && - Op->Flag != X86State::RFLAG_AF_RAW_LOC, - "PF/AF must be accessed as registers"); + LOGMAN_THROW_A_FMT(Op->Flag != X86State::RFLAG_PF_RAW_LOC && Op->Flag != X86State::RFLAG_AF_RAW_LOC, "PF/AF must be accessed as " + "registers"); strb(GetReg(Op->Value.ID()), STATE, offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag); } -FEXCore::ARMEmitter::ExtendedMemOperand Arm64JITCore::GenerateMemOperand(uint8_t AccessSize, - FEXCore::ARMEmitter::Register Base, - IR::OrderedNodeWrapper Offset, - IR::MemOffsetType OffsetType, - uint8_t OffsetScale) { +FEXCore::ARMEmitter::ExtendedMemOperand Arm64JITCore::GenerateMemOperand( + uint8_t AccessSize, FEXCore::ARMEmitter::Register Base, IR::OrderedNodeWrapper Offset, IR::MemOffsetType OffsetType, uint8_t OffsetScale) { if (Offset.IsInvalid()) { return ARMEmitter::ExtendedMemOperand(Base.X(), ARMEmitter::IndexType::OFFSET, 0); } else { @@ -990,11 +840,14 @@ FEXCore::ARMEmitter::ExtendedMemOperand Arm64JITCore::GenerateMemOperand(uint8_t return ARMEmitter::ExtendedMemOperand(Base.X(), ARMEmitter::IndexType::OFFSET, Const); } else { auto RegOffset = GetReg(Offset.ID()); - switch(OffsetType.Val) { - case IR::MEM_OFFSET_SXTX.Val: return ARMEmitter::ExtendedMemOperand(Base.X(), RegOffset.X(), ARMEmitter::ExtendedType::SXTX, FEXCore::ilog2(OffsetScale) ); - case IR::MEM_OFFSET_UXTW.Val: return ARMEmitter::ExtendedMemOperand(Base.X(), RegOffset.X(), ARMEmitter::ExtendedType::UXTW, FEXCore::ilog2(OffsetScale) ); - case IR::MEM_OFFSET_SXTW.Val: return ARMEmitter::ExtendedMemOperand(Base.X(), RegOffset.X(), ARMEmitter::ExtendedType::SXTW, FEXCore::ilog2(OffsetScale) ); - default: LOGMAN_MSG_A_FMT("Unhandled GenerateMemOperand OffsetType: {}", OffsetType.Val); break; + switch (OffsetType.Val) { + case IR::MEM_OFFSET_SXTX.Val: + return ARMEmitter::ExtendedMemOperand(Base.X(), RegOffset.X(), ARMEmitter::ExtendedType::SXTX, FEXCore::ilog2(OffsetScale)); + case IR::MEM_OFFSET_UXTW.Val: + return ARMEmitter::ExtendedMemOperand(Base.X(), RegOffset.X(), ARMEmitter::ExtendedType::UXTW, FEXCore::ilog2(OffsetScale)); + case IR::MEM_OFFSET_SXTW.Val: + return ARMEmitter::ExtendedMemOperand(Base.X(), RegOffset.X(), ARMEmitter::ExtendedType::SXTW, FEXCore::ilog2(OffsetScale)); + default: LOGMAN_MSG_A_FMT("Unhandled GenerateMemOperand OffsetType: {}", OffsetType.Val); break; } } } @@ -1002,16 +855,14 @@ FEXCore::ARMEmitter::ExtendedMemOperand Arm64JITCore::GenerateMemOperand(uint8_t FEX_UNREACHABLE; } -FEXCore::ARMEmitter::SVEMemOperand Arm64JITCore::GenerateSVEMemOperand(uint8_t AccessSize, - FEXCore::ARMEmitter::Register Base, - IR::OrderedNodeWrapper Offset, - IR::MemOffsetType OffsetType, - [[maybe_unused]] uint8_t OffsetScale) { +FEXCore::ARMEmitter::SVEMemOperand Arm64JITCore::GenerateSVEMemOperand(uint8_t AccessSize, FEXCore::ARMEmitter::Register Base, + IR::OrderedNodeWrapper Offset, IR::MemOffsetType OffsetType, + [[maybe_unused]] uint8_t OffsetScale) { if (Offset.IsInvalid()) { return FEXCore::ARMEmitter::SVEMemOperand(Base.X(), 0); } - uint64_t Const{}; + uint64_t Const {}; if (IsInlineConstant(Offset, &Const)) { if (Const == 0) { return FEXCore::ARMEmitter::SVEMemOperand(Base.X(), 0); @@ -1050,8 +901,7 @@ FEXCore::ARMEmitter::SVEMemOperand Arm64JITCore::GenerateSVEMemOperand(uint8_t A // Note that we do nothing with the offset type and offset scale, // since SVE loads and stores don't have the ability to perform an // optional extension or shift as part of their behavior. - LOGMAN_THROW_A_FMT(OffsetType.Val == IR::MEM_OFFSET_SXTX.Val, - "Currently only the default offset type (SXTX) is supported."); + LOGMAN_THROW_A_FMT(OffsetType.Val == IR::MEM_OFFSET_SXTX.Val, "Currently only the default offset type (SXTX) is supported."); const auto RegOffset = GetReg(Offset.ID()); return FEXCore::ARMEmitter::SVEMemOperand(Base.X(), RegOffset.X()); @@ -1068,50 +918,27 @@ DEF_OP(LoadMem) { const auto Dst = GetReg(Node); switch (OpSize) { - case 1: - ldrb(Dst, MemSrc); - break; - case 2: - ldrh(Dst, MemSrc); - break; - case 4: - ldr(Dst.W(), MemSrc); - break; - case 8: - ldr(Dst.X(), MemSrc); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadMem size: {}", OpSize); - break; + case 1: ldrb(Dst, MemSrc); break; + case 2: ldrh(Dst, MemSrc); break; + case 4: ldr(Dst.W(), MemSrc); break; + case 8: ldr(Dst.X(), MemSrc); break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadMem size: {}", OpSize); break; } - } - else { + } else { const auto Dst = GetVReg(Node); switch (OpSize) { - case 1: - ldrb(Dst, MemSrc); - break; - case 2: - ldrh(Dst, MemSrc); - break; - case 4: - ldr(Dst.S(), MemSrc); - break; - case 8: - ldr(Dst.D(), MemSrc); - break; - case 16: - ldr(Dst.Q(), MemSrc); - break; - case 32: { - const auto Operand = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); - ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), Operand); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled LoadMem size: {}", OpSize); - break; + case 1: ldrb(Dst, MemSrc); break; + case 2: ldrh(Dst, MemSrc); break; + case 4: ldr(Dst.S(), MemSrc); break; + case 8: ldr(Dst.D(), MemSrc); break; + case 16: ldr(Dst.Q(), MemSrc); break; + case 32: { + const auto Operand = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); + ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), Operand); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled LoadMem size: {}", OpSize); break; } } } @@ -1133,103 +960,61 @@ DEF_OP(LoadMemTSO) { // 8bit load is always aligned to natural alignment const auto Dst = GetReg(Node); ldapurb(Dst, MemReg, Offset); - } - else { + } else { switch (OpSize) { - case 2: - ldapurh(Dst, MemReg, Offset); - break; - case 4: - ldapur(Dst.W(), MemReg, Offset); - break; - case 8: - ldapur(Dst.X(), MemReg, Offset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); - break; + case 2: ldapurh(Dst, MemReg, Offset); break; + case 4: ldapur(Dst.W(), MemReg, Offset); break; + case 8: ldapur(Dst.X(), MemReg, Offset); break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); break; } // Half-barrier once back-patched. nop(); } - } - else if (CTX->HostFeatures.SupportsRCPC && Op->Class == FEXCore::IR::GPRClass) { + } else if (CTX->HostFeatures.SupportsRCPC && Op->Class == FEXCore::IR::GPRClass) { const auto Dst = GetReg(Node); if (OpSize == 1) { // 8bit load is always aligned to natural alignment ldaprb(Dst.W(), MemReg); - } - else { + } else { switch (OpSize) { - case 2: - ldaprh(Dst.W(), MemReg); - break; - case 4: - ldapr(Dst.W(), MemReg); - break; - case 8: - ldapr(Dst.X(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); - break; + case 2: ldaprh(Dst.W(), MemReg); break; + case 4: ldapr(Dst.W(), MemReg); break; + case 8: ldapr(Dst.X(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); break; } // Half-barrier once back-patched. nop(); } - } - else if (Op->Class == FEXCore::IR::GPRClass) { + } else if (Op->Class == FEXCore::IR::GPRClass) { const auto Dst = GetReg(Node); if (OpSize == 1) { // 8bit load is always aligned to natural alignment ldarb(Dst, MemReg); - } - else { + } else { switch (OpSize) { - case 2: - ldarh(Dst, MemReg); - break; - case 4: - ldar(Dst.W(), MemReg); - break; - case 8: - ldar(Dst.X(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); - break; + case 2: ldarh(Dst, MemReg); break; + case 4: ldar(Dst.W(), MemReg); break; + case 8: ldar(Dst.X(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); break; } // Half-barrier once back-patched. nop(); } - } - else { + } else { const auto Dst = GetVReg(Node); const auto MemSrc = GenerateMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); switch (OpSize) { - case 1: - ldrb(Dst, MemSrc); - break; - case 2: - ldrh(Dst, MemSrc); - break; - case 4: - ldr(Dst.S(), MemSrc); - break; - case 8: - ldr(Dst.D(), MemSrc); - break; - case 16: - ldr(Dst.Q(), MemSrc); - break; - case 32: { - const auto MemSrc = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); - ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), MemSrc); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); - break; + case 1: ldrb(Dst, MemSrc); break; + case 2: ldrh(Dst, MemSrc); break; + case 4: ldr(Dst.S(), MemSrc); break; + case 8: ldr(Dst.D(), MemSrc); break; + case 16: ldr(Dst.Q(), MemSrc); break; + case 32: { + const auto MemSrc = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); + ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), MemSrc); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled LoadMemTSO size: {}", OpSize); break; } if (VectorTSOEnabled()) { // Half-barrier. @@ -1256,35 +1041,33 @@ DEF_OP(VLoadVectorMasked) { const auto MemSrc = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; // Check if the sign bit is set for the given element size. cmplt(SubRegSize, CMPPredicate, GoverningPredicate.Zeroing(), MaskReg.Z(), 0); switch (ElementSize) { - case 1: { - ld1b(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); - break; - } - case 2: { - ld1h(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); - break; - } - case 4: { - ld1w(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); - break; - } - case 8: { - ld1d(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled VLoadVectorMasked size: {}", ElementSize); - break; + case 1: { + ld1b(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); + break; + } + case 2: { + ld1h(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); + break; + } + case 4: { + ld1w(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); + break; + } + case 8: { + ld1d(Dst.Z(), CMPPredicate.Zeroing(), MemSrc); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled VLoadVectorMasked size: {}", ElementSize); break; } } @@ -1306,35 +1089,33 @@ DEF_OP(VStoreVectorMasked) { const auto MemDst = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; // Check if the sign bit is set for the given element size. cmplt(SubRegSize, CMPPredicate, GoverningPredicate.Zeroing(), MaskReg.Z(), 0); switch (ElementSize) { - case 1: { - st1b(RegData.Z(), CMPPredicate.Zeroing(), MemDst); - break; - } - case 2: { - st1h(RegData.Z(), CMPPredicate.Zeroing(), MemDst); - break; - } - case 4: { - st1w(RegData.Z(), CMPPredicate.Zeroing(), MemDst); - break; - } - case 8: { - st1d(RegData.Z(), CMPPredicate.Zeroing(), MemDst); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled VStoreVectorMasked size: {}", ElementSize); - break; + case 1: { + st1b(RegData.Z(), CMPPredicate.Zeroing(), MemDst); + break; + } + case 2: { + st1h(RegData.Z(), CMPPredicate.Zeroing(), MemDst); + break; + } + case 4: { + st1w(RegData.Z(), CMPPredicate.Zeroing(), MemDst); + break; + } + case 8: { + st1d(RegData.Z(), CMPPredicate.Zeroing(), MemDst); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled VStoreVectorMasked size: {}", ElementSize); break; } } @@ -1349,9 +1130,8 @@ DEF_OP(VLoadVectorElement) { const auto DstSrc = GetVReg(Op->DstSrc.ID()); const auto MemReg = GetReg(Op->Addr.ID()); - LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || - ElementSize == 4 || ElementSize == 8 || - ElementSize == 16, "Invalid element size"); + LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid element " + "size"); if (Is256Bit) { LOGMAN_MSG_A_FMT("Unsupported 256-bit VLoadVectorElement"); @@ -1360,24 +1140,12 @@ DEF_OP(VLoadVectorElement) { mov(Dst.Q(), DstSrc.Q()); } switch (ElementSize) { - case 1: - ld1(Dst.Q(), Op->Index, MemReg); - break; - case 2: - ld1(Dst.Q(), Op->Index, MemReg); - break; - case 4: - ld1(Dst.Q(), Op->Index, MemReg); - break; - case 8: - ld1(Dst.Q(), Op->Index, MemReg); - break; - case 16: - ldr(Dst.Q(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ElementSize); - return; + case 1: ld1(Dst.Q(), Op->Index, MemReg); break; + case 2: ld1(Dst.Q(), Op->Index, MemReg); break; + case 4: ld1(Dst.Q(), Op->Index, MemReg); break; + case 8: ld1(Dst.Q(), Op->Index, MemReg); break; + case 16: ldr(Dst.Q(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ElementSize); return; } } @@ -1397,9 +1165,8 @@ DEF_OP(VStoreVectorElement) { const auto Value = GetVReg(Op->Value.ID()); const auto MemReg = GetReg(Op->Addr.ID()); - LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || - ElementSize == 4 || ElementSize == 8 || - ElementSize == 16, "Invalid element size"); + LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid element " + "size"); // Emit a half-barrier if TSO is enabled. if (CTX->IsAtomicTSOEnabled() && VectorTSOEnabled()) { @@ -1410,24 +1177,12 @@ DEF_OP(VStoreVectorElement) { LOGMAN_MSG_A_FMT("Unsupported 256-bit {}", __func__); } else { switch (ElementSize) { - case 1: - st1(Value.Q(), Op->Index, MemReg); - break; - case 2: - st1(Value.Q(), Op->Index, MemReg); - break; - case 4: - st1(Value.Q(), Op->Index, MemReg); - break; - case 8: - st1(Value.Q(), Op->Index, MemReg); - break; - case 16: - str(Value.Q(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ElementSize); - return; + case 1: st1(Value.Q(), Op->Index, MemReg); break; + case 2: st1(Value.Q(), Op->Index, MemReg); break; + case 4: st1(Value.Q(), Op->Index, MemReg); break; + case 8: st1(Value.Q(), Op->Index, MemReg); break; + case 16: str(Value.Q(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ElementSize); return; } } } @@ -1442,9 +1197,8 @@ DEF_OP(VBroadcastFromMem) { const auto Dst = GetVReg(Node); const auto MemReg = GetReg(Op->Address.ID()); - LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || - ElementSize == 4 || ElementSize == 8 || - ElementSize == 16, "Invalid element size"); + LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid element " + "size"); if (Is256Bit && !HostSupportsSVE256) { LOGMAN_MSG_A_FMT("{}: 256-bit vectors must support SVE256", __func__); @@ -1455,49 +1209,24 @@ DEF_OP(VBroadcastFromMem) { const auto GoverningPredicate = PRED_TMP_32B.Zeroing(); switch (ElementSize) { - case 1: - ld1rb(ARMEmitter::SubRegSize::i8Bit, Dst.Z(), - GoverningPredicate, MemReg); - break; - case 2: - ld1rh(ARMEmitter::SubRegSize::i16Bit, Dst.Z(), - GoverningPredicate, MemReg); - break; - case 4: - ld1rw(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), - GoverningPredicate, MemReg); - break; - case 8: - ld1rd(Dst.Z(), GoverningPredicate, MemReg); - break; - case 16: - ld1rqb(Dst.Z(), GoverningPredicate, MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled VBroadcastFromMem size: {}", ElementSize); - return; + case 1: ld1rb(ARMEmitter::SubRegSize::i8Bit, Dst.Z(), GoverningPredicate, MemReg); break; + case 2: ld1rh(ARMEmitter::SubRegSize::i16Bit, Dst.Z(), GoverningPredicate, MemReg); break; + case 4: ld1rw(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), GoverningPredicate, MemReg); break; + case 8: ld1rd(Dst.Z(), GoverningPredicate, MemReg); break; + case 16: ld1rqb(Dst.Z(), GoverningPredicate, MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled VBroadcastFromMem size: {}", ElementSize); return; } } else { switch (ElementSize) { - case 1: - ld1r(Dst.Q(), MemReg); - break; - case 2: - ld1r(Dst.Q(), MemReg); - break; - case 4: - ld1r(Dst.Q(), MemReg); - break; - case 8: - ld1r(Dst.Q(), MemReg); - break; + case 1: ld1r(Dst.Q(), MemReg); break; + case 2: ld1r(Dst.Q(), MemReg); break; + case 4: ld1r(Dst.Q(), MemReg); break; + case 8: ld1r(Dst.Q(), MemReg); break; case 16: // Normal load, like ld1rqb with 128-bit regs. ldr(Dst.Q(), MemReg); break; - default: - LOGMAN_MSG_A_FMT("Unhandled VBroadcastFromMem size: {}", ElementSize); - return; + default: LOGMAN_MSG_A_FMT("Unhandled VBroadcastFromMem size: {}", ElementSize); return; } } @@ -1519,8 +1248,7 @@ DEF_OP(Push) { if (Dst == Src) { NeedsMoveAfterwards = true; // Need to be careful here, incoming source might be reused afterwards. - } - else { + } else { // RA constraints would let this always be true. mov(IROp->Size == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit, Dst, AddrSrc); } @@ -1544,52 +1272,51 @@ DEF_OP(Push) { if (NeedsMoveAfterwards) { switch (ValueSize) { - case 1: { - sturb(Src.W(), AddrSrc, -ValueSize); - break; - } - case 2: { - sturh(Src.W(), AddrSrc, -ValueSize); - break; - } - case 4: { - stur(Src.W(), AddrSrc, -ValueSize); - break; - } - case 8: { - stur(Src.X(), AddrSrc, -ValueSize); - break; - } - default: { - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ValueSize); - break; - } + case 1: { + sturb(Src.W(), AddrSrc, -ValueSize); + break; + } + case 2: { + sturh(Src.W(), AddrSrc, -ValueSize); + break; + } + case 4: { + stur(Src.W(), AddrSrc, -ValueSize); + break; + } + case 8: { + stur(Src.X(), AddrSrc, -ValueSize); + break; + } + default: { + LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ValueSize); + break; + } } sub(IROp->Size == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit, Dst, AddrSrc, ValueSize); - } - else { + } else { switch (ValueSize) { - case 1: { - strb(Src.W(), Dst, -ValueSize); - break; - } - case 2: { - strh(Src.W(), Dst, -ValueSize); - break; - } - case 4: { - str(Src.W(), Dst, -ValueSize); - break; - } - case 8: { - str(Src.X(), Dst, -ValueSize); - break; - } - default: { - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ValueSize); - break; - } + case 1: { + strb(Src.W(), Dst, -ValueSize); + break; + } + case 2: { + strh(Src.W(), Dst, -ValueSize); + break; + } + case 4: { + str(Src.W(), Dst, -ValueSize); + break; + } + case 8: { + str(Src.X(), Dst, -ValueSize); + break; + } + default: { + LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ValueSize); + break; + } } } } @@ -1604,55 +1331,42 @@ DEF_OP(StoreMem) { if (Op->Class == FEXCore::IR::GPRClass) { const auto Src = GetReg(Op->Value.ID()); switch (OpSize) { - case 1: - strb(Src, MemSrc); - break; - case 2: - strh(Src, MemSrc); - break; - case 4: - str(Src.W(), MemSrc); - break; - case 8: - str(Src.X(), MemSrc); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreMem size: {}", OpSize); - break; + case 1: strb(Src, MemSrc); break; + case 2: strh(Src, MemSrc); break; + case 4: str(Src.W(), MemSrc); break; + case 8: str(Src.X(), MemSrc); break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreMem size: {}", OpSize); break; } - } - else { + } else { const auto Src = GetVReg(Op->Value.ID()); switch (OpSize) { - case 1: { - strb(Src, MemSrc); - break; - } - case 2: { - strh(Src, MemSrc); - break; - } - case 4: { - str(Src.S(), MemSrc); - break; - } - case 8: { - str(Src.D(), MemSrc); - break; - } - case 16: { - str(Src.Q(), MemSrc); - break; - } - case 32: { - const auto MemSrc = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); - st1b(Src.Z(), PRED_TMP_32B, MemSrc); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled StoreMem size: {}", OpSize); - break; + case 1: { + strb(Src, MemSrc); + break; + } + case 2: { + strh(Src, MemSrc); + break; + } + case 4: { + str(Src.S(), MemSrc); + break; + } + case 8: { + str(Src.D(), MemSrc); + break; + } + case 16: { + str(Src.Q(), MemSrc); + break; + } + case 32: { + const auto MemSrc = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); + st1b(Src.Z(), PRED_TMP_32B, MemSrc); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled StoreMem size: {}", OpSize); break; } } } @@ -1673,53 +1387,33 @@ DEF_OP(StoreMemTSO) { if (OpSize == 1) { // 8bit load is always aligned to natural alignment stlurb(Src, MemReg, Offset); - } - else { + } else { // Half-barrier once back-patched. nop(); switch (OpSize) { - case 2: - stlurh(Src, MemReg, Offset); - break; - case 4: - stlur(Src.W(), MemReg, Offset); - break; - case 8: - stlur(Src.X(), MemReg, Offset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreMemTSO size: {}", OpSize); - break; + case 2: stlurh(Src, MemReg, Offset); break; + case 4: stlur(Src.W(), MemReg, Offset); break; + case 8: stlur(Src.X(), MemReg, Offset); break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreMemTSO size: {}", OpSize); break; } } - } - else if (Op->Class == FEXCore::IR::GPRClass) { + } else if (Op->Class == FEXCore::IR::GPRClass) { const auto Src = GetReg(Op->Value.ID()); if (OpSize == 1) { // 8bit load is always aligned to natural alignment stlrb(Src, MemReg); - } - else { + } else { // Half-barrier once back-patched. nop(); switch (OpSize) { - case 2: - stlrh(Src, MemReg); - break; - case 4: - stlr(Src.W(), MemReg); - break; - case 8: - stlr(Src.X(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled StoreMemTSO size: {}", OpSize); - break; + case 2: stlrh(Src, MemReg); break; + case 4: stlr(Src.W(), MemReg); break; + case 8: stlr(Src.X(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled StoreMemTSO size: {}", OpSize); break; } } - } - else { + } else { if (VectorTSOEnabled()) { // Half-Barrier. dmb(FEXCore::ARMEmitter::BarrierScope::ISH); @@ -1727,29 +1421,17 @@ DEF_OP(StoreMemTSO) { const auto Src = GetVReg(Op->Value.ID()); const auto MemSrc = GenerateMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); switch (OpSize) { - case 1: - strb(Src, MemSrc); - break; - case 2: - strh(Src, MemSrc); - break; - case 4: - str(Src.S(), MemSrc); - break; - case 8: - str(Src.D(), MemSrc); - break; - case 16: - str(Src.Q(), MemSrc); - break; - case 32: { - const auto Operand = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); - st1b(Src.Z(), PRED_TMP_32B, Operand); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled StoreMemTSO size: {}", OpSize); - break; + case 1: strb(Src, MemSrc); break; + case 2: strh(Src, MemSrc); break; + case 4: str(Src.S(), MemSrc); break; + case 8: str(Src.D(), MemSrc); break; + case 16: str(Src.Q(), MemSrc); break; + case 32: { + const auto Operand = GenerateSVEMemOperand(OpSize, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); + st1b(Src.Z(), PRED_TMP_32B, Operand); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled StoreMemTSO size: {}", OpSize); break; } } } @@ -1785,14 +1467,13 @@ DEF_OP(MemSet) { // // Counter is decremented regardless. - ARMEmitter::SingleUseForwardLabel BackwardImpl{}; - ARMEmitter::SingleUseForwardLabel Done{}; + ARMEmitter::SingleUseForwardLabel BackwardImpl {}; + ARMEmitter::SingleUseForwardLabel Done {}; mov(TMP1, Length.X()); if (Op->Prefix.IsInvalid()) { mov(TMP2, MemReg.X()); - } - else { + } else { const auto Prefix = GetReg(Op->Prefix.ID()); add(TMP2, Prefix.X(), MemReg.X()); } @@ -1804,21 +1485,11 @@ DEF_OP(MemSet) { auto MemStore = [this](auto Value, uint32_t OpSize, int32_t Size) { switch (OpSize) { - case 1: - strb(Value.W(), TMP2, Size); - break; - case 2: - strh(Value.W(), TMP2, Size); - break; - case 4: - str(Value.W(), TMP2, Size); - break; - case 8: - str(Value.X(), TMP2, Size); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); - break; + case 1: strb(Value.W(), TMP2, Size); break; + case 2: strh(Value.W(), TMP2, Size); break; + case 4: str(Value.W(), TMP2, Size); break; + case 8: str(Value.X(), TMP2, Size); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); break; } }; @@ -1826,55 +1497,45 @@ DEF_OP(MemSet) { if (OpSize == 1) { // 8bit load is always aligned to natural alignment stlrb(Value.W(), TMP2); - } - else { + } else { nop(); switch (OpSize) { - case 2: - stlrh(Value.W(), TMP2); - break; - case 4: - stlr(Value.W(), TMP2); - break; - case 8: - stlr(Value.X(), TMP2); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); - break; + case 2: stlrh(Value.W(), TMP2); break; + case 4: stlr(Value.W(), TMP2); break; + case 8: stlr(Value.X(), TMP2); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); break; } nop(); } if (Size >= 0) { add(ARMEmitter::Size::i64Bit, TMP2, TMP2, OpSize); - } - else { + } else { sub(ARMEmitter::Size::i64Bit, TMP2, TMP2, OpSize); } }; - const auto SubRegSize = - Size == 1 ? ARMEmitter::SubRegSize::i8Bit : - Size == 2 ? ARMEmitter::SubRegSize::i16Bit : - Size == 4 ? ARMEmitter::SubRegSize::i32Bit : - Size == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = Size == 1 ? ARMEmitter::SubRegSize::i8Bit : + Size == 2 ? ARMEmitter::SubRegSize::i16Bit : + Size == 4 ? ARMEmitter::SubRegSize::i32Bit : + Size == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; auto EmitMemset = [&](int32_t Direction) { const int32_t OpSize = Size; const int32_t SizeDirection = Size * Direction; - ARMEmitter::BiDirectionalLabel AgainInternal{}; - ARMEmitter::ForwardLabel DoneInternal{}; + ARMEmitter::BiDirectionalLabel AgainInternal {}; + ARMEmitter::ForwardLabel DoneInternal {}; // Early exit if zero count. cbz(ARMEmitter::Size::i64Bit, TMP1, &DoneInternal); if (!IsAtomic) { - ARMEmitter::ForwardLabel AgainInternal256Exit{}; - ARMEmitter::BackwardLabel AgainInternal256{}; - ARMEmitter::ForwardLabel AgainInternal128Exit{}; - ARMEmitter::BackwardLabel AgainInternal128{}; + ARMEmitter::ForwardLabel AgainInternal256Exit {}; + ARMEmitter::BackwardLabel AgainInternal256 {}; + ARMEmitter::ForwardLabel AgainInternal128Exit {}; + ARMEmitter::BackwardLabel AgainInternal128 {}; if (Direction == -1) { sub(ARMEmitter::Size::i64Bit, TMP2, TMP2, 32 - Size); @@ -1922,8 +1583,7 @@ DEF_OP(MemSet) { Bind(&AgainInternal); if (IsAtomic) { MemStoreTSO(Value, OpSize, SizeDirection); - } - else { + } else { MemStore(Value, OpSize, SizeDirection); } sub(ARMEmitter::Size::i64Bit, TMP1, TMP1, 1); @@ -1933,40 +1593,19 @@ DEF_OP(MemSet) { if (SizeDirection >= 0) { switch (OpSize) { - case 1: - add(Dst.X(), MemReg.X(), Length.X()); - break; - case 2: - add(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 1); - break; - case 4: - add(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 2); - break; - case 8: - add(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 3); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); - break; + case 1: add(Dst.X(), MemReg.X(), Length.X()); break; + case 2: add(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 1); break; + case 4: add(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 2); break; + case 8: add(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 3); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); break; } - } - else { + } else { switch (OpSize) { - case 1: - sub(Dst.X(), MemReg.X(), Length.X()); - break; - case 2: - sub(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 1); - break; - case 4: - sub(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 2); - break; - case 8: - sub(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 3); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); - break; + case 1: sub(Dst.X(), MemReg.X(), Length.X()); break; + case 2: sub(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 1); break; + case 4: sub(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 2); break; + case 8: sub(Dst.X(), MemReg.X(), Length.X(), ARMEmitter::ShiftType::LSL, 3); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); break; } } }; @@ -1974,10 +1613,9 @@ DEF_OP(MemSet) { if (DirectionIsInline) { LOGMAN_THROW_AA_FMT(DirectionConstant == 1 || DirectionConstant == -1, "unexpected direction"); EmitMemset(DirectionConstant); - } - else { + } else { // Emit forward direction memset then backward direction memset. - for (int32_t Direction : { 1, -1 }) { + for (int32_t Direction : {1, -1}) { EmitMemset(Direction); if (Direction == 1) { @@ -2021,22 +1659,20 @@ DEF_OP(MemCpy) { // // Counter is decremented regardless. - ARMEmitter::SingleUseForwardLabel BackwardImpl{}; - ARMEmitter::SingleUseForwardLabel Done{}; + ARMEmitter::SingleUseForwardLabel BackwardImpl {}; + ARMEmitter::SingleUseForwardLabel Done {}; mov(TMP1, Length.X()); if (Op->PrefixDest.IsInvalid()) { mov(TMP2, MemRegDest.X()); - } - else { + } else { const auto Prefix = GetReg(Op->PrefixDest.ID()); add(TMP2, Prefix.X(), MemRegDest.X()); } if (Op->PrefixSrc.IsInvalid()) { mov(TMP3, MemRegSrc.X()); - } - else { + } else { const auto Prefix = GetReg(Op->PrefixSrc.ID()); add(TMP3, Prefix.X(), MemRegSrc.X()); } @@ -2053,29 +1689,27 @@ DEF_OP(MemCpy) { auto MemCpy = [this](uint32_t OpSize, int32_t Size) { switch (OpSize) { - case 1: - ldrb(TMP4.W(), TMP3, Size); - strb(TMP4.W(), TMP2, Size); - break; - case 2: - ldrh(TMP4.W(), TMP3, Size); - strh(TMP4.W(), TMP2, Size); - break; - case 4: - ldr(TMP4.W(), TMP3, Size); - str(TMP4.W(), TMP2, Size); - break; - case 8: - ldr(TMP4, TMP3, Size); - str(TMP4, TMP2, Size); - break; - case 32: - ldp(VTMP1.Q(), VTMP2.Q(), TMP3, Size); - stp(VTMP1.Q(), VTMP2.Q(), TMP2, Size); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); - break; + case 1: + ldrb(TMP4.W(), TMP3, Size); + strb(TMP4.W(), TMP2, Size); + break; + case 2: + ldrh(TMP4.W(), TMP3, Size); + strh(TMP4.W(), TMP2, Size); + break; + case 4: + ldr(TMP4.W(), TMP3, Size); + str(TMP4.W(), TMP2, Size); + break; + case 8: + ldr(TMP4, TMP3, Size); + str(TMP4, TMP2, Size); + break; + case 32: + ldp(VTMP1.Q(), VTMP2.Q(), TMP3, Size); + stp(VTMP1.Q(), VTMP2.Q(), TMP2, Size); + break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); break; } }; @@ -2085,81 +1719,46 @@ DEF_OP(MemCpy) { // 8bit load is always aligned to natural alignment ldaprb(TMP4.W(), TMP3); stlrb(TMP4.W(), TMP2); - } - else { + } else { nop(); switch (OpSize) { - case 2: - ldaprh(TMP4.W(), TMP3); - break; - case 4: - ldapr(TMP4.W(), TMP3); - break; - case 8: - ldapr(TMP4, TMP3); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); - break; + case 2: ldaprh(TMP4.W(), TMP3); break; + case 4: ldapr(TMP4.W(), TMP3); break; + case 8: ldapr(TMP4, TMP3); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); break; } nop(); nop(); switch (OpSize) { - case 2: - stlrh(TMP4.W(), TMP2); - break; - case 4: - stlr(TMP4.W(), TMP2); - break; - case 8: - stlr(TMP4, TMP2); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); - break; + case 2: stlrh(TMP4.W(), TMP2); break; + case 4: stlr(TMP4.W(), TMP2); break; + case 8: stlr(TMP4, TMP2); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); break; } nop(); } - } - else { + } else { if (OpSize == 1) { // 8bit load is always aligned to natural alignment ldarb(TMP4.W(), TMP3); stlrb(TMP4.W(), TMP2); - } - else { + } else { nop(); switch (OpSize) { - case 2: - ldarh(TMP4.W(), TMP3); - break; - case 4: - ldar(TMP4.W(), TMP3); - break; - case 8: - ldar(TMP4, TMP3); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); - break; + case 2: ldarh(TMP4.W(), TMP3); break; + case 4: ldar(TMP4.W(), TMP3); break; + case 8: ldar(TMP4, TMP3); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); break; } nop(); nop(); switch (OpSize) { - case 2: - stlrh(TMP4.W(), TMP2); - break; - case 4: - stlr(TMP4.W(), TMP2); - break; - case 8: - stlr(TMP4, TMP2); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); - break; + case 2: stlrh(TMP4.W(), TMP2); break; + case 4: stlr(TMP4.W(), TMP2); break; + case 8: stlr(TMP4, TMP2); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Size); break; } nop(); } @@ -2168,8 +1767,7 @@ DEF_OP(MemCpy) { if (Size >= 0) { add(ARMEmitter::Size::i64Bit, TMP2, TMP2, OpSize); add(ARMEmitter::Size::i64Bit, TMP3, TMP3, OpSize); - } - else { + } else { sub(ARMEmitter::Size::i64Bit, TMP2, TMP2, OpSize); sub(ARMEmitter::Size::i64Bit, TMP3, TMP3, OpSize); } @@ -2179,18 +1777,18 @@ DEF_OP(MemCpy) { const int32_t OpSize = Size; const int32_t SizeDirection = Size * Direction; - ARMEmitter::BiDirectionalLabel AgainInternal{}; - ARMEmitter::ForwardLabel DoneInternal{}; + ARMEmitter::BiDirectionalLabel AgainInternal {}; + ARMEmitter::ForwardLabel DoneInternal {}; // Early exit if zero count. cbz(ARMEmitter::Size::i64Bit, TMP1, &DoneInternal); if (!IsAtomic) { - ARMEmitter::ForwardLabel AbsPos{}; - ARMEmitter::ForwardLabel AgainInternal256Exit{}; - ARMEmitter::ForwardLabel AgainInternal128Exit{}; - ARMEmitter::BackwardLabel AgainInternal128{}; - ARMEmitter::BackwardLabel AgainInternal256{}; + ARMEmitter::ForwardLabel AbsPos {}; + ARMEmitter::ForwardLabel AgainInternal256Exit {}; + ARMEmitter::ForwardLabel AgainInternal128Exit {}; + ARMEmitter::BackwardLabel AgainInternal128 {}; + ARMEmitter::BackwardLabel AgainInternal256 {}; sub(ARMEmitter::Size::i64Bit, TMP4, TMP2, TMP3); tbz(TMP4, 63, &AbsPos); @@ -2243,8 +1841,7 @@ DEF_OP(MemCpy) { Bind(&AgainInternal); if (IsAtomic) { MemCpyTSO(OpSize, SizeDirection); - } - else { + } else { MemCpy(OpSize, SizeDirection); } sub(ARMEmitter::Size::i64Bit, TMP1, TMP1, 1); @@ -2259,48 +1856,43 @@ DEF_OP(MemCpy) { if (SizeDirection >= 0) { switch (OpSize) { - case 1: - add(Dst.first.X(), TMP1, TMP3); - add(Dst.second.X(), TMP2, TMP3); - break; - case 2: - add(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 1); - add(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 1); - break; - case 4: - add(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 2); - add(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 2); - break; - case 8: - add(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 3); - add(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 3); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); - break; + case 1: + add(Dst.first.X(), TMP1, TMP3); + add(Dst.second.X(), TMP2, TMP3); + break; + case 2: + add(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 1); + add(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 1); + break; + case 4: + add(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 2); + add(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 2); + break; + case 8: + add(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 3); + add(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 3); + break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); break; } - } - else { + } else { switch (OpSize) { - case 1: - sub(Dst.first.X(), TMP1, TMP3); - sub(Dst.second.X(), TMP2, TMP3); - break; - case 2: - sub(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 1); - sub(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 1); - break; - case 4: - sub(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 2); - sub(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 2); - break; - case 8: - sub(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 3); - sub(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 3); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); - break; + case 1: + sub(Dst.first.X(), TMP1, TMP3); + sub(Dst.second.X(), TMP2, TMP3); + break; + case 2: + sub(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 1); + sub(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 1); + break; + case 4: + sub(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 2); + sub(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 2); + break; + case 8: + sub(Dst.first.X(), TMP1, TMP3, ARMEmitter::ShiftType::LSL, 3); + sub(Dst.second.X(), TMP2, TMP3, ARMEmitter::ShiftType::LSL, 3); + break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); break; } } }; @@ -2308,10 +1900,9 @@ DEF_OP(MemCpy) { if (DirectionIsInline) { LOGMAN_THROW_AA_FMT(DirectionConstant == 1 || DirectionConstant == -1, "unexpected direction"); EmitMemcpy(DirectionConstant); - } - else { + } else { // Emit forward direction memset then backward direction memset. - for (int32_t Direction : { 1, -1 }) { + for (int32_t Direction : {1, -1}) { EmitMemcpy(Direction); if (Direction == 1) { b(&Done); @@ -2340,100 +1931,67 @@ DEF_OP(ParanoidLoadMemTSO) { // 8bit load is always aligned to natural alignment const auto Dst = GetReg(Node); ldapurb(Dst, MemReg, Offset); - } - else { + } else { switch (OpSize) { - case 2: - ldapurh(Dst, MemReg, Offset); - break; - case 4: - ldapur(Dst.W(), MemReg, Offset); - break; - case 8: - ldapur(Dst.X(), MemReg, Offset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); - break; + case 2: ldapurh(Dst, MemReg, Offset); break; + case 4: ldapur(Dst.W(), MemReg, Offset); break; + case 8: ldapur(Dst.X(), MemReg, Offset); break; + default: LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); break; } } - } - else if (CTX->HostFeatures.SupportsRCPC && Op->Class == FEXCore::IR::GPRClass) { + } else if (CTX->HostFeatures.SupportsRCPC && Op->Class == FEXCore::IR::GPRClass) { const auto Dst = GetReg(Node); if (OpSize == 1) { // 8bit load is always aligned to natural alignment ldaprb(Dst.W(), MemReg); - } - else { + } else { switch (OpSize) { - case 2: - ldaprh(Dst.W(), MemReg); - break; - case 4: - ldapr(Dst.W(), MemReg); - break; - case 8: - ldapr(Dst.X(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); - break; + case 2: ldaprh(Dst.W(), MemReg); break; + case 4: ldapr(Dst.W(), MemReg); break; + case 8: ldapr(Dst.X(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); break; } } - } - else if (Op->Class == FEXCore::IR::GPRClass) { + } else if (Op->Class == FEXCore::IR::GPRClass) { const auto Dst = GetReg(Node); switch (OpSize) { - case 1: - ldarb(Dst, MemReg); - break; - case 2: - ldarh(Dst, MemReg); - break; - case 4: - ldar(Dst.W(), MemReg); - break; - case 8: - ldar(Dst.X(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); - break; + case 1: ldarb(Dst, MemReg); break; + case 2: ldarh(Dst, MemReg); break; + case 4: ldar(Dst.W(), MemReg); break; + case 8: ldar(Dst.X(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); break; } - } - else { + } else { const auto Dst = GetVReg(Node); switch (OpSize) { - case 1: - ldarb(TMP1, MemReg); - fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1.W()); - break; - case 2: - ldarh(TMP1, MemReg); - fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1.W()); - break; - case 4: - ldar(TMP1.W(), MemReg); - fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1.W()); - break; - case 8: - ldar(TMP1, MemReg); - fmov(ARMEmitter::Size::i64Bit, Dst.D(), TMP1); - break; - case 16: - ldaxp(ARMEmitter::Size::i64Bit, TMP1, TMP2, MemReg); - clrex(); - ins(ARMEmitter::SubRegSize::i64Bit, Dst, 0, TMP1); - ins(ARMEmitter::SubRegSize::i64Bit, Dst, 1, TMP2); - break; - case 32: - dmb(FEXCore::ARMEmitter::BarrierScope::ISH); - ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), MemReg); - dmb(FEXCore::ARMEmitter::BarrierScope::ISH); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); - break; + case 1: + ldarb(TMP1, MemReg); + fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1.W()); + break; + case 2: + ldarh(TMP1, MemReg); + fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1.W()); + break; + case 4: + ldar(TMP1.W(), MemReg); + fmov(ARMEmitter::Size::i32Bit, Dst.S(), TMP1.W()); + break; + case 8: + ldar(TMP1, MemReg); + fmov(ARMEmitter::Size::i64Bit, Dst.D(), TMP1); + break; + case 16: + ldaxp(ARMEmitter::Size::i64Bit, TMP1, TMP2, MemReg); + clrex(); + ins(ARMEmitter::SubRegSize::i64Bit, Dst, 0, TMP1); + ins(ARMEmitter::SubRegSize::i64Bit, Dst, 1, TMP2); + break; + case 32: + dmb(FEXCore::ARMEmitter::BarrierScope::ISH); + ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), MemReg); + dmb(FEXCore::ARMEmitter::BarrierScope::ISH); + break; + default: LOGMAN_MSG_A_FMT("Unhandled ParanoidLoadMemTSO size: {}", OpSize); break; } } } @@ -2454,86 +2012,63 @@ DEF_OP(ParanoidStoreMemTSO) { if (OpSize == 1) { // 8bit load is always aligned to natural alignment stlurb(Src, MemReg, Offset); - } - else { + } else { switch (OpSize) { - case 2: - stlurh(Src, MemReg, Offset); - break; - case 4: - stlur(Src.W(), MemReg, Offset); - break; - case 8: - stlur(Src.X(), MemReg, Offset); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled ParanoidStoreMemTSO size: {}", OpSize); - break; + case 2: stlurh(Src, MemReg, Offset); break; + case 4: stlur(Src.W(), MemReg, Offset); break; + case 8: stlur(Src.X(), MemReg, Offset); break; + default: LOGMAN_MSG_A_FMT("Unhandled ParanoidStoreMemTSO size: {}", OpSize); break; } } - } - else if (Op->Class == FEXCore::IR::GPRClass) { + } else if (Op->Class == FEXCore::IR::GPRClass) { const auto Src = GetReg(Op->Value.ID()); switch (OpSize) { - case 1: - stlrb(Src, MemReg); - break; - case 2: - stlrh(Src, MemReg); - break; - case 4: - stlr(Src.W(), MemReg); - break; - case 8: - stlr(Src.X(), MemReg); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled ParanoidStoreMemTSO size: {}", OpSize); - break; + case 1: stlrb(Src, MemReg); break; + case 2: stlrh(Src, MemReg); break; + case 4: stlr(Src.W(), MemReg); break; + case 8: stlr(Src.X(), MemReg); break; + default: LOGMAN_MSG_A_FMT("Unhandled ParanoidStoreMemTSO size: {}", OpSize); break; } - } - else { + } else { const auto Src = GetVReg(Op->Value.ID()); switch (OpSize) { - case 1: - umov(TMP1, Src, 0); - stlrb(TMP1, MemReg); - break; - case 2: - umov(TMP1, Src, 0); - stlrh(TMP1, MemReg); - break; - case 4: - umov(TMP1, Src, 0); - stlr(TMP1.W(), MemReg); - break; - case 8: - umov(TMP1, Src, 0); - stlr(TMP1, MemReg); - break; - case 16: { - // Move vector to GPRs - umov(TMP1, Src, 0); - umov(TMP2, Src, 1); - ARMEmitter::BackwardLabel B; - Bind(&B); + case 1: + umov(TMP1, Src, 0); + stlrb(TMP1, MemReg); + break; + case 2: + umov(TMP1, Src, 0); + stlrh(TMP1, MemReg); + break; + case 4: + umov(TMP1, Src, 0); + stlr(TMP1.W(), MemReg); + break; + case 8: + umov(TMP1, Src, 0); + stlr(TMP1, MemReg); + break; + case 16: { + // Move vector to GPRs + umov(TMP1, Src, 0); + umov(TMP2, Src, 1); + ARMEmitter::BackwardLabel B; + Bind(&B); - // ldaxp must not have both the destination registers be the same - ldaxp(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::zr, TMP3, MemReg); // <- Can hit SIGBUS. Overwritten with DMB - stlxp(ARMEmitter::Size::i64Bit, TMP3, TMP1, TMP2, MemReg); // <- Can also hit SIGBUS - cbnz(ARMEmitter::Size::i64Bit, TMP3, &B); // < Overwritten with DMB - break; - } - case 32: { - dmb(FEXCore::ARMEmitter::BarrierScope::ISH); - st1b(Src.Z(), PRED_TMP_32B, MemReg, 0); - dmb(FEXCore::ARMEmitter::BarrierScope::ISH); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled ParanoidStoreMemTSO size: {}", OpSize); - break; + // ldaxp must not have both the destination registers be the same + ldaxp(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::zr, TMP3, MemReg); // <- Can hit SIGBUS. Overwritten with DMB + stlxp(ARMEmitter::Size::i64Bit, TMP3, TMP1, TMP2, MemReg); // <- Can also hit SIGBUS + cbnz(ARMEmitter::Size::i64Bit, TMP3, &B); // < Overwritten with DMB + break; + } + case 32: { + dmb(FEXCore::ARMEmitter::BarrierScope::ISH); + st1b(Src.Z(), PRED_TMP_32B, MemReg, 0); + dmb(FEXCore::ARMEmitter::BarrierScope::ISH); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled ParanoidStoreMemTSO size: {}", OpSize); break; } } } @@ -2547,8 +2082,7 @@ DEF_OP(CacheLineClear) { // icache doesn't matter here since the guest application shouldn't be calling clflush on JIT code. if (CTX->HostFeatures.DCacheLineSize >= 64U) { dc(ARMEmitter::DataCacheOperation::CIVAC, MemReg); - } - else { + } else { auto CurrentWorkingReg = MemReg.X(); for (size_t i = 0; i < std::max(1U, CTX->HostFeatures.DCacheLineSize / 64U); ++i) { dc(ARMEmitter::DataCacheOperation::CIVAC, TMP1); @@ -2571,8 +2105,7 @@ DEF_OP(CacheLineClean) { // Clean dcache only if (CTX->HostFeatures.DCacheLineSize >= 64U) { dc(ARMEmitter::DataCacheOperation::CVAC, MemReg); - } - else { + } else { auto CurrentWorkingReg = MemReg.X(); for (size_t i = 0; i < std::max(1U, CTX->HostFeatures.DCacheLineSize / 64U); ++i) { dc(ARMEmitter::DataCacheOperation::CVAC, TMP1); @@ -2590,8 +2123,7 @@ DEF_OP(CacheLineZero) { if (CTX->HostFeatures.SupportsCLZERO) { // We can use this instruction directly dc(ARMEmitter::DataCacheOperation::ZVA, MemReg); - } - else { + } else { // We must walk the cacheline ourselves // Force cacheline alignment and_(ARMEmitter::Size::i64Bit, TMP1, MemReg, ~(CPUIDEmu::CACHELINE_SIZE - 1)); @@ -2611,10 +2143,7 @@ DEF_OP(Prefetch) { // Access size is only ever handled as 8-byte. Even though it is accesssed as a cacheline. const auto MemSrc = GenerateMemOperand(8, MemReg, Op->Offset, Op->OffsetType, Op->OffsetScale); - size_t LUT = - (Op->Stream ? 1 : 0) | - ((Op->CacheLevel - 1) << 1) | - (Op->ForStore ? 1U << 3 : 0); + size_t LUT = (Op->Stream ? 1 : 0) | ((Op->CacheLevel - 1) << 1) | (Op->ForStore ? 1U << 3 : 0); constexpr static std::array PrefetchType = { ARMEmitter::Prefetch::PLDL1KEEP, @@ -2646,5 +2175,4 @@ DEF_OP(Prefetch) { } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp index 099134979..137258dc6 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/MiscOps.cpp @@ -17,7 +17,7 @@ $end_info$ #include namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(GuestOpcode) { auto Op = IROp->C(); @@ -28,16 +28,10 @@ DEF_OP(GuestOpcode) { DEF_OP(Fence) { auto Op = IROp->C(); switch (Op->Fence) { - case IR::Fence_Load.Val: - dmb(FEXCore::ARMEmitter::BarrierScope::LD); - break; - case IR::Fence_LoadStore.Val: - dmb(FEXCore::ARMEmitter::BarrierScope::SY); - break; - case IR::Fence_Store.Val: - dmb(FEXCore::ARMEmitter::BarrierScope::ST); - break; - default: LOGMAN_MSG_A_FMT("Unknown Fence: {}", Op->Fence); break; + case IR::Fence_Load.Val: dmb(FEXCore::ARMEmitter::BarrierScope::LD); break; + case IR::Fence_LoadStore.Val: dmb(FEXCore::ARMEmitter::BarrierScope::SY); break; + case IR::Fence_Store.Val: dmb(FEXCore::ARMEmitter::BarrierScope::ST); break; + default: LOGMAN_MSG_A_FMT("Unknown Fence: {}", Op->Fence); break; } } @@ -55,7 +49,7 @@ DEF_OP(Break) { .err_code = Op->Reason.ErrorRegister, }; - uint64_t Constant{}; + uint64_t Constant {}; memcpy(&Constant, &State, sizeof(State)); LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r1, Constant); @@ -136,8 +130,7 @@ DEF_OP(Print) { if (IsGPR(Op->Value.ID())) { mov(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r0, GetReg(Op->Value.ID())); ldr(ARMEmitter::XReg::x3, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.Common.PrintValue)); - } - else { + } else { fmov(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r0, GetVReg(Op->Value.ID()), false); fmov(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r1, GetVReg(Op->Value.ID()), true); ldr(ARMEmitter::XReg::x3, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.Common.PrintVectorValue)); @@ -146,12 +139,10 @@ DEF_OP(Print) { if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] { if (IsGPR(Op->Value.ID())) { GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); - } - else { + } else { GenerateIndirectRuntimeCall(ARMEmitter::Reg::r3); } - } - else { + } else { blr(ARMEmitter::Reg::r3); } @@ -231,8 +222,7 @@ DEF_OP(RDRAND) { if (Op->GetReseeded) { mrs(Dst.first, ARMEmitter::SystemRegister::RNDRRS); - } - else { + } else { mrs(Dst.first, ARMEmitter::SystemRegister::RNDR); } @@ -245,5 +235,4 @@ DEF_OP(Yield) { } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/MoveOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/MoveOps.cpp index 118be0ce0..001bf8869 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/MoveOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/MoveOps.cpp @@ -8,7 +8,7 @@ $end_info$ #include "Interface/Core/JIT/Arm64/JITClass.h" namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) DEF_OP(ExtractElementPair) { auto Op = IROp->C(); LOGMAN_THROW_AA_FMT(Op->Header.Size == 4 || Op->Header.Size == 8, "Invalid size"); @@ -43,5 +43,4 @@ DEF_OP(CreateElementPair) { } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp index b8f815247..ffd2a985e 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp @@ -13,9 +13,10 @@ $end_info$ #include namespace FEXCore::CPU { -#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const *IROp, IR::NodeID Node) +#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node) -void Arm64JITCore::VFScalarOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarBinaryOpCaller ScalarEmit, ARMEmitter::VRegister Dst, ARMEmitter::VRegister Vector1, ARMEmitter::VRegister Vector2) { +void Arm64JITCore::VFScalarOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarBinaryOpCaller ScalarEmit, + ARMEmitter::VRegister Dst, ARMEmitter::VRegister Vector1, ARMEmitter::VRegister Vector2) { const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE; if (!Is256Bit) { LOGMAN_THROW_A_FMT(ZeroUpperBits == false, "128-bit operation doesn't support ZeroUpperBits in {}", __func__); @@ -25,10 +26,9 @@ void Arm64JITCore::VFScalarOperation(uint8_t OpSize, uint8_t ElementSize, bool Z // The upper bits of the destination comes from the first source. LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); constexpr auto Predicate = ARMEmitter::PReg::p0; @@ -41,65 +41,58 @@ void Arm64JITCore::VFScalarOperation(uint8_t OpSize, uint8_t ElementSize, bool Z if (HostSupportsAFP) { // If the host CPU supports AFP then scalar does an insert without modifying upper bits. ScalarEmit(Dst, Vector1, Vector2); - } - else { + } else { // If AFP is unsupported then the operation result goes in to a temporary. // and then it gets inserted. ScalarEmit(VTMP1, Vector1, Vector2); if (!ZeroUpperBits && Is256Bit) { ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } - } - else if (Dst != Vector2) { + } else if (Dst != Vector2) { if (!ZeroUpperBits && Is256Bit) { mov(Dst.Z(), Vector1.Z()); - } - else { + } else { mov(Dst.Q(), Vector1.Q()); } if (HostSupportsAFP) { ScalarEmit(Dst, Vector1, Vector2); - } - else { + } else { ScalarEmit(VTMP1, Vector1, Vector2); if (!ZeroUpperBits && Is256Bit) { ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } - } - else { + } else { // Destination intersects Vector2, can't do anything optimal in this case. // Do the scalar operation first and then move and insert. ScalarEmit(VTMP1, Vector1, Vector2); if (!ZeroUpperBits && Is256Bit) { mov(Dst.Z(), Vector1.Z()); - } - else { + } else { mov(Dst.Q(), Vector1.Q()); } if (!ZeroUpperBits && Is256Bit) { ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } } -void Arm64JITCore::VFScalarUnaryOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarUnaryOpCaller ScalarEmit, ARMEmitter::VRegister Dst, ARMEmitter::VRegister Vector1, std::variant Vector2) { +void Arm64JITCore::VFScalarUnaryOperation(uint8_t OpSize, uint8_t ElementSize, bool ZeroUpperBits, ScalarUnaryOpCaller ScalarEmit, + ARMEmitter::VRegister Dst, ARMEmitter::VRegister Vector1, + std::variant Vector2) { const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE; if (!Is256Bit) { LOGMAN_THROW_A_FMT(ZeroUpperBits == false, "128-bit operation doesn't support ZeroUpperBits in {}", __func__); @@ -109,10 +102,9 @@ void Arm64JITCore::VFScalarUnaryOperation(uint8_t OpSize, uint8_t ElementSize, b // The upper bits of the destination comes from the first source. LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); constexpr auto Predicate = ARMEmitter::PReg::p0; bool DstOverlapsVector2 = false; @@ -129,59 +121,50 @@ void Arm64JITCore::VFScalarUnaryOperation(uint8_t OpSize, uint8_t ElementSize, b if (HostSupportsAFP) { // If the host CPU supports AFP then scalar does an insert without modifying upper bits. ScalarEmit(Dst, Vector2); - } - else { + } else { // If AFP is unsupported then the operation result goes in to a temporary. // and then it gets inserted. ScalarEmit(VTMP1, Vector2); if (!ZeroUpperBits && Is256Bit) { ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } - } - else if (!DstOverlapsVector2) { + } else if (!DstOverlapsVector2) { if (!ZeroUpperBits && Is256Bit) { mov(Dst.Z(), Vector1.Z()); - } - else { + } else { mov(Dst.Q(), Vector1.Q()); } if (HostSupportsAFP) { ScalarEmit(Dst, Vector2); - } - else { + } else { ScalarEmit(VTMP1, Vector2); if (!ZeroUpperBits && Is256Bit) { ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } - } - else { + } else { // Destination intersects Vector2, can't do anything optimal in this case. // Do the scalar operation first and then move and insert. ScalarEmit(VTMP1, Vector2); if (!ZeroUpperBits && Is256Bit) { mov(Dst.Z(), Vector1.Z()); - } - else { + } else { mov(Dst.Q(), Vector1.Q()); } if (!ZeroUpperBits && Is256Bit) { ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } @@ -192,10 +175,9 @@ DEF_OP(VFAddScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { fadd(SubRegSize.Scalar, Dst, Src1, Src2); @@ -215,10 +197,9 @@ DEF_OP(VFSubScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { fsub(SubRegSize.Scalar, Dst, Src1, Src2); @@ -238,10 +219,9 @@ DEF_OP(VFMulScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { fmul(SubRegSize.Scalar, Dst, Src1, Src2); @@ -261,10 +241,9 @@ DEF_OP(VFDivScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { fdiv(SubRegSize.Scalar, Dst, Src1, Src2); @@ -284,17 +263,15 @@ DEF_OP(VFMinScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { if (HostSupportsAFP) { // AFP.AH lets fmin behave like x86 min fmin(SubRegSize.Scalar, Dst, Src1, Src2); - } - else { + } else { fcmp(SubRegSize.Scalar, Src1, Src2); fcsel(SubRegSize.Scalar, Dst, Src1, Src2, ARMEmitter::Condition::CC_MI); } @@ -314,18 +291,16 @@ DEF_OP(VFMaxScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); // AFP can make this more optimal. auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { if (HostSupportsAFP) { // AFP.AH lets fmax behave like x86 max fmax(SubRegSize.Scalar, Dst, Src1, Src2); - } - else { + } else { fcmp(SubRegSize.Scalar, Src1, Src2); fcsel(SubRegSize.Scalar, Dst, Src2, Src1, ARMEmitter::Condition::CC_MI); } @@ -345,10 +320,9 @@ DEF_OP(VFSqrtScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, std::variant SrcVar) { auto Src = *std::get_if(&SrcVar); @@ -369,10 +343,9 @@ DEF_OP(VFRSqrtScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, std::variant SrcVar) { auto Src = *std::get_if(&SrcVar); @@ -407,10 +380,9 @@ DEF_OP(VFRecpScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); auto ScalarEmit = [this, SubRegSize](ARMEmitter::VRegister Dst, std::variant SrcVar) { auto Src = *std::get_if(&SrcVar); @@ -448,31 +420,31 @@ DEF_OP(VFToFScalarInsert) { auto Src = *std::get_if(&SrcVar); switch (Conv) { - case 0x0204: { // Half <- Float - fcvt(Dst.H(), Src.S()); - break; - } - case 0x0208: { // Half <- Double - fcvt(Dst.H(), Src.D()); - break; - } - case 0x0402: { // Float <- Half - fcvt(Dst.S(), Src.H()); - break; - } - case 0x0802: { // Double <- Half - fcvt(Dst.D(), Src.H()); - break; - } - case 0x0804: { // Double <- Float - fcvt(Dst.D(), Src.S()); - break; - } - case 0x0408: { // Float <- Double - fcvt(Dst.S(), Src.D()); - break; - } - default: LOGMAN_MSG_A_FMT("Unknown FCVT sizes: 0x{:x}", Conv); + case 0x0204: { // Half <- Float + fcvt(Dst.H(), Src.S()); + break; + } + case 0x0208: { // Half <- Double + fcvt(Dst.H(), Src.D()); + break; + } + case 0x0402: { // Float <- Half + fcvt(Dst.S(), Src.H()); + break; + } + case 0x0802: { // Double <- Half + fcvt(Dst.D(), Src.H()); + break; + } + case 0x0804: { // Double <- Float + fcvt(Dst.D(), Src.S()); + break; + } + case 0x0408: { // Float <- Double + fcvt(Dst.S(), Src.D()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown FCVT sizes: 0x{:x}", Conv); } }; @@ -500,12 +472,10 @@ DEF_OP(VSToFVectorInsert) { if (ElementSize == 4) { if (HasTwoElements) { scvtf(ARMEmitter::SubRegSize::i32Bit, Dst.D(), Src.D()); - } - else { + } else { scvtf(ARMEmitter::ScalarRegSize::i32Bit, Dst.S(), Src.S()); } - } - else { + } else { scvtf(ARMEmitter::ScalarRegSize::i64Bit, Dst.D(), Src.D()); } }; @@ -532,34 +502,31 @@ DEF_OP(VSToFGPRInsert) { auto Src = *std::get_if(&SrcVar); switch (Conv) { - case 0x0204: { // Half <- int32_t - scvtf(ARMEmitter::Size::i32Bit, Dst.H(), Src); - break; - } - case 0x0208: { // Half <- int64_t - scvtf(ARMEmitter::Size::i64Bit, Dst.H(), Src); - break; - } - case 0x0404: { // Float <- int32_t - scvtf(ARMEmitter::Size::i32Bit, Dst.S(), Src); - break; - } - case 0x0408: { // Float <- int64_t - scvtf(ARMEmitter::Size::i64Bit, Dst.S(), Src); - break; - } - case 0x0804: { // Double <- int32_t - scvtf(ARMEmitter::Size::i32Bit, Dst.D(), Src); - break; - } - case 0x0808: { // Double <- int64_t - scvtf(ARMEmitter::Size::i64Bit, Dst.D(), Src); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled conversion mask: Mask=0x{:04x}", - Conv); - break; + case 0x0204: { // Half <- int32_t + scvtf(ARMEmitter::Size::i32Bit, Dst.H(), Src); + break; + } + case 0x0208: { // Half <- int64_t + scvtf(ARMEmitter::Size::i64Bit, Dst.H(), Src); + break; + } + case 0x0404: { // Float <- int32_t + scvtf(ARMEmitter::Size::i32Bit, Dst.S(), Src); + break; + } + case 0x0408: { // Float <- int64_t + scvtf(ARMEmitter::Size::i64Bit, Dst.S(), Src); + break; + } + case 0x0804: { // Double <- int32_t + scvtf(ARMEmitter::Size::i32Bit, Dst.D(), Src); + break; + } + case 0x0808: { // Double <- int64_t + scvtf(ARMEmitter::Size::i64Bit, Dst.D(), Src); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled conversion mask: Mask=0x{:04x}", Conv); break; } }; @@ -578,10 +545,9 @@ DEF_OP(VFToIScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); const auto RoundMode = Op->Round; @@ -589,21 +555,11 @@ DEF_OP(VFToIScalarInsert) { auto Src = *std::get_if(&SrcVar); switch (RoundMode) { - case IR::Round_Nearest: - frintn(SubRegSize.Scalar, Dst, Src); - break; - case IR::Round_Negative_Infinity: - frintm(SubRegSize.Scalar, Dst, Src); - break; - case IR::Round_Positive_Infinity: - frintp(SubRegSize.Scalar, Dst, Src); - break; - case IR::Round_Towards_Zero: - frintz(SubRegSize.Scalar, Dst, Src); - break; - case IR::Round_Host: - frinti(SubRegSize.Scalar, Dst, Src); - break; + case IR::Round_Nearest: frintn(SubRegSize.Scalar, Dst, Src); break; + case IR::Round_Negative_Infinity: frintm(SubRegSize.Scalar, Dst, Src); break; + case IR::Round_Positive_Infinity: frintp(SubRegSize.Scalar, Dst, Src); break; + case IR::Round_Towards_Zero: frintz(SubRegSize.Scalar, Dst, Src); break; + case IR::Round_Host: frinti(SubRegSize.Scalar, Dst, Src); break; } }; @@ -621,70 +577,60 @@ DEF_OP(VFCMPScalarInsert) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); const auto ZeroUpperBits = Op->ZeroUpperBits; const auto Is256Bit = IROp->Size == Core::CPUState::XMM_AVX_REG_SIZE; auto ScalarEmitEQ = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { switch (SubRegSize.Scalar) { - case ARMEmitter::ScalarRegSize::i16Bit: { - fcmeq(Dst.H(), Src1.H(), Src2.H()); - break; - } - case ARMEmitter::ScalarRegSize::i32Bit: - case ARMEmitter::ScalarRegSize::i64Bit: - fcmeq(SubRegSize.Scalar, Dst, Src1, Src2); - break; - default: - break; + case ARMEmitter::ScalarRegSize::i16Bit: { + fcmeq(Dst.H(), Src1.H(), Src2.H()); + break; + } + case ARMEmitter::ScalarRegSize::i32Bit: + case ARMEmitter::ScalarRegSize::i64Bit: fcmeq(SubRegSize.Scalar, Dst, Src1, Src2); break; + default: break; } }; auto ScalarEmitLT = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { switch (SubRegSize.Scalar) { - case ARMEmitter::ScalarRegSize::i16Bit: { - fcmgt(Dst.H(), Src2.H(), Src1.H()); - break; - } - case ARMEmitter::ScalarRegSize::i32Bit: - case ARMEmitter::ScalarRegSize::i64Bit: - fcmgt(SubRegSize.Scalar, Dst, Src2, Src1); - break; - default: - break; + case ARMEmitter::ScalarRegSize::i16Bit: { + fcmgt(Dst.H(), Src2.H(), Src1.H()); + break; + } + case ARMEmitter::ScalarRegSize::i32Bit: + case ARMEmitter::ScalarRegSize::i64Bit: fcmgt(SubRegSize.Scalar, Dst, Src2, Src1); break; + default: break; } }; auto ScalarEmitLE = [this, SubRegSize](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { switch (SubRegSize.Scalar) { - case ARMEmitter::ScalarRegSize::i16Bit: { - fcmge(Dst.H(), Src2.H(), Src1.H()); - break; - } - case ARMEmitter::ScalarRegSize::i32Bit: - case ARMEmitter::ScalarRegSize::i64Bit: - fcmge(SubRegSize.Scalar, Dst, Src2, Src1); - break; - default: - break; + case ARMEmitter::ScalarRegSize::i16Bit: { + fcmge(Dst.H(), Src2.H(), Src1.H()); + break; + } + case ARMEmitter::ScalarRegSize::i32Bit: + case ARMEmitter::ScalarRegSize::i64Bit: fcmge(SubRegSize.Scalar, Dst, Src2, Src1); break; + default: break; } }; - auto ScalarEmitUNO = [this, SubRegSize, ZeroUpperBits, Is256Bit](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { + auto ScalarEmitUNO = + [this, SubRegSize, ZeroUpperBits, Is256Bit](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { switch (SubRegSize.Scalar) { - case ARMEmitter::ScalarRegSize::i16Bit: { - fcmge(VTMP1.H(), Src1.H(), Src2.H()); - fcmgt(VTMP2.H(), Src2.H(), Src1.H()); - break; - } - case ARMEmitter::ScalarRegSize::i32Bit: - case ARMEmitter::ScalarRegSize::i64Bit: - fcmge(SubRegSize.Scalar, VTMP1, Src1, Src2); - fcmgt(SubRegSize.Scalar, VTMP2, Src2, Src1); - break; - default: - break; + case ARMEmitter::ScalarRegSize::i16Bit: { + fcmge(VTMP1.H(), Src1.H(), Src2.H()); + fcmgt(VTMP2.H(), Src2.H(), Src1.H()); + break; + } + case ARMEmitter::ScalarRegSize::i32Bit: + case ARMEmitter::ScalarRegSize::i64Bit: + fcmge(SubRegSize.Scalar, VTMP1, Src1, Src2); + fcmgt(SubRegSize.Scalar, VTMP2, Src2, Src1); + break; + default: break; } // If the destination is a temporary then it is going to do an insert after the operation. // This means this operation can avoid a redundant insert in this case. @@ -701,24 +647,21 @@ DEF_OP(VFCMPScalarInsert) { constexpr auto Predicate = ARMEmitter::PReg::p0; ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } }; - auto ScalarEmitNEQ = [this, SubRegSize, ZeroUpperBits, Is256Bit](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { + auto ScalarEmitNEQ = + [this, SubRegSize, ZeroUpperBits, Is256Bit](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { switch (SubRegSize.Scalar) { - case ARMEmitter::ScalarRegSize::i16Bit: { - fcmeq(VTMP1.H(), Src1.H(), Src2.H()); - break; - } - case ARMEmitter::ScalarRegSize::i32Bit: - case ARMEmitter::ScalarRegSize::i64Bit: - fcmeq(SubRegSize.Scalar, VTMP1, Src1, Src2); - break; - default: - break; + case ARMEmitter::ScalarRegSize::i16Bit: { + fcmeq(VTMP1.H(), Src1.H(), Src2.H()); + break; + } + case ARMEmitter::ScalarRegSize::i32Bit: + case ARMEmitter::ScalarRegSize::i64Bit: fcmeq(SubRegSize.Scalar, VTMP1, Src1, Src2); break; + default: break; } // If the destination is a temporary then it is going to do an insert after the operation. // This means this operation can avoid a redundant insert in this case. @@ -734,26 +677,25 @@ DEF_OP(VFCMPScalarInsert) { constexpr auto Predicate = ARMEmitter::PReg::p0; ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } }; - auto ScalarEmitORD = [this, SubRegSize, ZeroUpperBits, Is256Bit](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { + auto ScalarEmitORD = + [this, SubRegSize, ZeroUpperBits, Is256Bit](ARMEmitter::VRegister Dst, ARMEmitter::VRegister Src1, ARMEmitter::VRegister Src2) { switch (SubRegSize.Scalar) { - case ARMEmitter::ScalarRegSize::i16Bit: { - fcmge(VTMP1.H(), Src1.H(), Src2.H()); - fcmgt(VTMP2.H(), Src2.H(), Src1.H()); - break; - } - case ARMEmitter::ScalarRegSize::i32Bit: - case ARMEmitter::ScalarRegSize::i64Bit: - fcmge(SubRegSize.Scalar, VTMP1, Src1, Src2); - fcmgt(SubRegSize.Scalar, VTMP2, Src2, Src1); - break; - default: - break; + case ARMEmitter::ScalarRegSize::i16Bit: { + fcmge(VTMP1.H(), Src1.H(), Src2.H()); + fcmgt(VTMP2.H(), Src2.H(), Src1.H()); + break; + } + case ARMEmitter::ScalarRegSize::i32Bit: + case ARMEmitter::ScalarRegSize::i64Bit: + fcmge(SubRegSize.Scalar, VTMP1, Src1, Src2); + fcmgt(SubRegSize.Scalar, VTMP2, Src2, Src1); + break; + default: break; } // If the destination is a temporary then it is going to do an insert after the operation. // This means this operation can avoid a redundant insert in this case. @@ -769,8 +711,7 @@ DEF_OP(VFCMPScalarInsert) { constexpr auto Predicate = ARMEmitter::PReg::p0; ptrue(SubRegSize.Vector, Predicate, ARMEmitter::PredicatePattern::SVE_VL1); mov(SubRegSize.Vector, Dst.Z(), Predicate.Merging(), VTMP1.Z()); - } - else { + } else { ins(SubRegSize.Vector, Dst.Q(), 0, VTMP1.Q(), 0); } } @@ -802,11 +743,11 @@ DEF_OP(VectorImm) { const auto ElementSize = Op->Header.ElementSize; LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; const auto Dst = GetVReg(Node); @@ -816,8 +757,7 @@ DEF_OP(VectorImm) { // SVE dup uses sign extension where VectorImm wants zext LoadConstant(ARMEmitter::Size::i64Bit, TMP1, Op->Immediate); dup(SubRegSize, Dst.Z(), TMP1); - } - else { + } else { dup_imm(SubRegSize, Dst.Z(), static_cast(Op->Immediate)); } } else { @@ -825,8 +765,7 @@ DEF_OP(VectorImm) { // movi with 64bit element size doesn't do what we want here LoadConstant(ARMEmitter::Size::i64Bit, TMP1, static_cast(Op->Immediate) << Op->ShiftAmount); dup(SubRegSize, Dst.Q(), TMP1.R()); - } - else { + } else { movi(SubRegSize, Dst.Q(), Op->Immediate, Op->ShiftAmount); } } @@ -838,22 +777,18 @@ DEF_OP(LoadNamedVectorConstant) { const auto Dst = GetVReg(Node); switch (Op->Constant) { - case FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO: - movi(ARMEmitter::SubRegSize::i64Bit, Dst.Q(), 0); - return; - default: - // Intentionally doing nothing. - break; + case FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO: movi(ARMEmitter::SubRegSize::i64Bit, Dst.Q(), 0); return; + default: + // Intentionally doing nothing. + break; } if (HostSupportsSVE128) { switch (Op->Constant) { - case FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_MOVMSKPS_SHIFT: - index(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), 0, 1); - return; - default: - // Intentionally doing nothing. - break; + case FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_MOVMSKPS_SHIFT: index(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), 0, 1); return; + default: + // Intentionally doing nothing. + break; } } // Load the pointer. @@ -878,24 +813,12 @@ DEF_OP(LoadNamedVectorConstant) { auto MemOperand = GenerateMemOperand(OpSize, Op->Constant, STATE); switch (OpSize) { - case 1: - ldrb(Dst, MemOperand); - break; - case 2: - ldrh(Dst, MemOperand); - break; - case 4: - ldr(Dst.S(), MemOperand); - break; - case 8: - ldr(Dst.D(), MemOperand); - break; - case 16: - ldr(Dst.Q(), MemOperand); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); - break; + case 1: ldrb(Dst, MemOperand); break; + case 2: ldrh(Dst, MemOperand); break; + case 4: ldr(Dst.S(), MemOperand); break; + case 8: ldr(Dst.D(), MemOperand); break; + case 16: ldr(Dst.Q(), MemOperand); break; + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); break; } } DEF_OP(LoadNamedVectorIndexedConstant) { @@ -908,29 +831,17 @@ DEF_OP(LoadNamedVectorIndexedConstant) { ldr(TMP1, STATE_PTR(CpuStateFrame, Pointers.Common.IndexedNamedVectorConstantPointers[Op->Constant])); switch (OpSize) { - case 1: - ldrb(Dst, TMP1, Op->Index); - break; - case 2: - ldrh(Dst, TMP1, Op->Index); - break; - case 4: - ldr(Dst.S(), TMP1, Op->Index); - break; - case 8: - ldr(Dst.D(), TMP1, Op->Index); - break; - case 16: - ldr(Dst.Q(), TMP1, Op->Index); - break; - case 32: { - add(ARMEmitter::Size::i64Bit, TMP1, TMP1, Op->Index); - ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), TMP1, 0); - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); - break; + case 1: ldrb(Dst, TMP1, Op->Index); break; + case 2: ldrh(Dst, TMP1, Op->Index); break; + case 4: ldr(Dst.S(), TMP1, Op->Index); break; + case 8: ldr(Dst.D(), TMP1, Op->Index); break; + case 16: ldr(Dst.Q(), TMP1, Op->Index); break; + case 32: { + add(ARMEmitter::Size::i64Bit, TMP1, TMP1, Op->Index); + ld1b(Dst.Z(), PRED_TMP_32B.Zeroing(), TMP1, 0); + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, OpSize); break; } } @@ -942,47 +853,45 @@ DEF_OP(VMov) { const auto Source = GetVReg(Op->Source.ID()); switch (OpSize) { - case 1: { - movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0); - ins(ARMEmitter::SubRegSize::i8Bit, VTMP1, 0, Source, 0); - mov(Dst.Q(), VTMP1.Q()); - break; + case 1: { + movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0); + ins(ARMEmitter::SubRegSize::i8Bit, VTMP1, 0, Source, 0); + mov(Dst.Q(), VTMP1.Q()); + break; + } + case 2: { + movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0); + ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 0, Source, 0); + mov(Dst.Q(), VTMP1.Q()); + break; + } + case 4: { + movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0); + ins(ARMEmitter::SubRegSize::i32Bit, VTMP1, 0, Source, 0); + mov(Dst.Q(), VTMP1.Q()); + break; + } + case 8: { + mov(Dst.D(), Source.D()); + break; + } + case 16: { + if (HostSupportsSVE256 || Dst.Idx() != Source.Idx()) { + mov(Dst.Q(), Source.Q()); } - case 2: { - movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0); - ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 0, Source, 0); - mov(Dst.Q(), VTMP1.Q()); - break; + break; + } + case 32: { + // NOTE: If, in the distant future we support larger moves, or registers + // (*cough* AVX-512 *cough*) make sure to change this to treat + // 256-bit moves with zero extending behavior instead of doing only + // a regular SVE move into a 512-bit register. + if (Dst.Idx() != Source.Idx()) { + mov(Dst.Z(), Source.Z()); } - case 4: { - movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0); - ins(ARMEmitter::SubRegSize::i32Bit, VTMP1, 0, Source, 0); - mov(Dst.Q(), VTMP1.Q()); - break; - } - case 8: { - mov(Dst.D(), Source.D()); - break; - } - case 16: { - if (HostSupportsSVE256 || Dst.Idx() != Source.Idx()) { - mov(Dst.Q(), Source.Q()); - } - break; - } - case 32: { - // NOTE: If, in the distant future we support larger moves, or registers - // (*cough* AVX-512 *cough*) make sure to change this to treat - // 256-bit moves with zero extending behavior instead of doing only - // a regular SVE move into a 512-bit register. - if (Dst.Idx() != Source.Idx()) { - mov(Dst.Z(), Source.Z()); - } - break; - } - default: - LOGMAN_MSG_A_FMT("Unknown Op Size: {}", OpSize); - break; + break; + } + default: LOGMAN_MSG_A_FMT("Unknown Op Size: {}", OpSize); break; } } @@ -1062,11 +971,11 @@ DEF_OP(VAdd) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { add(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); @@ -1087,11 +996,11 @@ DEF_OP(VSub) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { sub(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); @@ -1112,11 +1021,11 @@ DEF_OP(VUQAdd) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { uqadd(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); @@ -1137,11 +1046,11 @@ DEF_OP(VUQSub) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { uqsub(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); @@ -1162,11 +1071,11 @@ DEF_OP(VSQAdd) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { sqadd(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); @@ -1187,11 +1096,11 @@ DEF_OP(VSQSub) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { sqsub(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); @@ -1213,11 +1122,11 @@ DEF_OP(VAddP) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -1254,11 +1163,12 @@ DEF_OP(VFAddV) { const auto Dst = GetVReg(Node); const auto Vector = GetVReg(Op->Vector.ID()); - LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE || OpSize == Core::CPUState::XMM_AVX_REG_SIZE, "Only AVX and SSE size supported"); + LOGMAN_THROW_AA_FMT(OpSize == Core::CPUState::XMM_SSE_REG_SIZE || OpSize == Core::CPUState::XMM_AVX_REG_SIZE, "Only AVX and SSE size " + "supported"); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -1272,8 +1182,7 @@ DEF_OP(VFAddV) { if (ElementSize == 4) { faddp(SubRegSize.Vector, Dst.Q(), Vector.Q(), Vector.Q()); faddp(SubRegSize.Scalar, Dst, Vector); - } - else { + } else { faddp(SubRegSize.Scalar, Dst, Vector); } } @@ -1290,11 +1199,11 @@ DEF_OP(VAddV) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { // SVE doesn't have an equivalent ADDV instruction, so we make do @@ -1314,8 +1223,7 @@ DEF_OP(VAddV) { } else { if (ElementSize == 8) { addp(SubRegSize.Scalar, Dst, Vector); - } - else { + } else { addv(SubRegSize.Vector, Dst.Q(), Vector.Q()); } } @@ -1332,11 +1240,11 @@ DEF_OP(VUMinV) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B; @@ -1358,11 +1266,11 @@ DEF_OP(VUMaxV) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B; @@ -1385,11 +1293,11 @@ DEF_OP(VURAvg) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -1423,11 +1331,11 @@ DEF_OP(VAbs) { const auto Src = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { abs(SubRegSize, Dst.Z(), PRED_TMP_32B.Merging(), Src.Z()); @@ -1453,30 +1361,29 @@ DEF_OP(VFAbs) { const auto Src = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { fabs(SubRegSize, Dst.Z(), PRED_TMP_32B.Merging(), Src.Z()); } else { if (ElementSize == OpSize) { switch (ElementSize) { - case 2: { - fabs(Dst.H(), Src.H()); - break; - } - case 4: { - fabs(Dst.S(), Src.S()); - break; - } - case 8: { - fabs(Dst.D(), Src.D()); - break; - } - default: - break; + case 2: { + fabs(Dst.H(), Src.H()); + break; + } + case 4: { + fabs(Dst.S(), Src.S()); + break; + } + case 8: { + fabs(Dst.D(), Src.D()); + break; + } + default: break; } } else { // Vector @@ -1498,11 +1405,11 @@ DEF_OP(VPopcount) { const auto Src = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -1529,30 +1436,29 @@ DEF_OP(VFAdd) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { fadd(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fadd(Dst.H(), Vector1.H(), Vector2.H()); - break; - } - case 4: { - fadd(Dst.S(), Vector1.S(), Vector2.S()); - break; - } - case 8: { - fadd(Dst.D(), Vector1.D(), Vector2.D()); - break; - } - default: - break; + case 2: { + fadd(Dst.H(), Vector1.H(), Vector2.H()); + break; + } + case 4: { + fadd(Dst.S(), Vector1.S(), Vector2.S()); + break; + } + case 8: { + fadd(Dst.D(), Vector1.D(), Vector2.D()); + break; + } + default: break; } } else { fadd(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); @@ -1572,10 +1478,10 @@ DEF_OP(VFAddP) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -1611,30 +1517,29 @@ DEF_OP(VFSub) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { fsub(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fsub(Dst.H(), Vector1.H(), Vector2.H()); - break; - } - case 4: { - fsub(Dst.S(), Vector1.S(), Vector2.S()); - break; - } - case 8: { - fsub(Dst.D(), Vector1.D(), Vector2.D()); - break; - } - default: - break; + case 2: { + fsub(Dst.H(), Vector1.H(), Vector2.H()); + break; + } + case 4: { + fsub(Dst.S(), Vector1.S(), Vector2.S()); + break; + } + case 8: { + fsub(Dst.D(), Vector1.D(), Vector2.D()); + break; + } + default: break; } } else { fsub(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); @@ -1655,30 +1560,29 @@ DEF_OP(VFMul) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { fmul(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fmul(Dst.H(), Vector1.H(), Vector2.H()); - break; - } - case 4: { - fmul(Dst.S(), Vector1.S(), Vector2.S()); - break; - } - case 8: { - fmul(Dst.D(), Vector1.D(), Vector2.D()); - break; - } - default: - break; + case 2: { + fmul(Dst.H(), Vector1.H(), Vector2.H()); + break; + } + case 4: { + fmul(Dst.S(), Vector1.S(), Vector2.S()); + break; + } + case 8: { + fmul(Dst.D(), Vector1.D(), Vector2.D()); + break; + } + default: break; } } else { fmul(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); @@ -1699,10 +1603,10 @@ DEF_OP(VFDiv) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -1726,20 +1630,19 @@ DEF_OP(VFDiv) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fdiv(Dst.H(), Vector1.H(), Vector2.H()); - break; - } - case 4: { - fdiv(Dst.S(), Vector1.S(), Vector2.S()); - break; - } - case 8: { - fdiv(Dst.D(), Vector1.D(), Vector2.D()); - break; - } - default: - break; + case 2: { + fdiv(Dst.H(), Vector1.H(), Vector2.H()); + break; + } + case 4: { + fdiv(Dst.S(), Vector1.S(), Vector2.S()); + break; + } + case 8: { + fdiv(Dst.D(), Vector1.D(), Vector2.D()); + break; + } + default: break; } } else { fdiv(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); @@ -1760,10 +1663,10 @@ DEF_OP(VFMin) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; // NOTE: We don't directly use FMIN here for any of the implementations, // because it has undesirable NaN handling behavior (it sets @@ -1785,10 +1688,9 @@ DEF_OP(VFMin) { // predicate bits from the second vector into the // same temporary. // 5. Move temporary into the destination register and we're done. - fcmgt(SubRegSize, ComparePred, Mask.Zeroing(), - Vector2.Z(), Vector1.Z()); + fcmgt(SubRegSize, ComparePred, Mask.Zeroing(), Vector2.Z(), Vector1.Z()); not_(ComparePred, Mask.Zeroing(), ComparePred); - + if (Dst == Vector1) { // Trivial case where Vector1 is also the destination. // We don't need to move any data around in this case (aside from the merge). @@ -1804,23 +1706,22 @@ DEF_OP(VFMin) { mrs(TMP1, ARMEmitter::SystemRegister::NZCV); switch (ElementSize) { - case 2: { - fcmp(Vector1.H(), Vector2.H()); - fcsel(Dst.H(), Vector1.H(), Vector2.H(), ARMEmitter::Condition::CC_MI); - break; - } - case 4: { - fcmp(Vector1.S(), Vector2.S()); - fcsel(Dst.S(), Vector1.S(), Vector2.S(), ARMEmitter::Condition::CC_MI); - break; - } - case 8: { - fcmp(Vector1.D(), Vector2.D()); - fcsel(Dst.D(), Vector1.D(), Vector2.D(), ARMEmitter::Condition::CC_MI); - break; - } - default: - break; + case 2: { + fcmp(Vector1.H(), Vector2.H()); + fcsel(Dst.H(), Vector1.H(), Vector2.H(), ARMEmitter::Condition::CC_MI); + break; + } + case 4: { + fcmp(Vector1.S(), Vector2.S()); + fcsel(Dst.S(), Vector1.S(), Vector2.S(), ARMEmitter::Condition::CC_MI); + break; + } + case 8: { + fcmp(Vector1.D(), Vector2.D()); + fcsel(Dst.D(), Vector1.D(), Vector2.D(), ARMEmitter::Condition::CC_MI); + break; + } + default: break; } // Restore NZCV @@ -1830,13 +1731,11 @@ DEF_OP(VFMin) { // Destination is already Vector1, need to insert Vector2 on false. fcmgt(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); bif(Dst.Q(), Vector2.Q(), VTMP1.Q()); - } - else if (Dst == Vector2) { + } else if (Dst == Vector2) { // Destination is already Vector2, Invert arguments and insert Vector1 on false. fcmgt(SubRegSize, VTMP1.Q(), Vector1.Q(), Vector2.Q()); bif(Dst.Q(), Vector1.Q(), VTMP1.Q()); - } - else { + } else { // Dst is not either source, need a move. fcmgt(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); mov(Dst.Q(), Vector1.Q()); @@ -1859,10 +1758,10 @@ DEF_OP(VFMax) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; // NOTE: See VFMin implementation for reasons why we // don't just use FMAX/FMIN for these implementations. @@ -1871,8 +1770,7 @@ DEF_OP(VFMax) { const auto Mask = PRED_TMP_32B; const auto ComparePred = ARMEmitter::PReg::p0; - fcmgt(SubRegSize, ComparePred, Mask.Zeroing(), - Vector2.Z(), Vector1.Z()); + fcmgt(SubRegSize, ComparePred, Mask.Zeroing(), Vector2.Z(), Vector1.Z()); if (Dst == Vector1) { // Trivial case where Vector1 is also the destination. @@ -1889,23 +1787,22 @@ DEF_OP(VFMax) { mrs(TMP1, ARMEmitter::SystemRegister::NZCV); switch (ElementSize) { - case 2: { - fcmp(Vector1.H(), Vector2.H()); - fcsel(Dst.H(), Vector2.H(), Vector1.H(), ARMEmitter::Condition::CC_MI); - break; - } - case 4: { - fcmp(Vector1.S(), Vector2.S()); - fcsel(Dst.S(), Vector2.S(), Vector1.S(), ARMEmitter::Condition::CC_MI); - break; - } - case 8: { - fcmp(Vector1.D(), Vector2.D()); - fcsel(Dst.D(), Vector2.D(), Vector1.D(), ARMEmitter::Condition::CC_MI); - break; - } - default: - break; + case 2: { + fcmp(Vector1.H(), Vector2.H()); + fcsel(Dst.H(), Vector2.H(), Vector1.H(), ARMEmitter::Condition::CC_MI); + break; + } + case 4: { + fcmp(Vector1.S(), Vector2.S()); + fcsel(Dst.S(), Vector2.S(), Vector1.S(), ARMEmitter::Condition::CC_MI); + break; + } + case 8: { + fcmp(Vector1.D(), Vector2.D()); + fcsel(Dst.D(), Vector2.D(), Vector1.D(), ARMEmitter::Condition::CC_MI); + break; + } + default: break; } // Restore NZCV @@ -1915,13 +1812,11 @@ DEF_OP(VFMax) { // Destination is already Vector1, need to insert Vector2 on true. fcmgt(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); bit(Dst.Q(), Vector2.Q(), VTMP1.Q()); - } - else if (Dst == Vector2) { + } else if (Dst == Vector2) { // Destination is already Vector2, Invert arguments and insert Vector1 on true. fcmgt(SubRegSize, VTMP1.Q(), Vector1.Q(), Vector2.Q()); bit(Dst.Q(), Vector1.Q(), VTMP1.Q()); - } - else { + } else { // Dst is not either source, need a move. fcmgt(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); mov(Dst.Q(), Vector1.Q()); @@ -1943,10 +1838,10 @@ DEF_OP(VFRecp) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -1970,28 +1865,26 @@ DEF_OP(VFRecp) { fmov(SubRegSize.Scalar, VTMP1.Q(), 1.0f); switch (ElementSize) { - case 2: { - fdiv(Dst.H(), VTMP1.H(), Vector.H()); - break; - } - case 4: { - fdiv(Dst.S(), VTMP1.S(), Vector.S()); - break; - } - case 8: { - fdiv(Dst.D(), VTMP1.D(), Vector.D()); - break; - } - default: - break; + case 2: { + fdiv(Dst.H(), VTMP1.H(), Vector.H()); + break; + } + case 4: { + fdiv(Dst.S(), VTMP1.S(), Vector.S()); + break; + } + case 8: { + fdiv(Dst.D(), VTMP1.D(), Vector.D()); + break; + } + default: break; } } else { if (ElementSize == 4 && HostSupportsRPRES) { // RPRES gives enough precision for this. if (OpSize == 8) { frecpe(SubRegSize.Vector, Dst.D(), Vector.D()); - } - else { + } else { frecpe(SubRegSize.Vector, Dst.Q(), Vector.Q()); } return; @@ -2015,10 +1908,10 @@ DEF_OP(VFSqrt) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2027,20 +1920,19 @@ DEF_OP(VFSqrt) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fsqrt(Dst.H(), Vector.H()); - break; - } - case 4: { - fsqrt(Dst.S(), Vector.S()); - break; - } - case 8: { - fsqrt(Dst.D(), Vector.D()); - break; - } - default: - break; + case 2: { + fsqrt(Dst.H(), Vector.H()); + break; + } + case 4: { + fsqrt(Dst.S(), Vector.S()); + break; + } + case 8: { + fsqrt(Dst.D(), Vector.D()); + break; + } + default: break; } } else { fsqrt(SubRegSize, Dst.Q(), Vector.Q()); @@ -2060,10 +1952,10 @@ DEF_OP(VFRSqrt) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2086,31 +1978,29 @@ DEF_OP(VFRSqrt) { fmov(SubRegSize.Scalar, VTMP1.Q(), 1.0); switch (ElementSize) { - case 2: { - fsqrt(VTMP2.H(), Vector.H()); - fdiv(Dst.H(), VTMP1.H(), VTMP2.H()); - break; - } - case 4: { - fsqrt(VTMP2.S(), Vector.S()); - fdiv(Dst.S(), VTMP1.S(), VTMP2.S()); - break; - } - case 8: { - fsqrt(VTMP2.D(), Vector.D()); - fdiv(Dst.D(), VTMP1.D(), VTMP2.D()); - break; - } - default: - break; + case 2: { + fsqrt(VTMP2.H(), Vector.H()); + fdiv(Dst.H(), VTMP1.H(), VTMP2.H()); + break; + } + case 4: { + fsqrt(VTMP2.S(), Vector.S()); + fdiv(Dst.S(), VTMP1.S(), VTMP2.S()); + break; + } + case 8: { + fsqrt(VTMP2.D(), Vector.D()); + fdiv(Dst.D(), VTMP1.D(), VTMP2.D()); + break; + } + default: break; } } else { if (ElementSize == 4 && HostSupportsRPRES) { // RPRES gives enough precision for this. if (OpSize == 8) { frsqrte(SubRegSize.Vector, Dst.D(), Vector.D()); - } - else { + } else { frsqrte(SubRegSize.Vector, Dst.Q(), Vector.Q()); } return; @@ -2131,14 +2021,14 @@ DEF_OP(VNeg) { const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE; const auto Dst = GetVReg(Node); - const auto Vector= GetVReg(Op->Vector.ID()); + const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2159,10 +2049,10 @@ DEF_OP(VFNeg) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2200,11 +2090,11 @@ DEF_OP(VUMin) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2224,21 +2114,20 @@ DEF_OP(VUMin) { } } else { switch (ElementSize) { - case 1: - case 2: - case 4: { - umin(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); - break; - } - case 8: { - cmhi(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); - mov(VTMP2.Q(), Vector1.Q()); - bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); - mov(Dst.Q(), VTMP2.Q()); - break; - } - default: - break; + case 1: + case 2: + case 4: { + umin(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); + break; + } + case 8: { + cmhi(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); + mov(VTMP2.Q(), Vector1.Q()); + bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); + mov(Dst.Q(), VTMP2.Q()); + break; + } + default: break; } } } @@ -2255,11 +2144,11 @@ DEF_OP(VSMin) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2279,21 +2168,20 @@ DEF_OP(VSMin) { } } else { switch (ElementSize) { - case 1: - case 2: - case 4: { - smin(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); - break; - } - case 8: { - cmgt(SubRegSize, VTMP1.Q(), Vector1.Q(), Vector2.Q()); - mov(VTMP2.Q(), Vector1.Q()); - bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); - mov(Dst.Q(), VTMP2.Q()); - break; - } - default: - break; + case 1: + case 2: + case 4: { + smin(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); + break; + } + case 8: { + cmgt(SubRegSize, VTMP1.Q(), Vector1.Q(), Vector2.Q()); + mov(VTMP2.Q(), Vector1.Q()); + bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); + mov(Dst.Q(), VTMP2.Q()); + break; + } + default: break; } } } @@ -2310,11 +2198,11 @@ DEF_OP(VUMax) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2334,21 +2222,20 @@ DEF_OP(VUMax) { } } else { switch (ElementSize) { - case 1: - case 2: - case 4: { - umax(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); - break; - } - case 8: { - cmhi(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); - mov(VTMP2.Q(), Vector1.Q()); - bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); - mov(Dst.Q(), VTMP2.Q()); - break; - } - default: - break; + case 1: + case 2: + case 4: { + umax(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); + break; + } + case 8: { + cmhi(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); + mov(VTMP2.Q(), Vector1.Q()); + bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); + mov(Dst.Q(), VTMP2.Q()); + break; + } + default: break; } } } @@ -2365,11 +2252,11 @@ DEF_OP(VSMax) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Pred = PRED_TMP_32B.Merging(); @@ -2389,21 +2276,20 @@ DEF_OP(VSMax) { } } else { switch (ElementSize) { - case 1: - case 2: - case 4: { - smax(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); - break; - } - case 8: { - cmgt(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); - mov(VTMP2.Q(), Vector1.Q()); - bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); - mov(Dst.Q(), VTMP2.Q()); - break; - } - default: - break; + case 1: + case 2: + case 4: { + smax(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q()); + break; + } + case 8: { + cmgt(SubRegSize, VTMP1.Q(), Vector2.Q(), Vector1.Q()); + mov(VTMP2.Q(), Vector1.Q()); + bif(VTMP2.Q(), Vector2.Q(), VTMP1.Q()); + mov(Dst.Q(), VTMP2.Q()); + break; + } + default: break; } } } @@ -2420,11 +2306,11 @@ DEF_OP(VZip) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { zip1(SubRegSize, Dst.Z(), VectorLower.Z(), VectorUpper.Z()); @@ -2449,11 +2335,11 @@ DEF_OP(VZip2) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { zip2(SubRegSize, Dst.Z(), VectorLower.Z(), VectorUpper.Z()); @@ -2478,11 +2364,11 @@ DEF_OP(VUnZip) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { uzp1(SubRegSize, Dst.Z(), VectorLower.Z(), VectorUpper.Z()); @@ -2507,11 +2393,11 @@ DEF_OP(VUnZip2) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { uzp2(SubRegSize, Dst.Z(), VectorLower.Z(), VectorUpper.Z()); @@ -2536,11 +2422,11 @@ DEF_OP(VTrn) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { trn1(SubRegSize, Dst.Z(), VectorLower.Z(), VectorUpper.Z()); @@ -2565,11 +2451,11 @@ DEF_OP(VTrn2) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { trn2(SubRegSize, Dst.Z(), VectorLower.Z(), VectorUpper.Z()); @@ -2611,30 +2497,24 @@ DEF_OP(VBSL) { // Can use BSL without any moves. if (OpSize == 8) { bsl(Dst.D(), VectorTrue.D(), VectorFalse.D()); - } - else { + } else { bsl(Dst.Q(), VectorTrue.Q(), VectorFalse.Q()); } - } - else if (VectorTrue == Dst) { + } else if (VectorTrue == Dst) { // Can use BIF without any moves. if (OpSize == 8) { bif(Dst.D(), VectorFalse.D(), VectorMask.D()); - } - else { + } else { bif(Dst.Q(), VectorFalse.Q(), VectorMask.Q()); } - } - else if (VectorFalse == Dst) { + } else if (VectorFalse == Dst) { // Can use BIT without any moves. if (OpSize == 8) { bit(Dst.D(), VectorTrue.D(), VectorMask.D()); - } - else { + } else { bit(Dst.Q(), VectorTrue.Q(), VectorMask.Q()); } - } - else { + } else { // Needs moves. if (OpSize == 8) { mov(Dst.D(), VectorMask.D()); @@ -2660,11 +2540,11 @@ DEF_OP(VCMPEQ) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit); if (HostSupportsSVE256 && Is256Bit) { // FIXME: We should rework this op to avoid the NZCV spill/fill dance. @@ -2704,11 +2584,11 @@ DEF_OP(VCMPEQZ) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -2752,11 +2632,11 @@ DEF_OP(VCMPGT) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -2796,11 +2676,11 @@ DEF_OP(VCMPGTZ) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -2840,11 +2720,11 @@ DEF_OP(VCMPLTZ) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -2885,10 +2765,10 @@ DEF_OP(VFCMPEQ) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -2901,16 +2781,13 @@ DEF_OP(VFCMPEQ) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fcmeq(Dst.H(), Vector1.H(), Vector2.H()); - break; - } - case 4: - case 8: - fcmeq(SubRegSize.Scalar, Dst, Vector1, Vector2); - break; - default: - break; + case 2: { + fcmeq(Dst.H(), Vector1.H(), Vector2.H()); + break; + } + case 4: + case 8: fcmeq(SubRegSize.Scalar, Dst, Vector1, Vector2); break; + default: break; } } else { fcmeq(SubRegSize.Vector, Dst.Q(), Vector1.Q(), Vector2.Q()); @@ -2931,10 +2808,10 @@ DEF_OP(VFCMPNEQ) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -2947,16 +2824,13 @@ DEF_OP(VFCMPNEQ) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fcmeq(Dst.H(), Vector1.H(), Vector2.H()); - break; - } - case 4: - case 8: - fcmeq(SubRegSize.Scalar, Dst, Vector1, Vector2); - break; - default: - break; + case 2: { + fcmeq(Dst.H(), Vector1.H(), Vector2.H()); + break; + } + case 4: + case 8: fcmeq(SubRegSize.Scalar, Dst, Vector1, Vector2); break; + default: break; } mvn(ARMEmitter::SubRegSize::i8Bit, Dst.D(), Dst.D()); } else { @@ -2968,7 +2842,7 @@ DEF_OP(VFCMPNEQ) { DEF_OP(VFCMPLT) { const auto Op = IROp->C(); - const auto OpSize = IROp->Size; + const auto OpSize = IROp->Size; const auto ElementSize = Op->Header.ElementSize; const auto IsScalar = ElementSize == OpSize; @@ -2979,10 +2853,10 @@ DEF_OP(VFCMPLT) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -2995,16 +2869,13 @@ DEF_OP(VFCMPLT) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fcmgt(Dst.H(), Vector2.H(), Vector1.H()); - break; - } - case 4: - case 8: - fcmgt(SubRegSize.Scalar, Dst, Vector2, Vector1); - break; - default: - break; + case 2: { + fcmgt(Dst.H(), Vector2.H(), Vector1.H()); + break; + } + case 4: + case 8: fcmgt(SubRegSize.Scalar, Dst, Vector2, Vector1); break; + default: break; } } else { fcmgt(SubRegSize.Vector, Dst.Q(), Vector2.Q(), Vector1.Q()); @@ -3025,10 +2896,10 @@ DEF_OP(VFCMPGT) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -3041,16 +2912,13 @@ DEF_OP(VFCMPGT) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fcmgt(Dst.H(), Vector1.H(), Vector2.H()); - break; - } - case 4: - case 8: - fcmgt(SubRegSize.Scalar, Dst, Vector1, Vector2); - break; - default: - break; + case 2: { + fcmgt(Dst.H(), Vector1.H(), Vector2.H()); + break; + } + case 4: + case 8: fcmgt(SubRegSize.Scalar, Dst, Vector1, Vector2); break; + default: break; } } else { fcmgt(SubRegSize.Vector, Dst.Q(), Vector1.Q(), Vector2.Q()); @@ -3071,10 +2939,10 @@ DEF_OP(VFCMPLE) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -3087,16 +2955,13 @@ DEF_OP(VFCMPLE) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fcmge(Dst.H(), Vector2.H(), Vector1.H()); - break; - } - case 4: - case 8: - fcmge(SubRegSize.Scalar, Dst, Vector2, Vector1); - break; - default: - break; + case 2: { + fcmge(Dst.H(), Vector2.H(), Vector1.H()); + break; + } + case 4: + case 8: fcmge(SubRegSize.Scalar, Dst, Vector2, Vector1); break; + default: break; } } else { fcmge(SubRegSize.Vector, Dst.Q(), Vector2.Q(), Vector1.Q()); @@ -3118,10 +2983,10 @@ DEF_OP(VFCMPORD) { LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Incorrect size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -3138,20 +3003,19 @@ DEF_OP(VFCMPORD) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fcmge(VTMP1.H(), Vector1.H(), Vector2.H()); - fcmgt(VTMP2.H(), Vector2.H(), Vector1.H()); - orr(Dst.D(), VTMP1.D(), VTMP2.D()); - break; - } - case 4: - case 8: - fcmge(SubRegSize.Scalar, VTMP1, Vector1, Vector2); - fcmgt(SubRegSize.Scalar, VTMP2, Vector2, Vector1); - orr(Dst.D(), VTMP1.D(), VTMP2.D()); - break; - default: - break; + case 2: { + fcmge(VTMP1.H(), Vector1.H(), Vector2.H()); + fcmgt(VTMP2.H(), Vector2.H(), Vector1.H()); + orr(Dst.D(), VTMP1.D(), VTMP2.D()); + break; + } + case 4: + case 8: + fcmge(SubRegSize.Scalar, VTMP1, Vector1, Vector2); + fcmgt(SubRegSize.Scalar, VTMP2, Vector2, Vector1); + orr(Dst.D(), VTMP1.D(), VTMP2.D()); + break; + default: break; } } else { fcmge(SubRegSize.Vector, VTMP1.Q(), Vector1.Q(), Vector2.Q()); @@ -3175,10 +3039,10 @@ DEF_OP(VFCMPUNO) { LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Incorrect size"); - const auto SubRegSize = ARMEmitter::ToVectorSizePair( - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit); + const auto SubRegSize = ARMEmitter::ToVectorSizePair(ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit); if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Zeroing(); @@ -3191,22 +3055,21 @@ DEF_OP(VFCMPUNO) { } else { if (IsScalar) { switch (ElementSize) { - case 2: { - fcmge(VTMP1.H(), Vector1.H(), Vector2.H()); - fcmgt(VTMP2.H(), Vector2.H(), Vector1.H()); - orr(Dst.D(), VTMP1.D(), VTMP2.D()); - mvn(ARMEmitter::SubRegSize::i8Bit, Dst.D(), Dst.D()); - break; - } - case 4: - case 8: - fcmge(SubRegSize.Scalar, VTMP1, Vector1, Vector2); - fcmgt(SubRegSize.Scalar, VTMP2, Vector2, Vector1); - orr(Dst.D(), VTMP1.D(), VTMP2.D()); - mvn(ARMEmitter::SubRegSize::i8Bit, Dst.D(), Dst.D()); - break; - default: - break; + case 2: { + fcmge(VTMP1.H(), Vector1.H(), Vector2.H()); + fcmgt(VTMP2.H(), Vector2.H(), Vector1.H()); + orr(Dst.D(), VTMP1.D(), VTMP2.D()); + mvn(ARMEmitter::SubRegSize::i8Bit, Dst.D(), Dst.D()); + break; + } + case 4: + case 8: + fcmge(SubRegSize.Scalar, VTMP1, Vector1, Vector2); + fcmgt(SubRegSize.Scalar, VTMP2, Vector2, Vector1); + orr(Dst.D(), VTMP1.D(), VTMP2.D()); + mvn(ARMEmitter::SubRegSize::i8Bit, Dst.D(), Dst.D()); + break; + default: break; } } else { fcmge(SubRegSize.Vector, VTMP1.Q(), Vector1.Q(), Vector2.Q()); @@ -3231,11 +3094,11 @@ DEF_OP(VUShl) { const auto RangeCheck = Op->RangeCheck; LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3291,11 +3154,11 @@ DEF_OP(VUShr) { const auto RangeCheck = Op->RangeCheck; LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3354,11 +3217,11 @@ DEF_OP(VSShr) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3415,11 +3278,11 @@ DEF_OP(VUShlS) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3450,11 +3313,11 @@ DEF_OP(VUShrS) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3486,10 +3349,10 @@ DEF_OP(VUShrSWide) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3501,12 +3364,10 @@ DEF_OP(VUShrSWide) { } if (ElementSize == 8) { lsr(SubRegSize, Dst.Z(), Mask, Dst.Z(), VTMP1.Z()); - } - else { + } else { lsr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), VTMP1.Z()); } - } - else if (HostSupportsSVE128) { + } else if (HostSupportsSVE128) { const auto Mask = PRED_TMP_16B.Merging(); auto ShiftRegister = ShiftScalar; @@ -3529,8 +3390,7 @@ DEF_OP(VUShrSWide) { } if (ElementSize == 8) { lsr(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); - } - else { + } else { lsr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } } else { @@ -3559,10 +3419,10 @@ DEF_OP(VSShrSWide) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3574,12 +3434,10 @@ DEF_OP(VSShrSWide) { } if (ElementSize == 8) { asr(SubRegSize, Dst.Z(), Mask, Dst.Z(), VTMP1.Z()); - } - else { + } else { asr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), VTMP1.Z()); } - } - else if (HostSupportsSVE128) { + } else if (HostSupportsSVE128) { const auto Mask = PRED_TMP_16B.Merging(); auto ShiftRegister = ShiftScalar; @@ -3602,8 +3460,7 @@ DEF_OP(VSShrSWide) { } if (ElementSize == 8) { asr(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); - } - else { + } else { asr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } } else { @@ -3632,10 +3489,10 @@ DEF_OP(VUShlSWide) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -3647,12 +3504,10 @@ DEF_OP(VUShlSWide) { } if (ElementSize == 8) { lsl(SubRegSize, Dst.Z(), Mask, Dst.Z(), VTMP1.Z()); - } - else { + } else { lsl_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), VTMP1.Z()); } - } - else if (HostSupportsSVE128) { + } else if (HostSupportsSVE128) { const auto Mask = PRED_TMP_16B.Merging(); auto ShiftRegister = ShiftScalar; @@ -3675,8 +3530,7 @@ DEF_OP(VUShlSWide) { } if (ElementSize == 8) { lsl(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); - } - else { + } else { lsl_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } } else { @@ -3704,13 +3558,13 @@ DEF_OP(VSShrS) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; - if (HostSupportsSVE256 && Is256Bit) { + if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); // NOTE: SVE ASR is a destructive operation, so we need to @@ -3744,11 +3598,11 @@ DEF_OP(VInsElement) { if (HostSupportsSVE256 && Is256Bit) { LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; // Broadcast our source value across a temporary, // then combine with the destination. @@ -3784,14 +3638,13 @@ DEF_OP(VInsElement) { // Restore NZCV msr(ARMEmitter::SystemRegister::NZCV, TMP1); } - } - else { + } else { LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; // If nothing aliases the destination, then we can just // move the DestVector over and directly insert. @@ -3834,19 +3687,18 @@ DEF_OP(VDupElement) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8 || ElementSize == 16, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i128Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i128Bit; if (HostSupportsSVE256 && Is256Bit) { dup(SubRegSize, Dst.Z(), Vector.Z(), Index); } else { if (Is128Bit) { dup(SubRegSize, Dst.Q(), Vector.Q(), Index); - } - else { + } else { dup(SubRegSize, Dst.D(), Vector.D(), Index); } } @@ -3911,11 +3763,11 @@ DEF_OP(VUShrI) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (BitShift >= (ElementSize * 8)) { movi(ARMEmitter::SubRegSize::i64Bit, Dst.Q(), 0); @@ -3960,22 +3812,20 @@ DEF_OP(VUShraI) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { if (Dst == DestVector) { usra(SubRegSize, Dst.Z(), Vector.Z(), BitShift); - } - else { + } else { if (Dst != Vector) { mov(Dst.Z(), DestVector.Z()); usra(SubRegSize, Dst.Z(), Vector.Z(), BitShift); - } - else { + } else { mov(VTMP1.Z(), DestVector.Z()); usra(SubRegSize, Dst.Z(), Vector.Z(), BitShift); mov(Dst.Z(), VTMP1.Z()); @@ -3984,13 +3834,11 @@ DEF_OP(VUShraI) { } else { if (Dst == DestVector) { usra(SubRegSize, Dst.Q(), Vector.Q(), BitShift); - } - else { + } else { if (Dst != Vector) { mov(Dst.Q(), DestVector.Q()); usra(SubRegSize, Dst.Q(), Vector.Q(), BitShift); - } - else { + } else { mov(VTMP1.Q(), DestVector.Q()); usra(SubRegSize, VTMP1.Q(), Vector.Q(), BitShift); mov(Dst.Q(), VTMP1.Q()); @@ -4011,11 +3859,11 @@ DEF_OP(VSShrI) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -4055,11 +3903,11 @@ DEF_OP(VShlI) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (BitShift >= (ElementSize * 8)) { @@ -4104,10 +3952,10 @@ DEF_OP(VUShrNI) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4, "Incorrect size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { shrnb(SubRegSize, Dst.Z(), Vector.Z(), BitShift); @@ -4130,10 +3978,10 @@ DEF_OP(VUShrNI2) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_16B; @@ -4171,13 +4019,12 @@ DEF_OP(VSXTL) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Incorrect size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; - if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || - (HostSupportsSVE256 && Is256Bit)) { + if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || (HostSupportsSVE256 && Is256Bit)) { sunpklo(SubRegSize, Dst.Z(), Vector.Z()); } else { sxtl(SubRegSize, Dst.D(), Vector.D()); @@ -4195,13 +4042,12 @@ DEF_OP(VSXTL2) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Incorrect size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; - if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || - (HostSupportsSVE256 && Is256Bit)) { + if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || (HostSupportsSVE256 && Is256Bit)) { sunpkhi(SubRegSize, Dst.Z(), Vector.Z()); } else { sxtl2(SubRegSize, Dst.Q(), Vector.Q()); @@ -4219,13 +4065,12 @@ DEF_OP(VUXTL) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Incorrect size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; - if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || - (HostSupportsSVE256 && Is256Bit)) { + if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || (HostSupportsSVE256 && Is256Bit)) { uunpklo(SubRegSize, Dst.Z(), Vector.Z()); } else { uxtl(SubRegSize, Dst.D(), Vector.D()); @@ -4243,13 +4088,12 @@ DEF_OP(VUXTL2) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Incorrect size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; - if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || - (HostSupportsSVE256 && Is256Bit)) { + if ((HostSupportsSVE128 && !Is256Bit && !HostSupportsSVE256) || (HostSupportsSVE256 && Is256Bit)) { uunpkhi(SubRegSize, Dst.Z(), Vector.Z()); } else { uxtl2(SubRegSize, Dst.Q(), Vector.Q()); @@ -4267,10 +4111,10 @@ DEF_OP(VSQXTN) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4, "Incorrect size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { // Note that SVE SQXTNB and SQXTNT are a tad different @@ -4325,10 +4169,10 @@ DEF_OP(VSQXTN2) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { // We use the 16 byte mask due to how SPLICE works. We only @@ -4374,10 +4218,10 @@ DEF_OP(VSQXTNPair) { auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4, "Incorrect size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { // This combines the SVE versions of VSQXTN/VSQXTN2. @@ -4399,8 +4243,7 @@ DEF_OP(VSQXTNPair) { if (OpSize == 8) { zip1(ARMEmitter::SubRegSize::i64Bit, Dst.Q(), VectorLower.Q(), VectorUpper.Q()); sqxtn(SubRegSize, Dst, Dst); - } - else { + } else { if (Dst == VectorUpper) { // If the destination overlaps the upper then we need to move it temporarily. mov(VTMP1.Q(), VectorUpper.Q()); @@ -4423,10 +4266,10 @@ DEF_OP(VSQXTUN) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { sqxtunb(SubRegSize, Dst.Z(), Vector.Z()); @@ -4448,10 +4291,10 @@ DEF_OP(VSQXTUN2) { const auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { // NOTE: See VSQXTN2 implementation for an in-depth explanation @@ -4499,10 +4342,10 @@ DEF_OP(VSQXTUNPair) { auto VectorUpper = GetVReg(Op->VectorUpper.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4, "Incorrect size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { // This combines the SVE versions of VSQXTUN/VSQXTUN2. @@ -4524,8 +4367,7 @@ DEF_OP(VSQXTUNPair) { if (OpSize == 8) { zip1(ARMEmitter::SubRegSize::i64Bit, Dst.Q(), VectorLower.Q(), VectorUpper.Q()); sqxtun(SubRegSize, Dst, Dst); - } - else { + } else { if (Dst == VectorUpper) { // If the destination overlaps the upper then we need to move it temporarily. mov(VTMP1.Q(), VectorUpper.Q()); @@ -4549,11 +4391,11 @@ DEF_OP(VSRSHR) { const auto BitShift = Op->BitShift; LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -4566,8 +4408,7 @@ DEF_OP(VSRSHR) { } else { if (OpSize == 8) { srshr(SubRegSize, Dst.D(), Vector.D(), BitShift); - } - else { + } else { srshr(SubRegSize, Dst.Q(), Vector.Q(), BitShift); } } @@ -4585,11 +4426,11 @@ DEF_OP(VSQSHL) { const auto BitShift = Op->BitShift; LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -4602,8 +4443,7 @@ DEF_OP(VSQSHL) { } else { if (OpSize == 8) { sqshl(SubRegSize, Dst.D(), Vector.D(), BitShift); - } - else { + } else { sqshl(SubRegSize, Dst.Q(), Vector.Q(), BitShift); } } @@ -4621,11 +4461,11 @@ DEF_OP(VMul) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { mul(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); @@ -4646,10 +4486,10 @@ DEF_OP(VUMull) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { umullb(SubRegSize, VTMP1.Z(), Vector1.Z(), Vector2.Z()); @@ -4672,10 +4512,10 @@ DEF_OP(VSMull) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { smullb(SubRegSize, VTMP1.Z(), Vector1.Z(), Vector2.Z()); @@ -4698,10 +4538,10 @@ DEF_OP(VUMull2) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { umullb(SubRegSize, VTMP1.Z(), Vector1.Z(), Vector2.Z()); @@ -4724,10 +4564,10 @@ DEF_OP(VSMull2) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { smullb(SubRegSize, VTMP1.Z(), Vector1.Z(), Vector2.Z()); @@ -4751,46 +4591,40 @@ DEF_OP(VUMulH) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit; - const auto SubRegSizeLarger = - ElementSize == 1 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSizeLarger = ElementSize == 1 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { umulh(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); - } - else if (HostSupportsSVE128 && Is128Bit) { + } else if (HostSupportsSVE128 && Is128Bit) { if (HostSupportsSVE256) { // Do predicated to ensure upper-bits get zero as expected const auto Mask = PRED_TMP_16B.Merging(); if (Dst == Vector1) { umulh(SubRegSize, Dst.Z(), Mask, Dst.Z(), Vector2.Z()); - } - else if (Dst == Vector2) { + } else if (Dst == Vector2) { umulh(SubRegSize, Dst.Z(), Mask, Dst.Z(), Vector1.Z()); - } - else { + } else { // Destination register doesn't overlap either source. // NOTE: SVE umulh (predicated) is a destructive operation. movprfx(Dst.Z(), Vector1.Z()); umulh(SubRegSize, Dst.Z(), Mask, Dst.Z(), Vector2.Z()); } - } - else { + } else { umulh(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); } - } - else if (OpSize == 8) { + } else if (OpSize == 8) { umull(SubRegSizeLarger, Dst.D(), Vector1.D(), Vector2.D()); shrn(SubRegSize, Dst.D(), Dst.D(), ElementSize * 8); - } - else { + } else { // ASIMD doesn't have a umulh. Need to emulate. umull2(SubRegSizeLarger, VTMP1.Q(), Vector1.Q(), Vector2.Q()); umull(SubRegSizeLarger, Dst.D(), Vector1.D(), Vector2.D()); @@ -4811,46 +4645,40 @@ DEF_OP(VSMulH) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit; - const auto SubRegSizeLarger = - ElementSize == 1 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSizeLarger = ElementSize == 1 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { smulh(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); - } - else if (HostSupportsSVE128 && Is128Bit) { + } else if (HostSupportsSVE128 && Is128Bit) { if (HostSupportsSVE256) { // Do predicated to ensure upper-bits get zero as expected const auto Mask = PRED_TMP_16B.Merging(); if (Dst == Vector1) { smulh(SubRegSize, Dst.Z(), Mask, Dst.Z(), Vector2.Z()); - } - else if (Dst == Vector2) { + } else if (Dst == Vector2) { smulh(SubRegSize, Dst.Z(), Mask, Dst.Z(), Vector1.Z()); - } - else { + } else { // Destination register doesn't overlap either source. // NOTE: SVE umulh (predicated) is a destructive operation. movprfx(Dst.Z(), Vector1.Z()); smulh(SubRegSize, Dst.Z(), Mask, Dst.Z(), Vector2.Z()); } - } - else { + } else { smulh(SubRegSize, Dst.Z(), Vector1.Z(), Vector2.Z()); } - } - else if (OpSize == 8) { + } else if (OpSize == 8) { smull(SubRegSizeLarger, Dst.D(), Vector1.D(), Vector2.D()); shrn(SubRegSize, Dst.D(), Dst.D(), ElementSize * 8); - } - else { + } else { // ASIMD doesn't have a umulh. Need to emulate. smull2(SubRegSizeLarger, VTMP1.Q(), Vector1.Q(), Vector2.Q()); smull(SubRegSizeLarger, Dst.D(), Vector1.D(), Vector2.D()); @@ -4870,10 +4698,10 @@ DEF_OP(VUABDL) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { // To mimic the behavior of AdvSIMD UABDL, we need to get the @@ -4901,10 +4729,10 @@ DEF_OP(VUABDL2) { const auto Vector2 = GetVReg(Op->Vector2.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : - ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ElementSize == 8 ? ARMEmitter::SubRegSize::i64Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { // To mimic the behavior of AdvSIMD UABDL, we need to get the @@ -4929,24 +4757,21 @@ DEF_OP(VTBL1) { const auto VectorTable = GetVReg(Op->VectorTable.ID()); switch (OpSize) { - case 8: { - tbl(Dst.D(), VectorTable.Q(), VectorIndices.D()); - break; - } - case 16: { - tbl(Dst.Q(), VectorTable.Q(), VectorIndices.Q()); - break; - } - case 32: { - LOGMAN_THROW_AA_FMT(HostSupportsSVE256, - "Host does not support SVE. Cannot perform 256-bit table lookup"); + case 8: { + tbl(Dst.D(), VectorTable.Q(), VectorIndices.D()); + break; + } + case 16: { + tbl(Dst.Q(), VectorTable.Q(), VectorIndices.Q()); + break; + } + case 32: { + LOGMAN_THROW_AA_FMT(HostSupportsSVE256, "Host does not support SVE. Cannot perform 256-bit table lookup"); - tbl(ARMEmitter::SubRegSize::i8Bit, Dst.Z(), VectorTable.Z(), VectorIndices.Z()); - break; - } - default: - LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); - break; + tbl(ARMEmitter::SubRegSize::i8Bit, Dst.Z(), VectorTable.Z(), VectorIndices.Z()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); break; } } @@ -4964,37 +4789,32 @@ DEF_OP(VTBL2) { if (OpSize == 32) { mov(VTMP1.Z(), VectorTable1.Z()); mov(VTMP2.Z(), VectorTable2.Z()); - } - else { + } else { mov(VTMP1.Q(), VectorTable1.Q()); mov(VTMP2.Q(), VectorTable2.Q()); } - static_assert(ARMEmitter::AreVectorsSequential(VTMP1, VTMP2), - "VTMP1 and VTMP2 must be sequential in order to use double-table TBL"); + static_assert(ARMEmitter::AreVectorsSequential(VTMP1, VTMP2), "VTMP1 and VTMP2 must be sequential in order to use double-table TBL"); VectorTable1 = VTMP1; VectorTable2 = VTMP2; } switch (OpSize) { - case 8: { - tbl(Dst.D(), VectorTable1.Q(), VectorTable2.Q(), VectorIndices.D()); - break; - } - case 16: { - tbl(Dst.Q(), VectorTable1.Q(), VectorTable2.Q(), VectorIndices.Q()); - break; - } - case 32: { - LOGMAN_THROW_AA_FMT(HostSupportsSVE256, - "Host does not support SVE. Cannot perform 256-bit table lookup"); + case 8: { + tbl(Dst.D(), VectorTable1.Q(), VectorTable2.Q(), VectorIndices.D()); + break; + } + case 16: { + tbl(Dst.Q(), VectorTable1.Q(), VectorTable2.Q(), VectorIndices.Q()); + break; + } + case 32: { + LOGMAN_THROW_AA_FMT(HostSupportsSVE256, "Host does not support SVE. Cannot perform 256-bit table lookup"); - tbl(ARMEmitter::SubRegSize::i8Bit, Dst.Z(), VectorTable1.Z(), VectorTable2.Z(), VectorIndices.Z()); - break; - } - default: - LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); - break; + tbl(ARMEmitter::SubRegSize::i8Bit, Dst.Z(), VectorTable1.Z(), VectorTable2.Z(), VectorIndices.Z()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); break; } } @@ -5009,50 +4829,44 @@ DEF_OP(VTBX1) { if (Dst != VectorSrcDst) { switch (OpSize) { - case 8: { - mov(VTMP1.D(), VectorSrcDst.D()); - tbx(VTMP1.D(), VectorTable.Q(), VectorIndices.D()); - mov(Dst.D(), VTMP1.D()); - break; - } - case 16: { - mov(VTMP1.Q(), VectorSrcDst.Q()); - tbx(VTMP1.Q(), VectorTable.Q(), VectorIndices.Q()); - mov(Dst.Q(), VTMP1.Q()); - break; - } - case 32: { - LOGMAN_THROW_AA_FMT(HostSupportsSVE256, - "Host does not support SVE. Cannot perform 256-bit table lookup"); - mov(VTMP1.Z(), VectorSrcDst.Z()); - tbx(ARMEmitter::SubRegSize::i8Bit, VTMP1.Z(), VectorTable.Z(), VectorIndices.Z()); - mov(Dst.Z(), VTMP1.Z()); - break; - } - default: - LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); - break; + case 8: { + mov(VTMP1.D(), VectorSrcDst.D()); + tbx(VTMP1.D(), VectorTable.Q(), VectorIndices.D()); + mov(Dst.D(), VTMP1.D()); + break; + } + case 16: { + mov(VTMP1.Q(), VectorSrcDst.Q()); + tbx(VTMP1.Q(), VectorTable.Q(), VectorIndices.Q()); + mov(Dst.Q(), VTMP1.Q()); + break; + } + case 32: { + LOGMAN_THROW_AA_FMT(HostSupportsSVE256, "Host does not support SVE. Cannot perform 256-bit table lookup"); + mov(VTMP1.Z(), VectorSrcDst.Z()); + tbx(ARMEmitter::SubRegSize::i8Bit, VTMP1.Z(), VectorTable.Z(), VectorIndices.Z()); + mov(Dst.Z(), VTMP1.Z()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); break; } } else { switch (OpSize) { - case 8: { - tbx(VectorSrcDst.D(), VectorTable.Q(), VectorIndices.D()); - break; - } - case 16: { - tbx(VectorSrcDst.Q(), VectorTable.Q(), VectorIndices.Q()); - break; - } - case 32: { - LOGMAN_THROW_AA_FMT(HostSupportsSVE256, - "Host does not support SVE. Cannot perform 256-bit table lookup"); + case 8: { + tbx(VectorSrcDst.D(), VectorTable.Q(), VectorIndices.D()); + break; + } + case 16: { + tbx(VectorSrcDst.Q(), VectorTable.Q(), VectorIndices.Q()); + break; + } + case 32: { + LOGMAN_THROW_AA_FMT(HostSupportsSVE256, "Host does not support SVE. Cannot perform 256-bit table lookup"); - tbx(ARMEmitter::SubRegSize::i8Bit, VectorSrcDst.Z(), VectorTable.Z(), VectorIndices.Z()); - break; - } - default: - LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); - break; + tbx(ARMEmitter::SubRegSize::i8Bit, VectorSrcDst.Z(), VectorTable.Z(), VectorIndices.Z()); + break; + } + default: LOGMAN_MSG_A_FMT("Unknown OpSize: {}", OpSize); break; } } } @@ -5068,30 +4882,26 @@ DEF_OP(VRev32) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i16Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i16Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); switch (ElementSize) { - case 1: { - revb(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Vector.Z()); - break; - } - case 2: { - revh(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Vector.Z()); - break; - } - default: - LOGMAN_MSG_A_FMT("Invalid Element Size: {}", ElementSize); - break; + case 1: { + revb(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Vector.Z()); + break; + } + case 2: { + revh(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), Mask, Vector.Z()); + break; + } + default: LOGMAN_MSG_A_FMT("Invalid Element Size: {}", ElementSize); break; } } else { if (OpSize == 8) { rev32(SubRegSize, Dst.D(), Vector.D()); - } - else { + } else { rev32(SubRegSize, Dst.Q(), Vector.Q()); } } @@ -5109,36 +4919,33 @@ DEF_OP(VRev64) { const auto Vector = GetVReg(Op->Vector.ID()); LOGMAN_THROW_AA_FMT(ElementSize == 1 || ElementSize == 2 || ElementSize == 4, "Invalid size"); - const auto SubRegSize = - ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i8Bit; + const auto SubRegSize = ElementSize == 1 ? ARMEmitter::SubRegSize::i8Bit : + ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i8Bit; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); switch (ElementSize) { - case 1: { - revb(ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Vector.Z()); - break; - } - case 2: { - revh(ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Vector.Z()); - break; - } - case 4: { - revw(ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Vector.Z()); - break; - } - default: - LOGMAN_MSG_A_FMT("Invalid Element Size: {}", ElementSize); - break; + case 1: { + revb(ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Vector.Z()); + break; + } + case 2: { + revh(ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Vector.Z()); + break; + } + case 4: { + revw(ARMEmitter::SubRegSize::i64Bit, Dst.Z(), Mask, Vector.Z()); + break; + } + default: LOGMAN_MSG_A_FMT("Invalid Element Size: {}", ElementSize); break; } } else { if (OpSize == 8) { rev64(SubRegSize, Dst.D(), Vector.D()); - } - else { + } else { rev64(SubRegSize, Dst.Q(), Vector.Q()); } } @@ -5157,11 +4964,10 @@ DEF_OP(VFCADD) { LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size"); LOGMAN_THROW_A_FMT(Op->Rotate == 90 || Op->Rotate == 270, "Invalidate Rotate"); - const auto SubRegSize = - ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : - ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit; - const auto Rotate = - Op->Rotate == 90 ? ARMEmitter::Rotation::ROTATE_90 : ARMEmitter::Rotation::ROTATE_270; + const auto SubRegSize = ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit : + ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : + ARMEmitter::SubRegSize::i64Bit; + const auto Rotate = Op->Rotate == 90 ? ARMEmitter::Rotation::ROTATE_90 : ARMEmitter::Rotation::ROTATE_270; if (HostSupportsSVE256 && Is256Bit) { const auto Mask = PRED_TMP_32B.Merging(); @@ -5184,13 +4990,11 @@ DEF_OP(VFCADD) { } else { if (OpSize == 8) { fcadd(SubRegSize, Dst.D(), Vector1.D(), Vector2.D(), Rotate); - } - else { + } else { fcadd(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q(), Rotate); } } } #undef DEF_OP -} - +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/JIT/JITCore.h b/FEXCore/Source/Interface/Core/JIT/JITCore.h index cc3b79317..85c43b9dc 100644 --- a/FEXCore/Source/Interface/Core/JIT/JITCore.h +++ b/FEXCore/Source/Interface/Core/JIT/JITCore.h @@ -15,8 +15,8 @@ struct InternalThreadState; namespace FEXCore::CPU { class CPUBackend; -[[nodiscard]] fextl::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, - FEXCore::Core::InternalThreadState *Thread); +[[nodiscard]] +fextl::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl* ctx, FEXCore::Core::InternalThreadState* Thread); CPUBackendFeatures GetArm64JITBackendFeatures(); } // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/LookupCache.cpp b/FEXCore/Source/Interface/Core/LookupCache.cpp index 03c3123c9..1deefdb7d 100644 --- a/FEXCore/Source/Interface/Core/LookupCache.cpp +++ b/FEXCore/Source/Interface/Core/LookupCache.cpp @@ -13,8 +13,8 @@ $end_info$ #include "Interface/Core/LookupCache.h" namespace FEXCore { -LookupCache::LookupCache(FEXCore::Context::ContextImpl *CTX) - : BlockLinks_mbr { fextl::pmr::get_default_resource() } +LookupCache::LookupCache(FEXCore::Context::ContextImpl* CTX) + : BlockLinks_mbr {fextl::pmr::get_default_resource()} , ctx {CTX} { TotalCacheSize = ctx->Config.VirtualMemSize / 4096 * 8 + CODE_SIZE + L1_SIZE; @@ -78,5 +78,4 @@ void LookupCache::ClearCache() { BlockList.clear(); } -} - +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/LookupCache.h b/FEXCore/Source/Interface/Core/LookupCache.h index c1b91ead6..32130e78a 100644 --- a/FEXCore/Source/Interface/Core/LookupCache.h +++ b/FEXCore/Source/Interface/Core/LookupCache.h @@ -26,12 +26,12 @@ public: uintptr_t GuestCode; }; - LookupCache(FEXCore::Context::ContextImpl *CTX); + LookupCache(FEXCore::Context::ContextImpl* CTX); ~LookupCache(); uintptr_t FindBlock(uint64_t Address) { // Try L1, no lock needed - auto &L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; + auto& L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; if (L1Entry.GuestCode == Address) { return L1Entry.HostCode; } @@ -40,7 +40,7 @@ public: std::lock_guard lk(WriteLock); // Try L2 - const auto PageIndex = (Address & (VirtualMemSize -1)) >> 12; + const auto PageIndex = (Address & (VirtualMemSize - 1)) >> 12; const auto PageOffset = Address & (0x0FFF); const auto Pointers = reinterpret_cast(PagePointer); @@ -51,8 +51,7 @@ public: // Find there pointer for the address in the blocks auto BlockPointers = reinterpret_cast(LocalPagePointer); - if (BlockPointers[PageOffset].GuestCode == Address) - { + if (BlockPointers[PageOffset].GuestCode == Address) { L1Entry.GuestCode = Address; L1Entry.HostCode = BlockPointers[PageOffset].HostCode; return L1Entry.HostCode; @@ -74,7 +73,7 @@ public: #ifdef _M_ARM_64EC bool CheckPageEC(uint64_t Address) { if (!RtlIsEcCode(Address)) { - return false; + return false; } std::lock_guard lk(WriteLock); @@ -82,7 +81,7 @@ public: // Mark L2 entry for this page as EC by setting the LSB, this can then be // checked by the dispatcher to see if it needs to perform a call/return to // EC code. - const auto PageIndex = (Address & (VirtualMemSize -1)) >> 12; + const auto PageIndex = (Address & (VirtualMemSize - 1)) >> 12; const auto Pointers = reinterpret_cast(PagePointer); Pointers[PageIndex] |= 1; return true; @@ -98,8 +97,8 @@ public: bool rv = false; - for (auto CurrentPage = Start >> 12, EndPage = (Start + Length -1) >> 12; CurrentPage <= EndPage; CurrentPage++) { - auto &CodePage = CodePages[CurrentPage]; + for (auto CurrentPage = Start >> 12, EndPage = (Start + Length - 1) >> 12; CurrentPage <= EndPage; CurrentPage++) { + auto& CodePage = CodePages[CurrentPage]; rv |= CodePage.size() == 0; CodePage.push_back(Address); } @@ -108,7 +107,7 @@ public: } // Adds to Guest -> Host code mapping - void AddBlockMapping(uint64_t Address, void *HostCode) { + void AddBlockMapping(uint64_t Address, void* HostCode) { std::lock_guard lk(WriteLock); [[maybe_unused]] auto Inserted = BlockList.emplace(Address, (uintptr_t)HostCode).second; @@ -116,18 +115,18 @@ public: // There is no need to update L1 or L2, they will get updated on first lookup // However, adding to L1 here increases performance - auto &L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; + auto& L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; L1Entry.GuestCode = Address; L1Entry.HostCode = (uintptr_t)HostCode; } - void Erase(FEXCore::Core::CpuStateFrame *Frame, uint64_t Address) { + void Erase(FEXCore::Core::CpuStateFrame* Frame, uint64_t Address) { std::lock_guard lk(WriteLock); // Sever any links to this block auto lower = BlockLinks->lower_bound({Address, nullptr}); - auto upper = BlockLinks->upper_bound({Address, reinterpret_cast(UINTPTR_MAX)}); + auto upper = BlockLinks->upper_bound({Address, reinterpret_cast(UINTPTR_MAX)}); for (auto it = lower; it != upper; it = BlockLinks->erase(it)) { it->second(Frame, it->first.HostLink); } @@ -136,7 +135,7 @@ public: BlockList.erase(Address); // Do L1 - auto &L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; + auto& L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; if (L1Entry.GuestCode == Address) { L1Entry.GuestCode = 0; // Leave L1Entry.HostCode as is, so that concurrent lookups won't read a null pointer @@ -145,11 +144,11 @@ public: } // Do full map - Address = Address & (VirtualMemSize -1); + Address = Address & (VirtualMemSize - 1); uint64_t PageOffset = Address & (0x0FFF); Address >>= 12; - uintptr_t *Pointers = reinterpret_cast(PagePointer); + uintptr_t* Pointers = reinterpret_cast(PagePointer); uint64_t LocalPagePointer = Pointers[Address]; if (!LocalPagePointer) { // Page for this code didn't even exist, nothing to do @@ -162,7 +161,7 @@ public: BlockPointers[PageOffset].HostCode = 0; } - void AddBlockLink(uint64_t GuestDestination, FEXCore::Context::ExitFunctionLinkData * HostLink, const FEXCore::Context::BlockDelinkerFunc &delinker) { + void AddBlockLink(uint64_t GuestDestination, FEXCore::Context::ExitFunctionLinkData* HostLink, const FEXCore::Context::BlockDelinkerFunc& delinker) { std::lock_guard lk(WriteLock); BlockLinks->insert({{GuestDestination, HostLink}, delinker}); @@ -171,9 +170,15 @@ public: void ClearCache(); void ClearL2Cache(); - uintptr_t GetL1Pointer() const { return L1Pointer; } - uintptr_t GetPagePointer() const { return PagePointer; } - uintptr_t GetVirtualMemorySize() const { return VirtualMemSize; } + uintptr_t GetL1Pointer() const { + return L1Pointer; + } + uintptr_t GetPagePointer() const { + return PagePointer; + } + uintptr_t GetVirtualMemorySize() const { + return VirtualMemSize; + } constexpr static size_t L1_ENTRIES = 1 * 1024 * 1024; // Must be a power of 2 constexpr static size_t L1_ENTRIES_MASK = L1_ENTRIES - 1; @@ -190,17 +195,17 @@ public: private: void CacheBlockMapping(uint64_t Address, uintptr_t HostCode) { // Do L1 - auto &L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; + auto& L1Entry = reinterpret_cast(L1Pointer)[Address & L1_ENTRIES_MASK]; L1Entry.GuestCode = Address; L1Entry.HostCode = HostCode; // Do ful map auto FullAddress = Address; - Address = Address & (VirtualMemSize -1); + Address = Address & (VirtualMemSize - 1); uint64_t PageOffset = Address & (0x0FFF); Address >>= 12; - uintptr_t *Pointers = reinterpret_cast(PagePointer); + uintptr_t* Pointers = reinterpret_cast(PagePointer); uint64_t LocalPagePointer = Pointers[Address]; if (!LocalPagePointer) { // We don't have a page pointer for this address @@ -244,15 +249,16 @@ private: struct BlockLinkTag { uint64_t GuestDestination; - FEXCore::Context::ExitFunctionLinkData *HostLink; + FEXCore::Context::ExitFunctionLinkData* HostLink; - bool operator <(const BlockLinkTag& other) const { - if (GuestDestination < other.GuestDestination) + bool operator<(const BlockLinkTag& other) const { + if (GuestDestination < other.GuestDestination) { return true; - else if (GuestDestination == other.GuestDestination) + } else if (GuestDestination == other.GuestDestination) { return HostLink < other.HostLink; - else + } else { return false; + } } }; @@ -265,7 +271,7 @@ private: std::pmr::monotonic_buffer_resource BlockLinks_mbr; using BlockLinksMapType = std::pmr::map; fextl::unique_ptr> BlockLinks_pma; - BlockLinksMapType *BlockLinks; + BlockLinksMapType* BlockLinks; fextl::robin_map BlockList; @@ -277,7 +283,7 @@ private: size_t AllocateOffset {}; - FEXCore::Context::ContextImpl *ctx; - uint64_t VirtualMemSize{}; + FEXCore::Context::ContextImpl* ctx; + uint64_t VirtualMemSize {}; }; -} +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/ObjectCache/CodeObjectSerializationConfig.h b/FEXCore/Source/Interface/Core/ObjectCache/CodeObjectSerializationConfig.h index 200e3f997..499d2f060 100644 --- a/FEXCore/Source/Interface/Core/ObjectCache/CodeObjectSerializationConfig.h +++ b/FEXCore/Source/Interface/Core/ObjectCache/CodeObjectSerializationConfig.h @@ -6,79 +6,81 @@ #include namespace FEXCore::CodeSerialize { - // If any of the config options mismatch on load then the cache won't be used - // Any of these will result in codegen changes - struct - FEX_PACKED - CodeObjectSerializationConfig { - // Cookie in the header of the file, isn't part of the config hash - uint64_t Cookie{}; +// If any of the config options mismatch on load then the cache won't be used +// Any of these will result in codegen changes +struct FEX_PACKED CodeObjectSerializationConfig { + // Cookie in the header of the file, isn't part of the config hash + uint64_t Cookie {}; - // Instructions per block configuration - int32_t MaxInstPerBlock{}; + // Instructions per block configuration + int32_t MaxInstPerBlock {}; - // Follows CPUID 4000_0001_EAX[3:0] - unsigned Arch : 4; + // Follows CPUID 4000_0001_EAX[3:0] + unsigned Arch : 4; - // Multiblock enabled - unsigned MultiBlock : 1; + // Multiblock enabled + unsigned MultiBlock : 1; - // Hardware TSO enabled - unsigned HardwareTSOEnabled : 1; + // Hardware TSO enabled + unsigned HardwareTSOEnabled : 1; - // TSO enabled - unsigned TSOEnabled : 1; + // TSO enabled + unsigned TSOEnabled : 1; - // ABI local flag unsafe optimization - unsigned ABILocalFlags : 1; + // ABI local flag unsafe optimization + unsigned ABILocalFlags : 1; - // Paranoid TSO mode enabled - unsigned ParanoidTSO : 1; + // Paranoid TSO mode enabled + unsigned ParanoidTSO : 1; - // Guest code execution mode (We don't support live mode switch) - unsigned Is64BitMode : 1; + // Guest code execution mode (We don't support live mode switch) + unsigned Is64BitMode : 1; - // SMC checks style - unsigned SMCChecks : 2; + // SMC checks style + unsigned SMCChecks : 2; - // x87 reduced precision - unsigned x87ReducedPrecision : 1; + // x87 reduced precision + unsigned x87ReducedPrecision : 1; - // Padding to remove uninitialized data warning from asan - // Shows remaining amount of bits available for config - unsigned _Pad : 19; + // Padding to remove uninitialized data warning from asan + // Shows remaining amount of bits available for config + unsigned _Pad : 19; - bool operator==(CodeObjectSerializationConfig const &other) const { - return Cookie == other.Cookie && - MaxInstPerBlock == other.MaxInstPerBlock && - Arch == other.Arch && - MultiBlock == other.MultiBlock && - HardwareTSOEnabled == other.HardwareTSOEnabled && - TSOEnabled == other.TSOEnabled && - ABILocalFlags == other.ABILocalFlags && - ParanoidTSO == other.ParanoidTSO && - Is64BitMode == other.Is64BitMode && - SMCChecks == other.SMCChecks && - x87ReducedPrecision == other.x87ReducedPrecision; - } - static uint64_t GetHash(CodeObjectSerializationConfig const &other) { - // For < 64-bits of data just pack directly - // Skip the cookie - uint64_t Hash{}; - Hash <<= 32; Hash |= other.MaxInstPerBlock; - Hash <<= 1; Hash |= other.Arch; - Hash <<= 1; Hash |= other.MultiBlock; - Hash <<= 1; Hash |= other.HardwareTSOEnabled; - Hash <<= 1; Hash |= other.TSOEnabled; - Hash <<= 1; Hash |= other.ABILocalFlags; - Hash <<= 1; Hash |= other.ParanoidTSO; - Hash <<= 1; Hash |= other.Is64BitMode; - Hash <<= 2; Hash |= other.SMCChecks; - Hash <<= 1; Hash |= other.x87ReducedPrecision; - return Hash; - } - }; + bool operator==(const CodeObjectSerializationConfig& other) const { + return Cookie == other.Cookie && MaxInstPerBlock == other.MaxInstPerBlock && Arch == other.Arch && MultiBlock == other.MultiBlock && + HardwareTSOEnabled == other.HardwareTSOEnabled && TSOEnabled == other.TSOEnabled && ABILocalFlags == other.ABILocalFlags && + ParanoidTSO == other.ParanoidTSO && Is64BitMode == other.Is64BitMode && SMCChecks == other.SMCChecks && + x87ReducedPrecision == other.x87ReducedPrecision; + } + static uint64_t GetHash(const CodeObjectSerializationConfig& other) { + // For < 64-bits of data just pack directly + // Skip the cookie + uint64_t Hash {}; + Hash <<= 32; + Hash |= other.MaxInstPerBlock; + Hash <<= 1; + Hash |= other.Arch; + Hash <<= 1; + Hash |= other.MultiBlock; + Hash <<= 1; + Hash |= other.HardwareTSOEnabled; + Hash <<= 1; + Hash |= other.TSOEnabled; + Hash <<= 1; + Hash |= other.ABILocalFlags; + Hash <<= 1; + Hash |= other.ParanoidTSO; + Hash <<= 1; + Hash |= other.Is64BitMode; + Hash <<= 2; + Hash |= other.SMCChecks; + Hash <<= 1; + Hash |= other.x87ReducedPrecision; + return Hash; + } +}; - static_assert(sizeof(CodeObjectSerializationConfig) == 16, "Size changed"); - static_assert((sizeof(CodeObjectSerializationConfig) - sizeof(uint64_t)) == 8, "Config size exceeded 64its. Need to change how the hash is generated!"); -} +static_assert(sizeof(CodeObjectSerializationConfig) == 16, "Size changed"); +static_assert((sizeof(CodeObjectSerializationConfig) - sizeof(uint64_t)) == 8, "Config size exceeded 64its. Need to change how the hash is " + "generated!"); +} // namespace FEXCore::CodeSerialize diff --git a/FEXCore/Source/Interface/Core/ObjectCache/JobHandling.cpp b/FEXCore/Source/Interface/Core/ObjectCache/JobHandling.cpp index 9f5ea8eb0..7b81cc144 100644 --- a/FEXCore/Source/Interface/Core/ObjectCache/JobHandling.cpp +++ b/FEXCore/Source/Interface/Core/ObjectCache/JobHandling.cpp @@ -11,120 +11,112 @@ #include namespace FEXCore::CodeSerialize { - void AsyncJobHandler::AsyncAddNamedRegionJob(uintptr_t Base, uintptr_t Size, uintptr_t Offset, const fextl::string &filename) { +void AsyncJobHandler::AsyncAddNamedRegionJob(uintptr_t Base, uintptr_t Size, uintptr_t Offset, const fextl::string& filename) { #ifndef _WIN32 - // This function adds a named region *JOB* to our named region handler - // This needs to be as fast as possible to keep out of the way of the JIT + // This function adds a named region *JOB* to our named region handler + // This needs to be as fast as possible to keep out of the way of the JIT - const fextl::string BaseFilename = FHU::Filesystem::GetFilename(filename); + const fextl::string BaseFilename = FHU::Filesystem::GetFilename(filename); - if (!BaseFilename.empty()) { - // Create a new entry that once set up will be put in to our section object map - auto Entry = fextl::make_unique( - Base, - Size, - Offset, - filename, - NamedRegionHandler->DefaultCodeHeader(Base, Offset) - ); + if (!BaseFilename.empty()) { + // Create a new entry that once set up will be put in to our section object map + auto Entry = fextl::make_unique(Base, Size, Offset, filename, NamedRegionHandler->DefaultCodeHeader(Base, Offset)); - // Lock the job ref counter so we can block anything attempting to use the entry before it is loaded - Entry->NamedJobRefCountMutex.lock(); + // Lock the job ref counter so we can block anything attempting to use the entry before it is loaded + Entry->NamedJobRefCountMutex.lock(); - CodeRegionMapType::iterator EntryIterator; - { - std::unique_lock lk {CodeObjectCacheService->GetEntryMapMutex()}; - - auto &EntryMap = CodeObjectCacheService->GetEntryMap(); - - auto it = EntryMap.emplace(Base, std::move(Entry)); - if (!it.second) { - // This happens when an application overwrites a previous region without unmapping what was there - - // Lock this entry's Named job reference counter. - // Once this passes then we know that this section has been loaded. - it.first->second->NamedJobRefCountMutex.lock(); - - // Finalize anything the region needs to do first. - CodeObjectCacheService->DoCodeRegionClosure(it.first->second->Base, it.first->second.get()); - - // munmap the file that was mapped - FEXCore::Allocator::munmap(it.first->second->CodeData, it.first->second->FileSize); - - // Remove this entry from the unrelocated map as well - { - std::unique_lock lk2 {CodeObjectCacheService->GetUnrelocatedEntryMapMutex()}; - CodeObjectCacheService->GetUnrelocatedEntryMap().erase(it.first->second->EntryHeader.OriginalBase); - } - - // Now overwrite the entry in the map - it = EntryMap.insert_or_assign(Base, std::move(Entry)); - EntryIterator = it.first; - } - else { - // No overwrite, just insert - EntryIterator = it.first; - } - } - - // Now that this entry has been added to the map, we can insert a load job using the entry iterator. - // This allows us to quickly unblock the JIT thread when it is loading multiple regions and have the async thread - // do the loading for us. - // - // Create the async work queue job now so it can load - NamedRegionHandler->AsyncAddNamedRegionWorkItem(BaseFilename, filename, true, EntryIterator); - - // Tell the async thread that it has work to do - CodeObjectCacheService->NotifyWork(); - } -#endif - } - - void AsyncJobHandler::AsyncRemoveNamedRegionJob(uintptr_t Base, uintptr_t Size) { -#ifndef _WIN32 - // Removing a named region through the job system - // We need to find the entry that we are deleting first - fextl::unique_ptr EntryPointer; + CodeRegionMapType::iterator EntryIterator; { std::unique_lock lk {CodeObjectCacheService->GetEntryMapMutex()}; - auto &EntryMap = CodeObjectCacheService->GetEntryMap(); - auto it = EntryMap.find(Base); - if (it != EntryMap.end()) { - // Lock the job ref counter since we are erasing it - // Once this passes it will have been loaded - it->second->NamedJobRefCountMutex.lock(); + auto& EntryMap = CodeObjectCacheService->GetEntryMap(); - // Take the pointer from the map - EntryPointer = std::move(it->second); + auto it = EntryMap.emplace(Base, std::move(Entry)); + if (!it.second) { + // This happens when an application overwrites a previous region without unmapping what was there - // We can now unmap the file data - FEXCore::Allocator::munmap(EntryPointer->CodeData, EntryPointer->FileSize); + // Lock this entry's Named job reference counter. + // Once this passes then we know that this section has been loaded. + it.first->second->NamedJobRefCountMutex.lock(); - // Remove this from the entry map - EntryMap.erase(it); + // Finalize anything the region needs to do first. + CodeObjectCacheService->DoCodeRegionClosure(it.first->second->Base, it.first->second.get()); + + // munmap the file that was mapped + FEXCore::Allocator::munmap(it.first->second->CodeData, it.first->second->FileSize); // Remove this entry from the unrelocated map as well { std::unique_lock lk2 {CodeObjectCacheService->GetUnrelocatedEntryMapMutex()}; - CodeObjectCacheService->GetUnrelocatedEntryMap().erase(EntryPointer->EntryHeader.OriginalBase); + CodeObjectCacheService->GetUnrelocatedEntryMap().erase(it.first->second->EntryHeader.OriginalBase); } - } - else { - // Tried to remove something that wasn't in our code object tracking - return; - } - // Create the async work queue job now so it can finalize what it needs to do - NamedRegionHandler->AsyncRemoveNamedRegionWorkItem(Base, Size, std::move(EntryPointer)); - - // Tell the async thread that it has work to do - CodeObjectCacheService->NotifyWork(); + // Now overwrite the entry in the map + it = EntryMap.insert_or_assign(Base, std::move(Entry)); + EntryIterator = it.first; + } else { + // No overwrite, just insert + EntryIterator = it.first; + } } -#endif - } - void AsyncJobHandler::AsyncAddSerializationJob(fextl::unique_ptr Data) { - // XXX: Actually add serialization job + // Now that this entry has been added to the map, we can insert a load job using the entry iterator. + // This allows us to quickly unblock the JIT thread when it is loading multiple regions and have the async thread + // do the loading for us. + // + // Create the async work queue job now so it can load + NamedRegionHandler->AsyncAddNamedRegionWorkItem(BaseFilename, filename, true, EntryIterator); + + // Tell the async thread that it has work to do + CodeObjectCacheService->NotifyWork(); } +#endif } + +void AsyncJobHandler::AsyncRemoveNamedRegionJob(uintptr_t Base, uintptr_t Size) { +#ifndef _WIN32 + // Removing a named region through the job system + // We need to find the entry that we are deleting first + fextl::unique_ptr EntryPointer; + { + std::unique_lock lk {CodeObjectCacheService->GetEntryMapMutex()}; + + auto& EntryMap = CodeObjectCacheService->GetEntryMap(); + auto it = EntryMap.find(Base); + if (it != EntryMap.end()) { + // Lock the job ref counter since we are erasing it + // Once this passes it will have been loaded + it->second->NamedJobRefCountMutex.lock(); + + // Take the pointer from the map + EntryPointer = std::move(it->second); + + // We can now unmap the file data + FEXCore::Allocator::munmap(EntryPointer->CodeData, EntryPointer->FileSize); + + // Remove this from the entry map + EntryMap.erase(it); + + // Remove this entry from the unrelocated map as well + { + std::unique_lock lk2 {CodeObjectCacheService->GetUnrelocatedEntryMapMutex()}; + CodeObjectCacheService->GetUnrelocatedEntryMap().erase(EntryPointer->EntryHeader.OriginalBase); + } + } else { + // Tried to remove something that wasn't in our code object tracking + return; + } + + // Create the async work queue job now so it can finalize what it needs to do + NamedRegionHandler->AsyncRemoveNamedRegionWorkItem(Base, Size, std::move(EntryPointer)); + + // Tell the async thread that it has work to do + CodeObjectCacheService->NotifyWork(); + } +#endif +} + +void AsyncJobHandler::AsyncAddSerializationJob(fextl::unique_ptr Data) { + // XXX: Actually add serialization job +} +} // namespace FEXCore::CodeSerialize diff --git a/FEXCore/Source/Interface/Core/ObjectCache/NamedRegionObjectHandler.cpp b/FEXCore/Source/Interface/Core/ObjectCache/NamedRegionObjectHandler.cpp index 3a9c11697..f2beb7d59 100644 --- a/FEXCore/Source/Interface/Core/ObjectCache/NamedRegionObjectHandler.cpp +++ b/FEXCore/Source/Interface/Core/ObjectCache/NamedRegionObjectHandler.cpp @@ -7,66 +7,67 @@ #include namespace FEXCore::CodeSerialize { - NamedRegionObjectHandler::NamedRegionObjectHandler(FEXCore::Context::ContextImpl *ctx) { - DefaultSerializationConfig.Cookie = CODE_COOKIE; +NamedRegionObjectHandler::NamedRegionObjectHandler(FEXCore::Context::ContextImpl* ctx) { + DefaultSerializationConfig.Cookie = CODE_COOKIE; - // Initialize the Arch from CPUID - uint32_t Arch = ctx->CPUID.RunFunction(0x4000'0001, 0).eax & 0xF; - DefaultSerializationConfig.Arch = Arch; + // Initialize the Arch from CPUID + uint32_t Arch = ctx->CPUID.RunFunction(0x4000'0001, 0).eax & 0xF; + DefaultSerializationConfig.Arch = Arch; - DefaultSerializationConfig.MaxInstPerBlock = ctx->Config.MaxInstPerBlock; - DefaultSerializationConfig.MultiBlock = ctx->Config.Multiblock; - DefaultSerializationConfig.TSOEnabled = ctx->Config.TSOEnabled; - DefaultSerializationConfig.ABILocalFlags = ctx->Config.ABILocalFlags; - DefaultSerializationConfig.ParanoidTSO = ctx->Config.ParanoidTSO; - DefaultSerializationConfig.Is64BitMode = ctx->Config.Is64BitMode; - DefaultSerializationConfig.SMCChecks = ctx->Config.SMCChecks; - DefaultSerializationConfig.x87ReducedPrecision = ctx->Config.x87ReducedPrecision; - } + DefaultSerializationConfig.MaxInstPerBlock = ctx->Config.MaxInstPerBlock; + DefaultSerializationConfig.MultiBlock = ctx->Config.Multiblock; + DefaultSerializationConfig.TSOEnabled = ctx->Config.TSOEnabled; + DefaultSerializationConfig.ABILocalFlags = ctx->Config.ABILocalFlags; + DefaultSerializationConfig.ParanoidTSO = ctx->Config.ParanoidTSO; + DefaultSerializationConfig.Is64BitMode = ctx->Config.Is64BitMode; + DefaultSerializationConfig.SMCChecks = ctx->Config.SMCChecks; + DefaultSerializationConfig.x87ReducedPrecision = ctx->Config.x87ReducedPrecision; +} - void NamedRegionObjectHandler::AddNamedRegionObject(CodeRegionMapType::iterator Entry, const fextl::string &base_filename, const fextl::string &filename, bool Executable) { - // XXX: Add named region objects +void NamedRegionObjectHandler::AddNamedRegionObject(CodeRegionMapType::iterator Entry, const fextl::string& base_filename, + const fextl::string& filename, bool Executable) { + // XXX: Add named region objects - // XXX: Until entry loading is complete just claim it is loaded - Entry->second->NamedJobRefCountMutex.unlock(); - } + // XXX: Until entry loading is complete just claim it is loaded + Entry->second->NamedJobRefCountMutex.unlock(); +} - void NamedRegionObjectHandler::RemoveNamedRegionObject(uintptr_t Base, uintptr_t Size, fextl::unique_ptr Entry) { - // XXX: Remove named region objects +void NamedRegionObjectHandler::RemoveNamedRegionObject(uintptr_t Base, uintptr_t Size, fextl::unique_ptr Entry) { + // XXX: Remove named region objects - // XXX: Until entry loading is complete just claim it is loaded - Entry->NamedJobRefCountMutex.unlock(); - } + // XXX: Until entry loading is complete just claim it is loaded + Entry->NamedJobRefCountMutex.unlock(); +} - void NamedRegionObjectHandler::HandleNamedRegionObjectJobs() { - // Walk through all of our jobs sequentially until the work queue is empty - while (NamedWorkQueueJobs.load()) { - fextl::unique_ptr WorkItem; +void NamedRegionObjectHandler::HandleNamedRegionObjectJobs() { + // Walk through all of our jobs sequentially until the work queue is empty + while (NamedWorkQueueJobs.load()) { + fextl::unique_ptr WorkItem; - { - // Lock the work queue mutex for a short moment and grab an item from the list - std::unique_lock lk {NamedWorkQueueMutex}; - size_t WorkItems = WorkQueue.size(); - if (WorkItems != 0) { - WorkItem = std::move(WorkQueue.front()); - WorkQueue.pop(); - } - - // Atomically update the number of jobs - --NamedWorkQueueJobs; + { + // Lock the work queue mutex for a short moment and grab an item from the list + std::unique_lock lk {NamedWorkQueueMutex}; + size_t WorkItems = WorkQueue.size(); + if (WorkItems != 0) { + WorkItem = std::move(WorkQueue.front()); + WorkQueue.pop(); } - if (WorkItem) { - if (WorkItem->GetType() == AsyncJobHandler::NamedRegionJobType::JOB_ADD_NAMED_REGION) { - auto WorkAdd = static_cast(WorkItem.get()); - AddNamedRegionObject(WorkAdd->Entry, WorkAdd->BaseFilename, WorkAdd->Filename, WorkAdd->Executable); - } + // Atomically update the number of jobs + --NamedWorkQueueJobs; + } - if (WorkItem->GetType() == AsyncJobHandler::NamedRegionJobType::JOB_REMOVE_NAMED_REGION) { - auto WorkRemove = static_cast(WorkItem.get()); - RemoveNamedRegionObject(WorkRemove->Base, WorkRemove->Size, std::move(WorkRemove->Entry)); - } + if (WorkItem) { + if (WorkItem->GetType() == AsyncJobHandler::NamedRegionJobType::JOB_ADD_NAMED_REGION) { + auto WorkAdd = static_cast(WorkItem.get()); + AddNamedRegionObject(WorkAdd->Entry, WorkAdd->BaseFilename, WorkAdd->Filename, WorkAdd->Executable); + } + + if (WorkItem->GetType() == AsyncJobHandler::NamedRegionJobType::JOB_REMOVE_NAMED_REGION) { + auto WorkRemove = static_cast(WorkItem.get()); + RemoveNamedRegionObject(WorkRemove->Base, WorkRemove->Size, std::move(WorkRemove->Entry)); } } } } +} // namespace FEXCore::CodeSerialize diff --git a/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.cpp b/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.cpp index 5cea7b7ab..e4aaef127 100644 --- a/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.cpp +++ b/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.cpp @@ -6,80 +6,80 @@ #include namespace { - static void* ThreadHandler(void *Arg) { - FEXCore::CodeSerialize::CodeObjectSerializeService *This = reinterpret_cast(Arg); - This->ExecutionThread(); - return nullptr; - } +static void* ThreadHandler(void* Arg) { + FEXCore::CodeSerialize::CodeObjectSerializeService* This = reinterpret_cast(Arg); + This->ExecutionThread(); + return nullptr; } +} // namespace namespace FEXCore::CodeSerialize { - CodeObjectSerializeService::CodeObjectSerializeService(FEXCore::Context::ContextImpl *ctx) - : CTX {ctx} - , AsyncHandler { &NamedRegionHandler , this } - , NamedRegionHandler { ctx } { - Initialize(); +CodeObjectSerializeService::CodeObjectSerializeService(FEXCore::Context::ContextImpl* ctx) + : CTX {ctx} + , AsyncHandler {&NamedRegionHandler, this} + , NamedRegionHandler {ctx} { + Initialize(); +} + +void CodeObjectSerializeService::Shutdown() { + if (CTX->Config.CacheObjectCodeCompilation() == FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE) { + return; } - void CodeObjectSerializeService::Shutdown() { - if (CTX->Config.CacheObjectCodeCompilation() == FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE) { - return; - } + WorkerThreadShuttingDown = true; - WorkerThreadShuttingDown = true; + // Kick the working thread + WorkAvailable.NotifyAll(); - // Kick the working thread - WorkAvailable.NotifyAll(); - - if (WorkerThread->joinable()) { - // Wait for worker thread to close down - WorkerThread->join(nullptr); - } - } - - void CodeObjectSerializeService::Initialize() { - // Add a canary so we don't crash on empty map iterator handling - auto it = AddressToEntryMap.insert_or_assign(~0ULL, fextl::make_unique()); - UnrelocatedAddressToEntryMap.insert_or_assign(~0ULL, it.first->second.get()); - - uint64_t OldMask = FEXCore::Threads::SetSignalMask(~0ULL); - WorkerThread = FEXCore::Threads::Thread::Create(ThreadHandler, this); - FEXCore::Threads::SetSignalMask(OldMask); - } - - void CodeObjectSerializeService::DoCodeRegionClosure(uint64_t Base, CodeRegionEntry *it) { - if (Base == ~0ULL) { - // Don't do closure on canary - return; - } - // XXX: Do code region closure - } - - CodeObjectFileSection const *CodeObjectSerializeService::FetchCodeObjectFromCache(uint64_t GuestRIP) { - // XXX: Actually fetch code objects from cache - return nullptr; - } - - void CodeObjectSerializeService::ExecutionThread() { - // Set our thread name so we can see its relation - FEXCore::Threads::SetThreadName("ObjectCodeSeri\0"); - while (WorkerThreadShuttingDown.load() != true) { - // Wait for work - WorkAvailable.Wait(); - - // Handle named region async jobs first. Highest priority - NamedRegionHandler.HandleNamedRegionObjectJobs(); - - // XXX: Handle code serialization jobs second. - } - - // Do final code region closures on thread shutdown - for (auto &it : AddressToEntryMap) { - DoCodeRegionClosure(it.first, it.second.get()); - } - - // Safely clear our maps now - AddressToEntryMap.clear(); - UnrelocatedAddressToEntryMap.clear(); + if (WorkerThread->joinable()) { + // Wait for worker thread to close down + WorkerThread->join(nullptr); } } + +void CodeObjectSerializeService::Initialize() { + // Add a canary so we don't crash on empty map iterator handling + auto it = AddressToEntryMap.insert_or_assign(~0ULL, fextl::make_unique()); + UnrelocatedAddressToEntryMap.insert_or_assign(~0ULL, it.first->second.get()); + + uint64_t OldMask = FEXCore::Threads::SetSignalMask(~0ULL); + WorkerThread = FEXCore::Threads::Thread::Create(ThreadHandler, this); + FEXCore::Threads::SetSignalMask(OldMask); +} + +void CodeObjectSerializeService::DoCodeRegionClosure(uint64_t Base, CodeRegionEntry* it) { + if (Base == ~0ULL) { + // Don't do closure on canary + return; + } + // XXX: Do code region closure +} + +const CodeObjectFileSection* CodeObjectSerializeService::FetchCodeObjectFromCache(uint64_t GuestRIP) { + // XXX: Actually fetch code objects from cache + return nullptr; +} + +void CodeObjectSerializeService::ExecutionThread() { + // Set our thread name so we can see its relation + FEXCore::Threads::SetThreadName("ObjectCodeSeri\0"); + while (WorkerThreadShuttingDown.load() != true) { + // Wait for work + WorkAvailable.Wait(); + + // Handle named region async jobs first. Highest priority + NamedRegionHandler.HandleNamedRegionObjectJobs(); + + // XXX: Handle code serialization jobs second. + } + + // Do final code region closures on thread shutdown + for (auto& it : AddressToEntryMap) { + DoCodeRegionClosure(it.first, it.second.get()); + } + + // Safely clear our maps now + AddressToEntryMap.clear(); + UnrelocatedAddressToEntryMap.clear(); +} +} // namespace FEXCore::CodeSerialize diff --git a/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h b/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h index e5797f4cd..dc7caee24 100644 --- a/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h +++ b/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h @@ -17,445 +17,441 @@ #include namespace FEXCore::CodeSerialize { - // XXX: Does this need to be signal safe? - using CodeSerializationMutex = std::shared_mutex; - struct CodeSerializationData { - }; +// XXX: Does this need to be signal safe? +using CodeSerializationMutex = std::shared_mutex; +struct CodeSerializationData {}; - struct CodeObjectFileSection { - bool Serialized; - bool Invalid; - const CodeSerializationData *Data; - const char *HostCode; - uint64_t NumRelocations; - const char *Relocations; - }; +struct CodeObjectFileSection { + bool Serialized; + bool Invalid; + const CodeSerializationData* Data; + const char* HostCode; + uint64_t NumRelocations; + const char* Relocations; +}; + +/** + * @brief This is the file header that lives at the start of an object cache file + * + * This header is updated from multiple processes! + * Care must be taken to use OS locks when updating the file backing including this header + */ +struct CodeObjectSerializationHeader { + // The configuration that this file has + CodeObjectSerializationConfig Config; + // The original RIP that this object section was mapped at + uint64_t OriginalBase {}; + // The original offset in to the file that this object section was loaded from + uint64_t OriginalOffset {}; + // Total amount of code that should be in this file + uint64_t TotalCodeSize {}; + // Used to reserve the TSL map + uint64_t NumCodeEntries {}; + // The number of relocations that point to this section + uint64_t NumRelocationsTo {}; + // Total relocations in this file + uint64_t TotalRelocationsCount {}; +}; + +struct CodeRegionEntry { + /** + * @name Threaded initialization objects for the initial object creation + * @{ */ + // Base address in memory where the code region is at + uint64_t Base {}; + + // Size of this code entry + uint64_t Size {}; + + // The offset inside the file that is mapped to Base + uint64_t Offset {}; + + // Filename of the object + fextl::string Filename {}; + + CodeObjectSerializationHeader EntryHeader {}; + /** @} */ + + // The filename of the object cache for this entry + fextl::string ObjectEntrySourceFilename {}; + + // In the case of file corruption that we can detect, we can disable serialization early for an entry + // We should be resiliant to corruption but things happen + bool StillSerializing {true}; + + // Long lived FD for serialization if we have multiple jobs to serialize + // Bursts of code entries are common and this reduces file lock overhead + // + // Especially useful over network mounts where file locks are very slow + int CurrentSerializedFD {-1}; /** - * @brief This is the file header that lives at the start of an object cache file - * - * This header is updated from multiple processes! - * Care must be taken to use OS locks when updating the file backing including this header - */ - struct CodeObjectSerializationHeader { - // The configuration that this file has - CodeObjectSerializationConfig Config; - // The original RIP that this object section was mapped at - uint64_t OriginalBase{}; - // The original offset in to the file that this object section was loaded from - uint64_t OriginalOffset{}; - // Total amount of code that should be in this file - uint64_t TotalCodeSize{}; - // Used to reserve the TSL map - uint64_t NumCodeEntries{}; - // The number of relocations that point to this section - uint64_t NumRelocationsTo{}; - // Total relocations in this file - uint64_t TotalRelocationsCount{}; - }; + * @name Objects required to sync objects between threads + * @{ */ + // Refcount for the number of outstanding code entries waiting to be written for this object section + CodeSerializationMutex ObjectJobRefCountMutex; - struct CodeRegionEntry { - /** - * @name Threaded initialization objects for the initial object creation - * @{ */ - // Base address in memory where the code region is at - uint64_t Base{}; - - // Size of this code entry - uint64_t Size{}; - - // The offset inside the file that is mapped to Base - uint64_t Offset{}; - - // Filename of the object - fextl::string Filename{}; - - CodeObjectSerializationHeader EntryHeader{}; - /** @} */ - - // The filename of the object cache for this entry - fextl::string ObjectEntrySourceFilename{}; - - // In the case of file corruption that we can detect, we can disable serialization early for an entry - // We should be resiliant to corruption but things happen - bool StillSerializing {true}; - - // Long lived FD for serialization if we have multiple jobs to serialize - // Bursts of code entries are common and this reduces file lock overhead - // - // Especially useful over network mounts where file locks are very slow - int CurrentSerializedFD {-1}; - - /** - * @name Objects required to sync objects between threads - * @{ */ - // Refcount for the number of outstanding code entries waiting to be written for this object section - CodeSerializationMutex ObjectJobRefCountMutex; - - // Refcount for outstanding named object region entry loading itself - // Will block JIT code cache look up when this has a unique_lock held - CodeSerializationMutex NamedJobRefCountMutex; - /** @} */ - - /** - * @name Object Entry data management - * @{ */ - - /** - * @name This is the raw file data that we loaded from the code region entry file - * @{ */ - char *CodeData{}; - size_t FileSize{}; - - fextl::vector FileCodeSections; - /** @} */ - - // This per section map takes the most time to load and needs to be quick - // This is the map of all code segments for this entry - fextl::robin_map SectionLookupMap{}; - /** @} */ - - // Default initialization - CodeRegionEntry() = default; - - // Initializer specifically for threaded loading - CodeRegionEntry(uint64_t Base, - uint64_t Size, - uint64_t Offset, - fextl::string const &Filename, - CodeObjectSerializationHeader const &DefaultHeader) - : Base {Base} - , Size {Size} - , Offset {Offset} - , Filename {Filename} - , EntryHeader {DefaultHeader} { - } - }; - - // Map type must use an interator that isn't invalidation on erase/insert - using CodeRegionMapType = fextl::map>; - using CodeRegionPtrMapType = fextl::map; - - class NamedRegionObjectHandler; - class CodeObjectSerializeService; - - class AsyncJobHandler final { - public: - /** - * @brief Structure containing all the data required to async serialize code objects - */ - struct SerializationJobData { - uint64_t GuestRIP; ///< The RIP for the guest - // XXX: Support multiblock - uint64_t GuestCodeLength; ///< The Guest's code length - uint64_t GuestCodeHash; ///< Hash of the guest code - - void *HostCodeBegin; ///< Host JIT code starting memory address - size_t HostCodeLength; ///< Host JIT code length - uint64_t HostCodeHash; ///< Host JIT code hash before any backpatching - - // This is the thread specific ref counter for outstanding jobs. - // This shared mutex is incremented when the job is added, then decremented when the job is complete. - // If a thread is shutting down or clearing code cache then the thread will pull a unique lock on this mutex. - // This way it will wait until the async job handler is complete with it. - CodeSerializationMutex *ThreadJobRefCount; - - // These are the reolocations for this serialization job - // Relatively small number of entries most of the time - fextl::vector Relocations; - - /** - * @name Objects filled in from the Code Object Serialization service when a job is added - * @{ */ - // This is the code region's ref counter for outstanding jobs. - // This shared mutex is incremented when the job is added, then decremented when the job is complete. - // If a named region is being removed then a unique lock will be pulled to wait for all jobs to complete and no new jobs to be added. - CodeSerializationMutex *ObjectJobRefCountMutexPtr; - - // This is the code region iterator to reduce the number of map lookups - // This will remain valid while jobs are outstanding for this region - CodeRegionMapType::iterator CodeRegionIterator; - /** @} */ - }; - - AsyncJobHandler(NamedRegionObjectHandler *NamedRegionHandler, CodeObjectSerializeService *CodeObjectCacheService) - : NamedRegionHandler {NamedRegionHandler} - , CodeObjectCacheService {CodeObjectCacheService} {} - - protected: - friend class CodeObjectSerializeService; - friend class NamedRegionObjectHandler; - /** - * @name Async job submission functions - * @{ */ - void AsyncAddNamedRegionJob(uintptr_t Base, uintptr_t Size, uintptr_t Offset, const fextl::string &filename); - void AsyncRemoveNamedRegionJob(uintptr_t Base, uintptr_t Size); - void AsyncAddSerializationJob(fextl::unique_ptr Data); - /** @} */ - - /** - * @name Async named region handling - * @{ */ - /** - * @brief The async named region jobs to handle. - * - * Only two, Code serialization goes in to a different queue. - */ - enum class NamedRegionJobType { - JOB_ADD_NAMED_REGION, - JOB_REMOVE_NAMED_REGION, - }; - - class NamedRegionWorkItem { - public: - NamedRegionJobType GetType() const { return Type; } - - protected: - friend class WorkItemAddNamedRegion; - NamedRegionWorkItem(NamedRegionJobType type) - : Type {type} {} - - private: - NamedRegionJobType Type; - }; - - class WorkItemAddNamedRegion : public NamedRegionWorkItem { - public: - WorkItemAddNamedRegion(const fextl::string &base, const fextl::string &filename, bool executable, CodeRegionMapType::iterator entry) - : NamedRegionWorkItem {NamedRegionJobType::JOB_ADD_NAMED_REGION} - , BaseFilename {base} - , Filename {filename} - , Executable {executable} - , Entry {entry} - {} - const fextl::string BaseFilename; - const fextl::string Filename; - bool Executable; - CodeRegionMapType::iterator Entry; - }; - - class WorkItemRemoveNamedRegion : public NamedRegionWorkItem { - public: - WorkItemRemoveNamedRegion(uint64_t base, uint64_t size, fextl::unique_ptr entry) - : NamedRegionWorkItem {NamedRegionJobType::JOB_REMOVE_NAMED_REGION} - , Base {base} - , Size {size} - , Entry {std::move(entry)} {} - - uint64_t Base; - uint64_t Size; - fextl::unique_ptr Entry; - }; - /** @} */ - - private: - NamedRegionObjectHandler *NamedRegionHandler; - CodeObjectSerializeService *CodeObjectCacheService; - }; - - class NamedRegionObjectHandler final { - public: - NamedRegionObjectHandler(FEXCore::Context::ContextImpl *ctx); - - void HandleNamedRegionObjectJobs(); - - CodeObjectSerializationConfig const &GetDefaultSerializationConfig() const { - return DefaultSerializationConfig; - } - - protected: - friend class AsyncJobHandler; - - // Return a default code header based off the default serialization config - CodeObjectSerializationHeader DefaultCodeHeader(uint64_t Base, uint64_t Offset) const { - return CodeObjectSerializationHeader { - .Config = DefaultSerializationConfig, - .OriginalBase = Base, - .OriginalOffset = Offset, - .NumCodeEntries = 0, - .NumRelocationsTo = 0, - .TotalRelocationsCount = 0, - }; - } - - /** - * @brief Adds an asynchronous add named region work item to the object queue - * - * This adds the job that will do the loading of file resources and data tracking. - */ - void AsyncAddNamedRegionWorkItem(const fextl::string &base, const fextl::string &filename, bool executable, CodeRegionMapType::iterator entry) { - std::unique_lock lk {NamedWorkQueueMutex}; - WorkQueue.emplace(fextl::make_unique ( - base, - filename, - executable, - entry - )); - ++NamedWorkQueueJobs; - } - - void AsyncRemoveNamedRegionWorkItem(uint64_t Base, uint64_t Size, fextl::unique_ptr Entry) { - std::unique_lock lk {NamedWorkQueueMutex}; - WorkQueue.emplace(fextl::make_unique ( - Base, - Size, - std::move(Entry) - )); - ++NamedWorkQueueJobs; - } - - private: - // Code version. If the code emission changes then this needs to increment - constexpr static uint32_t CODE_VERSION = 0x0; - - // Default cookie header for the file header - constexpr static uint64_t CODE_COOKIE = FEXCore::IR::COOKIE_VERSION("FEXC", CODE_VERSION); - - // Code serialization config for our current process configuration - CodeObjectSerializationConfig DefaultSerializationConfig; - - // Atomic counter for number of jobs in the queue without needing to pull the mutex to check - std::atomic NamedWorkQueueJobs{}; - - // Mutex for ading new jobs to the work queue - std::mutex NamedWorkQueueMutex{}; - - // The job queue itself - // Jobs get consumed as a FIFO - // Jobs always get appended to the end - fextl::queue> WorkQueue{}; - - /** - * @name Named Region object handling - * @{ */ - void AddNamedRegionObject(CodeRegionMapType::iterator Entry, const fextl::string &base_filename, const fextl::string &filename, bool Executable); - void RemoveNamedRegionObject(uintptr_t Base, uintptr_t Size, fextl::unique_ptr Entry); - /** @} */ - }; + // Refcount for outstanding named object region entry loading itself + // Will block JIT code cache look up when this has a unique_lock held + CodeSerializationMutex NamedJobRefCountMutex; + /** @} */ /** - * @brief Context specific code object serialization class - * - * Contains everything required for FEXCore to serialize code objects + * @name Object Entry data management + * @{ */ + + /** + * @name This is the raw file data that we loaded from the code region entry file + * @{ */ + char* CodeData {}; + size_t FileSize {}; + + fextl::vector FileCodeSections; + /** @} */ + + // This per section map takes the most time to load and needs to be quick + // This is the map of all code segments for this entry + fextl::robin_map SectionLookupMap {}; + /** @} */ + + // Default initialization + CodeRegionEntry() = default; + + // Initializer specifically for threaded loading + CodeRegionEntry(uint64_t Base, uint64_t Size, uint64_t Offset, const fextl::string& Filename, const CodeObjectSerializationHeader& DefaultHeader) + : Base {Base} + , Size {Size} + , Offset {Offset} + , Filename {Filename} + , EntryHeader {DefaultHeader} {} +}; + +// Map type must use an interator that isn't invalidation on erase/insert +using CodeRegionMapType = fextl::map>; +using CodeRegionPtrMapType = fextl::map; + +class NamedRegionObjectHandler; +class CodeObjectSerializeService; + +class AsyncJobHandler final { +public: + /** + * @brief Structure containing all the data required to async serialize code objects */ - class CodeObjectSerializeService final { - public: - CodeObjectSerializeService(FEXCore::Context::ContextImpl *ctx); + struct SerializationJobData { + uint64_t GuestRIP; ///< The RIP for the guest + // XXX: Support multiblock + uint64_t GuestCodeLength; ///< The Guest's code length + uint64_t GuestCodeHash; ///< Hash of the guest code - /** - * @brief Initialize the internal interface - * - * Is a public interface to allow the service to reinitialize after forking - */ - void Initialize(); + void* HostCodeBegin; ///< Host JIT code starting memory address + size_t HostCodeLength; ///< Host JIT code length + uint64_t HostCodeHash; ///< Host JIT code hash before any backpatching - /** - * @brief Safely shut down the Code Object serialization service. - * - * This service needs to be resiliant to application crashes, but shutting down safely is still preferred. - */ - void Shutdown(); + // This is the thread specific ref counter for outstanding jobs. + // This shared mutex is incremented when the job is added, then decremented when the job is complete. + // If a thread is shutting down or clearing code cache then the thread will pull a unique lock on this mutex. + // This way it will wait until the async job handler is complete with it. + CodeSerializationMutex* ThreadJobRefCount; - /** - * @name Async interface - * @{ */ - /** - * @brief Loads a named region in to the code serialization service. As async as possible. - * - * @param Base - Virtual address that this named region is loaded - * @param Size - The size of the region - * @param Offset - The offset from the file - * @param filename - The filename itself - */ - void AsyncAddNamedRegionJob(uintptr_t Base, uintptr_t Size, uintptr_t Offset, const fextl::string &filename) { - AsyncHandler.AsyncAddNamedRegionJob(Base, Size, Offset, filename); - } + // These are the reolocations for this serialization job + // Relatively small number of entries most of the time + fextl::vector Relocations; - /** - * @brief Unloads a named region from the code serialization service. As async as possible. - * - * @param Base - Virtual address of the named region - * @param Size - The size of the region - */ - void AsyncRemoveNamedRegionJob(uintptr_t Base, uintptr_t Size) { - AsyncHandler.AsyncRemoveNamedRegionJob(Base, Size); - } + /** + * @name Objects filled in from the Code Object Serialization service when a job is added + * @{ */ + // This is the code region's ref counter for outstanding jobs. + // This shared mutex is incremented when the job is added, then decremented when the job is complete. + // If a named region is being removed then a unique lock will be pulled to wait for all jobs to complete and no new jobs to be added. + CodeSerializationMutex* ObjectJobRefCountMutexPtr; - /** - * @brief Adds a code object serialization job. As async as possible. - * Code hashing happens prior to async job serialization to catch invalidations due to backpatching. - * - * @param Data - A fully filled out struct containing all the code serialization - */ - void AsyncAddSerializationJob(fextl::unique_ptr Data) { - AsyncHandler.AsyncAddSerializationJob(std::move(Data)); - } - /** @} */ - - /** - * @name Synchronous interface - * @{ */ - /** - * @brief Synchronously waits for this thread's job queue to become empty. - * - * This is necessary for when a thread is shutting down - * - * @param ThreadJobRefCount - The shared mutex to wait on until to be empty - */ - static void WaitForEmptyJobQueue(CodeSerializationMutex *ThreadJobRefCount) { - // Once the shared mutex is empty this unique lock will be gained - std::unique_lock lk {*ThreadJobRefCount}; - } - - /** - * @brief Fetches object code from the Code Object Cache for JIT. - * - * @param GuestRIP - Which GuestRIP to search the cache for - * - * @return Data required for the JIT to relocate the Object code. - */ - CodeObjectFileSection const *FetchCodeObjectFromCache(uint64_t GuestRIP); - /** @} */ - - // Public for threading - void ExecutionThread(); - - protected: - friend class AsyncJobHandler; - - /** - * @brief Safely closes out code object regions from the map - * - * @param it - iterator to do a closure on - */ - void DoCodeRegionClosure(uint64_t Base, CodeRegionEntry *it); - - CodeSerializationMutex &GetEntryMapMutex() { return EntryMapMutex; } - CodeSerializationMutex &GetUnrelocatedEntryMapMutex() { return EntryMapMutex; } - - CodeRegionMapType &GetEntryMap() { return AddressToEntryMap; } - CodeRegionPtrMapType &GetUnrelocatedEntryMap() { return UnrelocatedAddressToEntryMap; } - - /** - * @brief Notify the async thread that it has work to do - */ - void NotifyWork() { WorkAvailable.NotifyOne(); } - - private: - FEXCore::Context::ContextImpl *CTX; - - Event WorkAvailable{}; - fextl::unique_ptr WorkerThread; - std::atomic_bool WorkerThreadShuttingDown {false}; - AsyncJobHandler AsyncHandler; - NamedRegionObjectHandler NamedRegionHandler; - - // Mutex to hold when modifying the entry maps - CodeSerializationMutex EntryMapMutex; - CodeSerializationMutex UnrelocatedEntryMapMutex; - - // Entry maps - CodeRegionMapType AddressToEntryMap; - CodeRegionPtrMapType UnrelocatedAddressToEntryMap; + // This is the code region iterator to reduce the number of map lookups + // This will remain valid while jobs are outstanding for this region + CodeRegionMapType::iterator CodeRegionIterator; + /** @} */ }; -} + + AsyncJobHandler(NamedRegionObjectHandler* NamedRegionHandler, CodeObjectSerializeService* CodeObjectCacheService) + : NamedRegionHandler {NamedRegionHandler} + , CodeObjectCacheService {CodeObjectCacheService} {} + +protected: + friend class CodeObjectSerializeService; + friend class NamedRegionObjectHandler; + /** + * @name Async job submission functions + * @{ */ + void AsyncAddNamedRegionJob(uintptr_t Base, uintptr_t Size, uintptr_t Offset, const fextl::string& filename); + void AsyncRemoveNamedRegionJob(uintptr_t Base, uintptr_t Size); + void AsyncAddSerializationJob(fextl::unique_ptr Data); + /** @} */ + + /** + * @name Async named region handling + * @{ */ + /** + * @brief The async named region jobs to handle. + * + * Only two, Code serialization goes in to a different queue. + */ + enum class NamedRegionJobType { + JOB_ADD_NAMED_REGION, + JOB_REMOVE_NAMED_REGION, + }; + + class NamedRegionWorkItem { + public: + NamedRegionJobType GetType() const { + return Type; + } + + protected: + friend class WorkItemAddNamedRegion; + NamedRegionWorkItem(NamedRegionJobType type) + : Type {type} {} + + private: + NamedRegionJobType Type; + }; + + class WorkItemAddNamedRegion : public NamedRegionWorkItem { + public: + WorkItemAddNamedRegion(const fextl::string& base, const fextl::string& filename, bool executable, CodeRegionMapType::iterator entry) + : NamedRegionWorkItem {NamedRegionJobType::JOB_ADD_NAMED_REGION} + , BaseFilename {base} + , Filename {filename} + , Executable {executable} + , Entry {entry} {} + const fextl::string BaseFilename; + const fextl::string Filename; + bool Executable; + CodeRegionMapType::iterator Entry; + }; + + class WorkItemRemoveNamedRegion : public NamedRegionWorkItem { + public: + WorkItemRemoveNamedRegion(uint64_t base, uint64_t size, fextl::unique_ptr entry) + : NamedRegionWorkItem {NamedRegionJobType::JOB_REMOVE_NAMED_REGION} + , Base {base} + , Size {size} + , Entry {std::move(entry)} {} + + uint64_t Base; + uint64_t Size; + fextl::unique_ptr Entry; + }; + /** @} */ + +private: + NamedRegionObjectHandler* NamedRegionHandler; + CodeObjectSerializeService* CodeObjectCacheService; +}; + +class NamedRegionObjectHandler final { +public: + NamedRegionObjectHandler(FEXCore::Context::ContextImpl* ctx); + + void HandleNamedRegionObjectJobs(); + + const CodeObjectSerializationConfig& GetDefaultSerializationConfig() const { + return DefaultSerializationConfig; + } + +protected: + friend class AsyncJobHandler; + + // Return a default code header based off the default serialization config + CodeObjectSerializationHeader DefaultCodeHeader(uint64_t Base, uint64_t Offset) const { + return CodeObjectSerializationHeader { + .Config = DefaultSerializationConfig, + .OriginalBase = Base, + .OriginalOffset = Offset, + .NumCodeEntries = 0, + .NumRelocationsTo = 0, + .TotalRelocationsCount = 0, + }; + } + + /** + * @brief Adds an asynchronous add named region work item to the object queue + * + * This adds the job that will do the loading of file resources and data tracking. + */ + void AsyncAddNamedRegionWorkItem(const fextl::string& base, const fextl::string& filename, bool executable, CodeRegionMapType::iterator entry) { + std::unique_lock lk {NamedWorkQueueMutex}; + WorkQueue.emplace(fextl::make_unique(base, filename, executable, entry)); + ++NamedWorkQueueJobs; + } + + void AsyncRemoveNamedRegionWorkItem(uint64_t Base, uint64_t Size, fextl::unique_ptr Entry) { + std::unique_lock lk {NamedWorkQueueMutex}; + WorkQueue.emplace(fextl::make_unique(Base, Size, std::move(Entry))); + ++NamedWorkQueueJobs; + } + +private: + // Code version. If the code emission changes then this needs to increment + constexpr static uint32_t CODE_VERSION = 0x0; + + // Default cookie header for the file header + constexpr static uint64_t CODE_COOKIE = FEXCore::IR::COOKIE_VERSION("FEXC", CODE_VERSION); + + // Code serialization config for our current process configuration + CodeObjectSerializationConfig DefaultSerializationConfig; + + // Atomic counter for number of jobs in the queue without needing to pull the mutex to check + std::atomic NamedWorkQueueJobs {}; + + // Mutex for ading new jobs to the work queue + std::mutex NamedWorkQueueMutex {}; + + // The job queue itself + // Jobs get consumed as a FIFO + // Jobs always get appended to the end + fextl::queue> WorkQueue {}; + + /** + * @name Named Region object handling + * @{ */ + void AddNamedRegionObject(CodeRegionMapType::iterator Entry, const fextl::string& base_filename, const fextl::string& filename, bool Executable); + void RemoveNamedRegionObject(uintptr_t Base, uintptr_t Size, fextl::unique_ptr Entry); + /** @} */ +}; + +/** + * @brief Context specific code object serialization class + * + * Contains everything required for FEXCore to serialize code objects + */ +class CodeObjectSerializeService final { +public: + CodeObjectSerializeService(FEXCore::Context::ContextImpl* ctx); + + /** + * @brief Initialize the internal interface + * + * Is a public interface to allow the service to reinitialize after forking + */ + void Initialize(); + + /** + * @brief Safely shut down the Code Object serialization service. + * + * This service needs to be resiliant to application crashes, but shutting down safely is still preferred. + */ + void Shutdown(); + + /** + * @name Async interface + * @{ */ + /** + * @brief Loads a named region in to the code serialization service. As async as possible. + * + * @param Base - Virtual address that this named region is loaded + * @param Size - The size of the region + * @param Offset - The offset from the file + * @param filename - The filename itself + */ + void AsyncAddNamedRegionJob(uintptr_t Base, uintptr_t Size, uintptr_t Offset, const fextl::string& filename) { + AsyncHandler.AsyncAddNamedRegionJob(Base, Size, Offset, filename); + } + + /** + * @brief Unloads a named region from the code serialization service. As async as possible. + * + * @param Base - Virtual address of the named region + * @param Size - The size of the region + */ + void AsyncRemoveNamedRegionJob(uintptr_t Base, uintptr_t Size) { + AsyncHandler.AsyncRemoveNamedRegionJob(Base, Size); + } + + /** + * @brief Adds a code object serialization job. As async as possible. + * Code hashing happens prior to async job serialization to catch invalidations due to backpatching. + * + * @param Data - A fully filled out struct containing all the code serialization + */ + void AsyncAddSerializationJob(fextl::unique_ptr Data) { + AsyncHandler.AsyncAddSerializationJob(std::move(Data)); + } + /** @} */ + + /** + * @name Synchronous interface + * @{ */ + /** + * @brief Synchronously waits for this thread's job queue to become empty. + * + * This is necessary for when a thread is shutting down + * + * @param ThreadJobRefCount - The shared mutex to wait on until to be empty + */ + static void WaitForEmptyJobQueue(CodeSerializationMutex* ThreadJobRefCount) { + // Once the shared mutex is empty this unique lock will be gained + std::unique_lock lk {*ThreadJobRefCount}; + } + + /** + * @brief Fetches object code from the Code Object Cache for JIT. + * + * @param GuestRIP - Which GuestRIP to search the cache for + * + * @return Data required for the JIT to relocate the Object code. + */ + const CodeObjectFileSection* FetchCodeObjectFromCache(uint64_t GuestRIP); + /** @} */ + + // Public for threading + void ExecutionThread(); + +protected: + friend class AsyncJobHandler; + + /** + * @brief Safely closes out code object regions from the map + * + * @param it - iterator to do a closure on + */ + void DoCodeRegionClosure(uint64_t Base, CodeRegionEntry* it); + + CodeSerializationMutex& GetEntryMapMutex() { + return EntryMapMutex; + } + CodeSerializationMutex& GetUnrelocatedEntryMapMutex() { + return EntryMapMutex; + } + + CodeRegionMapType& GetEntryMap() { + return AddressToEntryMap; + } + CodeRegionPtrMapType& GetUnrelocatedEntryMap() { + return UnrelocatedAddressToEntryMap; + } + + /** + * @brief Notify the async thread that it has work to do + */ + void NotifyWork() { + WorkAvailable.NotifyOne(); + } + +private: + FEXCore::Context::ContextImpl* CTX; + + Event WorkAvailable {}; + fextl::unique_ptr WorkerThread; + std::atomic_bool WorkerThreadShuttingDown {false}; + AsyncJobHandler AsyncHandler; + NamedRegionObjectHandler NamedRegionHandler; + + // Mutex to hold when modifying the entry maps + CodeSerializationMutex EntryMapMutex; + CodeSerializationMutex UnrelocatedEntryMapMutex; + + // Entry maps + CodeRegionMapType AddressToEntryMap; + CodeRegionPtrMapType UnrelocatedAddressToEntryMap; +}; +} // namespace FEXCore::CodeSerialize diff --git a/FEXCore/Source/Interface/Core/ObjectCache/Relocations.h b/FEXCore/Source/Interface/Core/ObjectCache/Relocations.h index 8ad125e0b..aebc4138d 100644 --- a/FEXCore/Source/Interface/Core/ObjectCache/Relocations.h +++ b/FEXCore/Source/Interface/Core/ObjectCache/Relocations.h @@ -3,77 +3,77 @@ #include namespace FEXCore::CPU { - enum class RelocationTypes : uint8_t { - // 8 byte literal in memory for symbol - // Aligned to struct RelocNamedSymbolLiteral - RELOC_NAMED_SYMBOL_LITERAL, +enum class RelocationTypes : uint8_t { + // 8 byte literal in memory for symbol + // Aligned to struct RelocNamedSymbolLiteral + RELOC_NAMED_SYMBOL_LITERAL, - // Fixed size named thunk move - // 4 instruction constant generation on AArch64 - // 64-bit mov on x86-64 - // Aligned to struct RelocNamedThunkMove - RELOC_NAMED_THUNK_MOVE, + // Fixed size named thunk move + // 4 instruction constant generation on AArch64 + // 64-bit mov on x86-64 + // Aligned to struct RelocNamedThunkMove + RELOC_NAMED_THUNK_MOVE, - // Fixed size guest RIP move - // 4 instruction constant generation on AArch64 - // 64-bit mov on x86-64 - // Aligned to struct RelocGuestRIPMove - RELOC_GUEST_RIP_MOVE, + // Fixed size guest RIP move + // 4 instruction constant generation on AArch64 + // 64-bit mov on x86-64 + // Aligned to struct RelocGuestRIPMove + RELOC_GUEST_RIP_MOVE, +}; + +struct RelocationTypeHeader final { + RelocationTypes Type; +}; + +struct RelocNamedSymbolLiteral final { + enum class NamedSymbol : uint8_t { + ///< Thread specific relocations + // JIT Literal pointers + SYMBOL_LITERAL_EXITFUNCTION_LINKER, }; - struct RelocationTypeHeader final { - RelocationTypes Type; - }; + RelocationTypeHeader Header {}; - struct RelocNamedSymbolLiteral final { - enum class NamedSymbol : uint8_t { - ///< Thread specific relocations - // JIT Literal pointers - SYMBOL_LITERAL_EXITFUNCTION_LINKER, - }; + NamedSymbol Symbol; - RelocationTypeHeader Header{}; + // Offset in to the code section to begin the relocation + uint64_t Offset {}; +}; - NamedSymbol Symbol; +struct RelocNamedThunkMove final { + RelocationTypeHeader Header {}; - // Offset in to the code section to begin the relocation - uint64_t Offset{}; - }; + // GPR index the constant is being moved to + uint8_t RegisterIndex; - struct RelocNamedThunkMove final { - RelocationTypeHeader Header{}; + // The thunk SHA256 hash + IR::SHA256Sum Symbol; - // GPR index the constant is being moved to - uint8_t RegisterIndex; + // Offset in to the code section to begin the relocation + uint64_t Offset {}; +}; - // The thunk SHA256 hash - IR::SHA256Sum Symbol; +struct RelocGuestRIPMove final { + RelocationTypeHeader Header {}; - // Offset in to the code section to begin the relocation - uint64_t Offset{}; - }; + // GPR index the constant is being moved to + uint8_t RegisterIndex; - struct RelocGuestRIPMove final { - RelocationTypeHeader Header{}; + // Offset in to the code section to begin the relocation + uint64_t Offset {}; - // GPR index the constant is being moved to - uint8_t RegisterIndex; + // The unrelocated RIP that is being moved + uint64_t GuestRIP; +}; - // Offset in to the code section to begin the relocation - uint64_t Offset{}; +union Relocation { + RelocationTypeHeader Header {}; - // The unrelocated RIP that is being moved - uint64_t GuestRIP; - }; + RelocNamedSymbolLiteral NamedSymbolLiteral; + // This makes our union of relocations at least 48 bytes + // It might be more efficient to not use a union + RelocNamedThunkMove NamedThunkMove; - union Relocation { - RelocationTypeHeader Header{}; - - RelocNamedSymbolLiteral NamedSymbolLiteral; - // This makes our union of relocations at least 48 bytes - // It might be more efficient to not use a union - RelocNamedThunkMove NamedThunkMove; - - RelocGuestRIPMove GuestRIPMove; - }; -} + RelocGuestRIPMove GuestRIPMove; +}; +} // namespace FEXCore::CPU diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 4346c5f1b..9f00250c5 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -40,25 +40,15 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { constexpr size_t SyscallArgs = 7; using SyscallArray = std::array; - size_t NumArguments{}; - const SyscallArray *GPRIndexes {}; + size_t NumArguments {}; + const SyscallArray* GPRIndexes {}; static constexpr SyscallArray GPRIndexes_64 = { - FEXCore::X86State::REG_RAX, - FEXCore::X86State::REG_RDI, - FEXCore::X86State::REG_RSI, - FEXCore::X86State::REG_RDX, - FEXCore::X86State::REG_R10, - FEXCore::X86State::REG_R8, - FEXCore::X86State::REG_R9, + FEXCore::X86State::REG_RAX, FEXCore::X86State::REG_RDI, FEXCore::X86State::REG_RSI, FEXCore::X86State::REG_RDX, + FEXCore::X86State::REG_R10, FEXCore::X86State::REG_R8, FEXCore::X86State::REG_R9, }; static constexpr SyscallArray GPRIndexes_32 = { - FEXCore::X86State::REG_RAX, - FEXCore::X86State::REG_RBX, - FEXCore::X86State::REG_RCX, - FEXCore::X86State::REG_RDX, - FEXCore::X86State::REG_RSI, - FEXCore::X86State::REG_RDI, - FEXCore::X86State::REG_RBP, + FEXCore::X86State::REG_RAX, FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RCX, FEXCore::X86State::REG_RDX, + FEXCore::X86State::REG_RSI, FEXCore::X86State::REG_RDI, FEXCore::X86State::REG_RBP, }; static constexpr SyscallArray GPRIndexes_Hangover = { @@ -66,12 +56,8 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { }; static constexpr SyscallArray GPRIndexes_Win64 = { - FEXCore::X86State::REG_RAX, - FEXCore::X86State::REG_R10, - FEXCore::X86State::REG_RDX, - FEXCore::X86State::REG_R8, - FEXCore::X86State::REG_R9, - FEXCore::X86State::REG_RSP, + FEXCore::X86State::REG_RAX, FEXCore::X86State::REG_R10, FEXCore::X86State::REG_RDX, + FEXCore::X86State::REG_R8, FEXCore::X86State::REG_R9, FEXCore::X86State::REG_RSP, }; SyscallFlags DefaultSyscallFlags = FEXCore::IR::SyscallFlags::DEFAULT; @@ -80,27 +66,22 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { if (OSABI == FEXCore::HLE::SyscallOSABI::OS_LINUX64) { NumArguments = GPRIndexes_64.size(); GPRIndexes = &GPRIndexes_64; - } - else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_LINUX32) { + } else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_LINUX32) { NumArguments = GPRIndexes_32.size(); GPRIndexes = &GPRIndexes_32; - } - else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_WIN64) { + } else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_WIN64) { NumArguments = 6; GPRIndexes = &GPRIndexes_Win64; DefaultSyscallFlags = FEXCore::IR::SyscallFlags::NORETURNEDRESULT; - } - else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_WIN32) { + } else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_WIN32) { // Since the whole context is going to be saved at entry anyway, theres no need to do additional work to pass in args NumArguments = 0; GPRIndexes = nullptr; DefaultSyscallFlags = FEXCore::IR::SyscallFlags::NORETURNEDRESULT; - } - else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_HANGOVER) { + } else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_HANGOVER) { NumArguments = 1; GPRIndexes = &GPRIndexes_Hangover; - } - else { + } else { LogMan::Msg::DFmt("Unhandled OSABI syscall"); } @@ -111,14 +92,8 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { auto NewRIP = GetRelocatedPC(Op, -Op->InstSize); _StoreContext(GPRSize, GPRClass, NewRIP, offsetof(FEXCore::Core::CPUState, rip)); - OrderedNode *Arguments[SyscallArgs] { - InvalidNode, - InvalidNode, - InvalidNode, - InvalidNode, - InvalidNode, - InvalidNode, - InvalidNode, + OrderedNode* Arguments[SyscallArgs] { + InvalidNode, InvalidNode, InvalidNode, InvalidNode, InvalidNode, InvalidNode, InvalidNode, }; for (size_t i = 0; i < NumArguments; ++i) { Arguments[i] = LoadGPRRegister(GPRIndexes->at(i)); @@ -138,15 +113,7 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { StoreGPRRegister(X86State::REG_RCX, RIPAfterInst, 8); } - auto SyscallOp = _Syscall( - Arguments[0], - Arguments[1], - Arguments[2], - Arguments[3], - Arguments[4], - Arguments[5], - Arguments[6], - DefaultSyscallFlags); + auto SyscallOp = _Syscall(Arguments[0], Arguments[1], Arguments[2], Arguments[3], Arguments[4], Arguments[5], Arguments[6], DefaultSyscallFlags); if (OSABI != FEXCore::HLE::SyscallOSABI::OS_HANGOVER && (DefaultSyscallFlags & FEXCore::IR::SyscallFlags::NORETURNEDRESULT) != FEXCore::IR::SyscallFlags::NORETURNEDRESULT) { @@ -168,27 +135,20 @@ void OpDispatchBuilder::ThunkOp(OpcodeArgs) { CalculateDeferredFlags(); const uint8_t GPRSize = CTX->GetGPRSize(); - uint8_t *sha256 = (uint8_t *)(Op->PC + 2); + uint8_t* sha256 = (uint8_t*)(Op->PC + 2); if (CTX->Config.Is64BitMode) { // x86-64 ABI puts the function argument in RDI - _Thunk( - LoadGPRRegister(X86State::REG_RDI), - *reinterpret_cast(sha256) - ); - } - else { + _Thunk(LoadGPRRegister(X86State::REG_RDI), *reinterpret_cast(sha256)); + } else { // x86 fastcall ABI puts the function argument in ECX - _Thunk( - LoadGPRRegister(X86State::REG_RCX), - *reinterpret_cast(sha256) - ); + _Thunk(LoadGPRRegister(X86State::REG_RCX), *reinterpret_cast(sha256)); } auto Constant = _Constant(GPRSize); auto OldSP = LoadGPRRegister(X86State::REG_RSP); auto NewRIP = _LoadMem(GPRClass, GPRSize, OldSP, GPRSize); - OrderedNode *NewSP = _Add(IR::SizeToOpSize(GPRSize), OldSP, Constant); + OrderedNode* NewSP = _Add(IR::SizeToOpSize(GPRSize), OldSP, Constant); // Store the new stack pointer StoreGPRRegister(X86State::REG_RSP, NewSP); @@ -204,8 +164,9 @@ void OpDispatchBuilder::LEAOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); if (CTX->Config.Is64BitMode) { - const uint32_t DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? 2 : - X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST ? 8 : 4; + const uint32_t DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? 2 : + X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST ? 8 : + 4; auto Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], SrcSize, Op->Flags, {.LoadData = false}); if (DstSize != SrcSize) { @@ -214,8 +175,7 @@ void OpDispatchBuilder::LEAOp(OpcodeArgs) { Src = _Bfe(IR::SizeToOpSize(GPRSize), SrcSize * 8, 0, Src); } StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Src, DstSize, -1); - } - else { + } else { uint32_t DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? 2 : 4; auto Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], SrcSize, Op->Flags, {.LoadData = false}); @@ -223,8 +183,7 @@ void OpDispatchBuilder::LEAOp(OpcodeArgs) { } } -void OpDispatchBuilder::NOPOp(OpcodeArgs) { -} +void OpDispatchBuilder::NOPOp(OpcodeArgs) {} void OpDispatchBuilder::RETOp(OpcodeArgs) { const uint8_t GPRSize = CTX->GetGPRSize(); @@ -234,8 +193,7 @@ void OpDispatchBuilder::RETOp(OpcodeArgs) { _InvalidateFlags(~0UL); // all flags // Deferred flags are invalidated now InvalidateDeferredFlags(); - } - else { + } else { // Calculate flags early. CalculateDeferredFlags(); } @@ -244,12 +202,11 @@ void OpDispatchBuilder::RETOp(OpcodeArgs) { auto OldSP = LoadGPRRegister(X86State::REG_RSP); auto NewRIP = _LoadMem(GPRClass, GPRSize, OldSP, GPRSize); - OrderedNode *NewSP; + OrderedNode* NewSP; if (Op->OP == 0xC2) { auto Offset = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); NewSP = _Add(IR::SizeToOpSize(GPRSize), _Add(IR::SizeToOpSize(GPRSize), OldSP, Constant), Offset); - } - else { + } else { NewSP = _Add(IR::SizeToOpSize(GPRSize), OldSP, Constant); } @@ -297,7 +254,7 @@ void OpDispatchBuilder::IRETOp(OpcodeArgs) { UpdatePrefixFromSegment(NewSegmentCS, FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX); SP = _Add(IR::SizeToOpSize(GPRSize), SP, Constant); - //eflags (lower 16 used) + // eflags (lower 16 used) auto eflags = _LoadMem(GPRClass, GPRSize, SP, GPRSize); SetPackedRFLAG(false, eflags); SP = _Add(IR::SizeToOpSize(GPRSize), SP, Constant); @@ -314,8 +271,7 @@ void OpDispatchBuilder::IRETOp(OpcodeArgs) { UpdatePrefixFromSegment(NewSegmentSS, FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX); _Add(IR::SizeToOpSize(GPRSize), SP, Constant); - } - else { + } else { // Store the stack in 32-bit mode StoreGPRRegister(X86State::REG_RSP, SP); } @@ -345,36 +301,36 @@ void OpDispatchBuilder::SecondaryALUOp(OpcodeArgs) { case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 0): IROp = FEXCore::IR::IROps::OP_ADD; AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHADD; - break; + break; case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 1): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 1): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 1): IROp = FEXCore::IR::IROps::OP_OR; AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHOR; - break; + break; case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 4): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 4): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 4): IROp = FEXCore::IR::IROps::OP_ANDWITHFLAGS; AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHAND; - break; + break; case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 5): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 5): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 5): IROp = FEXCore::IR::IROps::OP_SUB; AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHSUB; - break; + break; case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 6): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 6): case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 6): IROp = FEXCore::IR::IROps::OP_XOR; AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHXOR; - break; + break; default: IROp = FEXCore::IR::IROps::OP_LAST; AtomicIROp = FEXCore::IR::IROps::OP_LAST; LOGMAN_MSG_A_FMT("Unknown ALU Op: 0x{:x}", Op->OP); - break; + break; }; #undef OPD @@ -386,26 +342,26 @@ void OpDispatchBuilder::ADCOp(OpcodeArgs) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); uint8_t Size = GetDstSize(Op); const auto OpSize = IR::SizeToOpSize(std::max(4u, Size)); - OrderedNode *Before{}; + OrderedNode* Before {}; if (DestIsLockedMem(Op)) { auto ALUOp = _Adc(OpSize, _Constant(0), Src); HandledLock = true; - - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); + + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); Before = _AtomicFetchAdd(IR::SizeToOpSize(Size), ALUOp, DestMem); - } - else { + } else { Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); } - OrderedNode *Result = CalculateFlags_ADC(Size, Before, Src); - if (!DestIsLockedMem(Op)) + OrderedNode* Result = CalculateFlags_ADC(Size, Before, Src); + if (!DestIsLockedMem(Op)) { StoreResult(GPRClass, Op, Result, -1); + } } template @@ -413,34 +369,33 @@ void OpDispatchBuilder::SBBOp(OpcodeArgs) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); auto Size = GetDstSize(Op); const auto OpSize = IR::SizeToOpSize(std::max(4u, Size)); - OrderedNode *Result{}; - OrderedNode *Before{}; + OrderedNode* Result {}; + OrderedNode* Before {}; if (DestIsLockedMem(Op)) { HandledLock = true; - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); auto SrcPlusCF = _Adc(OpSize, _Constant(0), Src); Before = _AtomicFetchSub(IR::SizeToOpSize(Size), SrcPlusCF, DestMem); - } - else { + } else { Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); } Result = CalculateFlags_SBB(Size, Before, Src); - if (!DestIsLockedMem(Op)) + if (!DestIsLockedMem(Op)) { StoreResult(GPRClass, Op, Result, -1); + } } void OpDispatchBuilder::SALCOp(OpcodeArgs) { CalculateDeferredFlags(); - auto Result = _NZCVSelect(OpSize::i32Bit, CondClassType{COND_UGE} /* CF = 1 */, - _Constant(0xffffffff), _Constant(0)); + auto Result = _NZCVSelect(OpSize::i32Bit, CondClassType {COND_UGE} /* CF = 1 */, _Constant(0xffffffff), _Constant(0)); StoreResult(GPRClass, Op, Result, -1); } @@ -448,7 +403,7 @@ void OpDispatchBuilder::SALCOp(OpcodeArgs) { void OpDispatchBuilder::PUSHOp(OpcodeArgs) { const uint8_t Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); auto OldSP = LoadGPRRegister(X86State::REG_RSP); @@ -462,8 +417,7 @@ void OpDispatchBuilder::PUSHOp(OpcodeArgs) { void OpDispatchBuilder::PUSHREGOp(OpcodeArgs) { const uint8_t Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Dest , Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); auto OldSP = LoadGPRRegister(X86State::REG_RSP); const uint8_t GPRSize = CTX->GetGPRSize(); @@ -489,8 +443,8 @@ void OpDispatchBuilder::PUSHAOp(OpcodeArgs) { // push ESI // push EDI - OrderedNode *Src{}; - OrderedNode *NewSP = OldSP; + OrderedNode* Src {}; + OrderedNode* NewSP = OldSP; const uint8_t GPRSize = CTX->GetGPRSize(); Src = LoadGPRRegister(X86State::REG_RAX); @@ -528,51 +482,50 @@ void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs) { auto OldSP = LoadGPRRegister(X86State::REG_RSP); - OrderedNode *Src{}; + OrderedNode* Src {}; if (!CTX->Config.Is64BitMode()) { switch (SegmentReg) { - case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, es_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, cs_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ss_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ds_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, gs_idx)); - break; - default: break; // Do nothing + case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, es_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, cs_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ss_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ds_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, gs_idx)); + break; + default: break; // Do nothing } - } - else { + } else { switch (SegmentReg) { - case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, es_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, cs_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ss_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ds_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: - Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, gs_cached)); - break; - default: break; // Do nothing + case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, es_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, cs_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ss_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, ds_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: + Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, gs_cached)); + break; + default: break; // Do nothing } } @@ -618,8 +571,8 @@ void OpDispatchBuilder::POPAOp(OpcodeArgs) { // pop ECX // pop EAX - OrderedNode *Src{}; - OrderedNode *NewSP = OldSP; + OrderedNode* Src {}; + OrderedNode* NewSP = OldSP; Src = _LoadMem(GPRClass, Size, NewSP, Size); StoreGPRRegister(X86State::REG_RDI, Src, Size); NewSP = _Add(OpSize::i64Bit, NewSP, Constant); @@ -667,25 +620,25 @@ void OpDispatchBuilder::POPSegmentOp(OpcodeArgs) { StoreGPRRegister(X86State::REG_RSP, NewSP); switch (SegmentReg) { - case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: - _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, es_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: - _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, cs_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: - _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ss_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: - _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ds_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: - _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, fs_idx)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: - _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, gs_idx)); - break; - default: break; // Do nothing + case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: + _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, es_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: + _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, cs_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: + _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ss_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: + _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ds_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: + _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, fs_idx)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: + _StoreContext(DstSize, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, gs_idx)); + break; + default: break; // Do nothing } UpdatePrefixFromSegment(NewSegment, SegmentReg); @@ -718,17 +671,16 @@ void OpDispatchBuilder::CALLOp(OpcodeArgs) { _InvalidateFlags(~0UL); // all flags // Deferred flags are invalidated now InvalidateDeferredFlags(); - } - else { + } else { // Calculate flags early. CalculateDeferredFlags(); } auto ConstantPC = GetRelocatedPC(Op); - OrderedNode *JMPPCOffset = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* JMPPCOffset = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *NewRIP = _Add(IR::SizeToOpSize(GPRSize), ConstantPC, JMPPCOffset); + OrderedNode* NewRIP = _Add(IR::SizeToOpSize(GPRSize), ConstantPC, JMPPCOffset); // Push the return address. auto OldSP = LoadGPRRegister(X86State::REG_RSP); @@ -745,8 +697,7 @@ void OpDispatchBuilder::CALLOp(OpcodeArgs) { if (NextRIP != TargetRIP) { // Store the RIP _ExitFunction(NewRIP); // If we get here then leave the function now - } - else { + } else { NeedsBlockEnd = true; } } @@ -758,7 +709,7 @@ void OpDispatchBuilder::CALLAbsoluteOp(OpcodeArgs) { BlockSetRIP = true; const uint8_t Size = GetSrcSize(Op); - OrderedNode *JMPPCOffset = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* JMPPCOffset = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); auto ConstantPCReturn = GetRelocatedPC(Op); @@ -774,92 +725,87 @@ void OpDispatchBuilder::CALLAbsoluteOp(OpcodeArgs) { _ExitFunction(JMPPCOffset); // If we get here then leave the function now } -OrderedNode *OpDispatchBuilder::SelectBit(OrderedNode *Cmp, IR::OpSize ResultSize, OrderedNode *TrueValue, OrderedNode *FalseValue) { +OrderedNode* OpDispatchBuilder::SelectBit(OrderedNode* Cmp, IR::OpSize ResultSize, OrderedNode* TrueValue, OrderedNode* FalseValue) { uint64_t TrueConst, FalseConst; - if (IsValueConstant(WrapNode(TrueValue), &TrueConst) && - IsValueConstant(WrapNode(FalseValue), &FalseConst) && - TrueConst == 1 && - FalseConst == 0) { + if (IsValueConstant(WrapNode(TrueValue), &TrueConst) && IsValueConstant(WrapNode(FalseValue), &FalseConst) && TrueConst == 1 && FalseConst == 0) { - return _And(ResultSize, Cmp, _Constant(1)); + return _And(ResultSize, Cmp, _Constant(1)); } SaveNZCV(); _TestNZ(OpSize::i32Bit, Cmp, _Constant(1)); - return _NZCVSelect(ResultSize, CondClassType{COND_NEQ}, - TrueValue, FalseValue); + return _NZCVSelect(ResultSize, CondClassType {COND_NEQ}, TrueValue, FalseValue); } std::pair OpDispatchBuilder::DecodeNZCVCondition(uint8_t OP) const { switch (OP) { - case 0x0: { // JO - Jump if OF == 1 - return {false, CondClassType{COND_FU}}; - } - case 0x1:{ // JNO - Jump if OF == 0 - return {false, CondClassType{COND_FNU}}; - } - case 0x2: { // JC - Jump if CF == 1 - return {false, CondClassType{COND_UGE}}; - } - case 0x3: { // JNC - Jump if CF == 0 - return {false, CondClassType{COND_ULT}}; - } - case 0x4: { // JE - Jump if ZF == 1 - return {false, CondClassType{COND_EQ}}; - } - case 0x5: { // JNE - Jump if ZF == 0 - return {false, CondClassType{COND_NEQ}}; - } - case 0x8: { // JS - Jump if SF == 1 - return {false, CondClassType{COND_MI}}; - } - case 0x9: { // JNS - Jump if SF == 0 - return {false, CondClassType{COND_PL}}; - } - case 0xC: { // SF <> OF - return {false, CondClassType{COND_SLT}}; - } - case 0xD: { // SF = OF - return {false, CondClassType{COND_SGE}}; - } - case 0xE: {// ZF = 1 || SF <> OF - return {false, CondClassType{COND_SLE}}; - } - case 0xF: {// ZF = 0 && SF = OF - return {false, CondClassType{COND_SGT}}; - } - default: - // Other conditions do not map directly, caller gets to deal with it. - return {true, CondClassType{0}}; + case 0x0: { // JO - Jump if OF == 1 + return {false, CondClassType {COND_FU}}; + } + case 0x1: { // JNO - Jump if OF == 0 + return {false, CondClassType {COND_FNU}}; + } + case 0x2: { // JC - Jump if CF == 1 + return {false, CondClassType {COND_UGE}}; + } + case 0x3: { // JNC - Jump if CF == 0 + return {false, CondClassType {COND_ULT}}; + } + case 0x4: { // JE - Jump if ZF == 1 + return {false, CondClassType {COND_EQ}}; + } + case 0x5: { // JNE - Jump if ZF == 0 + return {false, CondClassType {COND_NEQ}}; + } + case 0x8: { // JS - Jump if SF == 1 + return {false, CondClassType {COND_MI}}; + } + case 0x9: { // JNS - Jump if SF == 0 + return {false, CondClassType {COND_PL}}; + } + case 0xC: { // SF <> OF + return {false, CondClassType {COND_SLT}}; + } + case 0xD: { // SF = OF + return {false, CondClassType {COND_SGE}}; + } + case 0xE: { // ZF = 1 || SF <> OF + return {false, CondClassType {COND_SLE}}; + } + case 0xF: { // ZF = 0 && SF = OF + return {false, CondClassType {COND_SGT}}; + } + default: + // Other conditions do not map directly, caller gets to deal with it. + return {true, CondClassType {0}}; } } -OrderedNode *OpDispatchBuilder::SelectCC(uint8_t OP, IR::OpSize ResultSize, OrderedNode *TrueValue, OrderedNode *FalseValue) { +OrderedNode* OpDispatchBuilder::SelectCC(uint8_t OP, IR::OpSize ResultSize, OrderedNode* TrueValue, OrderedNode* FalseValue) { auto [Complex, Cond] = DecodeNZCVCondition(OP); - if (!Complex) - return _NZCVSelect(ResultSize, Cond, TrueValue, FalseValue); + if (!Complex) { + return _NZCVSelect(ResultSize, Cond, TrueValue, FalseValue); + } switch (OP) { - case 0x6: { // JNA - Jump if CF == 1 || ZC == 1 - // (A || B) ? C : D is equivalent to B ? C : (A ? C : D) - auto TMP = _NZCVSelect(ResultSize, CondClassType{COND_UGE}, TrueValue, FalseValue); - return _NZCVSelect(ResultSize, CondClassType{COND_EQ}, TrueValue, TMP); - } - case 0x7: { // JA - Jump if CF == 0 && ZF == 0 - // (A && B) ? C : D is equivalent to B ? (A ? C : D) : D - auto TMP = _NZCVSelect(ResultSize, CondClassType{COND_ULT}, TrueValue, FalseValue); - return _NZCVSelect(ResultSize, CondClassType{COND_NEQ}, TMP, FalseValue); - } - case 0xA: { // JP - Jump if PF == 1 - // Raw value contains inverted PF in bottom bit - return SelectBit(LoadPFRaw(true), ResultSize, TrueValue, FalseValue); - } - case 0xB: { // JNP - Jump if PF == 0 - return SelectBit(LoadPFRaw(false), ResultSize, TrueValue, FalseValue); - } - default: - LOGMAN_MSG_A_FMT("Unknown CC Op: 0x{:x}\n", OP); - return nullptr; + case 0x6: { // JNA - Jump if CF == 1 || ZC == 1 + // (A || B) ? C : D is equivalent to B ? C : (A ? C : D) + auto TMP = _NZCVSelect(ResultSize, CondClassType {COND_UGE}, TrueValue, FalseValue); + return _NZCVSelect(ResultSize, CondClassType {COND_EQ}, TrueValue, TMP); + } + case 0x7: { // JA - Jump if CF == 0 && ZF == 0 + // (A && B) ? C : D is equivalent to B ? (A ? C : D) : D + auto TMP = _NZCVSelect(ResultSize, CondClassType {COND_ULT}, TrueValue, FalseValue); + return _NZCVSelect(ResultSize, CondClassType {COND_NEQ}, TMP, FalseValue); + } + case 0xA: { // JP - Jump if PF == 1 + // Raw value contains inverted PF in bottom bit + return SelectBit(LoadPFRaw(true), ResultSize, TrueValue, FalseValue); + } + case 0xB: { // JNP - Jump if PF == 0 + return SelectBit(LoadPFRaw(false), ResultSize, TrueValue, FalseValue); + } + default: LOGMAN_MSG_A_FMT("Unknown CC Op: 0x{:x}\n", OP); return nullptr; } } @@ -882,12 +828,11 @@ void OpDispatchBuilder::CMOVOp(OpcodeArgs) { CalculateDeferredFlags(); // Destination is always a GPR. - OrderedNode *Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); - OrderedNode *Src{}; + OrderedNode* Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); + OrderedNode* Src {}; if (Op->Src[0].IsGPR()) { Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], GPRSize, Op->Flags); - } - else { + } else { Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); } @@ -913,8 +858,7 @@ void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) { if (TargetOffset < 0 && -TargetOffset > InstRIP) { // Invert the signed value if we are underflowing TargetOffset = 0x1'0000'0000ULL + TargetOffset; - } - else if (TargetOffset >= 0 && Target >= 0x1'0000'0000ULL) { + } else if (TargetOffset >= 0 && Target >= 0x1'0000'0000ULL) { // We are overflowing, wrap around TargetOffset = TargetOffset - 0x1'0000'0000ULL; } @@ -943,8 +887,7 @@ void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) { // Taking branch block if (TrueBlock != JumpTargets.end()) { SetTrueJumpTarget(CondJump_, TrueBlock->second.BlockEntry); - } - else { + } else { // Make sure to start a new block after ending this one auto JumpTarget = CreateNewCodeBlockAtEnd(); SetTrueJumpTarget(CondJump_, JumpTarget); @@ -960,8 +903,7 @@ void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) { // Failure to take branch if (FalseBlock != JumpTargets.end()) { SetFalseJumpTarget(CondJump_, FalseBlock->second.BlockEntry); - } - else { + } else { // Make sure to start a new block after ending this one // Place it after this block for fallthrough optimization auto JumpTarget = CreateNewCodeBlockAfter(CurrentBlock); @@ -995,7 +937,7 @@ void OpDispatchBuilder::CondJUMPRCXOp(OpcodeArgs) { uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].Data.Literal.Value; - OrderedNode *CondReg = LoadGPRRegister(X86State::REG_RCX, JcxGPRSize); + OrderedNode* CondReg = LoadGPRRegister(X86State::REG_RCX, JcxGPRSize); auto TrueBlock = JumpTargets.find(Target); auto FalseBlock = JumpTargets.find(Op->PC + Op->InstSize); @@ -1008,8 +950,7 @@ void OpDispatchBuilder::CondJUMPRCXOp(OpcodeArgs) { // Taking branch block if (TrueBlock != JumpTargets.end()) { SetTrueJumpTarget(CondJump_, TrueBlock->second.BlockEntry); - } - else { + } else { // Make sure to start a new block after ending this one auto JumpTarget = CreateNewCodeBlockAtEnd(); SetTrueJumpTarget(CondJump_, JumpTarget); @@ -1025,8 +966,7 @@ void OpDispatchBuilder::CondJUMPRCXOp(OpcodeArgs) { // Failure to take branch if (FalseBlock != JumpTargets.end()) { SetFalseJumpTarget(CondJump_, FalseBlock->second.BlockEntry); - } - else { + } else { // Make sure to start a new block after ending this one // Place it after the current block for fallthrough behavior auto JumpTarget = CreateNewCodeBlockAfter(CurrentBlock); @@ -1064,7 +1004,7 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) { uint64_t Target = Op->PC + Op->InstSize + Op->Src[1].Data.Literal.Value; - OrderedNode *CondReg = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* CondReg = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], SrcSize, Op->Flags); CondReg = _Sub(OpSize, CondReg, _Constant(SrcSize * 8, 1)); StoreResult(GPRClass, Op, Op->Src[0], CondReg, -1); @@ -1086,8 +1026,7 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) { // Taking branch block if (TrueBlock != JumpTargets.end()) { SetTrueJumpTarget(CondJump_, TrueBlock->second.BlockEntry); - } - else { + } else { // Make sure to start a new block after ending this one auto JumpTarget = CreateNewCodeBlockAtEnd(); SetTrueJumpTarget(CondJump_, JumpTarget); @@ -1103,8 +1042,7 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) { // Failure to take branch if (FalseBlock != JumpTargets.end()) { SetFalseJumpTarget(CondJump_, FalseBlock->second.BlockEntry); - } - else { + } else { // Make sure to start a new block after ending this one // Place after this block for fallthrough behavior auto JumpTarget = CreateNewCodeBlockAfter(GetCurrentBlock()); @@ -1138,8 +1076,7 @@ void OpDispatchBuilder::JUMPOp(OpcodeArgs) { if (TargetOffset < 0 && -TargetOffset > InstRIP) { // Invert the signed value if we are underflowing TargetOffset = 0x1'0000'0000ULL + TargetOffset; - } - else if (TargetOffset >= 0 && TargetRIP >= 0x1'0000'0000ULL) { + } else if (TargetOffset >= 0 && TargetRIP >= 0x1'0000'0000ULL) { // We are overflowing, wrap around TargetOffset = TargetOffset - 0x1'0000'0000ULL; } @@ -1153,8 +1090,7 @@ void OpDispatchBuilder::JUMPOp(OpcodeArgs) { auto JumpBlock = JumpTargets.find(TargetRIP); if (JumpBlock != JumpTargets.end()) { Jump(GetNewJumpBlock(TargetRIP)); - } - else { + } else { // If the block isn't a jump target then we need to create an exit block auto Jump_ = Jump(); @@ -1197,18 +1133,17 @@ template void OpDispatchBuilder::TESTOp(OpcodeArgs) { // TEST is an instruction that does an AND between the sources // Result isn't stored in result, only writes to flags - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, - {.AllowUpperGarbage = true}); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); auto Size = GetDstSize(Op); // Optimize out masking constants uint64_t Const; if (IsValueConstant(WrapNode(Src), &Const)) { - if (Const == (Size == 8 ? ~0ULL : ((1ull << Size * 8) - 1))) + if (Const == (Size == 8 ? ~0ULL : ((1ull << Size * 8) - 1))) { Src = Dest; + } } HandleNZ00Write(); @@ -1228,17 +1163,15 @@ void OpDispatchBuilder::MOVSXDOp(OpcodeArgs) { // uint8_t Size = std::min(static_cast(4), GetSrcSize(Op)); - OrderedNode *Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], Size, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], Size, Op->Flags); if (Size == 2) { // This'll make sure to insert in to the lower 16bits without modifying upper bits StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Src, Size, -1); - } - else if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REX_WIDENING) { + } else if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REX_WIDENING) { // With REX.W then Sext Src = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src); StoreResult(GPRClass, Op, Src, -1); - } - else { + } else { // Without REX.W then Zext (store result implicitly zero extends) StoreResult(GPRClass, Op, Src, -1); } @@ -1248,13 +1181,13 @@ void OpDispatchBuilder::MOVSXOp(OpcodeArgs) { // This will ZExt the loaded size // We want to Sext it uint8_t Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); Src = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src); StoreResult(GPRClass, Op, Op->Dest, Src, -1); } void OpDispatchBuilder::MOVZXOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); // Store result implicitly zero extends StoreResult(GPRClass, Op, Src, -1); } @@ -1263,24 +1196,22 @@ template void OpDispatchBuilder::CMPOp(OpcodeArgs) { // CMP is an instruction that does a SUB between the sources // Result isn't stored in result, only writes to flags - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); GenerateFlags_SUB(Op, Dest, Src); } void OpDispatchBuilder::CQOOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); auto Size = GetSrcSize(Op); - OrderedNode *Upper = _Sbfe(OpSize::i64Bit, 1, Size * 8 - 1, Src); + OrderedNode* Upper = _Sbfe(OpSize::i64Bit, 1, Size * 8 - 1, Src); StoreResult(GPRClass, Op, Upper, -1); } void OpDispatchBuilder::XCHGOp(OpcodeArgs) { // Load both the source and the destination - if (Op->OP == 0x90 && - GetSrcSize(Op) >= 4 && - Op->Src[0].IsGPR() && Op->Src[0].Data.GPR.GPR == FEXCore::X86State::REG_RAX && + if (Op->OP == 0x90 && GetSrcSize(Op) >= 4 && Op->Src[0].IsGPR() && Op->Src[0].Data.GPR.GPR == FEXCore::X86State::REG_RAX && Op->Dest.IsGPR() && Op->Dest.Data.GPR.GPR == FEXCore::X86State::REG_RAX) { // This is one heck of a sucky special case // If we are the 0x90 XCHG opcode (Meaning source is GPR RAX) @@ -1301,18 +1232,16 @@ void OpDispatchBuilder::XCHGOp(OpcodeArgs) { } // AllowUpperGarbage: OK to allow as it will be overwritten by StoreResult. - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); if (DestIsMem(Op)) { HandledLock = (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK) != 0; - OrderedNode *Dest = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Dest = MakeSegmentAddress(Op, Op->Dest); auto Result = _AtomicSwap(OpSizeFromSrc(Op), Src, Dest); StoreResult(GPRClass, Op, Op->Src[0], Result, -1); - } - else { + } else { // AllowUpperGarbage: OK to allow as it will be overwritten by StoreResult. - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); // Swap the contents // Order matters here since we don't want to swap context contents for one that effects the other @@ -1324,17 +1253,16 @@ void OpDispatchBuilder::XCHGOp(OpcodeArgs) { void OpDispatchBuilder::CDQOp(OpcodeArgs) { uint8_t DstSize = GetDstSize(Op); uint8_t SrcSize = DstSize >> 1; - OrderedNode *Src = LoadGPRRegister(X86State::REG_RAX, SrcSize, 0, true); + OrderedNode* Src = LoadGPRRegister(X86State::REG_RAX, SrcSize, 0, true); - Src = _Sbfe(DstSize <= 4 ? OpSize::i32Bit : OpSize::i64Bit, SrcSize * 8, 0, - Src); + Src = _Sbfe(DstSize <= 4 ? OpSize::i32Bit : OpSize::i64Bit, SrcSize * 8, 0, Src); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Src, DstSize, -1); } void OpDispatchBuilder::SAHFOp(OpcodeArgs) { // Extract AH - OrderedNode *Src = LoadGPRRegister(X86State::REG_RAX, 1, 8); + OrderedNode* Src = LoadGPRRegister(X86State::REG_RAX, 1, 8); // Clear bits that aren't supposed to be set Src = _Andn(OpSize::i64Bit, Src, _Constant(0b101000)); @@ -1360,19 +1288,19 @@ void OpDispatchBuilder::FLAGControlOp(OpcodeArgs) { switch (Op->OP) { case 0xF5: // CMC CarryInvert(); - break; + break; case 0xF8: // CLC SetRFLAG(_Constant(0), FEXCore::X86State::RFLAG_CF_RAW_LOC); - break; + break; case 0xF9: // STC SetRFLAG(_Constant(1), FEXCore::X86State::RFLAG_CF_RAW_LOC); - break; + break; case 0xFC: // CLD SetRFLAG(_Constant(0), FEXCore::X86State::RFLAG_DF_RAW_LOC); - break; + break; case 0xFD: // STD SetRFLAG(_Constant(1), FEXCore::X86State::RFLAG_DF_RAW_LOC); - break; + break; } } @@ -1395,108 +1323,104 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs) { // The loads here also load the selector, NOT the base if constexpr (ToSeg) { - OrderedNode *Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], 2, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], 2, Op->Flags); switch (Op->Dest.Data.GPR.GPR) { - case FEXCore::X86State::REG_RAX: // ES - case FEXCore::X86State::REG_R8: // ES - _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, es_idx)); - UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX); - break; - case FEXCore::X86State::REG_RBX: // DS - case FEXCore::X86State::REG_R11: // DS - _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, ds_idx)); - UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX); - break; - case FEXCore::X86State::REG_RCX: // CS - case FEXCore::X86State::REG_R9: // CS - // CPL3 can't write to this - _Break(FEXCore::IR::BreakDefinition { - .ErrorRegister = 0, - .Signal = SIGILL, - .TrapNumber = 0, - .si_code = 0, - }); - break; - case FEXCore::X86State::REG_RDX: // SS - case FEXCore::X86State::REG_R10: // SS - _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, ss_idx)); - UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX); - break; - case FEXCore::X86State::REG_RBP: // GS - case FEXCore::X86State::REG_R13: // GS - if (!CTX->Config.Is64BitMode) { - _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, gs_idx)); - UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX); - } else { - LogMan::Msg::EFmt("We don't support modifying GS selector in 64bit mode!"); - DecodeFailure = true; - } - break; - case FEXCore::X86State::REG_RSP: // FS - case FEXCore::X86State::REG_R12: // FS - if (!CTX->Config.Is64BitMode) { - _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, fs_idx)); - UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX); - } else { - LogMan::Msg::EFmt("We don't support modifying FS selector in 64bit mode!"); - DecodeFailure = true; - } - break; - default: - LogMan::Msg::EFmt("Unknown segment register: {}", Op->Dest.Data.GPR.GPR); + case FEXCore::X86State::REG_RAX: // ES + case FEXCore::X86State::REG_R8: // ES + _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, es_idx)); + UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX); + break; + case FEXCore::X86State::REG_RBX: // DS + case FEXCore::X86State::REG_R11: // DS + _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, ds_idx)); + UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX); + break; + case FEXCore::X86State::REG_RCX: // CS + case FEXCore::X86State::REG_R9: // CS + // CPL3 can't write to this + _Break(FEXCore::IR::BreakDefinition { + .ErrorRegister = 0, + .Signal = SIGILL, + .TrapNumber = 0, + .si_code = 0, + }); + break; + case FEXCore::X86State::REG_RDX: // SS + case FEXCore::X86State::REG_R10: // SS + _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, ss_idx)); + UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX); + break; + case FEXCore::X86State::REG_RBP: // GS + case FEXCore::X86State::REG_R13: // GS + if (!CTX->Config.Is64BitMode) { + _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, gs_idx)); + UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX); + } else { + LogMan::Msg::EFmt("We don't support modifying GS selector in 64bit mode!"); DecodeFailure = true; - break; + } + break; + case FEXCore::X86State::REG_RSP: // FS + case FEXCore::X86State::REG_R12: // FS + if (!CTX->Config.Is64BitMode) { + _StoreContext(2, GPRClass, Src, offsetof(FEXCore::Core::CPUState, fs_idx)); + UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX); + } else { + LogMan::Msg::EFmt("We don't support modifying FS selector in 64bit mode!"); + DecodeFailure = true; + } + break; + default: + LogMan::Msg::EFmt("Unknown segment register: {}", Op->Dest.Data.GPR.GPR); + DecodeFailure = true; + break; } - } - else { - OrderedNode *Segment{}; + } else { + OrderedNode* Segment {}; switch (Op->Src[0].Data.GPR.GPR) { - case FEXCore::X86State::REG_RAX: // ES - case FEXCore::X86State::REG_R8: // ES - Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, es_idx)); - break; - case FEXCore::X86State::REG_RBX: // DS - case FEXCore::X86State::REG_R11: // DS - Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, ds_idx)); - break; - case FEXCore::X86State::REG_RCX: // CS - case FEXCore::X86State::REG_R9: // CS - Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, cs_idx)); - break; - case FEXCore::X86State::REG_RDX: // SS - case FEXCore::X86State::REG_R10: // SS - Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, ss_idx)); - break; - case FEXCore::X86State::REG_RBP: // GS - case FEXCore::X86State::REG_R13: // GS - if (CTX->Config.Is64BitMode) { - Segment = _Constant(0); - } - else { - Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, gs_idx)); - } - break; - case FEXCore::X86State::REG_RSP: // FS - case FEXCore::X86State::REG_R12: // FS - if (CTX->Config.Is64BitMode) { - Segment = _Constant(0); - } - else { - Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, fs_idx)); - } - break; - default: - LogMan::Msg::EFmt("Unknown segment register: {}", Op->Dest.Data.GPR.GPR); - DecodeFailure = true; - return; + case FEXCore::X86State::REG_RAX: // ES + case FEXCore::X86State::REG_R8: // ES + Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, es_idx)); + break; + case FEXCore::X86State::REG_RBX: // DS + case FEXCore::X86State::REG_R11: // DS + Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, ds_idx)); + break; + case FEXCore::X86State::REG_RCX: // CS + case FEXCore::X86State::REG_R9: // CS + Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, cs_idx)); + break; + case FEXCore::X86State::REG_RDX: // SS + case FEXCore::X86State::REG_R10: // SS + Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, ss_idx)); + break; + case FEXCore::X86State::REG_RBP: // GS + case FEXCore::X86State::REG_R13: // GS + if (CTX->Config.Is64BitMode) { + Segment = _Constant(0); + } else { + Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, gs_idx)); + } + break; + case FEXCore::X86State::REG_RSP: // FS + case FEXCore::X86State::REG_R12: // FS + if (CTX->Config.Is64BitMode) { + Segment = _Constant(0); + } else { + Segment = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, fs_idx)); + } + break; + default: + LogMan::Msg::EFmt("Unknown segment register: {}", Op->Dest.Data.GPR.GPR); + DecodeFailure = true; + return; } if (DestIsMem(Op)) { // If the destination is memory then we always store 16-bits only StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Segment, 2, -1); - } - else { + } else { // If the destination is a GPR then we follow register storing rules StoreResult(GPRClass, Op, Segment, -1); } @@ -1504,7 +1428,7 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs) { } void OpDispatchBuilder::MOVOffsetOp(OpcodeArgs) { - OrderedNode *Src; + OrderedNode* Src; switch (Op->OP) { case 0xA0: @@ -1529,18 +1453,18 @@ void OpDispatchBuilder::MOVOffsetOp(OpcodeArgs) { void OpDispatchBuilder::CPUIDOp(OpcodeArgs) { const auto GPRSize = CTX->GetGPRSize(); - OrderedNode *Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], GPRSize, Op->Flags); - OrderedNode *Leaf = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], GPRSize, Op->Flags); + OrderedNode* Leaf = LoadGPRRegister(X86State::REG_RCX); auto Res = _CPUID(Src, Leaf); - OrderedNode *Result_Lower = _ExtractElementPair(OpSize::i64Bit, Res, 0); - OrderedNode *Result_Upper = _ExtractElementPair(OpSize::i64Bit, Res, 1); + OrderedNode* Result_Lower = _ExtractElementPair(OpSize::i64Bit, Res, 0); + OrderedNode* Result_Upper = _ExtractElementPair(OpSize::i64Bit, Res, 1); - StoreGPRRegister(X86State::REG_RAX, _Bfe(OpSize::i64Bit, 32, 0, Result_Lower)); + StoreGPRRegister(X86State::REG_RAX, _Bfe(OpSize::i64Bit, 32, 0, Result_Lower)); StoreGPRRegister(X86State::REG_RBX, _Bfe(OpSize::i64Bit, 32, 32, Result_Lower)); StoreGPRRegister(X86State::REG_RDX, _Bfe(OpSize::i64Bit, 32, 32, Result_Upper)); - StoreGPRRegister(X86State::REG_RCX, _Bfe(OpSize::i64Bit, 32, 0, Result_Upper)); + StoreGPRRegister(X86State::REG_RCX, _Bfe(OpSize::i64Bit, 32, 0, Result_Upper)); } uint32_t OpDispatchBuilder::LoadConstantShift(X86Tables::DecodedOp Op, bool Is1Bit) { @@ -1557,12 +1481,12 @@ uint32_t OpDispatchBuilder::LoadConstantShift(X86Tables::DecodedOp Op, bool Is1B } void OpDispatchBuilder::XGetBVOp(OpcodeArgs) { - OrderedNode *Function = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* Function = LoadGPRRegister(X86State::REG_RCX); auto Res = _XGetBV(Function); - OrderedNode *Result_Lower = _ExtractElementPair(OpSize::i32Bit, Res, 0); - OrderedNode *Result_Upper = _ExtractElementPair(OpSize::i32Bit, Res, 1); + OrderedNode* Result_Lower = _ExtractElementPair(OpSize::i32Bit, Res, 0); + OrderedNode* Result_Upper = _ExtractElementPair(OpSize::i32Bit, Res, 1); StoreGPRRegister(X86State::REG_RAX, Result_Lower); StoreGPRRegister(X86State::REG_RDX, Result_Upper); @@ -1573,19 +1497,19 @@ void OpDispatchBuilder::SHLOp(OpcodeArgs) { auto Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); auto Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = _Lshl(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Src); + OrderedNode* Result = _Lshl(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Src); HandleShift(Op, Result, Dest, ShiftType::LSL, Src); } template void OpDispatchBuilder::SHLImmediateOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); uint64_t Shift = LoadConstantShift(Op, SHL1Bit); const auto Size = GetSrcBitSize(Op); - OrderedNode *Src = _Constant(Size, Shift); - OrderedNode *Result = _Lshl(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Src); + OrderedNode* Src = _Constant(Size, Shift); + OrderedNode* Result = _Lshl(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Src); StoreResult(GPRClass, Op, Result, -1); @@ -1607,7 +1531,7 @@ void OpDispatchBuilder::SHRImmediateOp(OpcodeArgs) { uint64_t Shift = LoadConstantShift(Op, SHR1Bit); const auto Size = GetSrcBitSize(Op); - OrderedNode *Src = _Constant(Size, Shift); + OrderedNode* Src = _Constant(Size, Shift); auto ALUOp = _Lshr(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Src); StoreResult(GPRClass, Op, ALUOp, -1); @@ -1618,11 +1542,11 @@ void OpDispatchBuilder::SHLDOp(OpcodeArgs) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); // Allow garbage on the shift, we're masking it anyway. - OrderedNode *Shift = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Shift = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); const auto Size = GetSrcBitSize(Op); @@ -1635,13 +1559,12 @@ void OpDispatchBuilder::SHLDOp(OpcodeArgs) { // a64 masks the bottom bits, so if we're using a native 32/64-bit shift, we // can negate to do the subtract (it's congruent), which saves a constant. - auto ShiftRight = Size >= 32 ? _Neg(OpSize::i64Bit, Shift) : - _Sub(OpSize::i64Bit, _Constant(Size), Shift); + auto ShiftRight = Size >= 32 ? _Neg(OpSize::i64Bit, Shift) : _Sub(OpSize::i64Bit, _Constant(Size), Shift); auto Tmp1 = _Lshl(OpSize::i64Bit, Dest, Shift); auto Tmp2 = _Lshr(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Src, ShiftRight); - OrderedNode *Res = _Or(OpSize::i64Bit, Tmp1, Tmp2); + OrderedNode* Res = _Or(OpSize::i64Bit, Tmp1, Tmp2); // If shift count was zero then output doesn't change // Needs to be checked for the 32bit operand case @@ -1652,40 +1575,36 @@ void OpDispatchBuilder::SHLDOp(OpcodeArgs) { // // TODO: This whole function wants to be wrapped in the if. Maybe b/w pass is // a good idea after all. - Res = _Select(FEXCore::IR::COND_EQ, - Shift, _Constant(0), - Dest, Res); + Res = _Select(FEXCore::IR::COND_EQ, Shift, _Constant(0), Dest, Res); HandleShift(Op, Res, Dest, ShiftType::LSL, Shift); } void OpDispatchBuilder::SHLDImmediateOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); uint64_t Shift = LoadConstantShift(Op, false); const auto Size = GetSrcBitSize(Op); if (Shift != 0) { - OrderedNode *Res{}; + OrderedNode* Res {}; if (Size < 32) { - OrderedNode *ShiftLeft = _Constant(Shift); + OrderedNode* ShiftLeft = _Constant(Shift); auto ShiftRight = _Constant(Size - Shift); auto Tmp1 = _Lshl(OpSize::i64Bit, Dest, ShiftLeft); auto Tmp2 = _Lshr(OpSize::i32Bit, Src, ShiftRight); Res = _Or(OpSize::i64Bit, Tmp1, Tmp2); - } - else { + } else { // 32-bit and 64-bit SHLD behaves like an EXTR where the lower bits are filled from the source. Res = _Extr(OpSizeFromSrc(Op), Dest, Src, Size - Shift); } StoreResult(GPRClass, Op, Res, -1); GenerateFlags_ShiftLeftImmediate(Op, Res, Dest, Shift); - } - else if (Shift == 0 && Size == 32) { + } else if (Shift == 0 && Size == 32) { // Ensure Zext still occurs StoreResult(GPRClass, Op, Dest, -1); } @@ -1696,10 +1615,10 @@ void OpDispatchBuilder::SHRDOp(OpcodeArgs) { // This instruction conditionally generates flags so we need to insure sane state going in. CalculateDeferredFlags(); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Shift = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* Shift = LoadGPRRegister(X86State::REG_RCX); const auto Size = GetDstBitSize(Op); @@ -1715,45 +1634,41 @@ void OpDispatchBuilder::SHRDOp(OpcodeArgs) { auto Tmp1 = _Lshr(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Shift); auto Tmp2 = _Lshl(OpSize::i64Bit, Src, ShiftLeft); - OrderedNode *Res = _Or(OpSize::i64Bit, Tmp1, Tmp2); + OrderedNode* Res = _Or(OpSize::i64Bit, Tmp1, Tmp2); // If shift count was zero then output doesn't change // Needs to be checked for the 32bit operand case // where shift = 0 and the source register still gets Zext - Res = _Select(FEXCore::IR::COND_EQ, - Shift, _Constant(0), - Dest, Res); + Res = _Select(FEXCore::IR::COND_EQ, Shift, _Constant(0), Dest, Res); HandleShift(Op, Res, Dest, ShiftType::LSR, Shift); } void OpDispatchBuilder::SHRDImmediateOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); uint64_t Shift = LoadConstantShift(Op, false); const auto Size = GetSrcBitSize(Op); if (Shift != 0) { - OrderedNode *Res{}; + OrderedNode* Res {}; if (Size < 32) { - OrderedNode *ShiftRight = _Constant(Shift); + OrderedNode* ShiftRight = _Constant(Shift); auto ShiftLeft = _Constant(Size - Shift); auto Tmp1 = _Lshr(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, ShiftRight); auto Tmp2 = _Lshl(OpSize::i64Bit, Src, ShiftLeft); Res = _Or(OpSize::i64Bit, Tmp1, Tmp2); - } - else { + } else { // 32-bit and 64-bit SHRD behaves like an EXTR where the upper bits are filled from the source. Res = _Extr(OpSizeFromSrc(Op), Src, Dest, Shift); } StoreResult(GPRClass, Op, Res, -1); GenerateFlags_ShiftRightDoubleImmediate(Op, Res, Dest, Shift); - } - else if (Shift == 0 && Size == 32) { + } else if (Shift == 0 && Size == 32) { // Ensure Zext still occurs StoreResult(GPRClass, Op, Dest, -1); } @@ -1768,13 +1683,13 @@ void OpDispatchBuilder::ASHROp(OpcodeArgs) { Dest = _Sbfe(OpSize::i64Bit, Size, 0, Dest); } - OrderedNode *Result = _Ashr(IR::SizeToOpSize(std::max(4, GetSrcSize(Op))), Dest, Src); + OrderedNode* Result = _Ashr(IR::SizeToOpSize(std::max(4, GetSrcSize(Op))), Dest, Src); HandleShift(Op, Result, Dest, ShiftType::ASR, Src); } template void OpDispatchBuilder::ASHRImmediateOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); uint64_t Shift = LoadConstantShift(Op, SHR1Bit); const auto Size = GetSrcBitSize(Op); @@ -1783,8 +1698,8 @@ void OpDispatchBuilder::ASHRImmediateOp(OpcodeArgs) { Dest = _Sbfe(OpSize::i64Bit, Size, 0, Dest); } - OrderedNode *Src = _Constant(Size, Shift); - OrderedNode *Result = _Ashr(IR::SizeToOpSize(std::max(4, GetOpSize(Dest))), Dest, Src); + OrderedNode* Src = _Constant(Size, Shift); + OrderedNode* Result = _Ashr(IR::SizeToOpSize(std::max(4, GetOpSize(Dest))), Dest, Src); StoreResult(GPRClass, Op, Result, -1); @@ -1795,7 +1710,7 @@ template void OpDispatchBuilder::RotateOp(OpcodeArgs) { CalculateDeferredFlags(); - auto LoadShift = [this, Op](bool MustMask) -> OrderedNode * { + auto LoadShift = [this, Op](bool MustMask) -> OrderedNode* { if (Is1Bit || IsImmediate) { return _Constant(LoadConstantShift(Op, Is1Bit)); } else { @@ -1808,7 +1723,7 @@ void OpDispatchBuilder::RotateOp(OpcodeArgs) { } }; - Calculate_ShiftVariable(LoadShift(true), [this, LoadShift, Op](){ + Calculate_ShiftVariable(LoadShift(true), [this, LoadShift, Op]() { const uint32_t Size = GetSrcBitSize(Op); const auto OpSize = Size == 64 ? OpSize::i64Bit : OpSize::i32Bit; @@ -1839,8 +1754,9 @@ void OpDispatchBuilder::RotateOp(OpcodeArgs) { // Ends up faster overall if we don't have FlagM, slower if we do... // If Shift != 1, OF is undefined so we choose to zero here. - if (!CTX->HostFeatures.SupportsFlagM) + if (!CTX->HostFeatures.SupportsFlagM) { ZeroCV(); + } // Extract the last bit shifted in to CF SetRFLAG(Res, Left ? 0 : Size - 1, true); @@ -1883,9 +1799,7 @@ void OpDispatchBuilder::BEXTRBMIOp(OpcodeArgs) { auto Shifted = _Lshr(IR::SizeToOpSize(Size), Src1, Start); // Shifts larger than operand size need to be set to zero. - auto SanitizedShifted = _Select(IR::COND_ULE, - Start, MaxSrcBitOp, - Shifted, _Constant(SrcSize, 0)); + auto SanitizedShifted = _Select(IR::COND_ULE, Start, MaxSrcBitOp, Shifted, _Constant(SrcSize, 0)); // Now handle the length specifier. auto Length = _Bfe(OpSizeFromSrc(Op), 8, 8, Src2); @@ -1980,11 +1894,9 @@ void OpDispatchBuilder::BZHI(OpcodeArgs) { // In 32-bit mode we only look at bottom 32-bit, no 8 or 16-bit BZHI so no // need to zero-extend sources - auto* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, - {.AllowUpperGarbage = true}); + auto* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); - auto* Index = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, - {.AllowUpperGarbage = true}); + auto* Index = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); // Clear the high bits specified by the index. A64 only considers bottom bits // of the shift, so we don't need to mask bottom 8-bits ourselves. @@ -1997,13 +1909,12 @@ void OpDispatchBuilder::BZHI(OpcodeArgs) { // considers the bottom 8-bits, so we really want to know if the bottom 8-bits // have their top bits set. Test exactly that. _TestNZ(OpSize::i64Bit, Index, _Constant(0xFF & ~(OperandSize - 1))); - auto Result = _NZCVSelect(IR::SizeToOpSize(Size), CondClassType{COND_NEQ}, - Src, MaskResult); + auto Result = _NZCVSelect(IR::SizeToOpSize(Size), CondClassType {COND_NEQ}, Src, MaskResult); StoreResult(GPRClass, Op, Result, -1); auto Zero = _Constant(0); auto One = _Constant(1); - auto CF = _NZCVSelect(OpSize::i32Bit, CondClassType{COND_NEQ}, One, Zero); + auto CF = _NZCVSelect(OpSize::i32Bit, CondClassType {COND_NEQ}, One, Zero); GenerateFlags_BZHI(Op, Result, CF); } @@ -2015,8 +1926,7 @@ void OpDispatchBuilder::RORX(OpcodeArgs) { const auto GPRSize = CTX->GetGPRSize(); const auto DoRotation = Amount != 0 && Amount < SrcSizeBits; - const auto IsSameGPR = Op->Src[0].IsGPR() && Op->Dest.IsGPR() && - Op->Src[0].Data.GPR.GPR == Op->Dest.Data.GPR.GPR; + const auto IsSameGPR = Op->Src[0].IsGPR() && Op->Dest.IsGPR() && Op->Src[0].Data.GPR.GPR == Op->Dest.Data.GPR.GPR; const auto SrcSizeIsGPRSize = SrcSize == GPRSize; // If we don't need to rotate and our source is the same as the destination @@ -2128,10 +2038,10 @@ void OpDispatchBuilder::RCROp1Bit(OpcodeArgs) { CalculateDeferredFlags(); // We expliclty mask for <32-bit so allow garbage - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); const auto Size = GetSrcBitSize(Op); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); - OrderedNode *Res; + OrderedNode* Res; // Our new CF will be bit 0 of the source. Set upfront to avoid a move. SetRFLAG(Dest, 0, true); @@ -2141,8 +2051,7 @@ void OpDispatchBuilder::RCROp1Bit(OpcodeArgs) { if (Size == 32 || Size == 64) { // Rotate and insert CF in the upper bit Res = _Extr(OpSizeFromSrc(Op), CF, Dest, Shift); - } - else { + } else { // Res = Src >> Shift Res = _Bfe(OpSize::i32Bit, Size - Shift, Shift, Dest); @@ -2161,7 +2070,7 @@ void OpDispatchBuilder::RCROp8x1Bit(OpcodeArgs) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); const auto SizeBit = GetSrcBitSize(Op); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); @@ -2169,7 +2078,7 @@ void OpDispatchBuilder::RCROp8x1Bit(OpcodeArgs) { SetRFLAG(Dest, 0, true); // Rotate and insert CF in the upper bit - OrderedNode *Res = _Bfe(OpSize::i32Bit, 7, 1, Dest); + OrderedNode* Res = _Bfe(OpSize::i32Bit, 7, 1, Dest); Res = _Bfi(OpSize::i32Bit, 1, 7, Res, CF); StoreResult(GPRClass, Op, Res, -1); @@ -2192,24 +2101,26 @@ void OpDispatchBuilder::RCROp(OpcodeArgs) { CalculateDeferredFlags(); const auto OpSize = OpSizeFromSrc(Op); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); uint64_t Const; if (IsValueConstant(WrapNode(Src), &Const)) { Const &= Mask; - if (!Const) + if (!Const) { return; + } - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); // Res = Src >> Shift - OrderedNode *Res = _Lshr(OpSize, Dest, Src); + OrderedNode* Res = _Lshr(OpSize, Dest, Src); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); InvalidateDeferredFlags(); // Constant folded version of the above, with fused shifts. - if (Const > 1) + if (Const > 1) { Res = _Orlshl(OpSize, Res, Dest, Size + 1 - Const); + } // Our new CF will be bit (Shift - 1) of the source. SetRFLAG(Dest, Const - 1, true); @@ -2228,14 +2139,14 @@ void OpDispatchBuilder::RCROp(OpcodeArgs) { return; } - OrderedNode *SrcMasked = _And(OpSize, Src, _Constant(Size, Mask)); - Calculate_ShiftVariable(SrcMasked, [this, Op, Size, OpSize](){ + OrderedNode* SrcMasked = _And(OpSize, Src, _Constant(Size, Mask)); + Calculate_ShiftVariable(SrcMasked, [this, Op, Size, OpSize]() { // Rematerialize loads to avoid crossblock liveness - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); // Res = Src >> Shift - OrderedNode *Res = _Lshr(OpSize, Dest, Src); + OrderedNode* Res = _Lshr(OpSize, Dest, Src); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); auto One = _Constant(Size, 1); @@ -2248,7 +2159,7 @@ void OpDispatchBuilder::RCROp(OpcodeArgs) { // The masking of Lshl means we don't need mask the source, since: // // -(x & Mask) & Mask = (-x) & Mask - OrderedNode *NegSrc = _Neg(OpSize, Src); + OrderedNode* NegSrc = _Neg(OpSize, Src); Res = _Orlshl(OpSize, Res, _Lshl(OpSize, Dest, NegSrc), 1); // Our new CF will be bit (Shift - 1) of the source. this is hoisted up to @@ -2274,19 +2185,19 @@ void OpDispatchBuilder::RCRSmallerOp(OpcodeArgs) { const auto Size = GetSrcBitSize(Op); // x86 masks the shift by 0x3F or 0x1F depending on size of op - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); Src = AndConst(OpSize::i32Bit, Src, 0x1F); // CF only changes if we actually shifted. OF undefined if we didn't shift. // The result is unchanged if we didn't shift. So branch over the whole thing. - Calculate_ShiftVariable(Src, [this, Op, Size](){ + Calculate_ShiftVariable(Src, [this, Op, Size]() { // Rematerialized to avoid crossblock liveness - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Tmp{}; + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Tmp {}; // Insert the incoming value across the temporary 64bit source // Make sure to insert at + 1 offsets @@ -2321,8 +2232,7 @@ void OpDispatchBuilder::RCRSmallerOp(OpcodeArgs) { // Final cascade, copies 9 bits again from itself. Tmp = _Bfi(OpSize::i64Bit, 9, 36, Tmp, Tmp); - } - else { + } else { // 16-bit optimal cascade // Cascade: 0 // Data: -> [15:0] @@ -2346,7 +2256,7 @@ void OpDispatchBuilder::RCRSmallerOp(OpcodeArgs) { // Entire bitfield has been setup // Just extract the 8 or 16bits we need - OrderedNode *Res = _Lshr(OpSize::i32Bit, Tmp, Src); + OrderedNode* Res = _Lshr(OpSize::i32Bit, Tmp, Src); StoreResult(GPRClass, Op, Res, -1); @@ -2377,14 +2287,14 @@ void OpDispatchBuilder::RCLOp1Bit(OpcodeArgs) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); const auto Size = GetSrcBitSize(Op); const auto OpSize = Size == 64 ? OpSize::i64Bit : OpSize::i32Bit; auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); // Rotate left and insert CF in to lowest bit // TODO: Use `adc Res, xzr, Dest, lsl 1` to save an instruction - OrderedNode *Res = _Orlshl(OpSize, CF, Dest, 1); + OrderedNode* Res = _Orlshl(OpSize, CF, Dest, 1); StoreResult(GPRClass, Op, Res, -1); @@ -2409,25 +2319,27 @@ void OpDispatchBuilder::RCLOp(OpcodeArgs) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); const auto OpSize = OpSizeFromSrc(Op); uint64_t Const; if (IsValueConstant(WrapNode(Src), &Const)) { Const &= Mask; - if (!Const) + if (!Const) { return; + } // Res = Src << Shift - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Res = _Lshl(OpSize, Dest, Src); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Res = _Lshl(OpSize, Dest, Src); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); InvalidateDeferredFlags(); // Res |= (Src << (Size - Shift + 1)); - if (Const > 1) + if (Const > 1) { Res = _Orlshr(OpSize, Res, Dest, Size + 1 - Const); + } // Our new CF will be bit (Shift - 1) of the source SetRFLAG(Dest, Size - Const, true); @@ -2446,14 +2358,14 @@ void OpDispatchBuilder::RCLOp(OpcodeArgs) { return; } - OrderedNode *SrcMasked = _And(OpSize, Src, _Constant(Size, Mask)); - Calculate_ShiftVariable(SrcMasked, [this, Op, Size, OpSize](){ + OrderedNode* SrcMasked = _And(OpSize, Src, _Constant(Size, Mask)); + Calculate_ShiftVariable(SrcMasked, [this, Op, Size, OpSize]() { // Rematerialized to avoid crossblock liveness - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); // Res = Src << Shift - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Res = _Lshl(OpSize, Dest, Src); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Res = _Lshl(OpSize, Dest, Src); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); // Res |= (Dest >> (Size - Shift + 1)), expressed as @@ -2467,7 +2379,7 @@ void OpDispatchBuilder::RCLOp(OpcodeArgs) { SetRFLAG(NewCF, 0, true); // Since Shift != 0 we can inject the CF. Shift absorbs the masking. - OrderedNode *CFShl = _Sub(OpSize, Src, _Constant(Size, 1)); + OrderedNode* CFShl = _Sub(OpSize, Src, _Constant(Size, 1)); auto TmpCF = _Lshl(OpSize, CF, CFShl); Res = _Or(OpSize, Res, TmpCF); @@ -2489,20 +2401,20 @@ void OpDispatchBuilder::RCLSmallerOp(OpcodeArgs) { const auto Size = GetSrcBitSize(Op); // x86 masks the shift by 0x3F or 0x1F depending on size of op - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); Src = AndConst(OpSize::i32Bit, Src, 0x1F); // CF only changes if we actually shifted. OF undefined if we didn't shift. // The result is unchanged if we didn't shift. So branch over the whole thing. - Calculate_ShiftVariable(Src, [this, Op, Size](){ + Calculate_ShiftVariable(Src, [this, Op, Size]() { // Rematerialized to avoid crossblock liveness - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); Src = AndConst(OpSize::i32Bit, Src, 0x1F); - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); - OrderedNode *Tmp = _Constant(64, 0); + OrderedNode* Tmp = _Constant(64, 0); for (size_t i = 0; i < (32 + Size + 1); i += (Size + 1)) { // Insert incoming value @@ -2520,7 +2432,7 @@ void OpDispatchBuilder::RCLSmallerOp(OpcodeArgs) { // Shift 1 more bit that expected to get our result // Shifting to the right will now behave like a rotate to the left // Which we emulate with a _Ror - OrderedNode *Res = _Ror(OpSize::i64Bit, Tmp, _Neg(OpSize::i32Bit, Src)); + OrderedNode* Res = _Ror(OpSize::i64Bit, Tmp, _Neg(OpSize::i32Bit, Src)); StoreResult(GPRClass, Op, Res, -1); @@ -2542,8 +2454,8 @@ void OpDispatchBuilder::RCLSmallerOp(OpcodeArgs) { template void OpDispatchBuilder::BTOp(OpcodeArgs) { - OrderedNode *Value; - OrderedNode *Src{}; + OrderedNode* Value; + OrderedNode* Src {}; bool IsNonconstant = Op->Src[SrcIndex].IsGPR(); uint8_t ConstantShift = 0; @@ -2555,8 +2467,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { if (IsNonconstant) { // Because we mask explicitly with And/Bfe/Sbfe after, we can allow garbage here. - Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, - {.AllowUpperGarbage = true }); + Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true}); } else { // Can only be an immediate // Masked by operand size @@ -2590,21 +2501,21 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { } case BTAction::BTClear: { - OrderedNode *BitMask = _Lshl(IR::SizeToOpSize(LshrSize), _Constant(1), BitSelect); + OrderedNode* BitMask = _Lshl(IR::SizeToOpSize(LshrSize), _Constant(1), BitSelect); Dest = _Andn(IR::SizeToOpSize(LshrSize), Dest, BitMask); StoreResult(GPRClass, Op, Dest, -1); break; } case BTAction::BTSet: { - OrderedNode *BitMask = _Lshl(IR::SizeToOpSize(LshrSize), _Constant(1), BitSelect); + OrderedNode* BitMask = _Lshl(IR::SizeToOpSize(LshrSize), _Constant(1), BitSelect); Dest = _Or(IR::SizeToOpSize(LshrSize), Dest, BitMask); StoreResult(GPRClass, Op, Dest, -1); break; } case BTAction::BTComplement: { - OrderedNode *BitMask = _Lshl(IR::SizeToOpSize(LshrSize), _Constant(1), BitSelect); + OrderedNode* BitMask = _Lshl(IR::SizeToOpSize(LshrSize), _Constant(1), BitSelect); Dest = _Xor(IR::SizeToOpSize(LshrSize), Dest, BitMask); StoreResult(GPRClass, Op, Dest, -1); break; @@ -2612,9 +2523,9 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { } } else { // Load the address to the memory location - OrderedNode *Dest = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Dest = MakeSegmentAddress(Op, Op->Dest); // Get the bit selection from the src - OrderedNode *BitSelect = _Bfe(IR::SizeToOpSize(std::max(4u, GetOpSize(Src))), 3, 0, Src); + OrderedNode* BitSelect = _Bfe(IR::SizeToOpSize(std::max(4u, GetOpSize(Src))), 3, 0, Src); // Address is provided as bits we want BYTE offsets // Extract Signed offset @@ -2624,7 +2535,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { // Then use that to index in to the memory location by size of op // Now add the addresses together and load the memory - OrderedNode *MemoryLocation = _Add(OpSize::i64Bit, Dest, Src); + OrderedNode* MemoryLocation = _Add(OpSize::i64Bit, Dest, Src); ConstantShift = 0; @@ -2635,7 +2546,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { } case BTAction::BTClear: { - OrderedNode *BitMask = _Lshl(OpSize::i64Bit, _Constant(1), BitSelect); + OrderedNode* BitMask = _Lshl(OpSize::i64Bit, _Constant(1), BitSelect); if (DestIsLockedMem(Op)) { HandledLock = true; @@ -2650,7 +2561,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { } case BTAction::BTSet: { - OrderedNode *BitMask = _Lshl(OpSize::i64Bit, _Constant(1), BitSelect); + OrderedNode* BitMask = _Lshl(OpSize::i64Bit, _Constant(1), BitSelect); if (DestIsLockedMem(Op)) { HandledLock = true; @@ -2665,7 +2576,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { } case BTAction::BTComplement: { - OrderedNode *BitMask = _Lshl(OpSize::i64Bit, _Constant(1), BitSelect); + OrderedNode* BitMask = _Lshl(OpSize::i64Bit, _Constant(1), BitSelect); if (DestIsLockedMem(Op)) { HandledLock = true; @@ -2690,36 +2601,36 @@ void OpDispatchBuilder::BTOp(OpcodeArgs) { void OpDispatchBuilder::IMUL1SrcOp(OpcodeArgs) { /* We're just going to sign-extend the non-garbage anyway.. */ - OrderedNode *Src1 = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Src2 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src2 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); uint8_t Size = GetSrcSize(Op); - OrderedNode *Dest{}; - OrderedNode *ResultHigh{}; + OrderedNode* Dest {}; + OrderedNode* ResultHigh {}; switch (Size) { - case 1: - case 2: { - Src1 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src1); - Src2 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src2); - Dest = _Mul(OpSize::i64Bit, Src1, Src2); - ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, Dest); - break; - } - case 4: { - ResultHigh = _SMull(Src1, Src2); - ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, ResultHigh); - // Flipped order to save a move - Dest = _Mul(OpSize::i32Bit, Src1, Src2); - break; - } - case 8: { - ResultHigh = _MulH(OpSize::i64Bit, Src1, Src2); - // Flipped order to save a move - Dest = _Mul(OpSize::i64Bit, Src1, Src2); - break; - } - default: FEX_UNREACHABLE; + case 1: + case 2: { + Src1 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src1); + Src2 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src2); + Dest = _Mul(OpSize::i64Bit, Src1, Src2); + ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, Dest); + break; + } + case 4: { + ResultHigh = _SMull(Src1, Src2); + ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, ResultHigh); + // Flipped order to save a move + Dest = _Mul(OpSize::i32Bit, Src1, Src2); + break; + } + case 8: { + ResultHigh = _MulH(OpSize::i64Bit, Src1, Src2); + // Flipped order to save a move + Dest = _Mul(OpSize::i64Bit, Src1, Src2); + break; + } + default: FEX_UNREACHABLE; } StoreResult(GPRClass, Op, Dest, -1); @@ -2727,37 +2638,37 @@ void OpDispatchBuilder::IMUL1SrcOp(OpcodeArgs) { } void OpDispatchBuilder::IMUL2SrcOp(OpcodeArgs) { - OrderedNode *Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Src2 = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src2 = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = true}); uint8_t Size = GetSrcSize(Op); - OrderedNode *Dest{}; - OrderedNode *ResultHigh{}; + OrderedNode* Dest {}; + OrderedNode* ResultHigh {}; switch (Size) { - case 1: - case 2: { - Src1 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src1); - Src2 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src2); - Dest = _Mul(OpSize::i64Bit, Src1, Src2); - ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, Dest); - break; - } - case 4: { - ResultHigh = _SMull(Src1, Src2); - ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, ResultHigh); - // Flipped order to save a move - Dest = _Mul(OpSize::i32Bit, Src1, Src2); - break; - } - case 8: { - ResultHigh = _MulH(OpSize::i64Bit, Src1, Src2); - // Flipped order to save a move - Dest = _Mul(OpSize::i64Bit, Src1, Src2); - break; - } - default: FEX_UNREACHABLE; + case 1: + case 2: { + Src1 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src1); + Src2 = _Sbfe(OpSize::i64Bit, Size * 8, 0, Src2); + Dest = _Mul(OpSize::i64Bit, Src1, Src2); + ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, Dest); + break; + } + case 4: { + ResultHigh = _SMull(Src1, Src2); + ResultHigh = _Sbfe(OpSize::i64Bit, Size * 8, Size * 8, ResultHigh); + // Flipped order to save a move + Dest = _Mul(OpSize::i32Bit, Src1, Src2); + break; + } + case 8: { + ResultHigh = _MulH(OpSize::i64Bit, Src1, Src2); + // Flipped order to save a move + Dest = _Mul(OpSize::i64Bit, Src1, Src2); + break; + } + default: FEX_UNREACHABLE; } StoreResult(GPRClass, Op, Dest, -1); @@ -2767,7 +2678,7 @@ void OpDispatchBuilder::IMUL2SrcOp(OpcodeArgs) { void OpDispatchBuilder::IMULOp(OpcodeArgs) { const uint8_t Size = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RAX); if (Size != 8) { @@ -2776,21 +2687,19 @@ void OpDispatchBuilder::IMULOp(OpcodeArgs) { } // 64-bit special cased to save a move - OrderedNode *Result = Size < 8 ? _Mul(OpSize::i64Bit, Src1, Src2) : nullptr; - OrderedNode *ResultHigh{}; + OrderedNode* Result = Size < 8 ? _Mul(OpSize::i64Bit, Src1, Src2) : nullptr; + OrderedNode* ResultHigh {}; if (Size == 1) { // Result is stored in AX StoreGPRRegister(X86State::REG_RAX, Result, 2); ResultHigh = _Sbfe(OpSize::i64Bit, 8, 8, Result); - } - else if (Size == 2) { + } else if (Size == 2) { // 16bits stored in AX // 16bits stored in DX StoreGPRRegister(X86State::REG_RAX, Result, Size); ResultHigh = _Sbfe(OpSize::i64Bit, 16, 16, Result); StoreGPRRegister(X86State::REG_RDX, ResultHigh, Size); - } - else if (Size == 4) { + } else if (Size == 4) { // 32bits stored in EAX // 32bits stored in EDX // Make sure they get Zext correctly @@ -2800,8 +2709,7 @@ void OpDispatchBuilder::IMULOp(OpcodeArgs) { Result = _Sbfe(OpSize::i64Bit, 32, 0, Result); StoreGPRRegister(X86State::REG_RAX, LocalResult); StoreGPRRegister(X86State::REG_RDX, LocalResultHigh); - } - else if (Size == 8) { + } else if (Size == 8) { if (!CTX->Config.Is64BitMode) { LogMan::Msg::EFmt("Doesn't exist in 32bit mode"); DecodeFailure = true; @@ -2821,37 +2729,34 @@ void OpDispatchBuilder::IMULOp(OpcodeArgs) { void OpDispatchBuilder::MULOp(OpcodeArgs) { const uint8_t Size = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RAX); if (Size != 8) { Src1 = _Bfe(OpSize::i64Bit, Size * 8, 0, Src1); Src2 = _Bfe(OpSize::i64Bit, Size * 8, 0, Src2); } - OrderedNode *Result = _UMul(OpSize::i64Bit, Src1, Src2); - OrderedNode *ResultHigh{}; + OrderedNode* Result = _UMul(OpSize::i64Bit, Src1, Src2); + OrderedNode* ResultHigh {}; if (Size == 1) { // Result is stored in AX StoreGPRRegister(X86State::REG_RAX, Result, 2); ResultHigh = _Bfe(OpSize::i64Bit, 8, 8, Result); - } - else if (Size == 2) { + } else if (Size == 2) { // 16bits stored in AX // 16bits stored in DX StoreGPRRegister(X86State::REG_RAX, Result, Size); ResultHigh = _Bfe(OpSize::i64Bit, 16, 16, Result); StoreGPRRegister(X86State::REG_RDX, ResultHigh, Size); - } - else if (Size == 4) { + } else if (Size == 4) { // 32bits stored in EAX // 32bits stored in EDX - OrderedNode *ResultLow = _Bfe(OpSize::i64Bit, 32, 0, Result); + OrderedNode* ResultLow = _Bfe(OpSize::i64Bit, 32, 0, Result); ResultHigh = _Bfe(OpSize::i64Bit, 32, 32, Result); StoreGPRRegister(X86State::REG_RAX, ResultLow); StoreGPRRegister(X86State::REG_RDX, ResultHigh); - } - else if (Size == 8) { + } else if (Size == 8) { if (!CTX->Config.Is64BitMode) { LogMan::Msg::EFmt("Doesn't exist in 32bit mode"); DecodeFailure = true; @@ -2869,21 +2774,20 @@ void OpDispatchBuilder::MULOp(OpcodeArgs) { void OpDispatchBuilder::NOTOp(OpcodeArgs) { uint8_t Size = GetSrcSize(Op); - OrderedNode *MaskConst{}; + OrderedNode* MaskConst {}; if (Size == 8) { MaskConst = _Constant(~0ULL); - } - else { + } else { MaskConst = _Constant((1ULL << (Size * 8)) - 1); } if (DestIsLockedMem(Op)) { HandledLock = true; - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); _AtomicXor(IR::SizeToOpSize(Size), MaskConst, DestMem); } else if (!Op->Dest.IsGPR()) { // GPR version plays fast and loose with sizes, be safe for memory tho. - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); Src = _Xor(OpSize::i64Bit, Src, MaskConst); StoreResult(GPRClass, Op, Src, -1); } else { @@ -2899,17 +2803,18 @@ void OpDispatchBuilder::NOTOp(OpcodeArgs) { // Always load full size, we explicitly want the upper bits to get the // insert behaviour for free/implicitly. const uint8_t GPRSize = CTX->GetGPRSize(); - OrderedNode *Src = LoadSource_WithOpSize(GPRClass, Op, Dest, GPRSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(GPRClass, Op, Dest, GPRSize, Op->Flags); // For 8/16-bit, use 64-bit invert so we invert in place, while getting // insert behaviour. For 32-bit, use 32-bit invert to zero the upper bits. unsigned EffectiveSize = Size == 4 ? 4 : GPRSize; // If we're inverting the whole thing, use Not instead of Xor to save a constant. - if (Size >= 4) + if (Size >= 4) { Src = _Not(IR::SizeToOpSize(EffectiveSize), Src); - else + } else { Src = _Xor(IR::SizeToOpSize(EffectiveSize), Src, MaskConst); + } // Always store 64-bit, the Not/Xor correctly handle the upper bits and this // way we can delete the store. @@ -2918,9 +2823,9 @@ void OpDispatchBuilder::NOTOp(OpcodeArgs) { } void OpDispatchBuilder::XADDOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false}); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result; + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result; if (Op->Dest.IsGPR()) { // If this is a GPR then we can just do an Add @@ -2931,8 +2836,7 @@ void OpDispatchBuilder::XADDOp(OpcodeArgs) { // Calculated value gets stored in dst (order is important if dst is same as src) StoreResult(GPRClass, Op, Result, -1); - } - else { + } else { HandledLock = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK; Dest = AppendSegmentOffset(Dest, Op->Flags); auto Before = _AtomicFetchAdd(OpSizeFromSrc(Op), Src, Dest); @@ -2943,17 +2847,16 @@ void OpDispatchBuilder::XADDOp(OpcodeArgs) { } void OpDispatchBuilder::PopcountOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = GetSrcSize(Op) >= 4}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = GetSrcSize(Op) >= 4}); Src = _Popcount(OpSizeFromSrc(Op), Src); StoreResult(GPRClass, Op, Src, -1); GenerateFlags_POPCOUNT(Op, Src); } -OrderedNode *OpDispatchBuilder::CalculateAFForDecimal(OrderedNode *A) { +OrderedNode* OpDispatchBuilder::CalculateAFForDecimal(OrderedNode* A) { auto Nibble = _And(OpSize::i64Bit, A, _Constant(0xF)); - auto Greater = _Select(FEXCore::IR::COND_UGT, Nibble, _Constant(9), - _Constant(1), _Constant(0)); + auto Greater = _Select(FEXCore::IR::COND_UGT, Nibble, _Constant(9), _Constant(1), _Constant(0)); return _Or(OpSize::i64Bit, LoadAF(), Greater); } @@ -2968,12 +2871,10 @@ void OpDispatchBuilder::DAAOp(OpcodeArgs) { CF = _Or(OpSize::i64Bit, CF, _Select(FEXCore::IR::COND_UGT, AL, _Constant(0x99), _Constant(1), _Constant(0))); // AL = AF ? (AL + 0x6) : AL; - AL = _Select(FEXCore::IR::COND_NEQ, AF, _Constant(0), - _Add(OpSize::i64Bit, AL, _Constant(0x6)), AL); + AL = _Select(FEXCore::IR::COND_NEQ, AF, _Constant(0), _Add(OpSize::i64Bit, AL, _Constant(0x6)), AL); // AL = CF ? (AL + 0x60) : AL; - AL = _Select(FEXCore::IR::COND_NEQ, CF, _Constant(0), - _Add(OpSize::i64Bit, AL, _Constant(0x60)), AL); + AL = _Select(FEXCore::IR::COND_NEQ, CF, _Constant(0), _Add(OpSize::i64Bit, AL, _Constant(0x60)), AL); // SF, ZF, PF set according to result. CF set per above. OF undefined. StoreGPRRegister(X86State::REG_RAX, AL, 1); @@ -2996,12 +2897,10 @@ void OpDispatchBuilder::DASOp(OpcodeArgs) { auto NewCF = _Or(OpSize::i32Bit, CF, _Select(FEXCore::IR::COND_ULT, AL, _Constant(6), AF, CF)); // AL = AF ? (AL - 0x6) : AL; - AL = _Select(FEXCore::IR::COND_NEQ, AF, _Constant(0), - _Sub(OpSize::i64Bit, AL, _Constant(0x6)), AL); + AL = _Select(FEXCore::IR::COND_NEQ, AF, _Constant(0), _Sub(OpSize::i64Bit, AL, _Constant(0x6)), AL); // AL = CF ? (AL - 0x60) : AL; - AL = _Select(FEXCore::IR::COND_NEQ, CF, _Constant(0), - _Sub(OpSize::i64Bit, AL, _Constant(0x60)), AL); + AL = _Select(FEXCore::IR::COND_NEQ, CF, _Constant(0), _Sub(OpSize::i64Bit, AL, _Constant(0x60)), AL); // SF, ZF, PF set according to result. CF set per above. OF undefined. StoreGPRRegister(X86State::REG_RAX, AL, 1); @@ -3024,8 +2923,7 @@ void OpDispatchBuilder::AAAOp(OpcodeArgs) { CalculateDeferredFlags(); // AX = CF ? (AX + 0x106) : 0 - A = _NZCVSelect(OpSize::i32Bit, CondClassType{COND_UGE} /* CF = 1 */, - _Add(OpSize::i32Bit, A, _Constant(0x106)), A); + A = _NZCVSelect(OpSize::i32Bit, CondClassType {COND_UGE} /* CF = 1 */, _Add(OpSize::i32Bit, A, _Constant(0x106)), A); // AL = AL & 0x0F A = _And(OpSize::i32Bit, A, _Constant(0xFF0F)); @@ -3045,8 +2943,7 @@ void OpDispatchBuilder::AASOp(OpcodeArgs) { CalculateDeferredFlags(); // AX = CF ? (AX - 0x106) : 0 - A = _NZCVSelect(OpSize::i32Bit, CondClassType{COND_UGE} /* CF = 1 */, - _Sub(OpSize::i32Bit, A, _Constant(0x106)), A); + A = _NZCVSelect(OpSize::i32Bit, CondClassType {COND_UGE} /* CF = 1 */, _Sub(OpSize::i32Bit, A, _Constant(0x106)), A); // AL = AL & 0x0F A = _And(OpSize::i32Bit, A, _Constant(0xFF0F)); @@ -3084,9 +2981,8 @@ void OpDispatchBuilder::AADOp(OpcodeArgs) { } void OpDispatchBuilder::XLATOp(OpcodeArgs) { - OrderedNode *Src = MakeSegmentAddress(X86State::REG_RBX, Op->Flags, - X86Tables::DecodeFlags::FLAG_DS_PREFIX); - OrderedNode *Offset = LoadGPRRegister(X86State::REG_RAX, 1); + OrderedNode* Src = MakeSegmentAddress(X86State::REG_RBX, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); + OrderedNode* Offset = LoadGPRRegister(X86State::REG_RAX, 1); Src = _Add(OpSize::i64Bit, Src, Offset); @@ -3100,11 +2996,10 @@ void OpDispatchBuilder::ReadSegmentReg(OpcodeArgs) { // 64-bit only // Doesn't hit the segment register optimization auto Size = GetSrcSize(Op); - OrderedNode *Src{}; + OrderedNode* Src {}; if constexpr (Seg == Segment::FS) { Src = _LoadContext(Size, GPRClass, offsetof(FEXCore::Core::CPUState, fs_cached)); - } - else { + } else { Src = _LoadContext(Size, GPRClass, offsetof(FEXCore::Core::CPUState, gs_cached)); } @@ -3116,11 +3011,10 @@ void OpDispatchBuilder::WriteSegmentReg(OpcodeArgs) { // Documentation claims that the 32-bit version of this instruction inserts in to the lower 32-bits of the segment // This is incorrect and it instead zero extends the 32-bit value to 64-bit auto Size = GetDstSize(Op); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); if constexpr (Seg == Segment::FS) { _StoreContext(Size, GPRClass, Src, offsetof(FEXCore::Core::CPUState, fs_cached)); - } - else { + } else { _StoreContext(Size, GPRClass, Src, offsetof(FEXCore::Core::CPUState, gs_cached)); } } @@ -3134,7 +3028,7 @@ void OpDispatchBuilder::EnterOp(OpcodeArgs) { const uint16_t AllocSpace = Value & 0xFFFF; const uint8_t Level = (Value >> 16) & 0x1F; - const auto PushValue = [&](uint8_t Size, OrderedNode *Src) -> OrderedNode* { + const auto PushValue = [&](uint8_t Size, OrderedNode* Src) -> OrderedNode* { const uint8_t GPRSize = CTX->GetGPRSize(); auto OldSP = LoadGPRRegister(X86State::REG_RSP); @@ -3188,15 +3082,14 @@ void OpDispatchBuilder::SGDTOp(OpcodeArgs) { OpDispatchBuilder::CycleCounterPair OpDispatchBuilder::CycleCounter() { - OrderedNode *CounterLow{}; - OrderedNode *CounterHigh{}; + OrderedNode* CounterLow {}; + OrderedNode* CounterHigh {}; auto Counter = _CycleCounter(); if (CTX->Config.SmallTSCScale()) { const auto ShiftAmount = FEXCore::ilog2(FEXCore::Context::TSC_SCALE); CounterLow = _Lshl(OpSize::i32Bit, Counter, _Constant(ShiftAmount)); CounterHigh = _Lshr(OpSize::i64Bit, Counter, _Constant(32 - ShiftAmount)); - } - else { + } else { CounterLow = _Bfe(OpSize::i64Bit, 32, 0, Counter); CounterHigh = _Bfe(OpSize::i64Bit, 32, 32, Counter); } @@ -3220,8 +3113,8 @@ void OpDispatchBuilder::INCOp(OpcodeArgs) { return; } - OrderedNode *Dest; - OrderedNode *Result; + OrderedNode* Dest; + OrderedNode* Result; const auto Size = GetSrcBitSize(Op); auto OneConst = _Constant(Size, 1); @@ -3230,7 +3123,7 @@ void OpDispatchBuilder::INCOp(OpcodeArgs) { if (IsLocked) { HandledLock = true; - OrderedNode *DestAddress = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestAddress = MakeSegmentAddress(Op, Op->Dest); Dest = _AtomicFetchAdd(OpSizeFromSrc(Op), OneConst, DestAddress); } else { Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = Size >= 32}); @@ -3267,8 +3160,8 @@ void OpDispatchBuilder::DECOp(OpcodeArgs) { return; } - OrderedNode *Dest; - OrderedNode *Result; + OrderedNode* Dest; + OrderedNode* Result; const auto Size = GetSrcBitSize(Op); auto OneConst = _Constant(Size, 1); @@ -3277,7 +3170,7 @@ void OpDispatchBuilder::DECOp(OpcodeArgs) { if (IsLocked) { HandledLock = true; - OrderedNode *DestAddress = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestAddress = MakeSegmentAddress(Op, Op->Dest); // Use Add instead of Sub to avoid a NEG Dest = _AtomicFetchAdd(OpSizeFromSrc(Op), _Constant(Size, -1), DestAddress); @@ -3321,29 +3214,28 @@ void OpDispatchBuilder::STOSOp(OpcodeArgs) { if (!Repeat) { // Src is used only for a store of the same size so allow garbage - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); // Only ES prefix - OrderedNode *Dest = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); + OrderedNode* Dest = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); // Store to memory where RDI points _StoreMemAutoTSO(GPRClass, Size, Dest, Src, Size); // Offset the pointer - OrderedNode *TailDest = LoadGPRRegister(X86State::REG_RDI); + OrderedNode* TailDest = LoadGPRRegister(X86State::REG_RDI); StoreGPRRegister(X86State::REG_RDI, OffsetByDir(TailDest, Size)); - } - else { + } else { // FEX doesn't support partial faulting REP instructions. // Converting this to a `MemSet` IR op optimizes this quite significantly in our codegen. // If FEX is to gain support for faulting REP instructions, then this implementation needs to change significantly. - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadGPRRegister(X86State::REG_RDI); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadGPRRegister(X86State::REG_RDI); // Only ES prefix auto Segment = GetSegment(0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); - OrderedNode *Counter = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* Counter = LoadGPRRegister(X86State::REG_RCX); auto Result = _MemSet(CTX->IsAtomicTSOEnabled(), Size, Segment ?: InvalidNode, Dest, Src, Counter, LoadDir(1)); StoreGPRRegister(X86State::REG_RCX, _Constant(0)); @@ -3369,22 +3261,18 @@ void OpDispatchBuilder::MOVSOp(OpcodeArgs) { auto DstSegment = GetSegment(0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); auto SrcSegment = GetSegment(Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX); - auto Result = _MemCpy(CTX->IsAtomicTSOEnabled(), Size, - DstSegment ?: InvalidNode, - SrcSegment ?: InvalidNode, - DstAddr, SrcAddr, Counter, - LoadDir(1)); + auto Result = + _MemCpy(CTX->IsAtomicTSOEnabled(), Size, DstSegment ?: InvalidNode, SrcSegment ?: InvalidNode, DstAddr, SrcAddr, Counter, LoadDir(1)); - OrderedNode *Result_Dst = _ExtractElementPair(OpSize::i64Bit, Result, 0); - OrderedNode *Result_Src = _ExtractElementPair(OpSize::i64Bit, Result, 1); + OrderedNode* Result_Dst = _ExtractElementPair(OpSize::i64Bit, Result, 0); + OrderedNode* Result_Src = _ExtractElementPair(OpSize::i64Bit, Result, 1); StoreGPRRegister(X86State::REG_RCX, _Constant(0)); StoreGPRRegister(X86State::REG_RDI, Result_Dst); StoreGPRRegister(X86State::REG_RSI, Result_Src); - } - else { - OrderedNode *RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); - OrderedNode *RDI = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); + } else { + OrderedNode* RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); + OrderedNode* RDI = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); auto Src = _LoadMemAutoTSO(GPRClass, Size, RSI, Size); @@ -3412,11 +3300,9 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) { bool Repeat = Op->Flags & (FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX | FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX); if (!Repeat) { // Default DS prefix - OrderedNode *Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, - X86Tables::DecodeFlags::FLAG_DS_PREFIX); + OrderedNode* Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); // Only ES prefix - OrderedNode *Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, - X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); + OrderedNode* Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); auto Src1 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size); auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RSI, Size); @@ -3432,15 +3318,14 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) { // Offset second pointer Dest_RSI = _Add(OpSize::i64Bit, Dest_RSI, PtrDir); StoreGPRRegister(X86State::REG_RSI, Dest_RSI); - } - else { + } else { // Calculate flags early. CalculateDeferredFlags(); bool REPE = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX; // If rcx = 0, skip the whole loop. - OrderedNode *Counter = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* Counter = LoadGPRRegister(X86State::REG_RCX); auto OuterJump = CondJump(Counter, {COND_EQ}); auto BeforeLoop = CreateNewCodeBlockAfter(GetCurrentBlock()); @@ -3461,11 +3346,9 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) { // Working loop { // Default DS prefix - OrderedNode *Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, - X86Tables::DecodeFlags::FLAG_DS_PREFIX); + OrderedNode* Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); // Only ES prefix - OrderedNode *Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, - X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); + OrderedNode* Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); auto Src1 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size); auto Src2 = _LoadMem(GPRClass, Size, Dest_RSI, Size); @@ -3474,7 +3357,7 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) { _StoreRegister(Src1, false, offsetof(FEXCore::Core::CPUState, pf_raw), GPRClass, GPRFixedClass, CTX->GetGPRSize()); _StoreRegister(Src2, false, offsetof(FEXCore::Core::CPUState, af_raw), GPRClass, GPRFixedClass, CTX->GetGPRSize()); - OrderedNode *TailCounter = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* TailCounter = LoadGPRRegister(X86State::REG_RCX); // Decrement counter TailCounter = _SubWithFlags(OpSize::i64Bit, TailCounter, _Constant(1)); @@ -3537,18 +3420,16 @@ void OpDispatchBuilder::LODSOp(OpcodeArgs) { const bool Repeat = (Op->Flags & (FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX | FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX)) != 0; if (!Repeat) { - OrderedNode *Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, - X86Tables::DecodeFlags::FLAG_DS_PREFIX); + OrderedNode* Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); auto Src = _LoadMemAutoTSO(GPRClass, Size, Dest_RSI, Size); StoreResult(GPRClass, Op, Src, -1); // Offset the pointer - OrderedNode *TailDest_RSI = LoadGPRRegister(X86State::REG_RSI); + OrderedNode* TailDest_RSI = LoadGPRRegister(X86State::REG_RSI); StoreGPRRegister(X86State::REG_RSI, OffsetByDir(TailDest_RSI, Size)); - } - else { + } else { // Calculate flags early. because end of block CalculateDeferredFlags(); @@ -3566,7 +3447,7 @@ void OpDispatchBuilder::LODSOp(OpcodeArgs) { SetCurrentCodeBlock(LoopStart); StartNewBlock(); - OrderedNode *Counter = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* Counter = LoadGPRRegister(X86State::REG_RCX); // Can we end the block? @@ -3580,15 +3461,14 @@ void OpDispatchBuilder::LODSOp(OpcodeArgs) { // Working loop { - OrderedNode *Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, - X86Tables::DecodeFlags::FLAG_DS_PREFIX); + OrderedNode* Dest_RSI = MakeSegmentAddress(X86State::REG_RSI, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); auto Src = _LoadMemAutoTSO(GPRClass, Size, Dest_RSI, Size); StoreResult(GPRClass, Op, Src, -1); - OrderedNode *TailCounter = LoadGPRRegister(X86State::REG_RCX); - OrderedNode *TailDest_RSI = LoadGPRRegister(X86State::REG_RSI); + OrderedNode* TailCounter = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* TailDest_RSI = LoadGPRRegister(X86State::REG_RSI); // Decrement counter TailCounter = _Sub(OpSize::i64Bit, TailCounter, _Constant(1)); @@ -3623,8 +3503,7 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) { const bool Repeat = (Op->Flags & (FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX | FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX)) != 0; if (!Repeat) { - OrderedNode *Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, - X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); + OrderedNode* Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size); @@ -3632,14 +3511,13 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) { GenerateFlags_SUB(Op, Src1, Src2); // Offset the pointer - OrderedNode *TailDest_RDI = LoadGPRRegister(X86State::REG_RDI); + OrderedNode* TailDest_RDI = LoadGPRRegister(X86State::REG_RDI); StoreGPRRegister(X86State::REG_RDI, OffsetByDir(TailDest_RDI, Size)); - } - else { + } else { // Calculate flags early. because end of block CalculateDeferredFlags(); - ForeachDirection([this, Op, Size](int Dir){ + ForeachDirection([this, Op, Size](int Dir) { bool REPE = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX; auto JumpStart = Jump(); @@ -3649,7 +3527,7 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) { SetCurrentCodeBlock(LoopStart); StartNewBlock(); - OrderedNode *Counter = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* Counter = LoadGPRRegister(X86State::REG_RCX); // Can we end the block? // We leave if RCX = 0 @@ -3663,8 +3541,7 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) { // Working loop { - OrderedNode *Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, - X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); + OrderedNode* Dest_RDI = MakeSegmentAddress(X86State::REG_RDI, 0, X86Tables::DecodeFlags::FLAG_ES_PREFIX, true); auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size); @@ -3674,8 +3551,8 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *TailCounter = LoadGPRRegister(X86State::REG_RCX); - OrderedNode *TailDest_RDI = LoadGPRRegister(X86State::REG_RDI); + OrderedNode* TailCounter = LoadGPRRegister(X86State::REG_RCX); + OrderedNode* TailDest_RDI = LoadGPRRegister(X86State::REG_RDI); // Decrement counter TailCounter = _Sub(OpSize::i64Bit, TailCounter, _Constant(1)); @@ -3706,13 +3583,12 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) { } void OpDispatchBuilder::BSWAPOp(OpcodeArgs) { - OrderedNode *Dest; + OrderedNode* Dest; const auto Size = GetSrcSize(Op); if (Size == 2) { // BSWAP of 16bit is undef. ZEN+ causes the lower 16bits to get zero'd Dest = _Constant(0); - } - else { + } else { Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, CTX->GetGPRSize(), Op->Flags); Dest = _Rev(IR::SizeToOpSize(Size), Dest); } @@ -3722,7 +3598,7 @@ void OpDispatchBuilder::BSWAPOp(OpcodeArgs) { void OpDispatchBuilder::PUSHFOp(OpcodeArgs) { const uint8_t Size = GetSrcSize(Op); - OrderedNode *Src = GetPackedRFLAG(); + OrderedNode* Src = GetPackedRFLAG(); if (Size != 8) { Src = _Bfe(OpSize::i32Bit, Size * 8, 0, Src); } @@ -3741,7 +3617,7 @@ void OpDispatchBuilder::POPFOp(OpcodeArgs) { auto Constant = _Constant(Size); auto OldSP = LoadGPRRegister(X86State::REG_RSP); - OrderedNode *Src = _LoadMem(GPRClass, Size, OldSP, Size); + OrderedNode* Src = _LoadMem(GPRClass, Size, OldSP, Size); auto NewSP = _Add(OpSize::i64Bit, OldSP, Constant); // Store the new stack pointer @@ -3763,13 +3639,12 @@ void OpDispatchBuilder::NEGOp(OpcodeArgs) { auto ZeroConst = _Constant(0); if (DestIsLockedMem(Op)) { - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); - OrderedNode *Dest = _AtomicFetchNeg(IR::SizeToOpSize(Size), DestMem); + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Dest = _AtomicFetchNeg(IR::SizeToOpSize(Size), DestMem); CalculateFlags_SUB(Size, ZeroConst, Dest); - } - else { - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Result = CalculateFlags_SUB(Size, ZeroConst, Dest); + } else { + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Result = CalculateFlags_SUB(Size, ZeroConst, Dest); StoreResult(GPRClass, Op, Result, -1); } @@ -3777,13 +3652,13 @@ void OpDispatchBuilder::NEGOp(OpcodeArgs) { void OpDispatchBuilder::DIVOp(OpcodeArgs) { // This loads the divisor - OrderedNode *Divisor = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Divisor = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); const auto GPRSize = CTX->GetGPRSize(); const auto Size = GetSrcSize(Op); if (Size == 1) { - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX, 2); + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX, 2); auto UDivOp = _UDiv(OpSize::i16Bit, Src1, Divisor); auto URemOp = _URem(OpSize::i16Bit, Src1, Divisor); @@ -3791,34 +3666,31 @@ void OpDispatchBuilder::DIVOp(OpcodeArgs) { // AX[15:0] = concat auto ResultAX = _Bfi(IR::SizeToOpSize(GPRSize), 8, 8, UDivOp, URemOp); StoreGPRRegister(X86State::REG_RAX, ResultAX, 2); - } - else if (Size == 2) { - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX, Size); - OrderedNode *Src2 = LoadGPRRegister(X86State::REG_RDX, Size); + } else if (Size == 2) { + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX, Size); + OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RDX, Size); auto UDivOp = _LUDiv(OpSize::i16Bit, Src1, Src2, Divisor); auto URemOp = _LURem(OpSize::i16Bit, Src1, Src2, Divisor); StoreGPRRegister(X86State::REG_RAX, UDivOp, Size); StoreGPRRegister(X86State::REG_RDX, URemOp, Size); - } - else if (Size == 4) { - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX, Size); - OrderedNode *Src2 = LoadGPRRegister(X86State::REG_RDX, Size); + } else if (Size == 4) { + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX, Size); + OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RDX, Size); - OrderedNode *UDivOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LUDiv(OpSize::i32Bit, Src1, Src2, Divisor)); - OrderedNode *URemOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LURem(OpSize::i32Bit, Src1, Src2, Divisor)); + OrderedNode* UDivOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LUDiv(OpSize::i32Bit, Src1, Src2, Divisor)); + OrderedNode* URemOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LURem(OpSize::i32Bit, Src1, Src2, Divisor)); StoreGPRRegister(X86State::REG_RAX, UDivOp); StoreGPRRegister(X86State::REG_RDX, URemOp); - } - else if (Size == 8) { + } else if (Size == 8) { if (!CTX->Config.Is64BitMode) { LogMan::Msg::EFmt("Doesn't exist in 32bit mode"); DecodeFailure = true; return; } - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX); - OrderedNode *Src2 = LoadGPRRegister(X86State::REG_RDX); + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX); + OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RDX); auto UDivOp = _LUDiv(OpSize::i64Bit, Src1, Src2, Divisor); auto URemOp = _LURem(OpSize::i64Bit, Src1, Src2, Divisor); @@ -3830,13 +3702,13 @@ void OpDispatchBuilder::DIVOp(OpcodeArgs) { void OpDispatchBuilder::IDIVOp(OpcodeArgs) { // This loads the divisor - OrderedNode *Divisor = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Divisor = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); const auto GPRSize = CTX->GetGPRSize(); const auto Size = GetSrcSize(Op); if (Size == 1) { - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX, 2); + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX, 2); Src1 = _Sbfe(OpSize::i64Bit, 16, 0, Src1); Divisor = _Sbfe(OpSize::i64Bit, 8, 0, Divisor); @@ -3846,34 +3718,31 @@ void OpDispatchBuilder::IDIVOp(OpcodeArgs) { // AX[15:0] = concat auto ResultAX = _Bfi(IR::SizeToOpSize(GPRSize), 8, 8, UDivOp, URemOp); StoreGPRRegister(X86State::REG_RAX, ResultAX, 2); - } - else if (Size == 2) { - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX, Size); - OrderedNode *Src2 = LoadGPRRegister(X86State::REG_RDX, Size); + } else if (Size == 2) { + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX, Size); + OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RDX, Size); auto UDivOp = _LDiv(OpSize::i16Bit, Src1, Src2, Divisor); auto URemOp = _LRem(OpSize::i16Bit, Src1, Src2, Divisor); StoreGPRRegister(X86State::REG_RAX, UDivOp, Size); StoreGPRRegister(X86State::REG_RDX, URemOp, Size); - } - else if (Size == 4) { - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX, Size); - OrderedNode *Src2 = LoadGPRRegister(X86State::REG_RDX, Size); + } else if (Size == 4) { + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX, Size); + OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RDX, Size); - OrderedNode *UDivOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LDiv(OpSize::i32Bit, Src1, Src2, Divisor)); - OrderedNode *URemOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LRem(OpSize::i32Bit, Src1, Src2, Divisor)); + OrderedNode* UDivOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LDiv(OpSize::i32Bit, Src1, Src2, Divisor)); + OrderedNode* URemOp = _Bfe(OpSize::i32Bit, Size * 8, 0, _LRem(OpSize::i32Bit, Src1, Src2, Divisor)); StoreGPRRegister(X86State::REG_RAX, UDivOp); StoreGPRRegister(X86State::REG_RDX, URemOp); - } - else if (Size == 8) { + } else if (Size == 8) { if (!CTX->Config.Is64BitMode) { LogMan::Msg::EFmt("Doesn't exist in 32bit mode"); DecodeFailure = true; return; } - OrderedNode *Src1 = LoadGPRRegister(X86State::REG_RAX); - OrderedNode *Src2 = LoadGPRRegister(X86State::REG_RDX); + OrderedNode* Src1 = LoadGPRRegister(X86State::REG_RAX); + OrderedNode* Src2 = LoadGPRRegister(X86State::REG_RDX); auto UDivOp = _LDiv(OpSize::i64Bit, Src1, Src2, Divisor); auto URemOp = _LRem(OpSize::i64Bit, Src1, Src2, Divisor); @@ -3886,8 +3755,8 @@ void OpDispatchBuilder::IDIVOp(OpcodeArgs) { void OpDispatchBuilder::BSFOp(OpcodeArgs) { const uint8_t GPRSize = CTX->GetGPRSize(); const uint8_t DstSize = GetDstSize(Op) == 2 ? 2 : GPRSize; - OrderedNode *Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, DstSize, Op->Flags); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, DstSize, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); InvalidateDeferredFlags(); CachedNZCV = nullptr; @@ -3900,15 +3769,15 @@ void OpDispatchBuilder::BSFOp(OpcodeArgs) { SetNZ_ZeroCV(GetSrcSize(Op), Src); // If Src was zero then the destination doesn't get modified - auto SelectOp = _NZCVSelect(IR::SizeToOpSize(GPRSize), CondClassType{COND_EQ}, Dest, Result); + auto SelectOp = _NZCVSelect(IR::SizeToOpSize(GPRSize), CondClassType {COND_EQ}, Dest, Result); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, SelectOp, DstSize, -1); } void OpDispatchBuilder::BSROp(OpcodeArgs) { const uint8_t GPRSize = CTX->GetGPRSize(); const uint8_t DstSize = GetDstSize(Op) == 2 ? 2 : GPRSize; - OrderedNode *Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, DstSize, Op->Flags); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, DstSize, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); InvalidateDeferredFlags(); CachedNZCV = nullptr; @@ -3921,31 +3790,31 @@ void OpDispatchBuilder::BSROp(OpcodeArgs) { SetNZ_ZeroCV(GetSrcSize(Op), Src); // If Src was zero then the destination doesn't get modified - auto SelectOp = _NZCVSelect(IR::SizeToOpSize(GPRSize), CondClassType{COND_EQ}, Dest, Result); + auto SelectOp = _NZCVSelect(IR::SizeToOpSize(GPRSize), CondClassType {COND_EQ}, Dest, Result); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, SelectOp, DstSize, -1); } void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { -// CMPXCHG ModRM, reg, {RAX} -// MemData = *ModRM.dest -// if (RAX == MemData) -// modRM.dest = reg; -// ZF = 1 -// else -// ZF = 0 -// RAX = MemData -// -// CASL Xs, Xt, Xn -// MemData = *Xn -// if (MemData == Xs) -// *Xn = Xt -// Xs = MemData + // CMPXCHG ModRM, reg, {RAX} + // MemData = *ModRM.dest + // if (RAX == MemData) + // modRM.dest = reg; + // ZF = 1 + // else + // ZF = 0 + // RAX = MemData + // + // CASL Xs, Xt, Xn + // MemData = *Xn + // if (MemData == Xs) + // *Xn = Xt + // Xs = MemData const auto GPRSize = CTX->GetGPRSize(); auto Size = GetSrcSize(Op); // This is our source register - OrderedNode *Src2 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); // 0x80014000 // 0x80064000 // 0x80064000 @@ -3954,20 +3823,17 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { // If the destination is also the accumulator, we get some algebraic // simplifications. Not sure if this is actually hit but it's in // InstCountCI. - bool Trivial = Op->Dest.Data.GPR.GPR == X86State::REG_RAX && - !Op->Dest.IsGPRDirect() && - !Op->Dest.Data.GPR.HighBits; + bool Trivial = Op->Dest.Data.GPR.GPR == X86State::REG_RAX && !Op->Dest.IsGPRDirect() && !Op->Dest.Data.GPR.HighBits; - OrderedNode *Src1{}; - OrderedNode *Src1Lower{}; + OrderedNode* Src1 {}; + OrderedNode* Src1Lower {}; - OrderedNode *Src3{}; - OrderedNode *Src3Lower{}; + OrderedNode* Src3 {}; + OrderedNode* Src3Lower {}; if (GPRSize == 8 && Size == 4) { Src1 = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); Src3 = LoadGPRRegister(X86State::REG_RAX); - } - else { + } else { Src1 = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, Size, Op->Flags); Src3 = LoadGPRRegister(X86State::REG_RAX); } @@ -3975,8 +3841,7 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { if (Size != GPRSize) { Src1Lower = _Bfe(IR::SizeToOpSize(GPRSize), Size * 8, 0, Src1); Src3Lower = _Bfe(IR::SizeToOpSize(GPRSize), Size * 8, 0, Src3); - } - else { + } else { Src1Lower = Src1; Src3Lower = Src3; } @@ -3988,13 +3853,11 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { if (!Trivial) { if (GPRSize == 8 && Size == 4) { // This allows us to only hit the ZEXT case on failure - OrderedNode *RAXResult = _NZCVSelect(IR::i64Bit, CondClassType{COND_EQ}, - Src3, Src1Lower); + OrderedNode* RAXResult = _NZCVSelect(IR::i64Bit, CondClassType {COND_EQ}, Src3, Src1Lower); // When the size is 4 we need to make sure not zext the GPR when the comparison fails StoreGPRRegister(X86State::REG_RAX, RAXResult); - } - else { + } else { StoreGPRRegister(X86State::REG_RAX, Src1Lower, Size); } } @@ -4002,8 +3865,7 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { // Op1 = RAX == Op1 ? Op2 : Op1 // If they match then set the rm operand to the input // else don't set the rm operand - OrderedNode *DestResult = - Trivial ? Src2 : _NZCVSelect(IR::i64Bit, CondClassType{COND_EQ}, Src2, Src1); + OrderedNode* DestResult = Trivial ? Src2 : _NZCVSelect(IR::i64Bit, CondClassType {COND_EQ}, Src2, Src1); // Store in to GPR Dest if (GPRSize == 8 && Size == 4) { @@ -4011,35 +3873,31 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { } else { StoreResult(GPRClass, Op, DestResult, -1); } - } - else { + } else { HandledLock = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK; - OrderedNode *Src3{}; - OrderedNode *Src3Lower{}; + OrderedNode* Src3 {}; + OrderedNode* Src3Lower {}; if (GPRSize == 8 && Size == 4) { Src3 = LoadGPRRegister(X86State::REG_RAX); Src3Lower = _Bfe(OpSize::i32Bit, 32, 0, Src3); - } - else { + } else { Src3 = LoadGPRRegister(X86State::REG_RAX, Size); Src3Lower = Src3; } // If this is a memory location then we want the pointer to it - OrderedNode *Src1 = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Src1 = MakeSegmentAddress(Op, Op->Dest); // DataSrc = *Src1 // if (DataSrc == Src3) { *Src1 == Src2; } Src2 = DataSrc // This will write to memory! Careful! // Third operand must be a calculated guest memory address - OrderedNode *CASResult = _CAS(IR::SizeToOpSize(Size), Src3Lower, Src2, Src1); - OrderedNode *RAXResult = CASResult; + OrderedNode* CASResult = _CAS(IR::SizeToOpSize(Size), Src3Lower, Src2, Src1); + OrderedNode* RAXResult = CASResult; if (GPRSize == 8 && Size == 4) { // This allows us to only hit the ZEXT case on failure - RAXResult = _Select(FEXCore::IR::COND_EQ, - CASResult, Src3Lower, - Src3, CASResult); + RAXResult = _Select(FEXCore::IR::COND_EQ, CASResult, Src3Lower, Src3, CASResult); Size = 8; } @@ -4061,15 +3919,15 @@ void OpDispatchBuilder::CMPXCHGPairOp(OpcodeArgs) { HandledLock = (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK) != 0; // If this is a memory location then we want the pointer to it - OrderedNode *Src1 = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Src1 = MakeSegmentAddress(Op, Op->Dest); - OrderedNode *Expected_Lower = LoadGPRRegister(X86State::REG_RAX, Size); - OrderedNode *Expected_Upper = LoadGPRRegister(X86State::REG_RDX, Size); - OrderedNode *Expected = _CreateElementPair(IR::SizeToOpSize(Size * 2), Expected_Lower, Expected_Upper); + OrderedNode* Expected_Lower = LoadGPRRegister(X86State::REG_RAX, Size); + OrderedNode* Expected_Upper = LoadGPRRegister(X86State::REG_RDX, Size); + OrderedNode* Expected = _CreateElementPair(IR::SizeToOpSize(Size * 2), Expected_Lower, Expected_Upper); - OrderedNode *Desired_Lower = LoadGPRRegister(X86State::REG_RBX, Size); - OrderedNode *Desired_Upper = LoadGPRRegister(X86State::REG_RCX, Size); - OrderedNode *Desired = _CreateElementPair(IR::SizeToOpSize(Size * 2), Desired_Lower, Desired_Upper); + OrderedNode* Desired_Lower = LoadGPRRegister(X86State::REG_RBX, Size); + OrderedNode* Desired_Upper = LoadGPRRegister(X86State::REG_RCX, Size); + OrderedNode* Desired = _CreateElementPair(IR::SizeToOpSize(Size * 2), Desired_Lower, Desired_Upper); // ssa0 = Expected // ssa1 = Desired @@ -4080,10 +3938,10 @@ void OpDispatchBuilder::CMPXCHGPairOp(OpcodeArgs) { // This will write to memory! Careful! // Third operand must be a calculated guest memory address - OrderedNode *CASResult = _CASPair(IR::SizeToOpSize(Size * 2), Expected, Desired, Src1); + OrderedNode* CASResult = _CASPair(IR::SizeToOpSize(Size * 2), Expected, Desired, Src1); - OrderedNode *Result_Lower = _ExtractElementPair(IR::SizeToOpSize(Size), CASResult, 0); - OrderedNode *Result_Upper = _ExtractElementPair(IR::SizeToOpSize(Size), CASResult, 1); + OrderedNode* Result_Lower = _ExtractElementPair(IR::SizeToOpSize(Size), CASResult, 0); + OrderedNode* Result_Upper = _ExtractElementPair(IR::SizeToOpSize(Size), CASResult, 1); HandleNZCV_RMW(); _CmpPairZ(IR::SizeToOpSize(Size), CASResult, Expected); @@ -4092,20 +3950,19 @@ void OpDispatchBuilder::CMPXCHGPairOp(OpcodeArgs) { auto UpdateIfNotZF = [this](auto Reg, auto Value) { // Always use 64-bit csel to preserve existing upper bits. If we have a // 32-bit cmpxchg in a 64-bit context, Value will be zeroed in upper bits. - StoreGPRRegister(Reg, _NZCVSelect(OpSize::i64Bit, CondClassType{COND_NEQ}, - Value, LoadGPRRegister(Reg))); + StoreGPRRegister(Reg, _NZCVSelect(OpSize::i64Bit, CondClassType {COND_NEQ}, Value, LoadGPRRegister(Reg))); }; UpdateIfNotZF(X86State::REG_RAX, Result_Lower); UpdateIfNotZF(X86State::REG_RDX, Result_Upper); } -void OpDispatchBuilder::CreateJumpBlocks(fextl::vector const *Blocks) { - OrderedNode *PrevCodeBlock{}; - for (auto &Target : *Blocks) { +void OpDispatchBuilder::CreateJumpBlocks(const fextl::vector* Blocks) { + OrderedNode* PrevCodeBlock {}; + for (auto& Target : *Blocks) { auto CodeNode = CreateCodeNode(); - JumpTargets.try_emplace(Target.Entry, JumpTargetInfo{CodeNode, false}); + JumpTargets.try_emplace(Target.Entry, JumpTargetInfo {CodeNode, false}); if (PrevCodeBlock) { LinkCodeBlocks(PrevCodeBlock, CodeNode); @@ -4115,7 +3972,7 @@ void OpDispatchBuilder::CreateJumpBlocks(fextl::vector const *Blocks, uint32_t NumInstructions) { +void OpDispatchBuilder::BeginFunction(uint64_t RIP, const fextl::vector* Blocks, uint32_t NumInstructions) { Entry = RIP; auto IRHeader = _IRHeader(InvalidNode, RIP, 0, NumInstructions); CreateJumpBlocks(Blocks); @@ -4134,15 +3991,16 @@ void OpDispatchBuilder::Finalize() { const uint8_t GPRSize = CTX->GetGPRSize(); // Node 0 is invalid node - OrderedNode *RealNode = reinterpret_cast(GetNode(1)); + OrderedNode* RealNode = reinterpret_cast(GetNode(1)); - [[maybe_unused]] const FEXCore::IR::IROp_Header *IROp = - RealNode->Op(DualListData.DataBegin()); + [[maybe_unused]] const FEXCore::IR::IROp_Header* IROp = RealNode->Op(DualListData.DataBegin()); LOGMAN_THROW_AA_FMT(IROp->Op == OP_IRHEADER, "First op in function must be our header"); // Let's walk the jump blocks and see if we have handled every block target - for (auto &Handler : JumpTargets) { - if (Handler.second.HaveEmitted) continue; + for (auto& Handler : JumpTargets) { + if (Handler.second.HaveEmitted) { + continue; + } // We haven't emitted. Dump out to the dispatcher SetCurrentCodeBlock(Handler.second.BlockEntry); @@ -4171,19 +4029,17 @@ uint32_t OpDispatchBuilder::GetDstBitSize(X86Tables::DecodedOp Op) const { return GetDstSize(Op) * 8; } -OrderedNode *OpDispatchBuilder::GetSegment(uint32_t Flags, uint32_t DefaultPrefix, bool Override) { +OrderedNode* OpDispatchBuilder::GetSegment(uint32_t Flags, uint32_t DefaultPrefix, bool Override) { const uint8_t GPRSize = CTX->GetGPRSize(); if (CTX->Config.Is64BitMode) { if (Flags & FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX) { return _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_cached)); - } - else if (Flags & FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX) { + } else if (Flags & FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX) { return _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, gs_cached)); } // If there was any other segment in 64bit then it is ignored - } - else { + } else { uint32_t Prefix = Flags & FEXCore::X86Tables::DecodeFlags::FLAG_SEGMENTS; if (!Prefix || Override) { // If there was no prefix then use the default one if available @@ -4191,28 +4047,27 @@ OrderedNode *OpDispatchBuilder::GetSegment(uint32_t Flags, uint32_t DefaultPrefi Prefix = DefaultPrefix; } // With the segment register optimization we store the GDT bases directly in the segment register to remove indexed loads - OrderedNode *SegmentResult{}; + OrderedNode* SegmentResult {}; switch (Prefix) { - case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: - SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, es_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: - SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, cs_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: - SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, ss_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: - SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, ds_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: - SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: - SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, gs_cached)); - break; - default: - break; // Do nothing + case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: + SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, es_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: + SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, cs_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: + SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, ss_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: + SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, ds_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: + SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: + SegmentResult = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, gs_cached)); + break; + default: break; // Do nothing } CheckLegacySegmentRead(SegmentResult, Prefix); @@ -4221,7 +4076,7 @@ OrderedNode *OpDispatchBuilder::GetSegment(uint32_t Flags, uint32_t DefaultPrefi return nullptr; } -OrderedNode *OpDispatchBuilder::AppendSegmentOffset(OrderedNode *Value, uint32_t Flags, uint32_t DefaultPrefix, bool Override) { +OrderedNode* OpDispatchBuilder::AppendSegmentOffset(OrderedNode* Value, uint32_t Flags, uint32_t DefaultPrefix, bool Override) { auto Segment = GetSegment(Flags, DefaultPrefix, Override); if (Segment) { Value = _Add(IR::SizeToOpSize(std::max(4, std::max(GetOpSize(Value), GetOpSize(Segment)))), Value, Segment); @@ -4231,10 +4086,9 @@ OrderedNode *OpDispatchBuilder::AppendSegmentOffset(OrderedNode *Value, uint32_t } -void OpDispatchBuilder::CheckLegacySegmentRead(OrderedNode *NewNode, uint32_t SegmentReg) { +void OpDispatchBuilder::CheckLegacySegmentRead(OrderedNode* NewNode, uint32_t SegmentReg) { #ifndef FEX_DISABLE_TELEMETRY - if (SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX || - SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX) { + if (SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX || SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX) { // FS and GS segments aren't considered legacy. return; } @@ -4250,25 +4104,25 @@ void OpDispatchBuilder::CheckLegacySegmentRead(OrderedNode *NewNode, uint32_t Se return; } - FEXCore::Telemetry::TelemetryType TelemIndex{}; + FEXCore::Telemetry::TelemetryType TelemIndex {}; switch (SegmentReg) { - case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_ES; - SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX; - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_CS; - SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX; - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_SS; - SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX; - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_DS; - SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX; - break; - default: FEX_UNREACHABLE; + case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_ES; + SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX; + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_CS; + SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX; + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_SS; + SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX; + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_DS; + SegmentsNeedReadCheck &= ~FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX; + break; + default: FEX_UNREACHABLE; } // Will set the telemetry value if NewNode is != 0 @@ -4276,10 +4130,9 @@ void OpDispatchBuilder::CheckLegacySegmentRead(OrderedNode *NewNode, uint32_t Se #endif } -void OpDispatchBuilder::CheckLegacySegmentWrite(OrderedNode *NewNode, uint32_t SegmentReg) { +void OpDispatchBuilder::CheckLegacySegmentWrite(OrderedNode* NewNode, uint32_t SegmentReg) { #ifndef FEX_DISABLE_TELEMETRY - if (SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX || - SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX) { + if (SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX || SegmentReg == FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX) { // FS and GS segments aren't considered legacy. return; } @@ -4289,25 +4142,25 @@ void OpDispatchBuilder::CheckLegacySegmentWrite(OrderedNode *NewNode, uint32_t S return; } - FEXCore::Telemetry::TelemetryType TelemIndex{}; + FEXCore::Telemetry::TelemetryType TelemIndex {}; switch (SegmentReg) { - case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_ES; - SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX; - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_CS; - SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX; - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_SS; - SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX; - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: - TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_DS; - SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX; - break; - default: FEX_UNREACHABLE; + case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_ES; + SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX; + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_CS; + SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX; + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_SS; + SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX; + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: + TelemIndex = FEXCore::Telemetry::TelemetryType::TYPE_WRITES_32BIT_SEGMENT_DS; + SegmentsNeedReadCheck |= FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX; + break; + default: FEX_UNREACHABLE; } // Will set the telemetry value if NewNode is != 0 @@ -4315,48 +4168,45 @@ void OpDispatchBuilder::CheckLegacySegmentWrite(OrderedNode *NewNode, uint32_t S #endif } -void OpDispatchBuilder::UpdatePrefixFromSegment(OrderedNode *Segment, uint32_t SegmentReg) { +void OpDispatchBuilder::UpdatePrefixFromSegment(OrderedNode* Segment, uint32_t SegmentReg) { // Use BFE to extract the selector index in bits [15,3] of the segment register. // In some cases the upper 16-bits of the 32-bit GPR contain garbage to ignore. Segment = _Bfe(OpSize::i32Bit, 16 - 3, 3, Segment); auto NewSegment = _LoadContextIndexed(Segment, 4, offsetof(FEXCore::Core::CPUState, gdt[0]), 4, GPRClass); CheckLegacySegmentWrite(NewSegment, SegmentReg); switch (SegmentReg) { - case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: - _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, es_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: - _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, cs_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: - _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ss_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: - _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ds_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: - _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, fs_cached)); - break; - case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: - _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, gs_cached)); - break; - default: break; // Do nothing + case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX: + _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, es_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX: + _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, cs_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_SS_PREFIX: + _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ss_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX: + _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, ds_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX: + _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, fs_cached)); + break; + case FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX: + _StoreContext(4, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, gs_cached)); + break; + default: break; // Do nothing } } -OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X86Tables::DecodedOp const& Op, X86Tables::DecodedOperand const& Operand, - uint8_t OpSize, uint32_t Flags, const LoadSourceOptions& Options) { - LOGMAN_THROW_A_FMT(Operand.IsGPR() || - Operand.IsLiteral() || - Operand.IsGPRDirect() || - Operand.IsGPRIndirect() || - Operand.IsRIPRelative() || - Operand.IsSIB(), - "Unsupported Src type"); +OrderedNode* OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86Tables::DecodedOp& Op, + const X86Tables::DecodedOperand& Operand, uint8_t OpSize, uint32_t Flags, + const LoadSourceOptions& Options) { + LOGMAN_THROW_A_FMT( + Operand.IsGPR() || Operand.IsLiteral() || Operand.IsGPRDirect() || Operand.IsGPRIndirect() || Operand.IsRIPRelative() || Operand.IsSIB(), + "Unsupported Src type"); auto [Align, LoadData, ForceLoad, AccessType, AllowUpperGarbage] = Options; - OrderedNode *Src {nullptr}; + OrderedNode* Src {nullptr}; bool LoadableType = false; const uint8_t GPRSize = CTX->GetGPRSize(); const uint32_t AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize; @@ -4370,15 +4220,13 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X constant = constant & ((1ULL << width) - 1); } Src = _Constant(width, constant); - } - else if (Operand.IsGPR()) { + } else if (Operand.IsGPR()) { const auto gpr = Operand.Data.GPR.GPR; const auto highIndex = Operand.Data.GPR.HighBits ? 1 : 0; if (gpr >= FEXCore::X86State::REG_MM_0) { Src = _LoadContext(OpSize, FPRClass, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0])); - } - else if (gpr >= FEXCore::X86State::REG_XMM_0) { + } else if (gpr >= FEXCore::X86State::REG_XMM_0) { const auto gprIndex = gpr - X86State::REG_XMM_0; // Load the full register size if it is a XMM register source. @@ -4390,20 +4238,17 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X if (!AllowUpperGarbage && OpSize < Core::CPUState::XMM_SSE_REG_SIZE) { Src = _VMov(OpSize, Src); } - } - else { + } else { Src = LoadGPRRegister(gpr, OpSize, highIndex ? 8 : 0, AllowUpperGarbage); } - } - else if (Operand.IsGPRDirect()) { + } else if (Operand.IsGPRDirect()) { Src = LoadGPRRegister(Operand.Data.GPR.GPR, GPRSize); LoadableType = true; if (Operand.Data.GPR.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) { AccessType = MemoryAccessType::NONTSO; } - } - else if (Operand.IsGPRIndirect()) { + } else if (Operand.IsGPRIndirect()) { auto GPR = LoadGPRRegister(Operand.Data.GPRIndirect.GPR, GPRSize); auto Constant = _Constant(GPRSize * 8, Operand.Data.GPRIndirect.Displacement); @@ -4414,33 +4259,28 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X if (Operand.Data.GPRIndirect.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) { AccessType = MemoryAccessType::NONTSO; } - } - else if (Operand.IsRIPRelative()) { + } else if (Operand.IsRIPRelative()) { if (CTX->Config.Is64BitMode) { Src = GetRelocatedPC(Op, Operand.Data.RIPLiteral.Value.s); - } - else { + } else { // 32bit this isn't RIP relative but instead absolute Src = _Constant(GPRSize * 8, Operand.Data.RIPLiteral.Value.u); } LoadableType = true; - } - else if (Operand.IsSIB()) { + } else if (Operand.IsSIB()) { const bool IsVSIB = (Op->Flags & X86Tables::DecodeFlags::FLAG_VSIB_BYTE) != 0; - OrderedNode *Tmp{}; + OrderedNode* Tmp {}; if (!IsVSIB && Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID && Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) { auto Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize); auto Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize); if (Operand.Data.SIB.Scale == 1) { Tmp = _Add(IR::SizeToOpSize(GPRSize), Base, Index); - } - else { + } else { Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale)); } - } - else { + } else { // NOTE: VSIB cannot have the index * scale portion calculated ahead of time, // since the index in this case is a vector. So, we can't just apply the scale // to it, since this needs to be applied to each element in the index register @@ -4464,8 +4304,7 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X if (Tmp != nullptr) { Tmp = _Add(IR::SizeToOpSize(GPRSize), Tmp, GPR); - } - else { + } else { Tmp = GPR; } } @@ -4474,29 +4313,24 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X if (Operand.Data.SIB.Offset) { if (Tmp != nullptr) { Src = _Add(IR::SizeToOpSize(GPRSize), Tmp, _Constant(GPRSize * 8, Operand.Data.SIB.Offset)); - } - else { + } else { Src = _Constant(GPRSize * 8, Operand.Data.SIB.Offset); } - } - else { + } else { if (Tmp != nullptr) { Src = Tmp; - } - else { + } else { Src = _Constant(GPRSize * 8, 0); } } - if ((Operand.Data.SIB.Base == FEXCore::X86State::REG_RSP || - Operand.Data.SIB.Index == FEXCore::X86State::REG_RSP) - && AccessType == MemoryAccessType::DEFAULT) { + if ((Operand.Data.SIB.Base == FEXCore::X86State::REG_RSP || Operand.Data.SIB.Index == FEXCore::X86State::REG_RSP) && + AccessType == MemoryAccessType::DEFAULT) { AccessType = MemoryAccessType::NONTSO; } LoadableType = true; - } - else { + } else { LOGMAN_MSG_A_FMT("Unknown Src Type: {}\n", Operand.Type); } @@ -4513,54 +4347,53 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X if (AccessType == MemoryAccessType::NONTSO || AccessType == MemoryAccessType::STREAM) { Src = _LoadMem(Class, OpSize, Src, Align == -1 ? OpSize : Align); - } - else { + } else { Src = _LoadMemAutoTSO(Class, OpSize, Src, Align == -1 ? OpSize : Align); } } return Src; } -OrderedNode *OpDispatchBuilder::GetRelocatedPC(FEXCore::X86Tables::DecodedOp const& Op, int64_t Offset) { +OrderedNode* OpDispatchBuilder::GetRelocatedPC(const FEXCore::X86Tables::DecodedOp& Op, int64_t Offset) { const uint8_t GPRSize = CTX->GetGPRSize(); return _EntrypointOffset(IR::SizeToOpSize(GPRSize), Op->PC + Op->InstSize + Offset - Entry); } -OrderedNode *OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8_t Offset, bool AllowUpperGarbage) { +OrderedNode* OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8_t Offset, bool AllowUpperGarbage) { const uint8_t GPRSize = CTX->GetGPRSize(); if (Size == -1) { Size = GPRSize; } - OrderedNode *Reg = _LoadRegister(false, offsetof(FEXCore::Core::CPUState, gregs[GPR]), GPRClass, GPRFixedClass, GPRSize); + OrderedNode* Reg = _LoadRegister(false, offsetof(FEXCore::Core::CPUState, gregs[GPR]), GPRClass, GPRFixedClass, GPRSize); if ((!AllowUpperGarbage && (Size != GPRSize)) || Offset != 0) { // Extract the subregister if requested. const auto OpSize = IR::SizeToOpSize(std::max(4u, Size)); - if (AllowUpperGarbage) + if (AllowUpperGarbage) { Reg = _Lshr(OpSize, Reg, _Constant(Offset)); - else + } else { Reg = _Bfe(OpSize, Size * 8, Offset, Reg); + } } return Reg; } -OrderedNode *OpDispatchBuilder::LoadXMMRegister(uint32_t XMM) { +OrderedNode* OpDispatchBuilder::LoadXMMRegister(uint32_t XMM) { const auto VectorSize = CTX->HostFeatures.SupportsAVX ? 32 : 16; - const auto VectorOffset = CTX->HostFeatures.SupportsAVX ? - offsetof(Core::CPUState, xmm.avx.data[XMM][0]) : - offsetof(Core::CPUState, xmm.sse.data[XMM][0]); + const auto VectorOffset = + CTX->HostFeatures.SupportsAVX ? offsetof(Core::CPUState, xmm.avx.data[XMM][0]) : offsetof(Core::CPUState, xmm.sse.data[XMM][0]); - OrderedNode *Reg = _LoadRegister(false, VectorOffset, FPRClass, FPRFixedClass, VectorSize); + OrderedNode* Reg = _LoadRegister(false, VectorOffset, FPRClass, FPRFixedClass, VectorSize); return Reg; } -void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, OrderedNode *const Src, int8_t Size, uint8_t Offset) { +void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, OrderedNode* const Src, int8_t Size, uint8_t Offset) { const uint8_t GPRSize = CTX->GetGPRSize(); if (Size == -1) { Size = GPRSize; } - OrderedNode *Reg = Src; + OrderedNode* Reg = Src; if (Size != GPRSize || Offset != 0) { // Need to do an insert if not automatic size or zero offset. Reg = LoadGPRRegister(GPR); @@ -4570,33 +4403,30 @@ void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, OrderedNode *const Src, i _StoreRegister(Reg, false, offsetof(FEXCore::Core::CPUState, gregs[GPR]), GPRClass, GPRFixedClass, GPRSize); } -void OpDispatchBuilder::StoreXMMRegister(uint32_t XMM, OrderedNode *const Src) { +void OpDispatchBuilder::StoreXMMRegister(uint32_t XMM, OrderedNode* const Src) { const auto VectorSize = CTX->HostFeatures.SupportsAVX ? 32 : 16; - const auto VectorOffset = CTX->HostFeatures.SupportsAVX ? - offsetof(Core::CPUState, xmm.avx.data[XMM][0]) : - offsetof(Core::CPUState, xmm.sse.data[XMM][0]); + const auto VectorOffset = + CTX->HostFeatures.SupportsAVX ? offsetof(Core::CPUState, xmm.avx.data[XMM][0]) : offsetof(Core::CPUState, xmm.sse.data[XMM][0]); _StoreRegister(Src, false, VectorOffset, FPRClass, FPRFixedClass, VectorSize); } -OrderedNode *OpDispatchBuilder::LoadSource(RegisterClassType Class, X86Tables::DecodedOp const& Op, X86Tables::DecodedOperand const& Operand, - uint32_t Flags, const LoadSourceOptions& Options) { +OrderedNode* OpDispatchBuilder::LoadSource(RegisterClassType Class, const X86Tables::DecodedOp& Op, + const X86Tables::DecodedOperand& Operand, uint32_t Flags, const LoadSourceOptions& Options) { const uint8_t OpSize = GetSrcSize(Op); return LoadSource_WithOpSize(Class, Op, Operand, OpSize, Flags, Options); } -void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, FEXCore::X86Tables::DecodedOperand const& Operand, OrderedNode *const Src, uint8_t OpSize, int8_t Align, MemoryAccessType AccessType) { - LOGMAN_THROW_A_FMT(Operand.IsGPR() || - Operand.IsLiteral() || - Operand.IsGPRDirect() || - Operand.IsGPRIndirect() || - Operand.IsRIPRelative() || - Operand.IsSIB(), - "Unsupported Dest type"); +void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, + const FEXCore::X86Tables::DecodedOperand& Operand, OrderedNode* const Src, uint8_t OpSize, + int8_t Align, MemoryAccessType AccessType) { + LOGMAN_THROW_A_FMT( + Operand.IsGPR() || Operand.IsLiteral() || Operand.IsGPRDirect() || Operand.IsGPRIndirect() || Operand.IsRIPRelative() || Operand.IsSIB(), + "Unsupported Dest type"); // 8Bit and 16bit destination types store their result without effecting the upper bits // 32bit ops ZEXT the result to 64bit - OrderedNode *MemStoreDst {nullptr}; + OrderedNode* MemStoreDst {nullptr}; bool MemStore = false; const uint8_t GPRSize = CTX->GetGPRSize(); const uint32_t AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize; @@ -4604,13 +4434,11 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl if (Operand.IsLiteral()) { MemStoreDst = _Constant(Operand.Data.Literal.Size * 8, Operand.Data.Literal.Value); MemStore = true; // Literals are ONLY hardcoded memory destinations - } - else if (Operand.IsGPR()) { + } else if (Operand.IsGPR()) { const auto gpr = Operand.Data.GPR.GPR; if (gpr >= FEXCore::X86State::REG_MM_0) { _StoreContext(OpSize, Class, Src, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0])); - } - else if (gpr >= FEXCore::X86State::REG_XMM_0) { + } else if (gpr >= FEXCore::X86State::REG_XMM_0) { const auto gprIndex = gpr - X86State::REG_XMM_0; const auto VectorSize = CTX->HostFeatures.SupportsAVX ? 32 : 16; @@ -4619,8 +4447,7 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl // Partial writes can come from FPRs. // TODO: Fix the instructions doing partial writes rather than dealing with it here. - LOGMAN_THROW_A_FMT(Class != IR::GPRClass, "Partial writes from GPR not allowed. Instruction: {}", - Op->TableInfo->Name); + LOGMAN_THROW_A_FMT(Class != IR::GPRClass, "Partial writes from GPR not allowed. Instruction: {}", Op->TableInfo->Name); // XMM-size is handled in implementations. if (VectorSize != Core::CPUState::XMM_AVX_REG_SIZE || OpSize != Core::CPUState::XMM_SSE_REG_SIZE) { @@ -4630,17 +4457,15 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl } StoreXMMRegister(gprIndex, Result); - } - else { + } else { if (GPRSize == 8 && OpSize == 4) { // If the Source IR op is 64 bits, we need to zext the upper bits // For all other sizes, the upper bits are guaranteed to already be zero - OrderedNode *Value = GetOpSize(Src) == 8 ? _Bfe(OpSize::i32Bit, 32, 0, Src) : Src; + OrderedNode* Value = GetOpSize(Src) == 8 ? _Bfe(OpSize::i32Bit, 32, 0, Src) : Src; StoreGPRRegister(gpr, Value, GPRSize); LOGMAN_THROW_AA_FMT(!Operand.Data.GPR.HighBits, "Can't handle 32bit store to high 8bit register"); - } - else { + } else { LOGMAN_THROW_AA_FMT(!(GPRSize == 4 && OpSize > 4), "Oops had a {} GPR load", OpSize); if (GPRSize != OpSize) { @@ -4650,22 +4475,19 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl // mov ah, 2 ; Move in to upper 8-bits of 16-bit reg. // mov ax, 2 ; Move in to lower 16-bits of reg. StoreGPRRegister(gpr, Src, OpSize, Operand.Data.GPR.HighBits * 8); - } - else { + } else { StoreGPRRegister(gpr, Src, std::min(GPRSize, OpSize)); } } } - } - else if (Operand.IsGPRDirect()) { + } else if (Operand.IsGPRDirect()) { MemStoreDst = LoadGPRRegister(Operand.Data.GPR.GPR, GPRSize); MemStore = true; if (Operand.Data.GPR.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) { AccessType = MemoryAccessType::NONTSO; } - } - else if (Operand.IsGPRIndirect()) { + } else if (Operand.IsGPRIndirect()) { auto GPR = LoadGPRRegister(Operand.Data.GPRIndirect.GPR, GPRSize); auto Constant = _Constant(GPRSize * 8, Operand.Data.GPRIndirect.Displacement); @@ -4674,31 +4496,26 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl if (Operand.Data.GPRIndirect.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) { AccessType = MemoryAccessType::NONTSO; } - } - else if (Operand.IsRIPRelative()) { + } else if (Operand.IsRIPRelative()) { if (CTX->Config.Is64BitMode) { MemStoreDst = GetRelocatedPC(Op, Operand.Data.RIPLiteral.Value.s); - } - else { + } else { // 32bit this isn't RIP relative but instead absolute MemStoreDst = _Constant(GPRSize * 8, Operand.Data.RIPLiteral.Value.u); } MemStore = true; - } - else if (Operand.IsSIB()) { - OrderedNode *Tmp {}; + } else if (Operand.IsSIB()) { + OrderedNode* Tmp {}; if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID && Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) { auto Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize); auto Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize); if (Operand.Data.SIB.Scale == 1) { Tmp = _Add(IR::SizeToOpSize(GPRSize), Base, Index); - } - else { + } else { Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale)); } - } - else { + } else { if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID) { Tmp = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize); @@ -4713,8 +4530,7 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl if (Tmp != nullptr) { Tmp = _Add(IR::SizeToOpSize(GPRSize), Tmp, GPR); - } - else { + } else { Tmp = GPR; } } @@ -4723,16 +4539,13 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl if (Operand.Data.SIB.Offset) { if (Tmp != nullptr) { MemStoreDst = _Add(IR::SizeToOpSize(GPRSize), Tmp, _Constant(GPRSize * 8, Operand.Data.SIB.Offset)); - } - else { + } else { MemStoreDst = _Constant(GPRSize * 8, Operand.Data.SIB.Offset); } - } - else { + } else { if (Tmp != nullptr) { MemStoreDst = Tmp; - } - else { + } else { MemStoreDst = _Constant(GPRSize * 8, 0); } } @@ -4743,9 +4556,8 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl MemStoreDst = _Bfe(IR::SizeToOpSize(std::max(4u, AddrSize)), AddrSize * 8, 0, MemStoreDst); } - if ((Operand.Data.SIB.Base == FEXCore::X86State::REG_RSP || - Operand.Data.SIB.Index == FEXCore::X86State::REG_RSP) - && AccessType == MemoryAccessType::DEFAULT) { + if ((Operand.Data.SIB.Base == FEXCore::X86State::REG_RSP || Operand.Data.SIB.Index == FEXCore::X86State::REG_RSP) && + AccessType == MemoryAccessType::DEFAULT) { AccessType = MemoryAccessType::NONTSO; } @@ -4764,32 +4576,33 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl } else { if (AccessType == MemoryAccessType::NONTSO || AccessType == MemoryAccessType::STREAM) { _StoreMem(Class, OpSize, MemStoreDst, Src, Align == -1 ? OpSize : Align); - } - else { + } else { _StoreMemAutoTSO(Class, OpSize, MemStoreDst, Src, Align == -1 ? OpSize : Align); } } } } -void OpDispatchBuilder::StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, FEXCore::X86Tables::DecodedOperand const& Operand, OrderedNode *const Src, int8_t Align, MemoryAccessType AccessType) { +void OpDispatchBuilder::StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, + const FEXCore::X86Tables::DecodedOperand& Operand, OrderedNode* const Src, int8_t Align, + MemoryAccessType AccessType) { StoreResult_WithOpSize(Class, Op, Operand, Src, GetDstSize(Op), Align, AccessType); } -void OpDispatchBuilder::StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, OrderedNode *const Src, int8_t Align, MemoryAccessType AccessType) { +void OpDispatchBuilder::StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, OrderedNode* const Src, + int8_t Align, MemoryAccessType AccessType) { StoreResult(Class, Op, Op->Dest, Src, Align, AccessType); } -OpDispatchBuilder::OpDispatchBuilder(FEXCore::Context::ContextImpl *ctx) +OpDispatchBuilder::OpDispatchBuilder(FEXCore::Context::ContextImpl* ctx) : IREmitter {ctx->OpDispatcherAllocator} , CTX {ctx} { ResetWorkingList(); InstallHostSpecificOpcodeHandlers(); } -OpDispatchBuilder::OpDispatchBuilder(FEXCore::Utils::IntrusivePooledAllocator &Allocator) +OpDispatchBuilder::OpDispatchBuilder(FEXCore::Utils::IntrusivePooledAllocator& Allocator) : IREmitter {Allocator} - , CTX {nullptr} { -} + , CTX {nullptr} {} void OpDispatchBuilder::ResetWorkingList() { IREmitter::ResetWorkingList(); @@ -4806,12 +4619,12 @@ void OpDispatchBuilder::UnhandledOp(OpcodeArgs) { template void OpDispatchBuilder::MOVGPROp(OpcodeArgs) { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.Align = 1}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.Align = 1}); StoreResult(GPRClass, Op, Src, 1); } void OpDispatchBuilder::MOVGPRNTOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); StoreResult(GPRClass, Op, Src, 1, MemoryAccessType::STREAM); } @@ -4822,10 +4635,8 @@ void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCor * #0" is faster than "eor x0, x0, x0". Additionally this lets more constant * folding kick in for flags. */ - if (!DestIsLockedMem(Op) && - ALUIROp == FEXCore::IR::IROps::OP_XOR && - Op->Dest.IsGPR() && Op->Src[SrcIdx].IsGPR() && - Op->Dest.Data.GPR == Op->Src[SrcIdx].Data.GPR) { + if (!DestIsLockedMem(Op) && ALUIROp == FEXCore::IR::IROps::OP_XOR && Op->Dest.IsGPR() && Op->Src[SrcIdx].IsGPR() && + Op->Dest.Data.GPR == Op->Src[SrcIdx].Data.GPR) { auto Result = _Constant(0); StoreResult(GPRClass, Op, Result, -1); @@ -4836,24 +4647,24 @@ void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCor auto Size = GetDstSize(Op); auto RoundedSize = Size; - if (ALUIROp != FEXCore::IR::IROps::OP_ANDWITHFLAGS) + if (ALUIROp != FEXCore::IR::IROps::OP_ANDWITHFLAGS) { RoundedSize = std::max(4u, RoundedSize); + } const auto OpSize = IR::SizeToOpSize(RoundedSize); // X86 basic ALU ops just do the operation between the destination and a single source - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIdx], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[SrcIdx], Op->Flags, {.AllowUpperGarbage = true}); - OrderedNode *Result{}; - OrderedNode *Dest{}; + OrderedNode* Result {}; + OrderedNode* Dest {}; if (DestIsLockedMem(Op)) { HandledLock = true; - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); DeriveOp(FetchOp, AtomicFetchOp, _AtomicFetchAdd(IR::SizeToOpSize(Size), Src, DestMem)); Dest = FetchOp; - } - else { + } else { Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); } @@ -4862,28 +4673,25 @@ void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCor // Flags set switch (ALUIROp) { - case FEXCore::IR::IROps::OP_ADD: - Result = CalculateFlags_ADD(Size, Dest, Src); - break; - case FEXCore::IR::IROps::OP_SUB: - Result = CalculateFlags_SUB(Size, Dest, Src); - break; + case FEXCore::IR::IROps::OP_ADD: Result = CalculateFlags_ADD(Size, Dest, Src); break; + case FEXCore::IR::IROps::OP_SUB: Result = CalculateFlags_SUB(Size, Dest, Src); break; case FEXCore::IR::IROps::OP_XOR: case FEXCore::IR::IROps::OP_OR: { GenerateFlags_Logical(Op, Result, Dest, Src); - break; + break; } case FEXCore::IR::IROps::OP_ANDWITHFLAGS: { HandleNZ00Write(); CalculatePF(Result); _InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC); - break; + break; } default: break; } - if (!DestIsLockedMem(Op)) + if (!DestIsLockedMem(Op)) { StoreResult(GPRClass, Op, Result, -1); + } } template @@ -4925,34 +4733,34 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { Reason.Signal = Core::FAULT_SIGSEGV; Reason.TrapNumber = X86State::X86_TRAPNO_OF; Reason.si_code = 0x80; - break; + break; case 0xF1: // INT1 Reason.ErrorRegister = 0; Reason.Signal = Core::FAULT_SIGTRAP; Reason.TrapNumber = X86State::X86_TRAPNO_DB; Reason.si_code = 1; SetRIPToNext = true; - break; + break; case 0xF4: { // HLT Reason.ErrorRegister = 0; Reason.Signal = Core::FAULT_SIGSEGV; Reason.TrapNumber = X86State::X86_TRAPNO_GP; Reason.si_code = 0x80; - break; + break; } case 0x0B: // UD2 Reason.ErrorRegister = 0; Reason.Signal = Core::FAULT_SIGILL; Reason.TrapNumber = X86State::X86_TRAPNO_UD; Reason.si_code = 2; - break; + break; case 0xCC: // INT3 Reason.ErrorRegister = 0; Reason.Signal = Core::FAULT_SIGTRAP; Reason.TrapNumber = X86State::X86_TRAPNO_BP; Reason.si_code = 0x80; SetRIPToNext = true; - break; + break; } // Calculate flags early. @@ -4966,8 +4774,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { // We want to set RIP to the next instruction after INT3/INT1 auto NewRIP = GetRelocatedPC(Op); _StoreContext(GPRSize, GPRClass, NewRIP, offsetof(FEXCore::Core::CPUState, rip)); - } - else if (Op->OP != 0xCE) { + } else if (Op->OP != 0xCE) { auto NewRIP = GetRelocatedPC(Op, -Op->InstSize); _StoreContext(GPRSize, GPRClass, NewRIP, offsetof(FEXCore::Core::CPUState, rip)); } @@ -4992,8 +4799,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { SetTrueJumpTarget(CondJump_, JumpTarget); SetCurrentCodeBlock(JumpTarget); StartNewBlock(); - } - else { + } else { BlockSetRIP = true; _Break(Reason); } @@ -5001,7 +4807,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { void OpDispatchBuilder::TZCNT(OpcodeArgs) { // _FindTrailingZeroes ignores upper garbage so we don't need to mask - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); Src = _FindTrailingZeroes(OpSizeFromSrc(Op), Src); StoreResult(GPRClass, Op, Src, -1); @@ -5011,7 +4817,7 @@ void OpDispatchBuilder::TZCNT(OpcodeArgs) { void OpDispatchBuilder::LZCNT(OpcodeArgs) { // _CountLeadingZeroes clears upper garbage so we don't need to mask - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); auto Res = _CountLeadingZeroes(OpSizeFromSrc(Op), Src); StoreResult(GPRClass, Op, Res, -1); @@ -5022,30 +4828,29 @@ void OpDispatchBuilder::MOVBEOp(OpcodeArgs) { const uint8_t GPRSize = CTX->GetGPRSize(); const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); Src = _Rev(IR::SizeToOpSize(std::max(4u, SrcSize)), Src); if (SrcSize == 2) { // 16-bit does an insert. // Rev of 16-bit value as 32-bit replaces the result in the upper 16-bits of the result. // bfxil the 16-bit result in to the GPR. - OrderedNode *Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); auto Result = _Bfxil(IR::SizeToOpSize(GPRSize), 16, 16, Dest, Src); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Result, GPRSize, -1); - } - else { + } else { // 32-bit does regular zext StoreResult(GPRClass, Op, Op->Dest, Src, -1); } } void OpDispatchBuilder::CLWB(OpcodeArgs) { - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); _CacheLineClean(DestMem); } void OpDispatchBuilder::CLFLUSHOPT(OpcodeArgs) { - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); _CacheLineClear(DestMem, false); } @@ -5062,8 +4867,7 @@ void OpDispatchBuilder::MemFenceOrXSAVEOPT(OpcodeArgs) { if (Op->ModRM == 0xF0) { // 0xF0 is MFENCE _Fence(FEXCore::IR::Fence_LoadStore); - } - else { + } else { LogMan::Msg::EFmt("Application tried using XSAVEOPT"); UnimplementedOp(Op); } @@ -5073,22 +4877,21 @@ void OpDispatchBuilder::StoreFenceOrCLFlush(OpcodeArgs) { if (Op->ModRM == 0xF8) { // 0xF8 is SFENCE _Fence({FEXCore::IR::Fence_Store}); - } - else { + } else { // This is a CLFlush - OrderedNode *DestMem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* DestMem = MakeSegmentAddress(Op, Op->Dest); _CacheLineClear(DestMem, true); } } void OpDispatchBuilder::CLZeroOp(OpcodeArgs) { - OrderedNode *DestMem = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.LoadData = false}); + OrderedNode* DestMem = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.LoadData = false}); _CacheLineZero(DestMem); } template void OpDispatchBuilder::Prefetch(OpcodeArgs) { - OrderedNode *DestMem = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.LoadData = false}); + OrderedNode* DestMem = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.LoadData = false}); Prefetch(ForStore, Stream, Level, DestMem); } @@ -5119,14 +4922,13 @@ void OpDispatchBuilder::CRC32(OpcodeArgs) { // Destination GPR size is always 4 or 8 bytes depending on widening uint8_t DstSize = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REX_WIDENING ? 8 : 4; - OrderedNode *Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); // Incoming memory is 8, 16, 32, or 64 - OrderedNode *Src{}; + OrderedNode* Src {}; if (Op->Src[0].IsGPR()) { Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], GPRSize, Op->Flags); - } - else { + } else { Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); } auto Result = _CRC32(Dest, Src, GetSrcSize(Op)); @@ -5137,8 +4939,8 @@ template void OpDispatchBuilder::RDRANDOp(OpcodeArgs) { auto Res = _RDRAND(Reseed); - OrderedNode *Result_Lower = _ExtractElementPair(OpSize::i64Bit, Res, 0); - OrderedNode *Result_Upper = _ExtractElementPair(OpSize::i64Bit, Res, 1); + OrderedNode* Result_Lower = _ExtractElementPair(OpSize::i64Bit, Res, 0); + OrderedNode* Result_Upper = _ExtractElementPair(OpSize::i64Bit, Res, 1); StoreResult(GPRClass, Op, Result_Lower, -1); GenerateFlags_RDRAND(Op, Result_Upper); @@ -5198,23 +5000,18 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { } #define OPD(prefix, opcode) (((prefix) << 8) | opcode) constexpr uint16_t PF_38_NONE = 0; - constexpr uint16_t PF_38_66 = (1U << 0); - constexpr uint16_t PF_38_F2 = (1U << 1); + constexpr uint16_t PF_38_66 = (1U << 0); + constexpr uint16_t PF_38_F2 = (1U << 1); constexpr std::tuple H0F38_SHA[] = { - {OPD(PF_38_NONE, 0xC8), 1, &OpDispatchBuilder::SHA1NEXTEOp}, - {OPD(PF_38_NONE, 0xC9), 1, &OpDispatchBuilder::SHA1MSG1Op}, - {OPD(PF_38_NONE, 0xCA), 1, &OpDispatchBuilder::SHA1MSG2Op}, - {OPD(PF_38_NONE, 0xCB), 1, &OpDispatchBuilder::SHA256RNDS2Op}, - {OPD(PF_38_NONE, 0xCC), 1, &OpDispatchBuilder::SHA256MSG1Op}, - {OPD(PF_38_NONE, 0xCD), 1, &OpDispatchBuilder::SHA256MSG2Op}, + {OPD(PF_38_NONE, 0xC8), 1, &OpDispatchBuilder::SHA1NEXTEOp}, {OPD(PF_38_NONE, 0xC9), 1, &OpDispatchBuilder::SHA1MSG1Op}, + {OPD(PF_38_NONE, 0xCA), 1, &OpDispatchBuilder::SHA1MSG2Op}, {OPD(PF_38_NONE, 0xCB), 1, &OpDispatchBuilder::SHA256RNDS2Op}, + {OPD(PF_38_NONE, 0xCC), 1, &OpDispatchBuilder::SHA256MSG1Op}, {OPD(PF_38_NONE, 0xCD), 1, &OpDispatchBuilder::SHA256MSG2Op}, }; constexpr std::tuple H0F38_AES[] = { - {OPD(PF_38_66, 0xDB), 1, &OpDispatchBuilder::AESImcOp}, - {OPD(PF_38_66, 0xDC), 1, &OpDispatchBuilder::AESEncOp}, - {OPD(PF_38_66, 0xDD), 1, &OpDispatchBuilder::AESEncLastOp}, - {OPD(PF_38_66, 0xDE), 1, &OpDispatchBuilder::AESDecOp}, + {OPD(PF_38_66, 0xDB), 1, &OpDispatchBuilder::AESImcOp}, {OPD(PF_38_66, 0xDC), 1, &OpDispatchBuilder::AESEncOp}, + {OPD(PF_38_66, 0xDD), 1, &OpDispatchBuilder::AESEncLastOp}, {OPD(PF_38_66, 0xDE), 1, &OpDispatchBuilder::AESDecOp}, {OPD(PF_38_66, 0xDF), 1, &OpDispatchBuilder::AESDecLastOp}, }; constexpr std::tuple H0F38_CRC[] = { @@ -5228,12 +5025,12 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { #define OPD(REX, prefix, opcode) ((REX << 9) | (prefix << 8) | opcode) #define PF_3A_NONE 0 -#define PF_3A_66 1 +#define PF_3A_66 1 constexpr std::tuple H0F3A_AES[] = { - {OPD(0, PF_3A_66, 0xDF), 1, &OpDispatchBuilder::AESKeyGenAssist}, + {OPD(0, PF_3A_66, 0xDF), 1, &OpDispatchBuilder::AESKeyGenAssist}, }; constexpr std::tuple H0F3A_PCLMUL[] = { - {OPD(0, PF_3A_66, 0x44), 1, &OpDispatchBuilder::PCLMULQDQOp}, + {OPD(0, PF_3A_66, 0x44), 1, &OpDispatchBuilder::PCLMULQDQOp}, }; #undef PF_3A_NONE @@ -5812,12 +5609,12 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0xAC, 1, &OpDispatchBuilder::SHRDImmediateOp}, {0xAD, 1, &OpDispatchBuilder::SHRDOp}, {0xAF, 1, &OpDispatchBuilder::IMUL1SrcOp}, - {0xB0, 2, &OpDispatchBuilder::CMPXCHGOp}, // CMPXCHG + {0xB0, 2, &OpDispatchBuilder::CMPXCHGOp}, // CMPXCHG {0xB3, 1, &OpDispatchBuilder::BTOp<0, BTAction::BTClear>}, // BTR {0xB6, 2, &OpDispatchBuilder::MOVZXOp}, {0xBB, 1, &OpDispatchBuilder::BTOp<0, BTAction::BTComplement>}, // BTC - {0xBC, 1, &OpDispatchBuilder::BSFOp}, // BSF - {0xBD, 1, &OpDispatchBuilder::BSROp}, // BSF + {0xBC, 1, &OpDispatchBuilder::BSFOp}, // BSF + {0xBD, 1, &OpDispatchBuilder::BSROp}, // BSF {0xBE, 2, &OpDispatchBuilder::MOVSXOp}, {0xC0, 2, &OpDispatchBuilder::XADDOp}, {0xC3, 1, &OpDispatchBuilder::MOVGPRNTOp}, @@ -5969,7 +5766,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC0), 3), 1, &OpDispatchBuilder::RCROp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC0), 4), 1, &OpDispatchBuilder::SHLImmediateOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC0), 5), 1, &OpDispatchBuilder::SHRImmediateOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC0), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC0), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC0), 7), 1, &OpDispatchBuilder::ASHRImmediateOp}, // SAR {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC1), 0), 1, &OpDispatchBuilder::RotateOp}, @@ -5978,7 +5775,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC1), 3), 1, &OpDispatchBuilder::RCROp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC1), 4), 1, &OpDispatchBuilder::SHLImmediateOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC1), 5), 1, &OpDispatchBuilder::SHRImmediateOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC1), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC1), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xC1), 7), 1, &OpDispatchBuilder::ASHRImmediateOp}, // SAR {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 0), 1, &OpDispatchBuilder::RotateOp}, @@ -5986,8 +5783,8 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 2), 1, &OpDispatchBuilder::RCLOp1Bit}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 3), 1, &OpDispatchBuilder::RCROp8x1Bit}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 4), 1, &OpDispatchBuilder::SHLImmediateOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 5), 1, &OpDispatchBuilder::SHRImmediateOp}, // 1Bit SHR - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 5), 1, &OpDispatchBuilder::SHRImmediateOp}, // 1Bit SHR + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD0), 7), 1, &OpDispatchBuilder::ASHRImmediateOp}, // SAR {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 0), 1, &OpDispatchBuilder::RotateOp}, @@ -5995,8 +5792,8 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 2), 1, &OpDispatchBuilder::RCLOp1Bit}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 3), 1, &OpDispatchBuilder::RCROp1Bit}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 4), 1, &OpDispatchBuilder::SHLImmediateOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 5), 1, &OpDispatchBuilder::SHRImmediateOp}, // 1Bit SHR - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 5), 1, &OpDispatchBuilder::SHRImmediateOp}, // 1Bit SHR + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 6), 1, &OpDispatchBuilder::SHLImmediateOp}, // SAL {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD1), 7), 1, &OpDispatchBuilder::ASHRImmediateOp}, // SAR {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 0), 1, &OpDispatchBuilder::RotateOp}, @@ -6004,8 +5801,8 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 2), 1, &OpDispatchBuilder::RCLSmallerOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 3), 1, &OpDispatchBuilder::RCRSmallerOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 4), 1, &OpDispatchBuilder::SHLOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 5), 1, &OpDispatchBuilder::SHROp}, // SHR by CL - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 6), 1, &OpDispatchBuilder::SHLOp}, // SAL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 5), 1, &OpDispatchBuilder::SHROp}, // SHR by CL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 6), 1, &OpDispatchBuilder::SHLOp}, // SAL {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD2), 7), 1, &OpDispatchBuilder::ASHROp}, // SAR {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 0), 1, &OpDispatchBuilder::RotateOp}, @@ -6013,8 +5810,8 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 2), 1, &OpDispatchBuilder::RCLOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 3), 1, &OpDispatchBuilder::RCROp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 4), 1, &OpDispatchBuilder::SHLOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 5), 1, &OpDispatchBuilder::SHROp}, // SHR by CL - {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 6), 1, &OpDispatchBuilder::SHLOp}, // SAL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 5), 1, &OpDispatchBuilder::SHROp}, // SHR by CL + {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 6), 1, &OpDispatchBuilder::SHLOp}, // SAL {OPD(FEXCore::X86Tables::TYPE_GROUP_2, OpToIndex(0xD3), 7), 1, &OpDispatchBuilder::ASHROp}, // SAR // GROUP 3 @@ -6024,7 +5821,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF6), 3), 1, &OpDispatchBuilder::NEGOp}, // NEG {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF6), 4), 1, &OpDispatchBuilder::MULOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF6), 5), 1, &OpDispatchBuilder::IMULOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF6), 6), 1, &OpDispatchBuilder::DIVOp}, // DIV + {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF6), 6), 1, &OpDispatchBuilder::DIVOp}, // DIV {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF6), 7), 1, &OpDispatchBuilder::IDIVOp}, // IDIV {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF7), 0), 1, &OpDispatchBuilder::TESTOp<1>}, @@ -6034,7 +5831,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF7), 4), 1, &OpDispatchBuilder::MULOp}, // MUL {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF7), 5), 1, &OpDispatchBuilder::IMULOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF7), 6), 1, &OpDispatchBuilder::DIVOp}, // DIV + {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF7), 6), 1, &OpDispatchBuilder::DIVOp}, // DIV {OPD(FEXCore::X86Tables::TYPE_GROUP_3, OpToIndex(0xF7), 7), 1, &OpDispatchBuilder::IDIVOp}, // IDIV // GROUP 4 @@ -6095,7 +5892,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x2C, 1, &OpDispatchBuilder::CVTFPR_To_GPR<8, false>}, {0x2D, 1, &OpDispatchBuilder::CVTFPR_To_GPR<8, true>}, {0x51, 1, &OpDispatchBuilder::VectorScalarUnaryInsertALUOp}, - //x52 = Invalid + // x52 = Invalid {0x58, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, {0x59, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, {0x5A, 1, &OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<4, 8>}, @@ -6222,10 +6019,10 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0xFE, 1, &OpDispatchBuilder::VectorALUOp}, }; -constexpr uint16_t PF_NONE = 0; -constexpr uint16_t PF_F3 = 1; -constexpr uint16_t PF_66 = 2; -constexpr uint16_t PF_F2 = 3; + constexpr uint16_t PF_NONE = 0; + constexpr uint16_t PF_F3 = 1; + constexpr uint16_t PF_66 = 2; + constexpr uint16_t PF_F2 = 3; #define OPD(group, prefix, Reg) (((group - FEXCore::X86Tables::TYPE_GROUP_6) << 5) | (prefix) << 3 | (Reg)) constexpr std::tuple SecondaryExtensionOpTable[] = { // GROUP 7 @@ -6381,14 +6178,14 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xD8, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xD0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, - {OPD(0xD8, 0xD8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, - {OPD(0xD8, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xD0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xD8, 0xD8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xD8, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, {OPDReg(0xD9, 0) | 0x00, 8, &OpDispatchBuilder::FLDF64<32>}, @@ -6406,42 +6203,42 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xD9, 7) | 0x00, 8, &OpDispatchBuilder::X87FSTCW}, - {OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::FLDF64<80>}, - {OPD(0xD9, 0xC8), 8, &OpDispatchBuilder::FXCH}, - {OPD(0xD9, 0xD0), 1, &OpDispatchBuilder::NOPOp}, // FNOP - // D1 = Invalid - // D8 = Invalid - {OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::FCHSF64}, - {OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::FABSF64}, - // E2 = Invalid - {OPD(0xD9, 0xE4), 1, &OpDispatchBuilder::FTSTF64}, - {OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAMF64}, - // E6 = Invalid - {OPD(0xD9, 0xE8), 1, &OpDispatchBuilder::FLDF64_Const<0x3FF0000000000000>}, // 1.0 - {OPD(0xD9, 0xE9), 1, &OpDispatchBuilder::FLDF64_Const<0x400A934F0979A372>}, // log2l(10) - {OPD(0xD9, 0xEA), 1, &OpDispatchBuilder::FLDF64_Const<0x3FF71547652B82FE>}, // log2l(e) - {OPD(0xD9, 0xEB), 1, &OpDispatchBuilder::FLDF64_Const<0x400921FB54442D18>}, // pi - {OPD(0xD9, 0xEC), 1, &OpDispatchBuilder::FLDF64_Const<0x3FD34413509F79FF>}, // log10l(2) - {OPD(0xD9, 0xED), 1, &OpDispatchBuilder::FLDF64_Const<0x3FE62E42FEFA39EF>}, // log(2) - {OPD(0xD9, 0xEE), 1, &OpDispatchBuilder::FLDF64_Const<0>}, // 0.0 + {OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::FLDF64<80>}, + {OPD(0xD9, 0xC8), 8, &OpDispatchBuilder::FXCH}, + {OPD(0xD9, 0xD0), 1, &OpDispatchBuilder::NOPOp}, // FNOP + // D1 = Invalid + // D8 = Invalid + {OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::FCHSF64}, + {OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::FABSF64}, + // E2 = Invalid + {OPD(0xD9, 0xE4), 1, &OpDispatchBuilder::FTSTF64}, + {OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAMF64}, + // E6 = Invalid + {OPD(0xD9, 0xE8), 1, &OpDispatchBuilder::FLDF64_Const<0x3FF0000000000000>}, // 1.0 + {OPD(0xD9, 0xE9), 1, &OpDispatchBuilder::FLDF64_Const<0x400A934F0979A372>}, // log2l(10) + {OPD(0xD9, 0xEA), 1, &OpDispatchBuilder::FLDF64_Const<0x3FF71547652B82FE>}, // log2l(e) + {OPD(0xD9, 0xEB), 1, &OpDispatchBuilder::FLDF64_Const<0x400921FB54442D18>}, // pi + {OPD(0xD9, 0xEC), 1, &OpDispatchBuilder::FLDF64_Const<0x3FD34413509F79FF>}, // log10l(2) + {OPD(0xD9, 0xED), 1, &OpDispatchBuilder::FLDF64_Const<0x3FE62E42FEFA39EF>}, // log(2) + {OPD(0xD9, 0xEE), 1, &OpDispatchBuilder::FLDF64_Const<0>}, // 0.0 - // EF = Invalid - {OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::X87UnaryOpF64}, - {OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::X87FYL2XF64}, - {OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::X87TANF64}, - {OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::X87ATANF64}, - {OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::FXTRACTF64}, - {OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::X87BinaryOpF64}, - {OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::X87ModifySTP}, - {OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::X87ModifySTP}, - {OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::X87BinaryOpF64}, - {OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::X87FYL2XF64}, - {OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::FSQRTF64}, - {OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::X87SinCosF64}, - {OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::FRNDINTF64}, - {OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::X87BinaryOpF64}, - {OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::X87UnaryOpF64}, - {OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::X87UnaryOpF64}, + // EF = Invalid + {OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::X87UnaryOpF64}, + {OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::X87FYL2XF64}, + {OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::X87TANF64}, + {OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::X87ATANF64}, + {OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::FXTRACTF64}, + {OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::X87BinaryOpF64}, + {OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::X87ModifySTP}, + {OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::X87ModifySTP}, + {OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::X87BinaryOpF64}, + {OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::X87FYL2XF64}, + {OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::FSQRTF64}, + {OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::X87SinCosF64}, + {OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::FRNDINTF64}, + {OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::X87BinaryOpF64}, + {OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::X87UnaryOpF64}, + {OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::X87UnaryOpF64}, {OPDReg(0xDA, 0) | 0x00, 8, &OpDispatchBuilder::FADDF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>}, @@ -6459,16 +6256,16 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDA, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xDA, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDA, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDA, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDA, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, - // E0 = Invalid - // E8 = Invalid - {OPD(0xDA, 0xE9), 1, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, - // EA = Invalid - // F0 = Invalid - // F8 = Invalid + {OPD(0xDA, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, + // E0 = Invalid + // E8 = Invalid + {OPD(0xDA, 0xE9), 1, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, + // EA = Invalid + // F0 = Invalid + // F8 = Invalid {OPDReg(0xDB, 0) | 0x00, 8, &OpDispatchBuilder::FILDF64}, @@ -6487,18 +6284,18 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDB, 7) | 0x00, 8, &OpDispatchBuilder::FSTF64<80>}, - {OPD(0xDB, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDB, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDB, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDB, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, - // E0 = Invalid - {OPD(0xDB, 0xE2), 1, &OpDispatchBuilder::NOPOp}, // FNCLEX - {OPD(0xDB, 0xE3), 1, &OpDispatchBuilder::FNINITF64}, - // E4 = Invalid - {OPD(0xDB, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, - {OPD(0xDB, 0xF0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDB, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, + // E0 = Invalid + {OPD(0xDB, 0xE2), 1, &OpDispatchBuilder::NOPOp}, // FNCLEX + {OPD(0xDB, 0xE3), 1, &OpDispatchBuilder::FNINITF64}, + // E4 = Invalid + {OPD(0xDB, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDB, 0xF0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, - // F8 = Invalid + // F8 = Invalid {OPDReg(0xDC, 0) | 0x00, 8, &OpDispatchBuilder::FADDF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>}, @@ -6516,12 +6313,12 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDC, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, {OPDReg(0xDD, 0) | 0x00, 8, &OpDispatchBuilder::FLDF64<64>}, @@ -6538,12 +6335,12 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDD, 7) | 0x00, 8, &OpDispatchBuilder::X87FNSTSW}, - {OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE}, - {OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::FST}, //register-register from regular X87 - {OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::FST}, //^ + {OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE}, + {OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::FST}, // register-register from regular X87 + {OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::FST}, //^ - {OPD(0xDD, 0xE0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, - {OPD(0xDD, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xDD, 0xE0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xDD, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, {OPDReg(0xDE, 0) | 0x00, 8, &OpDispatchBuilder::FADDF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>}, @@ -6561,13 +6358,13 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDE, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, - {OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, + {OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, {OPDReg(0xDF, 0) | 0x00, 8, &OpDispatchBuilder::FILDF64}, @@ -6585,13 +6382,13 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDF, 7) | 0x00, 8, &OpDispatchBuilder::FISTF64}, - // XXX: This should also set the x87 tag bits to empty - // We don't support this currently, so just pop the stack - {OPD(0xDF, 0xC0), 8, &OpDispatchBuilder::X87ModifySTP}, + // XXX: This should also set the x87 tag bits to empty + // We don't support this currently, so just pop the stack + {OPD(0xDF, 0xC0), 8, &OpDispatchBuilder::X87ModifySTP}, - {OPD(0xDF, 0xE0), 8, &OpDispatchBuilder::X87FNSTSW}, - {OPD(0xDF, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, - {OPD(0xDF, 0xF0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDF, 0xE0), 8, &OpDispatchBuilder::X87FNSTSW}, + {OPD(0xDF, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDF, 0xF0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, }; constexpr std::tuple X87OpTable[] = { @@ -6611,14 +6408,14 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xD8, 7) | 0x00, 8, &OpDispatchBuilder::FDIV<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xC0), 8, &OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xC8), 8, &OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xD0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, - {OPD(0xD8, 0xD8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, - {OPD(0xD8, 0xE0), 8, &OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xE8), 8, &OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xF0), 8, &OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xD8, 0xF8), 8, &OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xC0), 8, &OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xC8), 8, &OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xD0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xD8, 0xD8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xD8, 0xE0), 8, &OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xE8), 8, &OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xF0), 8, &OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xF8), 8, &OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, {OPDReg(0xD9, 0) | 0x00, 8, &OpDispatchBuilder::FLD<32>}, @@ -6636,42 +6433,42 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xD9, 7) | 0x00, 8, &OpDispatchBuilder::X87FSTCW}, - {OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::FLD<80>}, - {OPD(0xD9, 0xC8), 8, &OpDispatchBuilder::FXCH}, - {OPD(0xD9, 0xD0), 1, &OpDispatchBuilder::NOPOp}, // FNOP - // D1 = Invalid - // D8 = Invalid - {OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::FCHS}, - {OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::FABS}, - // E2 = Invalid - {OPD(0xD9, 0xE4), 1, &OpDispatchBuilder::FTST}, - {OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAM}, - // E6 = Invalid - {OPD(0xD9, 0xE8), 1, &OpDispatchBuilder::FLD_Const}, // 1.0 - {OPD(0xD9, 0xE9), 1, &OpDispatchBuilder::FLD_Const}, // log2l(10) - {OPD(0xD9, 0xEA), 1, &OpDispatchBuilder::FLD_Const}, // log2l(e) - {OPD(0xD9, 0xEB), 1, &OpDispatchBuilder::FLD_Const}, // pi - {OPD(0xD9, 0xEC), 1, &OpDispatchBuilder::FLD_Const}, // log10l(2) - {OPD(0xD9, 0xED), 1, &OpDispatchBuilder::FLD_Const}, // log(2) - {OPD(0xD9, 0xEE), 1, &OpDispatchBuilder::FLD_Const}, // 0.0 + {OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::FLD<80>}, + {OPD(0xD9, 0xC8), 8, &OpDispatchBuilder::FXCH}, + {OPD(0xD9, 0xD0), 1, &OpDispatchBuilder::NOPOp}, // FNOP + // D1 = Invalid + // D8 = Invalid + {OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::FCHS}, + {OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::FABS}, + // E2 = Invalid + {OPD(0xD9, 0xE4), 1, &OpDispatchBuilder::FTST}, + {OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAM}, + // E6 = Invalid + {OPD(0xD9, 0xE8), 1, &OpDispatchBuilder::FLD_Const}, // 1.0 + {OPD(0xD9, 0xE9), 1, &OpDispatchBuilder::FLD_Const}, // log2l(10) + {OPD(0xD9, 0xEA), 1, &OpDispatchBuilder::FLD_Const}, // log2l(e) + {OPD(0xD9, 0xEB), 1, &OpDispatchBuilder::FLD_Const}, // pi + {OPD(0xD9, 0xEC), 1, &OpDispatchBuilder::FLD_Const}, // log10l(2) + {OPD(0xD9, 0xED), 1, &OpDispatchBuilder::FLD_Const}, // log(2) + {OPD(0xD9, 0xEE), 1, &OpDispatchBuilder::FLD_Const}, // 0.0 - // EF = Invalid - {OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::X87UnaryOp}, - {OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::X87FYL2X}, - {OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::X87TAN}, - {OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::X87ATAN}, - {OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::FXTRACT}, - {OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::X87BinaryOp}, - {OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::X87ModifySTP}, - {OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::X87ModifySTP}, - {OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::X87BinaryOp}, - {OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::X87FYL2X}, - {OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::X87UnaryOp}, - {OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::X87SinCos}, - {OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::FRNDINT}, - {OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::X87BinaryOp}, - {OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::X87UnaryOp}, - {OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::X87UnaryOp}, + // EF = Invalid + {OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::X87UnaryOp}, + {OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::X87FYL2X}, + {OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::X87TAN}, + {OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::X87ATAN}, + {OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::FXTRACT}, + {OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::X87BinaryOp}, + {OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::X87ModifySTP}, + {OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::X87ModifySTP}, + {OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::X87BinaryOp}, + {OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::X87FYL2X}, + {OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::X87UnaryOp}, + {OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::X87SinCos}, + {OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::FRNDINT}, + {OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::X87BinaryOp}, + {OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::X87UnaryOp}, + {OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::X87UnaryOp}, {OPDReg(0xDA, 0) | 0x00, 8, &OpDispatchBuilder::FADD<32, true, OpDispatchBuilder::OpResult::RES_ST0>}, @@ -6689,16 +6486,16 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDA, 7) | 0x00, 8, &OpDispatchBuilder::FDIV<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xDA, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDA, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDA, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDA, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, - // E0 = Invalid - // E8 = Invalid - {OPD(0xDA, 0xE9), 1, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, - // EA = Invalid - // F0 = Invalid - // F8 = Invalid + {OPD(0xDA, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, + // E0 = Invalid + // E8 = Invalid + {OPD(0xDA, 0xE9), 1, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, + // EA = Invalid + // F0 = Invalid + // F8 = Invalid {OPDReg(0xDB, 0) | 0x00, 8, &OpDispatchBuilder::FILD}, @@ -6717,18 +6514,18 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDB, 7) | 0x00, 8, &OpDispatchBuilder::FST<80>}, - {OPD(0xDB, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDB, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDB, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, - {OPD(0xDB, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, - // E0 = Invalid - {OPD(0xDB, 0xE2), 1, &OpDispatchBuilder::NOPOp}, // FNCLEX - {OPD(0xDB, 0xE3), 1, &OpDispatchBuilder::FNINIT}, - // E4 = Invalid - {OPD(0xDB, 0xE8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, - {OPD(0xDB, 0xF0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDB, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, + // E0 = Invalid + {OPD(0xDB, 0xE2), 1, &OpDispatchBuilder::NOPOp}, // FNCLEX + {OPD(0xDB, 0xE3), 1, &OpDispatchBuilder::FNINIT}, + // E4 = Invalid + {OPD(0xDB, 0xE8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDB, 0xF0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, - // F8 = Invalid + // F8 = Invalid {OPDReg(0xDC, 0) | 0x00, 8, &OpDispatchBuilder::FADD<64, false, OpDispatchBuilder::OpResult::RES_ST0>}, @@ -6746,12 +6543,12 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDC, 7) | 0x00, 8, &OpDispatchBuilder::FDIV<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, {OPDReg(0xDD, 0) | 0x00, 8, &OpDispatchBuilder::FLD<64>}, @@ -6768,12 +6565,12 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDD, 7) | 0x00, 8, &OpDispatchBuilder::X87FNSTSW}, - {OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE}, - {OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::FST}, - {OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::FST}, + {OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE}, + {OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::FST}, + {OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::FST}, - {OPD(0xDD, 0xE0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, - {OPD(0xDD, 0xE8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xDD, 0xE0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xDD, 0xE8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, {OPDReg(0xDE, 0) | 0x00, 8, &OpDispatchBuilder::FADD<16, true, OpDispatchBuilder::OpResult::RES_ST0>}, @@ -6791,13 +6588,13 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDE, 7) | 0x00, 8, &OpDispatchBuilder::FDIV<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, - {OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, - {OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, - {OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, + {OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, {OPDReg(0xDF, 0) | 0x00, 8, &OpDispatchBuilder::FILD}, @@ -6815,84 +6612,84 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDF, 7) | 0x00, 8, &OpDispatchBuilder::FIST}, - // XXX: This should also set the x87 tag bits to empty - // We don't support this currently, so just pop the stack - {OPD(0xDF, 0xC0), 8, &OpDispatchBuilder::X87ModifySTP}, + // XXX: This should also set the x87 tag bits to empty + // We don't support this currently, so just pop the stack + {OPD(0xDF, 0xC0), 8, &OpDispatchBuilder::X87ModifySTP}, - {OPD(0xDF, 0xE0), 8, &OpDispatchBuilder::X87FNSTSW}, - {OPD(0xDF, 0xE8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, - {OPD(0xDF, 0xF0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDF, 0xE0), 8, &OpDispatchBuilder::X87FNSTSW}, + {OPD(0xDF, 0xE8), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDF, 0xF0), 8, &OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, }; #undef OPD #undef OPDReg #define OPD(prefix, opcode) (((prefix) << 8) | opcode) constexpr uint16_t PF_38_NONE = 0; - constexpr uint16_t PF_38_66 = (1U << 0); - constexpr uint16_t PF_38_F3 = (1U << 2); + constexpr uint16_t PF_38_66 = (1U << 0); + constexpr uint16_t PF_38_F3 = (1U << 2); constexpr std::tuple H0F38Table[] = { {OPD(PF_38_NONE, 0x00), 1, &OpDispatchBuilder::PSHUFBOp}, - {OPD(PF_38_66, 0x00), 1, &OpDispatchBuilder::PSHUFBOp}, + {OPD(PF_38_66, 0x00), 1, &OpDispatchBuilder::PSHUFBOp}, {OPD(PF_38_NONE, 0x01), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x01), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x01), 1, &OpDispatchBuilder::VectorALUOp}, {OPD(PF_38_NONE, 0x02), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x02), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x02), 1, &OpDispatchBuilder::VectorALUOp}, {OPD(PF_38_NONE, 0x03), 1, &OpDispatchBuilder::PHADDS}, - {OPD(PF_38_66, 0x03), 1, &OpDispatchBuilder::PHADDS}, + {OPD(PF_38_66, 0x03), 1, &OpDispatchBuilder::PHADDS}, {OPD(PF_38_NONE, 0x04), 1, &OpDispatchBuilder::PMADDUBSW}, - {OPD(PF_38_66, 0x04), 1, &OpDispatchBuilder::PMADDUBSW}, + {OPD(PF_38_66, 0x04), 1, &OpDispatchBuilder::PMADDUBSW}, {OPD(PF_38_NONE, 0x05), 1, &OpDispatchBuilder::PHSUB<2>}, - {OPD(PF_38_66, 0x05), 1, &OpDispatchBuilder::PHSUB<2>}, + {OPD(PF_38_66, 0x05), 1, &OpDispatchBuilder::PHSUB<2>}, {OPD(PF_38_NONE, 0x06), 1, &OpDispatchBuilder::PHSUB<4>}, - {OPD(PF_38_66, 0x06), 1, &OpDispatchBuilder::PHSUB<4>}, + {OPD(PF_38_66, 0x06), 1, &OpDispatchBuilder::PHSUB<4>}, {OPD(PF_38_NONE, 0x07), 1, &OpDispatchBuilder::PHSUBS}, - {OPD(PF_38_66, 0x07), 1, &OpDispatchBuilder::PHSUBS}, + {OPD(PF_38_66, 0x07), 1, &OpDispatchBuilder::PHSUBS}, {OPD(PF_38_NONE, 0x08), 1, &OpDispatchBuilder::PSIGN<1>}, - {OPD(PF_38_66, 0x08), 1, &OpDispatchBuilder::PSIGN<1>}, + {OPD(PF_38_66, 0x08), 1, &OpDispatchBuilder::PSIGN<1>}, {OPD(PF_38_NONE, 0x09), 1, &OpDispatchBuilder::PSIGN<2>}, - {OPD(PF_38_66, 0x09), 1, &OpDispatchBuilder::PSIGN<2>}, + {OPD(PF_38_66, 0x09), 1, &OpDispatchBuilder::PSIGN<2>}, {OPD(PF_38_NONE, 0x0A), 1, &OpDispatchBuilder::PSIGN<4>}, - {OPD(PF_38_66, 0x0A), 1, &OpDispatchBuilder::PSIGN<4>}, + {OPD(PF_38_66, 0x0A), 1, &OpDispatchBuilder::PSIGN<4>}, {OPD(PF_38_NONE, 0x0B), 1, &OpDispatchBuilder::PMULHRSW}, - {OPD(PF_38_66, 0x0B), 1, &OpDispatchBuilder::PMULHRSW}, - {OPD(PF_38_66, 0x10), 1, &OpDispatchBuilder::VectorVariableBlend<1>}, - {OPD(PF_38_66, 0x14), 1, &OpDispatchBuilder::VectorVariableBlend<4>}, - {OPD(PF_38_66, 0x15), 1, &OpDispatchBuilder::VectorVariableBlend<8>}, - {OPD(PF_38_66, 0x17), 1, &OpDispatchBuilder::PTestOp}, + {OPD(PF_38_66, 0x0B), 1, &OpDispatchBuilder::PMULHRSW}, + {OPD(PF_38_66, 0x10), 1, &OpDispatchBuilder::VectorVariableBlend<1>}, + {OPD(PF_38_66, 0x14), 1, &OpDispatchBuilder::VectorVariableBlend<4>}, + {OPD(PF_38_66, 0x15), 1, &OpDispatchBuilder::VectorVariableBlend<8>}, + {OPD(PF_38_66, 0x17), 1, &OpDispatchBuilder::PTestOp}, {OPD(PF_38_NONE, 0x1C), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_66, 0x1C), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_66, 0x1C), 1, &OpDispatchBuilder::VectorUnaryOp}, {OPD(PF_38_NONE, 0x1D), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_66, 0x1D), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_66, 0x1D), 1, &OpDispatchBuilder::VectorUnaryOp}, {OPD(PF_38_NONE, 0x1E), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_66, 0x1E), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_66, 0x20), 1, &OpDispatchBuilder::ExtendVectorElements<1, 2, true>}, - {OPD(PF_38_66, 0x21), 1, &OpDispatchBuilder::ExtendVectorElements<1, 4, true>}, - {OPD(PF_38_66, 0x22), 1, &OpDispatchBuilder::ExtendVectorElements<1, 8, true>}, - {OPD(PF_38_66, 0x23), 1, &OpDispatchBuilder::ExtendVectorElements<2, 4, true>}, - {OPD(PF_38_66, 0x24), 1, &OpDispatchBuilder::ExtendVectorElements<2, 8, true>}, - {OPD(PF_38_66, 0x25), 1, &OpDispatchBuilder::ExtendVectorElements<4, 8, true>}, - {OPD(PF_38_66, 0x28), 1, &OpDispatchBuilder::PMULLOp<4, true>}, - {OPD(PF_38_66, 0x29), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x2A), 1, &OpDispatchBuilder::MOVVectorNTOp}, - {OPD(PF_38_66, 0x2B), 1, &OpDispatchBuilder::PACKUSOp<4>}, - {OPD(PF_38_66, 0x30), 1, &OpDispatchBuilder::ExtendVectorElements<1, 2, false>}, - {OPD(PF_38_66, 0x31), 1, &OpDispatchBuilder::ExtendVectorElements<1, 4, false>}, - {OPD(PF_38_66, 0x32), 1, &OpDispatchBuilder::ExtendVectorElements<1, 8, false>}, - {OPD(PF_38_66, 0x33), 1, &OpDispatchBuilder::ExtendVectorElements<2, 4, false>}, - {OPD(PF_38_66, 0x34), 1, &OpDispatchBuilder::ExtendVectorElements<2, 8, false>}, - {OPD(PF_38_66, 0x35), 1, &OpDispatchBuilder::ExtendVectorElements<4, 8, false>}, - {OPD(PF_38_66, 0x37), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x38), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x39), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x3A), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x3B), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x3C), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x3D), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x3E), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x3F), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x40), 1, &OpDispatchBuilder::VectorALUOp}, - {OPD(PF_38_66, 0x41), 1, &OpDispatchBuilder::PHMINPOSUWOp}, + {OPD(PF_38_66, 0x1E), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_66, 0x20), 1, &OpDispatchBuilder::ExtendVectorElements<1, 2, true>}, + {OPD(PF_38_66, 0x21), 1, &OpDispatchBuilder::ExtendVectorElements<1, 4, true>}, + {OPD(PF_38_66, 0x22), 1, &OpDispatchBuilder::ExtendVectorElements<1, 8, true>}, + {OPD(PF_38_66, 0x23), 1, &OpDispatchBuilder::ExtendVectorElements<2, 4, true>}, + {OPD(PF_38_66, 0x24), 1, &OpDispatchBuilder::ExtendVectorElements<2, 8, true>}, + {OPD(PF_38_66, 0x25), 1, &OpDispatchBuilder::ExtendVectorElements<4, 8, true>}, + {OPD(PF_38_66, 0x28), 1, &OpDispatchBuilder::PMULLOp<4, true>}, + {OPD(PF_38_66, 0x29), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x2A), 1, &OpDispatchBuilder::MOVVectorNTOp}, + {OPD(PF_38_66, 0x2B), 1, &OpDispatchBuilder::PACKUSOp<4>}, + {OPD(PF_38_66, 0x30), 1, &OpDispatchBuilder::ExtendVectorElements<1, 2, false>}, + {OPD(PF_38_66, 0x31), 1, &OpDispatchBuilder::ExtendVectorElements<1, 4, false>}, + {OPD(PF_38_66, 0x32), 1, &OpDispatchBuilder::ExtendVectorElements<1, 8, false>}, + {OPD(PF_38_66, 0x33), 1, &OpDispatchBuilder::ExtendVectorElements<2, 4, false>}, + {OPD(PF_38_66, 0x34), 1, &OpDispatchBuilder::ExtendVectorElements<2, 8, false>}, + {OPD(PF_38_66, 0x35), 1, &OpDispatchBuilder::ExtendVectorElements<4, 8, false>}, + {OPD(PF_38_66, 0x37), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x38), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x39), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x3A), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x3B), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x3C), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x3D), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x3E), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x3F), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x40), 1, &OpDispatchBuilder::VectorALUOp}, + {OPD(PF_38_66, 0x41), 1, &OpDispatchBuilder::PHMINPOSUWOp}, {OPD(PF_38_NONE, 0xF0), 2, &OpDispatchBuilder::MOVBEOp}, {OPD(PF_38_66, 0xF0), 2, &OpDispatchBuilder::MOVBEOp}, @@ -6905,38 +6702,38 @@ constexpr uint16_t PF_F2 = 3; #define OPD(REX, prefix, opcode) ((REX << 9) | (prefix << 8) | opcode) #define PF_3A_NONE 0 -#define PF_3A_66 1 +#define PF_3A_66 1 constexpr std::tuple H0F3ATable[] = { - {OPD(0, PF_3A_66, 0x08), 1, &OpDispatchBuilder::VectorRound<4>}, - {OPD(0, PF_3A_66, 0x09), 1, &OpDispatchBuilder::VectorRound<8>}, - {OPD(0, PF_3A_66, 0x0A), 1, &OpDispatchBuilder::InsertScalarRound<4>}, - {OPD(0, PF_3A_66, 0x0B), 1, &OpDispatchBuilder::InsertScalarRound<8>}, - {OPD(0, PF_3A_66, 0x0C), 1, &OpDispatchBuilder::VectorBlend<4>}, - {OPD(0, PF_3A_66, 0x0D), 1, &OpDispatchBuilder::VectorBlend<8>}, - {OPD(0, PF_3A_66, 0x0E), 1, &OpDispatchBuilder::VectorBlend<2>}, + {OPD(0, PF_3A_66, 0x08), 1, &OpDispatchBuilder::VectorRound<4>}, + {OPD(0, PF_3A_66, 0x09), 1, &OpDispatchBuilder::VectorRound<8>}, + {OPD(0, PF_3A_66, 0x0A), 1, &OpDispatchBuilder::InsertScalarRound<4>}, + {OPD(0, PF_3A_66, 0x0B), 1, &OpDispatchBuilder::InsertScalarRound<8>}, + {OPD(0, PF_3A_66, 0x0C), 1, &OpDispatchBuilder::VectorBlend<4>}, + {OPD(0, PF_3A_66, 0x0D), 1, &OpDispatchBuilder::VectorBlend<8>}, + {OPD(0, PF_3A_66, 0x0E), 1, &OpDispatchBuilder::VectorBlend<2>}, {OPD(0, PF_3A_NONE, 0x0F), 1, &OpDispatchBuilder::PAlignrOp}, - {OPD(0, PF_3A_66, 0x0F), 1, &OpDispatchBuilder::PAlignrOp}, - {OPD(1, PF_3A_66, 0x0F), 1, &OpDispatchBuilder::PAlignrOp}, + {OPD(0, PF_3A_66, 0x0F), 1, &OpDispatchBuilder::PAlignrOp}, + {OPD(1, PF_3A_66, 0x0F), 1, &OpDispatchBuilder::PAlignrOp}, - {OPD(0, PF_3A_66, 0x14), 1, &OpDispatchBuilder::PExtrOp<1>}, - {OPD(0, PF_3A_66, 0x15), 1, &OpDispatchBuilder::PExtrOp<2>}, - {OPD(0, PF_3A_66, 0x16), 1, &OpDispatchBuilder::PExtrOp<4>}, - {OPD(1, PF_3A_66, 0x16), 1, &OpDispatchBuilder::PExtrOp<8>}, - {OPD(0, PF_3A_66, 0x17), 1, &OpDispatchBuilder::PExtrOp<4>}, + {OPD(0, PF_3A_66, 0x14), 1, &OpDispatchBuilder::PExtrOp<1>}, + {OPD(0, PF_3A_66, 0x15), 1, &OpDispatchBuilder::PExtrOp<2>}, + {OPD(0, PF_3A_66, 0x16), 1, &OpDispatchBuilder::PExtrOp<4>}, + {OPD(1, PF_3A_66, 0x16), 1, &OpDispatchBuilder::PExtrOp<8>}, + {OPD(0, PF_3A_66, 0x17), 1, &OpDispatchBuilder::PExtrOp<4>}, - {OPD(0, PF_3A_66, 0x20), 1, &OpDispatchBuilder::PINSROp<1>}, - {OPD(0, PF_3A_66, 0x21), 1, &OpDispatchBuilder::InsertPSOp}, - {OPD(0, PF_3A_66, 0x22), 1, &OpDispatchBuilder::PINSROp<4>}, - {OPD(1, PF_3A_66, 0x22), 1, &OpDispatchBuilder::PINSROp<8>}, - {OPD(0, PF_3A_66, 0x40), 1, &OpDispatchBuilder::DPPOp<4>}, - {OPD(0, PF_3A_66, 0x41), 1, &OpDispatchBuilder::DPPOp<8>}, - {OPD(0, PF_3A_66, 0x42), 1, &OpDispatchBuilder::MPSADBWOp}, + {OPD(0, PF_3A_66, 0x20), 1, &OpDispatchBuilder::PINSROp<1>}, + {OPD(0, PF_3A_66, 0x21), 1, &OpDispatchBuilder::InsertPSOp}, + {OPD(0, PF_3A_66, 0x22), 1, &OpDispatchBuilder::PINSROp<4>}, + {OPD(1, PF_3A_66, 0x22), 1, &OpDispatchBuilder::PINSROp<8>}, + {OPD(0, PF_3A_66, 0x40), 1, &OpDispatchBuilder::DPPOp<4>}, + {OPD(0, PF_3A_66, 0x41), 1, &OpDispatchBuilder::DPPOp<8>}, + {OPD(0, PF_3A_66, 0x42), 1, &OpDispatchBuilder::MPSADBWOp}, - {OPD(0, PF_3A_66, 0x60), 1, &OpDispatchBuilder::VPCMPESTRMOp}, - {OPD(0, PF_3A_66, 0x61), 1, &OpDispatchBuilder::VPCMPESTRIOp}, - {OPD(0, PF_3A_66, 0x62), 1, &OpDispatchBuilder::VPCMPISTRMOp}, - {OPD(0, PF_3A_66, 0x63), 1, &OpDispatchBuilder::VPCMPISTRIOp}, + {OPD(0, PF_3A_66, 0x60), 1, &OpDispatchBuilder::VPCMPESTRMOp}, + {OPD(0, PF_3A_66, 0x61), 1, &OpDispatchBuilder::VPCMPESTRIOp}, + {OPD(0, PF_3A_66, 0x62), 1, &OpDispatchBuilder::VPCMPISTRMOp}, + {OPD(0, PF_3A_66, 0x63), 1, &OpDispatchBuilder::VPCMPISTRIOp}, {OPD(0, PF_3A_NONE, 0xCC), 1, &OpDispatchBuilder::SHA1RNDS4Op}, }; @@ -6986,27 +6783,23 @@ constexpr uint16_t PF_F2 = 3; #define OPD(map_select, pp, opcode) (((map_select - 1) << 10) | (pp << 8) | (opcode)) static constexpr std::tuple BMITable[] = { - {OPD(2, 0b00, 0xF2), 1, &OpDispatchBuilder::ANDNBMIOp}, - {OPD(2, 0b00, 0xF5), 1, &OpDispatchBuilder::BZHI}, - {OPD(2, 0b10, 0xF5), 1, &OpDispatchBuilder::PEXT}, - {OPD(2, 0b11, 0xF5), 1, &OpDispatchBuilder::PDEP}, - {OPD(2, 0b11, 0xF6), 1, &OpDispatchBuilder::MULX}, - {OPD(2, 0b00, 0xF7), 1, &OpDispatchBuilder::BEXTRBMIOp}, - {OPD(2, 0b01, 0xF7), 1, &OpDispatchBuilder::BMI2Shift}, - {OPD(2, 0b10, 0xF7), 1, &OpDispatchBuilder::BMI2Shift}, + {OPD(2, 0b00, 0xF2), 1, &OpDispatchBuilder::ANDNBMIOp}, {OPD(2, 0b00, 0xF5), 1, &OpDispatchBuilder::BZHI}, + {OPD(2, 0b10, 0xF5), 1, &OpDispatchBuilder::PEXT}, {OPD(2, 0b11, 0xF5), 1, &OpDispatchBuilder::PDEP}, + {OPD(2, 0b11, 0xF6), 1, &OpDispatchBuilder::MULX}, {OPD(2, 0b00, 0xF7), 1, &OpDispatchBuilder::BEXTRBMIOp}, + {OPD(2, 0b01, 0xF7), 1, &OpDispatchBuilder::BMI2Shift}, {OPD(2, 0b10, 0xF7), 1, &OpDispatchBuilder::BMI2Shift}, {OPD(2, 0b11, 0xF7), 1, &OpDispatchBuilder::BMI2Shift}, {OPD(3, 0b11, 0xF0), 1, &OpDispatchBuilder::RORX}, }; #undef OPD - #define OPD(group, pp, opcode) (((group - X86Tables::InstType::TYPE_VEX_GROUP_12) << 4) | (pp << 3) | (opcode)) - constexpr std::tuple VEXGroupTable[] = { - {OPD(X86Tables::InstType::TYPE_VEX_GROUP_17, 0, 0b001), 1, &OpDispatchBuilder::BLSRBMIOp}, - {OPD(X86Tables::InstType::TYPE_VEX_GROUP_17, 0, 0b010), 1, &OpDispatchBuilder::BLSMSKBMIOp}, - {OPD(X86Tables::InstType::TYPE_VEX_GROUP_17, 0, 0b011), 1, &OpDispatchBuilder::BLSIBMIOp}, - }; - #undef OPD +#define OPD(group, pp, opcode) (((group - X86Tables::InstType::TYPE_VEX_GROUP_12) << 4) | (pp << 3) | (opcode)) + constexpr std::tuple VEXGroupTable[] = { + {OPD(X86Tables::InstType::TYPE_VEX_GROUP_17, 0, 0b001), 1, &OpDispatchBuilder::BLSRBMIOp}, + {OPD(X86Tables::InstType::TYPE_VEX_GROUP_17, 0, 0b010), 1, &OpDispatchBuilder::BLSMSKBMIOp}, + {OPD(X86Tables::InstType::TYPE_VEX_GROUP_17, 0, 0b011), 1, &OpDispatchBuilder::BLSIBMIOp}, + }; +#undef OPD constexpr std::tuple EVEXTable[] = { {0x10, 2, &OpDispatchBuilder::UnimplementedOp}, @@ -7047,8 +6840,7 @@ constexpr uint16_t PF_F2 = 3; if (Mode == Context::MODE_32BIT) { InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable_32); InstallToTable(FEXCore::X86Tables::SecondBaseOps, TwoByteOpTable_32); - } - else { + } else { InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable_64); InstallToTable(FEXCore::X86Tables::SecondBaseOps, TwoByteOpTable_64); } @@ -7067,7 +6859,7 @@ constexpr uint16_t PF_F2 = 3; InstallToTable(FEXCore::X86Tables::SecondModRMTableOps, SecondaryModRMExtensionOpTable); FEX_CONFIG_OPT(ReducedPrecision, X87REDUCEDPRECISION); - if(ReducedPrecision) { + if (ReducedPrecision) { InstallToX87Table(FEXCore::X86Tables::X87Ops, X87F64OpTable); } else { InstallToX87Table(FEXCore::X86Tables::X87Ops, X87OpTable); @@ -7081,4 +6873,4 @@ constexpr uint16_t PF_F2 = 3; InstallToTable(FEXCore::X86Tables::EVEXTableOps, EVEXTable); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 1b610d537..b84d23002 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -71,8 +71,8 @@ struct LoadSourceOptions { }; class OpDispatchBuilder final : public IREmitter { -friend class FEXCore::IR::Pass; -friend class FEXCore::IR::PassManager; + friend class FEXCore::IR::Pass; + friend class FEXCore::IR::PassManager; public: enum class FlagsGenerationType : uint8_t { @@ -103,11 +103,15 @@ public: void SetNewBlockIfChanged(uint64_t RIP) { auto it = JumpTargets.find(RIP); - if (it == JumpTargets.end()) return; + if (it == JumpTargets.end()) { + return; + } it->second.HaveEmitted = true; - if (CurrentCodeBlock->Wrapped(DualListData.ListBegin()).ID() == it->second.BlockEntry->Wrapped(DualListData.ListBegin()).ID()) return; + if (CurrentCodeBlock->Wrapped(DualListData.ListBegin()).ID() == it->second.BlockEntry->Wrapped(DualListData.ListBegin()).ID()) { + return; + } // We have hit a RIP that is a jump target // Thus we need to end up in a new block @@ -131,19 +135,20 @@ public: CalculateDeferredFlags(); return _Jump(); } - IRPair Jump(OrderedNode *_TargetBlock) { + IRPair Jump(OrderedNode* _TargetBlock) { CalculateDeferredFlags(); return _Jump(_TargetBlock); } - IRPair CondJump(OrderedNode *_Cmp1, OrderedNode *_Cmp2, OrderedNode *_TrueBlock, OrderedNode *_FalseBlock, CondClassType _Cond = {COND_NEQ}, uint8_t _CompareSize = 0) { + IRPair CondJump(OrderedNode* _Cmp1, OrderedNode* _Cmp2, OrderedNode* _TrueBlock, OrderedNode* _FalseBlock, + CondClassType _Cond = {COND_NEQ}, uint8_t _CompareSize = 0) { CalculateDeferredFlags(); return _CondJump(_Cmp1, _Cmp2, _TrueBlock, _FalseBlock, _Cond, _CompareSize); } - IRPair CondJump(OrderedNode *ssa0, CondClassType cond = {COND_NEQ}) { + IRPair CondJump(OrderedNode* ssa0, CondClassType cond = {COND_NEQ}) { CalculateDeferredFlags(); return _CondJump(ssa0, cond); } - IRPair CondJump(OrderedNode *ssa0, OrderedNode *ssa1, OrderedNode *ssa2, CondClassType cond = {COND_NEQ}) { + IRPair CondJump(OrderedNode* ssa0, OrderedNode* ssa1, OrderedNode* ssa2, CondClassType cond = {COND_NEQ}) { CalculateDeferredFlags(); return _CondJump(ssa0, ssa1, ssa2, cond); } @@ -179,8 +184,7 @@ public: // Set the RIP to the next instruction and leave auto RelocatedNextRIP = _EntrypointOffset(IR::SizeToOpSize(GPRSize), NextRIP - Entry); _ExitFunction(RelocatedNextRIP); - } - else if (it != JumpTargets.end()) { + } else if (it != JumpTargets.end()) { Jump(it->second.BlockEntry); return true; } @@ -195,7 +199,7 @@ public: return false; } - static bool CanHaveSideEffects(FEXCore::X86Tables::X86InstInfo const* TableInfo, FEXCore::X86Tables::DecodedOp Op) { + static bool CanHaveSideEffects(const FEXCore::X86Tables::X86InstInfo* TableInfo, FEXCore::X86Tables::DecodedOp Op) { if (TableInfo && TableInfo->Flags & X86Tables::InstFlags::FLAGS_DEBUG_MEM_ACCESS) { // If it is marked as having memory access then always say it has a side-effect. // Not always true but better to be safe. @@ -204,7 +208,7 @@ public: auto CanHaveSideEffects = false; - auto HasPotentialMemoryAccess = [](X86Tables::DecodedOperand const &Operand) -> bool { + auto HasPotentialMemoryAccess = [](const X86Tables::DecodedOperand& Operand) -> bool { if (Operand.IsNone()) { return false; } @@ -220,7 +224,7 @@ public: return CanHaveSideEffects; } - template + template void ForeachDirection(F&& Routine) { // Otherwise, prepare to branch. auto Zero = _Constant(0); @@ -246,21 +250,35 @@ public: StartNewBlock(); } - OpDispatchBuilder(FEXCore::Context::ContextImpl *ctx); - OpDispatchBuilder(FEXCore::Utils::IntrusivePooledAllocator &Allocator); + OpDispatchBuilder(FEXCore::Context::ContextImpl* ctx); + OpDispatchBuilder(FEXCore::Utils::IntrusivePooledAllocator& Allocator); void ResetWorkingList(); - void ResetDecodeFailure() { NeedsBlockEnd = DecodeFailure = false; } - bool HadDecodeFailure() const { return DecodeFailure; } - bool NeedsBlockEnder() const { return NeedsBlockEnd; } + void ResetDecodeFailure() { + NeedsBlockEnd = DecodeFailure = false; + } + bool HadDecodeFailure() const { + return DecodeFailure; + } + bool NeedsBlockEnder() const { + return NeedsBlockEnd; + } - void ResetHandledLock() { HandledLock = false; } - bool HasHandledLock() const { return HandledLock; } + void ResetHandledLock() { + HandledLock = false; + } + bool HasHandledLock() const { + return HandledLock; + } - void SetDumpIR(bool DumpIR) { ShouldDump = DumpIR; } - bool ShouldDumpIR() const { return ShouldDump; } + void SetDumpIR(bool DumpIR) { + ShouldDump = DumpIR; + } + bool ShouldDumpIR() const { + return ShouldDump; + } - void BeginFunction(uint64_t RIP, fextl::vector const *Blocks, uint32_t NumInstructions); + void BeginFunction(uint64_t RIP, const fextl::vector* Blocks, uint32_t NumInstructions); void Finalize(); // Dispatch builder functions @@ -366,8 +384,8 @@ public: void POPFOp(OpcodeArgs); struct CycleCounterPair { - OrderedNode *CounterLow; - OrderedNode *CounterHigh; + OrderedNode* CounterLow; + OrderedNode* CounterHigh; }; CycleCounterPair CycleCounter(); void RDTSCOp(OpcodeArgs); @@ -478,9 +496,9 @@ public: template void PExtrOp(OpcodeArgs); - template + template void PSIGN(OpcodeArgs); - template + template void VPSIGN(OpcodeArgs); // BMI1 Ops @@ -502,21 +520,21 @@ public: void ADXOp(OpcodeArgs); // AVX Ops - template + template void AVXVectorALUOp(OpcodeArgs); - template + template void AVXVectorUnaryOp(OpcodeArgs); - template + template void AVXVectorRound(OpcodeArgs); - template + template void AVXScalar_CVT_Float_To_Float(OpcodeArgs); - template + template void AVXVector_CVT_Float_To_Int(OpcodeArgs); - template + template void AVXVector_CVT_Int_To_Float(OpcodeArgs); template @@ -535,7 +553,7 @@ public: void InsertMMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs); template void InsertCVTGPR_To_FPR(OpcodeArgs); - template + template void AVXInsertCVTGPR_To_FPR(OpcodeArgs); template @@ -543,23 +561,23 @@ public: template void AVXInsertScalar_CVT_Float_To_Float(OpcodeArgs); - template + template void InsertScalarRound(OpcodeArgs); - template + template void AVXInsertScalarRound(OpcodeArgs); - template + template void InsertScalarFCMPOp(OpcodeArgs); - template + template void AVXInsertScalarFCMPOp(OpcodeArgs); - template + template void AVXCVTGPR_To_FPR(OpcodeArgs); - template + template void AVXVFCMPOp(OpcodeArgs); - template + template void VADDSUBPOp(OpcodeArgs); void VAESDecOp(OpcodeArgs); @@ -573,23 +591,23 @@ public: void VPBLENDDOp(OpcodeArgs); void VPBLENDWOp(OpcodeArgs); - template + template void VBROADCASTOp(OpcodeArgs); - template + template void VDPPOp(OpcodeArgs); void VEXTRACT128Op(OpcodeArgs); - template + template void VHADDPOp(OpcodeArgs); - template + template void VHSUBPOp(OpcodeArgs); void VINSERTOp(OpcodeArgs); void VINSERTPSOp(OpcodeArgs); - template + template void VMASKMOVOp(OpcodeArgs); void VMOVHPOp(OpcodeArgs); @@ -607,10 +625,10 @@ public: void VMPSADBWOp(OpcodeArgs); - template + template void VPACKSSOp(OpcodeArgs); - template + template void VPACKUSOp(OpcodeArgs); void VPALIGNROp(OpcodeArgs); @@ -624,14 +642,14 @@ public: void VPERMDOp(OpcodeArgs); void VPERMQOp(OpcodeArgs); - template + template void VPERMILImmOp(OpcodeArgs); - template + template void VPERMILRegOp(OpcodeArgs); void VPHADDSWOp(OpcodeArgs); - template + template void VPHSUBOp(OpcodeArgs); void VPHSUBSWOp(OpcodeArgs); @@ -642,65 +660,65 @@ public: void VPMADDUBSWOp(OpcodeArgs); void VPMADDWDOp(OpcodeArgs); - template + template void VPMASKMOVOp(OpcodeArgs); void VPMULHRSWOp(OpcodeArgs); - template + template void VPMULHWOp(OpcodeArgs); - template + template void VPMULLOp(OpcodeArgs); void VPSADBWOp(OpcodeArgs); void VPSHUFBOp(OpcodeArgs); - template + template void VPSHUFWOp(OpcodeArgs); - template + template void VPSLLOp(OpcodeArgs); void VPSLLDQOp(OpcodeArgs); - template + template void VPSLLIOp(OpcodeArgs); void VPSLLVOp(OpcodeArgs); - template + template void VPSRAOp(OpcodeArgs); - template + template void VPSRAIOp(OpcodeArgs); void VPSRAVDOp(OpcodeArgs); void VPSRLVOp(OpcodeArgs); - template + template void VPSRLDOp(OpcodeArgs); void VPSRLDQOp(OpcodeArgs); - template + template void VPUNPCKHOp(OpcodeArgs); - template + template void VPUNPCKLOp(OpcodeArgs); - template + template void VPSRLIOp(OpcodeArgs); - template + template void VSHUFOp(OpcodeArgs); - template + template void VTESTPOp(OpcodeArgs); void VZEROOp(OpcodeArgs); // X87 Ops - OrderedNode *ReconstructFSW(); + OrderedNode* ReconstructFSW(); // Returns new x87 stack top from FSW. - OrderedNode *ReconstructX87StateFromFSW(OrderedNode *FSW); + OrderedNode* ReconstructX87StateFromFSW(OrderedNode* FSW); template void FLD(OpcodeArgs); template @@ -824,7 +842,7 @@ public: void FXSaveOp(OpcodeArgs); void FXRStoreOp(OpcodeArgs); - OrderedNode *XSaveBase(X86Tables::DecodedOp Op); + OrderedNode* XSaveBase(X86Tables::DecodedOp Op); void XSaveOp(OpcodeArgs); void PAlignrOp(OpcodeArgs); @@ -890,7 +908,7 @@ public: void PSADBW(OpcodeArgs); - OrderedNode *BitwiseAtLeastTwo(OrderedNode *A, OrderedNode *B, OrderedNode *C); + OrderedNode* BitwiseAtLeastTwo(OrderedNode* A, OrderedNode* B, OrderedNode* C); void SHA1NEXTEOp(OpcodeArgs); void SHA1MSG1Op(OpcodeArgs); @@ -933,18 +951,20 @@ public: void InvalidOp(OpcodeArgs); - void SetPackedRFLAG(bool Lower8, OrderedNode *Src); - OrderedNode *GetPackedRFLAG(uint32_t FlagsMask = ~0U); + void SetPackedRFLAG(bool Lower8, OrderedNode* Src); + OrderedNode* GetPackedRFLAG(uint32_t FlagsMask = ~0U); - void SetMultiblock(bool _Multiblock) { Multiblock = _Multiblock; } + void SetMultiblock(bool _Multiblock) { + Multiblock = _Multiblock; + } static inline constexpr unsigned IndexNZCV(unsigned BitOffset) { switch (BitOffset) { - case FEXCore::X86State::RFLAG_OF_RAW_LOC: return 28; - case FEXCore::X86State::RFLAG_CF_RAW_LOC: return 29; - case FEXCore::X86State::RFLAG_ZF_RAW_LOC: return 30; - case FEXCore::X86State::RFLAG_SF_RAW_LOC: return 31; - default: FEX_UNREACHABLE; + case FEXCore::X86State::RFLAG_OF_RAW_LOC: return 28; + case FEXCore::X86State::RFLAG_CF_RAW_LOC: return 29; + case FEXCore::X86State::RFLAG_ZF_RAW_LOC: return 30; + case FEXCore::X86State::RFLAG_SF_RAW_LOC: return 31; + default: FEX_UNREACHABLE; } } @@ -960,19 +980,20 @@ protected: /* On AFP platforms, becomes fmin/fmax and preserves NZCV. Otherwise * becomes fcmp and clobbers. */ - if (CTX->HostFeatures.SupportsAFP) + if (CTX->HostFeatures.SupportsAFP) { return; + } break; - default: - break; + default: break; } // Invariant: When executing instructions that clobber NZCV, the flags must // be resident in a GPR, which is equivalent to CachedNZCV != nullptr. Get // the NZCV which fills the cache if necessary. - if (CachedNZCV == nullptr) + if (CachedNZCV == nullptr) { GetNZCV(); + } // Assume we'll need a reload. NZCVDirty = true; @@ -984,13 +1005,10 @@ private: bool HaveEmitted; }; - FEXCore::Context::ContextImpl *CTX{}; + FEXCore::Context::ContextImpl* CTX {}; - constexpr static unsigned FullNZCVMask = - (1U << FEXCore::X86State::RFLAG_CF_RAW_LOC) | - (1U << FEXCore::X86State::RFLAG_ZF_RAW_LOC) | - (1U << FEXCore::X86State::RFLAG_SF_RAW_LOC) | - (1U << FEXCore::X86State::RFLAG_OF_RAW_LOC); + constexpr static unsigned FullNZCVMask = (1U << FEXCore::X86State::RFLAG_CF_RAW_LOC) | (1U << FEXCore::X86State::RFLAG_ZF_RAW_LOC) | + (1U << FEXCore::X86State::RFLAG_SF_RAW_LOC) | (1U << FEXCore::X86State::RFLAG_OF_RAW_LOC); static bool ContainsNZCV(unsigned BitMask) { return (BitMask & FullNZCVMask) != 0; @@ -1000,139 +1018,106 @@ private: return ContainsNZCV(1U << BitOffset); } - OrderedNode* CachedNZCV{}; - bool NZCVDirty{}; - uint32_t PossiblySetNZCVBits{}; + OrderedNode* CachedNZCV {}; + bool NZCVDirty {}; + uint32_t PossiblySetNZCVBits {}; fextl::map JumpTargets; - bool HandledLock{false}; - bool DecodeFailure{false}; - bool NeedsBlockEnd{false}; + bool HandledLock {false}; + bool DecodeFailure {false}; + bool NeedsBlockEnd {false}; // Used during new op bringup - bool ShouldDump{false}; + bool ShouldDump {false}; void ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp, unsigned SrcIdx); // Opcode helpers for generalizing behavior across VEX and non-VEX variants. - OrderedNode* ADDSUBPOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2); + OrderedNode* ADDSUBPOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2); void AVXVectorALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); void AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); - template + template void AVXVectorVariableBlend(OpcodeArgs); void AVXVariableShiftImpl(OpcodeArgs, IROps IROp); OrderedNode* AESKeyGenAssistImpl(OpcodeArgs); - OrderedNode* CVTGPR_To_FPRImpl(OpcodeArgs, size_t DstElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op); + OrderedNode* + CVTGPR_To_FPRImpl(OpcodeArgs, size_t DstElementSize, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op); - OrderedNode* DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, + OrderedNode* DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm, size_t ElementSize); - OrderedNode* VDPPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, + OrderedNode* VDPPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm); - OrderedNode* ExtendVectorElementsImpl(OpcodeArgs, size_t ElementSize, - size_t DstElementSize, bool Signed); + OrderedNode* ExtendVectorElementsImpl(OpcodeArgs, size_t ElementSize, size_t DstElementSize, bool Signed); - OrderedNode* HSUBPOpImpl(OpcodeArgs, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op); + OrderedNode* HSUBPOpImpl(OpcodeArgs, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op); - OrderedNode* InsertPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, + OrderedNode* InsertPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm); - OrderedNode* MPSADBWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, + OrderedNode* MPSADBWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op, const X86Tables::DecodedOperand& ImmOp); - OrderedNode* PACKSSOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2); + OrderedNode* PACKSSOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2); - OrderedNode* PACKUSOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2); + OrderedNode* PACKUSOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2); - OrderedNode* PALIGNROpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, - const X86Tables::DecodedOperand& Imm, - bool IsAVX); + OrderedNode* PALIGNROpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, + const X86Tables::DecodedOperand& Imm, bool IsAVX); void PCMPXSTRXOpImpl(OpcodeArgs, bool IsExplicit, bool IsMask); - OrderedNode* PHADDSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2); + OrderedNode* PHADDSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2); OrderedNode* PHMINPOSUWOpImpl(OpcodeArgs); - OrderedNode* PHSUBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, size_t ElementSize); + OrderedNode* PHSUBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, size_t ElementSize); - OrderedNode* PHSUBSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op); + OrderedNode* PHSUBSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op); - OrderedNode* PINSROpImpl(OpcodeArgs, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, + OrderedNode* PINSROpImpl(OpcodeArgs, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op, const X86Tables::DecodedOperand& Imm); - OrderedNode* PMADDWDOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2); + OrderedNode* PMADDWDOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2); - OrderedNode* PMADDUBSWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op); + OrderedNode* PMADDUBSWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op); - OrderedNode* PMULHRSWOpImpl(OpcodeArgs, OrderedNode *Src1, OrderedNode *Src2); + OrderedNode* PMULHRSWOpImpl(OpcodeArgs, OrderedNode* Src1, OrderedNode* Src2); - OrderedNode* PMULHWOpImpl(OpcodeArgs, bool Signed, - OrderedNode *Src1, OrderedNode *Src2); + OrderedNode* PMULHWOpImpl(OpcodeArgs, bool Signed, OrderedNode* Src1, OrderedNode* Src2); - OrderedNode* PMULLOpImpl(OpcodeArgs, size_t ElementSize, bool Signed, - OrderedNode *Src1, OrderedNode *Src2); + OrderedNode* PMULLOpImpl(OpcodeArgs, size_t ElementSize, bool Signed, OrderedNode* Src1, OrderedNode* Src2); - OrderedNode* PSADBWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op); + OrderedNode* PSADBWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op); - OrderedNode* PSHUFBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2); + OrderedNode* PSHUFBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2); - OrderedNode* PSIGNImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2); + OrderedNode* PSIGNImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2); - OrderedNode* PSLLIImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, uint64_t Shift); + OrderedNode* PSLLIImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, uint64_t Shift); - OrderedNode* PSLLImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, OrderedNode *ShiftVec); + OrderedNode* PSLLImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, OrderedNode* ShiftVec); - OrderedNode* PSRAOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, OrderedNode *ShiftVec); + OrderedNode* PSRAOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, OrderedNode* ShiftVec); - OrderedNode* PSRLDOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, OrderedNode *ShiftVec); + OrderedNode* PSRLDOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, OrderedNode* ShiftVec); - OrderedNode* SHUFOpImpl(OpcodeArgs, size_t ElementSize, - const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, + OrderedNode* SHUFOpImpl(OpcodeArgs, size_t ElementSize, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm); - void VMASKMOVOpImpl(OpcodeArgs, size_t ElementSize, size_t DataSize, bool IsStore, - const X86Tables::DecodedOperand& MaskOp, + void VMASKMOVOpImpl(OpcodeArgs, size_t ElementSize, size_t DataSize, bool IsStore, const X86Tables::DecodedOperand& MaskOp, const X86Tables::DecodedOperand& DataOp); void MOVScalarOpImpl(OpcodeArgs, size_t ElementSize); void VMOVScalarOpImpl(OpcodeArgs, size_t ElementSize); - OrderedNode* VFCMPOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2, uint8_t CompType); + OrderedNode* VFCMPOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2, uint8_t CompType); void VTESTOpImpl(OpcodeArgs, size_t ElementSize); @@ -1151,47 +1136,28 @@ private: // - Example 32bit ADDSS Dest, Src // - Dest[31:0] = Dest[31:0] + Src[31:0] // - Dest[{256,128}:32] = (Unmodified) - OrderedNode* VectorScalarInsertALUOpImpl(OpcodeArgs, IROps IROp, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - bool ZeroUpperBits); + OrderedNode* VectorScalarInsertALUOpImpl(OpcodeArgs, IROps IROp, size_t DstSize, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits); - OrderedNode* VectorScalarUnaryInsertALUOpImpl(OpcodeArgs, IROps IROp, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - bool ZeroUpperBits); + OrderedNode* VectorScalarUnaryInsertALUOpImpl(OpcodeArgs, IROps IROp, size_t DstSize, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits); - OrderedNode* InsertCVTGPR_To_FPRImpl(OpcodeArgs, - size_t DstSize, size_t DstElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - bool ZeroUpperBits); + OrderedNode* InsertCVTGPR_To_FPRImpl(OpcodeArgs, size_t DstSize, size_t DstElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits); - OrderedNode* InsertScalar_CVT_Float_To_FloatImpl(OpcodeArgs, - size_t DstSize, size_t DstElementSize, size_t SrcElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, + OrderedNode* InsertScalar_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstSize, size_t DstElementSize, size_t SrcElementSize, + const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits); - OrderedNode* InsertScalarRoundImpl(OpcodeArgs, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - uint64_t Mode, bool ZeroUpperBits); + OrderedNode* InsertScalarRoundImpl(OpcodeArgs, size_t DstSize, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, uint64_t Mode, bool ZeroUpperBits); - OrderedNode* InsertScalarFCMPOpImpl(OpcodeArgs, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - uint8_t CompType, bool ZeroUpperBits); + OrderedNode* InsertScalarFCMPOpImpl(OpcodeArgs, size_t DstSize, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, uint8_t CompType, bool ZeroUpperBits); - OrderedNode* VectorRoundImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, uint64_t Mode); + OrderedNode* VectorRoundImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, uint64_t Mode); OrderedNode* Scalar_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstElementSize, size_t SrcElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op); + const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op); void Vector_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstElementSize, size_t SrcElementSize, bool IsAVX); @@ -1200,53 +1166,62 @@ private: OrderedNode* Vector_CVT_Int_To_FloatImpl(OpcodeArgs, size_t SrcElementSize, bool Widen); void XSaveOpImpl(OpcodeArgs); - void SaveX87State(OpcodeArgs, OrderedNode *MemBase); - void SaveSSEState(OrderedNode *MemBase); - void SaveMXCSRState(OrderedNode *MemBase); - void SaveAVXState(OrderedNode *MemBase); + void SaveX87State(OpcodeArgs, OrderedNode* MemBase); + void SaveSSEState(OrderedNode* MemBase); + void SaveMXCSRState(OrderedNode* MemBase); + void SaveAVXState(OrderedNode* MemBase); void XRstorOpImpl(OpcodeArgs); - void RestoreX87State(OrderedNode *MemBase); - void RestoreSSEState(OrderedNode *MemBase); - void RestoreMXCSRState(OrderedNode *MXCSR); - void RestoreAVXState(OrderedNode *MemBase); + void RestoreX87State(OrderedNode* MemBase); + void RestoreSSEState(OrderedNode* MemBase); + void RestoreMXCSRState(OrderedNode* MXCSR); + void RestoreAVXState(OrderedNode* MemBase); void DefaultX87State(OpcodeArgs); void DefaultSSEState(); void DefaultAVXState(); - OrderedNode *GetMXCSR(); + OrderedNode* GetMXCSR(); - #undef OpcodeArgs +#undef OpcodeArgs - OrderedNode *AppendSegmentOffset(OrderedNode *Value, uint32_t Flags, uint32_t DefaultPrefix = 0, bool Override = false); - OrderedNode *GetSegment(uint32_t Flags, uint32_t DefaultPrefix = 0, bool Override = false); + OrderedNode* AppendSegmentOffset(OrderedNode* Value, uint32_t Flags, uint32_t DefaultPrefix = 0, bool Override = false); + OrderedNode* GetSegment(uint32_t Flags, uint32_t DefaultPrefix = 0, bool Override = false); - void UpdatePrefixFromSegment(OrderedNode *Segment, uint32_t SegmentReg); + void UpdatePrefixFromSegment(OrderedNode* Segment, uint32_t SegmentReg); - OrderedNode *LoadGPRRegister(uint32_t GPR, int8_t Size = -1, uint8_t Offset = 0, bool AllowUpperGarbage = false); - OrderedNode *LoadXMMRegister(uint32_t XMM); - void StoreGPRRegister(uint32_t GPR, OrderedNode *const Src, int8_t Size = -1, uint8_t Offset = 0); - void StoreXMMRegister(uint32_t XMM, OrderedNode *const Src); + OrderedNode* LoadGPRRegister(uint32_t GPR, int8_t Size = -1, uint8_t Offset = 0, bool AllowUpperGarbage = false); + OrderedNode* LoadXMMRegister(uint32_t XMM); + void StoreGPRRegister(uint32_t GPR, OrderedNode* const Src, int8_t Size = -1, uint8_t Offset = 0); + void StoreXMMRegister(uint32_t XMM, OrderedNode* const Src); - OrderedNode *GetRelocatedPC(FEXCore::X86Tables::DecodedOp const& Op, int64_t Offset = 0); + OrderedNode* GetRelocatedPC(const FEXCore::X86Tables::DecodedOp& Op, int64_t Offset = 0); - OrderedNode *LoadSource(RegisterClassType Class, X86Tables::DecodedOp const& Op, X86Tables::DecodedOperand const& Operand, uint32_t Flags, const LoadSourceOptions& Options = {}); - OrderedNode *LoadSource_WithOpSize(RegisterClassType Class, X86Tables::DecodedOp const& Op, X86Tables::DecodedOperand const& Operand, uint8_t OpSize, uint32_t Flags, const LoadSourceOptions& Options = {}); - void StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, FEXCore::X86Tables::DecodedOperand const& Operand, OrderedNode *const Src, uint8_t OpSize, int8_t Align, MemoryAccessType AccessType = MemoryAccessType::DEFAULT); - void StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, FEXCore::X86Tables::DecodedOperand const& Operand, OrderedNode *const Src, int8_t Align, MemoryAccessType AccessType = MemoryAccessType::DEFAULT); - void StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, OrderedNode *const Src, int8_t Align, MemoryAccessType AccessType = MemoryAccessType::DEFAULT); + OrderedNode* LoadSource(RegisterClassType Class, const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand, uint32_t Flags, + const LoadSourceOptions& Options = {}); + OrderedNode* LoadSource_WithOpSize(RegisterClassType Class, const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand, + uint8_t OpSize, uint32_t Flags, const LoadSourceOptions& Options = {}); + void StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, + const FEXCore::X86Tables::DecodedOperand& Operand, OrderedNode* const Src, uint8_t OpSize, int8_t Align, + MemoryAccessType AccessType = MemoryAccessType::DEFAULT); + void StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, const FEXCore::X86Tables::DecodedOperand& Operand, + OrderedNode* const Src, int8_t Align, MemoryAccessType AccessType = MemoryAccessType::DEFAULT); + void StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, OrderedNode* const Src, int8_t Align, + MemoryAccessType AccessType = MemoryAccessType::DEFAULT); // In several instances, it's desirable to get a base address with the segment offset // applied to it. This pulls all the common-case appending into a single set of functions. - [[nodiscard]] OrderedNode *MakeSegmentAddress(const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand, uint8_t OpSize) { - OrderedNode *Mem = LoadSource_WithOpSize(GPRClass, Op, Operand, OpSize, Op->Flags, {.LoadData = false}); + [[nodiscard]] + OrderedNode* MakeSegmentAddress(const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand, uint8_t OpSize) { + OrderedNode* Mem = LoadSource_WithOpSize(GPRClass, Op, Operand, OpSize, Op->Flags, {.LoadData = false}); return AppendSegmentOffset(Mem, Op->Flags); } - [[nodiscard]] OrderedNode *MakeSegmentAddress(const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand) { + [[nodiscard]] + OrderedNode* MakeSegmentAddress(const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand) { return MakeSegmentAddress(Op, Operand, GetSrcSize(Op)); } - [[nodiscard]] OrderedNode *MakeSegmentAddress(X86State::X86Reg Reg, uint32_t Flags, uint32_t DefaultPrefix = 0, bool Override = false) { - OrderedNode *Address = LoadGPRRegister(Reg); + [[nodiscard]] + OrderedNode* MakeSegmentAddress(X86State::X86Reg Reg, uint32_t Flags, uint32_t DefaultPrefix = 0, bool Override = false) { + OrderedNode* Address = LoadGPRRegister(Reg); return AppendSegmentOffset(Address, Flags, DefaultPrefix, Override); } @@ -1254,28 +1229,36 @@ private: return CTX->HostFeatures.SupportsAVX ? OpSize::i256Bit : OpSize::i128Bit; } - [[nodiscard]] static uint32_t GPROffset(X86State::X86Reg reg) { + [[nodiscard]] + static uint32_t GPROffset(X86State::X86Reg reg) { LOGMAN_THROW_AA_FMT(reg <= X86State::X86Reg::REG_R15, "Invalid reg used"); return static_cast(offsetof(Core::CPUState, gregs[static_cast(reg)])); } - [[nodiscard]] static uint32_t MMBaseOffset() { + [[nodiscard]] + static uint32_t MMBaseOffset() { return static_cast(offsetof(Core::CPUState, mm[0][0])); } - [[nodiscard]] uint8_t GetDstSize(X86Tables::DecodedOp Op) const; - [[nodiscard]] uint8_t GetSrcSize(X86Tables::DecodedOp Op) const; - [[nodiscard]] uint32_t GetDstBitSize(X86Tables::DecodedOp Op) const; - [[nodiscard]] uint32_t GetSrcBitSize(X86Tables::DecodedOp Op) const; - [[nodiscard]] IR::OpSize OpSizeFromDst(X86Tables::DecodedOp Op) const { + [[nodiscard]] + uint8_t GetDstSize(X86Tables::DecodedOp Op) const; + [[nodiscard]] + uint8_t GetSrcSize(X86Tables::DecodedOp Op) const; + [[nodiscard]] + uint32_t GetDstBitSize(X86Tables::DecodedOp Op) const; + [[nodiscard]] + uint32_t GetSrcBitSize(X86Tables::DecodedOp Op) const; + [[nodiscard]] + IR::OpSize OpSizeFromDst(X86Tables::DecodedOp Op) const { return IR::SizeToOpSize(GetDstSize(Op)); } - [[nodiscard]] IR::OpSize OpSizeFromSrc(X86Tables::DecodedOp Op) const { + [[nodiscard]] + IR::OpSize OpSizeFromSrc(X86Tables::DecodedOp Op) const { return IR::SizeToOpSize(GetSrcSize(Op)); } static inline constexpr unsigned NZCVIndexMask(unsigned BitMask) { - unsigned NZCVMask{}; + unsigned NZCVMask {}; if (BitMask & (1U << FEXCore::X86State::RFLAG_OF_RAW_LOC)) { NZCVMask |= 1U << IndexNZCV(FEXCore::X86State::RFLAG_OF_RAW_LOC); } @@ -1306,8 +1289,9 @@ private: void HandleNZCV_RMW(uint32_t _PossiblySetNZCVBits = ~0) { CalculateDeferredFlags(); - if (NZCVDirty && CachedNZCV) + if (NZCVDirty && CachedNZCV) { _StoreNZCV(CachedNZCV); + } HandleNZCVWrite(_PossiblySetNZCVBits); } @@ -1317,14 +1301,15 @@ private: HandleNZCVWrite((1u << 31) | (1u << 30)); } - OrderedNode *GetNZCV() { - if (!CachedNZCV) + OrderedNode* GetNZCV() { + if (!CachedNZCV) { CachedNZCV = _LoadNZCV(); + } return CachedNZCV; } - void SetNZCV(OrderedNode *Value) { + void SetNZCV(OrderedNode* Value) { CachedNZCV = Value; NZCVDirty = true; } @@ -1341,17 +1326,16 @@ private: // Mask out the NZ bits, clearing CV. Even if the code sets CV after, this can end up faster // moves by allowing orlshl to be used instead of bfi. - PossiblySetNZCVBits = (1u << IndexNZCV(FEXCore::X86State::RFLAG_SF_RAW_LOC)) | - (1u << IndexNZCV(FEXCore::X86State::RFLAG_ZF_RAW_LOC)); + PossiblySetNZCVBits = (1u << IndexNZCV(FEXCore::X86State::RFLAG_SF_RAW_LOC)) | (1u << IndexNZCV(FEXCore::X86State::RFLAG_ZF_RAW_LOC)); SetNZCV(_And(OpSize::i32Bit, OldNZCV, _Constant(PossiblySetNZCVBits))); } - void SetNZ_ZeroCV(unsigned SrcSize, OrderedNode *Res) { + void SetNZ_ZeroCV(unsigned SrcSize, OrderedNode* Res) { HandleNZ00Write(); _TestNZ(IR::SizeToOpSize(SrcSize), Res, Res); } - void InsertNZCV(unsigned BitOffset, OrderedNode *Value, signed FlagOffset, bool MustMask) { + void InsertNZCV(unsigned BitOffset, OrderedNode* Value, signed FlagOffset, bool MustMask) { signed Bit = IndexNZCV(BitOffset); // If NZCV is not dirty, we always want to use rmif, it's 1 instruction to @@ -1360,13 +1344,13 @@ private: // expect that 2 instruction sequence to be a win (versus something like // bfe+mov+bfi+mov which can happen with our RA..). It's not totally // conservative but it's pretty good in practice. - bool PreferRmif = !NZCVDirty || FlagOffset || MustMask || - (PossiblySetNZCVBits & (1u << Bit)); + bool PreferRmif = !NZCVDirty || FlagOffset || MustMask || (PossiblySetNZCVBits & (1u << Bit)); if (CTX->HostFeatures.SupportsFlagM && PreferRmif) { // Update NZCV - if (NZCVDirty && CachedNZCV) + if (NZCVDirty && CachedNZCV) { _StoreNZCV(CachedNZCV); + } CachedNZCV = nullptr; NZCVDirty = false; @@ -1377,15 +1361,17 @@ private: CachedNZCV = nullptr; } else { // Insert as GPR - if (FlagOffset || MustMask) + if (FlagOffset || MustMask) { Value = _Bfe(OpSize::i64Bit, 1, FlagOffset, Value); + } - if (PossiblySetNZCVBits == 0) + if (PossiblySetNZCVBits == 0) { SetNZCV(_Lshl(OpSize::i64Bit, Value, _Constant(Bit))); - else if ((PossiblySetNZCVBits & (1u << Bit)) == 0) + } else if ((PossiblySetNZCVBits & (1u << Bit)) == 0) { SetNZCV(_Orlshl(OpSize::i32Bit, GetNZCV(), Value, Bit)); - else + } else { SetNZCV(_Bfi(OpSize::i32Bit, 1, Bit, GetNZCV(), Value)); + } } PossiblySetNZCVBits |= (1u << Bit); @@ -1407,11 +1393,11 @@ private: } template - void SetRFLAG(OrderedNode *Value, unsigned ValueOffset = 0, bool MustMask = false) { + void SetRFLAG(OrderedNode* Value, unsigned ValueOffset = 0, bool MustMask = false) { SetRFLAG(Value, BitOffset, ValueOffset, MustMask); } - void SetRFLAG(OrderedNode *Value, unsigned BitOffset, unsigned ValueOffset = 0, bool MustMask = false) { + void SetRFLAG(OrderedNode* Value, unsigned BitOffset, unsigned ValueOffset = 0, bool MustMask = false) { if (IsNZCV(BitOffset)) { InsertNZCV(BitOffset, Value, ValueOffset, MustMask); } else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { @@ -1419,8 +1405,9 @@ private: } else if (BitOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) { _StoreRegister(Value, false, offsetof(FEXCore::Core::CPUState, af_raw), GPRClass, GPRFixedClass, CTX->GetGPRSize()); } else { - if (ValueOffset || MustMask) + if (ValueOffset || MustMask) { Value = _Bfe(OpSize::i32Bit, 1, ValueOffset, Value); + } // For DF, we need to transform 0/1 into 1/-1 if (BitOffset == FEXCore::X86State::RFLAG_DF_RAW_LOC) { @@ -1443,37 +1430,32 @@ private: CondClassType CondForNZCVBit(unsigned BitOffset, bool Invert) { switch (BitOffset) { - case FEXCore::X86State::RFLAG_SF_RAW_LOC: - return Invert ? CondClassType{COND_PL} : CondClassType{COND_MI}; + case FEXCore::X86State::RFLAG_SF_RAW_LOC: return Invert ? CondClassType {COND_PL} : CondClassType {COND_MI}; - case FEXCore::X86State::RFLAG_ZF_RAW_LOC: - return Invert ? CondClassType{COND_NEQ} : CondClassType{COND_EQ}; + case FEXCore::X86State::RFLAG_ZF_RAW_LOC: return Invert ? CondClassType {COND_NEQ} : CondClassType {COND_EQ}; - case FEXCore::X86State::RFLAG_CF_RAW_LOC: - return Invert ? CondClassType{COND_ULT} : CondClassType{COND_UGE}; + case FEXCore::X86State::RFLAG_CF_RAW_LOC: return Invert ? CondClassType {COND_ULT} : CondClassType {COND_UGE}; - case FEXCore::X86State::RFLAG_OF_RAW_LOC: - return Invert ? CondClassType{COND_FNU} : CondClassType{COND_FU}; + case FEXCore::X86State::RFLAG_OF_RAW_LOC: return Invert ? CondClassType {COND_FNU} : CondClassType {COND_FU}; - default: - FEX_UNREACHABLE; + default: FEX_UNREACHABLE; } } - OrderedNode *GetRFLAG(unsigned BitOffset, bool Invert = false) { + OrderedNode* GetRFLAG(unsigned BitOffset, bool Invert = false) { if (IsNZCV(BitOffset)) { if (!(PossiblySetNZCVBits & (1u << IndexNZCV(BitOffset)))) { return _Constant(Invert ? 1 : 0); } else if (NZCVDirty) { auto Value = _Bfe(OpSize::i32Bit, 1, IndexNZCV(BitOffset), GetNZCV()); - if (Invert) + if (Invert) { return _Xor(OpSize::i32Bit, Value, _Constant(1)); - else + } else { return Value; + } } else { - return _NZCVSelect(OpSize::i32Bit, CondForNZCVBit(BitOffset, Invert), - _Constant(1), _Constant(0)); + return _NZCVSelect(OpSize::i32Bit, CondForNZCVBit(BitOffset, Invert), _Constant(1), _Constant(0)); } } else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { return _LoadRegister(false, offsetof(FEXCore::Core::CPUState, pf_raw), GPRClass, GPRFixedClass, CTX->GetGPRSize()); @@ -1488,18 +1470,19 @@ private: } // Returns (DF ? -Size : Size) - OrderedNode *LoadDir(const unsigned Size) { + OrderedNode* LoadDir(const unsigned Size) { auto Dir = _LoadDF(); auto Shift = FEXCore::ilog2(Size); - if (Shift) + if (Shift) { return _Lshl(IR::SizeToOpSize(CTX->GetGPRSize()), Dir, _Constant(Shift)); - else + } else { return Dir; + } } // Returns DF ? (X - Size) : (X + Size) - OrderedNode *OffsetByDir(OrderedNode *X, const unsigned Size) { + OrderedNode* OffsetByDir(OrderedNode* X, const unsigned Size) { auto Shift = FEXCore::ilog2(Size); return _AddShift(OpSize::i64Bit, X, _LoadDF(), ShiftType::LSL, Shift); @@ -1521,8 +1504,7 @@ private: // // We set PF to unordered (V), but our PF representation is inverted so we // actually set to !V. This is one instruction with the VC cond code. - OrderedNode *PFInvert = - _NZCVSelect(OpSize::i32Bit, CondClassType{COND_FNU}, _Constant(1), _Constant(0)); + OrderedNode* PFInvert = _NZCVSelect(OpSize::i32Bit, CondClassType {COND_FNU}, _Constant(1), _Constant(0)); SetRFLAG(PFInvert); @@ -1535,9 +1517,9 @@ private: // now, add a cfinv to deal. Hopefully we delete this later. CarryInvert(); } else { - OrderedNode *Z = GetRFLAG(FEXCore::X86State::RFLAG_ZF_RAW_LOC); - OrderedNode *C_inv = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC, true); - OrderedNode *V = GetRFLAG(FEXCore::X86State::RFLAG_OF_RAW_LOC); + OrderedNode* Z = GetRFLAG(FEXCore::X86State::RFLAG_ZF_RAW_LOC); + OrderedNode* C_inv = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC, true); + OrderedNode* V = GetRFLAG(FEXCore::X86State::RFLAG_OF_RAW_LOC); // We want to zero SF/OF, and then set CF/ZF. Zeroing up front lets us do // this all with shifted-or's on non-flagm platforms. @@ -1556,7 +1538,7 @@ private: // Set x87 comparison flags based on the result set by Arm FCMP. Clobbers // NZCV on flagm2 platforms. void ConvertNZCVToX87() { - OrderedNode *V = GetRFLAG(FEXCore::X86State::RFLAG_OF_RAW_LOC); + OrderedNode* V = GetRFLAG(FEXCore::X86State::RFLAG_OF_RAW_LOC); if (CTX->HostFeatures.SupportsFlagM2) { LOGMAN_THROW_A_FMT(!NZCVDirty, "only expected after fcmp"); @@ -1569,8 +1551,8 @@ private: SetRFLAG(GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC, true)); SetRFLAG(GetRFLAG(FEXCore::X86State::RFLAG_ZF_RAW_LOC)); } else { - OrderedNode *Z = GetRFLAG(FEXCore::X86State::RFLAG_ZF_RAW_LOC); - OrderedNode *N = GetRFLAG(FEXCore::X86State::RFLAG_SF_RAW_LOC); + OrderedNode* Z = GetRFLAG(FEXCore::X86State::RFLAG_ZF_RAW_LOC); + OrderedNode* N = GetRFLAG(FEXCore::X86State::RFLAG_SF_RAW_LOC); SetRFLAG(_Or(OpSize::i32Bit, N, V)); SetRFLAG(_Or(OpSize::i32Bit, Z, V)); @@ -1582,8 +1564,7 @@ private: // Helper to store a variable shift and calculate its flags for a variable // shift, with correct PF handling. - void HandleShift(X86Tables::DecodedOp Op, OrderedNode *Result, - OrderedNode *Dest, ShiftType Shift, OrderedNode *Src) { + void HandleShift(X86Tables::DecodedOp Op, OrderedNode* Result, OrderedNode* Dest, ShiftType Shift, OrderedNode* Src) { StoreResult(GPRClass, Op, Result, -1); @@ -1598,19 +1579,18 @@ private: // but does the right handling of ImplicitFlagClobber at least and must be // used instead of raw Op mutation. #define DeriveOp(Dest, NewOp, Expr) \ - if (ImplicitFlagClobber(NewOp)) \ - SaveNZCV(NewOp); \ - auto Dest = (Expr); \ + if (ImplicitFlagClobber(NewOp)) SaveNZCV(NewOp); \ + auto Dest = (Expr); \ Dest.first->Header.Op = (NewOp) // Named constant cache for the current block. // Different arrays for sizes 1,2,4,8,16,32. - OrderedNode *CachedNamedVectorConstants[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_MAX][6]{}; + OrderedNode* CachedNamedVectorConstants[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_MAX][6] {}; struct IndexNamedVectorMapKey { - uint32_t Index{}; + uint32_t Index {}; FEXCore::IR::IndexNamedVectorConstant NamedIndexedConstant; - uint8_t log2_size_in_bytes{}; - uint16_t _pad{}; + uint8_t log2_size_in_bytes {}; + uint16_t _pad {}; bool operator==(const IndexNamedVectorMapKey&) const = default; }; @@ -1619,10 +1599,10 @@ private: return XXH3_64bits(&k, sizeof(k)); } }; - fextl::unordered_map CachedIndexedNamedVectorConstants; + fextl::unordered_map CachedIndexedNamedVectorConstants; // Load and cache a named vector constant. - OrderedNode *LoadAndCacheNamedVectorConstant(uint8_t Size, FEXCore::IR::NamedVectorConstant NamedConstant) { + OrderedNode* LoadAndCacheNamedVectorConstant(uint8_t Size, FEXCore::IR::NamedVectorConstant NamedConstant) { auto log2_size_bytes = FEXCore::ilog2(Size); if (CachedNamedVectorConstants[NamedConstant][log2_size_bytes]) { return CachedNamedVectorConstants[NamedConstant][log2_size_bytes]; @@ -1632,7 +1612,7 @@ private: CachedNamedVectorConstants[NamedConstant][log2_size_bytes] = Constant; return Constant; } - OrderedNode *LoadAndCacheIndexedNamedVectorConstant(uint8_t Size, FEXCore::IR::IndexNamedVectorConstant NamedIndexedConstant, uint32_t Index) { + OrderedNode* LoadAndCacheIndexedNamedVectorConstant(uint8_t Size, FEXCore::IR::IndexNamedVectorConstant NamedIndexedConstant, uint32_t Index) { IndexNamedVectorMapKey Key { .Index = Index, .NamedIndexedConstant = NamedIndexedConstant, @@ -1657,8 +1637,8 @@ private: } std::pair DecodeNZCVCondition(uint8_t OP) const; - OrderedNode *SelectBit(OrderedNode *Cmp, IR::OpSize ResultSize, OrderedNode *TrueValue, OrderedNode *FalseValue); - OrderedNode *SelectCC(uint8_t OP, IR::OpSize ResultSize, OrderedNode *TrueValue, OrderedNode *FalseValue); + OrderedNode* SelectBit(OrderedNode* Cmp, IR::OpSize ResultSize, OrderedNode* TrueValue, OrderedNode* FalseValue); + OrderedNode* SelectCC(uint8_t OP, IR::OpSize ResultSize, OrderedNode* TrueValue, OrderedNode* FalseValue); /** * @name Deferred RFLAG calculation and generation. @@ -1687,7 +1667,7 @@ private: uint8_t SrcSize; // Every flag generation type has a result - OrderedNode *Res{}; + OrderedNode* Res {}; union { // UMUL, BEXTR, BLSI, POPCOUNT, ZCNT, RDRAND @@ -1696,32 +1676,32 @@ private: // MUL, BLSR, BLSMSKB, BZHI struct { - OrderedNode *Src1; + OrderedNode* Src1; } OneSource; // Logical struct { - OrderedNode *Src1; - OrderedNode *Src2; + OrderedNode* Src1; + OrderedNode* Src2; } TwoSource; // LSHLI, LSHRI, ASHRI struct { - OrderedNode *Src1; + OrderedNode* Src1; uint64_t Imm; } OneSrcImmediate; // ADD, SUB struct { - OrderedNode *Src1; - OrderedNode *Src2; + OrderedNode* Src1; + OrderedNode* Src2; bool UpdateCF; } TwoSrcImmediate; - } Sources{}; + } Sources {}; }; - DeferredFlagData CurrentDeferredFlags{}; + DeferredFlagData CurrentDeferredFlags {}; /** * @brief Takes the current deferred flag state and stores the result in to RFLAGS. @@ -1753,13 +1733,14 @@ private: return CurrentDeferredFlags.Type == FlagsGenerationType::TYPE_NONE; } - template - void Calculate_ShiftVariable(OrderedNode *Shift, F&& Calculate) { + template + void Calculate_ShiftVariable(OrderedNode* Shift, F&& Calculate) { // RCR can call this with constants, so handle that without branching. uint64_t Const; if (IsValueConstant(WrapNode(Shift), &Const)) { - if (Const) + if (Const) { Calculate(); + } return; } @@ -1788,37 +1769,37 @@ private: /** * @name These functions are used by the deferred flag handling while it is calculating and storing flags in to RFLAGs. * @{ */ - OrderedNode *LoadPFRaw(bool Invert); - OrderedNode *LoadAF(); + OrderedNode* LoadPFRaw(bool Invert); + OrderedNode* LoadAF(); void FixupAF(); - void SetAFAndFixup(OrderedNode *AF); - OrderedNode *CalculateAFForDecimal(OrderedNode *A); - void CalculatePF(OrderedNode *Res); - void CalculateAF(OrderedNode *Src1, OrderedNode *Src2); + void SetAFAndFixup(OrderedNode* AF); + OrderedNode* CalculateAFForDecimal(OrderedNode* A); + void CalculatePF(OrderedNode* Res); + void CalculateAF(OrderedNode* Src1, OrderedNode* Src2); - void CalculateOF(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool Sub); - OrderedNode *CalculateFlags_ADC(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2); - OrderedNode *CalculateFlags_SBB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2); - OrderedNode *CalculateFlags_SUB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true); - OrderedNode *CalculateFlags_ADD(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true); - void CalculateFlags_MUL(uint8_t SrcSize, OrderedNode *Res, OrderedNode *High); - void CalculateFlags_UMUL(OrderedNode *High); - void CalculateFlags_Logical(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2); - void CalculateFlags_ShiftLeft(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2); - void CalculateFlags_ShiftLeftImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift); - void CalculateFlags_ShiftRight(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2); - void CalculateFlags_ShiftRightImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift); - void CalculateFlags_ShiftRightDoubleImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift); - void CalculateFlags_ShiftRightImmediateCommon(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift); - void CalculateFlags_SignShiftRightImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift); - void CalculateFlags_BEXTR(OrderedNode *Src); - void CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode *Src); - void CalculateFlags_BLSMSK(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src); - void CalculateFlags_BLSR(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src); - void CalculateFlags_POPCOUNT(OrderedNode *Src); - void CalculateFlags_BZHI(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src); - void CalculateFlags_ZCNT(uint8_t SrcSize, OrderedNode *Result); - void CalculateFlags_RDRAND(OrderedNode *Src); + void CalculateOF(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, OrderedNode* Src2, bool Sub); + OrderedNode* CalculateFlags_ADC(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2); + OrderedNode* CalculateFlags_SBB(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2); + OrderedNode* CalculateFlags_SUB(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2, bool UpdateCF = true); + OrderedNode* CalculateFlags_ADD(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2, bool UpdateCF = true); + void CalculateFlags_MUL(uint8_t SrcSize, OrderedNode* Res, OrderedNode* High); + void CalculateFlags_UMUL(OrderedNode* High); + void CalculateFlags_Logical(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, OrderedNode* Src2); + void CalculateFlags_ShiftLeft(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, OrderedNode* Src2); + void CalculateFlags_ShiftLeftImmediate(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift); + void CalculateFlags_ShiftRight(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, OrderedNode* Src2); + void CalculateFlags_ShiftRightImmediate(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift); + void CalculateFlags_ShiftRightDoubleImmediate(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift); + void CalculateFlags_ShiftRightImmediateCommon(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift); + void CalculateFlags_SignShiftRightImmediate(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift); + void CalculateFlags_BEXTR(OrderedNode* Src); + void CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode* Src); + void CalculateFlags_BLSMSK(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src); + void CalculateFlags_BLSR(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src); + void CalculateFlags_POPCOUNT(OrderedNode* Src); + void CalculateFlags_BZHI(uint8_t SrcSize, OrderedNode* Result, OrderedNode* Src); + void CalculateFlags_ZCNT(uint8_t SrcSize, OrderedNode* Result); + void CalculateFlags_RDRAND(OrderedNode* Src); /** @} */ /** @@ -1826,7 +1807,7 @@ private: * * Depending on the operation it may force a RFLAGs calculation before storing the new deferred state. * @{ */ - void GenerateFlags_SUB(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true) { + void GenerateFlags_SUB(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Src1, OrderedNode* Src2, bool UpdateCF = true) { if (!UpdateCF) { // If we aren't updating CF then we need to calculate flags. Invalidation mask would make this not required. CalculateDeferredFlags(); @@ -1834,30 +1815,34 @@ private: CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_SUB, .SrcSize = GetSrcSize(Op), - .Sources = { - .TwoSrcImmediate = { - .Src1 = Src1, - .Src2 = Src2, - .UpdateCF = UpdateCF, + .Sources = + { + .TwoSrcImmediate = + { + .Src1 = Src1, + .Src2 = Src2, + .UpdateCF = UpdateCF, + }, }, - }, }; } - void GenerateFlags_MUL(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *High) { + void GenerateFlags_MUL(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* High) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_MUL, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .OneSource = { - .Src1 = High, + .Sources = + { + .OneSource = + { + .Src1 = High, + }, }, - }, }; } - void GenerateFlags_UMUL(FEXCore::X86Tables::DecodedOp Op, OrderedNode *High) { + void GenerateFlags_UMUL(FEXCore::X86Tables::DecodedOp Op, OrderedNode* High) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_UMUL, .SrcSize = GetSrcSize(Op), @@ -1865,89 +1850,107 @@ private: }; } - void GenerateFlags_Logical(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2) { + void GenerateFlags_Logical(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* Src1, OrderedNode* Src2) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_LOGICAL, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .TwoSource = { - .Src1 = Src1, - .Src2 = Src2, + .Sources = + { + .TwoSource = + { + .Src1 = Src1, + .Src2 = Src2, + }, }, - }, }; } - void GenerateFlags_ShiftLeftImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { + void GenerateFlags_ShiftLeftImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero. - if (Shift == 0) return; + if (Shift == 0) { + return; + } CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_LSHLI, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .OneSrcImmediate = { - .Src1 = Src1, - .Imm = Shift, + .Sources = + { + .OneSrcImmediate = + { + .Src1 = Src1, + .Imm = Shift, + }, }, - }, }; } - void GenerateFlags_SignShiftRightImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { + void GenerateFlags_SignShiftRightImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero. - if (Shift == 0) return; + if (Shift == 0) { + return; + } CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_ASHRI, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .OneSrcImmediate = { - .Src1 = Src1, - .Imm = Shift, + .Sources = + { + .OneSrcImmediate = + { + .Src1 = Src1, + .Imm = Shift, + }, }, - }, }; } - void GenerateFlags_ShiftRightImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { + void GenerateFlags_ShiftRightImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero. - if (Shift == 0) return; + if (Shift == 0) { + return; + } CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_LSHRI, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .OneSrcImmediate = { - .Src1 = Src1, - .Imm = Shift, + .Sources = + { + .OneSrcImmediate = + { + .Src1 = Src1, + .Imm = Shift, + }, }, - }, }; } - void GenerateFlags_ShiftRightDoubleImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { + void GenerateFlags_ShiftRightDoubleImmediate(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero. - if (Shift == 0) return; + if (Shift == 0) { + return; + } CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_LSHRDI, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .OneSrcImmediate = { - .Src1 = Src1, - .Imm = Shift, + .Sources = + { + .OneSrcImmediate = + { + .Src1 = Src1, + .Imm = Shift, + }, }, - }, }; } - void GenerateFlags_BEXTR(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { + void GenerateFlags_BEXTR(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_BEXTR, .SrcSize = GetSrcSize(Op), @@ -1955,7 +1958,7 @@ private: }; } - void GenerateFlags_BLSI(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { + void GenerateFlags_BLSI(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_BLSI, .SrcSize = GetSrcSize(Op), @@ -1963,33 +1966,37 @@ private: }; } - void GenerateFlags_BLSMSK(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src) { + void GenerateFlags_BLSMSK(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_BLSMSK, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .OneSource = { - .Src1 = Src, + .Sources = + { + .OneSource = + { + .Src1 = Src, + }, }, - }, }; } - void GenerateFlags_BLSR(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src) { + void GenerateFlags_BLSR(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Res, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_BLSR, .SrcSize = GetSrcSize(Op), .Res = Res, - .Sources = { - .OneSource = { - .Src1 = Src, + .Sources = + { + .OneSource = + { + .Src1 = Src, + }, }, - }, }; } - void GenerateFlags_POPCOUNT(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { + void GenerateFlags_POPCOUNT(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_POPCOUNT, .SrcSize = GetSrcSize(Op), @@ -1997,20 +2004,22 @@ private: }; } - void GenerateFlags_BZHI(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Result, OrderedNode *Src) { + void GenerateFlags_BZHI(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Result, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_BZHI, .SrcSize = GetSrcSize(Op), .Res = Result, - .Sources = { - .OneSource = { - .Src1 = Src, + .Sources = + { + .OneSource = + { + .Src1 = Src, + }, }, - }, }; } - void GenerateFlags_ZCNT(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { + void GenerateFlags_ZCNT(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_ZCNT, .SrcSize = GetSrcSize(Op), @@ -2018,7 +2027,7 @@ private: }; } - void GenerateFlags_RDRAND(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { + void GenerateFlags_RDRAND(FEXCore::X86Tables::DecodedOp Op, OrderedNode* Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_RDRAND, .SrcSize = GetSrcSize(Op), @@ -2026,7 +2035,7 @@ private: }; } - OrderedNode *AndConst(FEXCore::IR::OpSize Size, OrderedNode *Node, uint64_t Const) { + OrderedNode* AndConst(FEXCore::IR::OpSize Size, OrderedNode* Node, uint64_t Const) { uint64_t NodeConst; if (IsValueConstant(WrapNode(Node), &NodeConst)) { @@ -2039,14 +2048,14 @@ private: /** @} */ /** @} */ - OrderedNode * GetX87Top(); - void SetX87ValidTag(OrderedNode *Value, bool Valid); - OrderedNode *GetX87ValidTag(OrderedNode *Value); - OrderedNode *GetX87Tag(OrderedNode *Value, OrderedNode *AbridgedFTW); - OrderedNode *GetX87Tag(OrderedNode *Value); - void SetX87FTW(OrderedNode *FTW); - OrderedNode *GetX87FTW(); - void SetX87Top(OrderedNode *Value); + OrderedNode* GetX87Top(); + void SetX87ValidTag(OrderedNode* Value, bool Valid); + OrderedNode* GetX87ValidTag(OrderedNode* Value); + OrderedNode* GetX87Tag(OrderedNode* Value, OrderedNode* AbridgedFTW); + OrderedNode* GetX87Tag(OrderedNode* Value); + void SetX87FTW(OrderedNode* FTW); + OrderedNode* GetX87FTW(); + void SetX87Top(OrderedNode* Value); bool DestIsLockedMem(FEXCore::X86Tables::DecodedOp Op) const { return DestIsMem(Op) && (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK) != 0; @@ -2056,52 +2065,51 @@ private: return !Op->Dest.IsGPR(); } - void CreateJumpBlocks(fextl::vector const *Blocks); + void CreateJumpBlocks(const fextl::vector* Blocks); bool BlockSetRIP {false}; - bool Multiblock{}; + bool Multiblock {}; uint64_t Entry; - OrderedNode* _StoreMemAutoTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode *Addr, OrderedNode *Value, uint8_t Align = 1) { - if (CTX->IsAtomicTSOEnabled()) + OrderedNode* _StoreMemAutoTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode* Addr, OrderedNode* Value, uint8_t Align = 1) { + if (CTX->IsAtomicTSOEnabled()) { return _StoreMemTSO(Class, Size, Value, Addr, Invalid(), Align, MEM_OFFSET_SXTX, 1); - else + } else { return _StoreMem(Class, Size, Value, Addr, Invalid(), Align, MEM_OFFSET_SXTX, 1); + } } - OrderedNode* _LoadMemAutoTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode *ssa0, uint8_t Align = 1) { - if (CTX->IsAtomicTSOEnabled()) + OrderedNode* _LoadMemAutoTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode* ssa0, uint8_t Align = 1) { + if (CTX->IsAtomicTSOEnabled()) { return _LoadMemTSO(Class, Size, ssa0, Invalid(), Align, MEM_OFFSET_SXTX, 1); - else + } else { return _LoadMem(Class, Size, ssa0, Invalid(), Align, MEM_OFFSET_SXTX, 1); + } } - OrderedNode* Prefetch(bool ForStore, bool Stream, uint8_t CacheLevel, OrderedNode *ssa0) { + OrderedNode* Prefetch(bool ForStore, bool Stream, uint8_t CacheLevel, OrderedNode* ssa0) { return _Prefetch(ForStore, Stream, CacheLevel, ssa0, Invalid(), MEM_OFFSET_SXTX, 1); } void InstallHostSpecificOpcodeHandlers(); ///< Segment telemetry tracking - uint32_t SegmentsNeedReadCheck{~0U}; - void CheckLegacySegmentWrite(OrderedNode *NewNode, uint32_t SegmentReg); - void CheckLegacySegmentRead(OrderedNode *NewNode, uint32_t SegmentReg); + uint32_t SegmentsNeedReadCheck {~0U}; + void CheckLegacySegmentWrite(OrderedNode* NewNode, uint32_t SegmentReg); + void CheckLegacySegmentRead(OrderedNode* NewNode, uint32_t SegmentReg); }; void InstallOpcodeHandlers(Context::OperatingMode Mode); -} -template <> +} // namespace FEXCore::IR +template<> struct fmt::formatter : fmt::formatter { using Base = fmt::formatter; // Pass-through the underlying value, so IDs can // be formatted like any integral value. - template + template auto format(const FEXCore::IR::OpDispatchBuilder::FlagsGenerationType& ID, FormatContext& ctx) { return Base::format(static_cast(ID), ctx); } }; - - - diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp index dc1ea4069..2e1aa85e4 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Crypto.cpp @@ -22,10 +22,10 @@ class OrderedNode; #define OpcodeArgs [[maybe_unused]] FEXCore::X86Tables::DecodedOp Op void OpDispatchBuilder::SHA1NEXTEOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *RotatedNode{}; + OrderedNode* RotatedNode {}; if (CTX->HostFeatures.SupportsSHA) { // ARMv8 SHA1 extension provides a `SHA1H` instruction which does a fixed rotate by 30. // This only operates on element 0 rather than element 3. We don't have the luxury of rewriting the x86 SHA algorithm to take advantage of this. @@ -34,8 +34,7 @@ void OpDispatchBuilder::SHA1NEXTEOp(OpcodeArgs) { auto Duplicated = _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Dest, 3); auto Sha1HRotated = _VSha1H(Duplicated); RotatedNode = _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Sha1HRotated, 0); - } - else { + } else { // SHA1 extension missing, manually rotate. // Emulate rotate. auto ShiftLeft = _VShlI(OpSize::i128Bit, OpSize::i32Bit, Dest, 30); @@ -48,20 +47,20 @@ void OpDispatchBuilder::SHA1NEXTEOp(OpcodeArgs) { } void OpDispatchBuilder::SHA1MSG1Op(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *NewVec = _VExtr(16, 8, Dest, Src, 1); + OrderedNode* NewVec = _VExtr(16, 8, Dest, Src, 1); // [W0, W1, W2, W3] ^ [W2, W3, W4, W5] - OrderedNode *Result = _VXor(16, 1, Dest, NewVec); + OrderedNode* Result = _VXor(16, 1, Dest, NewVec); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::SHA1MSG2Op(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); // This instruction mostly matches ARMv8's SHA1SU1 instruction but one of the elements are flipped in an unexpected way. // Do all the work without it. @@ -91,41 +90,43 @@ void OpDispatchBuilder::SHA1MSG2Op(OpcodeArgs) { } void OpDispatchBuilder::SHA1RNDS4Op(OpcodeArgs) { - LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), - "Src1 needs to be literal here to indicate function and constants"); + LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here to indicate function and constants"); using FnType = OrderedNode* (*)(OpDispatchBuilder&, OrderedNode*, OrderedNode*, OrderedNode*); - const auto f0 = [](OpDispatchBuilder &Self, OrderedNode *B, OrderedNode *C, OrderedNode *D) -> OrderedNode* { + const auto f0 = [](OpDispatchBuilder& Self, OrderedNode* B, OrderedNode* C, OrderedNode* D) -> OrderedNode* { return Self._Xor(OpSize::i32Bit, Self._And(OpSize::i32Bit, B, C), Self._Andn(OpSize::i32Bit, D, B)); }; - const auto f1 = [](OpDispatchBuilder &Self, OrderedNode *B, OrderedNode *C, OrderedNode *D) -> OrderedNode* { + const auto f1 = [](OpDispatchBuilder& Self, OrderedNode* B, OrderedNode* C, OrderedNode* D) -> OrderedNode* { return Self._Xor(OpSize::i32Bit, Self._Xor(OpSize::i32Bit, B, C), D); }; - const auto f2 = [](OpDispatchBuilder &Self, OrderedNode *B, OrderedNode *C, OrderedNode *D) -> OrderedNode* { + const auto f2 = [](OpDispatchBuilder& Self, OrderedNode* B, OrderedNode* C, OrderedNode* D) -> OrderedNode* { return Self.BitwiseAtLeastTwo(B, C, D); }; - const auto f3 = [](OpDispatchBuilder &Self, OrderedNode *B, OrderedNode *C, OrderedNode *D) -> OrderedNode* { + const auto f3 = [](OpDispatchBuilder& Self, OrderedNode* B, OrderedNode* C, OrderedNode* D) -> OrderedNode* { return Self._Xor(OpSize::i32Bit, Self._Xor(OpSize::i32Bit, B, C), D); }; - constexpr std::array k_array{ + constexpr std::array k_array { 0x5A827999U, 0x6ED9EBA1U, 0x8F1BBCDCU, 0xCA62C1D6U, }; - constexpr std::array fn_array{ - f0, f1, f2, f3, + constexpr std::array fn_array { + f0, + f1, + f2, + f3, }; const uint64_t Imm8 = Op->Src[1].Data.Literal.Value & 0b11; const FnType Fn = fn_array[Imm8]; auto K = _Constant(32, k_array[Imm8]); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto W0E = _VExtractToGPR(16, 4, Src, 3); @@ -137,7 +138,8 @@ void OpDispatchBuilder::SHA1RNDS4Op(OpcodeArgs) { auto C = _VExtractToGPR(16, 4, Dest, 1); auto D = _VExtractToGPR(16, 4, Dest, 0); - auto A1 = _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, Fn(*this, B, C, D), _Ror(OpSize::i32Bit, A, _Constant(32, 27))), W0E), K); + auto A1 = + _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, Fn(*this, B, C, D), _Ror(OpSize::i32Bit, A, _Constant(32, 27))), W0E), K); auto B1 = A; auto C1 = _Ror(OpSize::i32Bit, B, _Constant(32, 2)); auto D1 = C; @@ -145,13 +147,14 @@ void OpDispatchBuilder::SHA1RNDS4Op(OpcodeArgs) { return {A1, B1, C1, D1, E1}; }; - const auto Round1To3 = [&](OrderedNode *A, OrderedNode *B, OrderedNode *C, - OrderedNode *D, OrderedNode *E, OrderedNode *Src, unsigned W_idx) -> RoundResult { + const auto Round1To3 = [&](OrderedNode* A, OrderedNode* B, OrderedNode* C, OrderedNode* D, OrderedNode* E, OrderedNode* Src, + unsigned W_idx) -> RoundResult { // Kill W and E at the beginning auto W = _VExtractToGPR(16, 4, Src, W_idx); auto Q = _Add(OpSize::i32Bit, W, E); - auto ANext = _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, Fn(*this, B, C, D), _Ror(OpSize::i32Bit, A, _Constant(32, 27))), Q), K); + auto ANext = + _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, _Add(OpSize::i32Bit, Fn(*this, B, C, D), _Ror(OpSize::i32Bit, A, _Constant(32, 27))), Q), K); auto BNext = A; auto CNext = _Ror(OpSize::i32Bit, B, _Constant(32, 2)); auto DNext = C; @@ -163,9 +166,9 @@ void OpDispatchBuilder::SHA1RNDS4Op(OpcodeArgs) { auto [A1, B1, C1, D1, E1] = Round0(); auto [A2, B2, C2, D2, E2] = Round1To3(A1, B1, C1, D1, E1, Src, 2); auto [A3, B3, C3, D3, E3] = Round1To3(A2, B2, C2, D2, E2, Src, 1); - auto Final = Round1To3(A3, B3, C3, D3, E3, Src, 0); + auto Final = Round1To3(A3, B3, C3, D3, E3, Src, 0); - auto Dest3 = _VInsGPR(16, 4, 3, Dest, std::get<0>(Final)); + auto Dest3 = _VInsGPR(16, 4, 3, Dest, std::get<0>(Final)); auto Dest2 = _VInsGPR(16, 4, 2, Dest3, std::get<1>(Final)); auto Dest1 = _VInsGPR(16, 4, 1, Dest2, std::get<2>(Final)); auto Dest0 = _VInsGPR(16, 4, 0, Dest1, std::get<3>(Final)); @@ -174,17 +177,17 @@ void OpDispatchBuilder::SHA1RNDS4Op(OpcodeArgs) { } void OpDispatchBuilder::SHA256MSG1Op(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result{}; + OrderedNode* Result {}; if (CTX->HostFeatures.SupportsSHA) { Result = _VSha256U0(Dest, Src); - } - else { + } else { const auto Sigma0 = [this](OrderedNode* W) -> OrderedNode* { - return _Xor(OpSize::i32Bit, _Xor(OpSize::i32Bit, _Ror(OpSize::i32Bit, W, _Constant(32, 7)), _Ror(OpSize::i32Bit, W, _Constant(32, 18))), _Lshr(OpSize::i32Bit, W, _Constant(32, 3))); + return _Xor(OpSize::i32Bit, _Xor(OpSize::i32Bit, _Ror(OpSize::i32Bit, W, _Constant(32, 7)), _Ror(OpSize::i32Bit, W, _Constant(32, 18))), + _Lshr(OpSize::i32Bit, W, _Constant(32, 3))); }; auto W4 = _VExtractToGPR(16, 4, Src, 0); @@ -209,11 +212,12 @@ void OpDispatchBuilder::SHA256MSG1Op(OpcodeArgs) { void OpDispatchBuilder::SHA256MSG2Op(OpcodeArgs) { const auto Sigma1 = [this](OrderedNode* W) -> OrderedNode* { - return _Xor(OpSize::i32Bit, _Xor(OpSize::i32Bit, _Ror(OpSize::i32Bit, W, _Constant(32, 17)), _Ror(OpSize::i32Bit, W, _Constant(32, 19))), _Lshr(OpSize::i32Bit, W, _Constant(32, 10))); + return _Xor(OpSize::i32Bit, _Xor(OpSize::i32Bit, _Ror(OpSize::i32Bit, W, _Constant(32, 17)), _Ror(OpSize::i32Bit, W, _Constant(32, 19))), + _Lshr(OpSize::i32Bit, W, _Constant(32, 10))); }; - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto W14 = _VExtractToGPR(16, 4, Src, 2); auto W15 = _VExtractToGPR(16, 4, Src, 3); @@ -230,36 +234,38 @@ void OpDispatchBuilder::SHA256MSG2Op(OpcodeArgs) { StoreResult(FPRClass, Op, D0, -1); } -OrderedNode *OpDispatchBuilder::BitwiseAtLeastTwo(OrderedNode *A, OrderedNode *B, OrderedNode *C) { - // Returns whether at least 2/3 of A/B/C is true. - // Expressed as (A & (B | C)) | (B & C) - // - // Equivalent to expression in SHA calculations: (A & B) ^ (A & C) ^ (B & C) - auto And = _And(OpSize::i32Bit, B, C); - auto Or = _Or(OpSize::i32Bit, B, C); - return _Or(OpSize::i32Bit, _And(OpSize::i32Bit, A, Or), And); +OrderedNode* OpDispatchBuilder::BitwiseAtLeastTwo(OrderedNode* A, OrderedNode* B, OrderedNode* C) { + // Returns whether at least 2/3 of A/B/C is true. + // Expressed as (A & (B | C)) | (B & C) + // + // Equivalent to expression in SHA calculations: (A & B) ^ (A & C) ^ (B & C) + auto And = _And(OpSize::i32Bit, B, C); + auto Or = _Or(OpSize::i32Bit, B, C); + return _Or(OpSize::i32Bit, _And(OpSize::i32Bit, A, Or), And); } void OpDispatchBuilder::SHA256RNDS2Op(OpcodeArgs) { - const auto Ch = [this](OrderedNode *E, OrderedNode *F, OrderedNode *G) -> OrderedNode* { + const auto Ch = [this](OrderedNode* E, OrderedNode* F, OrderedNode* G) -> OrderedNode* { return _Xor(OpSize::i32Bit, _And(OpSize::i32Bit, E, F), _Andn(OpSize::i32Bit, G, E)); }; - const auto Sigma0 = [this](OrderedNode *A) -> OrderedNode* { - return _XorShift(OpSize::i32Bit, _XorShift(OpSize::i32Bit, _Ror(OpSize::i32Bit, A, _Constant(32, 2)), A, ShiftType::ROR, 13), A, ShiftType::ROR, 22); + const auto Sigma0 = [this](OrderedNode* A) -> OrderedNode* { + return _XorShift(OpSize::i32Bit, _XorShift(OpSize::i32Bit, _Ror(OpSize::i32Bit, A, _Constant(32, 2)), A, ShiftType::ROR, 13), A, + ShiftType::ROR, 22); }; - const auto Sigma1 = [this](OrderedNode *E) -> OrderedNode* { - return _XorShift(OpSize::i32Bit, _XorShift(OpSize::i32Bit, _Ror(OpSize::i32Bit, E, _Constant(32, 6)), E, ShiftType::ROR, 11), E, ShiftType::ROR, 25); + const auto Sigma1 = [this](OrderedNode* E) -> OrderedNode* { + return _XorShift(OpSize::i32Bit, _XorShift(OpSize::i32Bit, _Ror(OpSize::i32Bit, E, _Constant(32, 6)), E, ShiftType::ROR, 11), E, + ShiftType::ROR, 25); }; - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); // Hardcoded to XMM0 auto XMM0 = LoadXMMRegister(0); auto E0 = _VExtractToGPR(16, 4, Src, 1); auto F0 = _VExtractToGPR(16, 4, Src, 0); auto G0 = _VExtractToGPR(16, 4, Dest, 1); - OrderedNode *Q0 = _Add(OpSize::i32Bit, Ch(E0, F0, G0), Sigma1(E0)); + OrderedNode* Q0 = _Add(OpSize::i32Bit, Ch(E0, F0, G0), Sigma1(E0)); auto WK0 = _VExtractToGPR(16, 4, XMM0, 0); Q0 = _Add(OpSize::i32Bit, Q0, WK0); @@ -275,7 +281,7 @@ void OpDispatchBuilder::SHA256RNDS2Op(OpcodeArgs) { auto D0 = _VExtractToGPR(16, 4, Dest, 2); auto E1 = _Add(OpSize::i32Bit, Q0, D0); - OrderedNode * Q1 = _Add(OpSize::i32Bit, Ch(E1, E0, F0), Sigma1(E1)); + OrderedNode* Q1 = _Add(OpSize::i32Bit, Ch(E1, E0, F0), Sigma1(E1)); auto WK1 = _VExtractToGPR(16, 4, XMM0, 1); Q1 = _Add(OpSize::i32Bit, Q1, WK1); @@ -299,16 +305,16 @@ void OpDispatchBuilder::SHA256RNDS2Op(OpcodeArgs) { } void OpDispatchBuilder::AESImcOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = _VAESImc(Src); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = _VAESImc(Src); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::AESEncOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(16, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESEnc(16, Dest, Src, ZeroRegister); + OrderedNode* Result = _VAESEnc(16, Dest, Src, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } @@ -319,19 +325,19 @@ void OpDispatchBuilder::VAESEncOp(OpcodeArgs) { // TODO: Handle 256-bit VAESENC. LOGMAN_THROW_A_FMT(Is128Bit, "256-bit VAESENC unimplemented"); - OrderedNode *State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESEnc(DstSize, State, Key, ZeroRegister); + OrderedNode* Result = _VAESEnc(DstSize, State, Key, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::AESEncLastOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(16, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESEncLast(16, Dest, Src, ZeroRegister); + OrderedNode* Result = _VAESEncLast(16, Dest, Src, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } @@ -342,19 +348,19 @@ void OpDispatchBuilder::VAESEncLastOp(OpcodeArgs) { // TODO: Handle 256-bit VAESENCLAST. LOGMAN_THROW_A_FMT(Is128Bit, "256-bit VAESENCLAST unimplemented"); - OrderedNode *State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESEncLast(DstSize, State, Key, ZeroRegister); + OrderedNode* Result = _VAESEncLast(DstSize, State, Key, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::AESDecOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(16, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESDec(16, Dest, Src, ZeroRegister); + OrderedNode* Result = _VAESDec(16, Dest, Src, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } @@ -365,19 +371,19 @@ void OpDispatchBuilder::VAESDecOp(OpcodeArgs) { // TODO: Handle 256-bit VAESDEC. LOGMAN_THROW_A_FMT(Is128Bit, "256-bit VAESDEC unimplemented"); - OrderedNode *State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESDec(DstSize, State, Key, ZeroRegister); + OrderedNode* Result = _VAESDec(DstSize, State, Key, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::AESDecLastOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(16, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESDecLast(16, Dest, Src, ZeroRegister); + OrderedNode* Result = _VAESDecLast(16, Dest, Src, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } @@ -388,16 +394,16 @@ void OpDispatchBuilder::VAESDecLastOp(OpcodeArgs) { // TODO: Handle 256-bit VAESDECLAST. LOGMAN_THROW_A_FMT(Is128Bit, "256-bit VAESDECLAST unimplemented"); - OrderedNode *State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* State = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Key = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = _VAESDecLast(DstSize, State, Key, ZeroRegister); + OrderedNode* Result = _VAESDecLast(DstSize, State, Key, ZeroRegister); StoreResult(FPRClass, Op, Result, -1); } OrderedNode* OpDispatchBuilder::AESKeyGenAssistImpl(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t RCON = Op->Src[1].Data.Literal.Value; @@ -407,15 +413,15 @@ OrderedNode* OpDispatchBuilder::AESKeyGenAssistImpl(OpcodeArgs) { } void OpDispatchBuilder::AESKeyGenAssist(OpcodeArgs) { - OrderedNode *Result = AESKeyGenAssistImpl(Op); + OrderedNode* Result = AESKeyGenAssistImpl(Op); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::PCLMULQDQOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Selector needs to be literal here"); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); const auto Selector = static_cast(Op->Src[1].Data.Literal.Value); auto Res = _PCLMUL(16, Dest, Src, Selector); @@ -427,12 +433,12 @@ void OpDispatchBuilder::VPCLMULQDQOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); const auto Selector = static_cast(Op->Src[2].Data.Literal.Value); - OrderedNode *Res = _PCLMUL(DstSize, Src1, Src2, Selector); + OrderedNode* Res = _PCLMUL(DstSize, Src1, Src2, Selector); StoreResult(FPRClass, Op, Res, -1); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp index ba5bc2cae..faea27af3 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp @@ -19,23 +19,12 @@ $end_info$ namespace FEXCore::IR { constexpr std::array FlagOffsets = { - FEXCore::X86State::RFLAG_CF_RAW_LOC, - FEXCore::X86State::RFLAG_PF_RAW_LOC, - FEXCore::X86State::RFLAG_AF_RAW_LOC, - FEXCore::X86State::RFLAG_ZF_RAW_LOC, - FEXCore::X86State::RFLAG_SF_RAW_LOC, - FEXCore::X86State::RFLAG_TF_LOC, - FEXCore::X86State::RFLAG_IF_LOC, - FEXCore::X86State::RFLAG_DF_RAW_LOC, - FEXCore::X86State::RFLAG_OF_RAW_LOC, - FEXCore::X86State::RFLAG_IOPL_LOC, - FEXCore::X86State::RFLAG_NT_LOC, - FEXCore::X86State::RFLAG_RF_LOC, - FEXCore::X86State::RFLAG_VM_LOC, - FEXCore::X86State::RFLAG_AC_LOC, - FEXCore::X86State::RFLAG_VIF_LOC, - FEXCore::X86State::RFLAG_VIP_LOC, - FEXCore::X86State::RFLAG_ID_LOC, + FEXCore::X86State::RFLAG_CF_RAW_LOC, FEXCore::X86State::RFLAG_PF_RAW_LOC, FEXCore::X86State::RFLAG_AF_RAW_LOC, + FEXCore::X86State::RFLAG_ZF_RAW_LOC, FEXCore::X86State::RFLAG_SF_RAW_LOC, FEXCore::X86State::RFLAG_TF_LOC, + FEXCore::X86State::RFLAG_IF_LOC, FEXCore::X86State::RFLAG_DF_RAW_LOC, FEXCore::X86State::RFLAG_OF_RAW_LOC, + FEXCore::X86State::RFLAG_IOPL_LOC, FEXCore::X86State::RFLAG_NT_LOC, FEXCore::X86State::RFLAG_RF_LOC, + FEXCore::X86State::RFLAG_VM_LOC, FEXCore::X86State::RFLAG_AC_LOC, FEXCore::X86State::RFLAG_VIF_LOC, + FEXCore::X86State::RFLAG_VIP_LOC, FEXCore::X86State::RFLAG_ID_LOC, }; void OpDispatchBuilder::ZeroPF_AF() { @@ -44,7 +33,7 @@ void OpDispatchBuilder::ZeroPF_AF() { SetAF(0); } -void OpDispatchBuilder::SetPackedRFLAG(bool Lower8, OrderedNode *Src) { +void OpDispatchBuilder::SetPackedRFLAG(bool Lower8, OrderedNode* Src) { size_t NumFlags = FlagOffsets.size(); if (Lower8) { // Calculate flags early. @@ -52,8 +41,7 @@ void OpDispatchBuilder::SetPackedRFLAG(bool Lower8, OrderedNode *Src) { // This is only a partial overwrite of flags since OF isn't stored here. CalculateDeferredFlags(); NumFlags = 5; - } - else { + } else { // We are overwriting all RFLAGS. Invalidate the deferred flag state. InvalidateDeferredFlags(); } @@ -73,7 +61,7 @@ void OpDispatchBuilder::SetPackedRFLAG(bool Lower8, OrderedNode *Src) { SetRFLAG(Src, FEXCore::X86State::RFLAG_AF_RAW_LOC); } else if (FlagOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { // PF is stored parity flipped - OrderedNode *Tmp = _Bfe(OpSize::i32Bit, 1, FlagOffset, Src); + OrderedNode* Tmp = _Bfe(OpSize::i32Bit, 1, FlagOffset, Src); Tmp = _Xor(OpSize::i32Bit, Tmp, _Constant(1)); SetRFLAG(Tmp, FlagOffset); } else { @@ -82,15 +70,14 @@ void OpDispatchBuilder::SetPackedRFLAG(bool Lower8, OrderedNode *Src) { } } -OrderedNode *OpDispatchBuilder::GetPackedRFLAG(uint32_t FlagsMask) { +OrderedNode* OpDispatchBuilder::GetPackedRFLAG(uint32_t FlagsMask) { // Calculate flags early. CalculateDeferredFlags(); - OrderedNode *Original = _Constant(0); + OrderedNode* Original = _Constant(0); // SF/ZF and N/Z are together on both arm64 and x86_64, so we special case that. - bool GetNZ = (FlagsMask & (1 << FEXCore::X86State::RFLAG_SF_RAW_LOC)) && - (FlagsMask & (1 << FEXCore::X86State::RFLAG_ZF_RAW_LOC)); + bool GetNZ = (FlagsMask & (1 << FEXCore::X86State::RFLAG_SF_RAW_LOC)) && (FlagsMask & (1 << FEXCore::X86State::RFLAG_ZF_RAW_LOC)); // Handle CF first, since it's at bit 0 and hence doesn't need shift or OR. if (FlagsMask & (1 << FEXCore::X86State::RFLAG_CF_RAW_LOC)) { @@ -104,21 +91,20 @@ OrderedNode *OpDispatchBuilder::GetPackedRFLAG(uint32_t FlagsMask) { continue; } - if ((GetNZ && (FlagOffset == FEXCore::X86State::RFLAG_SF_RAW_LOC || - FlagOffset == FEXCore::X86State::RFLAG_ZF_RAW_LOC)) || - FlagOffset == FEXCore::X86State::RFLAG_CF_RAW_LOC || - FlagOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { + if ((GetNZ && (FlagOffset == FEXCore::X86State::RFLAG_SF_RAW_LOC || FlagOffset == FEXCore::X86State::RFLAG_ZF_RAW_LOC)) || + FlagOffset == FEXCore::X86State::RFLAG_CF_RAW_LOC || FlagOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { // Already handled continue; } // Note that the Bfi only considers the bottom bit of the flag, the rest of // the byte is allowed to be garbage. - OrderedNode *Flag; - if (FlagOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) + OrderedNode* Flag; + if (FlagOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) { Flag = LoadAF(); - else + } else { Flag = GetRFLAG(FlagOffset); + } Original = _Orlshl(OpSize::i64Bit, Original, Flag, FlagOffset); } @@ -146,16 +132,17 @@ OrderedNode *OpDispatchBuilder::GetPackedRFLAG(uint32_t FlagsMask) { } // The constant is OR'ed in at the end, to avoid a pointless or xzr, #2. - if ((1U << X86State::RFLAG_RESERVED_LOC) & FlagsMask) + if ((1U << X86State::RFLAG_RESERVED_LOC) & FlagsMask) { Original = _Or(OpSize::i64Bit, Original, _Constant(2)); + } return Original; } -void OpDispatchBuilder::CalculateOF(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool Sub) { +void OpDispatchBuilder::CalculateOF(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, OrderedNode* Src2, bool Sub) { auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit; uint64_t SignBit = (SrcSize * 8) - 1; - OrderedNode *Anded = nullptr; + OrderedNode* Anded = nullptr; // For add, OF is set iff the sources have the same sign but the destination // sign differs. If we know a source sign, we can simplify the expression: if @@ -169,24 +156,26 @@ void OpDispatchBuilder::CalculateOF(uint8_t SrcSize, OrderedNode *Res, OrderedNo if (IsValueConstant(WrapNode(Src2), &Const)) { bool Negative = (Const & (1ull << SignBit)) != 0; - if (Negative ^ Sub) + if (Negative ^ Sub) { Anded = _Andn(OpSize, Src1, Res); - else + } else { Anded = _Andn(OpSize, Res, Src1); + } } else { auto XorOp1 = _Xor(OpSize, Src1, Src2); auto XorOp2 = _Xor(OpSize, Res, Src1); - if (Sub) + if (Sub) { Anded = _And(OpSize, XorOp2, XorOp1); - else + } else { Anded = _Andn(OpSize, XorOp2, XorOp1); + } } SetRFLAG(Anded, SrcSize * 8 - 1, true); } -OrderedNode *OpDispatchBuilder::LoadPFRaw(bool Invert) { +OrderedNode* OpDispatchBuilder::LoadPFRaw(bool Invert) { // Read the stored byte. This is the original result (up to 64-bits), it needs // parity calculated. auto Result = GetRFLAG(FEXCore::X86State::RFLAG_PF_RAW_LOC); @@ -195,15 +184,16 @@ OrderedNode *OpDispatchBuilder::LoadPFRaw(bool Invert) { Result = _XorShift(OpSize::i32Bit, Result, Result, ShiftType::LSR, 4); Result = _XorShift(OpSize::i32Bit, Result, Result, ShiftType::LSR, 2); - if (Invert) + if (Invert) { Result = _XornShift(OpSize::i32Bit, Result, Result, ShiftType::LSR, 1); - else + } else { Result = _XorShift(OpSize::i32Bit, Result, Result, ShiftType::LSR, 1); + } return Result; } -OrderedNode *OpDispatchBuilder::LoadAF() { +OrderedNode* OpDispatchBuilder::LoadAF() { // Read the stored value. This is the XOR of the arguments. auto AFWord = GetRFLAG(FEXCore::X86State::RFLAG_AF_RAW_LOC); @@ -224,11 +214,11 @@ void OpDispatchBuilder::FixupAF() { auto PFRaw = GetRFLAG(FEXCore::X86State::RFLAG_PF_RAW_LOC); auto AFRaw = GetRFLAG(FEXCore::X86State::RFLAG_AF_RAW_LOC); - OrderedNode *XorRes = _Xor(OpSize::i32Bit, AFRaw, PFRaw); + OrderedNode* XorRes = _Xor(OpSize::i32Bit, AFRaw, PFRaw); SetRFLAG(XorRes); } -void OpDispatchBuilder::SetAFAndFixup(OrderedNode *AF) { +void OpDispatchBuilder::SetAFAndFixup(OrderedNode* AF) { // We have a value of AF, we shift into AF[4]. We need to fixup AF[4] so that // we get the right value when we XOR in PF[4] later. The easiest solution is // to XOR by PF[4], since: @@ -237,16 +227,16 @@ void OpDispatchBuilder::SetAFAndFixup(OrderedNode *AF) { auto PFRaw = GetRFLAG(FEXCore::X86State::RFLAG_PF_RAW_LOC); - OrderedNode *XorRes = _XorShift(OpSize::i32Bit, PFRaw, AF, ShiftType::LSL, 4); + OrderedNode* XorRes = _XorShift(OpSize::i32Bit, PFRaw, AF, ShiftType::LSL, 4); SetRFLAG(XorRes); } -void OpDispatchBuilder::CalculatePF(OrderedNode *Res) { +void OpDispatchBuilder::CalculatePF(OrderedNode* Res) { // Calculation is entirely deferred until load, just store the 8-bit result. SetRFLAG(Res); } -void OpDispatchBuilder::CalculateAF(OrderedNode *Src1, OrderedNode *Src2) { +void OpDispatchBuilder::CalculateAF(OrderedNode* Src1, OrderedNode* Src2) { // We only care about bit 4 in the subsequent XOR. If we'll XOR with 0, // there's no sense XOR'ing at all. If we'll XOR with 1, that's just // inverting. @@ -264,15 +254,16 @@ void OpDispatchBuilder::CalculateAF(OrderedNode *Src1, OrderedNode *Src2) { // We store the XOR of the arguments. At read time, we XOR with the // appropriate bit of the result (available as the PF flag) and extract the // appropriate bit. - OrderedNode *XorRes = _Xor(OpSize::i32Bit, Src1, Src2); + OrderedNode* XorRes = _Xor(OpSize::i32Bit, Src1, Src2); SetRFLAG(XorRes); } void OpDispatchBuilder::CalculateDeferredFlags(uint32_t FlagsToCalculateMask) { if (CurrentDeferredFlags.Type == FlagsGenerationType::TYPE_NONE) { // Nothing to do - if (NZCVDirty && CachedNZCV) + if (NZCVDirty && CachedNZCV) { _StoreNZCV(CachedNZCV); + } CachedNZCV = nullptr; NZCVDirty = false; @@ -280,113 +271,68 @@ void OpDispatchBuilder::CalculateDeferredFlags(uint32_t FlagsToCalculateMask) { } switch (CurrentDeferredFlags.Type) { - case FlagsGenerationType::TYPE_SUB: - CalculateFlags_SUB( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Sources.TwoSrcImmediate.Src1, - CurrentDeferredFlags.Sources.TwoSrcImmediate.Src2, - CurrentDeferredFlags.Sources.TwoSrcImmediate.UpdateCF); - break; - case FlagsGenerationType::TYPE_MUL: - CalculateFlags_MUL( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSource.Src1); - break; - case FlagsGenerationType::TYPE_UMUL: - CalculateFlags_UMUL(CurrentDeferredFlags.Res); - break; - case FlagsGenerationType::TYPE_LOGICAL: - CalculateFlags_Logical( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.TwoSource.Src1, - CurrentDeferredFlags.Sources.TwoSource.Src2); - break; - case FlagsGenerationType::TYPE_LSHLI: - CalculateFlags_ShiftLeftImmediate( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, - CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); - break; - case FlagsGenerationType::TYPE_LSHRI: - CalculateFlags_ShiftRightImmediate( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, - CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); - break; - case FlagsGenerationType::TYPE_LSHRDI: - CalculateFlags_ShiftRightDoubleImmediate( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, - CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); - break; - case FlagsGenerationType::TYPE_ASHRI: - CalculateFlags_SignShiftRightImmediate( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, - CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); - break; - case FlagsGenerationType::TYPE_BEXTR: - CalculateFlags_BEXTR(CurrentDeferredFlags.Res); - break; - case FlagsGenerationType::TYPE_BLSI: - CalculateFlags_BLSI( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res); - break; - case FlagsGenerationType::TYPE_BLSMSK: - CalculateFlags_BLSMSK( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSource.Src1); - break; - case FlagsGenerationType::TYPE_BLSR: - CalculateFlags_BLSR( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSource.Src1); - break; - case FlagsGenerationType::TYPE_POPCOUNT: - CalculateFlags_POPCOUNT(CurrentDeferredFlags.Res); - break; - case FlagsGenerationType::TYPE_BZHI: - CalculateFlags_BZHI( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res, - CurrentDeferredFlags.Sources.OneSource.Src1); - break; - case FlagsGenerationType::TYPE_ZCNT: - CalculateFlags_ZCNT( - CurrentDeferredFlags.SrcSize, - CurrentDeferredFlags.Res); - break; - case FlagsGenerationType::TYPE_RDRAND: - CalculateFlags_RDRAND(CurrentDeferredFlags.Res); - break; - case FlagsGenerationType::TYPE_NONE: - default: ERROR_AND_DIE_FMT("Unhandled flags type {}", CurrentDeferredFlags.Type); + case FlagsGenerationType::TYPE_SUB: + CalculateFlags_SUB(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Sources.TwoSrcImmediate.Src1, + CurrentDeferredFlags.Sources.TwoSrcImmediate.Src2, CurrentDeferredFlags.Sources.TwoSrcImmediate.UpdateCF); + break; + case FlagsGenerationType::TYPE_MUL: + CalculateFlags_MUL(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, CurrentDeferredFlags.Sources.OneSource.Src1); + break; + case FlagsGenerationType::TYPE_UMUL: CalculateFlags_UMUL(CurrentDeferredFlags.Res); break; + case FlagsGenerationType::TYPE_LOGICAL: + CalculateFlags_Logical(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, CurrentDeferredFlags.Sources.TwoSource.Src1, + CurrentDeferredFlags.Sources.TwoSource.Src2); + break; + case FlagsGenerationType::TYPE_LSHLI: + CalculateFlags_ShiftLeftImmediate(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, + CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); + break; + case FlagsGenerationType::TYPE_LSHRI: + CalculateFlags_ShiftRightImmediate(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, + CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); + break; + case FlagsGenerationType::TYPE_LSHRDI: + CalculateFlags_ShiftRightDoubleImmediate(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, + CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); + break; + case FlagsGenerationType::TYPE_ASHRI: + CalculateFlags_SignShiftRightImmediate(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, + CurrentDeferredFlags.Sources.OneSrcImmediate.Src1, CurrentDeferredFlags.Sources.OneSrcImmediate.Imm); + break; + case FlagsGenerationType::TYPE_BEXTR: CalculateFlags_BEXTR(CurrentDeferredFlags.Res); break; + case FlagsGenerationType::TYPE_BLSI: CalculateFlags_BLSI(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res); break; + case FlagsGenerationType::TYPE_BLSMSK: + CalculateFlags_BLSMSK(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, CurrentDeferredFlags.Sources.OneSource.Src1); + break; + case FlagsGenerationType::TYPE_BLSR: + CalculateFlags_BLSR(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, CurrentDeferredFlags.Sources.OneSource.Src1); + break; + case FlagsGenerationType::TYPE_POPCOUNT: CalculateFlags_POPCOUNT(CurrentDeferredFlags.Res); break; + case FlagsGenerationType::TYPE_BZHI: + CalculateFlags_BZHI(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res, CurrentDeferredFlags.Sources.OneSource.Src1); + break; + case FlagsGenerationType::TYPE_ZCNT: CalculateFlags_ZCNT(CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res); break; + case FlagsGenerationType::TYPE_RDRAND: CalculateFlags_RDRAND(CurrentDeferredFlags.Res); break; + case FlagsGenerationType::TYPE_NONE: + default: ERROR_AND_DIE_FMT("Unhandled flags type {}", CurrentDeferredFlags.Type); } // Done calculating CurrentDeferredFlags.Type = FlagsGenerationType::TYPE_NONE; - if (NZCVDirty && CachedNZCV) + if (NZCVDirty && CachedNZCV) { _StoreNZCV(CachedNZCV); + } CachedNZCV = nullptr; NZCVDirty = false; } -OrderedNode *OpDispatchBuilder::CalculateFlags_ADC(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::CalculateFlags_ADC(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2) { auto Zero = _Constant(0); auto One = _Constant(1); auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit; - OrderedNode *Res; + OrderedNode* Res; CalculateAF(Src1, Src2); @@ -400,7 +346,7 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_ADC(uint8_t SrcSize, OrderedNode auto SelectOpLT = _Select(FEXCore::IR::COND_ULT, Res, Src2, One, Zero); auto SelectOpLE = _Select(FEXCore::IR::COND_ULE, Res, Src2, One, Zero); - auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT); + auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT); SetNZ_ZeroCV(SrcSize, Res); SetRFLAG(SelectCF); @@ -411,14 +357,14 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_ADC(uint8_t SrcSize, OrderedNode return Res; } -OrderedNode *OpDispatchBuilder::CalculateFlags_SBB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::CalculateFlags_SBB(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2) { auto Zero = _Constant(0); auto One = _Constant(1); auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit; CalculateAF(Src1, Src2); - OrderedNode *Res; + OrderedNode* Res; if (SrcSize >= 4) { // Rectify input carry CarryInvert(); @@ -435,7 +381,7 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_SBB(uint8_t SrcSize, OrderedNode auto SelectOpLT = _Select(FEXCore::IR::COND_UGT, Res, Src1, One, Zero); auto SelectOpLE = _Select(FEXCore::IR::COND_UGE, Res, Src1, One, Zero); - auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT); + auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT); SetNZ_ZeroCV(SrcSize, Res); SetRFLAG(SelectCF); @@ -446,7 +392,7 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_SBB(uint8_t SrcSize, OrderedNode return Res; } -OrderedNode *OpDispatchBuilder::CalculateFlags_SUB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF) { +OrderedNode* OpDispatchBuilder::CalculateFlags_SUB(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2, bool UpdateCF) { // Stash CF before stomping over it auto OldCF = UpdateCF ? nullptr : GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); @@ -454,7 +400,7 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_SUB(uint8_t SrcSize, OrderedNode CalculateAF(Src1, Src2); - OrderedNode *Res; + OrderedNode* Res; if (SrcSize >= 4) { Res = _SubWithFlags(IR::SizeToOpSize(SrcSize), Src1, Src2); } else { @@ -466,15 +412,16 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_SUB(uint8_t SrcSize, OrderedNode // If we're updating CF, we need to invert it for correctness. If we're not // updating CF, we need to restore the CF since we stomped over it. - if (UpdateCF) + if (UpdateCF) { CarryInvert(); - else + } else { SetRFLAG(OldCF); + } return Res; } -OrderedNode *OpDispatchBuilder::CalculateFlags_ADD(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF) { +OrderedNode* OpDispatchBuilder::CalculateFlags_ADD(uint8_t SrcSize, OrderedNode* Src1, OrderedNode* Src2, bool UpdateCF) { // Stash CF before stomping over it auto OldCF = UpdateCF ? nullptr : GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC); @@ -482,7 +429,7 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_ADD(uint8_t SrcSize, OrderedNode CalculateAF(Src1, Src2); - OrderedNode *Res; + OrderedNode* Res; if (SrcSize >= 4) { Res = _AddWithFlags(IR::SizeToOpSize(SrcSize), Src1, Src2); } else { @@ -493,13 +440,14 @@ OrderedNode *OpDispatchBuilder::CalculateFlags_ADD(uint8_t SrcSize, OrderedNode CalculatePF(Res); // We stomped over CF while calculation flags, restore it. - if (!UpdateCF) + if (!UpdateCF) { SetRFLAG(OldCF); + } return Res; } -void OpDispatchBuilder::CalculateFlags_MUL(uint8_t SrcSize, OrderedNode *Res, OrderedNode *High) { +void OpDispatchBuilder::CalculateFlags_MUL(uint8_t SrcSize, OrderedNode* Res, OrderedNode* High) { HandleNZCVWrite(); // PF/AF/ZF/SF @@ -519,11 +467,11 @@ void OpDispatchBuilder::CalculateFlags_MUL(uint8_t SrcSize, OrderedNode *Res, Or // If High = SignBit, then sets to nZcv. Else sets to nzCV. Since SF/ZF // undefined, this does what we need. auto Zero = _Constant(0); - _CondAddNZCV(OpSize::i64Bit, Zero, Zero, CondClassType{COND_EQ}, 0x3 /* nzCV */); + _CondAddNZCV(OpSize::i64Bit, Zero, Zero, CondClassType {COND_EQ}, 0x3 /* nzCV */); } } -void OpDispatchBuilder::CalculateFlags_UMUL(OrderedNode *High) { +void OpDispatchBuilder::CalculateFlags_UMUL(OrderedNode* High) { HandleNZCVWrite(); auto Zero = _Constant(0); @@ -544,11 +492,11 @@ void OpDispatchBuilder::CalculateFlags_UMUL(OrderedNode *High) { // If High = 0, then sets to nZcv. Else sets to nzCV. Since SF/ZF undefined, // this does what we need. - _CondAddNZCV(Size, Zero, Zero, CondClassType{COND_EQ}, 0x3 /* nzCV */); + _CondAddNZCV(Size, Zero, Zero, CondClassType {COND_EQ}, 0x3 /* nzCV */); } } -void OpDispatchBuilder::CalculateFlags_Logical(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2) { +void OpDispatchBuilder::CalculateFlags_Logical(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, OrderedNode* Src2) { // AF // Undefined _InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC); @@ -559,9 +507,11 @@ void OpDispatchBuilder::CalculateFlags_Logical(uint8_t SrcSize, OrderedNode *Res SetNZ_ZeroCV(SrcSize, Res); } -void OpDispatchBuilder::CalculateFlags_ShiftLeftImmediate(uint8_t SrcSize, OrderedNode *UnmaskedRes, OrderedNode *Src1, uint64_t Shift) { +void OpDispatchBuilder::CalculateFlags_ShiftLeftImmediate(uint8_t SrcSize, OrderedNode* UnmaskedRes, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero - if (Shift == 0) return; + if (Shift == 0) { + return; + } auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit; @@ -593,16 +543,18 @@ void OpDispatchBuilder::CalculateFlags_ShiftLeftImmediate(uint8_t SrcSize, Order } } -void OpDispatchBuilder::CalculateFlags_SignShiftRightImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { +void OpDispatchBuilder::CalculateFlags_SignShiftRightImmediate(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero - if (Shift == 0) return; + if (Shift == 0) { + return; + } SetNZ_ZeroCV(SrcSize, Res); // CF { // Extract the last bit shifted in to CF - SetRFLAG(Src1, Shift-1, true); + SetRFLAG(Src1, Shift - 1, true); } CalculatePF(Res); @@ -617,7 +569,7 @@ void OpDispatchBuilder::CalculateFlags_SignShiftRightImmediate(uint8_t SrcSize, // already zeroed there's nothing to do here. } -void OpDispatchBuilder::CalculateFlags_ShiftRightImmediateCommon(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { +void OpDispatchBuilder::CalculateFlags_ShiftRightImmediateCommon(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // Set SF and PF. Clobbers OF, but OF only defined for Shift = 1 where it is // set below. SetNZ_ZeroCV(SrcSize, Res); @@ -625,7 +577,7 @@ void OpDispatchBuilder::CalculateFlags_ShiftRightImmediateCommon(uint8_t SrcSize // CF { // Extract the last bit shifted in to CF - SetRFLAG(Src1, Shift-1, true); + SetRFLAG(Src1, Shift - 1, true); } CalculatePF(Res); @@ -635,9 +587,11 @@ void OpDispatchBuilder::CalculateFlags_ShiftRightImmediateCommon(uint8_t SrcSize _InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC); } -void OpDispatchBuilder::CalculateFlags_ShiftRightImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { +void OpDispatchBuilder::CalculateFlags_ShiftRightImmediate(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero - if (Shift == 0) return; + if (Shift == 0) { + return; + } CalculateFlags_ShiftRightImmediateCommon(SrcSize, Res, Src1, Shift); @@ -651,9 +605,11 @@ void OpDispatchBuilder::CalculateFlags_ShiftRightImmediate(uint8_t SrcSize, Orde } } -void OpDispatchBuilder::CalculateFlags_ShiftRightDoubleImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift) { +void OpDispatchBuilder::CalculateFlags_ShiftRightDoubleImmediate(uint8_t SrcSize, OrderedNode* Res, OrderedNode* Src1, uint64_t Shift) { // No flags changed if shift is zero - if (Shift == 0) return; + if (Shift == 0) { + return; + } const auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit; CalculateFlags_ShiftRightImmediateCommon(SrcSize, Res, Src1, Shift); @@ -670,16 +626,15 @@ void OpDispatchBuilder::CalculateFlags_ShiftRightDoubleImmediate(uint8_t SrcSize } } -void OpDispatchBuilder::CalculateFlags_BEXTR(OrderedNode *Src) { +void OpDispatchBuilder::CalculateFlags_BEXTR(OrderedNode* Src) { // ZF is set properly. CF and OF are defined as being set to zero. SF, PF, and // AF are undefined. SetNZ_ZeroCV(GetOpSize(Src), Src); - _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | - (1UL << X86State::RFLAG_AF_RAW_LOC)); + _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); } -void OpDispatchBuilder::CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode *Result) { +void OpDispatchBuilder::CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode* Result) { // CF is cleared if Src is zero, otherwise it's set. However, Src is zero iff // Result is zero, so we can test the result instead. So, CF is just the // inverted ZF. @@ -691,14 +646,12 @@ void OpDispatchBuilder::CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode *Result SetRFLAG(CFOp); // PF/AF undefined - _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | - (1UL << X86State::RFLAG_AF_RAW_LOC)); + _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); } -void OpDispatchBuilder::CalculateFlags_BLSMSK(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src) { +void OpDispatchBuilder::CalculateFlags_BLSMSK(uint8_t SrcSize, OrderedNode* Result, OrderedNode* Src) { // PF/AF undefined - _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | - (1UL << X86State::RFLAG_AF_RAW_LOC)); + _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); // CF set according to the Src auto Zero = _Constant(0); @@ -711,7 +664,7 @@ void OpDispatchBuilder::CalculateFlags_BLSMSK(uint8_t SrcSize, OrderedNode *Resu SetRFLAG(CFOp); } -void OpDispatchBuilder::CalculateFlags_BLSR(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src) { +void OpDispatchBuilder::CalculateFlags_BLSR(uint8_t SrcSize, OrderedNode* Result, OrderedNode* Src) { auto Zero = _Constant(0); auto One = _Constant(1); auto CFOp = _Select(IR::COND_EQ, Src, Zero, One, Zero); @@ -720,11 +673,10 @@ void OpDispatchBuilder::CalculateFlags_BLSR(uint8_t SrcSize, OrderedNode *Result SetRFLAG(CFOp); // PF/AF undefined - _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | - (1UL << X86State::RFLAG_AF_RAW_LOC)); + _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); } -void OpDispatchBuilder::CalculateFlags_POPCOUNT(OrderedNode *Result) { +void OpDispatchBuilder::CalculateFlags_POPCOUNT(OrderedNode* Result) { // We need to set ZF while clearing the rest of NZCV. The result of a popcount // is in the range [0, 63]. In particular, it is always positive. So a // combined NZ test will correctly zero SF/CF/OF while setting ZF. @@ -732,16 +684,15 @@ void OpDispatchBuilder::CalculateFlags_POPCOUNT(OrderedNode *Result) { ZeroPF_AF(); } -void OpDispatchBuilder::CalculateFlags_BZHI(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src) { +void OpDispatchBuilder::CalculateFlags_BZHI(uint8_t SrcSize, OrderedNode* Result, OrderedNode* Src) { // PF/AF undefined - _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | - (1UL << X86State::RFLAG_AF_RAW_LOC)); + _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); SetNZ_ZeroCV(SrcSize, Result); SetRFLAG(Src); } -void OpDispatchBuilder::CalculateFlags_ZCNT(uint8_t SrcSize, OrderedNode *Result) { +void OpDispatchBuilder::CalculateFlags_ZCNT(uint8_t SrcSize, OrderedNode* Result) { // OF, SF, AF, PF all undefined // Test ZF of result, SF is undefined so this is ok. SetNZ_ZeroCV(SrcSize, Result); @@ -753,7 +704,7 @@ void OpDispatchBuilder::CalculateFlags_ZCNT(uint8_t SrcSize, OrderedNode *Result SetRFLAG(Result, CarryBit); } -void OpDispatchBuilder::CalculateFlags_RDRAND(OrderedNode *Src) { +void OpDispatchBuilder::CalculateFlags_RDRAND(OrderedNode* Src) { // OF, SF, ZF, AF, PF all zero ZeroNZCV(); ZeroPF_AF(); @@ -762,4 +713,4 @@ void OpDispatchBuilder::CalculateFlags_RDRAND(OrderedNode *Src) { SetRFLAG(Src); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 1a333923e..6b469d3ce 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -24,28 +24,25 @@ namespace FEXCore::IR { #define OpcodeArgs [[maybe_unused]] FEXCore::X86Tables::DecodedOp Op void OpDispatchBuilder::MOVVectorAlignedOp(OpcodeArgs) { - if (Op->Dest.IsGPR() && Op->Src[0].IsGPR() && - Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { + if (Op->Dest.IsGPR() && Op->Src[0].IsGPR() && Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { // Nop return; } - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); StoreResult(FPRClass, Op, Src, -1); } void OpDispatchBuilder::MOVVectorUnalignedOp(OpcodeArgs) { - if (Op->Dest.IsGPR() && Op->Src[0].IsGPR() && - Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { + if (Op->Dest.IsGPR() && Op->Src[0].IsGPR() && Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { // Nop return; } - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); StoreResult(FPRClass, Op, Src, 1); } void OpDispatchBuilder::MOVVectorNTOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, - {.Align = 1, .AccessType = MemoryAccessType::STREAM}); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1, .AccessType = MemoryAccessType::STREAM}); StoreResult(FPRClass, Op, Src, 1, MemoryAccessType::STREAM); } @@ -53,7 +50,7 @@ void OpDispatchBuilder::VMOVAPS_VMOVAPDOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is128Bit = SrcSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); if (Is128Bit && Op->Dest.IsGPR()) { Src = _VMov(16, Src); @@ -65,7 +62,7 @@ void OpDispatchBuilder::VMOVUPS_VMOVUPDOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is128Bit = SrcSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); if (Is128Bit && Op->Dest.IsGPR()) { Src = _VMov(16, Src); @@ -77,39 +74,37 @@ void OpDispatchBuilder::MOVHPDOp(OpcodeArgs) { if (Op->Dest.IsGPR()) { if (Op->Src[0].IsGPR()) { // MOVLHPS between two vector registers. - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, 16, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, 16, Op->Flags); auto Result = _VInsElement(16, 8, 1, 0, Dest, Src); StoreResult(FPRClass, Op, Result, -1); - } - else { + } else { // If the destination is a GPR then the source is memory // xmm1[127:64] = src - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.LoadData = false}); - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, 16, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.LoadData = false}); + OrderedNode* Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, 16, Op->Flags); auto Result = _VLoadVectorElement(16, 8, Dest, 1, Src); StoreResult(FPRClass, Op, Result, -1); } - } - else { + } else { // In this case memory is the destination and the high bits of the XMM are source // Mem64 = xmm1[127:64] - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, 8, Op->Flags, {.LoadData = false}); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, 8, Op->Flags, {.LoadData = false}); _VStoreVectorElement(16, 8, Src, 1, Dest); } } void OpDispatchBuilder::VMOVHPOp(OpcodeArgs) { if (Op->Dest.IsGPR()) { - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags, {.Align = 8}); - OrderedNode *Result = _VInsElement(16, 8, 1, 0, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags, {.Align = 8}); + OrderedNode* Result = _VInsElement(16, 8, 1, 0, Src1, Src2); StoreResult(FPRClass, Op, Result, -1); } else { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); - OrderedNode *Result = _VInsElement(16, 8, 0, 1, Src, Src); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); + OrderedNode* Result = _VInsElement(16, 8, 0, 1, Src, Src); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, 8, 8); } } @@ -118,69 +113,65 @@ void OpDispatchBuilder::MOVLPOp(OpcodeArgs) { if (Op->Dest.IsGPR()) { // xmm, xmm is movhlps special case if (Op->Src[0].IsGPR()) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, {.Align = 16}); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, {.Align = 16}); auto Result = _VInsElement(16, 8, 0, 1, Dest, Src); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, 16, 16); - } - else { + } else { auto DstSize = GetDstSize(Op); - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 8, .LoadData = false}); - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags); + OrderedNode* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 8, .LoadData = false}); + OrderedNode* Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags); auto Result = _VLoadVectorElement(16, 8, Dest, 0, Src); StoreResult(FPRClass, Op, Result, -1); } - } - else { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 8}); + } else { + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 8}); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Src, 8, 8); } } void OpDispatchBuilder::VMOVLPOp(OpcodeArgs) { if (Op->Dest.IsGPR()) { - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags, {.Align = 8}); - OrderedNode *Result = _VInsElement(16, 8, 0, 0, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 16}); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags, {.Align = 8}); + OrderedNode* Result = _VInsElement(16, 8, 0, 0, Src1, Src2); StoreResult(FPRClass, Op, Result, -1); } else { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 8}); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 8}); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Src, 8, 8); } } void OpDispatchBuilder::VMOVSHDUPOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = _VTrn2(SrcSize, 4, Src, Src); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = _VTrn2(SrcSize, 4, Src, Src); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VMOVSLDUPOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = _VTrn(SrcSize, 4, Src, Src); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = _VTrn(SrcSize, 4, Src, Src); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::MOVScalarOpImpl(OpcodeArgs, size_t ElementSize) { if (Op->Dest.IsGPR() && Op->Src[0].IsGPR()) { // MOVSS/SD xmm1, xmm2 - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto Result = _VInsElement(16, ElementSize, 0, 0, Dest, Src); StoreResult(FPRClass, Op, Result, -1); - } - else if (Op->Dest.IsGPR()) { + } else if (Op->Dest.IsGPR()) { // MOVSS/SD xmm1, mem32/mem64 // xmm1[127:0] <- zext(mem32/mem64) - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], ElementSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], ElementSize, Op->Flags); StoreResult(FPRClass, Op, Src, -1); - } - else { + } else { // MOVSS/SD mem32/mem64, xmm1 - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Src, ElementSize, -1); } } @@ -196,17 +187,17 @@ void OpDispatchBuilder::MOVSDOp(OpcodeArgs) { void OpDispatchBuilder::VMOVScalarOpImpl(OpcodeArgs, size_t ElementSize) { if (Op->Dest.IsGPR() && Op->Src[0].IsGPR() && Op->Src[1].IsGPR()) { // VMOVSS/SD xmm1, xmm2, xmm3 - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = _VInsElement(16, ElementSize, 0, 0, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = _VInsElement(16, ElementSize, 0, 0, Src1, Src2); StoreResult(FPRClass, Op, Result, -1); } else if (Op->Dest.IsGPR()) { // VMOVSS/SD xmm1, mem32/mem64 - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], ElementSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], ElementSize, Op->Flags); StoreResult(FPRClass, Op, Src, -1); } else { // VMOVSS/SD mem32/mem64, xmm1 - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Src, ElementSize, -1); } } @@ -221,449 +212,286 @@ void OpDispatchBuilder::VMOVSSOp(OpcodeArgs) { void OpDispatchBuilder::VectorALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { const auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); DeriveOp(ALUOp, IROp, _VAdd(Size, ElementSize, Dest, Src)); StoreResult(FPRClass, Op, ALUOp, -1); } -template +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs) { VectorALUOpImpl(Op, IROp, ElementSize); } -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUOp(OpcodeArgs); void OpDispatchBuilder::AVXVectorALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { const auto Size = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); DeriveOp(ALUOp, IROp, _VAdd(Size, ElementSize, Src1, Src2)); StoreResult(FPRClass, Op, ALUOp, -1); } -template +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs) { AVXVectorALUOpImpl(Op, IROp, ElementSize); } -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorALUOp(OpcodeArgs); void OpDispatchBuilder::VectorALUROpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { const auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); DeriveOp(ALUOp, IROp, _VAdd(Size, ElementSize, Src, Dest)); StoreResult(FPRClass, Op, ALUOp, -1); } -template +template void OpDispatchBuilder::VectorALUROp(OpcodeArgs) { VectorALUROpImpl(Op, IROp, ElementSize); } -template -void OpDispatchBuilder::VectorALUROp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUROp(OpcodeArgs); -template -void OpDispatchBuilder::VectorALUROp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUROp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUROp(OpcodeArgs); +template void OpDispatchBuilder::VectorALUROp(OpcodeArgs); -OrderedNode* OpDispatchBuilder::VectorScalarInsertALUOpImpl(OpcodeArgs, IROps IROp, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - bool ZeroUpperBits) { +OrderedNode* OpDispatchBuilder::VectorScalarInsertALUOpImpl(OpcodeArgs, IROps IROp, size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, {.AllowUpperGarbage = true}); // If OpSize == ElementSize then it only does the lower scalar op - DeriveOp(ALUOp, IROp, - _VFAddScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, ZeroUpperBits)); + DeriveOp(ALUOp, IROp, _VFAddScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, ZeroUpperBits)); return ALUOp; } -template +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Dest, Op->Src[0], false); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Src[0], Op->Src[1], true); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); -OrderedNode* OpDispatchBuilder::VectorScalarUnaryInsertALUOpImpl(OpcodeArgs, IROps IROp, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - bool ZeroUpperBits) { +OrderedNode* OpDispatchBuilder::VectorScalarUnaryInsertALUOpImpl(OpcodeArgs, IROps IROp, size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, {.AllowUpperGarbage = true}); // If OpSize == ElementSize then it only does the lower scalar op DeriveOp(ALUOp, IROp, _VFSqrtScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, ZeroUpperBits)); return ALUOp; } -template +template void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Dest, Op->Src[0], false); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Src[0], Op->Src[1], true); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); void OpDispatchBuilder::InsertMMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs) { // We load the full vector width when dealing with a source vector, @@ -672,8 +500,8 @@ void OpDispatchBuilder::InsertMMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); const auto SrcSize = Op->Src[0].IsGPR() ? 8 : GetSrcSize(Op); - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); // Always 32-bit. const size_t ElementSize = 4; @@ -683,24 +511,20 @@ void OpDispatchBuilder::InsertMMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs) { StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Dest, DstSize, -1); } -OrderedNode* OpDispatchBuilder::InsertCVTGPR_To_FPRImpl(OpcodeArgs, - size_t DstSize, size_t DstElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - bool ZeroUpperBits) { +OrderedNode* OpDispatchBuilder::InsertCVTGPR_To_FPRImpl(OpcodeArgs, size_t DstSize, size_t DstElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); if (Src2Op.IsGPR()) { // If the source is a GPR then convert directly from the GPR. auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, CTX->GetGPRSize(), Op->Flags); return _VSToFGPRInsert(IR::SizeToOpSize(DstSize), DstElementSize, SrcSize, Src1, Src2, ZeroUpperBits); - } - else if (SrcSize != DstElementSize) { + } else if (SrcSize != DstElementSize) { // If the source is from memory but the Source size and destination size aren't the same, // then it is more optimal to load in to a GPR and convert between GPR->FPR. // ARM GPR->FPR conversion supports different size source and destinations while FPR->FPR doesn't. @@ -722,36 +546,29 @@ void OpDispatchBuilder::InsertCVTGPR_To_FPR(OpcodeArgs) { StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::InsertCVTGPR_To_FPR<4>(OpcodeArgs); -template -void OpDispatchBuilder::InsertCVTGPR_To_FPR<8>(OpcodeArgs); +template void OpDispatchBuilder::InsertCVTGPR_To_FPR<4>(OpcodeArgs); +template void OpDispatchBuilder::InsertCVTGPR_To_FPR<8>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); - OrderedNode *Result = InsertCVTGPR_To_FPRImpl(Op, DstSize, DstElementSize, Op->Src[0], Op->Src[1], true); + OrderedNode* Result = InsertCVTGPR_To_FPRImpl(Op, DstSize, DstElementSize, Op->Src[0], Op->Src[1], true); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<4>(OpcodeArgs); -template -void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<8>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<4>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::InsertScalar_CVT_Float_To_FloatImpl(OpcodeArgs, - size_t DstSize, size_t DstElementSize, size_t SrcElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - bool ZeroUpperBits) { +OrderedNode* OpDispatchBuilder::InsertScalar_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstSize, size_t DstElementSize, + size_t SrcElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, {.AllowUpperGarbage = true}); return _VFToFScalarInsert(IR::SizeToOpSize(DstSize), DstElementSize, SrcElementSize, Src1, Src2, ZeroUpperBits); } @@ -759,40 +576,32 @@ OrderedNode* OpDispatchBuilder::InsertScalar_CVT_Float_To_FloatImpl(OpcodeArgs, template void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); - OrderedNode *Result = InsertScalar_CVT_Float_To_FloatImpl(Op, DstSize, DstElementSize, SrcElementSize, Op->Dest, Op->Src[0], false); + OrderedNode* Result = InsertScalar_CVT_Float_To_FloatImpl(Op, DstSize, DstElementSize, SrcElementSize, Op->Dest, Op->Src[0], false); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); -template -void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); +template void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float(OpcodeArgs) { const auto DstSize = GetGuestVectorLength(); - OrderedNode *Result = InsertScalar_CVT_Float_To_FloatImpl(Op, DstSize, DstElementSize, SrcElementSize, Op->Src[0], Op->Src[1], true); + OrderedNode* Result = InsertScalar_CVT_Float_To_FloatImpl(Op, DstSize, DstElementSize, SrcElementSize, Op->Src[0], Op->Src[1], true); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); -template -void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::InsertScalarRoundImpl(OpcodeArgs, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - uint64_t Mode, bool ZeroUpperBits) { +OrderedNode* OpDispatchBuilder::InsertScalarRoundImpl(OpcodeArgs, size_t DstSize, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, uint64_t Mode, bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, {.AllowUpperGarbage = true}); const uint64_t RoundControlSource = (Mode >> 2) & 1; uint64_t RoundControl = Mode & 0b11; @@ -817,14 +626,12 @@ void OpDispatchBuilder::InsertScalarRound(OpcodeArgs) { const uint64_t Mode = Op->Src[1].Data.Literal.Value; const auto DstSize = GetGuestVectorLength(); - OrderedNode *Result = InsertScalarRoundImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], Mode, false); + OrderedNode* Result = InsertScalarRoundImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], Mode, false); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::InsertScalarRound<4>(OpcodeArgs); -template -void OpDispatchBuilder::InsertScalarRound<8>(OpcodeArgs); +template void OpDispatchBuilder::InsertScalarRound<4>(OpcodeArgs); +template void OpDispatchBuilder::InsertScalarRound<8>(OpcodeArgs); template void OpDispatchBuilder::AVXInsertScalarRound(OpcodeArgs) { @@ -832,58 +639,74 @@ void OpDispatchBuilder::AVXInsertScalarRound(OpcodeArgs) { const uint64_t Mode = Op->Src[2].Data.Literal.Value; const auto DstSize = GetGuestVectorLength(); - OrderedNode *Result = InsertScalarRoundImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], Mode, true); + OrderedNode* Result = InsertScalarRoundImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], Mode, true); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::AVXInsertScalarRound<4>(OpcodeArgs); -template -void OpDispatchBuilder::AVXInsertScalarRound<8>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertScalarRound<4>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertScalarRound<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::InsertScalarFCMPOpImpl(OpcodeArgs, - size_t DstSize, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - uint8_t CompType, bool ZeroUpperBits) { +OrderedNode* OpDispatchBuilder::InsertScalarFCMPOpImpl(OpcodeArgs, size_t DstSize, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, uint8_t CompType, bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, - {.AllowUpperGarbage = true}); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, {.AllowUpperGarbage = true}); switch (CompType) { - case 0x00: case 0x08: case 0x10: case 0x18: // EQ - return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::EQ, ZeroUpperBits); - case 0x01: case 0x09: case 0x11: case 0x19: // LT, GT(Swapped operand) - return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::LT, ZeroUpperBits); - case 0x02: case 0x0A: case 0x12: case 0x1A: // LE, GE(Swapped operand) - return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::LE, ZeroUpperBits); - case 0x03: case 0x0B: case 0x13: case 0x1B: // Unordered - return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::UNO, ZeroUpperBits); - case 0x04: case 0x0C: case 0x14: case 0x1C: // NEQ - return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::NEQ, ZeroUpperBits); - case 0x05: case 0x0D: case 0x15: case 0x1D: { // NLT, NGT(Swapped operand) - OrderedNode *Result = _VFCMPLT(ElementSize, ElementSize, Src1, Src2); - Result = _VNot(ElementSize, ElementSize, Result); - // Insert the lower bits - return _VInsElement(GetDstSize(Op), ElementSize, 0, 0, Src1, Result); - } - case 0x06: case 0x0E: case 0x16: case 0x1E: { // NLE, NGE(Swapped operand) - OrderedNode *Result = _VFCMPLE(ElementSize, ElementSize, Src1, Src2); - Result = _VNot(ElementSize, ElementSize, Result); - // Insert the lower bits - return _VInsElement(GetDstSize(Op), ElementSize, 0, 0, Src1, Result); - } - case 0x07: case 0x0F: case 0x17: case 0x1F: // Ordered - return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::ORD, ZeroUpperBits); - default: - LOGMAN_MSG_A_FMT("Unknown Comparison type: {}", CompType); - break; + case 0x00: + case 0x08: + case 0x10: + case 0x18: // EQ + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::EQ, ZeroUpperBits); + case 0x01: + case 0x09: + case 0x11: + case 0x19: // LT, GT(Swapped operand) + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::LT, ZeroUpperBits); + case 0x02: + case 0x0A: + case 0x12: + case 0x1A: // LE, GE(Swapped operand) + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::LE, ZeroUpperBits); + case 0x03: + case 0x0B: + case 0x13: + case 0x1B: // Unordered + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::UNO, ZeroUpperBits); + case 0x04: + case 0x0C: + case 0x14: + case 0x1C: // NEQ + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::NEQ, ZeroUpperBits); + case 0x05: + case 0x0D: + case 0x15: + case 0x1D: { // NLT, NGT(Swapped operand) + OrderedNode* Result = _VFCMPLT(ElementSize, ElementSize, Src1, Src2); + Result = _VNot(ElementSize, ElementSize, Result); + // Insert the lower bits + return _VInsElement(GetDstSize(Op), ElementSize, 0, 0, Src1, Result); + } + case 0x06: + case 0x0E: + case 0x16: + case 0x1E: { // NLE, NGE(Swapped operand) + OrderedNode* Result = _VFCMPLE(ElementSize, ElementSize, Src1, Src2); + Result = _VNot(ElementSize, ElementSize, Result); + // Insert the lower bits + return _VInsElement(GetDstSize(Op), ElementSize, 0, 0, Src1, Result); + } + case 0x07: + case 0x0F: + case 0x17: + case 0x1F: // Ordered + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::ORD, ZeroUpperBits); + default: LOGMAN_MSG_A_FMT("Unknown Comparison type: {}", CompType); break; } FEX_UNREACHABLE; } @@ -894,14 +717,12 @@ void OpDispatchBuilder::InsertScalarFCMPOp(OpcodeArgs) { const uint8_t CompType = Op->Src[1].Data.Literal.Value; const auto DstSize = GetGuestVectorLength(); - OrderedNode *Result = InsertScalarFCMPOpImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], CompType, false); + OrderedNode* Result = InsertScalarFCMPOpImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], CompType, false); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::InsertScalarFCMPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::InsertScalarFCMPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::InsertScalarFCMPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::InsertScalarFCMPOp<8>(OpcodeArgs); template void OpDispatchBuilder::AVXInsertScalarFCMPOp(OpcodeArgs) { @@ -909,14 +730,12 @@ void OpDispatchBuilder::AVXInsertScalarFCMPOp(OpcodeArgs) { const uint8_t CompType = Op->Src[2].Data.Literal.Value; const auto DstSize = GetGuestVectorLength(); - OrderedNode *Result = InsertScalarFCMPOpImpl(Op, DstSize, ElementSize, Op->Src[0], Op->Src[1], CompType, true); + OrderedNode* Result = InsertScalarFCMPOpImpl(Op, DstSize, ElementSize, Op->Src[0], Op->Src[1], CompType, true); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::AVXInsertScalarFCMPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::AVXInsertScalarFCMPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertScalarFCMPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::AVXInsertScalarFCMPOp<8>(OpcodeArgs); void OpDispatchBuilder::VectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { // In the event of a scalar operation and a vector source, then @@ -926,34 +745,27 @@ void OpDispatchBuilder::VectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t Element const auto SrcSize = GetSrcSize(Op); const auto OpSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); DeriveOp(ALUOp, IROp, _VFSqrt(OpSize, ElementSize, Src)); StoreResult(FPRClass, Op, ALUOp, -1); } -template +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs) { VectorUnaryOpImpl(Op, IROp, ElementSize); } -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); void OpDispatchBuilder::AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { // In the event of a scalar operation and a vector source, then @@ -963,7 +775,7 @@ void OpDispatchBuilder::AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t Elem const auto SrcSize = GetSrcSize(Op); const auto OpSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); DeriveOp(ALUOp, IROp, _VFSqrt(OpSize, ElementSize, Src)); @@ -975,31 +787,24 @@ void OpDispatchBuilder::AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t Elem StoreResult(FPRClass, Op, ALUOp, -1); } -template +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs) { AVXVectorUnaryOpImpl(Op, IROp, ElementSize); } -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); void OpDispatchBuilder::VectorUnaryDuplicateOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { const auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); DeriveOp(ALUOp, IROp, _VFSqrt(ElementSize, ElementSize, Src)); @@ -1008,19 +813,17 @@ void OpDispatchBuilder::VectorUnaryDuplicateOpImpl(OpcodeArgs, IROps IROp, size_ StoreResult(FPRClass, Op, Result, -1); } -template +template void OpDispatchBuilder::VectorUnaryDuplicateOp(OpcodeArgs) { VectorUnaryDuplicateOpImpl(Op, IROp, ElementSize); } -template -void OpDispatchBuilder::VectorUnaryDuplicateOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryDuplicateOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryDuplicateOp(OpcodeArgs); +template void OpDispatchBuilder::VectorUnaryDuplicateOp(OpcodeArgs); void OpDispatchBuilder::MOVQOp(OpcodeArgs) { const auto SrcSize = Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); // This instruction is a bit special that if the destination is a register then it'll ZEXT the 64bit source to 128bit if (Op->Dest.IsGPR()) { const auto gpr = Op->Dest.Data.GPR.GPR; @@ -1028,15 +831,14 @@ void OpDispatchBuilder::MOVQOp(OpcodeArgs) { auto Reg = _VMov(8, Src); StoreXMMRegister(gprIndex, Reg); - } - else { + } else { // This is simple, just store the result StoreResult(FPRClass, Op, Src, -1); } } void OpDispatchBuilder::MOVQMMXOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); StoreResult(FPRClass, Op, Src, 1); } @@ -1045,23 +847,22 @@ void OpDispatchBuilder::MOVMSKOp(OpcodeArgs) { auto Size = GetSrcSize(Op); uint8_t NumElements = Size / ElementSize; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); if (Size == 16 && ElementSize == 8) { // UnZip2 the 64-bit elements as 32-bit to get the sign bits closer. // Sign bits are now in bit positions 31 and 63 after this. - Src =_VUnZip2(Size, 4, Src, Src); + Src = _VUnZip2(Size, 4, Src, Src); // Extract the low 64-bits to GPR in one move. - OrderedNode *GPR = _VExtractToGPR(Size, 8, Src, 0); + OrderedNode* GPR = _VExtractToGPR(Size, 8, Src, 0); // BFI the sign bit in 31 in to 62. // Inserting the full lower 32-bits offset 31 so the sign bit ends up at offset 63. GPR = _Bfi(OpSize::i64Bit, 32, 31, GPR, GPR); // Shift right to only get the two sign bits we care about. GPR = _Lshr(OpSize::i64Bit, GPR, _Constant(62)); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, CTX->GetGPRSize(), -1); - } - else if (Size == 16 && ElementSize == 4) { + } else if (Size == 16 && ElementSize == 4) { // Shift all the sign bits to the bottom of their respective elements. Src = _VUShrI(Size, 4, Src, 31); // Load the specific 128-bit movmskps shift elements operator. @@ -1071,15 +872,14 @@ void OpDispatchBuilder::MOVMSKOp(OpcodeArgs) { // Add across the vector so the sign bits will end up in bits [3:0] Src = _VAddV(Size, 4, Src); // Extract to a GPR. - OrderedNode *GPR = _VExtractToGPR(Size, 4, Src, 0); + OrderedNode* GPR = _VExtractToGPR(Size, 4, Src, 0); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, CTX->GetGPRSize(), -1); - } - else { - OrderedNode *CurrentVal = _Constant(0); + } else { + OrderedNode* CurrentVal = _Constant(0); for (unsigned i = 0; i < NumElements; ++i) { // Extract the top bit of the element - OrderedNode *Tmp = _VExtractToGPR(Size, ElementSize, Src, i); + OrderedNode* Tmp = _VExtractToGPR(Size, ElementSize, Src, i); Tmp = _Bfe(IR::SizeToOpSize(ElementSize), 1, ElementSize * 8 - 1, Tmp); // Shift it to the correct location @@ -1092,25 +892,23 @@ void OpDispatchBuilder::MOVMSKOp(OpcodeArgs) { } } -template -void OpDispatchBuilder::MOVMSKOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::MOVMSKOp<8>(OpcodeArgs); +template void OpDispatchBuilder::MOVMSKOp<4>(OpcodeArgs); +template void OpDispatchBuilder::MOVMSKOp<8>(OpcodeArgs); void OpDispatchBuilder::MOVMSKOpOne(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is256Bit = SrcSize == Core::CPUState::XMM_AVX_REG_SIZE; const auto ExtractSize = Is256Bit ? 4 : 2; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *VMask = LoadAndCacheNamedVectorConstant(SrcSize, NAMED_VECTOR_MOVMASKB); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* VMask = LoadAndCacheNamedVectorConstant(SrcSize, NAMED_VECTOR_MOVMASKB); auto VCMP = _VCMPLTZ(SrcSize, 1, Src); auto VAnd = _VAnd(SrcSize, 1, VCMP, VMask); // Since we also handle the MM MOVMSKB here too, // we need to clamp the lower bound. - const auto VAdd1Size = std::max(SrcSize, uint8_t{16}); + const auto VAdd1Size = std::max(SrcSize, uint8_t {16}); const auto VAdd2Size = std::max(SrcSize / 2, 8); auto VAdd1 = _VAddP(VAdd1Size, 1, VAnd, VAnd); @@ -1126,36 +924,32 @@ template void OpDispatchBuilder::PUNPCKLOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto ALUOp = _VZip(Size, ElementSize, Dest, Src); StoreResult(FPRClass, Op, ALUOp, -1); } -template -void OpDispatchBuilder::PUNPCKLOp<1>(OpcodeArgs); -template -void OpDispatchBuilder::PUNPCKLOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PUNPCKLOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::PUNPCKLOp<8>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKLOp<1>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKLOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKLOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKLOp<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VPUNPCKLOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is128Bit = SrcSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result{}; + OrderedNode* Result {}; if (Is128Bit) { Result = _VZip(SrcSize, ElementSize, Src1, Src2); } else { - OrderedNode *ZipLo = _VZip(SrcSize, ElementSize, Src1, Src2); - OrderedNode *ZipHi = _VZip2(SrcSize, ElementSize, Src1, Src2); + OrderedNode* ZipLo = _VZip(SrcSize, ElementSize, Src1, Src2); + OrderedNode* ZipHi = _VZip2(SrcSize, ElementSize, Src1, Src2); Result = _VInsElement(SrcSize, 16, 1, 0, ZipLo, ZipHi); } @@ -1163,48 +957,40 @@ void OpDispatchBuilder::VPUNPCKLOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPUNPCKLOp<1>(OpcodeArgs); -template -void OpDispatchBuilder::VPUNPCKLOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPUNPCKLOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPUNPCKLOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKLOp<1>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKLOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKLOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKLOp<8>(OpcodeArgs); template void OpDispatchBuilder::PUNPCKHOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto ALUOp = _VZip2(Size, ElementSize, Dest, Src); StoreResult(FPRClass, Op, ALUOp, -1); } -template -void OpDispatchBuilder::PUNPCKHOp<1>(OpcodeArgs); -template -void OpDispatchBuilder::PUNPCKHOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PUNPCKHOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::PUNPCKHOp<8>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKHOp<1>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKHOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKHOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PUNPCKHOp<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VPUNPCKHOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is128Bit = SrcSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result{}; + OrderedNode* Result {}; if (Is128Bit) { Result = _VZip2(SrcSize, ElementSize, Src1, Src2); } else { - OrderedNode *ZipLo = _VZip(SrcSize, ElementSize, Src1, Src2); - OrderedNode *ZipHi = _VZip2(SrcSize, ElementSize, Src1, Src2); + OrderedNode* ZipLo = _VZip(SrcSize, ElementSize, Src1, Src2); + OrderedNode* ZipHi = _VZip2(SrcSize, ElementSize, Src1, Src2); Result = _VInsElement(SrcSize, 16, 0, 1, ZipHi, ZipLo); } @@ -1212,26 +998,21 @@ void OpDispatchBuilder::VPUNPCKHOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPUNPCKHOp<1>(OpcodeArgs); -template -void OpDispatchBuilder::VPUNPCKHOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPUNPCKHOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPUNPCKHOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKHOp<1>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKHOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKHOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPUNPCKHOp<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PSHUFBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2) { - OrderedNode *Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); - OrderedNode *Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); +OrderedNode* OpDispatchBuilder::PSHUFBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2) { + OrderedNode* Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); + OrderedNode* Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); const auto SrcSize = GetSrcSize(Op); const auto Is256Bit = SrcSize == Core::CPUState::XMM_AVX_REG_SIZE; // We perform the 256-bit version as two 128-bit operations due to // the lane splitting behavior, so cap the maximum size at 16. - const auto SanitizedSrcSize = std::min(SrcSize, uint8_t{16}); + const auto SanitizedSrcSize = std::min(SrcSize, uint8_t {16}); // PSHUFB doesn't 100% match VTBL behaviour // VTBL will set the element zero if the index is greater than @@ -1241,29 +1022,28 @@ OrderedNode* OpDispatchBuilder::PSHUFBOpImpl(OpcodeArgs, const X86Tables::Decode // Mask the selection bits and top bit correctly // Bits [6:4] is reserved for 128-bit/256-bit // Bits [6:3] is reserved for 64-bit - const uint8_t MaskImm = SrcSize == 8 ? 0b1000'0111 - : 0b1000'1111; + const uint8_t MaskImm = SrcSize == 8 ? 0b1000'0111 : 0b1000'1111; - OrderedNode *MaskVector = _VectorImm(SrcSize, 1, MaskImm); - OrderedNode *MaskedIndices = _VAnd(SrcSize, SrcSize, Src2Node, MaskVector); + OrderedNode* MaskVector = _VectorImm(SrcSize, 1, MaskImm); + OrderedNode* MaskedIndices = _VAnd(SrcSize, SrcSize, Src2Node, MaskVector); - OrderedNode *Low = _VTBL1(SanitizedSrcSize, Src1Node, MaskedIndices); + OrderedNode* Low = _VTBL1(SanitizedSrcSize, Src1Node, MaskedIndices); if (!Is256Bit) { return Low; } - OrderedNode *HighSrc1 = _VInsElement(SrcSize, 16, 0, 1, Src1Node, Src1Node); - OrderedNode *High = _VTBL1(SanitizedSrcSize, HighSrc1, MaskedIndices); + OrderedNode* HighSrc1 = _VInsElement(SrcSize, 16, 0, 1, Src1Node, Src1Node); + OrderedNode* High = _VTBL1(SanitizedSrcSize, HighSrc1, MaskedIndices); return _VInsElement(SrcSize, 16, 1, 0, Low, High); } void OpDispatchBuilder::PSHUFBOp(OpcodeArgs) { - OrderedNode *Result = PSHUFBOpImpl(Op, Op->Dest, Op->Src[0]); + OrderedNode* Result = PSHUFBOpImpl(Op, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPSHUFBOp(OpcodeArgs) { - OrderedNode *Result = PSHUFBOpImpl(Op, Op->Src[0], Op->Src[1]); + OrderedNode* Result = PSHUFBOpImpl(Op, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } @@ -1272,39 +1052,40 @@ void OpDispatchBuilder::PSHUFW8ByteOp(OpcodeArgs) { uint16_t Shuffle = Op->Src[1].Data.Literal.Value; const auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest{}; + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest {}; // TODO: There can be more optimized copies here. switch (Shuffle) { - case IdentityCopy: { - // Special case identity copy. - Dest = Src; - break; - } - case 0b01'01'00'00: { - // Zip with self. - // Dest[0] = Src[0] - // Dest[1] = Src[0] - // Dest[2] = Src[1] - // Dest[3] = Src[1] - Dest = _VZip(Size, 2, Src, Src); - break; - } - case 0b00'00'00'00: - case 0b01'01'01'01: - case 0b10'10'10'10: - case 0b11'11'11'11: { - // Special case element duplicate and broadcasts. - Dest = _VDupElement(Size, 2, Src, (Shuffle & 0b11)); - break; - } - default: { - // PSHUFW (mmx) also needs to scale by 16 to get correct low element. - auto LookupIndexes = LoadAndCacheIndexedNamedVectorConstant(Size, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFLW, Shuffle * 16); - Dest = _VTBL1(Size, Src, LookupIndexes); - break; - } + case IdentityCopy: { + // Special case identity copy. + Dest = Src; + break; + } + case 0b01'01'00'00: { + // Zip with self. + // Dest[0] = Src[0] + // Dest[1] = Src[0] + // Dest[2] = Src[1] + // Dest[3] = Src[1] + Dest = _VZip(Size, 2, Src, Src); + break; + } + case 0b00'00'00'00: + case 0b01'01'01'01: + case 0b10'10'10'10: + case 0b11'11'11'11: { + // Special case element duplicate and broadcasts. + Dest = _VDupElement(Size, 2, Src, (Shuffle & 0b11)); + break; + } + default: { + // PSHUFW (mmx) also needs to scale by 16 to get correct low element. + auto LookupIndexes = + LoadAndCacheIndexedNamedVectorConstant(Size, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFLW, Shuffle * 16); + Dest = _VTBL1(Size, Src, LookupIndexes); + break; + } } StoreResult(FPRClass, Op, Dest, -1); @@ -1316,117 +1097,113 @@ void OpDispatchBuilder::PSHUFWOp(OpcodeArgs) { uint16_t Shuffle = Op->Src[1].Data.Literal.Value; const auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest{}; + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest {}; const uint8_t NumElements = Size / 2; const uint8_t HalfNumElements = NumElements >> 1; // TODO: There can be more optimized copies here. switch (Shuffle) { - case IdentityCopy: { - // Special case identity copy. - Dest = Src; - break; + case IdentityCopy: { + // Special case identity copy. + Dest = Src; + break; + } + case 0b01'01'00'00: { + // Zip with self. + // Dest[0] = Src[0] + // Dest[1] = Src[0] + // Dest[2] = Src[1] + // Dest[3] = Src[1] + auto Zip = _VZip(Size, 2, Src, Src); + if (Low) { + Dest = _VZip(Size, 8, Zip, Src); + } else { + Dest = _VZip(Size, 8, Src, Zip); } - case 0b01'01'00'00: { - // Zip with self. - // Dest[0] = Src[0] - // Dest[1] = Src[0] - // Dest[2] = Src[1] - // Dest[3] = Src[1] - auto Zip = _VZip(Size, 2, Src, Src); - if (Low) { - Dest = _VZip(Size, 8, Zip, Src); - } - else { - Dest = _VZip(Size, 8, Src, Zip); - } - break; - } - case 0b00'00'00'00: - case 0b01'01'01'01: - case 0b10'10'10'10: - case 0b11'11'11'11: { - // Special case element duplicate and broadcast to low or high 64-bits. - auto DUP = _VDupElement(Size, 2, Src, (Low ? 0 : HalfNumElements) + (Shuffle & 0b11)); - if (Low) { - // DUP goes low. - // Source goes high. - Dest = _VTrn2(Size, 8, DUP, Src); - } - else { - // DUP goes high. - // Source goes low. - Dest = _VTrn(Size, 8, Src, DUP); - } - break; - } - default: { - // PSHUFLW needs to scale index by 16. - // PSHUFHW needs to scale index by 16. - // PSHUFW (mmx) also needs to scale by 16 to get correct low element. - const auto IndexedVectorConstant = Low ? - FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFLW : - FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFHW; - auto LookupIndexes = LoadAndCacheIndexedNamedVectorConstant(Size, IndexedVectorConstant, Shuffle * 16); - Dest = _VTBL1(Size, Src, LookupIndexes); - break; + break; + } + case 0b00'00'00'00: + case 0b01'01'01'01: + case 0b10'10'10'10: + case 0b11'11'11'11: { + // Special case element duplicate and broadcast to low or high 64-bits. + auto DUP = _VDupElement(Size, 2, Src, (Low ? 0 : HalfNumElements) + (Shuffle & 0b11)); + if (Low) { + // DUP goes low. + // Source goes high. + Dest = _VTrn2(Size, 8, DUP, Src); + } else { + // DUP goes high. + // Source goes low. + Dest = _VTrn(Size, 8, Src, DUP); } + break; + } + default: { + // PSHUFLW needs to scale index by 16. + // PSHUFHW needs to scale index by 16. + // PSHUFW (mmx) also needs to scale by 16 to get correct low element. + const auto IndexedVectorConstant = Low ? FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFLW : + FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFHW; + auto LookupIndexes = LoadAndCacheIndexedNamedVectorConstant(Size, IndexedVectorConstant, Shuffle * 16); + Dest = _VTBL1(Size, Src, LookupIndexes); + break; + } } StoreResult(FPRClass, Op, Dest, -1); } -template -void OpDispatchBuilder::PSHUFWOp(OpcodeArgs); -template -void OpDispatchBuilder::PSHUFWOp(OpcodeArgs); +template void OpDispatchBuilder::PSHUFWOp(OpcodeArgs); +template void OpDispatchBuilder::PSHUFWOp(OpcodeArgs); void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) { constexpr auto IdentityCopy = 0b11'10'01'00; uint16_t Shuffle = Op->Src[1].Data.Literal.Value; const auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest{}; + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest {}; // TODO: There can be more optimized copies here. switch (Shuffle) { - case IdentityCopy: { - // Special case identity copy. - Dest = Src; - break; - } - case 0b01'01'00'00: { - // Zip with self. - // Dest[0] = Src[0] - // Dest[1] = Src[0] - // Dest[2] = Src[1] - // Dest[3] = Src[1] - Dest = _VZip(Size, 4, Src, Src); - break; - } - case 0b00'00'00'00: - case 0b01'01'01'01: - case 0b10'10'10'10: - case 0b11'11'11'11: { - // Special case element duplicate and broadcast to low or high 64-bits. - Dest = _VDupElement(Size, 4, Src, Shuffle & 0b11); - break; - } - default: { - // PSHUFD needs to scale index by 16. - auto LookupIndexes = LoadAndCacheIndexedNamedVectorConstant(Size, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD, Shuffle * 16); - Dest = _VTBL1(Size, Src, LookupIndexes); - break; - } + case IdentityCopy: { + // Special case identity copy. + Dest = Src; + break; + } + case 0b01'01'00'00: { + // Zip with self. + // Dest[0] = Src[0] + // Dest[1] = Src[0] + // Dest[2] = Src[1] + // Dest[3] = Src[1] + Dest = _VZip(Size, 4, Src, Src); + break; + } + case 0b00'00'00'00: + case 0b01'01'01'01: + case 0b10'10'10'10: + case 0b11'11'11'11: { + // Special case element duplicate and broadcast to low or high 64-bits. + Dest = _VDupElement(Size, 4, Src, Shuffle & 0b11); + break; + } + default: { + // PSHUFD needs to scale index by 16. + auto LookupIndexes = + LoadAndCacheIndexedNamedVectorConstant(Size, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD, Shuffle * 16); + Dest = _VTBL1(Size, Src, LookupIndexes); + break; + } } StoreResult(FPRClass, Op, Dest, -1); } -template +template void OpDispatchBuilder::VPSHUFWOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is256Bit = SrcSize == Core::CPUState::XMM_AVX_REG_SIZE; @@ -1434,7 +1211,7 @@ void OpDispatchBuilder::VPSHUFWOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src[1] needs to be a literal"); auto Shuffle = Op->Src[1].Data.Literal.Value; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); // Note/TODO: With better immediate facilities or vector loading in our IR // much of this can be reduced to setting up a table index register @@ -1449,7 +1226,7 @@ void OpDispatchBuilder::VPSHUFWOp(OpcodeArgs) { // Should be much nicer than doing repeated inserts in any case. const size_t BaseElement = Low ? 0 : 4; - OrderedNode *Result = Src; + OrderedNode* Result = Src; if (Is256Bit) { for (size_t i = 0; i < 4; i++) { const auto Index = Shuffle & 0b11; @@ -1477,19 +1254,14 @@ void OpDispatchBuilder::VPSHUFWOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPSHUFWOp<2, false>(OpcodeArgs); -template -void OpDispatchBuilder::VPSHUFWOp<2, true>(OpcodeArgs); -template -void OpDispatchBuilder::VPSHUFWOp<4, true>(OpcodeArgs); +template void OpDispatchBuilder::VPSHUFWOp<2, false>(OpcodeArgs); +template void OpDispatchBuilder::VPSHUFWOp<2, true>(OpcodeArgs); +template void OpDispatchBuilder::VPSHUFWOp<4, true>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::SHUFOpImpl(OpcodeArgs, size_t ElementSize, - const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, - const X86Tables::DecodedOperand& Imm) { - OrderedNode *Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); - OrderedNode *Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); +OrderedNode* OpDispatchBuilder::SHUFOpImpl(OpcodeArgs, size_t ElementSize, const X86Tables::DecodedOperand& Src1, + const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm) { + OrderedNode* Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); + OrderedNode* Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); LOGMAN_THROW_A_FMT(Imm.IsLiteral(), "Imm needs to be a literal"); uint8_t Shuffle = Imm.Data.Literal.Value; @@ -1503,7 +1275,7 @@ OrderedNode* OpDispatchBuilder::SHUFOpImpl(OpcodeArgs, size_t ElementSize, const uint8_t DstSize = GetDstSize(Op); const bool Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - std::array Srcs{}; + std::array Srcs {}; for (size_t i = 0; i < HalfNumElements; ++i) { Srcs[i] = Src1Node; } @@ -1511,21 +1283,20 @@ OrderedNode* OpDispatchBuilder::SHUFOpImpl(OpcodeArgs, size_t ElementSize, Srcs[i] = Src2Node; } - OrderedNode *Dest = Src1Node; + OrderedNode* Dest = Src1Node; const uint8_t SelectionMask = NumElements - 1; const uint8_t ShiftAmount = std::popcount(SelectionMask); if (Is256Bit) { for (uint8_t Element = 0; Element < NumElements; ++Element) { - const auto SrcIndex1 = Shuffle & SelectionMask; + const auto SrcIndex1 = Shuffle & SelectionMask; // AVX differs the behavior of VSHUFPD and VSHUFPS. // The same immediate bits are used for both lanes with VSHUFPS, // but VSHUFPD uses different immediate bits for each lane. - const auto SrcIndex2 = ElementSize == 4 ? SrcIndex1 - : ((Shuffle >> 2) & SelectionMask); + const auto SrcIndex2 = ElementSize == 4 ? SrcIndex1 : ((Shuffle >> 2) & SelectionMask); - OrderedNode *Insert = _VInsElement(DstSize, ElementSize, Element, SrcIndex1, Dest, Srcs[Element]); + OrderedNode* Insert = _VInsElement(DstSize, ElementSize, Element, SrcIndex1, Dest, Srcs[Element]); Dest = _VInsElement(DstSize, ElementSize, Element + NumElements, SrcIndex2 + NumElements, Insert, Srcs[Element]); Shuffle >>= ShiftAmount; @@ -1535,148 +1306,147 @@ OrderedNode* OpDispatchBuilder::SHUFOpImpl(OpcodeArgs, size_t ElementSize, // We can shuffle optimally in a lot of cases. // TODO: We can optimize more of these cases. switch (Shuffle) { - case 0b01'00'01'00: - // Combining of low 64-bits. - // Dest[63:0] = Src1[63:0] - // Dest[127:64] = Src2[63:0] - return _VZip(DstSize, 8, Src1Node, Src2Node); - case 0b11'10'11'10: - // Combining of high 64-bits. - // Dest[63:0] = Src1[127:64] - // Dest[127:64] = Src2[127:64] - return _VZip2(DstSize, 8, Src1Node, Src2Node); - case 0b11'10'01'00: - // Mixing Low and high elements - // Dest[63:0] = Src1[63:0] - // Dest[127:64] = Src2[127:64] - return _VInsElement(DstSize, 8, 1, 1, Src1Node, Src2Node); - case 0b01'00'11'10: - // Mixing Low and high elements, inverse of above - // Dest[63:0] = Src1[127:64] - // Dest[127:64] = Src2[63:0] - return _VExtr(DstSize, 1, Src2Node, Src1Node, 8); - case 0b10'00'10'00: - // Mixing even elements. - // Dest[31:0] = Src1[31:0] - // Dest[63:32] = Src1[95:64] - // Dest[95:64] = Src2[31:0] - // Dest[127:96] = Src2[95:64] - return _VUnZip(DstSize, ElementSize, Src1Node, Src2Node); - case 0b11'01'11'01: - // Mixing odd elements. - // Dest[31:0] = Src1[63:32] - // Dest[63:32] = Src1[127:96] - // Dest[95:64] = Src2[63:32] - // Dest[127:96] = Src2[127:96] - return _VUnZip2(DstSize, ElementSize, Src1Node, Src2Node); - case 0b11'10'00'00: - case 0b11'10'01'01: - case 0b11'10'10'10: - case 0b11'10'11'11: { - // Bottom elements duplicated, Top 64-bits inserted - auto DupSrc1 = _VDupElement(DstSize, ElementSize, Src1Node, Shuffle & 0b11); - return _VZip2(DstSize, 8, DupSrc1, Src2Node); - } - case 0b01'00'00'00: - case 0b01'00'01'01: - case 0b01'00'10'10: - case 0b01'00'11'11: { - // Bottom elements duplicated, Bottom 64-bits inserted - auto DupSrc1 = _VDupElement(DstSize, ElementSize, Src1Node, Shuffle & 0b11); - return _VZip(DstSize, 8, DupSrc1, Src2Node); - } - case 0b00'00'01'00: - case 0b01'01'01'00: - case 0b10'10'01'00: - case 0b11'11'01'00: { - // Top elements duplicated, Bottom 64-bits inserted - auto DupSrc2 = _VDupElement(DstSize, ElementSize, Src2Node, (Shuffle >> 4) & 0b11); - return _VZip(DstSize, 8, Src1Node, DupSrc2); - } - case 0b00'00'11'10: - case 0b01'01'11'10: - case 0b10'10'11'10: - case 0b11'11'11'10: { - // Top elements duplicated, Top 64-bits inserted - auto DupSrc2 = _VDupElement(DstSize, ElementSize, Src2Node, (Shuffle >> 4) & 0b11); - return _VZip2(DstSize, 8, Src1Node, DupSrc2); - } - case 0b01'00'01'11: { - // TODO: This doesn't generate optimal code. - // RA doesn't understand that Src1Node is dead after VInsElement due to SRA class differences. - // With RA fixes this would be 2 instructions. - // Odd elements inverted, Low 64-bits inserted - Src1Node = _VInsElement(DstSize, 4, 0, 3, Src1Node, Src1Node); - return _VZip(DstSize, 8, Src1Node, Src2Node); - } - case 0b11'10'01'11: { - // TODO: This doesn't generate optimal code. - // RA doesn't understand that Src1Node is dead after VInsElement due to SRA class differences. - // With RA fixes this would be 2 instructions. - // Odd elements inverted, Top 64-bits inserted - Src1Node = _VInsElement(DstSize, 4, 0, 3, Src1Node, Src1Node); - return _VInsElement(DstSize, 8, 1, 1, Src1Node, Src2Node); - } - case 0b01'00'00'01: { - // Lower 32-bit elements inverted, low 64-bits inserted - Src1Node = _VRev64(DstSize, 4, Src1Node); - return _VZip(DstSize, 8, Src1Node, Src2Node); - } - case 0b11'10'00'01: { - // TODO: This doesn't generate optimal code. - // RA doesn't understand that Src1Node is dead after VInsElement due to SRA class differences. - // With RA fixes this would be 2 instructions. - // Lower 32-bit elements inverted, Top 64-bits inserted - Src1Node = _VRev64(DstSize, 4, Src1Node); - return _VInsElement(DstSize, 8, 1, 1, Src1Node, Src2Node); - } - case 0b00'00'00'00: - case 0b00'00'01'01: - case 0b00'00'10'10: - case 0b00'00'11'11: - case 0b01'01'00'00: - case 0b01'01'01'01: - case 0b01'01'10'10: - case 0b01'01'11'11: - case 0b10'10'00'00: - case 0b10'10'01'01: - case 0b10'10'10'10: - case 0b10'10'11'11: - case 0b11'11'00'00: - case 0b11'11'01'01: - case 0b11'11'10'10: - case 0b11'11'11'11: - { - // Duplicate element in upper and lower across each 64-bit segment. - auto DupSrc1 = _VDupElement(DstSize, ElementSize, Src1Node, Shuffle & 0b11); - auto DupSrc2 = _VDupElement(DstSize, ElementSize, Src2Node, (Shuffle >> 4) & 0b11); - return _VZip(DstSize, 8, DupSrc1, DupSrc2); - } - default: - // Use a TBL2 operation to handle this implementation. If the backend supports it. - if (CTX->BackendFeatures.SupportsVTBL2) { - auto LookupIndexes = LoadAndCacheIndexedNamedVectorConstant(DstSize, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_SHUFPS, Shuffle * 16); - return _VTBL2(DstSize, Src1Node, Src2Node, LookupIndexes); - } - break; + case 0b01'00'01'00: + // Combining of low 64-bits. + // Dest[63:0] = Src1[63:0] + // Dest[127:64] = Src2[63:0] + return _VZip(DstSize, 8, Src1Node, Src2Node); + case 0b11'10'11'10: + // Combining of high 64-bits. + // Dest[63:0] = Src1[127:64] + // Dest[127:64] = Src2[127:64] + return _VZip2(DstSize, 8, Src1Node, Src2Node); + case 0b11'10'01'00: + // Mixing Low and high elements + // Dest[63:0] = Src1[63:0] + // Dest[127:64] = Src2[127:64] + return _VInsElement(DstSize, 8, 1, 1, Src1Node, Src2Node); + case 0b01'00'11'10: + // Mixing Low and high elements, inverse of above + // Dest[63:0] = Src1[127:64] + // Dest[127:64] = Src2[63:0] + return _VExtr(DstSize, 1, Src2Node, Src1Node, 8); + case 0b10'00'10'00: + // Mixing even elements. + // Dest[31:0] = Src1[31:0] + // Dest[63:32] = Src1[95:64] + // Dest[95:64] = Src2[31:0] + // Dest[127:96] = Src2[95:64] + return _VUnZip(DstSize, ElementSize, Src1Node, Src2Node); + case 0b11'01'11'01: + // Mixing odd elements. + // Dest[31:0] = Src1[63:32] + // Dest[63:32] = Src1[127:96] + // Dest[95:64] = Src2[63:32] + // Dest[127:96] = Src2[127:96] + return _VUnZip2(DstSize, ElementSize, Src1Node, Src2Node); + case 0b11'10'00'00: + case 0b11'10'01'01: + case 0b11'10'10'10: + case 0b11'10'11'11: { + // Bottom elements duplicated, Top 64-bits inserted + auto DupSrc1 = _VDupElement(DstSize, ElementSize, Src1Node, Shuffle & 0b11); + return _VZip2(DstSize, 8, DupSrc1, Src2Node); } - } - else { + case 0b01'00'00'00: + case 0b01'00'01'01: + case 0b01'00'10'10: + case 0b01'00'11'11: { + // Bottom elements duplicated, Bottom 64-bits inserted + auto DupSrc1 = _VDupElement(DstSize, ElementSize, Src1Node, Shuffle & 0b11); + return _VZip(DstSize, 8, DupSrc1, Src2Node); + } + case 0b00'00'01'00: + case 0b01'01'01'00: + case 0b10'10'01'00: + case 0b11'11'01'00: { + // Top elements duplicated, Bottom 64-bits inserted + auto DupSrc2 = _VDupElement(DstSize, ElementSize, Src2Node, (Shuffle >> 4) & 0b11); + return _VZip(DstSize, 8, Src1Node, DupSrc2); + } + case 0b00'00'11'10: + case 0b01'01'11'10: + case 0b10'10'11'10: + case 0b11'11'11'10: { + // Top elements duplicated, Top 64-bits inserted + auto DupSrc2 = _VDupElement(DstSize, ElementSize, Src2Node, (Shuffle >> 4) & 0b11); + return _VZip2(DstSize, 8, Src1Node, DupSrc2); + } + case 0b01'00'01'11: { + // TODO: This doesn't generate optimal code. + // RA doesn't understand that Src1Node is dead after VInsElement due to SRA class differences. + // With RA fixes this would be 2 instructions. + // Odd elements inverted, Low 64-bits inserted + Src1Node = _VInsElement(DstSize, 4, 0, 3, Src1Node, Src1Node); + return _VZip(DstSize, 8, Src1Node, Src2Node); + } + case 0b11'10'01'11: { + // TODO: This doesn't generate optimal code. + // RA doesn't understand that Src1Node is dead after VInsElement due to SRA class differences. + // With RA fixes this would be 2 instructions. + // Odd elements inverted, Top 64-bits inserted + Src1Node = _VInsElement(DstSize, 4, 0, 3, Src1Node, Src1Node); + return _VInsElement(DstSize, 8, 1, 1, Src1Node, Src2Node); + } + case 0b01'00'00'01: { + // Lower 32-bit elements inverted, low 64-bits inserted + Src1Node = _VRev64(DstSize, 4, Src1Node); + return _VZip(DstSize, 8, Src1Node, Src2Node); + } + case 0b11'10'00'01: { + // TODO: This doesn't generate optimal code. + // RA doesn't understand that Src1Node is dead after VInsElement due to SRA class differences. + // With RA fixes this would be 2 instructions. + // Lower 32-bit elements inverted, Top 64-bits inserted + Src1Node = _VRev64(DstSize, 4, Src1Node); + return _VInsElement(DstSize, 8, 1, 1, Src1Node, Src2Node); + } + case 0b00'00'00'00: + case 0b00'00'01'01: + case 0b00'00'10'10: + case 0b00'00'11'11: + case 0b01'01'00'00: + case 0b01'01'01'01: + case 0b01'01'10'10: + case 0b01'01'11'11: + case 0b10'10'00'00: + case 0b10'10'01'01: + case 0b10'10'10'10: + case 0b10'10'11'11: + case 0b11'11'00'00: + case 0b11'11'01'01: + case 0b11'11'10'10: + case 0b11'11'11'11: { + // Duplicate element in upper and lower across each 64-bit segment. + auto DupSrc1 = _VDupElement(DstSize, ElementSize, Src1Node, Shuffle & 0b11); + auto DupSrc2 = _VDupElement(DstSize, ElementSize, Src2Node, (Shuffle >> 4) & 0b11); + return _VZip(DstSize, 8, DupSrc1, DupSrc2); + } + default: + // Use a TBL2 operation to handle this implementation. If the backend supports it. + if (CTX->BackendFeatures.SupportsVTBL2) { + auto LookupIndexes = + LoadAndCacheIndexedNamedVectorConstant(DstSize, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_SHUFPS, Shuffle * 16); + return _VTBL2(DstSize, Src1Node, Src2Node, LookupIndexes); + } + break; + } + } else { switch (Shuffle & 0b11) { - case 0b00: - // Low 64-bits of each source interleaved. - return _VZip(DstSize, ElementSize, Src1Node, Src2Node); - case 0b01: - // Upper 64-bits of Src1 in lower bits - // Lower 64-bits of Src2 in upper bits. - return _VExtr(DstSize, 1, Src2Node, Src1Node, 8); - case 0b10: - // Lower 32-bits of Src1 in lower bits. - // Upper 64-bits of Src2 in upper bits. - return _VInsElement(DstSize, ElementSize, 1, 1, Src1Node, Src2Node); - case 0b11: - // Upper 64-bits of each source interleaved. - return _VZip2(DstSize, ElementSize, Src1Node, Src2Node); + case 0b00: + // Low 64-bits of each source interleaved. + return _VZip(DstSize, ElementSize, Src1Node, Src2Node); + case 0b01: + // Upper 64-bits of Src1 in lower bits + // Lower 64-bits of Src2 in upper bits. + return _VExtr(DstSize, 1, Src2Node, Src1Node, 8); + case 0b10: + // Lower 32-bits of Src1 in lower bits. + // Upper 64-bits of Src2 in upper bits. + return _VInsElement(DstSize, ElementSize, 1, 1, Src1Node, Src2Node); + case 0b11: + // Upper 64-bits of each source interleaved. + return _VZip2(DstSize, ElementSize, Src1Node, Src2Node); } } @@ -1692,46 +1462,42 @@ OrderedNode* OpDispatchBuilder::SHUFOpImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::SHUFOp(OpcodeArgs) { - OrderedNode *Result = SHUFOpImpl(Op, ElementSize, Op->Dest, Op->Src[0], Op->Src[1]); + OrderedNode* Result = SHUFOpImpl(Op, ElementSize, Op->Dest, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::SHUFOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::SHUFOp<8>(OpcodeArgs); +template void OpDispatchBuilder::SHUFOp<4>(OpcodeArgs); +template void OpDispatchBuilder::SHUFOp<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VSHUFOp(OpcodeArgs) { - OrderedNode *Result = SHUFOpImpl(Op, ElementSize, Op->Src[0], Op->Src[1], Op->Src[2]); + OrderedNode* Result = SHUFOpImpl(Op, ElementSize, Op->Src[0], Op->Src[1], Op->Src[2]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VSHUFOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VSHUFOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VSHUFOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VSHUFOp<8>(OpcodeArgs); void OpDispatchBuilder::VANDNOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Dest = _VBic(SrcSize, SrcSize, Src2, Src1); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Dest = _VBic(SrcSize, SrcSize, Src2, Src1); StoreResult(FPRClass, Op, Dest, -1); } -template +template void OpDispatchBuilder::VHADDPOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is256Bit = SrcSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); DeriveOp(Res, IROp, _VFAddP(SrcSize, ElementSize, Src1, Src2)); - OrderedNode *Dest = Res; - if (Is256Bit) { + OrderedNode* Dest = Res; + if (Is256Bit) { Dest = _VInsElement(SrcSize, 8, 1, 2, Res, Res); Dest = _VInsElement(SrcSize, 8, 2, 1, Dest, Res); } @@ -1739,26 +1505,22 @@ void OpDispatchBuilder::VHADDPOp(OpcodeArgs) { StoreResult(FPRClass, Op, Dest, -1); } -template -void OpDispatchBuilder::VHADDPOp(OpcodeArgs); -template -void OpDispatchBuilder::VHADDPOp(OpcodeArgs); -template -void OpDispatchBuilder::VHADDPOp(OpcodeArgs); -template -void OpDispatchBuilder::VHADDPOp(OpcodeArgs); +template void OpDispatchBuilder::VHADDPOp(OpcodeArgs); +template void OpDispatchBuilder::VHADDPOp(OpcodeArgs); +template void OpDispatchBuilder::VHADDPOp(OpcodeArgs); +template void OpDispatchBuilder::VHADDPOp(OpcodeArgs); -template +template void OpDispatchBuilder::VBROADCASTOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Result{}; + OrderedNode* Result {}; if (Op->Src[0].IsGPR()) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); Result = _VDupElement(DstSize, ElementSize, Src, 0); } else { // Get the address to broadcast from into a GPR. - OrderedNode *Address = MakeSegmentAddress(Op, Op->Src[0], CTX->GetGPRSize()); + OrderedNode* Address = MakeSegmentAddress(Op, Op->Src[0], CTX->GetGPRSize()); Result = _VBroadcastFromMem(DstSize, ElementSize, Address); } @@ -1768,26 +1530,19 @@ void OpDispatchBuilder::VBROADCASTOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VBROADCASTOp<1>(OpcodeArgs); -template -void OpDispatchBuilder::VBROADCASTOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VBROADCASTOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VBROADCASTOp<8>(OpcodeArgs); -template -void OpDispatchBuilder::VBROADCASTOp<16>(OpcodeArgs); +template void OpDispatchBuilder::VBROADCASTOp<1>(OpcodeArgs); +template void OpDispatchBuilder::VBROADCASTOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VBROADCASTOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VBROADCASTOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VBROADCASTOp<16>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PINSROpImpl(OpcodeArgs, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, - const X86Tables::DecodedOperand& Imm) { +OrderedNode* OpDispatchBuilder::PINSROpImpl(OpcodeArgs, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, const X86Tables::DecodedOperand& Imm) { const auto Size = GetDstSize(Op); const auto NumElements = Size / ElementSize; LOGMAN_THROW_A_FMT(Imm.IsLiteral(), "Imm needs to be literal here"); const uint64_t Index = Imm.Data.Literal.Value & (NumElements - 1); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, Size, Op->Flags); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, Size, Op->Flags); if (Src2Op.IsGPR()) { // If the source is a GPR then convert directly from the GPR. @@ -1802,21 +1557,17 @@ OrderedNode* OpDispatchBuilder::PINSROpImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::PINSROp(OpcodeArgs) { - OrderedNode *Result = PINSROpImpl(Op, ElementSize, Op->Dest, Op->Src[0], Op->Src[1]); + OrderedNode* Result = PINSROpImpl(Op, ElementSize, Op->Dest, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PINSROp<1>(OpcodeArgs); -template -void OpDispatchBuilder::PINSROp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PINSROp<4>(OpcodeArgs); -template -void OpDispatchBuilder::PINSROp<8>(OpcodeArgs); +template void OpDispatchBuilder::PINSROp<1>(OpcodeArgs); +template void OpDispatchBuilder::PINSROp<2>(OpcodeArgs); +template void OpDispatchBuilder::PINSROp<4>(OpcodeArgs); +template void OpDispatchBuilder::PINSROp<8>(OpcodeArgs); void OpDispatchBuilder::VPINSRBOp(OpcodeArgs) { - OrderedNode *Result = PINSROpImpl(Op, 1, Op->Src[0], Op->Src[1], Op->Src[2]); + OrderedNode* Result = PINSROpImpl(Op, 1, Op->Src[0], Op->Src[1], Op->Src[2]); if (Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { Result = _VMov(16, Result); } @@ -1825,7 +1576,7 @@ void OpDispatchBuilder::VPINSRBOp(OpcodeArgs) { void OpDispatchBuilder::VPINSRDQOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); - OrderedNode *Result = PINSROpImpl(Op, SrcSize, Op->Src[0], Op->Src[1], Op->Src[2]); + OrderedNode* Result = PINSROpImpl(Op, SrcSize, Op->Src[0], Op->Src[1], Op->Src[2]); if (Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { Result = _VMov(16, Result); } @@ -1833,15 +1584,14 @@ void OpDispatchBuilder::VPINSRDQOp(OpcodeArgs) { } void OpDispatchBuilder::VPINSRWOp(OpcodeArgs) { - OrderedNode *Result = PINSROpImpl(Op, 2, Op->Src[0], Op->Src[1], Op->Src[2]); + OrderedNode* Result = PINSROpImpl(Op, 2, Op->Src[0], Op->Src[1], Op->Src[2]); if (Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { Result = _VMov(16, Result); } StoreResult(FPRClass, Op, Result, -1); } -OrderedNode* OpDispatchBuilder::InsertPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, +OrderedNode* OpDispatchBuilder::InsertPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm) { LOGMAN_THROW_A_FMT(Imm.IsLiteral(), "Imm needs to be literal here"); const uint8_t ImmValue = Imm.Data.Literal.Value; @@ -1851,7 +1601,7 @@ OrderedNode* OpDispatchBuilder::InsertPSOpImpl(OpcodeArgs, const X86Tables::Deco const auto DstSize = GetDstSize(Op); - OrderedNode *Dest{}; + OrderedNode* Dest {}; if (ZMask != 0xF) { // Only need to load destination if it isn't a full zero Dest = LoadSource_WithOpSize(FPRClass, Op, Src1, DstSize, Op->Flags); @@ -1859,7 +1609,7 @@ OrderedNode* OpDispatchBuilder::InsertPSOpImpl(OpcodeArgs, const X86Tables::Deco if ((ZMask & (1 << CountD)) == 0) { // In the case that ZMask overwrites the destination element, then don't even insert - OrderedNode *Src{}; + OrderedNode* Src {}; if (Src2.IsGPR()) { Src = LoadSource(FPRClass, Op, Src2, Op->Flags); } else { @@ -1889,12 +1639,12 @@ OrderedNode* OpDispatchBuilder::InsertPSOpImpl(OpcodeArgs, const X86Tables::Deco } void OpDispatchBuilder::InsertPSOp(OpcodeArgs) { - OrderedNode *Result = InsertPSOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1]); + OrderedNode* Result = InsertPSOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VINSERTPSOp(OpcodeArgs) { - OrderedNode *Result = InsertPSOpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2]); + OrderedNode* Result = InsertPSOpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2]); StoreResult(FPRClass, Op, Result, -1); } @@ -1902,7 +1652,7 @@ template void OpDispatchBuilder::PExtrOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); uint64_t Index = Op->Src[1].Data.Literal.Value; @@ -1922,101 +1672,88 @@ void OpDispatchBuilder::PExtrOp(OpcodeArgs) { if (Op->Dest.IsGPR()) { const uint8_t GPRSize = CTX->GetGPRSize(); // Extract already zero extends the result. - OrderedNode *Result = _VExtractToGPR(16, OverridenElementSize, Src, Index); + OrderedNode* Result = _VExtractToGPR(16, OverridenElementSize, Src, Index); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Result, GPRSize, -1); return; } // If we are storing to memory then we store the size of the element extracted - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false}); _VStoreVectorElement(16, OverridenElementSize, Src, Index, Dest); } -template -void OpDispatchBuilder::PExtrOp<1>(OpcodeArgs); -template -void OpDispatchBuilder::PExtrOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PExtrOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::PExtrOp<8>(OpcodeArgs); +template void OpDispatchBuilder::PExtrOp<1>(OpcodeArgs); +template void OpDispatchBuilder::PExtrOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PExtrOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PExtrOp<8>(OpcodeArgs); void OpDispatchBuilder::VEXTRACT128Op(OpcodeArgs) { const auto DstIsXMM = Op->Dest.IsGPR(); const auto StoreSize = DstIsXMM ? 32 : 16; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src[1] needs to be literal here"); const auto Selector = Op->Src[1].Data.Literal.Value & 0b1; // A selector of zero is the same as doing a 128-bit vector move. if (Selector == 0) { - OrderedNode *Result = DstIsXMM ? _VMov(16, Src) : Src; + OrderedNode* Result = DstIsXMM ? _VMov(16, Src) : Src; StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, StoreSize, -1); return; } // Otherwise replicate the element and only store the first 128-bits. - OrderedNode *Result = _VDupElement(32, 16, Src, Selector); + OrderedNode* Result = _VDupElement(32, 16, Src, Selector); if (DstIsXMM) { Result = _VMov(16, Result); } StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, StoreSize, -1); } -OrderedNode* OpDispatchBuilder::PSIGNImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::PSIGNImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2) { const auto Size = GetSrcSize(Op); if (CTX->BackendFeatures.SupportsSaturatingRoundingShifts) { - OrderedNode *Control = _VSQSHL(Size, ElementSize, Src2, (ElementSize * 8) - 1); + OrderedNode* Control = _VSQSHL(Size, ElementSize, Src2, (ElementSize * 8) - 1); Control = _VSRSHR(Size, ElementSize, Control, (ElementSize * 8) - 1); return _VMul(Size, ElementSize, Src1, Control); - } - else { + } else { auto NegVec = _VNeg(Size, ElementSize, Src1); - OrderedNode *CmpLT = _VCMPLTZ(Size, ElementSize, Src2); - OrderedNode *CmpEQ = _VCMPEQZ(Size, ElementSize, Src2); + OrderedNode* CmpLT = _VCMPLTZ(Size, ElementSize, Src2); + OrderedNode* CmpEQ = _VCMPEQZ(Size, ElementSize, Src2); auto BSLResult = _VBSL(Size, CmpLT, NegVec, Src1); return _VBic(Size, Size, BSLResult, CmpEQ); } } -template +template void OpDispatchBuilder::PSIGN(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); OrderedNode* Res = PSIGNImpl(Op, ElementSize, Dest, Src); StoreResult(FPRClass, Op, Res, -1); } -template -void OpDispatchBuilder::PSIGN<1>(OpcodeArgs); -template -void OpDispatchBuilder::PSIGN<2>(OpcodeArgs); -template -void OpDispatchBuilder::PSIGN<4>(OpcodeArgs); +template void OpDispatchBuilder::PSIGN<1>(OpcodeArgs); +template void OpDispatchBuilder::PSIGN<2>(OpcodeArgs); +template void OpDispatchBuilder::PSIGN<4>(OpcodeArgs); -template +template void OpDispatchBuilder::VPSIGN(OpcodeArgs) { - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); OrderedNode* Res = PSIGNImpl(Op, ElementSize, Src1, Src2); StoreResult(FPRClass, Op, Res, -1); } -template -void OpDispatchBuilder::VPSIGN<1>(OpcodeArgs); -template -void OpDispatchBuilder::VPSIGN<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPSIGN<4>(OpcodeArgs); +template void OpDispatchBuilder::VPSIGN<1>(OpcodeArgs); +template void OpDispatchBuilder::VPSIGN<2>(OpcodeArgs); +template void OpDispatchBuilder::VPSIGN<4>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PSRLDOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, OrderedNode *ShiftVec) { +OrderedNode* OpDispatchBuilder::PSRLDOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, OrderedNode* ShiftVec) { const auto Size = GetSrcSize(Op); // Incoming element size for the shift source is always 8 @@ -2025,28 +1762,25 @@ OrderedNode* OpDispatchBuilder::PSRLDOpImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::PSRLDOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PSRLDOpImpl(Op, ElementSize, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PSRLDOpImpl(Op, ElementSize, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PSRLDOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PSRLDOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::PSRLDOp<8>(OpcodeArgs); +template void OpDispatchBuilder::PSRLDOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PSRLDOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PSRLDOp<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VPSRLDOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is128Bit = DstSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Shift = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = PSRLDOpImpl(Op, ElementSize, Src, Shift); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Shift = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = PSRLDOpImpl(Op, ElementSize, Src, Shift); if (Is128Bit) { Result = _VMov(16, Result); @@ -2054,12 +1788,9 @@ void OpDispatchBuilder::VPSRLDOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPSRLDOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPSRLDOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPSRLDOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPSRLDOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPSRLDOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPSRLDOp<8>(OpcodeArgs); template void OpDispatchBuilder::PSRLI(OpcodeArgs) { @@ -2072,19 +1803,16 @@ void OpDispatchBuilder::PSRLI(OpcodeArgs) { const auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Shift = _VUShrI(Size, ElementSize, Dest, ShiftConstant); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Shift = _VUShrI(Size, ElementSize, Dest, ShiftConstant); StoreResult(FPRClass, Op, Shift, -1); } -template -void OpDispatchBuilder::PSRLI<2>(OpcodeArgs); -template -void OpDispatchBuilder::PSRLI<4>(OpcodeArgs); -template -void OpDispatchBuilder::PSRLI<8>(OpcodeArgs); +template void OpDispatchBuilder::PSRLI<2>(OpcodeArgs); +template void OpDispatchBuilder::PSRLI<4>(OpcodeArgs); +template void OpDispatchBuilder::PSRLI<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VPSRLIOp(OpcodeArgs) { const auto Size = GetSrcSize(Op); const auto Is128Bit = Size == Core::CPUState::XMM_SSE_REG_SIZE; @@ -2092,8 +1820,8 @@ void OpDispatchBuilder::VPSRLIOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t ShiftConstant = Op->Src[1].Data.Literal.Value; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = Src; + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = Src; if (ShiftConstant != 0) [[likely]] { Result = _VUShrI(Size, ElementSize, Src, ShiftConstant); @@ -2106,15 +1834,11 @@ void OpDispatchBuilder::VPSRLIOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPSRLIOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPSRLIOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPSRLIOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPSRLIOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPSRLIOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPSRLIOp<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PSLLIImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, uint64_t Shift) { +OrderedNode* OpDispatchBuilder::PSLLIImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, uint64_t Shift) { if (Shift == 0) [[unlikely]] { // If zero-shift then just return the source. return Src; @@ -2132,28 +1856,25 @@ void OpDispatchBuilder::PSLLI(OpcodeArgs) { return; } - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Result = PSLLIImpl(Op, ElementSize, Dest, ShiftConstant); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Result = PSLLIImpl(Op, ElementSize, Dest, ShiftConstant); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PSLLI<2>(OpcodeArgs); -template -void OpDispatchBuilder::PSLLI<4>(OpcodeArgs); -template -void OpDispatchBuilder::PSLLI<8>(OpcodeArgs); +template void OpDispatchBuilder::PSLLI<2>(OpcodeArgs); +template void OpDispatchBuilder::PSLLI<4>(OpcodeArgs); +template void OpDispatchBuilder::PSLLI<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VPSLLIOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t ShiftConstant = Op->Src[1].Data.Literal.Value; const auto DstSize = GetDstSize(Op); const auto Is128Bit = DstSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PSLLIImpl(Op, ElementSize, Src, ShiftConstant); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PSLLIImpl(Op, ElementSize, Src, ShiftConstant); if (ShiftConstant == 0 && Is128Bit) { Result = _VMov(16, Result); } @@ -2161,15 +1882,11 @@ void OpDispatchBuilder::VPSLLIOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPSLLIOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPSLLIOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPSLLIOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPSLLIOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPSLLIOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPSLLIOp<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PSLLImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, OrderedNode *ShiftVec) { +OrderedNode* OpDispatchBuilder::PSLLImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, OrderedNode* ShiftVec) { const auto Size = GetDstSize(Op); // Incoming element size for the shift source is always 8 @@ -2178,28 +1895,25 @@ OrderedNode* OpDispatchBuilder::PSLLImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::PSLL(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PSLLImpl(Op, ElementSize, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PSLLImpl(Op, ElementSize, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PSLL<2>(OpcodeArgs); -template -void OpDispatchBuilder::PSLL<4>(OpcodeArgs); -template -void OpDispatchBuilder::PSLL<8>(OpcodeArgs); +template void OpDispatchBuilder::PSLL<2>(OpcodeArgs); +template void OpDispatchBuilder::PSLL<4>(OpcodeArgs); +template void OpDispatchBuilder::PSLL<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VPSLLOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is128Bit = DstSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], 16, Op->Flags); - OrderedNode *Result = PSLLImpl(Op, ElementSize, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], 16, Op->Flags); + OrderedNode* Result = PSLLImpl(Op, ElementSize, Src1, Src2); if (Is128Bit) { Result = _VMov(16, Result); @@ -2207,15 +1921,11 @@ void OpDispatchBuilder::VPSLLOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPSLLOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPSLLOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPSLLOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPSLLOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPSLLOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPSLLOp<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PSRAOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, OrderedNode *ShiftVec) { +OrderedNode* OpDispatchBuilder::PSRAOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, OrderedNode* ShiftVec) { const auto Size = GetDstSize(Op); // Incoming element size for the shift source is always 8 @@ -2224,26 +1934,24 @@ OrderedNode* OpDispatchBuilder::PSRAOpImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::PSRAOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PSRAOpImpl(Op, ElementSize, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PSRAOpImpl(Op, ElementSize, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PSRAOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PSRAOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PSRAOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PSRAOp<4>(OpcodeArgs); -template +template void OpDispatchBuilder::VPSRAOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is128Bit = DstSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = PSRAOpImpl(Op, ElementSize, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = PSRAOpImpl(Op, ElementSize, Src1, Src2); if (Is128Bit) { Result = _VMov(16, Result); @@ -2251,10 +1959,8 @@ void OpDispatchBuilder::VPSRAOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPSRAOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPSRAOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPSRAOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPSRAOp<4>(OpcodeArgs); void OpDispatchBuilder::PSRLDQ(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); @@ -2266,8 +1972,8 @@ void OpDispatchBuilder::PSRLDQ(OpcodeArgs) { const auto Size = GetDstSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Result = LoadAndCacheNamedVectorConstant(Size, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Result = LoadAndCacheNamedVectorConstant(Size, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); if (Shift < Size) { Result = _VExtr(Size, 1, Result, Dest, Shift); @@ -2282,9 +1988,9 @@ void OpDispatchBuilder::VPSRLDQOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t Shift = Op->Src[1].Data.Literal.Value; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result{}; + OrderedNode* Result {}; if (Shift == 0) [[unlikely]] { if (Is128Bit) { Result = _VMov(16, Src); @@ -2300,8 +2006,8 @@ void OpDispatchBuilder::VPSRLDQOp(OpcodeArgs) { } } else { if (Shift < Core::CPUState::XMM_SSE_REG_SIZE) { - OrderedNode *ResultBottom = _VExtr(16, 1, Result, Src, Shift); - OrderedNode *ResultTop = _VExtr(DstSize, 1, Result, Src, 16 + Shift); + OrderedNode* ResultBottom = _VExtr(16, 1, Result, Src, Shift); + OrderedNode* ResultTop = _VExtr(DstSize, 1, Result, Src, 16 + Shift); Result = _VInsElement(DstSize, 16, 1, 0, ResultBottom, ResultTop); } @@ -2321,8 +2027,8 @@ void OpDispatchBuilder::PSLLDQ(OpcodeArgs) { const auto Size = GetDstSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Result = LoadAndCacheNamedVectorConstant(Size, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Result = LoadAndCacheNamedVectorConstant(Size, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); if (Shift < Size) { Result = _VExtr(Size, 1, Dest, Result, Size - Shift); } @@ -2337,9 +2043,9 @@ void OpDispatchBuilder::VPSLLDQOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t Shift = Op->Src[1].Data.Literal.Value; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = Src; + OrderedNode* Result = Src; if (Shift == 0) { if (Is128Bit) { @@ -2353,8 +2059,8 @@ void OpDispatchBuilder::VPSLLDQOp(OpcodeArgs) { } } else { if (Shift < Core::CPUState::XMM_SSE_REG_SIZE) { - OrderedNode *ResultBottom = _VExtr(16, 1, Src, Result, 16 - Shift); - OrderedNode* ResultTop = _VExtr(DstSize, 1, Src, Result, DstSize - Shift); + OrderedNode* ResultBottom = _VExtr(16, 1, Src, Result, 16 - Shift); + OrderedNode* ResultTop = _VExtr(DstSize, 1, Src, Result, DstSize - Shift); Result = _VInsElement(DstSize, 16, 1, 0, ResultBottom, ResultTop); } @@ -2374,25 +2080,23 @@ void OpDispatchBuilder::PSRAIOp(OpcodeArgs) { const auto Size = GetDstSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Result = _VSShrI(Size, ElementSize, Dest, Shift); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Result = _VSShrI(Size, ElementSize, Dest, Shift); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PSRAIOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PSRAIOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PSRAIOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PSRAIOp<4>(OpcodeArgs); -template +template void OpDispatchBuilder::VPSRAIOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t Shift = Op->Src[1].Data.Literal.Value; const auto Size = GetDstSize(Op); const auto Is128Bit = Size == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = Src; + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = Src; if (Shift != 0) [[likely]] { Result = _VSShrI(Size, ElementSize, Src, Shift); @@ -2405,17 +2109,15 @@ void OpDispatchBuilder::VPSRAIOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPSRAIOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPSRAIOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPSRAIOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPSRAIOp<4>(OpcodeArgs); void OpDispatchBuilder::AVXVariableShiftImpl(OpcodeArgs, IROps IROp) { const auto DstSize = GetDstSize(Op); const auto SrcSize = GetSrcSize(Op); - OrderedNode *Vector = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], DstSize, Op->Flags); - OrderedNode *ShiftVector = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], DstSize, Op->Flags); + OrderedNode* Vector = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], DstSize, Op->Flags); + OrderedNode* ShiftVector = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], DstSize, Op->Flags); DeriveOp(Shift, IROp, _VUShr(DstSize, SrcSize, Vector, ShiftVector, true)); @@ -2439,8 +2141,8 @@ void OpDispatchBuilder::MOVDDUPOp(OpcodeArgs) { // unnecessarily zero extend the vector. Otherwise, if // memory, then we want to load the element size exactly. const auto SrcSize = Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); - OrderedNode *Res = _VDupElement(16, GetSrcSize(Op), Src, 0); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Res = _VDupElement(16, GetSrcSize(Op), Src, 0); StoreResult(FPRClass, Op, Res, -1); } @@ -2451,10 +2153,10 @@ void OpDispatchBuilder::VMOVDDUPOp(OpcodeArgs) { const auto Is256Bit = SrcSize == Core::CPUState::XMM_AVX_REG_SIZE; const auto MemSize = Is256Bit ? 32 : 8; - OrderedNode *Src = IsSrcGPR ? LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags) - : LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], MemSize, Op->Flags); + OrderedNode* Src = IsSrcGPR ? LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags) : + LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], MemSize, Op->Flags); - OrderedNode *Res{}; + OrderedNode* Res {}; if (Is256Bit) { Res = _VTrn(SrcSize, 8, Src, Src); } else { @@ -2464,26 +2166,23 @@ void OpDispatchBuilder::VMOVDDUPOp(OpcodeArgs) { StoreResult(FPRClass, Op, Res, -1); } -OrderedNode* OpDispatchBuilder::CVTGPR_To_FPRImpl(OpcodeArgs, size_t DstElementSize, - const X86Tables::DecodedOperand& Src1Op, +OrderedNode* OpDispatchBuilder::CVTGPR_To_FPRImpl(OpcodeArgs, size_t DstElementSize, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op) { const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, 16, Op->Flags); - OrderedNode *Converted{}; + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, 16, Op->Flags); + OrderedNode* Converted {}; if (Src2Op.IsGPR()) { // If the source is a GPR then convert directly from the GPR. auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, CTX->GetGPRSize(), Op->Flags); Converted = _Float_FromGPR_S(DstElementSize, SrcSize, Src2); - } - else if (SrcSize != DstElementSize) { + } else if (SrcSize != DstElementSize) { // If the source is from memory but the Source size and destination size aren't the same, // then it is more optimal to load in to a GPR and convert between GPR->FPR. // ARM GPR->FPR conversion supports different size source and destinations while FPR->FPR doesn't. auto Src2 = LoadSource(GPRClass, Op, Src2Op, Op->Flags); Converted = _Float_FromGPR_S(DstElementSize, SrcSize, Src2); - } - else { + } else { // In the case of cvtsi2s{s,d} where the source and destination are the same size, // then it is more optimal to load in to the FPR register directly and convert there. auto Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); @@ -2495,24 +2194,20 @@ OrderedNode* OpDispatchBuilder::CVTGPR_To_FPRImpl(OpcodeArgs, size_t DstElementS template void OpDispatchBuilder::CVTGPR_To_FPR(OpcodeArgs) { - OrderedNode *Result = CVTGPR_To_FPRImpl(Op, DstElementSize, Op->Dest, Op->Src[0]); + OrderedNode* Result = CVTGPR_To_FPRImpl(Op, DstElementSize, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::CVTGPR_To_FPR<4>(OpcodeArgs); -template -void OpDispatchBuilder::CVTGPR_To_FPR<8>(OpcodeArgs); +template void OpDispatchBuilder::CVTGPR_To_FPR<4>(OpcodeArgs); +template void OpDispatchBuilder::CVTGPR_To_FPR<8>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXCVTGPR_To_FPR(OpcodeArgs) { - OrderedNode *Result = CVTGPR_To_FPRImpl(Op, DstElementSize, Op->Src[0], Op->Src[1]); + OrderedNode* Result = CVTGPR_To_FPRImpl(Op, DstElementSize, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::AVXCVTGPR_To_FPR<4>(OpcodeArgs); -template -void OpDispatchBuilder::AVXCVTGPR_To_FPR<8>(OpcodeArgs); +template void OpDispatchBuilder::AVXCVTGPR_To_FPR<4>(OpcodeArgs); +template void OpDispatchBuilder::AVXCVTGPR_To_FPR<8>(OpcodeArgs); template void OpDispatchBuilder::CVTFPR_To_GPR(OpcodeArgs) { @@ -2520,7 +2215,7 @@ void OpDispatchBuilder::CVTFPR_To_GPR(OpcodeArgs) { // unnecessarily zero extend the vector. Otherwise, if // memory, then we want to load the element size exactly. const auto SrcSize = Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); // GPR size is determined by REX.W // Source Element size is determined by instruction @@ -2528,28 +2223,23 @@ void OpDispatchBuilder::CVTFPR_To_GPR(OpcodeArgs) { if constexpr (HostRoundingMode) { Src = _Float_ToGPR_S(GPRSize, SrcElementSize, Src); - } - else { + } else { Src = _Float_ToGPR_ZS(GPRSize, SrcElementSize, Src); } StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Src, GPRSize, -1); } -template -void OpDispatchBuilder::CVTFPR_To_GPR<4, true>(OpcodeArgs); -template -void OpDispatchBuilder::CVTFPR_To_GPR<4, false>(OpcodeArgs); +template void OpDispatchBuilder::CVTFPR_To_GPR<4, true>(OpcodeArgs); +template void OpDispatchBuilder::CVTFPR_To_GPR<4, false>(OpcodeArgs); -template -void OpDispatchBuilder::CVTFPR_To_GPR<8, true>(OpcodeArgs); -template -void OpDispatchBuilder::CVTFPR_To_GPR<8, false>(OpcodeArgs); +template void OpDispatchBuilder::CVTFPR_To_GPR<8, true>(OpcodeArgs); +template void OpDispatchBuilder::CVTFPR_To_GPR<8, false>(OpcodeArgs); OrderedNode* OpDispatchBuilder::Vector_CVT_Int_To_FloatImpl(OpcodeArgs, size_t SrcElementSize, bool Widen) { const size_t Size = GetDstSize(Op); - OrderedNode *Src = [&] { + OrderedNode* Src = [&] { if (Widen) { // If loading a vector, use the full size, so we don't // unnecessarily zero extend the vector. Otherwise, if @@ -2572,32 +2262,27 @@ OrderedNode* OpDispatchBuilder::Vector_CVT_Int_To_FloatImpl(OpcodeArgs, size_t S template void OpDispatchBuilder::Vector_CVT_Int_To_Float(OpcodeArgs) { - OrderedNode *Result = Vector_CVT_Int_To_FloatImpl(Op, SrcElementSize, Widen); + OrderedNode* Result = Vector_CVT_Int_To_FloatImpl(Op, SrcElementSize, Widen); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::Vector_CVT_Int_To_Float<4, true>(OpcodeArgs); -template -void OpDispatchBuilder::Vector_CVT_Int_To_Float<4, false>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Int_To_Float<4, true>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Int_To_Float<4, false>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVector_CVT_Int_To_Float(OpcodeArgs) { - OrderedNode *Result = Vector_CVT_Int_To_FloatImpl(Op, SrcElementSize, Widen); + OrderedNode* Result = Vector_CVT_Int_To_FloatImpl(Op, SrcElementSize, Widen); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::AVXVector_CVT_Int_To_Float<4, false>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVector_CVT_Int_To_Float<4, true>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Int_To_Float<4, false>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Int_To_Float<4, true>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::Vector_CVT_Float_To_IntImpl(OpcodeArgs, size_t SrcElementSize, - bool Narrow, bool HostRoundingMode) { +OrderedNode* OpDispatchBuilder::Vector_CVT_Float_To_IntImpl(OpcodeArgs, size_t SrcElementSize, bool Narrow, bool HostRoundingMode) { const size_t DstSize = GetDstSize(Op); size_t ElementSize = SrcElementSize; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); if (Narrow) { Src = _Vector_FToF(DstSize, SrcElementSize >> 1, Src, SrcElementSize); @@ -2614,31 +2299,26 @@ OrderedNode* OpDispatchBuilder::Vector_CVT_Float_To_IntImpl(OpcodeArgs, size_t S template void OpDispatchBuilder::Vector_CVT_Float_To_Int(OpcodeArgs) { const size_t DstSize = GetDstSize(Op); - OrderedNode *Result = Vector_CVT_Float_To_IntImpl(Op, SrcElementSize, Narrow, HostRoundingMode); + OrderedNode* Result = Vector_CVT_Float_To_IntImpl(Op, SrcElementSize, Narrow, HostRoundingMode); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::Vector_CVT_Float_To_Int<4, false, false>(OpcodeArgs); -template -void OpDispatchBuilder::Vector_CVT_Float_To_Int<4, false, true>(OpcodeArgs); -template -void OpDispatchBuilder::Vector_CVT_Float_To_Int<4, true, false>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Float_To_Int<4, false, false>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Float_To_Int<4, false, true>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Float_To_Int<4, true, false>(OpcodeArgs); -template -void OpDispatchBuilder::Vector_CVT_Float_To_Int<8, true, true>(OpcodeArgs); -template -void OpDispatchBuilder::Vector_CVT_Float_To_Int<8, true, false>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Float_To_Int<8, true, true>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Float_To_Int<8, true, false>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVector_CVT_Float_To_Int(OpcodeArgs) { const auto DstSize = GetDstSize(Op); // VCVTPD2DQ/VCVTTPD2DQ only use the bottom lane, even for the 256-bit version. const auto Truncate = SrcElementSize == 8 && Narrow; - OrderedNode *Result = Vector_CVT_Float_To_IntImpl(Op, SrcElementSize, Narrow, HostRoundingMode); + OrderedNode* Result = Vector_CVT_Float_To_IntImpl(Op, SrcElementSize, Narrow, HostRoundingMode); if (Truncate) { Result = _VMov(16, Result); @@ -2646,53 +2326,44 @@ void OpDispatchBuilder::AVXVector_CVT_Float_To_Int(OpcodeArgs) { StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } -template -void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<4, false, false>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<4, false, true>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<4, false, false>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<4, false, true>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<8, true, false>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<8, true, true>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<8, true, false>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Float_To_Int<8, true, true>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::Scalar_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstElementSize, size_t SrcElementSize, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op) { +OrderedNode* OpDispatchBuilder::Scalar_CVT_Float_To_FloatImpl( + OpcodeArgs, size_t DstElementSize, size_t SrcElementSize, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op) { // In the case of vectors, we can just specify the full vector length, // so that we don't unnecessarily zero-extend the entire vector. // Otherwise, if it's a memory load, then we only want to load its exact size. const auto Src2Size = Src2Op.IsGPR() ? 16U : SrcElementSize; - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, 16, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, Src2Size, Op->Flags); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, 16, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, Src2Size, Op->Flags); - OrderedNode *Converted = _Float_FToF(DstElementSize, SrcElementSize, Src2); + OrderedNode* Converted = _Float_FToF(DstElementSize, SrcElementSize, Src2); return _VInsElement(16, DstElementSize, 0, 0, Src1, Converted); } template void OpDispatchBuilder::Scalar_CVT_Float_To_Float(OpcodeArgs) { - OrderedNode *Result = Scalar_CVT_Float_To_FloatImpl(Op, DstElementSize, SrcElementSize, Op->Dest, Op->Src[0]); + OrderedNode* Result = Scalar_CVT_Float_To_FloatImpl(Op, DstElementSize, SrcElementSize, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::Scalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); -template -void OpDispatchBuilder::Scalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); +template void OpDispatchBuilder::Scalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template void OpDispatchBuilder::Scalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXScalar_CVT_Float_To_Float(OpcodeArgs) { - OrderedNode *Result = Scalar_CVT_Float_To_FloatImpl(Op, DstElementSize, SrcElementSize, Op->Src[0], Op->Src[1]); + OrderedNode* Result = Scalar_CVT_Float_To_FloatImpl(Op, DstElementSize, SrcElementSize, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::AVXScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); -template -void OpDispatchBuilder::AVXScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); +template void OpDispatchBuilder::AVXScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template void OpDispatchBuilder::AVXScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); void OpDispatchBuilder::Vector_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstElementSize, size_t SrcElementSize, bool IsAVX) { const auto SrcSize = GetSrcSize(Op); @@ -2700,13 +2371,11 @@ void OpDispatchBuilder::Vector_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstElem const auto IsFloatSrc = SrcElementSize == 4; const auto Is128Bit = SrcSize == Core::CPUState::XMM_SSE_REG_SIZE; - const auto LoadSize = IsFloatSrc && !Op->Src[0].IsGPR() ? - SrcSize / 2 : - SrcSize; + const auto LoadSize = IsFloatSrc && !Op->Src[0].IsGPR() ? SrcSize / 2 : SrcSize; - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], LoadSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], LoadSize, Op->Flags); - OrderedNode *Result{}; + OrderedNode* Result {}; if (DstElementSize > SrcElementSize) { Result = _Vector_FToF(SrcSize, SrcElementSize << 1, Src, SrcElementSize); } else { @@ -2729,22 +2398,18 @@ template void OpDispatchBuilder::Vector_CVT_Float_To_Float(OpcodeArgs) { Vector_CVT_Float_To_FloatImpl(Op, DstElementSize, SrcElementSize, false); } -template -void OpDispatchBuilder::Vector_CVT_Float_To_Float<4, 8>(OpcodeArgs); -template -void OpDispatchBuilder::Vector_CVT_Float_To_Float<8, 4>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template void OpDispatchBuilder::Vector_CVT_Float_To_Float<8, 4>(OpcodeArgs); template void OpDispatchBuilder::AVXVector_CVT_Float_To_Float(OpcodeArgs) { Vector_CVT_Float_To_FloatImpl(Op, DstElementSize, SrcElementSize, true); } -template -void OpDispatchBuilder::AVXVector_CVT_Float_To_Float<4, 8>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVector_CVT_Float_To_Float<8, 4>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template void OpDispatchBuilder::AVXVector_CVT_Float_To_Float<8, 4>(OpcodeArgs); void OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); // Always 32-bit. size_t ElementSize = 4; @@ -2765,7 +2430,7 @@ void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int(OpcodeArgs) { // unnecessarily zero extend the vector. Otherwise, if // memory, then we want to load the element size exactly. const auto SrcSize = Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); size_t ElementSize = SrcElementSize; size_t Size = GetDstSize(Op); @@ -2777,37 +2442,32 @@ void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int(OpcodeArgs) { if constexpr (HostRoundingMode) { Src = _Vector_FToS(Size, ElementSize, Src); - } - else { + } else { Src = _Vector_FToZS(Size, ElementSize, Src); } StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Src, Size, -1); } -template -void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<4, false, false>(OpcodeArgs); -template -void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<4, false, true>(OpcodeArgs); -template -void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<8, true, false>(OpcodeArgs); -template -void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<8, true, true>(OpcodeArgs); +template void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<4, false, false>(OpcodeArgs); +template void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<4, false, true>(OpcodeArgs); +template void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<8, true, false>(OpcodeArgs); +template void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<8, true, true>(OpcodeArgs); void OpDispatchBuilder::MASKMOVOp(OpcodeArgs) { const auto Size = GetSrcSize(Op); - OrderedNode *MaskSrc = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* MaskSrc = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); // Mask only cares about the top bit of each byte MaskSrc = _VCMPLTZ(Size, 1, MaskSrc); // Vector that will overwrite byte elements. - OrderedNode *VectorSrc = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* VectorSrc = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); // RDI source (DS prefix by default) auto MemDest = MakeSegmentAddress(X86State::REG_RDI, Op->Flags, X86Tables::DecodeFlags::FLAG_DS_PREFIX); - OrderedNode *XMMReg = _LoadMem(FPRClass, Size, MemDest, 1); + OrderedNode* XMMReg = _LoadMem(FPRClass, Size, MemDest, 1); // If the Mask element high bit is set then overwrite the element with the source, else keep the memory variant XMMReg = _VBSL(Size, MaskSrc, VectorSrc, XMMReg); @@ -2815,24 +2475,23 @@ void OpDispatchBuilder::MASKMOVOp(OpcodeArgs) { } void OpDispatchBuilder::VMASKMOVOpImpl(OpcodeArgs, size_t ElementSize, size_t DataSize, bool IsStore, - const X86Tables::DecodedOperand& MaskOp, - const X86Tables::DecodedOperand& DataOp) { + const X86Tables::DecodedOperand& MaskOp, const X86Tables::DecodedOperand& DataOp) { const auto MakeAddress = [this, Op](const X86Tables::DecodedOperand& Data) { return MakeSegmentAddress(Op, Data, CTX->GetGPRSize()); }; - OrderedNode *Mask = LoadSource_WithOpSize(FPRClass, Op, MaskOp, DataSize, Op->Flags); + OrderedNode* Mask = LoadSource_WithOpSize(FPRClass, Op, MaskOp, DataSize, Op->Flags); if (IsStore) { - OrderedNode *Data = LoadSource_WithOpSize(FPRClass, Op, DataOp, DataSize, Op->Flags); - OrderedNode *Address = MakeAddress(Op->Dest); + OrderedNode* Data = LoadSource_WithOpSize(FPRClass, Op, DataOp, DataSize, Op->Flags); + OrderedNode* Address = MakeAddress(Op->Dest); _VStoreVectorMasked(DataSize, ElementSize, Mask, Data, Address, Invalid(), MEM_OFFSET_SXTX, 1); } else { const auto Is128Bit = GetDstSize(Op) == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Address = MakeAddress(DataOp); - OrderedNode *Result = _VLoadVectorMasked(DataSize, ElementSize, Mask, Address, Invalid(), MEM_OFFSET_SXTX, 1); + OrderedNode* Address = MakeAddress(DataOp); + OrderedNode* Result = _VLoadVectorMasked(DataSize, ElementSize, Mask, Address, Invalid(), MEM_OFFSET_SXTX, 1); if (Is128Bit) { Result = _VMov(16, Result); @@ -2841,96 +2500,107 @@ void OpDispatchBuilder::VMASKMOVOpImpl(OpcodeArgs, size_t ElementSize, size_t Da } } -template +template void OpDispatchBuilder::VMASKMOVOp(OpcodeArgs) { VMASKMOVOpImpl(Op, ElementSize, GetDstSize(Op), IsStore, Op->Src[0], Op->Src[1]); } -template -void OpDispatchBuilder::VMASKMOVOp<4, false>(OpcodeArgs); -template -void OpDispatchBuilder::VMASKMOVOp<4, true>(OpcodeArgs); -template -void OpDispatchBuilder::VMASKMOVOp<8, false>(OpcodeArgs); -template -void OpDispatchBuilder::VMASKMOVOp<8, true>(OpcodeArgs); +template void OpDispatchBuilder::VMASKMOVOp<4, false>(OpcodeArgs); +template void OpDispatchBuilder::VMASKMOVOp<4, true>(OpcodeArgs); +template void OpDispatchBuilder::VMASKMOVOp<8, false>(OpcodeArgs); +template void OpDispatchBuilder::VMASKMOVOp<8, true>(OpcodeArgs); -template +template void OpDispatchBuilder::VPMASKMOVOp(OpcodeArgs) { VMASKMOVOpImpl(Op, GetSrcSize(Op), GetDstSize(Op), IsStore, Op->Src[0], Op->Src[1]); } -template -void OpDispatchBuilder::VPMASKMOVOp(OpcodeArgs); -template -void OpDispatchBuilder::VPMASKMOVOp(OpcodeArgs); +template void OpDispatchBuilder::VPMASKMOVOp(OpcodeArgs); +template void OpDispatchBuilder::VPMASKMOVOp(OpcodeArgs); void OpDispatchBuilder::MOVBetweenGPR_FPR(OpcodeArgs) { - if (Op->Dest.IsGPR() && - Op->Dest.Data.GPR.GPR >= FEXCore::X86State::REG_XMM_0) { + if (Op->Dest.IsGPR() && Op->Dest.Data.GPR.GPR >= FEXCore::X86State::REG_XMM_0) { if (Op->Src[0].IsGPR()) { // Loading from GPR and moving to Vector. - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], CTX->GetGPRSize(), Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], CTX->GetGPRSize(), Op->Flags); // zext to 128bit auto Converted = _VCastFromGPR(16, GetSrcSize(Op), Src); StoreResult(FPRClass, Op, Op->Dest, Converted, -1); - } - else { + } else { // Loading from Memory as a scalar. Zero extend - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); StoreResult(FPRClass, Op, Op->Dest, Src, -1); } - } - else { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0],Op->Flags); + } else { + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); if (Op->Dest.IsGPR()) { auto ElementSize = GetDstSize(Op); // Extract element from GPR. Zero extending in the process. Src = _VExtractToGPR(GetSrcSize(Op), ElementSize, Src, 0); StoreResult(GPRClass, Op, Op->Dest, Src, -1); - } - else { + } else { // Storing first element to memory. - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false}); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false}); _StoreMem(FPRClass, GetDstSize(Op), Dest, Src, 1); } } } -OrderedNode* OpDispatchBuilder::VFCMPOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2, uint8_t CompType) { +OrderedNode* OpDispatchBuilder::VFCMPOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2, uint8_t CompType) { const auto Size = GetSrcSize(Op); - OrderedNode *Result{}; + OrderedNode* Result {}; switch (CompType) { - case 0x00: case 0x08: case 0x10: case 0x18: // EQ - Result = _VFCMPEQ(Size, ElementSize, Src1, Src2); - break; - case 0x01: case 0x09: case 0x11: case 0x19: // LT, GT(Swapped operand) - Result = _VFCMPLT(Size, ElementSize, Src1, Src2); - break; - case 0x02: case 0x0A: case 0x12: case 0x1A: // LE, GE(Swapped operand) - Result = _VFCMPLE(Size, ElementSize, Src1, Src2); - break; - case 0x03: case 0x0B: case 0x13: case 0x1B: // Unordered - Result = _VFCMPUNO(Size, ElementSize, Src1, Src2); - break; - case 0x04: case 0x0C: case 0x14: case 0x1C: // NEQ - Result = _VFCMPNEQ(Size, ElementSize, Src1, Src2); - break; - case 0x05: case 0x0D: case 0x15: case 0x1D: // NLT, NGT(Swapped operand) - Result = _VFCMPLT(Size, ElementSize, Src1, Src2); - Result = _VNot(Size, ElementSize, Result); - break; - case 0x06: case 0x0E: case 0x16: case 0x1E: // NLE, NGE(Swapped operand) - Result = _VFCMPLE(Size, ElementSize, Src1, Src2); - Result = _VNot(Size, ElementSize, Result); - break; - case 0x07: case 0x0F: case 0x17: case 0x1F: // Ordered - Result = _VFCMPORD(Size, ElementSize, Src1, Src2); - break; - default: - LOGMAN_MSG_A_FMT("Unknown Comparison type: {}", CompType); - break; + case 0x00: + case 0x08: + case 0x10: + case 0x18: // EQ + Result = _VFCMPEQ(Size, ElementSize, Src1, Src2); + break; + case 0x01: + case 0x09: + case 0x11: + case 0x19: // LT, GT(Swapped operand) + Result = _VFCMPLT(Size, ElementSize, Src1, Src2); + break; + case 0x02: + case 0x0A: + case 0x12: + case 0x1A: // LE, GE(Swapped operand) + Result = _VFCMPLE(Size, ElementSize, Src1, Src2); + break; + case 0x03: + case 0x0B: + case 0x13: + case 0x1B: // Unordered + Result = _VFCMPUNO(Size, ElementSize, Src1, Src2); + break; + case 0x04: + case 0x0C: + case 0x14: + case 0x1C: // NEQ + Result = _VFCMPNEQ(Size, ElementSize, Src1, Src2); + break; + case 0x05: + case 0x0D: + case 0x15: + case 0x1D: // NLT, NGT(Swapped operand) + Result = _VFCMPLT(Size, ElementSize, Src1, Src2); + Result = _VNot(Size, ElementSize, Result); + break; + case 0x06: + case 0x0E: + case 0x16: + case 0x1E: // NLE, NGE(Swapped operand) + Result = _VFCMPLE(Size, ElementSize, Src1, Src2); + Result = _VNot(Size, ElementSize, Result); + break; + case 0x07: + case 0x0F: + case 0x17: + case 0x1F: // Ordered + Result = _VFCMPORD(Size, ElementSize, Src1, Src2); + break; + default: LOGMAN_MSG_A_FMT("Unknown Comparison type: {}", CompType); break; } return Result; @@ -2943,8 +2613,8 @@ void OpDispatchBuilder::VFCMPOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto DstSize = GetDstSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags); const uint8_t CompType = Op->Src[1].Data.Literal.Value; OrderedNode* Result = VFCMPOpImpl(Op, ElementSize, Dest, Src, CompType); @@ -2952,12 +2622,10 @@ void OpDispatchBuilder::VFCMPOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VFCMPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VFCMPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VFCMPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VFCMPOp<8>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVFCMPOp(OpcodeArgs) { // No need for zero-extending in the scalar case, since // all we need is an insert at the end of the operation. @@ -2967,20 +2635,18 @@ void OpDispatchBuilder::AVXVFCMPOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src[2] needs to be literal"); const uint8_t CompType = Op->Src[2].Data.Literal.Value; - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], DstSize, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], SrcSize, Op->Flags); - OrderedNode *Result = VFCMPOpImpl(Op, ElementSize, Src1, Src2, CompType); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], DstSize, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], SrcSize, Op->Flags); + OrderedNode* Result = VFCMPOpImpl(Op, ElementSize, Src1, Src2, CompType); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::AVXVFCMPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVFCMPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::AVXVFCMPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::AVXVFCMPOp<8>(OpcodeArgs); void OpDispatchBuilder::FXSaveOp(OpcodeArgs) { - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Dest); SaveX87State(Op, Mem); SaveSSEState(Mem); @@ -2991,7 +2657,7 @@ void OpDispatchBuilder::XSaveOp(OpcodeArgs) { XSaveOpImpl(Op); } -OrderedNode *OpDispatchBuilder::XSaveBase(X86Tables::DecodedOp Op) { +OrderedNode* OpDispatchBuilder::XSaveBase(X86Tables::DecodedOp Op) { return MakeSegmentAddress(Op, Op->Dest); } @@ -3000,18 +2666,16 @@ void OpDispatchBuilder::XSaveOpImpl(OpcodeArgs) { // for features that are in the lower 32 bits, so EAX only is sufficient. const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); - const auto StoreIfFlagSet = [this, OpSize](uint32_t BitIndex, auto fn, uint32_t FieldSize = 1){ - OrderedNode *Mask = LoadGPRRegister(X86State::REG_RAX); - OrderedNode *BitFlag = _Bfe(OpSize, FieldSize, BitIndex, Mask); + const auto StoreIfFlagSet = [this, OpSize](uint32_t BitIndex, auto fn, uint32_t FieldSize = 1) { + OrderedNode* Mask = LoadGPRRegister(X86State::REG_RAX); + OrderedNode* BitFlag = _Bfe(OpSize, FieldSize, BitIndex, Mask); auto CondJump_ = CondJump(BitFlag, {COND_NEQ}); auto StoreBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); SetTrueJumpTarget(CondJump_, StoreBlock); SetCurrentCodeBlock(StoreBlock); StartNewBlock(); - { - fn(); - } + { fn(); } auto Jump_ = Jump(); auto NextJumpTarget = CreateNewCodeBlockAfter(StoreBlock); SetJumpTarget(Jump_, NextJumpTarget); @@ -3029,24 +2693,24 @@ void OpDispatchBuilder::XSaveOpImpl(OpcodeArgs) { StoreIfFlagSet(1, [this, Op] { SaveSSEState(XSaveBase(Op)); }); } // AVX - if (CTX->HostFeatures.SupportsAVX) - { + if (CTX->HostFeatures.SupportsAVX) { StoreIfFlagSet(2, [this, Op] { SaveAVXState(XSaveBase(Op)); }); } // We need to save MXCSR and MXCSR_MASK if either SSE or AVX are requested to be saved { - StoreIfFlagSet(1, [this, Op] { SaveMXCSRState(XSaveBase(Op)); }, 2); + StoreIfFlagSet( + 1, [this, Op] { SaveMXCSRState(XSaveBase(Op)); }, 2); } // Update XSTATE_BV region of the XSAVE header { - OrderedNode *Base = XSaveBase(Op); - OrderedNode *HeaderOffset = _Add(OpSize, Base, _Constant(512)); + OrderedNode* Base = XSaveBase(Op); + OrderedNode* HeaderOffset = _Add(OpSize, Base, _Constant(512)); // NOTE: We currently only support the first 3 bits (x87, SSE, and AVX) - OrderedNode *Mask = LoadGPRRegister(X86State::REG_RAX); - OrderedNode *RequestedFeatures = _Bfe(OpSize, 3, 0, Mask); + OrderedNode* Mask = LoadGPRRegister(X86State::REG_RAX); + OrderedNode* RequestedFeatures = _Bfe(OpSize, 3, 0, Mask); // XSTATE_BV section of the header is 8 bytes in size, but we only really // care about setting at most 3 bits in the first byte. We zero out the rest. @@ -3054,7 +2718,7 @@ void OpDispatchBuilder::XSaveOpImpl(OpcodeArgs) { } } -void OpDispatchBuilder::SaveX87State(OpcodeArgs, OrderedNode *MemBase) { +void OpDispatchBuilder::SaveX87State(OpcodeArgs, OrderedNode* MemBase) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); // Saves 512bytes to the memory location provided // Header changes depending on if REX.W is set or not @@ -3063,8 +2727,7 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, OrderedNode *MemBase) { // ------------------------------------------ // 00 | FCW | FSW | FTW | | FOP | FIP | // 16 | FDP | MXCSR | MXCSR_MASK| - } - else { + } else { // BYTE | 0 1 | 2 3 | 4 | 5 | 6 7 | 8 9 | a b | c d | e f | // ------------------------------------------ // 00 | FCW | FSW | FTW | | FOP | FIP[31:0] | FCS | | @@ -3077,13 +2740,13 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, OrderedNode *MemBase) { } { - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(2)); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(2)); _StoreMem(GPRClass, 2, MemLocation, ReconstructFSW(), 2); } { // Abridged FTW - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(4)); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(4)); auto AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); _StoreMem(GPRClass, 1, MemLocation, AbridgedFTW, 2); } @@ -3133,65 +2796,65 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, OrderedNode *MemBase) { // If OSFXSR bit in CR4 is not set than FXSAVE /may/ not save the XMM registers // This is implementation dependent for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) { - OrderedNode *MMReg = _LoadContext(16, FPRClass, offsetof(FEXCore::Core::CPUState, mm[i])); - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 32)); + OrderedNode* MMReg = _LoadContext(16, FPRClass, offsetof(FEXCore::Core::CPUState, mm[i])); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 32)); _StoreMem(FPRClass, 16, MemLocation, MMReg, 16); } } -void OpDispatchBuilder::SaveSSEState(OrderedNode *MemBase) { +void OpDispatchBuilder::SaveSSEState(OrderedNode* MemBase) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U; for (uint32_t i = 0; i < NumRegs; ++i) { - OrderedNode *XMMReg = LoadXMMRegister(i); - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 160)); + OrderedNode* XMMReg = LoadXMMRegister(i); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 160)); _StoreMem(FPRClass, 16, MemLocation, XMMReg, 16); } } -void OpDispatchBuilder::SaveMXCSRState(OrderedNode *MemBase) { +void OpDispatchBuilder::SaveMXCSRState(OrderedNode* MemBase) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); - OrderedNode *MXCSR = GetMXCSR(); - OrderedNode *MXCSRLocation = _Add(OpSize, MemBase, _Constant(24)); + OrderedNode* MXCSR = GetMXCSR(); + OrderedNode* MXCSRLocation = _Add(OpSize, MemBase, _Constant(24)); _StoreMem(GPRClass, 4, MXCSRLocation, MXCSR, 4); // Store the mask for all bits. - OrderedNode *MXCSRMaskLocation = _Add(OpSize, MXCSRLocation, _Constant(4)); + OrderedNode* MXCSRMaskLocation = _Add(OpSize, MXCSRLocation, _Constant(4)); _StoreMem(GPRClass, 4, MXCSRMaskLocation, _Constant(0xFFFF), 4); } -void OpDispatchBuilder::SaveAVXState(OrderedNode *MemBase) { +void OpDispatchBuilder::SaveAVXState(OrderedNode* MemBase) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U; for (uint32_t i = 0; i < NumRegs; ++i) { - OrderedNode *Upper = _VDupElement(32, 16, LoadXMMRegister(i), 1); - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 576)); + OrderedNode* Upper = _VDupElement(32, 16, LoadXMMRegister(i), 1); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 576)); _StoreMem(FPRClass, 16, MemLocation, Upper, 16); } } -OrderedNode *OpDispatchBuilder::GetMXCSR() { +OrderedNode* OpDispatchBuilder::GetMXCSR() { // Default MXCSR Value - OrderedNode *MXCSR = _Constant(0x1F80); - OrderedNode *RoundingMode = _GetRoundingMode(); + OrderedNode* MXCSR = _Constant(0x1F80); + OrderedNode* RoundingMode = _GetRoundingMode(); return _Bfi(OpSize::i32Bit, 3, 13, MXCSR, RoundingMode); } void OpDispatchBuilder::FXRStoreOp(OpcodeArgs) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Src[0]); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Src[0]); RestoreX87State(Mem); RestoreSSEState(Mem); - OrderedNode *MXCSRLocation = _Add(OpSize, Mem, _Constant(24)); - OrderedNode *MXCSR = _LoadMem(GPRClass, 4, MXCSRLocation, 4); + OrderedNode* MXCSRLocation = _Add(OpSize, Mem, _Constant(24)); + OrderedNode* MXCSR = _LoadMem(GPRClass, 4, MXCSRLocation, 4); RestoreMXCSRState(MXCSR); } @@ -3201,25 +2864,23 @@ void OpDispatchBuilder::XRstorOpImpl(OpcodeArgs) { // If a bit in our XSTATE_BV is set, then we restore from that region of the XSAVE area, // otherwise, if not set, then we need to set the relevant data the bit corresponds to // to it's defined initial configuration. - const auto RestoreIfFlagSetOrDefault = [this, Op, OpSize](uint32_t BitIndex, auto restore_fn, auto default_fn, uint32_t FieldSize = 1){ + const auto RestoreIfFlagSetOrDefault = [this, Op, OpSize](uint32_t BitIndex, auto restore_fn, auto default_fn, uint32_t FieldSize = 1) { // Set up base address for the XSAVE region to restore from, and also read // the XSTATE_BV bit flags out of the XSTATE header. // // Note: we rematerialize Base/Mask in each block to avoid crossblock // liveness. - OrderedNode *Base = XSaveBase(Op); - OrderedNode *Mask = _LoadMem(GPRClass, 8, _Add(OpSize, Base, _Constant(512)), 8); + OrderedNode* Base = XSaveBase(Op); + OrderedNode* Mask = _LoadMem(GPRClass, 8, _Add(OpSize, Base, _Constant(512)), 8); - OrderedNode *BitFlag = _Bfe(OpSize, FieldSize, BitIndex, Mask); + OrderedNode* BitFlag = _Bfe(OpSize, FieldSize, BitIndex, Mask); auto CondJump_ = CondJump(BitFlag, {COND_NEQ}); auto RestoreBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); SetTrueJumpTarget(CondJump_, RestoreBlock); SetCurrentCodeBlock(RestoreBlock); StartNewBlock(); - { - restore_fn(); - } + { restore_fn(); } auto RestoreExitJump = Jump(); auto DefaultBlock = CreateNewCodeBlockAfter(RestoreBlock); auto ExitBlock = CreateNewCodeBlockAfter(DefaultBlock); @@ -3227,9 +2888,7 @@ void OpDispatchBuilder::XRstorOpImpl(OpcodeArgs) { SetFalseJumpTarget(CondJump_, DefaultBlock); SetCurrentCodeBlock(DefaultBlock); StartNewBlock(); - { - default_fn(); - } + { default_fn(); } auto DefaultExitJump = Jump(); SetJumpTarget(DefaultExitJump, ExitBlock); SetCurrentCodeBlock(ExitBlock); @@ -3238,89 +2897,86 @@ void OpDispatchBuilder::XRstorOpImpl(OpcodeArgs) { // x87 { - RestoreIfFlagSetOrDefault(0, - [this, Op] { RestoreX87State(XSaveBase(Op)); }, - [this, Op] { DefaultX87State(Op); }); + RestoreIfFlagSetOrDefault( + 0, [this, Op] { RestoreX87State(XSaveBase(Op)); }, [this, Op] { DefaultX87State(Op); }); } // SSE { - RestoreIfFlagSetOrDefault(1, - [this, Op] { RestoreSSEState(XSaveBase(Op)); }, - [this] { DefaultSSEState(); }); + RestoreIfFlagSetOrDefault( + 1, [this, Op] { RestoreSSEState(XSaveBase(Op)); }, [this] { DefaultSSEState(); }); } // AVX - if (CTX->HostFeatures.SupportsAVX) - { - RestoreIfFlagSetOrDefault(2, - [this, Op] { RestoreAVXState(XSaveBase(Op)); }, - [this] { DefaultAVXState(); }); + if (CTX->HostFeatures.SupportsAVX) { + RestoreIfFlagSetOrDefault( + 2, [this, Op] { RestoreAVXState(XSaveBase(Op)); }, [this] { DefaultAVXState(); }); } { // We need to restore the MXCSR if either SSE or AVX are requested to be saved - RestoreIfFlagSetOrDefault(1, - [this, Op, OpSize] { - OrderedNode *Base = XSaveBase(Op); - OrderedNode *MXCSRLocation = _Add(OpSize, Base, _Constant(24)); - OrderedNode *MXCSR = _LoadMem(GPRClass, 4, MXCSRLocation, 4); - RestoreMXCSRState(MXCSR); - }, - [] { /* Intentionally do nothing*/ }, 2); + RestoreIfFlagSetOrDefault( + 1, + [this, Op, OpSize] { + OrderedNode* Base = XSaveBase(Op); + OrderedNode* MXCSRLocation = _Add(OpSize, Base, _Constant(24)); + OrderedNode* MXCSR = _LoadMem(GPRClass, 4, MXCSRLocation, 4); + RestoreMXCSRState(MXCSR); + }, + [] { /* Intentionally do nothing*/ }, 2); } } -void OpDispatchBuilder::RestoreX87State(OrderedNode *MemBase) { +void OpDispatchBuilder::RestoreX87State(OrderedNode* MemBase) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); auto NewFCW = _LoadMem(GPRClass, 2, MemBase, 2); _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); { - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(2)); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(2)); auto NewFSW = _LoadMem(GPRClass, 2, MemLocation, 2); ReconstructX87StateFromFSW(NewFSW); } { // Abridged FTW - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(4)); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(4)); auto NewAbridgedFTW = _LoadMem(GPRClass, 1, MemLocation, 2); _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) { - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 32)); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 32)); auto MMReg = _LoadMem(FPRClass, 16, MemLocation, 16); _StoreContext(16, FPRClass, MMReg, offsetof(FEXCore::Core::CPUState, mm[i])); } } -void OpDispatchBuilder::RestoreSSEState(OrderedNode *MemBase) { +void OpDispatchBuilder::RestoreSSEState(OrderedNode* MemBase) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U; for (uint32_t i = 0; i < NumRegs; ++i) { - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 160)); - OrderedNode *XMMReg = _LoadMem(FPRClass, 16, MemLocation, 16); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 160)); + OrderedNode* XMMReg = _LoadMem(FPRClass, 16, MemLocation, 16); StoreXMMRegister(i, XMMReg); } } -void OpDispatchBuilder::RestoreMXCSRState(OrderedNode *MXCSR) { +void OpDispatchBuilder::RestoreMXCSRState(OrderedNode* MXCSR) { // We only support the rounding mode and FTZ bit being set - OrderedNode *RoundingMode = _Bfe(OpSize::i32Bit, 3, 13, MXCSR); + OrderedNode* RoundingMode = _Bfe(OpSize::i32Bit, 3, 13, MXCSR); _SetRoundingMode(RoundingMode); } -void OpDispatchBuilder::RestoreAVXState(OrderedNode *MemBase) { +void OpDispatchBuilder::RestoreAVXState(OrderedNode* MemBase) { const auto OpSize = IR::SizeToOpSize(CTX->GetGPRSize()); const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U; for (uint32_t i = 0; i < NumRegs; ++i) { - OrderedNode *XMMReg = LoadXMMRegister(i); - OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 576)); - OrderedNode *YMMHReg = _LoadMem(FPRClass, 16, MemLocation, 16); - OrderedNode *YMM = _VInsElement(32, 16, 1, 0, XMMReg, YMMHReg); + OrderedNode* XMMReg = LoadXMMRegister(i); + OrderedNode* MemLocation = _Add(OpSize, MemBase, _Constant(i * 16 + 576)); + OrderedNode* YMMHReg = _LoadMem(FPRClass, 16, MemLocation, 16); + OrderedNode* YMM = _VInsElement(32, 16, 1, 0, XMMReg, YMMHReg); StoreXMMRegister(i, YMM); } } @@ -3332,7 +2988,7 @@ void OpDispatchBuilder::DefaultX87State(OpcodeArgs) { // On top of resetting the flags to a default state, we also need to clear // all of the ST0-7/MM0-7 registers to zero. - OrderedNode *ZeroVector = LoadAndCacheNamedVectorConstant(Core::CPUState::MM_REG_SIZE, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* ZeroVector = LoadAndCacheNamedVectorConstant(Core::CPUState::MM_REG_SIZE, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) { _StoreContext(16, FPRClass, ZeroVector, offsetof(FEXCore::Core::CPUState, mm[i])); } @@ -3341,7 +2997,7 @@ void OpDispatchBuilder::DefaultX87State(OpcodeArgs) { void OpDispatchBuilder::DefaultSSEState() { const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U; - OrderedNode *ZeroVector = LoadAndCacheNamedVectorConstant(Core::CPUState::XMM_SSE_REG_SIZE, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* ZeroVector = LoadAndCacheNamedVectorConstant(Core::CPUState::XMM_SSE_REG_SIZE, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); for (uint32_t i = 0; i < NumRegs; ++i) { StoreXMMRegister(i, ZeroVector); } @@ -3351,67 +3007,64 @@ void OpDispatchBuilder::DefaultAVXState() { const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U; for (uint32_t i = 0; i < NumRegs; i++) { - OrderedNode* Reg = LoadXMMRegister(i); - OrderedNode* Dst = _VMov(16, Reg); - StoreXMMRegister(i, Dst); - } + OrderedNode* Reg = LoadXMMRegister(i); + OrderedNode* Dst = _VMov(16, Reg); + StoreXMMRegister(i, Dst); + } } -OrderedNode* OpDispatchBuilder::PALIGNROpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, - const X86Tables::DecodedOperand& Imm, - bool IsAVX) { +OrderedNode* OpDispatchBuilder::PALIGNROpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, + const X86Tables::DecodedOperand& Imm, bool IsAVX) { LOGMAN_THROW_A_FMT(Imm.IsLiteral(), "Imm needs to be a literal"); // For the 256-bit case we handle it as pairs of 128-bit halves. const auto DstSize = GetDstSize(Op); - const auto SanitizedDstSize = std::min(DstSize, uint8_t{16}); + const auto SanitizedDstSize = std::min(DstSize, uint8_t {16}); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; const auto Index = Imm.Data.Literal.Value; - OrderedNode *Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); + OrderedNode* Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); if (Index == 0) { if (IsAVX && !Is256Bit) { // 128-bit AVX needs to zero the upper bits. return _VMov(16, Src2Node); - } - else { + } else { return Src2Node; } } - OrderedNode *Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); + OrderedNode* Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); if (Index >= (SanitizedDstSize * 2)) { // If the immediate is greater than both vectors combined then it zeroes the vector return LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); } - OrderedNode *Low = _VExtr(SanitizedDstSize, 1, Src1Node, Src2Node, Index); + OrderedNode* Low = _VExtr(SanitizedDstSize, 1, Src1Node, Src2Node, Index); if (!Is256Bit) { return Low; } - OrderedNode *HighSrc1 = _VInsElement(DstSize, 16, 0, 1, Src1Node, Src1Node); - OrderedNode *HighSrc2 = _VInsElement(DstSize, 16, 0, 1, Src2Node, Src2Node); - OrderedNode *High = _VExtr(SanitizedDstSize, 1, HighSrc1, HighSrc2, Index); + OrderedNode* HighSrc1 = _VInsElement(DstSize, 16, 0, 1, Src1Node, Src1Node); + OrderedNode* HighSrc2 = _VInsElement(DstSize, 16, 0, 1, Src2Node, Src2Node); + OrderedNode* High = _VExtr(SanitizedDstSize, 1, HighSrc1, HighSrc2, Index); return _VInsElement(DstSize, 16, 1, 0, Low, High); } void OpDispatchBuilder::PAlignrOp(OpcodeArgs) { - OrderedNode *Result = PALIGNROpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1], false); + OrderedNode* Result = PALIGNROpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1], false); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPALIGNROp(OpcodeArgs) { - OrderedNode *Result = PALIGNROpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2], true); + OrderedNode* Result = PALIGNROpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2], true); StoreResult(FPRClass, Op, Result, -1); } template void OpDispatchBuilder::UCOMISxOp(OpcodeArgs) { const auto SrcSize = Op->Src[0].IsGPR() ? GetGuestVectorLength() : GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetGuestVectorLength(), Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetGuestVectorLength(), Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); HandleNZCVWrite(); _FCmp(ElementSize, Src1, Src2); @@ -3423,13 +3076,11 @@ void OpDispatchBuilder::UCOMISxOp(OpcodeArgs) { SetRFLAG(_Constant(0)); } -template -void OpDispatchBuilder::UCOMISxOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::UCOMISxOp<8>(OpcodeArgs); +template void OpDispatchBuilder::UCOMISxOp<4>(OpcodeArgs); +template void OpDispatchBuilder::UCOMISxOp<8>(OpcodeArgs); void OpDispatchBuilder::LDMXCSR(OpcodeArgs) { - OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); RestoreMXCSRState(Dest); } @@ -3437,8 +3088,7 @@ void OpDispatchBuilder::STMXCSR(OpcodeArgs) { StoreResult(GPRClass, Op, GetMXCSR(), -1); } -OrderedNode* OpDispatchBuilder::PACKUSOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::PACKUSOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2) { const auto Size = GetSrcSize(Op); return _VSQXTUNPair(Size, ElementSize, Src1, Src2); @@ -3446,26 +3096,24 @@ OrderedNode* OpDispatchBuilder::PACKUSOpImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::PACKUSOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PACKUSOpImpl(Op, ElementSize, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PACKUSOpImpl(Op, ElementSize, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PACKUSOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PACKUSOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PACKUSOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PACKUSOp<4>(OpcodeArgs); template void OpDispatchBuilder::VPACKUSOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = PACKUSOpImpl(Op, ElementSize, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = PACKUSOpImpl(Op, ElementSize, Src1, Src2); if (Is256Bit) { // We do a little cheeky 64-bit swapping to interleave the result. @@ -3475,39 +3123,34 @@ void OpDispatchBuilder::VPACKUSOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPACKUSOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPACKUSOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPACKUSOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPACKUSOp<4>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PACKSSOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::PACKSSOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2) { const auto Size = GetSrcSize(Op); return _VSQXTNPair(Size, ElementSize, Src1, Src2); } template void OpDispatchBuilder::PACKSSOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PACKSSOpImpl(Op, ElementSize, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PACKSSOpImpl(Op, ElementSize, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PACKSSOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::PACKSSOp<4>(OpcodeArgs); +template void OpDispatchBuilder::PACKSSOp<2>(OpcodeArgs); +template void OpDispatchBuilder::PACKSSOp<4>(OpcodeArgs); template void OpDispatchBuilder::VPACKSSOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = PACKSSOpImpl(Op, ElementSize, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = PACKSSOpImpl(Op, ElementSize, Src1, Src2); if (Is256Bit) { // We do a little cheeky 64-bit swapping to interleave the result. @@ -3517,13 +3160,10 @@ void OpDispatchBuilder::VPACKSSOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPACKSSOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPACKSSOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPACKSSOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPACKSSOp<4>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PMULLOpImpl(OpcodeArgs, size_t ElementSize, bool Signed, - OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::PMULLOpImpl(OpcodeArgs, size_t ElementSize, bool Signed, OrderedNode* Src1, OrderedNode* Src2) { const auto Size = GetSrcSize(Op); if (Size == 8) { @@ -3546,41 +3186,35 @@ OrderedNode* OpDispatchBuilder::PMULLOpImpl(OpcodeArgs, size_t ElementSize, bool template void OpDispatchBuilder::PMULLOp(OpcodeArgs) { - static_assert(ElementSize == sizeof(uint32_t), - "Currently only handles 32-bit -> 64-bit"); + static_assert(ElementSize == sizeof(uint32_t), "Currently only handles 32-bit -> 64-bit"); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Res = PMULLOpImpl(Op, ElementSize, Signed, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Res = PMULLOpImpl(Op, ElementSize, Signed, Src1, Src2); StoreResult(FPRClass, Op, Res, -1); } -template -void OpDispatchBuilder::PMULLOp<4, false>(OpcodeArgs); -template -void OpDispatchBuilder::PMULLOp<4, true>(OpcodeArgs); +template void OpDispatchBuilder::PMULLOp<4, false>(OpcodeArgs); +template void OpDispatchBuilder::PMULLOp<4, true>(OpcodeArgs); -template +template void OpDispatchBuilder::VPMULLOp(OpcodeArgs) { - static_assert(ElementSize == sizeof(uint32_t), - "Currently only handles 32-bit -> 64-bit"); + static_assert(ElementSize == sizeof(uint32_t), "Currently only handles 32-bit -> 64-bit"); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = PMULLOpImpl(Op, ElementSize, Signed, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = PMULLOpImpl(Op, ElementSize, Signed, Src1, Src2); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPMULLOp<4, false>(OpcodeArgs); -template -void OpDispatchBuilder::VPMULLOp<4, true>(OpcodeArgs); +template void OpDispatchBuilder::VPMULLOp<4, false>(OpcodeArgs); +template void OpDispatchBuilder::VPMULLOp<4, true>(OpcodeArgs); template void OpDispatchBuilder::MOVQ2DQ(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); // This instruction is a bit special in that if the source is MMX then it zexts to 128bit if constexpr (ToXMM) { @@ -3588,33 +3222,27 @@ void OpDispatchBuilder::MOVQ2DQ(OpcodeArgs) { Src = _VMov(16, Src); StoreXMMRegister(Index, Src); - } - else { + } else { // This is simple, just store the result StoreResult(FPRClass, Op, Src, -1); } } -template -void OpDispatchBuilder::MOVQ2DQ(OpcodeArgs); -template -void OpDispatchBuilder::MOVQ2DQ(OpcodeArgs); +template void OpDispatchBuilder::MOVQ2DQ(OpcodeArgs); +template void OpDispatchBuilder::MOVQ2DQ(OpcodeArgs); -OrderedNode* OpDispatchBuilder::ADDSUBPOpImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::ADDSUBPOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src1, OrderedNode* Src2) { const auto Size = GetSrcSize(Op); if (CTX->HostFeatures.SupportsFCMA) { if (ElementSize == 4) { auto Swizzle = _VRev64(Size, 4, Src2); return _VFCADD(Size, ElementSize, Src1, Swizzle, 90); - } - else { + } else { auto Swizzle = _VExtr(Size, 1, Src2, Src2, 8); return _VFCADD(Size, ElementSize, Src1, Swizzle, 90); } - } - else { + } else { auto ConstantEOR = LoadAndCacheNamedVectorConstant(Size, ElementSize == 4 ? NAMED_VECTOR_PADDSUBPS_INVERT : NAMED_VECTOR_PADDSUBPD_INVERT); auto InvertedSource = _VXor(Size, ElementSize, Src2, ConstantEOR); return _VFAdd(Size, ElementSize, Src1, InvertedSource); @@ -3623,37 +3251,33 @@ OrderedNode* OpDispatchBuilder::ADDSUBPOpImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::ADDSUBPOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = ADDSUBPOpImpl(Op, ElementSize, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = ADDSUBPOpImpl(Op, ElementSize, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::ADDSUBPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::ADDSUBPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::ADDSUBPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::ADDSUBPOp<8>(OpcodeArgs); template void OpDispatchBuilder::VADDSUBPOp(OpcodeArgs) { - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = ADDSUBPOpImpl(Op, ElementSize, Src1, Src2); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = ADDSUBPOpImpl(Op, ElementSize, Src1, Src2); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VADDSUBPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VADDSUBPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VADDSUBPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VADDSUBPOp<8>(OpcodeArgs); void OpDispatchBuilder::PFNACCOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto DestUnzip = _VUnZip(Size, 4, Dest, Src); auto SrcUnzip = _VUnZip2(Size, 4, Dest, Src); @@ -3665,11 +3289,11 @@ void OpDispatchBuilder::PFNACCOp(OpcodeArgs) { void OpDispatchBuilder::PFPNACCOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *ResAdd{}; - OrderedNode *ResSub{}; + OrderedNode* ResAdd {}; + OrderedNode* ResSub {}; auto UpperSubDest = _VDupElement(Size, 4, Dest, 1); ResSub = _VFSub(4, 4, Dest, UpperSubDest); @@ -3682,14 +3306,14 @@ void OpDispatchBuilder::PFPNACCOp(OpcodeArgs) { void OpDispatchBuilder::PSWAPDOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto Result = _VRev64(Size, 4, Src); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::PI2FWOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); size_t Size = GetDstSize(Op); @@ -3707,7 +3331,7 @@ void OpDispatchBuilder::PI2FWOp(OpcodeArgs) { } void OpDispatchBuilder::PF2IWOp(OpcodeArgs) { - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); size_t Size = GetDstSize(Op); @@ -3726,17 +3350,17 @@ void OpDispatchBuilder::PF2IWOp(OpcodeArgs) { void OpDispatchBuilder::PMULHRWOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Res{}; + OrderedNode* Res {}; // Implementation is more efficient for 8byte registers // Multiplies 4 16bit values in to 4 32bit values Res = _VSMull(Size * 2, 2, Dest, Src); // Load 0x0000_8000 in to each 32-bit element. - OrderedNode *VConstant = _VectorImm(16, 4, 0x80, 8); + OrderedNode* VConstant = _VectorImm(16, 4, 0x80, 8); Res = _VAdd(Size * 2, 4, Res, VConstant); @@ -3749,39 +3373,33 @@ void OpDispatchBuilder::PMULHRWOp(OpcodeArgs) { template void OpDispatchBuilder::VPFCMPOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetDstSize(Op), Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetDstSize(Op), Op->Flags); - OrderedNode *Result{}; + OrderedNode* Result {}; // This maps 1:1 to an AArch64 NEON Op - //auto ALUOp = _VCMPGT(Size, 4, Dest, Src); + // auto ALUOp = _VCMPGT(Size, 4, Dest, Src); switch (CompType) { - case 0x00: // EQ - Result = _VFCMPEQ(Size, 4, Dest, Src); + case 0x00: // EQ + Result = _VFCMPEQ(Size, 4, Dest, Src); break; - case 0x01: // GE(Swapped operand) - Result = _VFCMPLE(Size, 4, Src, Dest); + case 0x01: // GE(Swapped operand) + Result = _VFCMPLE(Size, 4, Src, Dest); break; - case 0x02: // GT - Result = _VFCMPGT(Size, 4, Dest, Src); - break; - default: - LOGMAN_MSG_A_FMT("Unknown Comparison type: {}", CompType); + case 0x02: // GT + Result = _VFCMPGT(Size, 4, Dest, Src); break; + default: LOGMAN_MSG_A_FMT("Unknown Comparison type: {}", CompType); break; } StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPFCMPOp<0>(OpcodeArgs); -template -void OpDispatchBuilder::VPFCMPOp<1>(OpcodeArgs); -template -void OpDispatchBuilder::VPFCMPOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPFCMPOp<0>(OpcodeArgs); +template void OpDispatchBuilder::VPFCMPOp<1>(OpcodeArgs); +template void OpDispatchBuilder::VPFCMPOp<2>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PMADDWDOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2) { +OrderedNode* OpDispatchBuilder::PMADDWDOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2) { // This is a pretty curious operation // Does two MADD operations across 4 16bit signed integers and accumulates to 32bit integers in the destination // @@ -3792,8 +3410,8 @@ OrderedNode* OpDispatchBuilder::PMADDWDOpImpl(OpcodeArgs, const X86Tables::Decod auto Size = GetSrcSize(Op); - OrderedNode *Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); - OrderedNode *Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); + OrderedNode* Src1Node = LoadSource(FPRClass, Op, Src1, Op->Flags); + OrderedNode* Src2Node = LoadSource(FPRClass, Op, Src2, Op->Flags); if (Size == 8) { // MMX implementation can be slightly more optimal @@ -3810,30 +3428,29 @@ OrderedNode* OpDispatchBuilder::PMADDWDOpImpl(OpcodeArgs, const X86Tables::Decod } void OpDispatchBuilder::PMADDWD(OpcodeArgs) { - OrderedNode *Result = PMADDWDOpImpl(Op, Op->Dest, Op->Src[0]); + OrderedNode* Result = PMADDWDOpImpl(Op, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPMADDWDOp(OpcodeArgs) { - OrderedNode *Result = PMADDWDOpImpl(Op, Op->Src[0], Op->Src[1]); + OrderedNode* Result = PMADDWDOpImpl(Op, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } -OrderedNode* OpDispatchBuilder::PMADDUBSWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op) { +OrderedNode* OpDispatchBuilder::PMADDUBSWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op) { const auto Size = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); if (Size == 8) { // 64bit is more efficient // Src1 is unsigned - auto Src1_16b = _VUXTL(Size * 2, 1, Src1); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] + auto Src1_16b = _VUXTL(Size * 2, 1, Src1); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] // Src2 is signed - auto Src2_16b = _VSXTL(Size * 2, 1, Src2); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] + auto Src2_16b = _VSXTL(Size * 2, 1, Src2); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] auto ResMul_L = _VSMull(Size * 2, 2, Src1_16b, Src2_16b); auto ResMul_H = _VSMull2(Size * 2, 2, Src1_16b, Src2_16b); @@ -3851,13 +3468,13 @@ OrderedNode* OpDispatchBuilder::PMADDUBSWOpImpl(OpcodeArgs, const X86Tables::Dec // Requires implementing IR ops for BIC (vector, immediate) although. // Src1 is unsigned - auto Src1_16b_L = _VUXTL(Size, 1, Src1); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] - auto Src2_16b_L = _VSXTL(Size, 1, Src2); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] - auto ResMul_L = _VMul(Size, 2, Src1_16b_L, Src2_16b_L); + auto Src1_16b_L = _VUXTL(Size, 1, Src1); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] + auto Src2_16b_L = _VSXTL(Size, 1, Src2); // [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] + auto ResMul_L = _VMul(Size, 2, Src1_16b_L, Src2_16b_L); // Src2 is signed - auto Src1_16b_H = _VUXTL2(Size, 1, Src1); // Offset to +64bits [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] - auto Src2_16b_H = _VSXTL2(Size, 1, Src2); // Offset to +64bits [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] + auto Src1_16b_H = _VUXTL2(Size, 1, Src1); // Offset to +64bits [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] + auto Src2_16b_H = _VSXTL2(Size, 1, Src2); // Offset to +64bits [7:0 ], [15:8], [23:16], [31:24], [39:32], [47:40], [55:48], [63:56] auto ResMul_L_H = _VMul(Size, 2, Src1_16b_H, Src2_16b_H); auto TmpZip1 = _VUnZip(Size, 2, ResMul_L, ResMul_L_H); @@ -3867,48 +3484,44 @@ OrderedNode* OpDispatchBuilder::PMADDUBSWOpImpl(OpcodeArgs, const X86Tables::Dec } void OpDispatchBuilder::PMADDUBSW(OpcodeArgs) { - OrderedNode * Result = PMADDUBSWOpImpl(Op, Op->Dest, Op->Src[0]); + OrderedNode* Result = PMADDUBSWOpImpl(Op, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPMADDUBSWOp(OpcodeArgs) { - OrderedNode * Result = PMADDUBSWOpImpl(Op, Op->Src[0], Op->Src[1]); + OrderedNode* Result = PMADDUBSWOpImpl(Op, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } -OrderedNode* OpDispatchBuilder::PMULHWOpImpl(OpcodeArgs, bool Signed, - OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::PMULHWOpImpl(OpcodeArgs, bool Signed, OrderedNode* Src1, OrderedNode* Src2) { const auto Size = GetSrcSize(Op); if (Signed) { return _VSMulH(Size, 2, Src1, Src2); - } - else { + } else { return _VUMulH(Size, 2, Src1, Src2); } } template void OpDispatchBuilder::PMULHW(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PMULHWOpImpl(Op, Signed, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PMULHWOpImpl(Op, Signed, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PMULHW(OpcodeArgs); -template -void OpDispatchBuilder::PMULHW(OpcodeArgs); +template void OpDispatchBuilder::PMULHW(OpcodeArgs); +template void OpDispatchBuilder::PMULHW(OpcodeArgs); -template +template void OpDispatchBuilder::VPMULHWOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is128Bit = DstSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = PMULHWOpImpl(Op, Signed, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = PMULHWOpImpl(Op, Signed, Dest, Src); if (Is128Bit) { Result = _VMov(16, Result); @@ -3916,15 +3529,13 @@ void OpDispatchBuilder::VPMULHWOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPMULHWOp(OpcodeArgs); -template -void OpDispatchBuilder::VPMULHWOp(OpcodeArgs); +template void OpDispatchBuilder::VPMULHWOp(OpcodeArgs); +template void OpDispatchBuilder::VPMULHWOp(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PMULHRSWOpImpl(OpcodeArgs, OrderedNode *Src1, OrderedNode *Src2) { +OrderedNode* OpDispatchBuilder::PMULHRSWOpImpl(OpcodeArgs, OrderedNode* Src1, OrderedNode* Src2) { const auto Size = GetSrcSize(Op); - OrderedNode *Res{}; + OrderedNode* Res {}; if (Size == 8) { // Implementation is more efficient for 8byte registers Res = _VSMull(Size * 2, 2, Src1, Src2); @@ -3934,8 +3545,8 @@ OrderedNode* OpDispatchBuilder::PMULHRSWOpImpl(OpcodeArgs, OrderedNode *Src1, Or return _VUShrNI(Size * 2, 4, Res, 1); } else { // 128-bit and 256-bit are less efficient - OrderedNode *ResultLow; - OrderedNode *ResultHigh; + OrderedNode* ResultLow; + OrderedNode* ResultHigh; ResultLow = _VSMull(Size, 2, Src1, Src2); ResultHigh = _VSMull2(Size, 2, Src1, Src2); @@ -3954,28 +3565,27 @@ OrderedNode* OpDispatchBuilder::PMULHRSWOpImpl(OpcodeArgs, OrderedNode *Src1, Or } void OpDispatchBuilder::PMULHRSW(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = PMULHRSWOpImpl(Op, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = PMULHRSWOpImpl(Op, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPMULHRSWOp(OpcodeArgs) { - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); - OrderedNode *Result = PMULHRSWOpImpl(Op, Dest, Src); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Result = PMULHRSWOpImpl(Op, Dest, Src); StoreResult(FPRClass, Op, Result, -1); } -OrderedNode* OpDispatchBuilder::HSUBPOpImpl(OpcodeArgs, size_t ElementSize, - const X86Tables::DecodedOperand& Src1Op, +OrderedNode* OpDispatchBuilder::HSUBPOpImpl(OpcodeArgs, size_t ElementSize, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op) { const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); auto Even = _VUnZip(SrcSize, ElementSize, Src1, Src2); auto Odd = _VUnZip2(SrcSize, ElementSize, Src1, Src2); @@ -3984,22 +3594,20 @@ OrderedNode* OpDispatchBuilder::HSUBPOpImpl(OpcodeArgs, size_t ElementSize, template void OpDispatchBuilder::HSUBP(OpcodeArgs) { - OrderedNode *Result = HSUBPOpImpl(Op, ElementSize, Op->Dest, Op->Src[0]); + OrderedNode* Result = HSUBPOpImpl(Op, ElementSize, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::HSUBP<4>(OpcodeArgs); -template -void OpDispatchBuilder::HSUBP<8>(OpcodeArgs); +template void OpDispatchBuilder::HSUBP<4>(OpcodeArgs); +template void OpDispatchBuilder::HSUBP<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VHSUBPOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Result = HSUBPOpImpl(Op, ElementSize, Op->Src[0], Op->Src[1]); - OrderedNode *Dest = Result; + OrderedNode* Result = HSUBPOpImpl(Op, ElementSize, Op->Src[0], Op->Src[1]); + OrderedNode* Dest = Result; if (Is256Bit) { Dest = _VInsElement(DstSize, 8, 1, 2, Result, Result); Dest = _VInsElement(DstSize, 8, 2, 1, Dest, Result); @@ -4008,17 +3616,15 @@ void OpDispatchBuilder::VHSUBPOp(OpcodeArgs) { StoreResult(FPRClass, Op, Dest, -1); } -template -void OpDispatchBuilder::VHSUBPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VHSUBPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VHSUBPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VHSUBPOp<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PHSUBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, size_t ElementSize) { +OrderedNode* +OpDispatchBuilder::PHSUBOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, size_t ElementSize) { const auto Size = GetSrcSize(Op); - OrderedNode *Src1V = LoadSource(FPRClass, Op, Src1, Op->Flags); - OrderedNode *Src2V = LoadSource(FPRClass, Op, Src2, Op->Flags); + OrderedNode* Src1V = LoadSource(FPRClass, Op, Src1, Op->Flags); + OrderedNode* Src2V = LoadSource(FPRClass, Op, Src2, Op->Flags); auto Even = _VUnZip(Size, ElementSize, Src1V, Src2V); auto Odd = _VUnZip2(Size, ElementSize, Src1V, Src2V); @@ -4027,40 +3633,35 @@ OrderedNode* OpDispatchBuilder::PHSUBOpImpl(OpcodeArgs, const X86Tables::Decoded template void OpDispatchBuilder::PHSUB(OpcodeArgs) { - OrderedNode *Result = PHSUBOpImpl(Op, Op->Dest, Op->Src[0], ElementSize); + OrderedNode* Result = PHSUBOpImpl(Op, Op->Dest, Op->Src[0], ElementSize); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::PHSUB<2>(OpcodeArgs); -template -void OpDispatchBuilder::PHSUB<4>(OpcodeArgs); +template void OpDispatchBuilder::PHSUB<2>(OpcodeArgs); +template void OpDispatchBuilder::PHSUB<4>(OpcodeArgs); -template +template void OpDispatchBuilder::VPHSUBOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Result = PHSUBOpImpl(Op, Op->Src[0], Op->Src[1], ElementSize); + OrderedNode* Result = PHSUBOpImpl(Op, Op->Src[0], Op->Src[1], ElementSize); if (Is256Bit) { - OrderedNode *Inserted = _VInsElement(DstSize, 8, 1, 2, Result, Result); + OrderedNode* Inserted = _VInsElement(DstSize, 8, 1, 2, Result, Result); Result = _VInsElement(DstSize, 8, 2, 1, Inserted, Result); } StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPHSUBOp<2>(OpcodeArgs); -template -void OpDispatchBuilder::VPHSUBOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPHSUBOp<2>(OpcodeArgs); +template void OpDispatchBuilder::VPHSUBOp<4>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::PHADDSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op) { +OrderedNode* OpDispatchBuilder::PHADDSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op) { const auto Size = GetSrcSize(Op); const uint8_t ElementSize = 2; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); auto Even = _VUnZip(Size, ElementSize, Src1, Src2); auto Odd = _VUnZip2(Size, ElementSize, Src1, Src2); @@ -4070,7 +3671,7 @@ OrderedNode* OpDispatchBuilder::PHADDSOpImpl(OpcodeArgs, const X86Tables::Decode } void OpDispatchBuilder::PHADDS(OpcodeArgs) { - OrderedNode *Result = PHADDSOpImpl(Op, Op->Dest, Op->Src[0]); + OrderedNode* Result = PHADDSOpImpl(Op, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } @@ -4078,8 +3679,8 @@ void OpDispatchBuilder::VPHADDSWOp(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); const auto Is256Bit = SrcSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Result = PHADDSOpImpl(Op, Op->Src[0], Op->Src[1]); - OrderedNode *Dest = Result; + OrderedNode* Result = PHADDSOpImpl(Op, Op->Src[0], Op->Src[1]); + OrderedNode* Dest = Result; if (Is256Bit) { Dest = _VInsElement(SrcSize, 8, 1, 2, Result, Result); @@ -4089,13 +3690,12 @@ void OpDispatchBuilder::VPHADDSWOp(OpcodeArgs) { StoreResult(FPRClass, Op, Dest, -1); } -OrderedNode* OpDispatchBuilder::PHSUBSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op) { +OrderedNode* OpDispatchBuilder::PHSUBSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op) { const auto Size = GetSrcSize(Op); const uint8_t ElementSize = 2; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); auto Even = _VUnZip(Size, ElementSize, Src1, Src2); auto Odd = _VUnZip2(Size, ElementSize, Src1, Src2); @@ -4105,7 +3705,7 @@ OrderedNode* OpDispatchBuilder::PHSUBSOpImpl(OpcodeArgs, const X86Tables::Decode } void OpDispatchBuilder::PHSUBS(OpcodeArgs) { - OrderedNode *Result = PHSUBSOpImpl(Op, Op->Dest, Op->Src[0]); + OrderedNode* Result = PHSUBSOpImpl(Op, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } @@ -4113,8 +3713,8 @@ void OpDispatchBuilder::VPHSUBSWOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Result = PHSUBSOpImpl(Op, Op->Src[0], Op->Src[1]); - OrderedNode *Dest = Result; + OrderedNode* Result = PHSUBSOpImpl(Op, Op->Src[0], Op->Src[1]); + OrderedNode* Dest = Result; if (Is256Bit) { Dest = _VInsElement(DstSize, 8, 1, 2, Result, Result); Dest = _VInsElement(DstSize, 8, 2, 1, Dest, Result); @@ -4123,9 +3723,7 @@ void OpDispatchBuilder::VPHSUBSWOp(OpcodeArgs) { StoreResult(FPRClass, Op, Dest, -1); } -OrderedNode* OpDispatchBuilder::PSADBWOpImpl(OpcodeArgs, - const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op) { +OrderedNode* OpDispatchBuilder::PSADBWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op) { // The documentation is actually incorrect in how this instruction operates // It strongly implies that the `abs(dest[i] - src[i])` operates in 8bit space // but it actually operates in more than 8bit space @@ -4134,8 +3732,8 @@ OrderedNode* OpDispatchBuilder::PSADBWOpImpl(OpcodeArgs, const auto Size = GetSrcSize(Op); const auto Is128Bit = Size == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); if (Size == 8) { auto AbsResult = _VUABDL(Size * 2, 1, Src1, Src2); @@ -4147,39 +3745,38 @@ OrderedNode* OpDispatchBuilder::PSADBWOpImpl(OpcodeArgs, auto AbsResult_Low = _VUABDL(Size, 1, Src1, Src2); auto AbsResult_High = _VUABDL2(Size, 1, Src1, Src2); - OrderedNode *Result_Low = _VAddV(16, 2, AbsResult_Low); - OrderedNode *Result_High = _VAddV(16, 2, AbsResult_High); + OrderedNode* Result_Low = _VAddV(16, 2, AbsResult_Low); + OrderedNode* Result_High = _VAddV(16, 2, AbsResult_High); auto Low = _VZip(Size, 8, Result_Low, Result_High); if (Is128Bit) { return Low; } - OrderedNode *HighSrc1 = _VDupElement(Size, 16, AbsResult_Low, 1); - OrderedNode *HighSrc2 = _VDupElement(Size, 16, AbsResult_High, 1); + OrderedNode* HighSrc1 = _VDupElement(Size, 16, AbsResult_Low, 1); + OrderedNode* HighSrc2 = _VDupElement(Size, 16, AbsResult_High, 1); - OrderedNode *HighResult_Low = _VAddV(16, 2, HighSrc1); - OrderedNode *HighResult_High = _VAddV(16, 2, HighSrc2); + OrderedNode* HighResult_Low = _VAddV(16, 2, HighSrc1); + OrderedNode* HighResult_High = _VAddV(16, 2, HighSrc2); - OrderedNode *High = _VInsElement(Size, 8, 1, 0, HighResult_Low, HighResult_High); - OrderedNode *Full = _VInsElement(Size, 16, 1, 0, Low, High); + OrderedNode* High = _VInsElement(Size, 8, 1, 0, HighResult_Low, HighResult_High); + OrderedNode* Full = _VInsElement(Size, 16, 1, 0, Low, High); - OrderedNode *Tmp = _VInsElement(Size, 8, 2, 1, Full, Full); + OrderedNode* Tmp = _VInsElement(Size, 8, 2, 1, Full, Full); return _VInsElement(Size, 8, 1, 2, Tmp, Full); } void OpDispatchBuilder::PSADBW(OpcodeArgs) { - OrderedNode *Result = PSADBWOpImpl(Op, Op->Dest, Op->Src[0]); + OrderedNode* Result = PSADBWOpImpl(Op, Op->Dest, Op->Src[0]); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPSADBWOp(OpcodeArgs) { - OrderedNode *Result = PSADBWOpImpl(Op, Op->Src[0], Op->Src[1]); + OrderedNode* Result = PSADBWOpImpl(Op, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } -OrderedNode* OpDispatchBuilder::ExtendVectorElementsImpl(OpcodeArgs, size_t ElementSize, - size_t DstElementSize, bool Signed) { +OrderedNode* OpDispatchBuilder::ExtendVectorElementsImpl(OpcodeArgs, size_t ElementSize, size_t DstElementSize, bool Signed) { const auto DstSize = GetDstSize(Op); const auto GetSrc = [&] { @@ -4195,12 +3792,10 @@ OrderedNode* OpDispatchBuilder::ExtendVectorElementsImpl(OpcodeArgs, size_t Elem } }; - OrderedNode *Src = GetSrc(); - OrderedNode *Result{Src}; + OrderedNode* Src = GetSrc(); + OrderedNode* Result {Src}; - for (size_t CurrentElementSize = ElementSize; - CurrentElementSize != DstElementSize; - CurrentElementSize <<= 1) { + for (size_t CurrentElementSize = ElementSize; CurrentElementSize != DstElementSize; CurrentElementSize <<= 1) { if (Signed) { Result = _VSXTL(DstSize, CurrentElementSize, Result); } else { @@ -4211,40 +3806,27 @@ OrderedNode* OpDispatchBuilder::ExtendVectorElementsImpl(OpcodeArgs, size_t Elem return Result; } -template +template void OpDispatchBuilder::ExtendVectorElements(OpcodeArgs) { - OrderedNode *Result = ExtendVectorElementsImpl(Op, ElementSize, DstElementSize, Signed); + OrderedNode* Result = ExtendVectorElementsImpl(Op, ElementSize, DstElementSize, Signed); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::ExtendVectorElements<1, 2, false>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<1, 4, false>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<1, 8, false>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<2, 4, false>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<2, 8, false>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<4, 8, false>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<1, 2, false>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<1, 4, false>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<1, 8, false>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<2, 4, false>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<2, 8, false>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<4, 8, false>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<1, 2, true>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<1, 4, true>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<1, 8, true>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<2, 4, true>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<2, 8, true>(OpcodeArgs); -template -void OpDispatchBuilder::ExtendVectorElements<4, 8, true>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<1, 2, true>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<1, 4, true>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<1, 8, true>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<2, 4, true>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<2, 8, true>(OpcodeArgs); +template void OpDispatchBuilder::ExtendVectorElements<4, 8, true>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::VectorRoundImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, uint64_t Mode) { +OrderedNode* OpDispatchBuilder::VectorRoundImpl(OpcodeArgs, size_t ElementSize, OrderedNode* Src, uint64_t Mode) { const auto Size = GetDstSize(Op); const uint64_t RoundControlSource = (Mode >> 2) & 1; uint64_t RoundControl = Mode & 0b11; @@ -4254,10 +3836,7 @@ OrderedNode* OpDispatchBuilder::VectorRoundImpl(OpcodeArgs, size_t ElementSize, } static constexpr std::array SourceModes = { - FEXCore::IR::Round_Nearest, - FEXCore::IR::Round_Negative_Infinity, - FEXCore::IR::Round_Positive_Infinity, - FEXCore::IR::Round_Towards_Zero, + FEXCore::IR::Round_Nearest, FEXCore::IR::Round_Negative_Infinity, FEXCore::IR::Round_Positive_Infinity, FEXCore::IR::Round_Towards_Zero, FEXCore::IR::Round_Host, }; @@ -4270,7 +3849,7 @@ void OpDispatchBuilder::VectorRound(OpcodeArgs) { // No need to zero extend the vector in the event we have a // scalar source, especially since it's only inserted into another vector. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t Mode = Op->Src[1].Data.Literal.Value; @@ -4280,12 +3859,10 @@ void OpDispatchBuilder::VectorRound(OpcodeArgs) { StoreResult(FPRClass, Op, Src, -1); } -template -void OpDispatchBuilder::VectorRound<4>(OpcodeArgs); -template -void OpDispatchBuilder::VectorRound<8>(OpcodeArgs); +template void OpDispatchBuilder::VectorRound<4>(OpcodeArgs); +template void OpDispatchBuilder::VectorRound<8>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVectorRound(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const auto Mode = Op->Src[1].Data.Literal.Value; @@ -4294,16 +3871,14 @@ void OpDispatchBuilder::AVXVectorRound(OpcodeArgs) { // scalar source, especially since it's only inserted into another vector. const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); - OrderedNode *Result = VectorRoundImpl(Op, ElementSize, Src, Mode); + OrderedNode* Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags); + OrderedNode* Result = VectorRoundImpl(Op, ElementSize, Src, Mode); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::AVXVectorRound<4>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorRound<8>(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorRound<4>(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorRound<8>(OpcodeArgs); template void OpDispatchBuilder::VectorBlend(OpcodeArgs) { @@ -4312,200 +3887,196 @@ void OpDispatchBuilder::VectorBlend(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); uint8_t Select = Op->Src[1].Data.Literal.Value; - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); if constexpr (ElementSize == 4) { Select &= 0b1111; switch (Select) { - case 0b0000: - // No-op - return; - case 0b0001: - // Dest[31:0] = Src[31:0] - Dest = _VInsElement(DstSize, ElementSize, 0, 0, Dest, Src); - break; - case 0b0010: - // Dest[63:32] = Src[63:32] - Dest = _VInsElement(DstSize, ElementSize, 1, 1, Dest, Src); - break; - case 0b0011: - // Dest[31:0] = Src[31:0] - // Dest[63:32] = Src[63:32] - Dest = _VInsElement(DstSize, 8, 0, 0, Dest, Src); - break; - case 0b0100: - // Dest[95:64] = Src[95:64] - Dest = _VInsElement(DstSize, ElementSize, 2, 2, Dest, Src); - break; - case 0b0101: { - // Dest[31:0] = Src[31:0] - // Dest[63:32] = Dest[63:32] - // Dest[95:64] = Src[95:64] - // Dest[127:96] = Dest[127:96] - // Rotate the elements of the incoming source so they end up in the correct location. - // Then trn2 keeps the destination results in the expected location. - auto Temp = _VRev64(DstSize, 4, Src); - Dest = _VTrn2(DstSize, ElementSize, Temp, Dest); - break; - } - case 0b0110: { - // Dest[63:32] = Src[63:32] - // Dest[95:64] = Src[95:64] - auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_0110B); - Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); - break; - } - case 0b0111: { - // Dest[31:0] = Src[31:0] - // Dest[63:32] = Src[63:32] - // Dest[95:64] = Src[95:64] - auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_0111B); - Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); - break; - } - case 0b1000: - // Dest[127:96] = Src[127:96] - Dest = _VInsElement(DstSize, ElementSize, 3, 3, Dest, Src); - break; - case 0b1001: { - // Dest[31:0] = Src[31:0] - // Dest[127:96] = Src[127:96] - auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1001B); - Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); - break; - } - case 0b1010: { - // Dest[31:0] = Dest[31:0] - // Dest[63:32] = Src[63:32] - // Dest[95:64] = Dest[95:64] - // Dest[127:96] = Src[127:96] - // Rotate the elements of the incoming destination so they end up in the correct location. - // Then trn2 keeps the source results in the expected location. - auto Temp = _VRev64(DstSize, 4, Dest); - Dest = _VTrn2(DstSize, ElementSize, Temp, Src); - break; - } - case 0b1011: { - // Dest[31:0] = Src[31:0] - // Dest[63:32] = Src[63:32] - // Dest[95:64] = Src[95:64] - auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1011B); - Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); - break; - } - case 0b1100: - // Dest[95:64] = Src[95:64] - // Dest[127:96] = Src[127:96] - Dest = _VInsElement(DstSize, 8, 1, 1, Dest, Src); - break; - case 0b1101: { - // Dest[31:0] = Src[31:0] - // Dest[95:64] = Src[95:64] - // Dest[127:96] = Src[127:96] - auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1101B); - Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); - break; - } - case 0b1110: { - // Dest[63:32] = Src[63:32] - // Dest[95:64] = Src[95:64] - // Dest[127:96] = Src[127:96] - auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1110B); - Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); - break; - } - case 0b1111: - // Copy - Dest = Src; - break; - default: break; + case 0b0000: + // No-op + return; + case 0b0001: + // Dest[31:0] = Src[31:0] + Dest = _VInsElement(DstSize, ElementSize, 0, 0, Dest, Src); + break; + case 0b0010: + // Dest[63:32] = Src[63:32] + Dest = _VInsElement(DstSize, ElementSize, 1, 1, Dest, Src); + break; + case 0b0011: + // Dest[31:0] = Src[31:0] + // Dest[63:32] = Src[63:32] + Dest = _VInsElement(DstSize, 8, 0, 0, Dest, Src); + break; + case 0b0100: + // Dest[95:64] = Src[95:64] + Dest = _VInsElement(DstSize, ElementSize, 2, 2, Dest, Src); + break; + case 0b0101: { + // Dest[31:0] = Src[31:0] + // Dest[63:32] = Dest[63:32] + // Dest[95:64] = Src[95:64] + // Dest[127:96] = Dest[127:96] + // Rotate the elements of the incoming source so they end up in the correct location. + // Then trn2 keeps the destination results in the expected location. + auto Temp = _VRev64(DstSize, 4, Src); + Dest = _VTrn2(DstSize, ElementSize, Temp, Dest); + break; } - } - else if constexpr (ElementSize == 8) { + case 0b0110: { + // Dest[63:32] = Src[63:32] + // Dest[95:64] = Src[95:64] + auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_0110B); + Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); + break; + } + case 0b0111: { + // Dest[31:0] = Src[31:0] + // Dest[63:32] = Src[63:32] + // Dest[95:64] = Src[95:64] + auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_0111B); + Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); + break; + } + case 0b1000: + // Dest[127:96] = Src[127:96] + Dest = _VInsElement(DstSize, ElementSize, 3, 3, Dest, Src); + break; + case 0b1001: { + // Dest[31:0] = Src[31:0] + // Dest[127:96] = Src[127:96] + auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1001B); + Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); + break; + } + case 0b1010: { + // Dest[31:0] = Dest[31:0] + // Dest[63:32] = Src[63:32] + // Dest[95:64] = Dest[95:64] + // Dest[127:96] = Src[127:96] + // Rotate the elements of the incoming destination so they end up in the correct location. + // Then trn2 keeps the source results in the expected location. + auto Temp = _VRev64(DstSize, 4, Dest); + Dest = _VTrn2(DstSize, ElementSize, Temp, Src); + break; + } + case 0b1011: { + // Dest[31:0] = Src[31:0] + // Dest[63:32] = Src[63:32] + // Dest[95:64] = Src[95:64] + auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1011B); + Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); + break; + } + case 0b1100: + // Dest[95:64] = Src[95:64] + // Dest[127:96] = Src[127:96] + Dest = _VInsElement(DstSize, 8, 1, 1, Dest, Src); + break; + case 0b1101: { + // Dest[31:0] = Src[31:0] + // Dest[95:64] = Src[95:64] + // Dest[127:96] = Src[127:96] + auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1101B); + Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); + break; + } + case 0b1110: { + // Dest[63:32] = Src[63:32] + // Dest[95:64] = Src[95:64] + // Dest[127:96] = Src[127:96] + auto ConstantSwizzle = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_BLENDPS_1110B); + Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); + break; + } + case 0b1111: + // Copy + Dest = Src; + break; + default: break; + } + } else if constexpr (ElementSize == 8) { Select &= 0b11; switch (Select) { - case 0b00: - // No-op - return; - case 0b01: - // Dest[63:0] = Src[63:0] - Dest = _VInsElement(DstSize, ElementSize, 0, 0, Dest, Src); - break; - case 0b10: - // Dest[127:64] = Src[127:64] - Dest = _VInsElement(DstSize, ElementSize, 1, 1, Dest, Src); - break; - case 0b11: - // Copy - Dest = Src; - break; + case 0b00: + // No-op + return; + case 0b01: + // Dest[63:0] = Src[63:0] + Dest = _VInsElement(DstSize, ElementSize, 0, 0, Dest, Src); + break; + case 0b10: + // Dest[127:64] = Src[127:64] + Dest = _VInsElement(DstSize, ElementSize, 1, 1, Dest, Src); + break; + case 0b11: + // Copy + Dest = Src; + break; } - } - else { + } else { // TODO: There are some of these swizzles that can be more optimal. // NamedConstant + VTBX1 is quite quick already. // Implement more if it becomes relevant. switch (Select) { - case 0b0000'0000: - // No-op - return; - case 0b0000'0001: - case 0b0000'0010: - case 0b0000'0100: - case 0b0000'1000: - case 0b0001'0000: - case 0b0010'0000: - case 0b0100'0000: - case 0b1000'0000: { - // Single 16-bit element insert. - const auto Element = FEXCore::ilog2(Select); - Dest = _VInsElement(DstSize, ElementSize, Element, Element, Dest, Src); - break; - } - case 0b0000'0011: - case 0b0000'1100: - case 0b0011'0000: - case 0b1100'0000: { - // Single 32-bit element insert. - const auto Element = std::countr_zero(Select) / 2; - Dest = _VInsElement(DstSize, 4, Element, Element, Dest, Src); - break; - } - case 0b0000'1111: - case 0b1111'0000: { - // Single 64-bit element insert. - const auto Element = std::countr_zero(Select) / 4; - Dest = _VInsElement(DstSize, 8, Element, Element, Dest, Src); - break; - } - case 0b1111'1111: - // Copy - Dest = Src; - break; - default: { - auto ConstantSwizzle = LoadAndCacheIndexedNamedVectorConstant(DstSize, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PBLENDW, Select * 16); - Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); - break; - } + case 0b0000'0000: + // No-op + return; + case 0b0000'0001: + case 0b0000'0010: + case 0b0000'0100: + case 0b0000'1000: + case 0b0001'0000: + case 0b0010'0000: + case 0b0100'0000: + case 0b1000'0000: { + // Single 16-bit element insert. + const auto Element = FEXCore::ilog2(Select); + Dest = _VInsElement(DstSize, ElementSize, Element, Element, Dest, Src); + break; + } + case 0b0000'0011: + case 0b0000'1100: + case 0b0011'0000: + case 0b1100'0000: { + // Single 32-bit element insert. + const auto Element = std::countr_zero(Select) / 2; + Dest = _VInsElement(DstSize, 4, Element, Element, Dest, Src); + break; + } + case 0b0000'1111: + case 0b1111'0000: { + // Single 64-bit element insert. + const auto Element = std::countr_zero(Select) / 4; + Dest = _VInsElement(DstSize, 8, Element, Element, Dest, Src); + break; + } + case 0b1111'1111: + // Copy + Dest = Src; + break; + default: { + auto ConstantSwizzle = + LoadAndCacheIndexedNamedVectorConstant(DstSize, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PBLENDW, Select * 16); + Dest = _VTBX1(DstSize, Dest, Src, ConstantSwizzle); + break; + } } } StoreResult(FPRClass, Op, Dest, -1); } -template -void OpDispatchBuilder::VectorBlend<2>(OpcodeArgs); -template -void OpDispatchBuilder::VectorBlend<4>(OpcodeArgs); -template -void OpDispatchBuilder::VectorBlend<8>(OpcodeArgs); +template void OpDispatchBuilder::VectorBlend<2>(OpcodeArgs); +template void OpDispatchBuilder::VectorBlend<4>(OpcodeArgs); +template void OpDispatchBuilder::VectorBlend<8>(OpcodeArgs); template void OpDispatchBuilder::VectorVariableBlend(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); auto Mask = LoadXMMRegister(0); @@ -4520,37 +4091,31 @@ void OpDispatchBuilder::VectorVariableBlend(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VectorVariableBlend<1>(OpcodeArgs); -template -void OpDispatchBuilder::VectorVariableBlend<4>(OpcodeArgs); -template -void OpDispatchBuilder::VectorVariableBlend<8>(OpcodeArgs); +template void OpDispatchBuilder::VectorVariableBlend<1>(OpcodeArgs); +template void OpDispatchBuilder::VectorVariableBlend<4>(OpcodeArgs); +template void OpDispatchBuilder::VectorVariableBlend<8>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVectorVariableBlend(OpcodeArgs) { const auto SrcSize = GetSrcSize(Op); constexpr auto ElementSizeBits = ElementSize * 8; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src[2] needs to be literal here"); const auto Src3Selector = Op->Src[2].Data.Literal.Value; // Mask register is encoded within bits [7:4] of the selector - OrderedNode *Mask = LoadXMMRegister((Src3Selector >> 4) & 0b1111); + OrderedNode* Mask = LoadXMMRegister((Src3Selector >> 4) & 0b1111); - OrderedNode *Shifted = _VSShrI(SrcSize, ElementSize, Mask, ElementSizeBits - 1); - OrderedNode *Result = _VBSL(SrcSize, Shifted, Src2, Src1); + OrderedNode* Shifted = _VSShrI(SrcSize, ElementSize, Mask, ElementSizeBits - 1); + OrderedNode* Result = _VBSL(SrcSize, Shifted, Src2, Src1); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::AVXVectorVariableBlend<1>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorVariableBlend<4>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorVariableBlend<8>(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorVariableBlend<1>(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorVariableBlend<4>(OpcodeArgs); +template void OpDispatchBuilder::AVXVectorVariableBlend<8>(OpcodeArgs); void OpDispatchBuilder::PTestOp(OpcodeArgs) { // Invalidate deferred flags early @@ -4558,11 +4123,11 @@ void OpDispatchBuilder::PTestOp(OpcodeArgs) { auto Size = GetSrcSize(Op); - OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Test1 = _VAnd(Size, 1, Dest, Src); - OrderedNode *Test2 = _VBic(Size, 1, Src, Dest); + OrderedNode* Test1 = _VAnd(Size, 1, Dest, Src); + OrderedNode* Test2 = _VBic(Size, 1, Src, Dest); // Element size must be less than 32-bit for the sign bit tricks. Test1 = _VUMaxV(Size, 2, Test1); @@ -4574,8 +4139,7 @@ void OpDispatchBuilder::PTestOp(OpcodeArgs) { auto ZeroConst = _Constant(0); auto OneConst = _Constant(1); - Test2 = _Select(FEXCore::IR::COND_EQ, - Test2, ZeroConst, OneConst, ZeroConst); + Test2 = _Select(FEXCore::IR::COND_EQ, Test2, ZeroConst, OneConst, ZeroConst); // Careful, these flags are different between {V,}PTEST and VTESTP{S,D} // Set ZF according to Test1. SF will be zeroed since we do a 32-bit test on @@ -4592,30 +4156,29 @@ void OpDispatchBuilder::VTESTOpImpl(OpcodeArgs, size_t ElementSize) { const auto SrcSize = GetSrcSize(Op); const auto ElementSizeInBits = ElementSize * 8; - const auto MaskConstant = uint64_t{1} << (ElementSizeInBits - 1); + const auto MaskConstant = uint64_t {1} << (ElementSizeInBits - 1); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Dest, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Mask = _VDupFromGPR(SrcSize, ElementSize, _Constant(MaskConstant)); + OrderedNode* Mask = _VDupFromGPR(SrcSize, ElementSize, _Constant(MaskConstant)); - OrderedNode *AndTest = _VAnd(SrcSize, 1, Src2, Src1); - OrderedNode *AndNotTest = _VBic(SrcSize, 1, Src2, Src1); + OrderedNode* AndTest = _VAnd(SrcSize, 1, Src2, Src1); + OrderedNode* AndNotTest = _VBic(SrcSize, 1, Src2, Src1); - OrderedNode *MaskedAnd = _VAnd(SrcSize, 1, AndTest, Mask); - OrderedNode *MaskedAndNot = _VAnd(SrcSize, 1, AndNotTest, Mask); + OrderedNode* MaskedAnd = _VAnd(SrcSize, 1, AndTest, Mask); + OrderedNode* MaskedAndNot = _VAnd(SrcSize, 1, AndNotTest, Mask); - OrderedNode *MaxAnd = _VUMaxV(SrcSize, 2, MaskedAnd); - OrderedNode *MaxAndNot = _VUMaxV(SrcSize, 2, MaskedAndNot); + OrderedNode* MaxAnd = _VUMaxV(SrcSize, 2, MaskedAnd); + OrderedNode* MaxAndNot = _VUMaxV(SrcSize, 2, MaskedAndNot); - OrderedNode *AndGPR = _VExtractToGPR(SrcSize, 2, MaxAnd, 0); - OrderedNode *AndNotGPR = _VExtractToGPR(SrcSize, 2, MaxAndNot, 0); + OrderedNode* AndGPR = _VExtractToGPR(SrcSize, 2, MaxAnd, 0); + OrderedNode* AndNotGPR = _VExtractToGPR(SrcSize, 2, MaxAndNot, 0); - OrderedNode *ZeroConst = _Constant(0); - OrderedNode *OneConst = _Constant(1); + OrderedNode* ZeroConst = _Constant(0); + OrderedNode* OneConst = _Constant(1); - OrderedNode *CFResult = _Select(IR::COND_EQ, AndNotGPR, ZeroConst, - OneConst, ZeroConst); + OrderedNode* CFResult = _Select(IR::COND_EQ, AndNotGPR, ZeroConst, OneConst, ZeroConst); // As in PTest, this sets Z appropriately while zeroing the rest of NZCV. SetNZ_ZeroCV(32, AndGPR); @@ -4624,19 +4187,17 @@ void OpDispatchBuilder::VTESTOpImpl(OpcodeArgs, size_t ElementSize) { ZeroPF_AF(); } -template +template void OpDispatchBuilder::VTESTPOp(OpcodeArgs) { VTESTOpImpl(Op, ElementSize); } -template -void OpDispatchBuilder::VTESTPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VTESTPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VTESTPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VTESTPOp<8>(OpcodeArgs); OrderedNode* OpDispatchBuilder::PHMINPOSUWOpImpl(OpcodeArgs) { const auto Size = GetSrcSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); // Setup a vector swizzle // Initially load a 64-bit mask of immediates @@ -4673,12 +4234,11 @@ OrderedNode* OpDispatchBuilder::PHMINPOSUWOpImpl(OpcodeArgs) { } void OpDispatchBuilder::PHMINPOSUWOp(OpcodeArgs) { - OrderedNode *Result = PHMINPOSUWOpImpl(Op); + OrderedNode* Result = PHMINPOSUWOpImpl(Op); StoreResult(FPRClass, Op, Result, -1); } -OrderedNode* OpDispatchBuilder::DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, +OrderedNode* OpDispatchBuilder::DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm, size_t ElementSize) { LOGMAN_THROW_A_FMT(Imm.IsLiteral(), "Imm needs to be literal here"); const uint8_t Mask = Imm.Data.Literal.Value; @@ -4701,17 +4261,17 @@ OrderedNode* OpDispatchBuilder::DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOp }(); const auto DstSize = GetDstSize(Op); - OrderedNode *ZeroVec = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* ZeroVec = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); if (SrcMask == 0 || DstMask == 0) { // What are you even doing here? Go away. return ZeroVec; } - OrderedNode *Src1V = LoadSource(FPRClass, Op, Src1, Op->Flags); - OrderedNode *Src2V = LoadSource(FPRClass, Op, Src2, Op->Flags); + OrderedNode* Src1V = LoadSource(FPRClass, Op, Src1, Op->Flags); + OrderedNode* Src2V = LoadSource(FPRClass, Op, Src2, Op->Flags); // First step is to do an FMUL - OrderedNode *Temp = _VFMul(DstSize, ElementSize, Src1V, Src2V); + OrderedNode* Temp = _VFMul(DstSize, ElementSize, Src1V, Src2V); // Now mask results based on IndexMask. if (SrcMask != SizeMask) { @@ -4726,27 +4286,25 @@ OrderedNode* OpDispatchBuilder::DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOp // It can duplicate and zero results if (ElementSize == 8) { switch (DstMask) { - case 0b01: - // Dest[63:0] = Result - // Dest[127:64] = Zero - return _VZip(DstSize, ElementSize, Temp, ZeroVec); - case 0b10: - // Dest[63:0] = Zero - // Dest[127:64] = Result - return _VZip(DstSize, ElementSize, ZeroVec, Temp); - case 0b11: - // Broadcast - // Dest[63:0] = Result - // Dest[127:64] = Result - return _VDupElement(DstSize, ElementSize, Temp, 0); - case 0: - default: - LOGMAN_MSG_A_FMT("Unsupported"); + case 0b01: + // Dest[63:0] = Result + // Dest[127:64] = Zero + return _VZip(DstSize, ElementSize, Temp, ZeroVec); + case 0b10: + // Dest[63:0] = Zero + // Dest[127:64] = Result + return _VZip(DstSize, ElementSize, ZeroVec, Temp); + case 0b11: + // Broadcast + // Dest[63:0] = Result + // Dest[127:64] = Result + return _VDupElement(DstSize, ElementSize, Temp, 0); + case 0: + default: LOGMAN_MSG_A_FMT("Unsupported"); } - } - else { + } else { auto BadPath = [&]() { - OrderedNode *Result = ZeroVec; + OrderedNode* Result = ZeroVec; for (size_t i = 0; i < (DstSize / ElementSize); ++i) { const auto Bit = 1U << (i % 4); @@ -4759,106 +4317,105 @@ OrderedNode* OpDispatchBuilder::DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOp return Result; }; switch (DstMask) { - case 0b0001: - // Dest[31:0] = Result - // Dest[63:32] = Zero - // Dest[95:64] = Zero - // Dest[127:96] = Zero - return _VZip(DstSize, ElementSize, Temp, ZeroVec); - case 0b0010: - // Dest[31:0] = Zero - // Dest[63:32] = Result - // Dest[95:64] = Zero - // Dest[127:96] = Zero - return _VZip(DstSize / 2, ElementSize, ZeroVec, Temp); - case 0b0011: - // Dest[31:0] = Result - // Dest[63:32] = Result - // Dest[95:64] = Zero - // Dest[127:96] = Zero - return _VDupElement(DstSize / 2, ElementSize, Temp, 0); - case 0b0100: - // Dest[31:0] = Zero - // Dest[63:32] = Zero - // Dest[95:64] = Result - // Dest[127:96] = Zero - return _VZip(DstSize, 8, ZeroVec, Temp); - case 0b0101: - // Dest[31:0] = Result - // Dest[63:32] = Zero - // Dest[95:64] = Result - // Dest[127:96] = Zero - return _VZip(DstSize, 8, Temp, Temp); - case 0b0110: - // Dest[31:0] = Zero - // Dest[63:32] = Result - // Dest[95:64] = Result - // Dest[127:96] = Zero - return BadPath(); - case 0b0111: - // Dest[31:0] = Result - // Dest[63:32] = Result - // Dest[95:64] = Result - // Dest[127:96] = Zero - Temp = _VDupElement(DstSize, ElementSize, Temp, 0); - return _VInsElement(DstSize, ElementSize, 3, 0, Temp, ZeroVec); - case 0b1000: - // Dest[31:0] = Zero - // Dest[63:32] = Zero - // Dest[95:64] = Zero - // Dest[127:96] = Result - return _VExtr(DstSize, 1, Temp, ZeroVec, 4); - case 0b1001: - // Dest[31:0] = Result - // Dest[63:32] = Zero - // Dest[95:64] = Zero - // Dest[127:96] = Result - return BadPath(); - case 0b1010: - // Dest[31:0] = Zero - // Dest[63:32] = Result - // Dest[95:64] = Zero - // Dest[127:96] = Result - Temp = _VDupElement(DstSize, ElementSize, Temp, 0); - return _VZip(DstSize, 4, ZeroVec, Temp); - case 0b1011: - // Dest[31:0] = Result - // Dest[63:32] = Result - // Dest[95:64] = Zero - // Dest[127:96] = Result - Temp = _VDupElement(DstSize, ElementSize, Temp, 0); - return _VInsElement(DstSize, ElementSize, 2, 0, Temp, ZeroVec); - case 0b1100: - // Dest[31:0] = Zero - // Dest[63:32] = Zero - // Dest[95:64] = Result - // Dest[127:96] = Result - Temp = _VDupElement(DstSize, ElementSize, Temp, 0); - return _VZip(DstSize, 8, ZeroVec, Temp); - case 0b1101: - // Dest[31:0] = Result - // Dest[63:32] = Zero - // Dest[95:64] = Result - // Dest[127:96] = Result - Temp = _VDupElement(DstSize, ElementSize, Temp, 0); - return _VInsElement(DstSize, ElementSize, 1, 0, Temp, ZeroVec); - case 0b1110: - // Dest[31:0] = Zero - // Dest[63:32] = Result - // Dest[95:64] = Result - // Dest[127:96] = Result - Temp = _VDupElement(DstSize, ElementSize, Temp, 0); - return _VInsElement(DstSize, ElementSize, 0, 0, Temp, ZeroVec); - case 0b1111: - // Broadcast - // Dest[31:0] = Result - // Dest[63:32] = Zero - // Dest[95:64] = Zero - // Dest[127:96] = Zero - return _VDupElement(DstSize, ElementSize, Temp, 0); - case 0: - default: - LOGMAN_MSG_A_FMT("Unsupported"); + case 0b0001: + // Dest[31:0] = Result + // Dest[63:32] = Zero + // Dest[95:64] = Zero + // Dest[127:96] = Zero + return _VZip(DstSize, ElementSize, Temp, ZeroVec); + case 0b0010: + // Dest[31:0] = Zero + // Dest[63:32] = Result + // Dest[95:64] = Zero + // Dest[127:96] = Zero + return _VZip(DstSize / 2, ElementSize, ZeroVec, Temp); + case 0b0011: + // Dest[31:0] = Result + // Dest[63:32] = Result + // Dest[95:64] = Zero + // Dest[127:96] = Zero + return _VDupElement(DstSize / 2, ElementSize, Temp, 0); + case 0b0100: + // Dest[31:0] = Zero + // Dest[63:32] = Zero + // Dest[95:64] = Result + // Dest[127:96] = Zero + return _VZip(DstSize, 8, ZeroVec, Temp); + case 0b0101: + // Dest[31:0] = Result + // Dest[63:32] = Zero + // Dest[95:64] = Result + // Dest[127:96] = Zero + return _VZip(DstSize, 8, Temp, Temp); + case 0b0110: + // Dest[31:0] = Zero + // Dest[63:32] = Result + // Dest[95:64] = Result + // Dest[127:96] = Zero + return BadPath(); + case 0b0111: + // Dest[31:0] = Result + // Dest[63:32] = Result + // Dest[95:64] = Result + // Dest[127:96] = Zero + Temp = _VDupElement(DstSize, ElementSize, Temp, 0); + return _VInsElement(DstSize, ElementSize, 3, 0, Temp, ZeroVec); + case 0b1000: + // Dest[31:0] = Zero + // Dest[63:32] = Zero + // Dest[95:64] = Zero + // Dest[127:96] = Result + return _VExtr(DstSize, 1, Temp, ZeroVec, 4); + case 0b1001: + // Dest[31:0] = Result + // Dest[63:32] = Zero + // Dest[95:64] = Zero + // Dest[127:96] = Result + return BadPath(); + case 0b1010: + // Dest[31:0] = Zero + // Dest[63:32] = Result + // Dest[95:64] = Zero + // Dest[127:96] = Result + Temp = _VDupElement(DstSize, ElementSize, Temp, 0); + return _VZip(DstSize, 4, ZeroVec, Temp); + case 0b1011: + // Dest[31:0] = Result + // Dest[63:32] = Result + // Dest[95:64] = Zero + // Dest[127:96] = Result + Temp = _VDupElement(DstSize, ElementSize, Temp, 0); + return _VInsElement(DstSize, ElementSize, 2, 0, Temp, ZeroVec); + case 0b1100: + // Dest[31:0] = Zero + // Dest[63:32] = Zero + // Dest[95:64] = Result + // Dest[127:96] = Result + Temp = _VDupElement(DstSize, ElementSize, Temp, 0); + return _VZip(DstSize, 8, ZeroVec, Temp); + case 0b1101: + // Dest[31:0] = Result + // Dest[63:32] = Zero + // Dest[95:64] = Result + // Dest[127:96] = Result + Temp = _VDupElement(DstSize, ElementSize, Temp, 0); + return _VInsElement(DstSize, ElementSize, 1, 0, Temp, ZeroVec); + case 0b1110: + // Dest[31:0] = Zero + // Dest[63:32] = Result + // Dest[95:64] = Result + // Dest[127:96] = Result + Temp = _VDupElement(DstSize, ElementSize, Temp, 0); + return _VInsElement(DstSize, ElementSize, 0, 0, Temp, ZeroVec); + case 0b1111: + // Broadcast + // Dest[31:0] = Result + // Dest[63:32] = Zero + // Dest[95:64] = Zero + // Dest[127:96] = Zero + return _VDupElement(DstSize, ElementSize, Temp, 0); + case 0: + default: LOGMAN_MSG_A_FMT("Unsupported"); } } FEX_UNREACHABLE; @@ -4866,18 +4423,15 @@ OrderedNode* OpDispatchBuilder::DPPOpImpl(OpcodeArgs, const X86Tables::DecodedOp template void OpDispatchBuilder::DPPOp(OpcodeArgs) { - OrderedNode *Result = DPPOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1], ElementSize); + OrderedNode* Result = DPPOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1], ElementSize); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::DPPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::DPPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::DPPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::DPPOp<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::VDPPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, - const X86Tables::DecodedOperand& Src2, - const X86Tables::DecodedOperand& Imm) { +OrderedNode* OpDispatchBuilder::VDPPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, + const X86Tables::DecodedOperand& Imm) { LOGMAN_THROW_A_FMT(Imm.IsLiteral(), "Imm needs to be literal here"); constexpr size_t ElementSize = 4; const uint8_t Mask = Imm.Data.Literal.Value; @@ -4886,13 +4440,13 @@ OrderedNode* OpDispatchBuilder::VDPPSOpImpl(OpcodeArgs, const X86Tables::Decoded const auto DstSize = GetDstSize(Op); - OrderedNode *Src1V = LoadSource(FPRClass, Op, Src1, Op->Flags); - OrderedNode *Src2V = LoadSource(FPRClass, Op, Src2, Op->Flags); + OrderedNode* Src1V = LoadSource(FPRClass, Op, Src1, Op->Flags); + OrderedNode* Src2V = LoadSource(FPRClass, Op, Src2, Op->Flags); - OrderedNode *ZeroVec = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* ZeroVec = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); // First step is to do an FMUL - OrderedNode *Temp = _VFMul(DstSize, ElementSize, Src1V, Src2V); + OrderedNode* Temp = _VFMul(DstSize, ElementSize, Src1V, Src2V); // Now we zero out elements based on src mask for (size_t i = 0; i < (DstSize / ElementSize); ++i) { @@ -4914,7 +4468,7 @@ OrderedNode* OpDispatchBuilder::VDPPSOpImpl(OpcodeArgs, const X86Tables::Decoded // Now using the destination mask we choose where the result ends up // It can duplicate and zero results - OrderedNode *Result = ZeroVec; + OrderedNode* Result = ZeroVec; for (size_t i = 0; i < (DstSize / ElementSize); ++i) { const auto Bit = 1U << (i % 4); @@ -4927,16 +4481,15 @@ OrderedNode* OpDispatchBuilder::VDPPSOpImpl(OpcodeArgs, const X86Tables::Decoded return Result; } -template +template void OpDispatchBuilder::VDPPOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Result{}; + OrderedNode* Result {}; if (ElementSize == 4 && DstSize == Core::CPUState::XMM_AVX_REG_SIZE) { // 256-bit DPPS isn't handled by the 128-bit solution. Result = VDPPSOpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2]); - } - else { + } else { Result = DPPOpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2], ElementSize); } @@ -4945,30 +4498,26 @@ void OpDispatchBuilder::VDPPOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VDPPOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VDPPOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VDPPOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VDPPOp<8>(OpcodeArgs); -OrderedNode* OpDispatchBuilder::MPSADBWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, - const X86Tables::DecodedOperand& Src2Op, +OrderedNode* OpDispatchBuilder::MPSADBWOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1Op, const X86Tables::DecodedOperand& Src2Op, const X86Tables::DecodedOperand& ImmOp) { - const auto LaneHelper = [&, this](uint32_t Selector_Src1, uint32_t Selector_Src2, - OrderedNode *Src1, OrderedNode *Src2) { + const auto LaneHelper = [&, this](uint32_t Selector_Src1, uint32_t Selector_Src2, OrderedNode* Src1, OrderedNode* Src2) { // Src2 will grab a 32bit element and duplicate it across the 128bits - OrderedNode *DupSrc = _VDupElement(16, 4, Src2, Selector_Src2); + OrderedNode* DupSrc = _VDupElement(16, 4, Src2, Selector_Src2); // Src1/Dest needs a bunch of magic // Shift right by selected bytes // This will give us Dest[15:0], and Dest[79:64] - OrderedNode *Dest1 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 0); + OrderedNode* Dest1 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 0); // This will give us Dest[31:16], and Dest[95:80] - OrderedNode *Dest2 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 1); + OrderedNode* Dest2 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 1); // This will give us Dest[47:32], and Dest[111:96] - OrderedNode *Dest3 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 2); + OrderedNode* Dest3 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 2); // This will give us Dest[63:48], and Dest[127:112] - OrderedNode *Dest4 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 3); + OrderedNode* Dest4 = _VExtr(16, 1, Src1, Src1, Selector_Src1 + 3); // For each shifted section, we now have two 32-bit values per vector that can be used // Dest1.S[0] and Dest1.S[1] = Bytes - 0,1,2,3:4,5,6,7 @@ -5029,10 +4578,10 @@ OrderedNode* OpDispatchBuilder::MPSADBWOpImpl(OpcodeArgs, const X86Tables::Decod const uint8_t Select_Src1_Low = ((Select & 0b100) >> 2) * 32 / 8; const uint8_t Select_Src2_Low = Select & 0b11; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Src1Op, Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); - OrderedNode *Lower = LaneHelper(Select_Src1_Low, Select_Src2_Low, Src1, Src2); + OrderedNode* Lower = LaneHelper(Select_Src1_Low, Select_Src2_Low, Src1, Src2); if (Is128Bit) { return Lower; } @@ -5040,54 +4589,52 @@ OrderedNode* OpDispatchBuilder::MPSADBWOpImpl(OpcodeArgs, const X86Tables::Decod const uint8_t Select_Src1_High = ((Select & 0b100000) >> 5) * 32 / 8; const uint8_t Select_Src2_High = (Select & 0b11000) >> 3; - OrderedNode *UpperSrc1 = _VDupElement(32, 16, Src1, 1); - OrderedNode *UpperSrc2 = _VDupElement(32, 16, Src2, 1); - OrderedNode *Upper = LaneHelper(Select_Src1_High, Select_Src2_High, UpperSrc1, UpperSrc2); + OrderedNode* UpperSrc1 = _VDupElement(32, 16, Src1, 1); + OrderedNode* UpperSrc2 = _VDupElement(32, 16, Src2, 1); + OrderedNode* Upper = LaneHelper(Select_Src1_High, Select_Src2_High, UpperSrc1, UpperSrc2); return _VInsElement(32, 16, 1, 0, Lower, Upper); } void OpDispatchBuilder::MPSADBWOp(OpcodeArgs) { - OrderedNode *Result = MPSADBWOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1]); + OrderedNode* Result = MPSADBWOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1]); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VMPSADBWOp(OpcodeArgs) { - OrderedNode *Result = MPSADBWOpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2]); + OrderedNode* Result = MPSADBWOpImpl(Op, Op->Src[0], Op->Src[1], Op->Src[2]); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VINSERTOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], 16, Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], 16, Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src2 needs to be literal here"); const auto Selector = Op->Src[2].Data.Literal.Value & 1; - OrderedNode *Result = _VInsElement(DstSize, 16, Selector, 0, Src1, Src2); + OrderedNode* Result = _VInsElement(DstSize, 16, Selector, 0, Src1, Src2); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPERM2Op(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src2 needs to be literal here"); const auto Selector = Op->Src[2].Data.Literal.Value; - OrderedNode *Result = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* Result = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); const auto SelectElement = [&](uint64_t Index, uint64_t SelectorIdx) { switch (SelectorIdx) { - case 0: - case 1: - return _VInsElement(DstSize, 16, Index, SelectorIdx, Result, Src1); - case 2: - case 3: - default: - return _VInsElement(DstSize, 16, Index, SelectorIdx - 2, Result, Src2); + case 0: + case 1: return _VInsElement(DstSize, 16, Index, SelectorIdx, Result, Src1); + case 2: + case 3: + default: return _VInsElement(DstSize, 16, Index, SelectorIdx - 2, Result, Src2); } }; @@ -5104,12 +4651,12 @@ void OpDispatchBuilder::VPERM2Op(OpcodeArgs) { void OpDispatchBuilder::VPERMDOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Indices = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Indices = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); // Get rid of any junk unrelated to the relevant selector index bits (bits [2:0]) - OrderedNode *IndexMask = _VectorImm(DstSize, 4, 0b111); - OrderedNode *SanitizedIndices = _VAnd(DstSize, 1, Indices, IndexMask); + OrderedNode* IndexMask = _VectorImm(DstSize, 4, 0b111); + OrderedNode* SanitizedIndices = _VAnd(DstSize, 1, Indices, IndexMask); // Build up the broadcasted index mask. e.g. On x86-64, the selector index // is always in the lower 3 bits of a 32-bit element. However, in order to @@ -5141,8 +4688,8 @@ void OpDispatchBuilder::VPERMDOp(OpcodeArgs) { // // Cool! We now have everything we need to take this further. - OrderedNode *IndexTrn1 = _VTrn(DstSize, 1, SanitizedIndices, SanitizedIndices); - OrderedNode *IndexTrn2 = _VTrn(DstSize, 2, IndexTrn1, IndexTrn1); + OrderedNode* IndexTrn1 = _VTrn(DstSize, 1, SanitizedIndices, SanitizedIndices); + OrderedNode* IndexTrn2 = _VTrn(DstSize, 2, IndexTrn1, IndexTrn1); // Now that we have the indices set up, now we need to multiply each // element by 4 to convert the elements into byte indices rather than @@ -5150,10 +4697,10 @@ void OpDispatchBuilder::VPERMDOp(OpcodeArgs) { // // e.g. We turn our vector into: // ╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗ - // ║ 16 ║║ 16 ║║ 16 ║║ 16 ║║ 4 ║║ 4 ║║ 4 ║║ 4 ║║ 8 ║║ 8 ║║ 8 ║║ 8 ║║ 24 ║║ 24 ║║ 24 ║║ 24 ║║ 28 ║║ 28 ║║ 28 ║║ 28 ║║ 0 ║║ 0 ║║ 0 ║║ 0 ║║ 12 ║║ 12 ║║ 12 ║║ 12 ║║ 20 ║║ 20 ║║ 20 ║║ 20 ║ + // ║ 16 ║║ 16 ║║ 16 ║║ 16 ║║ 4 ║║ 4 ║║ 4 ║║ 4 ║║ 8 ║║ 8 ║║ 8 ║║ 8 ║║ 24 ║║ 24 ║║ 24 ║║ 24 ║║ 28 ║║ 28 ║║ 28 ║║ 28 ║║ 0 ║║ 0 ║║ 0 ║║ 0 ║║ 12 ║║ 12 ║║ 12 ║║ 12 ║║ 20 ║║ 20 ║║ 20 ║║ 20 ║ // ╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝ // - OrderedNode *ShiftedIndices = _VShlI(DstSize, 1, IndexTrn2, 2); + OrderedNode* ShiftedIndices = _VShlI(DstSize, 1, IndexTrn2, 2); // Now we need to add a byte vector containing [3, 2, 1, 0] repeating for the // entire length of it, to the index register, so that we specify the bytes @@ -5162,28 +4709,28 @@ void OpDispatchBuilder::VPERMDOp(OpcodeArgs) { // e.g. Our vector finally looks like so: // // ╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗ - // ║ 19 ║║ 18 ║║ 17 ║║ 16 ║║ 7 ║║ 6 ║║ 5 ║║ 4 ║║ 11 ║║ 10 ║║ 9 ║║ 8 ║║ 27 ║║ 26 ║║ 25 ║║ 24 ║║ 31 ║║ 30 ║║ 29 ║║ 28 ║║ 3 ║║ 2 ║║ 1 ║║ 0 ║║ 15 ║║ 14 ║║ 13 ║║ 12 ║║ 23 ║║ 22 ║║ 21 ║║ 20 ║ + // ║ 19 ║║ 18 ║║ 17 ║║ 16 ║║ 7 ║║ 6 ║║ 5 ║║ 4 ║║ 11 ║║ 10 ║║ 9 ║║ 8 ║║ 27 ║║ 26 ║║ 25 ║║ 24 ║║ 31 ║║ 30 ║║ 29 ║║ 28 ║║ 3 ║║ 2 ║║ 1 ║║ 0 ║║ 15 ║║ 14 ║║ 13 ║║ 12 ║║ 23 ║║ 22 ║║ 21 ║║ 20 ║ // ╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝ // // Which finally lets us permute the source vector and be done with everything. - OrderedNode *AddConst = _Constant(0x03020100); - OrderedNode *AddVector = _VDupFromGPR(DstSize, 4, AddConst); - OrderedNode *FinalIndices = _VAdd(DstSize, 1, ShiftedIndices, AddVector); + OrderedNode* AddConst = _Constant(0x03020100); + OrderedNode* AddVector = _VDupFromGPR(DstSize, 4, AddConst); + OrderedNode* FinalIndices = _VAdd(DstSize, 1, ShiftedIndices, AddVector); // Now lets finally shuffle this bad boy around. - OrderedNode *Result = _VTBL1(DstSize, Src, FinalIndices); + OrderedNode* Result = _VTBL1(DstSize, Src, FinalIndices); StoreResult(FPRClass, Op, Result, -1); } void OpDispatchBuilder::VPERMQOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const auto Selector = Op->Src[1].Data.Literal.Value; - OrderedNode *Result{}; + OrderedNode* Result {}; // If we're just broadcasting one element in particular across the vector // then this can be done fairly simply without any individual inserts. @@ -5200,11 +4747,11 @@ void OpDispatchBuilder::VPERMQOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -static OrderedNode* VBLENDOpImpl(IREmitter& IR, uint32_t VecSize, uint32_t ElementSize, - OrderedNode *Src1, OrderedNode *Src2, OrderedNode *ZeroRegister, uint64_t Selector) { - const std::array Sources{Src1, Src2}; +static OrderedNode* VBLENDOpImpl(IREmitter& IR, uint32_t VecSize, uint32_t ElementSize, OrderedNode* Src1, OrderedNode* Src2, + OrderedNode* ZeroRegister, uint64_t Selector) { + const std::array Sources {Src1, Src2}; - OrderedNode *Result = ZeroRegister; + OrderedNode* Result = ZeroRegister; const int NumElements = VecSize / ElementSize; for (int i = 0; i < NumElements; i++) { const auto SelectorIndex = (Selector >> i) & 1; @@ -5219,26 +4766,26 @@ void OpDispatchBuilder::VBLENDPDOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src[2] needs to be literal here"); const auto Selector = Op->Src[2].Data.Literal.Value; if (Selector == 0) { - OrderedNode *Result = Is256Bit ? Src1 : _VMov(16, Src1); + OrderedNode* Result = Is256Bit ? Src1 : _VMov(16, Src1); StoreResult(FPRClass, Op, Result, -1); return; } // Only the first four bits of the 8-bit immediate are used, so only check them. if (((Selector & 0b11) == 0b11 && !Is256Bit) || (Selector & 0b1111) == 0b1111) { - OrderedNode *Result = Is256Bit ? Src2 : _VMov(16, Src2); + OrderedNode* Result = Is256Bit ? Src2 : _VMov(16, Src2); StoreResult(FPRClass, Op, Result, -1); return; } const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = VBLENDOpImpl(*this, DstSize, 8, Src1, Src2, ZeroRegister, Selector); + OrderedNode* Result = VBLENDOpImpl(*this, DstSize, 8, Src1, Src2, ZeroRegister, Selector); StoreResult(FPRClass, Op, Result, -1); } @@ -5246,8 +4793,8 @@ void OpDispatchBuilder::VPBLENDDOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src[2] needs to be literal here"); const auto Selector = Op->Src[2].Data.Literal.Value; @@ -5281,7 +4828,7 @@ void OpDispatchBuilder::VPBLENDDOp(OpcodeArgs) { } const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = VBLENDOpImpl(*this, DstSize, 4, Src1, Src2, ZeroRegister, Selector); + OrderedNode* Result = VBLENDOpImpl(*this, DstSize, 4, Src1, Src2, ZeroRegister, Selector); if (!Is256Bit) { Result = _VMov(16, Result); } @@ -5292,19 +4839,19 @@ void OpDispatchBuilder::VPBLENDWOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is128Bit = DstSize == Core::CPUState::XMM_SSE_REG_SIZE; - OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src1 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Src2 = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src[2] needs to be literal here"); const auto Selector = Op->Src[2].Data.Literal.Value; if (Selector == 0) { - OrderedNode *Result = Is128Bit ? _VMov(16, Src1) : Src1; + OrderedNode* Result = Is128Bit ? _VMov(16, Src1) : Src1; StoreResult(FPRClass, Op, Result, -1); return; } if (Selector == 0xFF) { - OrderedNode *Result = Is128Bit ? _VMov(16, Src2) : Src2; + OrderedNode* Result = Is128Bit ? _VMov(16, Src2) : Src2; StoreResult(FPRClass, Op, Result, -1); return; } @@ -5315,7 +4862,7 @@ void OpDispatchBuilder::VPBLENDWOp(OpcodeArgs) { const auto NewSelector = Selector << 8 | Selector; const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Result = VBLENDOpImpl(*this, DstSize, 2, Src1, Src2, ZeroRegister, NewSelector); + OrderedNode* Result = VBLENDOpImpl(*this, DstSize, 2, Src1, Src2, ZeroRegister, NewSelector); if (Is128Bit) { Result = _VMov(16, Result); } @@ -5347,7 +4894,7 @@ void OpDispatchBuilder::VZEROOp(OpcodeArgs) { } } -template +template void OpDispatchBuilder::VPERMILImmOp(OpcodeArgs) { const auto DstSize = GetDstSize(Op); const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; @@ -5355,8 +4902,8 @@ void OpDispatchBuilder::VPERMILImmOp(OpcodeArgs) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const auto Selector = Op->Src[1].Data.Literal.Value & 0xFF; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Result = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Result = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); if constexpr (ElementSize == 8) { Result = _VInsElement(DstSize, ElementSize, 0, Selector & 0b0001, Result, Src); @@ -5383,12 +4930,10 @@ void OpDispatchBuilder::VPERMILImmOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPERMILImmOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPERMILImmOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPERMILImmOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPERMILImmOp<8>(OpcodeArgs); -template +template void OpDispatchBuilder::VPERMILRegOp(OpcodeArgs) { // NOTE: See implementation of VPERMD for the gist of what we do to make this work. // @@ -5399,54 +4944,52 @@ void OpDispatchBuilder::VPERMILRegOp(OpcodeArgs) { const auto Is256Bit = DstSize == Core::CPUState::XMM_AVX_REG_SIZE; constexpr auto IsPD = ElementSize == 8; - const auto SanitizeIndices = [&](OrderedNode *Indices) { + const auto SanitizeIndices = [&](OrderedNode* Indices) { const auto ShiftAmount = 0b11 >> static_cast(IsPD); - OrderedNode *IndexMask = _VectorImm(DstSize, ElementSize, ShiftAmount); + OrderedNode* IndexMask = _VectorImm(DstSize, ElementSize, ShiftAmount); return _VAnd(DstSize, 1, Indices, IndexMask); }; - OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - OrderedNode *Indices = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); + OrderedNode* Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* Indices = LoadSource(FPRClass, Op, Op->Src[1], Op->Flags); if constexpr (IsPD) { // VPERMILPD stores the selector in the second bit, rather than the // first bit of each element in the index vector. So move it over by one. Indices = _VUShrI(DstSize, ElementSize, Indices, 1); } - OrderedNode *SanitizedIndices = SanitizeIndices(Indices); - OrderedNode *IndexTrn1 = _VTrn(DstSize, 1, SanitizedIndices, SanitizedIndices); - OrderedNode *IndexTrn2 = _VTrn(DstSize, 2, IndexTrn1, IndexTrn1); - OrderedNode *IndexTrn3 = IndexTrn2; + OrderedNode* SanitizedIndices = SanitizeIndices(Indices); + OrderedNode* IndexTrn1 = _VTrn(DstSize, 1, SanitizedIndices, SanitizedIndices); + OrderedNode* IndexTrn2 = _VTrn(DstSize, 2, IndexTrn1, IndexTrn1); + OrderedNode* IndexTrn3 = IndexTrn2; if constexpr (IsPD) { IndexTrn3 = _VTrn(DstSize, 4, IndexTrn2, IndexTrn2); } constexpr auto IndexShift = IsPD ? 3 : 2; - OrderedNode *ShiftedIndices = _VShlI(DstSize, 1, IndexTrn3, IndexShift); + OrderedNode* ShiftedIndices = _VShlI(DstSize, 1, IndexTrn3, IndexShift); constexpr uint64_t VConstant = IsPD ? 0x0706050403020100 : 0x03020100; - OrderedNode *VectorConst = _VDupFromGPR(DstSize, ElementSize, _Constant(VConstant)); - OrderedNode *FinalIndices{}; + OrderedNode* VectorConst = _VDupFromGPR(DstSize, ElementSize, _Constant(VConstant)); + OrderedNode* FinalIndices {}; if (Is256Bit) { const auto ZeroRegister = LoadAndCacheNamedVectorConstant(DstSize, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); - OrderedNode *Vector16 = _VInsElement(DstSize, 16, 1, 0, ZeroRegister, _VectorImm(DstSize, 1, 16)); - OrderedNode *IndexOffsets = _VAdd(DstSize, 1, VectorConst, Vector16); + OrderedNode* Vector16 = _VInsElement(DstSize, 16, 1, 0, ZeroRegister, _VectorImm(DstSize, 1, 16)); + OrderedNode* IndexOffsets = _VAdd(DstSize, 1, VectorConst, Vector16); FinalIndices = _VAdd(DstSize, 1, IndexOffsets, ShiftedIndices); } else { FinalIndices = _VAdd(DstSize, 1, VectorConst, ShiftedIndices); } - OrderedNode *Result = _VTBL1(DstSize, Src, FinalIndices); + OrderedNode* Result = _VTBL1(DstSize, Src, FinalIndices); StoreResult(FPRClass, Op, Result, -1); } -template -void OpDispatchBuilder::VPERMILRegOp<4>(OpcodeArgs); -template -void OpDispatchBuilder::VPERMILRegOp<8>(OpcodeArgs); +template void OpDispatchBuilder::VPERMILRegOp<4>(OpcodeArgs); +template void OpDispatchBuilder::VPERMILRegOp<8>(OpcodeArgs); void OpDispatchBuilder::PCMPXSTRXOpImpl(OpcodeArgs, bool IsExplicit, bool IsMask) { LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src[1] needs to be a literal"); @@ -5462,11 +5005,10 @@ void OpDispatchBuilder::PCMPXSTRXOpImpl(OpcodeArgs, bool IsExplicit, bool IsMask // instructions in the Intel Software Development Manual). // // So, we specify Src2 as having an alignment of 1 to indicate this. - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, 16, Op->Flags); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags, - {.Align = 1}); + OrderedNode* Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, 16, Op->Flags); + OrderedNode* Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags, {.Align = 1}); - OrderedNode *IntermediateResult{}; + OrderedNode* IntermediateResult {}; if (IsExplicit) { // Will be 4 in the absence of a REX.W bit and 8 in the presence of a REX.W bit. // @@ -5477,15 +5019,15 @@ void OpDispatchBuilder::PCMPXSTRXOpImpl(OpcodeArgs, bool IsExplicit, bool IsMask const auto Is64Bit = SrcSize == 8; const auto NewControl = uint16_t(Control | (uint16_t(Is64Bit) << 8)); - OrderedNode *SrcRAX = LoadGPRRegister(X86State::REG_RAX); - OrderedNode *SrcRDX = LoadGPRRegister(X86State::REG_RDX); + OrderedNode* SrcRAX = LoadGPRRegister(X86State::REG_RAX); + OrderedNode* SrcRDX = LoadGPRRegister(X86State::REG_RDX); IntermediateResult = _VPCMPESTRX(Src1, Src2, SrcRAX, SrcRDX, NewControl); } else { IntermediateResult = _VPCMPISTRX(Src1, Src2, Control); } - OrderedNode *ZeroConst = _Constant(0); + OrderedNode* ZeroConst = _Constant(0); if (IsMask) { // For the masked variant of the instructions, if control[6] is set, then we @@ -5501,12 +5043,12 @@ void OpDispatchBuilder::PCMPXSTRXOpImpl(OpcodeArgs, bool IsExplicit, bool IsMask if (IsExpandedMask) { // We need to iterate over the intermediate result and // expand the mask into XMM0 elements. - const auto ElementSize = 1U << (Control & 1); + const auto ElementSize = 1U << (Control & 1); const auto NumElements = 16U >> (Control & 1); - OrderedNode *Result = LoadAndCacheNamedVectorConstant(Core::CPUState::XMM_SSE_REG_SIZE, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); + OrderedNode* Result = LoadAndCacheNamedVectorConstant(Core::CPUState::XMM_SSE_REG_SIZE, FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_ZERO); for (uint32_t i = 0; i < NumElements; i++) { - OrderedNode *SignBit = _Sbfe(OpSize::i64Bit, 1, i, IntermediateResult); + OrderedNode* SignBit = _Sbfe(OpSize::i64Bit, 1, i, IntermediateResult); Result = _VInsGPR(Core::CPUState::XMM_SSE_REG_SIZE, ElementSize, i, Result, SignBit); } StoreXMMRegister(0, Result); @@ -5520,14 +5062,12 @@ void OpDispatchBuilder::PCMPXSTRXOpImpl(OpcodeArgs, bool IsExplicit, bool IsMask // then we store the least significant bit. const auto UseMSBIndex = (Control & 0b0100'0000) != 0; - OrderedNode *ResultNoFlags = _Bfe(OpSize::i32Bit, 16, 0, IntermediateResult); + OrderedNode* ResultNoFlags = _Bfe(OpSize::i32Bit, 16, 0, IntermediateResult); - OrderedNode *IfZero = _Constant(16 >> (Control & 1)); - OrderedNode *IfNotZero = UseMSBIndex ? _FindMSB(IR::OpSize::i32Bit, ResultNoFlags) - : _FindLSB(IR::OpSize::i32Bit, ResultNoFlags); + OrderedNode* IfZero = _Constant(16 >> (Control & 1)); + OrderedNode* IfNotZero = UseMSBIndex ? _FindMSB(IR::OpSize::i32Bit, ResultNoFlags) : _FindLSB(IR::OpSize::i32Bit, ResultNoFlags); - OrderedNode *Result = _Select(IR::COND_EQ, ResultNoFlags, ZeroConst, - IfZero, IfNotZero); + OrderedNode* Result = _Select(IR::COND_EQ, ResultNoFlags, ZeroConst, IfZero, IfNotZero); const uint8_t GPRSize = CTX->GetGPRSize(); if (GPRSize == 8) { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp index 9751766a8..76dab8976 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp @@ -23,62 +23,59 @@ class OrderedNode; #define OpcodeArgs [[maybe_unused]] FEXCore::X86Tables::DecodedOp Op -OrderedNode *OpDispatchBuilder::GetX87Top() { +OrderedNode* OpDispatchBuilder::GetX87Top() { // Yes, we are storing 3 bits in a single flag register. // Deal with it return _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, flags) + FEXCore::X86State::X87FLAG_TOP_LOC); } -void OpDispatchBuilder::SetX87ValidTag(OrderedNode *Value, bool Valid) { +void OpDispatchBuilder::SetX87ValidTag(OrderedNode* Value, bool Valid) { // if we are popping then we must first mark this location as empty - OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); - OrderedNode *RegMask = _Lshl(OpSize::i32Bit, _Constant(1), Value); - OrderedNode *NewAbridgedFTW = Valid ? _Or(OpSize::i32Bit, AbridgedFTW, RegMask) : _Andn(OpSize::i32Bit, AbridgedFTW, RegMask); + OrderedNode* AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + OrderedNode* RegMask = _Lshl(OpSize::i32Bit, _Constant(1), Value); + OrderedNode* NewAbridgedFTW = Valid ? _Or(OpSize::i32Bit, AbridgedFTW, RegMask) : _Andn(OpSize::i32Bit, AbridgedFTW, RegMask); _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } -OrderedNode *OpDispatchBuilder::GetX87ValidTag(OrderedNode *Value) { - OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); +OrderedNode* OpDispatchBuilder::GetX87ValidTag(OrderedNode* Value) { + OrderedNode* AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); return _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1)); } -OrderedNode *OpDispatchBuilder::GetX87Tag(OrderedNode *Value, OrderedNode *AbridgedFTW) { - OrderedNode *RegValid = _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1)); - OrderedNode *X87Empty = _Constant(static_cast(FPState::X87Tag::Empty)); - OrderedNode *X87Valid = _Constant(static_cast(FPState::X87Tag::Valid)); +OrderedNode* OpDispatchBuilder::GetX87Tag(OrderedNode* Value, OrderedNode* AbridgedFTW) { + OrderedNode* RegValid = _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1)); + OrderedNode* X87Empty = _Constant(static_cast(FPState::X87Tag::Empty)); + OrderedNode* X87Valid = _Constant(static_cast(FPState::X87Tag::Valid)); - return _Select(FEXCore::IR::COND_EQ, - RegValid, _Constant(0), - X87Empty, X87Valid); + return _Select(FEXCore::IR::COND_EQ, RegValid, _Constant(0), X87Empty, X87Valid); } -OrderedNode *OpDispatchBuilder::GetX87Tag(OrderedNode *Value) { - OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); +OrderedNode* OpDispatchBuilder::GetX87Tag(OrderedNode* Value) { + OrderedNode* AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); return GetX87Tag(Value, AbridgedFTW); } -void OpDispatchBuilder::SetX87FTW(OrderedNode *FTW) { - OrderedNode *X87Empty = _Constant(static_cast(FPState::X87Tag::Empty)); - OrderedNode *NewAbridgedFTW; +void OpDispatchBuilder::SetX87FTW(OrderedNode* FTW) { + OrderedNode* X87Empty = _Constant(static_cast(FPState::X87Tag::Empty)); + OrderedNode* NewAbridgedFTW; for (int i = 0; i < 8; i++) { - OrderedNode *RegTag = _Bfe(OpSize::i32Bit, 2, i * 2, FTW); - OrderedNode *RegValid = _Select(FEXCore::IR::COND_NEQ, - RegTag, X87Empty, - _Constant(1), _Constant(0)); + OrderedNode* RegTag = _Bfe(OpSize::i32Bit, 2, i * 2, FTW); + OrderedNode* RegValid = _Select(FEXCore::IR::COND_NEQ, RegTag, X87Empty, _Constant(1), _Constant(0)); - if (i) + if (i) { NewAbridgedFTW = _Orlshl(OpSize::i32Bit, NewAbridgedFTW, RegValid, i); - else + } else { NewAbridgedFTW = RegValid; + } } _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } -OrderedNode *OpDispatchBuilder::GetX87FTW() { - OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); - OrderedNode *FTW = _Constant(0); +OrderedNode* OpDispatchBuilder::GetX87FTW() { + OrderedNode* AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + OrderedNode* FTW = _Constant(0); for (int i = 0; i < 8; i++) { const auto RegTag = GetX87Tag(_Constant(i), AbridgedFTW); @@ -88,13 +85,13 @@ OrderedNode *OpDispatchBuilder::GetX87FTW() { return FTW; } -void OpDispatchBuilder::SetX87Top(OrderedNode *Value) { +void OpDispatchBuilder::SetX87Top(OrderedNode* Value) { _StoreContext(1, GPRClass, Value, offsetof(FEXCore::Core::CPUState, flags) + FEXCore::X86State::X87FLAG_TOP_LOC); } -OrderedNode *OpDispatchBuilder::ReconstructFSW() { +OrderedNode* OpDispatchBuilder::ReconstructFSW() { // We must construct the FSW from our various bits - OrderedNode *FSW = _Constant(0); + OrderedNode* FSW = _Constant(0); auto Top = GetX87Top(); FSW = _Bfi(OpSize::i64Bit, 3, 11, FSW, Top); @@ -110,12 +107,12 @@ OrderedNode *OpDispatchBuilder::ReconstructFSW() { return FSW; } -OrderedNode *OpDispatchBuilder::ReconstructX87StateFromFSW(OrderedNode *FSW) { +OrderedNode* OpDispatchBuilder::ReconstructX87StateFromFSW(OrderedNode* FSW) { auto Top = _Bfe(OpSize::i32Bit, 3, 11, FSW); SetX87Top(Top); - auto C0 = _Bfe(OpSize::i32Bit, 1, 8, FSW); - auto C1 = _Bfe(OpSize::i32Bit, 1, 9, FSW); + auto C0 = _Bfe(OpSize::i32Bit, 1, 8, FSW); + auto C1 = _Bfe(OpSize::i32Bit, 1, 9, FSW); auto C2 = _Bfe(OpSize::i32Bit, 1, 10, FSW); auto C3 = _Bfe(OpSize::i32Bit, 1, 14, FSW); @@ -134,19 +131,18 @@ void OpDispatchBuilder::FLD(OpcodeArgs) { size_t read_width = (width == 80) ? 16 : width / 8; - OrderedNode *data{}; + OrderedNode* data {}; if (!Op->Src[0].IsNone()) { // Read from memory data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], read_width, Op->Flags); - } - else { + } else { // Implicit arg auto offset = _Constant(Op->OP & 7); data = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, offset), mask); data = _LoadContextIndexed(data, 16, MMBaseOffset(), 16, FPRClass); } - OrderedNode *converted = data; + OrderedNode* converted = data; // Convert to 80bit float if constexpr (width == 32 || width == 64) { @@ -161,12 +157,9 @@ void OpDispatchBuilder::FLD(OpcodeArgs) { //_StoreContext(converted, 16, offsetof(FEXCore::Core::CPUState, mm[7][0])); } -template -void OpDispatchBuilder::FLD<32>(OpcodeArgs); -template -void OpDispatchBuilder::FLD<64>(OpcodeArgs); -template -void OpDispatchBuilder::FLD<80>(OpcodeArgs); +template void OpDispatchBuilder::FLD<32>(OpcodeArgs); +template void OpDispatchBuilder::FLD<64>(OpcodeArgs); +template void OpDispatchBuilder::FLD<80>(OpcodeArgs); void OpDispatchBuilder::FBLD(OpcodeArgs) { // Update TOP @@ -177,8 +170,8 @@ void OpDispatchBuilder::FBLD(OpcodeArgs) { SetX87Top(top); // Read from memory - OrderedNode *data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags); - OrderedNode *converted = _F80BCDLoad(data); + OrderedNode* data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags); + OrderedNode* converted = _F80BCDLoad(data); _StoreContextIndexed(converted, top, 16, MMBaseOffset(), 16, FPRClass); } @@ -186,7 +179,7 @@ void OpDispatchBuilder::FBSTP(OpcodeArgs) { auto orig_top = GetX87Top(); auto data = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); - OrderedNode *converted = _F80BCDStore(data); + OrderedNode* converted = _F80BCDStore(data); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, converted, 10, 1); @@ -204,26 +197,19 @@ void OpDispatchBuilder::FLD_Const(OpcodeArgs) { SetX87ValidTag(top, true); SetX87Top(top); - OrderedNode *data = LoadAndCacheNamedVectorConstant(16, constant); + OrderedNode* data = LoadAndCacheNamedVectorConstant(16, constant); // Write to ST[TOP] _StoreContextIndexed(data, top, 16, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FLD_Const(OpcodeArgs); // 1.0 -template -void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log2l(10) -template -void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log2l(e) -template -void OpDispatchBuilder::FLD_Const(OpcodeArgs); // pi -template -void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log10l(2) -template -void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log(2) -template -void OpDispatchBuilder::FLD_Const(OpcodeArgs); // 0.0 +template void OpDispatchBuilder::FLD_Const(OpcodeArgs); // 1.0 +template void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log2l(10) +template void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log2l(e) +template void OpDispatchBuilder::FLD_Const(OpcodeArgs); // pi +template void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log10l(2) +template void OpDispatchBuilder::FLD_Const(OpcodeArgs); // log(2) +template void OpDispatchBuilder::FLD_Const(OpcodeArgs); // 0.0 void OpDispatchBuilder::FILD(OpcodeArgs) { // Update TOP @@ -249,8 +235,8 @@ void OpDispatchBuilder::FILD(OpcodeArgs) { // Extract sign and make interger absolute _SubNZCV(OpSize::i64Bit, data, zero); - auto sign = _NZCVSelect(OpSize::i64Bit, CondClassType{COND_SLT}, _Constant(0x8000), zero); - auto absolute = _Neg(OpSize::i64Bit, data, CondClassType{COND_MI}); + auto sign = _NZCVSelect(OpSize::i64Bit, CondClassType {COND_SLT}, _Constant(0x8000), zero); + auto absolute = _Neg(OpSize::i64Bit, data, CondClassType {COND_MI}); // left justify the absolute interger auto shift = _Sub(OpSize::i64Bit, _Constant(63), _FindMSB(IR::OpSize::i64Bit, absolute)); @@ -261,7 +247,7 @@ void OpDispatchBuilder::FILD(OpcodeArgs) { auto upper = _Or(OpSize::i64Bit, sign, zeroed_exponent); - OrderedNode *converted = _VCastFromGPR(16, 8, shifted); + OrderedNode* converted = _VCastFromGPR(16, 8, shifted); converted = _VInsElement(16, 8, 1, 0, converted, _VCastFromGPR(16, 8, upper)); // Write to ST[TOP] @@ -274,8 +260,7 @@ void OpDispatchBuilder::FST(OpcodeArgs) { auto data = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); if constexpr (width == 80) { StoreResult_WithOpSize(FPRClass, Op, Op->Dest, data, 10, 1); - } - else if constexpr (width == 32 || width == 64) { + } else if constexpr (width == 32 || width == 64) { auto result = _F80CVT(width / 8, data); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, result, width / 8, 1); } @@ -289,19 +274,16 @@ void OpDispatchBuilder::FST(OpcodeArgs) { } } -template -void OpDispatchBuilder::FST<32>(OpcodeArgs); -template -void OpDispatchBuilder::FST<64>(OpcodeArgs); -template -void OpDispatchBuilder::FST<80>(OpcodeArgs); +template void OpDispatchBuilder::FST<32>(OpcodeArgs); +template void OpDispatchBuilder::FST<64>(OpcodeArgs); +template void OpDispatchBuilder::FST<80>(OpcodeArgs); template void OpDispatchBuilder::FIST(OpcodeArgs) { auto Size = GetSrcSize(Op); auto orig_top = GetX87Top(); - OrderedNode *data = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); + OrderedNode* data = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); data = _F80CVTInt(Size, data, Truncate); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, data, Size, 1); @@ -315,18 +297,16 @@ void OpDispatchBuilder::FIST(OpcodeArgs) { } } -template -void OpDispatchBuilder::FIST(OpcodeArgs); -template -void OpDispatchBuilder::FIST(OpcodeArgs); +template void OpDispatchBuilder::FIST(OpcodeArgs); +template void OpDispatchBuilder::FIST(OpcodeArgs); -template +template void OpDispatchBuilder::FADD(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; + OrderedNode* StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); @@ -336,8 +316,7 @@ void OpDispatchBuilder::FADD(OpcodeArgs) { if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTToInt(arg, width / 8); - } - else { + } else { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTTo(arg, width / 8); } @@ -367,26 +346,20 @@ void OpDispatchBuilder::FADD(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 16, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FADD<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADD<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FADD<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADD<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADD<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FADD<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADD<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADD<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADD<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); template void OpDispatchBuilder::FMUL(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* StackLocation = top; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); @@ -397,8 +370,7 @@ void OpDispatchBuilder::FMUL(OpcodeArgs) { if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTToInt(arg, width / 8); - } - else { + } else { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTTo(arg, width / 8); } @@ -430,26 +402,20 @@ void OpDispatchBuilder::FMUL(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 16, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FMUL<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMUL<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FMUL<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMUL<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMUL<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FMUL<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMUL<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMUL<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMUL<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); template void OpDispatchBuilder::FDIV(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* StackLocation = top; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); @@ -460,8 +426,7 @@ void OpDispatchBuilder::FDIV(OpcodeArgs) { if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTToInt(arg, width / 8); - } - else { + } else { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTTo(arg, width / 8); } @@ -479,11 +444,10 @@ void OpDispatchBuilder::FDIV(OpcodeArgs) { auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); - OrderedNode *result{}; + OrderedNode* result {}; if constexpr (reverse) { result = _F80Div(b, a); - } - else { + } else { result = _F80Div(a, b); } @@ -499,42 +463,30 @@ void OpDispatchBuilder::FDIV(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 16, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FDIV<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIV<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIV<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); template void OpDispatchBuilder::FSUB(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* StackLocation = top; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); @@ -545,8 +497,7 @@ void OpDispatchBuilder::FSUB(OpcodeArgs) { if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTToInt(arg, width / 8); - } - else { + } else { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTTo(arg, width / 8); } @@ -563,11 +514,10 @@ void OpDispatchBuilder::FSUB(OpcodeArgs) { auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); - OrderedNode *result{}; + OrderedNode* result {}; if constexpr (reverse) { result = _F80Sub(b, a); - } - else { + } else { result = _F80Sub(a, b); } @@ -584,35 +534,23 @@ void OpDispatchBuilder::FSUB(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 16, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FSUB<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUB<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUB<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); void OpDispatchBuilder::FCHS(OpcodeArgs) { auto top = GetX87Top(); @@ -620,7 +558,7 @@ void OpDispatchBuilder::FCHS(OpcodeArgs) { auto low = _Constant(0); auto high = _Constant(0b1'000'0000'0000'0000ULL); - OrderedNode *data = _VCastFromGPR(16, 8, low); + OrderedNode* data = _VCastFromGPR(16, 8, low); data = _VInsGPR(16, 8, 1, data, high); auto result = _VXor(16, 1, a, data); @@ -635,7 +573,7 @@ void OpDispatchBuilder::FABS(OpcodeArgs) { auto low = _Constant(~0ULL); auto high = _Constant(0b0'111'1111'1111'1111ULL); - OrderedNode *data = _VCastFromGPR(16, 8, low); + OrderedNode* data = _VCastFromGPR(16, 8, low); data = _VInsGPR(16, 8, 1, data, high); auto result = _VAnd(16, 1, a, data); @@ -649,16 +587,13 @@ void OpDispatchBuilder::FTST(OpcodeArgs) { auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); auto low = _Constant(0); - OrderedNode *data = _VCastFromGPR(16, 8, low); + OrderedNode* data = _VCastFromGPR(16, 8, low); - OrderedNode *Res = _F80Cmp(a, data, - (1 << FCMP_FLAG_EQ) | - (1 << FCMP_FLAG_LT) | - (1 << FCMP_FLAG_UNORDERED)); + OrderedNode* Res = _F80Cmp(a, data, (1 << FCMP_FLAG_EQ) | (1 << FCMP_FLAG_LT) | (1 << FCMP_FLAG_UNORDERED)); - OrderedNode *HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); - OrderedNode *HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); - OrderedNode *HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); + OrderedNode* HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); + OrderedNode* HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); + OrderedNode* HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); HostFlag_CF = _Or(OpSize::i32Bit, HostFlag_CF, HostFlag_Unordered); HostFlag_ZF = _Or(OpSize::i32Bit, HostFlag_ZF, HostFlag_Unordered); @@ -717,8 +652,8 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) { auto top = GetX87Top(); auto mask = _Constant(7); - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* arg {}; + OrderedNode* b {}; if (!Op->Src[0].IsNone()) { // Memory arg @@ -726,8 +661,7 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) { if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTToInt(arg, width / 8); - } - else { + } else { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); b = _F80CVTTo(arg, width / 8); } @@ -741,14 +675,11 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) { auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); - OrderedNode *Res = _F80Cmp(a, b, - (1 << FCMP_FLAG_EQ) | - (1 << FCMP_FLAG_LT) | - (1 << FCMP_FLAG_UNORDERED)); + OrderedNode* Res = _F80Cmp(a, b, (1 << FCMP_FLAG_EQ) | (1 << FCMP_FLAG_LT) | (1 << FCMP_FLAG_UNORDERED)); - OrderedNode *HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); - OrderedNode *HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); - OrderedNode *HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); + OrderedNode* HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); + OrderedNode* HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); + OrderedNode* HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); HostFlag_CF = _Or(OpSize::i32Bit, HostFlag_CF, HostFlag_Unordered); HostFlag_ZF = _Or(OpSize::i32Bit, HostFlag_ZF, HostFlag_Unordered); @@ -757,8 +688,7 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) { SetRFLAG(_Constant(0)); SetRFLAG(HostFlag_Unordered); SetRFLAG(HostFlag_ZF); - } - else { + } else { // Invalidate deferred flags early // OF, SF, AF, PF all undefined InvalidateDeferredFlags(); @@ -780,8 +710,7 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) { // Set the new top now top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask); SetX87Top(top); - } - else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + } else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { // if we are popping then we must first mark this location as empty SetX87ValidTag(top, false); // Set the new top now @@ -790,24 +719,17 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) { } } -template -void OpDispatchBuilder::FCOMI<32, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMI<32, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMI<64, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMI<64, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>(OpcodeArgs); +template void OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMI<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMI<16, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMI<16, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMI<32, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMI<32, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); void OpDispatchBuilder::FXCH(OpcodeArgs) { @@ -858,8 +780,7 @@ void OpDispatchBuilder::X87UnaryOp(OpcodeArgs) { DeriveOp(result, IROp, _F80Round(a)); - if constexpr (IROp == IR::OP_F80SIN || - IROp == IR::OP_F80COS) { + if constexpr (IROp == IR::OP_F80SIN || IROp == IR::OP_F80COS) { // TODO: ACCURACY: should check source is in range –2^63 to +2^63 SetRFLAG(_Constant(0)); } @@ -868,30 +789,25 @@ void OpDispatchBuilder::X87UnaryOp(OpcodeArgs) { _StoreContextIndexed(result, top, 16, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); +template void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); +template void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); +template void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); +template void OpDispatchBuilder::X87UnaryOp(OpcodeArgs); template void OpDispatchBuilder::X87BinaryOp(OpcodeArgs) { auto top = GetX87Top(); auto mask = _Constant(7); - OrderedNode *st1 = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask); + OrderedNode* st1 = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask); auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); st1 = _LoadContextIndexed(st1, 16, MMBaseOffset(), 16, FPRClass); DeriveOp(result, IROp, _F80Add(a, st1)); - if constexpr (IROp == IR::OP_F80FPREM || - IROp == IR::OP_F80FPREM1) { - //TODO: Set C0 to Q2, C3 to Q1, C1 to Q0 + if constexpr (IROp == IR::OP_F80FPREM || IROp == IR::OP_F80FPREM1) { + // TODO: Set C0 to Q2, C3 to Q1, C1 to Q0 SetRFLAG(_Constant(0)); } @@ -899,12 +815,9 @@ void OpDispatchBuilder::X87BinaryOp(OpcodeArgs) { _StoreContextIndexed(result, top, 16, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::X87BinaryOp(OpcodeArgs); -template -void OpDispatchBuilder::X87BinaryOp(OpcodeArgs); -template -void OpDispatchBuilder::X87BinaryOp(OpcodeArgs); +template void OpDispatchBuilder::X87BinaryOp(OpcodeArgs); +template void OpDispatchBuilder::X87BinaryOp(OpcodeArgs); +template void OpDispatchBuilder::X87BinaryOp(OpcodeArgs); template void OpDispatchBuilder::X87ModifySTP(OpcodeArgs) { @@ -912,17 +825,14 @@ void OpDispatchBuilder::X87ModifySTP(OpcodeArgs) { if (Inc) { auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); - } - else { + } else { auto top = _And(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); } } -template -void OpDispatchBuilder::X87ModifySTP(OpcodeArgs); -template -void OpDispatchBuilder::X87ModifySTP(OpcodeArgs); +template void OpDispatchBuilder::X87ModifySTP(OpcodeArgs); +template void OpDispatchBuilder::X87ModifySTP(OpcodeArgs); void OpDispatchBuilder::X87SinCos(OpcodeArgs) { auto orig_top = GetX87Top(); @@ -952,11 +862,11 @@ void OpDispatchBuilder::X87FYL2X(OpcodeArgs) { auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); - OrderedNode *st0 = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); - OrderedNode *st1 = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); + OrderedNode* st0 = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); + OrderedNode* st1 = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); if (Plus1) { - OrderedNode *data = LoadAndCacheNamedVectorConstant(16, NamedVectorConstant::NAMED_VECTOR_X87_ONE); + OrderedNode* data = LoadAndCacheNamedVectorConstant(16, NamedVectorConstant::NAMED_VECTOR_X87_ONE); st0 = _F80Add(st0, data); } @@ -976,7 +886,7 @@ void OpDispatchBuilder::X87TAN(OpcodeArgs) { auto result = _F80TAN(a); - OrderedNode *data = LoadAndCacheNamedVectorConstant(16, NamedVectorConstant::NAMED_VECTOR_X87_ONE); + OrderedNode* data = LoadAndCacheNamedVectorConstant(16, NamedVectorConstant::NAMED_VECTOR_X87_ONE); // TODO: ACCURACY: should check source is in range –2^63 to +2^63 SetRFLAG(_Constant(0)); @@ -994,7 +904,7 @@ void OpDispatchBuilder::X87ATAN(OpcodeArgs) { SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); - OrderedNode *st1 = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); + OrderedNode* st1 = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); auto result = _F80ATAN(st1, a); @@ -1004,18 +914,18 @@ void OpDispatchBuilder::X87ATAN(OpcodeArgs) { void OpDispatchBuilder::X87LDENV(OpcodeArgs) { const auto Size = GetSrcSize(Op); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Src[0]); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Src[0]); auto NewFCW = _LoadMem(GPRClass, 2, Mem, 2); _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); auto NewFSW = _LoadMem(GPRClass, Size, MemLocation, Size); ReconstructX87StateFromFSW(NewFSW); { // FTW - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } } @@ -1041,7 +951,7 @@ void OpDispatchBuilder::X87FNSTENV(OpcodeArgs) { // 4 bytes : data pointer selector const auto Size = GetDstSize(Op); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Dest); { auto FCW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FCW)); @@ -1049,7 +959,7 @@ void OpDispatchBuilder::X87FNSTENV(OpcodeArgs) { } { - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); _StoreMem(GPRClass, Size, MemLocation, ReconstructFSW(), Size); } @@ -1057,37 +967,37 @@ void OpDispatchBuilder::X87FNSTENV(OpcodeArgs) { { // FTW - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); _StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size); } { // Instruction Offset - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 3)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 3)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Instruction CS selector (+ Opcode) - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 4)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 4)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Data pointer offset - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 5)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 5)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Data pointer selector - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 6)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 6)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } } void OpDispatchBuilder::X87FLDCW(OpcodeArgs) { - OrderedNode *NewFCW = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* NewFCW = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); } @@ -1098,7 +1008,7 @@ void OpDispatchBuilder::X87FSTCW(OpcodeArgs) { } void OpDispatchBuilder::X87LDSW(OpcodeArgs) { - OrderedNode *NewFSW = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + OrderedNode* NewFSW = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); ReconstructX87StateFromFSW(NewFSW); } @@ -1127,15 +1037,15 @@ void OpDispatchBuilder::X87FNSAVE(OpcodeArgs) { // 4 bytes : data pointer selector const auto Size = GetDstSize(Op); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Dest); - OrderedNode *Top = GetX87Top(); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Top = GetX87Top(); { auto FCW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FCW)); _StoreMem(GPRClass, Size, Mem, FCW, Size); } { - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); _StoreMem(GPRClass, Size, MemLocation, ReconstructFSW(), Size); } @@ -1143,35 +1053,35 @@ void OpDispatchBuilder::X87FNSAVE(OpcodeArgs) { { // FTW - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); _StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size); } { // Instruction Offset - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 3)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 3)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Instruction CS selector (+ Opcode) - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 4)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 4)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Data pointer offset - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 5)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 5)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Data pointer selector - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 6)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 6)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } - OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); + OrderedNode* ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); auto OneConst = _Constant(1); auto SevenConst = _Constant(7); @@ -1199,21 +1109,21 @@ void OpDispatchBuilder::X87FNSAVE(OpcodeArgs) { void OpDispatchBuilder::X87FRSTOR(OpcodeArgs) { const auto Size = GetSrcSize(Op); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Src[0]); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Src[0]); auto NewFCW = _LoadMem(GPRClass, 2, Mem, 2); _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); auto NewFSW = _LoadMem(GPRClass, Size, MemLocation, Size); auto Top = ReconstructX87StateFromFSW(NewFSW); { // FTW - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } - OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); + OrderedNode* ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); auto OneConst = _Constant(1); auto SevenConst = _Constant(7); @@ -1221,11 +1131,11 @@ void OpDispatchBuilder::X87FRSTOR(OpcodeArgs) { auto low = _Constant(~0ULL); auto high = _Constant(0xFFFF); - OrderedNode *Mask = _VCastFromGPR(16, 8, low); + OrderedNode* Mask = _VCastFromGPR(16, 8, low); Mask = _VInsGPR(16, 8, 1, Mask, high); for (int i = 0; i < 7; ++i) { - OrderedNode *Reg = _LoadMem(FPRClass, 16, ST0Location, 1); + OrderedNode* Reg = _LoadMem(FPRClass, 16, ST0Location, 1); // Mask off the top bits Reg = _VAnd(16, 16, Reg, Mask); @@ -1240,9 +1150,9 @@ void OpDispatchBuilder::X87FRSTOR(OpcodeArgs) { // Lower 64bits [63:0] // upper 16 bits [79:64] - OrderedNode *Reg = _LoadMem(FPRClass, 8, ST0Location, 1); + OrderedNode* Reg = _LoadMem(FPRClass, 8, ST0Location, 1); ST0Location = _Add(OpSize::i64Bit, ST0Location, _Constant(8)); - OrderedNode *RegHigh = _LoadMem(FPRClass, 2, ST0Location, 1); + OrderedNode* RegHigh = _LoadMem(FPRClass, 2, ST0Location, 1); Reg = _VInsElement(16, 2, 4, 0, Reg, RegHigh); _StoreContextIndexed(Reg, Top, 16, MMBaseOffset(), 16, FPRClass); } @@ -1250,7 +1160,7 @@ void OpDispatchBuilder::X87FRSTOR(OpcodeArgs) { void OpDispatchBuilder::X87FXAM(OpcodeArgs) { auto top = GetX87Top(); auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); - OrderedNode *Result = _VExtractToGPR(16, 8, a, 1); + OrderedNode* Result = _VExtractToGPR(16, 8, a, 1); // Extract the sign bit Result = _Bfe(OpSize::i64Bit, 1, 15, Result); @@ -1263,9 +1173,7 @@ void OpDispatchBuilder::X87FXAM(OpcodeArgs) { auto OneConst = _Constant(1); // In the case of top being invalid then C3:C2:C0 is 0b101 - auto C3 = _Select(FEXCore::IR::COND_NEQ, - TopValid, OneConst, - OneConst, ZeroConst); + auto C3 = _Select(FEXCore::IR::COND_NEQ, TopValid, OneConst, OneConst, ZeroConst); auto C2 = TopValid; auto C0 = C3; // Mirror C3 until something other than zero is supported @@ -1283,38 +1191,36 @@ void OpDispatchBuilder::X87FCMOV(OpcodeArgs) { switch (Opcode) { case 0x3'C0: CC = 0x3; // JNC - break; + break; case 0x2'C0: CC = 0x2; // JC - break; + break; case 0x2'C8: CC = 0x4; // JE - break; + break; case 0x3'C8: CC = 0x5; // JNE - break; + break; case 0x2'D0: CC = 0x6; // JNA - break; + break; case 0x3'D0: CC = 0x7; // JA - break; + break; case 0x2'D8: CC = 0xA; // JP - break; + break; case 0x3'D8: CC = 0xB; // JNP - break; - default: - LOGMAN_MSG_A_FMT("Unhandled FCMOV op: 0x{:x}", Opcode); - break; + break; + default: LOGMAN_MSG_A_FMT("Unhandled FCMOV op: 0x{:x}", Opcode); break; } auto ZeroConst = _Constant(0); auto AllOneConst = _Constant(0xffff'ffff'ffff'ffffull); - OrderedNode *SrcCond = SelectCC(CC, OpSize::i64Bit, AllOneConst, ZeroConst); - OrderedNode *VecCond = _VDupFromGPR(16, 8, SrcCond); + OrderedNode* SrcCond = SelectCC(CC, OpSize::i64Bit, AllOneConst, ZeroConst); + OrderedNode* VecCond = _VDupFromGPR(16, 8, SrcCond); auto top = GetX87Top(); OrderedNode* arg; @@ -1340,7 +1246,7 @@ void OpDispatchBuilder::X87EMMS(OpcodeArgs) { void OpDispatchBuilder::X87FFREE(OpcodeArgs) { // Only sets the selected stack register's tag bits to EMPTY - OrderedNode *top = GetX87Top(); + OrderedNode* top = GetX87Top(); // Implicit arg auto offset = _Constant(Op->OP & 7); @@ -1350,4 +1256,4 @@ void OpDispatchBuilder::X87FFREE(OpcodeArgs) { SetX87ValidTag(top, false); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index c7d6f6c5e..732dd7430 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -22,24 +22,24 @@ class OrderedNode; #define OpcodeArgs [[maybe_unused]] FEXCore::X86Tables::DecodedOp Op -//Functions in X87.cpp (no change required) -//GetX87Top -//SetX87ValidTag -//GetX87ValidTag -//GetX87Tag (will need changing once special tag handling is implemented) -//SetX87FTW -//GetX87FTW (will need changing once special tag handling is implemented) -//SetX87Top -//X87ModifySTP -//EMMS -//FFREE -//FNSTENV -//FSTCW -//LDSW -//FNSTSW -//FXCH -//FCMOV -//FST(register to register) +// Functions in X87.cpp (no change required) +// GetX87Top +// SetX87ValidTag +// GetX87ValidTag +// GetX87Tag (will need changing once special tag handling is implemented) +// SetX87FTW +// GetX87FTW (will need changing once special tag handling is implemented) +// SetX87Top +// X87ModifySTP +// EMMS +// FFREE +// FNSTENV +// FSTCW +// LDSW +// FNSTSW +// FXCH +// FCMOV +// FST(register to register) // State loading duplicated from X87.cpp, setting host rounding mode // See issue @@ -65,32 +65,32 @@ void OpDispatchBuilder::FNINITF64(OpcodeArgs) { void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) { const auto Size = GetSrcSize(Op); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Src[0]); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Src[0]); auto NewFCW = _LoadMem(GPRClass, 2, Mem, 2); - //ignore the rounding precision, we're always 64-bit in F64. - //extract rounding mode - OrderedNode *roundingMode = _Bfe(OpSize::i32Bit, 3, 10, NewFCW); + // ignore the rounding precision, we're always 64-bit in F64. + // extract rounding mode + OrderedNode* roundingMode = _Bfe(OpSize::i32Bit, 3, 10, NewFCW); _SetRoundingMode(roundingMode); _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); auto NewFSW = _LoadMem(GPRClass, Size, MemLocation, Size); ReconstructX87StateFromFSW(NewFSW); { // FTW - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } } void OpDispatchBuilder::X87FLDCWF64(OpcodeArgs) { - OrderedNode *NewFCW = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - //ignore the rounding precision, we're always 64-bit in F64. - //extract rounding mode - OrderedNode *roundingMode = _Bfe(OpSize::i32Bit, 3, 10, NewFCW); + OrderedNode* NewFCW = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); + // ignore the rounding precision, we're always 64-bit in F64. + // extract rounding mode + OrderedNode* roundingMode = _Bfe(OpSize::i32Bit, 3, 10, NewFCW); _SetRoundingMode(roundingMode); _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); } @@ -105,13 +105,13 @@ void OpDispatchBuilder::FLDF64(OpcodeArgs) { size_t read_width = (width == 80) ? 16 : width / 8; - OrderedNode *data{}; - OrderedNode *converted{}; + OrderedNode* data {}; + OrderedNode* converted {}; if (!Op->Src[0].IsNone()) { // Read from memory data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], read_width, Op->Flags); - // Convert to 64bit float + // Convert to 64bit float if constexpr (width == 32) { converted = _Float_FToF(8, 4, data); } else if constexpr (width == 80) { @@ -119,8 +119,7 @@ void OpDispatchBuilder::FLDF64(OpcodeArgs) { } else { converted = data; } - } - else { + } else { // Implicit arg (does this need to change with width?) auto offset = _Constant(Op->OP & 7); data = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, offset), mask); @@ -135,12 +134,9 @@ void OpDispatchBuilder::FLDF64(OpcodeArgs) { _StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FLDF64<32>(OpcodeArgs); -template -void OpDispatchBuilder::FLDF64<64>(OpcodeArgs); -template -void OpDispatchBuilder::FLDF64<80>(OpcodeArgs); +template void OpDispatchBuilder::FLDF64<32>(OpcodeArgs); +template void OpDispatchBuilder::FLDF64<64>(OpcodeArgs); +template void OpDispatchBuilder::FLDF64<80>(OpcodeArgs); void OpDispatchBuilder::FBLDF64(OpcodeArgs) { // Update TOP @@ -151,8 +147,8 @@ void OpDispatchBuilder::FBLDF64(OpcodeArgs) { SetX87Top(top); // Read from memory - OrderedNode *data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags); - OrderedNode *converted = _F80BCDLoad(data); + OrderedNode* data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags); + OrderedNode* converted = _F80BCDLoad(data); converted = _F80CVT(8, converted); _StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass); } @@ -161,7 +157,7 @@ void OpDispatchBuilder::FBSTPF64(OpcodeArgs) { auto orig_top = GetX87Top(); auto data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); - OrderedNode *converted = _F80CVTTo(data, 8); + OrderedNode* converted = _F80CVTTo(data, 8); converted = _F80BCDStore(converted); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, converted, 10, 1); @@ -184,20 +180,13 @@ void OpDispatchBuilder::FLDF64_Const(OpcodeArgs) { _StoreContextIndexed(data, top, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FLDF64_Const<0x3FF0000000000000>(OpcodeArgs); // 1.0 -template -void OpDispatchBuilder::FLDF64_Const<0x400A934F0979A372>(OpcodeArgs); // log2l(10) -template -void OpDispatchBuilder::FLDF64_Const<0x3FF71547652B82FE>(OpcodeArgs); // log2l(e) -template -void OpDispatchBuilder::FLDF64_Const<0x400921FB54442D18>(OpcodeArgs); // pi -template -void OpDispatchBuilder::FLDF64_Const<0x3FD34413509F79FF>(OpcodeArgs); // log10l(2) -template -void OpDispatchBuilder::FLDF64_Const<0x3FE62E42FEFA39EF>(OpcodeArgs); // log(2) -template -void OpDispatchBuilder::FLDF64_Const<0>(OpcodeArgs); // 0.0 +template void OpDispatchBuilder::FLDF64_Const<0x3FF0000000000000>(OpcodeArgs); // 1.0 +template void OpDispatchBuilder::FLDF64_Const<0x400A934F0979A372>(OpcodeArgs); // log2l(10) +template void OpDispatchBuilder::FLDF64_Const<0x3FF71547652B82FE>(OpcodeArgs); // log2l(e) +template void OpDispatchBuilder::FLDF64_Const<0x400921FB54442D18>(OpcodeArgs); // pi +template void OpDispatchBuilder::FLDF64_Const<0x3FD34413509F79FF>(OpcodeArgs); // log10l(2) +template void OpDispatchBuilder::FLDF64_Const<0x3FE62E42FEFA39EF>(OpcodeArgs); // log(2) +template void OpDispatchBuilder::FLDF64_Const<0>(OpcodeArgs); // 0.0 void OpDispatchBuilder::FILDF64(OpcodeArgs) { // Update TOP @@ -209,7 +198,7 @@ void OpDispatchBuilder::FILDF64(OpcodeArgs) { size_t read_width = GetSrcSize(Op); // Read from memory auto data = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], read_width, Op->Flags); - if(read_width == 2) { + if (read_width == 2) { data = _Sbfe(OpSize::i64Bit, read_width * 8, 0, data); } auto converted = _Float_FromGPR_S(8, read_width == 4 ? 4 : 8, data); @@ -222,14 +211,14 @@ void OpDispatchBuilder::FSTF64(OpcodeArgs) { auto orig_top = GetX87Top(); auto data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); if constexpr (width == 64) { - //Store 64-bit float directly + // Store 64-bit float directly StoreResult_WithOpSize(FPRClass, Op, Op->Dest, data, 8, 1); } else if constexpr (width == 32) { - //Convert to 32-bit float and store + // Convert to 32-bit float and store auto result = _Float_FToF(4, 8, data); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, result, 4, 1); } else if constexpr (width == 80) { - //Convert to 80-bit float + // Convert to 80-bit float auto result = _F80CVTTo(data, 8); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, result, 10, 1); } @@ -243,19 +232,16 @@ void OpDispatchBuilder::FSTF64(OpcodeArgs) { } } -template -void OpDispatchBuilder::FSTF64<32>(OpcodeArgs); -template -void OpDispatchBuilder::FSTF64<64>(OpcodeArgs); -template -void OpDispatchBuilder::FSTF64<80>(OpcodeArgs); +template void OpDispatchBuilder::FSTF64<32>(OpcodeArgs); +template void OpDispatchBuilder::FSTF64<64>(OpcodeArgs); +template void OpDispatchBuilder::FSTF64<80>(OpcodeArgs); template void OpDispatchBuilder::FISTF64(OpcodeArgs) { auto Size = GetSrcSize(Op); auto orig_top = GetX87Top(); - OrderedNode *data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + OrderedNode* data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); if constexpr (Truncate) { data = _Float_ToGPR_ZS(Size == 4 ? 4 : 8, 8, data); } else { @@ -272,18 +258,16 @@ void OpDispatchBuilder::FISTF64(OpcodeArgs) { } } -template -void OpDispatchBuilder::FISTF64(OpcodeArgs); -template -void OpDispatchBuilder::FISTF64(OpcodeArgs); +template void OpDispatchBuilder::FISTF64(OpcodeArgs); +template void OpDispatchBuilder::FISTF64(OpcodeArgs); -template +template void OpDispatchBuilder::FADDF64(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; + OrderedNode* StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); @@ -291,7 +275,7 @@ void OpDispatchBuilder::FADDF64(OpcodeArgs) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - if(width == 16) { + if (width == 16) { arg = _Sbfe(OpSize::i64Bit, 16, 0, arg); } b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg); @@ -325,26 +309,20 @@ void OpDispatchBuilder::FADDF64(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FADDF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADDF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FADDF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADDF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FADDF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FADDF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADDF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FADDF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); template void OpDispatchBuilder::FMULF64(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* StackLocation = top; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); @@ -352,7 +330,7 @@ void OpDispatchBuilder::FMULF64(OpcodeArgs) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - if(width == 16) { + if (width == 16) { arg = _Sbfe(OpSize::i64Bit, 16, 0, arg); } b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg); @@ -389,34 +367,28 @@ void OpDispatchBuilder::FMULF64(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FMULF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMULF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FMULF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMULF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FMULF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FMULF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMULF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FMULF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); template void OpDispatchBuilder::FDIVF64(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* StackLocation = top; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); - if (!Op->Src[0].IsNone()) { + if (!Op->Src[0].IsNone()) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - if(width == 16) { + if (width == 16) { arg = _Sbfe(OpSize::i64Bit, 16, 0, arg); } b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg); @@ -439,11 +411,10 @@ void OpDispatchBuilder::FDIVF64(OpcodeArgs) { auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - OrderedNode *result{}; + OrderedNode* result {}; if constexpr (reverse) { result = _VFDiv(8, 8, b, a); - } - else { + } else { result = _VFDiv(8, 8, a, b); } @@ -459,50 +430,38 @@ void OpDispatchBuilder::FDIVF64(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FDIVF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FDIVF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FDIVF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); template void OpDispatchBuilder::FSUBF64(OpcodeArgs) { auto top = GetX87Top(); - OrderedNode *StackLocation = top; - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* StackLocation = top; + OrderedNode* arg {}; + OrderedNode* b {}; auto mask = _Constant(7); - if (!Op->Src[0].IsNone()) { + if (!Op->Src[0].IsNone()) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - if(width == 16) { + if (width == 16) { arg = _Sbfe(OpSize::i64Bit, 16, 0, arg); } b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg); @@ -525,11 +484,10 @@ void OpDispatchBuilder::FSUBF64(OpcodeArgs) { auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - OrderedNode *result{}; + OrderedNode* result {}; if constexpr (reverse) { result = _VFSub(8, 8, b, a); - } - else { + } else { result = _VFSub(8, 8, a, b); } @@ -546,35 +504,23 @@ void OpDispatchBuilder::FSUBF64(OpcodeArgs) { _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::FSUBF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); -template -void OpDispatchBuilder::FSUBF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template void OpDispatchBuilder::FSUBF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); void OpDispatchBuilder::FCHSF64(OpcodeArgs) { auto top = GetX87Top(); @@ -597,7 +543,7 @@ void OpDispatchBuilder::FTSTF64(OpcodeArgs) { auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); auto low = _Constant(0); - OrderedNode *data = _VCastFromGPR(8, 8, low); + OrderedNode* data = _VCastFromGPR(8, 8, low); // We are going to clobber NZCV, make sure it's in a GPR first. GetNZCV(); @@ -608,7 +554,7 @@ void OpDispatchBuilder::FTSTF64(OpcodeArgs) { ConvertNZCVToX87(); } -//TODO: This should obey rounding mode +// TODO: This should obey rounding mode void OpDispatchBuilder::FRNDINTF64(OpcodeArgs) { auto top = GetX87Top(); auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); @@ -645,14 +591,14 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { auto top = GetX87Top(); auto mask = _Constant(7); - OrderedNode *arg{}; - OrderedNode *b{}; + OrderedNode* arg {}; + OrderedNode* b {}; if (!Op->Src[0].IsNone()) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); - if(width == 16) { + if (width == 16) { arg = _Sbfe(OpSize::i64Bit, 16, 0, arg); } b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg); @@ -678,8 +624,7 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { _FCmp(8, a, b); PossiblySetNZCVBits = ~0; ConvertNZCVToX87(); - } - else { + } else { // Invalidate deferred flags early // OF, SF, AF, PF all undefined InvalidateDeferredFlags(); @@ -697,8 +642,7 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { // Set the new top now top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask); SetX87Top(top); - } - else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + } else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { // if we are popping then we must first mark this location as empty SetX87ValidTag(top, false); // Set the new top now @@ -707,24 +651,17 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { } } -template -void OpDispatchBuilder::FCOMIF64<32, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMIF64<32, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMIF64<64, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMIF64<64, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>(OpcodeArgs); +template void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMIF64<16, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMIF64<16, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); -template -void OpDispatchBuilder::FCOMIF64<32, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template void OpDispatchBuilder::FCOMIF64<32, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); void OpDispatchBuilder::FSQRTF64(OpcodeArgs) { @@ -745,8 +682,7 @@ void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs) { DeriveOp(result, IROp, _F64SIN(a)); - if constexpr (IROp == IR::OP_F64SIN || - IROp == IR::OP_F64COS) { + if constexpr (IROp == IR::OP_F64SIN || IROp == IR::OP_F64COS) { // TODO: ACCURACY: should check source is in range –2^63 to +2^63 SetRFLAG(_Constant(0)); } @@ -755,12 +691,9 @@ void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs) { _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); -template -void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); -template -void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); +template void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); +template void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); +template void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); template @@ -768,16 +701,15 @@ void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs) { auto top = GetX87Top(); auto mask = _Constant(7); - OrderedNode *st1 = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask); + OrderedNode* st1 = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask); auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); st1 = _LoadContextIndexed(st1, 8, MMBaseOffset(), 16, FPRClass); DeriveOp(result, IROp, _F64ATAN(a, st1)); - if constexpr (IROp == IR::OP_F64FPREM || - IROp == IR::OP_F64FPREM1) { - //TODO: Set C0 to Q2, C3 to Q1, C1 to Q0 + if constexpr (IROp == IR::OP_F64FPREM || IROp == IR::OP_F64FPREM1) { + // TODO: Set C0 to Q2, C3 to Q1, C1 to Q0 SetRFLAG(_Constant(0)); } @@ -785,12 +717,9 @@ void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs) { _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); } -template -void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); -template -void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); -template -void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); +template void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); +template void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); +template void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); void OpDispatchBuilder::X87SinCosF64(OpcodeArgs) { auto orig_top = GetX87Top(); @@ -820,8 +749,8 @@ void OpDispatchBuilder::X87FYL2XF64(OpcodeArgs) { auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); - OrderedNode *st0 = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); - OrderedNode *st1 = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + OrderedNode* st0 = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + OrderedNode* st1 = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); if (Plus1) { auto one = _VCastFromGPR(8, 8, _Constant(0x3FF0000000000000)); @@ -862,7 +791,7 @@ void OpDispatchBuilder::X87ATANF64(OpcodeArgs) { SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); - OrderedNode *st1 = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + OrderedNode* st1 = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); auto result = _F64ATAN(st1, a); @@ -870,7 +799,7 @@ void OpDispatchBuilder::X87ATANF64(OpcodeArgs) { _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); } -//This function converts to F80 on save for compatibility +// This function converts to F80 on save for compatibility void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) { // 14 bytes for 16bit @@ -893,15 +822,15 @@ void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) { // 4 bytes : data pointer selector const auto Size = GetDstSize(Op); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Dest); - OrderedNode *Top = GetX87Top(); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Dest); + OrderedNode* Top = GetX87Top(); { auto FCW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FCW)); _StoreMem(GPRClass, Size, Mem, FCW, Size); } { - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); _StoreMem(GPRClass, Size, MemLocation, ReconstructFSW(), Size); } @@ -909,35 +838,35 @@ void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) { { // FTW - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); _StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size); } { // Instruction Offset - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 3)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 3)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Instruction CS selector (+ Opcode) - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 4)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 4)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Data pointer offset - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 5)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 5)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } { // Data pointer selector - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 6)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 6)); _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); } - OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); + OrderedNode* ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); auto OneConst = _Constant(1); auto SevenConst = _Constant(7); @@ -965,16 +894,16 @@ void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) { FNINIT(Op); } -//This function converts from F80 on load for compatibility +// This function converts from F80 on load for compatibility void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) { const auto Size = GetSrcSize(Op); - OrderedNode *Mem = MakeSegmentAddress(Op, Op->Src[0]); + OrderedNode* Mem = MakeSegmentAddress(Op, Op->Src[0]); auto NewFCW = _LoadMem(GPRClass, 2, Mem, 2); - //ignore the rounding precision, we're always 64-bit in F64. - //extract rounding mode - OrderedNode *roundingMode = NewFCW; + // ignore the rounding precision, we're always 64-bit in F64. + // extract rounding mode + OrderedNode* roundingMode = NewFCW; auto roundShift = _Constant(10); auto roundMask = _Constant(3); roundingMode = _Lshr(OpSize::i32Bit, roundingMode, roundShift); @@ -983,17 +912,17 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) { _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 1)); auto NewFSW = _LoadMem(GPRClass, Size, MemLocation, Size); auto Top = ReconstructX87StateFromFSW(NewFSW); { // FTW - OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); + OrderedNode* MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } - OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); + OrderedNode* ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); auto OneConst = _Constant(1); auto SevenConst = _Constant(7); @@ -1001,14 +930,14 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) { auto low = _Constant(~0ULL); auto high = _Constant(0xFFFF); - OrderedNode *Mask = _VCastFromGPR(16, 8, low); + OrderedNode* Mask = _VCastFromGPR(16, 8, low); Mask = _VInsGPR(16, 8, 1, Mask, high); for (int i = 0; i < 7; ++i) { - OrderedNode *Reg = _LoadMem(FPRClass, 16, ST0Location, 1); + OrderedNode* Reg = _LoadMem(FPRClass, 16, ST0Location, 1); // Mask off the top bits Reg = _VAnd(16, 16, Reg, Mask); - //Convert to double precision + // Convert to double precision Reg = _F80CVT(8, Reg); _StoreContextIndexed(Reg, Top, 8, MMBaseOffset(), 16, FPRClass); @@ -1021,20 +950,20 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) { // Lower 64bits [63:0] // upper 16 bits [79:64] - OrderedNode *Reg = _LoadMem(FPRClass, 8, ST0Location, 1); + OrderedNode* Reg = _LoadMem(FPRClass, 8, ST0Location, 1); ST0Location = _Add(OpSize::i64Bit, ST0Location, _Constant(8)); - OrderedNode *RegHigh = _LoadMem(FPRClass, 2, ST0Location, 1); + OrderedNode* RegHigh = _LoadMem(FPRClass, 2, ST0Location, 1); Reg = _VInsElement(16, 2, 4, 0, Reg, RegHigh); - Reg = _F80CVT(8, Reg); //Convert to double precision + Reg = _F80CVT(8, Reg); // Convert to double precision _StoreContextIndexed(Reg, Top, 8, MMBaseOffset(), 16, FPRClass); } -//FXAM needs change +// FXAM needs change void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) { auto top = GetX87Top(); auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - OrderedNode *Result = _VExtractToGPR(8, 8, a, 0); + OrderedNode* Result = _VExtractToGPR(8, 8, a, 0); // Extract the sign bit Result = _Bfe(OpSize::i64Bit, 1, 63, Result); @@ -1047,9 +976,7 @@ void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) { auto OneConst = _Constant(1); // In the case of top being invalid then C3:C2:C0 is 0b101 - auto C3 = _Select(FEXCore::IR::COND_EQ, - TopValid, OneConst, - ZeroConst, OneConst); + auto C3 = _Select(FEXCore::IR::COND_EQ, TopValid, OneConst, ZeroConst, OneConst); auto C2 = TopValid; auto C0 = C3; // Mirror C3 until something other than zero is supported @@ -1059,4 +986,4 @@ void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) { } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/Core/X86HelperGen.cpp b/FEXCore/Source/Interface/Core/X86HelperGen.cpp index f59982e77..357835ef6 100644 --- a/FEXCore/Source/Interface/Core/X86HelperGen.cpp +++ b/FEXCore/Source/Interface/Core/X86HelperGen.cpp @@ -39,15 +39,15 @@ X86GeneratedCode::X86GeneratedCode() { // Falling back to this generated code segment still allows a backtrace to work, just might not show // the symbol as VDSO since there is no ELF to parse. constexpr std::array sigreturn_32_code = { - 0x58, // pop eax + 0x58, // pop eax 0xb8, 0x77, 0x00, 0x00, 0x00, // mov eax, 0x77 - 0xcd, 0x80, // int 0x80 - 0x90, // nop + 0xcd, 0x80, // int 0x80 + 0x90, // nop }; constexpr std::array rt_sigreturn_32_code = { 0xb8, 0xad, 0x00, 0x00, 0x00, // mov eax, 0xad - 0xcd, 0x80, // int 0x80 + 0xcd, 0x80, // int 0x80 }; CallbackReturn = reinterpret_cast(CodePtr); @@ -84,10 +84,9 @@ void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) { // We need to have the sigret handler in the lower 32bits of memory space // Scan top down and try to allocate a location for (size_t Location = 0xFFFF'E000; Location != 0x0; Location -= 0x1000) { - void *Ptr = ::mmap(reinterpret_cast(Location), Size, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + void* Ptr = ::mmap(reinterpret_cast(Location), Size, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (Ptr != MAP_FAILED && - reinterpret_cast(Ptr) >= LOCATION_MAX) { + if (Ptr != MAP_FAILED && reinterpret_cast(Ptr) >= LOCATION_MAX) { // Failed to map in the lower 32bits // Try again // Can happen in the case that host kernel ignores MAP_FIXED_NOREPLACE @@ -108,5 +107,4 @@ void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) { #endif } -} - +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/X86HelperGen.h b/FEXCore/Source/Interface/Core/X86HelperGen.h index 9871c5a91..4f7d8dadb 100644 --- a/FEXCore/Source/Interface/Core/X86HelperGen.h +++ b/FEXCore/Source/Interface/Core/X86HelperGen.h @@ -16,12 +16,12 @@ public: X86GeneratedCode(); ~X86GeneratedCode(); - uint64_t CallbackReturn{}; - uint64_t sigreturn_32{}; - uint64_t rt_sigreturn_32{}; + uint64_t CallbackReturn {}; + uint64_t sigreturn_32 {}; + uint64_t rt_sigreturn_32 {}; private: - void *CodePtr{}; + void* CodePtr {}; void* AllocateGuestCodeSpace(size_t Size); }; -} +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/Core/X86Tables.cpp b/FEXCore/Source/Interface/Core/X86Tables.cpp index 430de3473..be634acd9 100644 --- a/FEXCore/Source/Interface/Core/X86Tables.cpp +++ b/FEXCore/Source/Interface/Core/X86Tables.cpp @@ -24,4 +24,4 @@ void InitializeInfoTables(Context::OperatingMode Mode) { InitializeH0F3ATables(Mode); } -} +} // namespace FEXCore::X86Tables diff --git a/FEXCore/Source/Interface/GDBJIT/GDBJIT.cpp b/FEXCore/Source/Interface/GDBJIT/GDBJIT.cpp index 0488806a8..bc572b6a7 100644 --- a/FEXCore/Source/Interface/GDBJIT/GDBJIT.cpp +++ b/FEXCore/Source/Interface/GDBJIT/GDBJIT.cpp @@ -14,9 +14,9 @@ extern "C" { enum jit_actions_t { JIT_NOACTION = 0, JIT_REGISTER_FN, JIT_UNREGISTER_FN }; struct jit_code_entry { - jit_code_entry *next_entry; - jit_code_entry *prev_entry; - const char *symfile_addr; + jit_code_entry* next_entry; + jit_code_entry* prev_entry; + const char* symfile_addr; uint64_t symfile_size; }; @@ -25,8 +25,8 @@ struct jit_descriptor { /* This type should be jit_actions_t, but we use uint32_t to be explicit about the bitwidth. */ uint32_t action_flag; - jit_code_entry *relevant_entry; - jit_code_entry *first_entry; + jit_code_entry* relevant_entry; + jit_code_entry* first_entry; }; /* Make sure to specify the version statically, because the @@ -42,9 +42,8 @@ void __attribute__((noinline)) __jit_debug_register_code() { namespace FEXCore { -void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry *Entry, uintptr_t VAFileStart, - uint64_t GuestRIP, uintptr_t HostEntry, - FEXCore::Core::DebugData *DebugData) { +void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry* Entry, uintptr_t VAFileStart, uint64_t GuestRIP, uintptr_t HostEntry, + FEXCore::Core::DebugData* DebugData) { auto map = Entry->SourcecodeMap.get(); if (map) { @@ -52,32 +51,28 @@ void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry *Entry, uintptr_t VAFileStart, auto Sym = map->FindSymbolMapping(FileOffset); - auto SymName = HLE::SourcecodeSymbolMapping::SymName( - Sym, Entry->Filename, HostEntry, FileOffset); + auto SymName = HLE::SourcecodeSymbolMapping::SymName(Sym, Entry->Filename, HostEntry, FileOffset); fextl::vector Lines; - for (const auto &GuestOpcode : DebugData->GuestOpcodes) { - auto Line = map->FindLineMapping(GuestRIP + GuestOpcode.GuestEntryOffset - - VAFileStart); + for (const auto& GuestOpcode : DebugData->GuestOpcodes) { + auto Line = map->FindLineMapping(GuestRIP + GuestOpcode.GuestEntryOffset - VAFileStart); if (Line) { - Lines.push_back( - {Line->LineNumber, HostEntry + GuestOpcode.HostEntryOffset}); + Lines.push_back({Line->LineNumber, HostEntry + GuestOpcode.HostEntryOffset}); } } - size_t size = sizeof(info_t) + 1 * sizeof(blocks_t) + - Lines.size() * sizeof(gdb_line_mapping); + size_t size = sizeof(info_t) + 1 * sizeof(blocks_t) + Lines.size() * sizeof(gdb_line_mapping); - auto mem = (uint8_t *)malloc(size); + auto mem = (uint8_t*)malloc(size); auto base = mem; - info_t *info = (info_t *)mem; + info_t* info = (info_t*)mem; mem += sizeof(info_t); strncpy(info->filename, map->SourceFile.c_str(), 511); info->nblocks = 1; - auto blocks = (blocks_t *)mem; + auto blocks = (blocks_t*)mem; info->blocks_ofs = mem - base; mem += info->nblocks * sizeof(blocks_t); @@ -90,7 +85,7 @@ void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry *Entry, uintptr_t VAFileStart, info->nlines = Lines.size(); - auto lines = (gdb_line_mapping *)mem; + auto lines = (gdb_line_mapping*)mem; info->lines_ofs = mem - base; mem += info->nlines * sizeof(gdb_line_mapping); @@ -98,9 +93,9 @@ void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry *Entry, uintptr_t VAFileStart, memcpy(lines, &Lines.at(0), info->nlines * sizeof(gdb_line_mapping)); } - auto entry = new jit_code_entry{0, 0, 0, 0}; + auto entry = new jit_code_entry {0, 0, 0, 0}; - entry->symfile_addr = (const char *)info; + entry->symfile_addr = (const char*)info; entry->symfile_size = size; if (__jit_debug_descriptor.first_entry) { @@ -118,11 +113,8 @@ void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry *Entry, uintptr_t VAFileStart, } // namespace FEXCore #else namespace FEXCore { -void GDBJITRegister([[maybe_unused]] FEXCore::IR::AOTIRCacheEntry *Entry, - [[maybe_unused]] uintptr_t VAFileStart, - [[maybe_unused]] uint64_t GuestRIP, - [[maybe_unused]] uintptr_t HostEntry, - [[maybe_unused]] FEXCore::Core::DebugData *DebugData) { +void GDBJITRegister([[maybe_unused]] FEXCore::IR::AOTIRCacheEntry* Entry, [[maybe_unused]] uintptr_t VAFileStart, [[maybe_unused]] uint64_t GuestRIP, + [[maybe_unused]] uintptr_t HostEntry, [[maybe_unused]] FEXCore::Core::DebugData* DebugData) { ERROR_AND_DIE_FMT("GDBSymbols support not compiled in"); } } // namespace FEXCore diff --git a/FEXCore/Source/Interface/GDBJIT/GDBJIT.h b/FEXCore/Source/Interface/GDBJIT/GDBJIT.h index 64ae8fa53..101224577 100644 --- a/FEXCore/Source/Interface/GDBJIT/GDBJIT.h +++ b/FEXCore/Source/Interface/GDBJIT/GDBJIT.h @@ -4,5 +4,6 @@ #include namespace FEXCore { - void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry *Entry, uintptr_t VAFileStart, uint64_t GuestRIP, uintptr_t HostEntry, FEXCore::Core::DebugData *DebugData); +void GDBJITRegister(FEXCore::IR::AOTIRCacheEntry* Entry, uintptr_t VAFileStart, uint64_t GuestRIP, uintptr_t HostEntry, + FEXCore::Core::DebugData* DebugData); } \ No newline at end of file diff --git a/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp b/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp index 6842b0e71..cdb192f2d 100644 --- a/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp +++ b/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp @@ -39,19 +39,18 @@ extern "C" { #define JEMALLOC_NOTHROW __attribute__((nothrow)) // Forward declare jemalloc functions because we can't include the headers from the glibc jemalloc project. // This is because we can't simultaneously set up include paths for both of our internal jemalloc modules. -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern int glibc_je_is_known_allocation(void *ptr); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern int glibc_je_is_known_allocation(void* ptr); } #endif #ifndef _WIN32 static __attribute__((aligned(16), naked, section("HostToGuestTrampolineTemplate"))) void HostToGuestTrampolineTemplate() { #if defined(_M_X86_64) - asm( - "lea 0f(%rip), %r11 \n" - "jmpq *0f(%rip) \n" - ".align 8 \n" - "0: \n" - ".quad 0, 0, 0, 0 \n" // TrampolineInstanceInfo + asm("lea 0f(%rip), %r11 \n" + "jmpq *0f(%rip) \n" + ".align 8 \n" + "0: \n" + ".quad 0, 0, 0, 0 \n" // TrampolineInstanceInfo ); #elif defined(_M_ARM_64) asm( @@ -76,441 +75,431 @@ extern char __stop_HostToGuestTrampolineTemplate[]; namespace FEXCore { #ifndef _WIN32 - struct LoadlibArgs { - const char *Name; +struct LoadlibArgs { + const char* Name; +}; + +static thread_local FEXCore::Core::InternalThreadState* Thread = nullptr; + + +struct ExportEntry { + uint8_t* sha256; + ThunkedFunction* Fn; +}; + +struct TrampolineInstanceInfo { + void* HostPacker; + uintptr_t CallCallback; + uintptr_t GuestUnpacker; + uintptr_t GuestTarget; +}; + +// Opaque type pointing to an instance of HostToGuestTrampolineTemplate and its +// embedded TrampolineInstanceInfo +struct HostToGuestTrampolinePtr; +const auto HostToGuestTrampolineSize = __stop_HostToGuestTrampolineTemplate - __start_HostToGuestTrampolineTemplate; + +static TrampolineInstanceInfo& GetInstanceInfo(HostToGuestTrampolinePtr* Trampoline) { + const auto Length = __stop_HostToGuestTrampolineTemplate - __start_HostToGuestTrampolineTemplate; + const auto InstanceInfoOffset = Length - sizeof(TrampolineInstanceInfo); + return *reinterpret_cast(reinterpret_cast(Trampoline) + InstanceInfoOffset); +} + +struct GuestcallInfo { + uintptr_t GuestUnpacker; + uintptr_t GuestTarget; + + bool operator==(const GuestcallInfo&) const noexcept = default; +}; + +struct GuestcallInfoHash { + size_t operator()(const GuestcallInfo& x) const noexcept { + // Hash only the target address, which is generally unique. + // For the unlikely case of a hash collision, fextl::unordered_map still picks the correct bucket entry. + return std::hash {}(x.GuestTarget); + } +}; + +// Bits in a SHA256 sum are already randomly distributed, so truncation yields a suitable hash function +struct TruncatingSHA256Hash { + size_t operator()(const FEXCore::IR::SHA256Sum& SHA256Sum) const noexcept { + return (const size_t&)SHA256Sum; + } +}; + +HostToGuestTrampolinePtr* MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker); + +struct ThunkHandler_impl final : public ThunkHandler { + std::shared_mutex ThunksMutex; + + fextl::unordered_map Thunks = { + {// sha256(fex:loadlib) + {0x27, 0x7e, 0xb7, 0x69, 0x5b, 0xe9, 0xab, 0x12, 0x6e, 0xf7, 0x85, 0x9d, 0x4b, 0xc9, 0xa2, 0x44, + 0x46, 0xcf, 0xbd, 0xb5, 0x87, 0x43, 0xef, 0x28, 0xa2, 0x65, 0xba, 0xfc, 0x89, 0x0f, 0x77, 0x80}, + &LoadLib}, + {// sha256(fex:is_lib_loaded) + {0xee, 0x57, 0xba, 0x0c, 0x5f, 0x6e, 0xef, 0x2a, 0x8c, 0xb5, 0x19, 0x81, 0xc9, 0x23, 0xe6, 0x51, + 0xae, 0x65, 0x02, 0x8f, 0x2b, 0x5d, 0x59, 0x90, 0x6a, 0x7e, 0xe2, 0xe7, 0x1c, 0x33, 0x8a, 0xff}, + &IsLibLoaded}, + {// sha256(fex:is_host_heap_allocation) + {0xf5, 0x77, 0x68, 0x43, 0xbb, 0x6b, 0x28, 0x18, 0x40, 0xb0, 0xdb, 0x8a, 0x66, 0xfb, 0x0e, 0x2d, + 0x98, 0xc2, 0xad, 0xe2, 0x5a, 0x18, 0x5a, 0x37, 0x2e, 0x13, 0xc9, 0xe7, 0xb9, 0x8c, 0xa9, 0x3e}, + &IsHostHeapAllocation}, + {// sha256(fex:link_address_to_function) + {0xe6, 0xa8, 0xec, 0x1c, 0x7b, 0x74, 0x35, 0x27, 0xe9, 0x4f, 0x5b, 0x6e, 0x2d, 0xc9, 0xa0, 0x27, + 0xd6, 0x1f, 0x2b, 0x87, 0x8f, 0x2d, 0x35, 0x50, 0xea, 0x16, 0xb8, 0xc4, 0x5e, 0x42, 0xfd, 0x77}, + &LinkAddressToGuestFunction}, + {// sha256(fex:allocate_host_trampoline_for_guest_function) + {0x9b, 0xb2, 0xf4, 0xb4, 0x83, 0x7d, 0x28, 0x93, 0x40, 0xcb, 0xf4, 0x7a, 0x0b, 0x47, 0x85, 0x87, + 0xf9, 0xbc, 0xb5, 0x27, 0xca, 0xa6, 0x93, 0xa5, 0xc0, 0x73, 0x27, 0x24, 0xae, 0xc8, 0xb8, 0x5a}, + &AllocateHostTrampolineForGuestFunction}, }; - static thread_local FEXCore::Core::InternalThreadState *Thread = nullptr; + // Can't be a string_view. We need to keep a copy of the library name in-case string_view pointer goes away. + // Ideally we track when a library has been unloaded and remove it from this set before the memory backing goes away. + fextl::set Libs; + + fextl::unordered_map GuestcallToHostTrampoline; + + uint8_t* HostTrampolineInstanceDataPtr; + size_t HostTrampolineInstanceDataAvailable = 0; - struct ExportEntry { uint8_t *sha256; ThunkedFunction* Fn; }; - - struct TrampolineInstanceInfo { - void* HostPacker; - uintptr_t CallCallback; - uintptr_t GuestUnpacker; - uintptr_t GuestTarget; - }; - - // Opaque type pointing to an instance of HostToGuestTrampolineTemplate and its - // embedded TrampolineInstanceInfo - struct HostToGuestTrampolinePtr; - const auto HostToGuestTrampolineSize = __stop_HostToGuestTrampolineTemplate - __start_HostToGuestTrampolineTemplate; - - static TrampolineInstanceInfo& GetInstanceInfo(HostToGuestTrampolinePtr* Trampoline) { - const auto Length = __stop_HostToGuestTrampolineTemplate - __start_HostToGuestTrampolineTemplate; - const auto InstanceInfoOffset = Length - sizeof(TrampolineInstanceInfo); - return *reinterpret_cast(reinterpret_cast(Trampoline) + InstanceInfoOffset); + /* + Set arg0/1 to arg regs, use CTX::HandleCallback to handle the callback + */ + static void CallCallback(void* callback, void* arg0, void* arg1) { + if (!Thread) { + ERROR_AND_DIE_FMT("Thunked library attempted to invoke guest callback asynchronously"); } - struct GuestcallInfo { + auto CTX = static_cast(Thread->CTX); + if (CTX->Config.Is64BitMode) { + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDI] = (uintptr_t)arg0; + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSI] = (uintptr_t)arg1; + } else { + if ((reinterpret_cast(arg1) >> 32) != 0) { + ERROR_AND_DIE_FMT("Tried to call guest function with arguments packed to a 64-bit address"); + } + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RCX] = (uintptr_t)arg0; + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDX] = (uintptr_t)arg1; + } + + Thread->CTX->HandleCallback(Thread, (uintptr_t)callback); + } + + /** + * Instructs the Core to redirect calls to functions at the given + * address to another function. The original callee address is passed + * to the target function through an implicit argument stored in r11. + * + * For 32-bit the implicit argument is stored in the lower 32-bits of mm0. + * + * The primary use case of this is ensuring that host function pointers + * returned from thunked APIs can safely be called by the guest. + */ + static void LinkAddressToGuestFunction(void* argsv) { + struct args_t { + uintptr_t original_callee; + uintptr_t target_addr; // Guest function to call when branching to original_callee + }; + + auto args = reinterpret_cast(argsv); + auto CTX = static_cast(Thread->CTX); + + LOGMAN_THROW_AA_FMT(args->original_callee, "Tried to link null pointer address to guest function"); + LOGMAN_THROW_AA_FMT(args->target_addr, "Tried to link address to null pointer guest function"); + if (!CTX->Config.Is64BitMode) { + LOGMAN_THROW_AA_FMT((args->original_callee >> 32) == 0, "Tried to link 64-bit address in 32-bit mode"); + LOGMAN_THROW_AA_FMT((args->target_addr >> 32) == 0, "Tried to link 64-bit address in 32-bit mode"); + } + + LogMan::Msg::DFmt("Thunks: Adding guest trampoline from address {:#x} to guest function {:#x}", args->original_callee, args->target_addr); + + auto Result = CTX->AddCustomIREntrypoint( + args->original_callee, + [CTX, GuestThunkEntrypoint = args->target_addr](uintptr_t Entrypoint, FEXCore::IR::IREmitter* emit) { + auto IRHeader = emit->_IRHeader(emit->Invalid(), Entrypoint, 0, 0); + auto Block = emit->CreateCodeNode(); + IRHeader.first->Blocks = emit->WrapNode(Block); + emit->SetCurrentCodeBlock(Block); + + const uint8_t GPRSize = CTX->GetGPRSize(); + + if (GPRSize == 8) { + emit->_StoreRegister(emit->_Constant(Entrypoint), false, offsetof(Core::CPUState, gregs[X86State::REG_R11]), IR::GPRClass, + IR::GPRFixedClass, GPRSize); + } else { + emit->_StoreContext(GPRSize, IR::FPRClass, emit->_VCastFromGPR(8, 8, emit->_Constant(Entrypoint)), offsetof(Core::CPUState, mm[0][0])); + } + emit->_ExitFunction(emit->_Constant(GuestThunkEntrypoint)); + }, + CTX->ThunkHandler.get(), (void*)args->target_addr); + + if (!Result) { + if (Result.Creator != CTX->ThunkHandler.get()) { + ERROR_AND_DIE_FMT("Input address for LinkAddressToGuestFunction is already linked by another module"); + } + if (Result.Data != (void*)args->target_addr) { + // NOTE: This may happen in Vulkan thunks if the Vulkan driver resolves two different symbols + // to the same function (e.g. vkGetPhysicalDeviceFeatures2/vkGetPhysicalDeviceFeatures2KHR) + LogMan::Msg::EFmt("Input address for LinkAddressToGuestFunction is already linked elsewhere"); + } + } + } + + /** + * Guest-side helper to initiate creation of a host trampoline for + * calling guest functions. This must be followed by a host-side call + * to FinalizeHostTrampolineForGuestFunction to make the trampoline + * usable. + * + * This two-step initialization is equivalent to a host-side call to + * MakeHostTrampolineForGuestFunction. The split is needed if the + * host doesn't have all information needed to create the trampoline + * on its own. + */ + static void AllocateHostTrampolineForGuestFunction(void* ArgsRV) { + struct ArgsRV_t { uintptr_t GuestUnpacker; uintptr_t GuestTarget; + uintptr_t rv; // Pointer to host trampoline + TrampolineInstanceInfo + }* args = reinterpret_cast(ArgsRV); - bool operator==(const GuestcallInfo&) const noexcept = default; - }; + args->rv = (uintptr_t)MakeHostTrampolineForGuestFunction(nullptr, args->GuestTarget, args->GuestUnpacker); + } - struct GuestcallInfoHash { - size_t operator()(const GuestcallInfo& x) const noexcept { - // Hash only the target address, which is generally unique. - // For the unlikely case of a hash collision, fextl::unordered_map still picks the correct bucket entry. - return std::hash{}(x.GuestTarget); - } - }; - - // Bits in a SHA256 sum are already randomly distributed, so truncation yields a suitable hash function - struct TruncatingSHA256Hash { - size_t operator()(const FEXCore::IR::SHA256Sum& SHA256Sum) const noexcept { - return (const size_t&)SHA256Sum; - } - }; - - HostToGuestTrampolinePtr* MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker); - - struct ThunkHandler_impl final: public ThunkHandler { - std::shared_mutex ThunksMutex; - - fextl::unordered_map Thunks = { - { - // sha256(fex:loadlib) - { 0x27, 0x7e, 0xb7, 0x69, 0x5b, 0xe9, 0xab, 0x12, 0x6e, 0xf7, 0x85, 0x9d, 0x4b, 0xc9, 0xa2, 0x44, 0x46, 0xcf, 0xbd, 0xb5, 0x87, 0x43, 0xef, 0x28, 0xa2, 0x65, 0xba, 0xfc, 0x89, 0x0f, 0x77, 0x80 }, - &LoadLib - }, - { - // sha256(fex:is_lib_loaded) - { 0xee, 0x57, 0xba, 0x0c, 0x5f, 0x6e, 0xef, 0x2a, 0x8c, 0xb5, 0x19, 0x81, 0xc9, 0x23, 0xe6, 0x51, 0xae, 0x65, 0x02, 0x8f, 0x2b, 0x5d, 0x59, 0x90, 0x6a, 0x7e, 0xe2, 0xe7, 0x1c, 0x33, 0x8a, 0xff }, - &IsLibLoaded - }, - { - // sha256(fex:is_host_heap_allocation) - { 0xf5, 0x77, 0x68, 0x43, 0xbb, 0x6b, 0x28, 0x18, 0x40, 0xb0, 0xdb, 0x8a, 0x66, 0xfb, 0x0e, 0x2d, 0x98, 0xc2, 0xad, 0xe2, 0x5a, 0x18, 0x5a, 0x37, 0x2e, 0x13, 0xc9, 0xe7, 0xb9, 0x8c, 0xa9, 0x3e }, - &IsHostHeapAllocation - }, - { - // sha256(fex:link_address_to_function) - { 0xe6, 0xa8, 0xec, 0x1c, 0x7b, 0x74, 0x35, 0x27, 0xe9, 0x4f, 0x5b, 0x6e, 0x2d, 0xc9, 0xa0, 0x27, 0xd6, 0x1f, 0x2b, 0x87, 0x8f, 0x2d, 0x35, 0x50, 0xea, 0x16, 0xb8, 0xc4, 0x5e, 0x42, 0xfd, 0x77 }, - &LinkAddressToGuestFunction - }, - { - // sha256(fex:allocate_host_trampoline_for_guest_function) - { 0x9b, 0xb2, 0xf4, 0xb4, 0x83, 0x7d, 0x28, 0x93, 0x40, 0xcb, 0xf4, 0x7a, 0x0b, 0x47, 0x85, 0x87, 0xf9, 0xbc, 0xb5, 0x27, 0xca, 0xa6, 0x93, 0xa5, 0xc0, 0x73, 0x27, 0x24, 0xae, 0xc8, 0xb8, 0x5a }, - &AllocateHostTrampolineForGuestFunction - }, - }; - - // Can't be a string_view. We need to keep a copy of the library name in-case string_view pointer goes away. - // Ideally we track when a library has been unloaded and remove it from this set before the memory backing goes away. - fextl::set Libs; - - fextl::unordered_map GuestcallToHostTrampoline; - - uint8_t *HostTrampolineInstanceDataPtr; - size_t HostTrampolineInstanceDataAvailable = 0; - - - /* - Set arg0/1 to arg regs, use CTX::HandleCallback to handle the callback - */ - static void CallCallback(void *callback, void *arg0, void* arg1) { - if (!Thread) { - ERROR_AND_DIE_FMT("Thunked library attempted to invoke guest callback asynchronously"); - } - - auto CTX = static_cast(Thread->CTX); - if (CTX->Config.Is64BitMode) { - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDI] = (uintptr_t)arg0; - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSI] = (uintptr_t)arg1; - } else { - if ((reinterpret_cast(arg1) >> 32) != 0) { - ERROR_AND_DIE_FMT("Tried to call guest function with arguments packed to a 64-bit address"); - } - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RCX] = (uintptr_t)arg0; - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDX] = (uintptr_t)arg1; - } - - Thread->CTX->HandleCallback(Thread, (uintptr_t)callback); - } - - /** - * Instructs the Core to redirect calls to functions at the given - * address to another function. The original callee address is passed - * to the target function through an implicit argument stored in r11. - * - * For 32-bit the implicit argument is stored in the lower 32-bits of mm0. - * - * The primary use case of this is ensuring that host function pointers - * returned from thunked APIs can safely be called by the guest. - */ - static void LinkAddressToGuestFunction(void* argsv) { - struct args_t { - uintptr_t original_callee; - uintptr_t target_addr; // Guest function to call when branching to original_callee - }; - - auto args = reinterpret_cast(argsv); - auto CTX = static_cast(Thread->CTX); - - LOGMAN_THROW_AA_FMT(args->original_callee, "Tried to link null pointer address to guest function"); - LOGMAN_THROW_AA_FMT(args->target_addr, "Tried to link address to null pointer guest function"); - if (!CTX->Config.Is64BitMode) { - LOGMAN_THROW_AA_FMT((args->original_callee >> 32) == 0, "Tried to link 64-bit address in 32-bit mode"); - LOGMAN_THROW_AA_FMT((args->target_addr >> 32) == 0, "Tried to link 64-bit address in 32-bit mode"); - } - - LogMan::Msg::DFmt("Thunks: Adding guest trampoline from address {:#x} to guest function {:#x}", - args->original_callee, args->target_addr); - - auto Result = CTX->AddCustomIREntrypoint( - args->original_callee, - [CTX, GuestThunkEntrypoint = args->target_addr](uintptr_t Entrypoint, FEXCore::IR::IREmitter *emit) { - auto IRHeader = emit->_IRHeader(emit->Invalid(), Entrypoint, 0, 0); - auto Block = emit->CreateCodeNode(); - IRHeader.first->Blocks = emit->WrapNode(Block); - emit->SetCurrentCodeBlock(Block); - - const uint8_t GPRSize = CTX->GetGPRSize(); - - if (GPRSize == 8) { - emit->_StoreRegister(emit->_Constant(Entrypoint), false, offsetof(Core::CPUState, gregs[X86State::REG_R11]), IR::GPRClass, IR::GPRFixedClass, GPRSize); - } - else { - emit->_StoreContext(GPRSize, IR::FPRClass, emit->_VCastFromGPR(8, 8, emit->_Constant(Entrypoint)), offsetof(Core::CPUState, mm[0][0])); - } - emit->_ExitFunction(emit->_Constant(GuestThunkEntrypoint)); - }, CTX->ThunkHandler.get(), (void*)args->target_addr); - - if (!Result) { - if (Result.Creator != CTX->ThunkHandler.get()) { - ERROR_AND_DIE_FMT("Input address for LinkAddressToGuestFunction is already linked by another module"); - } - if (Result.Data != (void*)args->target_addr) { - // NOTE: This may happen in Vulkan thunks if the Vulkan driver resolves two different symbols - // to the same function (e.g. vkGetPhysicalDeviceFeatures2/vkGetPhysicalDeviceFeatures2KHR) - LogMan::Msg::EFmt("Input address for LinkAddressToGuestFunction is already linked elsewhere"); - } - } - } - - /** - * Guest-side helper to initiate creation of a host trampoline for - * calling guest functions. This must be followed by a host-side call - * to FinalizeHostTrampolineForGuestFunction to make the trampoline - * usable. - * - * This two-step initialization is equivalent to a host-side call to - * MakeHostTrampolineForGuestFunction. The split is needed if the - * host doesn't have all information needed to create the trampoline - * on its own. - */ - static void AllocateHostTrampolineForGuestFunction(void* ArgsRV) { - struct ArgsRV_t { - uintptr_t GuestUnpacker; - uintptr_t GuestTarget; - uintptr_t rv; // Pointer to host trampoline + TrampolineInstanceInfo - } *args = reinterpret_cast(ArgsRV); - - args->rv = (uintptr_t)MakeHostTrampolineForGuestFunction(nullptr, args->GuestTarget, args->GuestUnpacker); - } - - /** - * Checks if the given pointer is allocated on the host heap. - * - * This is useful for thunking APIs that need to work with both guest - * and host heap pointers. - */ - static void IsHostHeapAllocation(void* ArgsRV) { + /** + * Checks if the given pointer is allocated on the host heap. + * + * This is useful for thunking APIs that need to work with both guest + * and host heap pointers. + */ + static void IsHostHeapAllocation(void* ArgsRV) { #ifdef ENABLE_JEMALLOC_GLIBC - struct ArgsRV_t { - void* ptr; - bool rv; - } *args = reinterpret_cast(ArgsRV); + struct ArgsRV_t { + void* ptr; + bool rv; + }* args = reinterpret_cast(ArgsRV); - args->rv = glibc_je_is_known_allocation(args->ptr); + args->rv = glibc_je_is_known_allocation(args->ptr); #else - // Thunks usage without jemalloc isn't supported - ERROR_AND_DIE_FMT("Unsupported: Thunks querying for host heap allocation information"); + // Thunks usage without jemalloc isn't supported + ERROR_AND_DIE_FMT("Unsupported: Thunks querying for host heap allocation information"); #endif - } + } - static void LoadLib(void *ArgsV) { - auto CTX = static_cast(Thread->CTX); + static void LoadLib(void* ArgsV) { + auto CTX = static_cast(Thread->CTX); - auto Args = reinterpret_cast(ArgsV); + auto Args = reinterpret_cast(ArgsV); - std::string_view Name = Args->Name; + std::string_view Name = Args->Name; - auto SOName = (CTX->Config.Is64BitMode() ? - CTX->Config.ThunkHostLibsPath() : - CTX->Config.ThunkHostLibsPath32()) - + "/" + Name.data() + "-host.so"; + auto SOName = (CTX->Config.Is64BitMode() ? CTX->Config.ThunkHostLibsPath() : CTX->Config.ThunkHostLibsPath32()) + "/" + Name.data() + "-host.so"; - LogMan::Msg::DFmt("LoadLib: {} -> {}", Name, SOName); + LogMan::Msg::DFmt("LoadLib: {} -> {}", Name, SOName); - auto Handle = dlopen(SOName.c_str(), RTLD_LOCAL | RTLD_NOW); - if (!Handle) { - ERROR_AND_DIE_FMT("LoadLib: Failed to dlopen thunk library {}: {}", SOName, dlerror()); - } + auto Handle = dlopen(SOName.c_str(), RTLD_LOCAL | RTLD_NOW); + if (!Handle) { + ERROR_AND_DIE_FMT("LoadLib: Failed to dlopen thunk library {}: {}", SOName, dlerror()); + } - // Library names often include dashes, which may not be used in C++ identifiers. - // They are replaced with underscores hence. - auto InitSym = "fexthunks_exports_" + fextl::string { Name }; - std::replace(InitSym.begin(), InitSym.end(), '-', '_'); + // Library names often include dashes, which may not be used in C++ identifiers. + // They are replaced with underscores hence. + auto InitSym = "fexthunks_exports_" + fextl::string {Name}; + std::replace(InitSym.begin(), InitSym.end(), '-', '_'); - ExportEntry* (*InitFN)(); - (void*&)InitFN = dlsym(Handle, InitSym.c_str()); - if (!InitFN) { - ERROR_AND_DIE_FMT("LoadLib: Failed to find export {}", InitSym); - } + ExportEntry* (*InitFN)(); + (void*&)InitFN = dlsym(Handle, InitSym.c_str()); + if (!InitFN) { + ERROR_AND_DIE_FMT("LoadLib: Failed to find export {}", InitSym); + } - auto Exports = InitFN(); - if (!Exports) { - ERROR_AND_DIE_FMT("LoadLib: Failed to initialize thunk library {}. " - "Check if the corresponding host library is installed " - "or disable thunking of this library.", Name); - } + auto Exports = InitFN(); + if (!Exports) { + ERROR_AND_DIE_FMT("LoadLib: Failed to initialize thunk library {}. " + "Check if the corresponding host library is installed " + "or disable thunking of this library.", + Name); + } - auto That = reinterpret_cast(CTX->ThunkHandler.get()); + auto That = reinterpret_cast(CTX->ThunkHandler.get()); - { - std::lock_guard lk(That->ThunksMutex); + { + std::lock_guard lk(That->ThunksMutex); - That->Libs.insert(fextl::string { Name }); + That->Libs.insert(fextl::string {Name}); - int i; - for (i = 0; Exports[i].sha256; i++) { - That->Thunks[*reinterpret_cast(Exports[i].sha256)] = Exports[i].Fn; - } + int i; + for (i = 0; Exports[i].sha256; i++) { + That->Thunks[*reinterpret_cast(Exports[i].sha256)] = Exports[i].Fn; + } - LogMan::Msg::DFmt("Loaded {} syms", i); - } - } + LogMan::Msg::DFmt("Loaded {} syms", i); + } + } - static void IsLibLoaded(void* ArgsRV) { - struct ArgsRV_t { - const char *Name; - bool rv; - }; - - auto &[Name, rv] = *reinterpret_cast(ArgsRV); - - auto CTX = static_cast(Thread->CTX); - auto That = reinterpret_cast(CTX->ThunkHandler.get()); - - { - std::shared_lock lk(That->ThunksMutex); - rv = That->Libs.contains(Name); - } - } - - ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) override { - - std::shared_lock lk(ThunksMutex); - - auto it = Thunks.find(sha256); - - if (it != Thunks.end()) { - return it->second; - } else { - return nullptr; - } - } - - void RegisterTLSState(FEXCore::Core::InternalThreadState *_Thread) override { - Thread = _Thread; - } - - void AppendThunkDefinitions(fextl::vector const& Definitions) override { - for (auto & Definition : Definitions) { - Thunks.emplace(Definition.Sum, Definition.ThunkFunction); - } - } + static void IsLibLoaded(void* ArgsRV) { + struct ArgsRV_t { + const char* Name; + bool rv; }; - fextl::unique_ptr ThunkHandler::Create() { - return fextl::make_unique(); + auto& [Name, rv] = *reinterpret_cast(ArgsRV); + + auto CTX = static_cast(Thread->CTX); + auto That = reinterpret_cast(CTX->ThunkHandler.get()); + + { + std::shared_lock lk(That->ThunksMutex); + rv = That->Libs.contains(Name); } + } - /** - * Generates a host-callable trampoline to call guest functions via the host ABI. - * - * This trampoline uses the same calling convention as the given HostPacker. Trampolines - * are cached, so it's safe to call this function repeatedly on the same arguments without - * leaking memory. - * - * Invoking the returned trampoline has the effect of: - * - packing the arguments (using the HostPacker identified by its SHA256) - * - performing a host->guest transition - * - unpacking the arguments via GuestUnpacker - * - calling the function at GuestTarget - * - * The primary use case of this is ensuring that guest function pointers ("callbacks") - * passed to thunked APIs can safely be called by the native host library. - * - * Returns a pointer to the generated host trampoline and its TrampolineInstanceInfo. - * - * If HostPacker is zero, the trampoline will be partially initialized and needs to be - * finalized with a call to FinalizeHostTrampolineForGuestFunction. A typical use case - * is to allocate the trampoline for a given GuestTarget/GuestUnpacker on the guest-side, - * and provide the HostPacker host-side. - */ - FEX_DEFAULT_VISIBILITY - HostToGuestTrampolinePtr* MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker) { - LOGMAN_THROW_AA_FMT(GuestTarget, "Tried to create host-trampoline to null pointer guest function"); + ThunkedFunction* LookupThunk(const IR::SHA256Sum& sha256) override { - const auto CTX = static_cast(Thread->CTX); - const auto ThunkHandler = reinterpret_cast(CTX->ThunkHandler.get()); + std::shared_lock lk(ThunksMutex); - const GuestcallInfo gci = { GuestUnpacker, GuestTarget }; + auto it = Thunks.find(sha256); - // Try first with shared_lock - { - std::shared_lock lk(ThunkHandler->ThunksMutex); - - auto found = ThunkHandler->GuestcallToHostTrampoline.find(gci); - if (found != ThunkHandler->GuestcallToHostTrampoline.end()) { - return found->second; - } - } - - std::lock_guard lk(ThunkHandler->ThunksMutex); - - // Retry lookup with full lock before making a new trampoline to avoid double trampolines - { - auto found = ThunkHandler->GuestcallToHostTrampoline.find(gci); - if (found != ThunkHandler->GuestcallToHostTrampoline.end()) { - return found->second; - } - } - - LogMan::Msg::DFmt("Thunks: Adding host trampoline for guest function {:#x} via unpacker {:#x}", - GuestTarget, GuestUnpacker); - - if (ThunkHandler->HostTrampolineInstanceDataAvailable < HostToGuestTrampolineSize) { - const auto allocation_step = 16 * 1024; - ThunkHandler->HostTrampolineInstanceDataAvailable = allocation_step; - ThunkHandler->HostTrampolineInstanceDataPtr = (uint8_t *)mmap( - 0, ThunkHandler->HostTrampolineInstanceDataAvailable, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - LOGMAN_THROW_AA_FMT(ThunkHandler->HostTrampolineInstanceDataPtr != MAP_FAILED, "Failed to mmap HostTrampolineInstanceDataPtr"); - } - - auto HostTrampoline = reinterpret_cast(ThunkHandler->HostTrampolineInstanceDataPtr); - ThunkHandler->HostTrampolineInstanceDataAvailable -= HostToGuestTrampolineSize; - ThunkHandler->HostTrampolineInstanceDataPtr += HostToGuestTrampolineSize; - memcpy(HostTrampoline, (void*)&HostToGuestTrampolineTemplate, HostToGuestTrampolineSize); - GetInstanceInfo(HostTrampoline) = TrampolineInstanceInfo { - .HostPacker = HostPacker, - .CallCallback = (uintptr_t)&ThunkHandler_impl::CallCallback, - .GuestUnpacker = GuestUnpacker, - .GuestTarget = GuestTarget - }; - - ThunkHandler->GuestcallToHostTrampoline[gci] = HostTrampoline; - return HostTrampoline; + if (it != Thunks.end()) { + return it->second; + } else { + return nullptr; } + } - FEX_DEFAULT_VISIBILITY - void FinalizeHostTrampolineForGuestFunction(HostToGuestTrampolinePtr* TrampolineAddress, void* HostPacker) { + void RegisterTLSState(FEXCore::Core::InternalThreadState* _Thread) override { + Thread = _Thread; + } - if (TrampolineAddress == nullptr) return; - - auto& Trampoline = GetInstanceInfo(TrampolineAddress); - - LOGMAN_THROW_A_FMT(Trampoline.CallCallback == (uintptr_t)&ThunkHandler_impl::CallCallback, - "Invalid trampoline at {} passed to {}", fmt::ptr(TrampolineAddress), __FUNCTION__); - - if (!Trampoline.HostPacker) { - LogMan::Msg::DFmt("Thunks: Finalizing trampoline at {} with host packer {}", fmt::ptr(TrampolineAddress), fmt::ptr(HostPacker)); - Trampoline.HostPacker = HostPacker; - } + void AppendThunkDefinitions(const fextl::vector& Definitions) override { + for (auto& Definition : Definitions) { + Thunks.emplace(Definition.Sum, Definition.ThunkFunction); } + } +}; - FEX_DEFAULT_VISIBILITY void* GetGuestStack() { - if (!Thread) { - ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously"); - } +fextl::unique_ptr ThunkHandler::Create() { + return fextl::make_unique(); +} - return (void*)(uintptr_t)((Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP])); +/** + * Generates a host-callable trampoline to call guest functions via the host ABI. + * + * This trampoline uses the same calling convention as the given HostPacker. Trampolines + * are cached, so it's safe to call this function repeatedly on the same arguments without + * leaking memory. + * + * Invoking the returned trampoline has the effect of: + * - packing the arguments (using the HostPacker identified by its SHA256) + * - performing a host->guest transition + * - unpacking the arguments via GuestUnpacker + * - calling the function at GuestTarget + * + * The primary use case of this is ensuring that guest function pointers ("callbacks") + * passed to thunked APIs can safely be called by the native host library. + * + * Returns a pointer to the generated host trampoline and its TrampolineInstanceInfo. + * + * If HostPacker is zero, the trampoline will be partially initialized and needs to be + * finalized with a call to FinalizeHostTrampolineForGuestFunction. A typical use case + * is to allocate the trampoline for a given GuestTarget/GuestUnpacker on the guest-side, + * and provide the HostPacker host-side. + */ +FEX_DEFAULT_VISIBILITY HostToGuestTrampolinePtr* +MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker) { + LOGMAN_THROW_AA_FMT(GuestTarget, "Tried to create host-trampoline to null pointer guest function"); + + const auto CTX = static_cast(Thread->CTX); + const auto ThunkHandler = reinterpret_cast(CTX->ThunkHandler.get()); + + const GuestcallInfo gci = {GuestUnpacker, GuestTarget}; + + // Try first with shared_lock + { + std::shared_lock lk(ThunkHandler->ThunksMutex); + + auto found = ThunkHandler->GuestcallToHostTrampoline.find(gci); + if (found != ThunkHandler->GuestcallToHostTrampoline.end()) { + return found->second; } + } - FEX_DEFAULT_VISIBILITY void MoveGuestStack(uintptr_t NewAddress) { - if (!Thread) { - ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously"); - } + std::lock_guard lk(ThunkHandler->ThunksMutex); - if (NewAddress >> 32) { - ERROR_AND_DIE_FMT("Tried to set stack pointer for 32-bit guest to a 64-bit address"); - } - - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = NewAddress; + // Retry lookup with full lock before making a new trampoline to avoid double trampolines + { + auto found = ThunkHandler->GuestcallToHostTrampoline.find(gci); + if (found != ThunkHandler->GuestcallToHostTrampoline.end()) { + return found->second; } + } + + LogMan::Msg::DFmt("Thunks: Adding host trampoline for guest function {:#x} via unpacker {:#x}", GuestTarget, GuestUnpacker); + + if (ThunkHandler->HostTrampolineInstanceDataAvailable < HostToGuestTrampolineSize) { + const auto allocation_step = 16 * 1024; + ThunkHandler->HostTrampolineInstanceDataAvailable = allocation_step; + ThunkHandler->HostTrampolineInstanceDataPtr = (uint8_t*)mmap(0, ThunkHandler->HostTrampolineInstanceDataAvailable, + PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + LOGMAN_THROW_AA_FMT(ThunkHandler->HostTrampolineInstanceDataPtr != MAP_FAILED, "Failed to mmap HostTrampolineInstanceDataPtr"); + } + + auto HostTrampoline = reinterpret_cast(ThunkHandler->HostTrampolineInstanceDataPtr); + ThunkHandler->HostTrampolineInstanceDataAvailable -= HostToGuestTrampolineSize; + ThunkHandler->HostTrampolineInstanceDataPtr += HostToGuestTrampolineSize; + memcpy(HostTrampoline, (void*)&HostToGuestTrampolineTemplate, HostToGuestTrampolineSize); + GetInstanceInfo(HostTrampoline) = TrampolineInstanceInfo { + .HostPacker = HostPacker, .CallCallback = (uintptr_t)&ThunkHandler_impl::CallCallback, .GuestUnpacker = GuestUnpacker, .GuestTarget = GuestTarget}; + + ThunkHandler->GuestcallToHostTrampoline[gci] = HostTrampoline; + return HostTrampoline; +} + +FEX_DEFAULT_VISIBILITY void FinalizeHostTrampolineForGuestFunction(HostToGuestTrampolinePtr* TrampolineAddress, void* HostPacker) { + + if (TrampolineAddress == nullptr) { + return; + } + + auto& Trampoline = GetInstanceInfo(TrampolineAddress); + + LOGMAN_THROW_A_FMT(Trampoline.CallCallback == (uintptr_t)&ThunkHandler_impl::CallCallback, "Invalid trampoline at {} passed to {}", + fmt::ptr(TrampolineAddress), __FUNCTION__); + + if (!Trampoline.HostPacker) { + LogMan::Msg::DFmt("Thunks: Finalizing trampoline at {} with host packer {}", fmt::ptr(TrampolineAddress), fmt::ptr(HostPacker)); + Trampoline.HostPacker = HostPacker; + } +} + +FEX_DEFAULT_VISIBILITY void* GetGuestStack() { + if (!Thread) { + ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously"); + } + + return (void*)(uintptr_t)((Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP])); +} + +FEX_DEFAULT_VISIBILITY void MoveGuestStack(uintptr_t NewAddress) { + if (!Thread) { + ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously"); + } + + if (NewAddress >> 32) { + ERROR_AND_DIE_FMT("Tried to set stack pointer for 32-bit guest to a 64-bit address"); + } + + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = NewAddress; +} #else - fextl::unique_ptr ThunkHandler::Create() { - ERROR_AND_DIE_FMT("Unsupported"); - } +fextl::unique_ptr ThunkHandler::Create() { + ERROR_AND_DIE_FMT("Unsupported"); +} #endif -} +} // namespace FEXCore diff --git a/FEXCore/Source/Interface/HLE/Thunks/Thunks.h b/FEXCore/Source/Interface/HLE/Thunks/Thunks.h index 6d6437f57..d4300a1b8 100644 --- a/FEXCore/Source/Interface/HLE/Thunks/Thunks.h +++ b/FEXCore/Source/Interface/HLE/Thunks/Thunks.h @@ -13,28 +13,28 @@ $end_info$ #include namespace FEXCore::Context { - class ContextImpl; +class ContextImpl; } namespace FEXCore::Core { - struct InternalThreadState; +struct InternalThreadState; } namespace FEXCore::IR { - struct SHA256Sum; +struct SHA256Sum; } namespace FEXCore { - typedef void ThunkedFunction(void* ArgsRv); +typedef void ThunkedFunction(void* ArgsRv); - class ThunkHandler { - public: - virtual ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) = 0; - virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0; - virtual ~ThunkHandler() { } +class ThunkHandler { +public: + virtual ThunkedFunction* LookupThunk(const IR::SHA256Sum& sha256) = 0; + virtual void RegisterTLSState(FEXCore::Core::InternalThreadState* Thread) = 0; + virtual ~ThunkHandler() {} - static fextl::unique_ptr Create(); + static fextl::unique_ptr Create(); - virtual void AppendThunkDefinitions(fextl::vector const& Definitions) = 0; - }; + virtual void AppendThunkDefinitions(const fextl::vector& Definitions) = 0; }; +}; // namespace FEXCore diff --git a/FEXCore/Source/Interface/IR/AOTIR.cpp b/FEXCore/Source/Interface/IR/AOTIR.cpp index a09bdfffe..961f75697 100644 --- a/FEXCore/Source/Interface/IR/AOTIR.cpp +++ b/FEXCore/Source/Interface/IR/AOTIR.cpp @@ -22,399 +22,399 @@ namespace FEXCore::IR { - AOTIRInlineEntry *AOTIRInlineIndex::GetInlineEntry(uint64_t DataOffset) { - uintptr_t This = (uintptr_t)this; +AOTIRInlineEntry* AOTIRInlineIndex::GetInlineEntry(uint64_t DataOffset) { + uintptr_t This = (uintptr_t)this; - return (AOTIRInlineEntry*)(This + DataBase + DataOffset); - } + return (AOTIRInlineEntry*)(This + DataBase + DataOffset); +} - AOTIRInlineEntry *AOTIRInlineIndex::Find(uint64_t GuestStart) { - ssize_t l = 0; - ssize_t r = Count - 1; +AOTIRInlineEntry* AOTIRInlineIndex::Find(uint64_t GuestStart) { + ssize_t l = 0; + ssize_t r = Count - 1; - while (l <= r) { - size_t m = l + (r - l) / 2; + while (l <= r) { + size_t m = l + (r - l) / 2; - if (Entries[m].GuestStart == GuestStart) - return GetInlineEntry(Entries[m].DataOffset); - else if (Entries[m].GuestStart < GuestStart) - l = m + 1; - else - r = m - 1; - } - - return nullptr; - } - - IR::RegisterAllocationData *AOTIRInlineEntry::GetRAData() { - return (IR::RegisterAllocationData *)InlineData; - } - - IR::IRListView *AOTIRInlineEntry::GetIRData() { - auto RAData = GetRAData(); - auto Offset = RAData->Size(RAData->MapCount); - - return (IR::IRListView *)&InlineData[Offset]; - } - - void AOTIRCaptureCacheEntry::AppendAOTIRCaptureCache(uint64_t GuestRIP, uint64_t Start, uint64_t Length, uint64_t Hash, FEXCore::IR::IRListView *IRList, FEXCore::IR::RegisterAllocationData *RAData) { - auto Inserted = Index.emplace(GuestRIP, Stream->Offset()); - - if (Inserted.second) { - //GuestHash - Stream->Write((const char*)&Hash, sizeof(Hash)); - - //GuestLength - Stream->Write((const char*)&Length, sizeof(Length)); - - RAData->Serialize(*Stream); - - // IRData (inline) - IRList->Serialize(*Stream); + if (Entries[m].GuestStart == GuestStart) { + return GetInlineEntry(Entries[m].DataOffset); + } else if (Entries[m].GuestStart < GuestStart) { + l = m + 1; + } else { + r = m - 1; } } - static bool readAll(int fd, void *data, size_t size) { - int rv = read(fd, data, size); + return nullptr; +} - if (rv != size) - return false; - else - return true; +IR::RegisterAllocationData* AOTIRInlineEntry::GetRAData() { + return (IR::RegisterAllocationData*)InlineData; +} + +IR::IRListView* AOTIRInlineEntry::GetIRData() { + auto RAData = GetRAData(); + auto Offset = RAData->Size(RAData->MapCount); + + return (IR::IRListView*)&InlineData[Offset]; +} + +void AOTIRCaptureCacheEntry::AppendAOTIRCaptureCache(uint64_t GuestRIP, uint64_t Start, uint64_t Length, uint64_t Hash, + FEXCore::IR::IRListView* IRList, FEXCore::IR::RegisterAllocationData* RAData) { + auto Inserted = Index.emplace(GuestRIP, Stream->Offset()); + + if (Inserted.second) { + // GuestHash + Stream->Write((const char*)&Hash, sizeof(Hash)); + + // GuestLength + Stream->Write((const char*)&Length, sizeof(Length)); + + RAData->Serialize(*Stream); + + // IRData (inline) + IRList->Serialize(*Stream); } +} - static bool LoadAOTIRCache(AOTIRCacheEntry *Entry, int streamfd) { -#ifndef _WIN32 - uint64_t tag; +static bool readAll(int fd, void* data, size_t size) { + int rv = read(fd, data, size); - if (!readAll(streamfd, (char*)&tag, sizeof(tag)) || tag != FEXCore::IR::AOTIR_COOKIE) - return false; - - fextl::string Module; - uint64_t ModSize; - uint64_t IndexSize; - - lseek(streamfd, -sizeof(ModSize), SEEK_END); - - if (!readAll(streamfd, (char*)&ModSize, sizeof(ModSize))) - return false; - - Module.resize(ModSize); - - lseek(streamfd, -sizeof(ModSize) - ModSize, SEEK_END); - - if (!readAll(streamfd, (char*)&Module[0], Module.size())) - return false; - - if (Entry->FileId != Module) { - return false; - } - - lseek(streamfd, -sizeof(ModSize) - ModSize - sizeof(IndexSize), SEEK_END); + if (rv != size) { + return false; + } else { + return true; + } +} - if (!readAll(streamfd, (char*)&IndexSize, sizeof(IndexSize))) - return false; +static bool LoadAOTIRCache(AOTIRCacheEntry* Entry, int streamfd) { +#ifndef _WIN32 + uint64_t tag; - struct stat fileinfo; - if (fstat(streamfd, &fileinfo) < 0) - return false; - size_t Size = (fileinfo.st_size + 4095) & ~4095; - - size_t IndexOffset = fileinfo.st_size - IndexSize -sizeof(ModSize) - ModSize - sizeof(IndexSize); - - void *FilePtr = FEXCore::Allocator::mmap(nullptr, Size, PROT_READ, MAP_SHARED, streamfd, 0); - - if (FilePtr == MAP_FAILED) { - return false; - } - - auto Array = (AOTIRInlineIndex *)((char*)FilePtr + IndexOffset); - - LOGMAN_THROW_AA_FMT(Entry->Array == nullptr && Entry->FilePtr == nullptr, "Entry must not be initialized here"); - Entry->Array = Array; - Entry->FilePtr = FilePtr; - Entry->Size = Size; - - LogMan::Msg::DFmt("AOTIR: Module {} has {} functions", Module, Array->Count); - - return true; -#else + if (!readAll(streamfd, (char*)&tag, sizeof(tag)) || tag != FEXCore::IR::AOTIR_COOKIE) { return false; -#endif } - void AOTIRCaptureCache::FinalizeAOTIRCache() { - AOTIRCaptureCacheWriteoutQueue_Flush(); + fextl::string Module; + uint64_t ModSize; + uint64_t IndexSize; - std::unique_lock lk(AOTIRCacheLock); + lseek(streamfd, -sizeof(ModSize), SEEK_END); - for (auto& [String, Entry] : AOTIRCaptureCacheMap) { - if (!Entry.Stream) { - continue; - } + if (!readAll(streamfd, (char*)&ModSize, sizeof(ModSize))) { + return false; + } - const auto ModSize = String.size(); - auto &stream = Entry.Stream; + Module.resize(ModSize); - // pad to 32 bytes - constexpr char Zero = 0; - while(stream->Offset() & 31) - stream->Write(&Zero, 1); + lseek(streamfd, -sizeof(ModSize) - ModSize, SEEK_END); - // AOTIRInlineIndex - const auto FnCount = Entry.Index.size(); - const size_t DataBase = -stream->Offset(); + if (!readAll(streamfd, (char*)&Module[0], Module.size())) { + return false; + } - stream->Write((const char*)&FnCount, sizeof(FnCount)); - stream->Write((const char*)&DataBase, sizeof(DataBase)); + if (Entry->FileId != Module) { + return false; + } - for (const auto& [GuestStart, DataOffset] : Entry.Index) { - //AOTIRInlineIndexEntry + lseek(streamfd, -sizeof(ModSize) - ModSize - sizeof(IndexSize), SEEK_END); - // GuestStart - stream->Write((const char*)&GuestStart, sizeof(GuestStart)); + if (!readAll(streamfd, (char*)&IndexSize, sizeof(IndexSize))) { + return false; + } - // DataOffset - stream->Write((const char*)&DataOffset, sizeof(DataOffset)); - } + struct stat fileinfo; + if (fstat(streamfd, &fileinfo) < 0) { + return false; + } + size_t Size = (fileinfo.st_size + 4095) & ~4095; - // End of file header - const auto IndexSize = FnCount * sizeof(FEXCore::IR::AOTIRInlineIndexEntry) + sizeof(DataBase) + sizeof(FnCount); - stream->Write((const char*)&IndexSize, sizeof(IndexSize)); - stream->Write(String.c_str(), ModSize); - stream->Write((const char*)&ModSize, sizeof(ModSize)); + size_t IndexOffset = fileinfo.st_size - IndexSize - sizeof(ModSize) - ModSize - sizeof(IndexSize); - // Close the stream - stream->Close(); + void* FilePtr = FEXCore::Allocator::mmap(nullptr, Size, PROT_READ, MAP_SHARED, streamfd, 0); - // Rename the file to atomically update the cache with the temporary file - AOTIRRenamer(String); + if (FilePtr == MAP_FAILED) { + return false; + } + + auto Array = (AOTIRInlineIndex*)((char*)FilePtr + IndexOffset); + + LOGMAN_THROW_AA_FMT(Entry->Array == nullptr && Entry->FilePtr == nullptr, "Entry must not be initialized here"); + Entry->Array = Array; + Entry->FilePtr = FilePtr; + Entry->Size = Size; + + LogMan::Msg::DFmt("AOTIR: Module {} has {} functions", Module, Array->Count); + + return true; +#else + return false; +#endif +} + +void AOTIRCaptureCache::FinalizeAOTIRCache() { + AOTIRCaptureCacheWriteoutQueue_Flush(); + + std::unique_lock lk(AOTIRCacheLock); + + for (auto& [String, Entry] : AOTIRCaptureCacheMap) { + if (!Entry.Stream) { + continue; + } + + const auto ModSize = String.size(); + auto& stream = Entry.Stream; + + // pad to 32 bytes + constexpr char Zero = 0; + while (stream->Offset() & 31) { + stream->Write(&Zero, 1); + } + + // AOTIRInlineIndex + const auto FnCount = Entry.Index.size(); + const size_t DataBase = -stream->Offset(); + + stream->Write((const char*)&FnCount, sizeof(FnCount)); + stream->Write((const char*)&DataBase, sizeof(DataBase)); + + for (const auto& [GuestStart, DataOffset] : Entry.Index) { + // AOTIRInlineIndexEntry + + // GuestStart + stream->Write((const char*)&GuestStart, sizeof(GuestStart)); + + // DataOffset + stream->Write((const char*)&DataOffset, sizeof(DataOffset)); + } + + // End of file header + const auto IndexSize = FnCount * sizeof(FEXCore::IR::AOTIRInlineIndexEntry) + sizeof(DataBase) + sizeof(FnCount); + stream->Write((const char*)&IndexSize, sizeof(IndexSize)); + stream->Write(String.c_str(), ModSize); + stream->Write((const char*)&ModSize, sizeof(ModSize)); + + // Close the stream + stream->Close(); + + // Rename the file to atomically update the cache with the temporary file + AOTIRRenamer(String); + } +} + +void AOTIRCaptureCache::AOTIRCaptureCacheWriteoutQueue_Flush() { + { + std::shared_lock lk {AOTIRCaptureCacheWriteoutLock}; + if (AOTIRCaptureCacheWriteoutQueue.size() == 0) { + AOTIRCaptureCacheWriteoutFlusing.store(false); + return; } } - void AOTIRCaptureCache::AOTIRCaptureCacheWriteoutQueue_Flush() { - { - std::shared_lock lk{AOTIRCaptureCacheWriteoutLock}; + for (;;) { + // This code is tricky to refactor so it doesn't allocate memory through glibc. + // The moved std::function object deallocates memory at the end of scope. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + + AOTIRCaptureCacheWriteoutLock.lock(); + WriteOutFn fn = std::move(AOTIRCaptureCacheWriteoutQueue.front()); + bool MaybeEmpty = false; + AOTIRCaptureCacheWriteoutQueue.pop(); + MaybeEmpty = AOTIRCaptureCacheWriteoutQueue.size() == 0; + AOTIRCaptureCacheWriteoutLock.unlock(); + + fn(); + if (MaybeEmpty) { + std::shared_lock lk {AOTIRCaptureCacheWriteoutLock}; if (AOTIRCaptureCacheWriteoutQueue.size() == 0) { AOTIRCaptureCacheWriteoutFlusing.store(false); return; } } - - for (;;) { - // This code is tricky to refactor so it doesn't allocate memory through glibc. - // The moved std::function object deallocates memory at the end of scope. - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - - AOTIRCaptureCacheWriteoutLock.lock(); - WriteOutFn fn = std::move(AOTIRCaptureCacheWriteoutQueue.front()); - bool MaybeEmpty = false; - AOTIRCaptureCacheWriteoutQueue.pop(); - MaybeEmpty = AOTIRCaptureCacheWriteoutQueue.size() == 0; - AOTIRCaptureCacheWriteoutLock.unlock(); - - fn(); - if (MaybeEmpty) { - std::shared_lock lk{AOTIRCaptureCacheWriteoutLock}; - if (AOTIRCaptureCacheWriteoutQueue.size() == 0) { - AOTIRCaptureCacheWriteoutFlusing.store(false); - return; - } - } - } - - LOGMAN_MSG_A_FMT("Must never get here"); } - void AOTIRCaptureCache::AOTIRCaptureCacheWriteoutQueue_Append(const WriteOutFn &fn) { - bool Flush = false; + LOGMAN_MSG_A_FMT("Must never get here"); +} - { - std::unique_lock lk{AOTIRCaptureCacheWriteoutLock}; - AOTIRCaptureCacheWriteoutQueue.push(fn); - if (AOTIRCaptureCacheWriteoutQueue.size() > 10000) { - Flush = true; - } - } +void AOTIRCaptureCache::AOTIRCaptureCacheWriteoutQueue_Append(const WriteOutFn& fn) { + bool Flush = false; - bool test_val = false; - if (Flush && AOTIRCaptureCacheWriteoutFlusing.compare_exchange_strong(test_val, true)) { - AOTIRCaptureCacheWriteoutQueue_Flush(); + { + std::unique_lock lk {AOTIRCaptureCacheWriteoutLock}; + AOTIRCaptureCacheWriteoutQueue.push(fn); + if (AOTIRCaptureCacheWriteoutQueue.size() > 10000) { + Flush = true; } } - void AOTIRCaptureCache::WriteFilesWithCode(const Context::AOTIRCodeFileWriterFn &Writer) { - std::shared_lock lk(AOTIRCacheLock); - for( const auto &Entry: AOTIRCache) { - if (Entry.second.ContainsCode) { - Writer(Entry.second.FileId, Entry.second.Filename); - } - } - } - - AOTIRCaptureCache::PreGenerateIRFetchResult AOTIRCaptureCache::PreGenerateIRFetch(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, FEXCore::IR::IRListView *IRList) { - auto AOTIRCacheEntry = CTX->SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); - - PreGenerateIRFetchResult Result{}; - - if (AOTIRCacheEntry.Entry) { - AOTIRCacheEntry.Entry->ContainsCode = true; - - if (IRList == nullptr && CTX->Config.AOTIRLoad()) { - auto Mod = AOTIRCacheEntry.Entry->Array; - - if (Mod != nullptr) - { - auto AOTEntry = Mod->Find(GuestRIP - AOTIRCacheEntry.VAFileStart); - - if (AOTEntry) { - // verify hash - auto MappedStart = GuestRIP; - auto hash = XXH3_64bits((void*)MappedStart, AOTEntry->GuestLength); - if (hash == AOTEntry->GuestHash) { - Result.IRList = AOTEntry->GetIRData(); - //LogMan::Msg::DFmt("using {} + {:x} -> {:x}\n", file->second.fileid, AOTEntry->first, GuestRIP); - - Result.RAData = AOTEntry->GetRAData()->CreateCopy(); - Result.DebugData = new FEXCore::Core::DebugData(); - Result.StartAddr = MappedStart; - Result.Length = AOTEntry->GuestLength; - Result.GeneratedIR = true; - } else { - LogMan::Msg::IFmt("AOTIR: hash check failed {:x}\n", MappedStart); - } - } else { - //LogMan::Msg::IFmt("AOTIR: Failed to find {:x}, {:x}, {}\n", GuestRIP, GuestRIP - file->second.Start + file->second.Offset, file->second.fileid); - } - } - } - } - - return Result; - } - - bool AOTIRCaptureCache::PostCompileCode( - FEXCore::Core::InternalThreadState *Thread, - void* CodePtr, - uint64_t GuestRIP, - uint64_t StartAddr, - uint64_t Length, - FEXCore::IR::RegisterAllocationData::UniquePtr RAData, - FEXCore::IR::IRListView *IRList, - FEXCore::Core::DebugData *DebugData, - bool GeneratedIR) { - - // Both generated ir and LibraryJITName need a named region lookup - if (GeneratedIR || CTX->Config.LibraryJITNaming() || CTX->Config.GDBSymbols()) { - - auto AOTIRCacheEntry = CTX->SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); - - if (AOTIRCacheEntry.Entry) { - if (DebugData && CTX->Config.LibraryJITNaming()) { - CTX->Symbols.RegisterNamedRegion(Thread->SymbolBuffer.get(), CodePtr, DebugData->HostCodeSize, AOTIRCacheEntry.Entry->Filename); - } - - if (CTX->Config.GDBSymbols()) { - GDBJITRegister(AOTIRCacheEntry.Entry, AOTIRCacheEntry.VAFileStart, GuestRIP, (uintptr_t)CodePtr, DebugData); - } - - // Add to AOT cache if aot generation is enabled - if (GeneratedIR && RAData && - (CTX->Config.AOTIRCapture() || CTX->Config.AOTIRGenerate())) { - - auto hash = XXH3_64bits((void*)StartAddr, Length); - - auto LocalRIP = GuestRIP - AOTIRCacheEntry.VAFileStart; - auto LocalStartAddr = StartAddr - AOTIRCacheEntry.VAFileStart; - auto FileId = AOTIRCacheEntry.Entry->FileId; - // The underlying pointer and the unique_ptr deleter for RAData must - // be marshalled separately to the lambda below. Otherwise, the - // lambda can't be used as an std::function due to being non-copyable - auto RADataCopy = RAData->CreateCopy(); - auto RADataCopyDeleter = RADataCopy.get_deleter(); - auto IRListCopy = IRList->CreateCopy(); - - // The lambda is converted to std::function. This is tricky to refactor so it doesn't allocate memory through glibc. - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - AOTIRCaptureCacheWriteoutQueue_Append([this, LocalRIP, LocalStartAddr, Length, hash, IRListCopy, RADataCopy=RADataCopy.release(), RADataCopyDeleter, FileId]() { - - // It is guaranteed via AOTIRCaptureCacheWriteoutLock and AOTIRCaptureCacheWriteoutFlusing that this will not run concurrently - // Memory coherency is guaranteed via AOTIRCaptureCacheWriteoutLock - - auto *AotFile = &AOTIRCaptureCacheMap[FileId]; - - if (!AotFile->Stream) { - AotFile->Stream = AOTIRWriter(FileId); - uint64_t tag = FEXCore::IR::AOTIR_COOKIE; - AotFile->Stream->Write(&tag, sizeof(tag)); - } - AotFile->AppendAOTIRCaptureCache(LocalRIP, LocalStartAddr, Length, hash, IRListCopy, RADataCopy); - RADataCopyDeleter(RADataCopy); - delete IRListCopy; - }); - - if (CTX->Config.AOTIRGenerate()) { - // cleanup memory and early exit here -- we're not running the application - Thread->CPUBackend->ClearCache(); - return true; - } - } - } - - // Insert to caches if we generated IR - if (GeneratedIR) { - // If the IR doesn't need to be retained then we can just delete it now - delete DebugData; - if (IRList->IsCopy()) delete IRList; - } - } - - return false; - } - - AOTIRCacheEntry *AOTIRCaptureCache::LoadAOTIRCacheEntry(const fextl::string &filename) { - fextl::string base_filename = FHU::Filesystem::GetFilename(filename); - - if (!base_filename.empty()) { - auto filename_hash = XXH3_64bits(filename.c_str(), filename.size()); - - auto fileid = fextl::fmt::format("{}-{}-{}{}{}", - base_filename, - filename_hash, - (CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? 'S' : 's', - CTX->Config.TSOEnabled ? 'T' : 't', - CTX->Config.ABILocalFlags ? 'L' : 'l'); - - std::unique_lock lk(AOTIRCacheLock); - - auto Inserted = AOTIRCache.insert({fileid, AOTIRCacheEntry { .FileId = fileid, .Filename = filename }}); - auto Entry = &(Inserted.first->second); - - LOGMAN_THROW_AA_FMT(Entry->Array == nullptr, "Duplicate LoadAOTIRCacheEntry"); - - if (CTX->Config.AOTIRLoad && AOTIRLoader) { - auto streamfd = AOTIRLoader(fileid); - if (streamfd != -1) { - FEXCore::IR::LoadAOTIRCache(Entry, streamfd); - close(streamfd); - } - } - return Entry; - } - - return nullptr; - } - - void AOTIRCaptureCache::UnloadAOTIRCacheEntry(AOTIRCacheEntry *Entry) { -#ifndef _WIN32 - LOGMAN_THROW_AA_FMT(Entry != nullptr, "Removing not existing entry"); - - if (Entry->Array) { - FEXCore::Allocator::munmap(Entry->FilePtr, Entry->Size); - Entry->Array = nullptr; - Entry->FilePtr = nullptr; - Entry->Size = 0; - } -#endif + bool test_val = false; + if (Flush && AOTIRCaptureCacheWriteoutFlusing.compare_exchange_strong(test_val, true)) { + AOTIRCaptureCacheWriteoutQueue_Flush(); } } + +void AOTIRCaptureCache::WriteFilesWithCode(const Context::AOTIRCodeFileWriterFn& Writer) { + std::shared_lock lk(AOTIRCacheLock); + for (const auto& Entry : AOTIRCache) { + if (Entry.second.ContainsCode) { + Writer(Entry.second.FileId, Entry.second.Filename); + } + } +} + +AOTIRCaptureCache::PreGenerateIRFetchResult +AOTIRCaptureCache::PreGenerateIRFetch(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, FEXCore::IR::IRListView* IRList) { + auto AOTIRCacheEntry = CTX->SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); + + PreGenerateIRFetchResult Result {}; + + if (AOTIRCacheEntry.Entry) { + AOTIRCacheEntry.Entry->ContainsCode = true; + + if (IRList == nullptr && CTX->Config.AOTIRLoad()) { + auto Mod = AOTIRCacheEntry.Entry->Array; + + if (Mod != nullptr) { + auto AOTEntry = Mod->Find(GuestRIP - AOTIRCacheEntry.VAFileStart); + + if (AOTEntry) { + // verify hash + auto MappedStart = GuestRIP; + auto hash = XXH3_64bits((void*)MappedStart, AOTEntry->GuestLength); + if (hash == AOTEntry->GuestHash) { + Result.IRList = AOTEntry->GetIRData(); + // LogMan::Msg::DFmt("using {} + {:x} -> {:x}\n", file->second.fileid, AOTEntry->first, GuestRIP); + + Result.RAData = AOTEntry->GetRAData()->CreateCopy(); + Result.DebugData = new FEXCore::Core::DebugData(); + Result.StartAddr = MappedStart; + Result.Length = AOTEntry->GuestLength; + Result.GeneratedIR = true; + } else { + LogMan::Msg::IFmt("AOTIR: hash check failed {:x}\n", MappedStart); + } + } else { + // LogMan::Msg::IFmt("AOTIR: Failed to find {:x}, {:x}, {}\n", GuestRIP, GuestRIP - file->second.Start + file->second.Offset, file->second.fileid); + } + } + } + } + + return Result; +} + +bool AOTIRCaptureCache::PostCompileCode(FEXCore::Core::InternalThreadState* Thread, void* CodePtr, uint64_t GuestRIP, uint64_t StartAddr, + uint64_t Length, FEXCore::IR::RegisterAllocationData::UniquePtr RAData, + FEXCore::IR::IRListView* IRList, FEXCore::Core::DebugData* DebugData, bool GeneratedIR) { + + // Both generated ir and LibraryJITName need a named region lookup + if (GeneratedIR || CTX->Config.LibraryJITNaming() || CTX->Config.GDBSymbols()) { + + auto AOTIRCacheEntry = CTX->SyscallHandler->LookupAOTIRCacheEntry(Thread, GuestRIP); + + if (AOTIRCacheEntry.Entry) { + if (DebugData && CTX->Config.LibraryJITNaming()) { + CTX->Symbols.RegisterNamedRegion(Thread->SymbolBuffer.get(), CodePtr, DebugData->HostCodeSize, AOTIRCacheEntry.Entry->Filename); + } + + if (CTX->Config.GDBSymbols()) { + GDBJITRegister(AOTIRCacheEntry.Entry, AOTIRCacheEntry.VAFileStart, GuestRIP, (uintptr_t)CodePtr, DebugData); + } + + // Add to AOT cache if aot generation is enabled + if (GeneratedIR && RAData && (CTX->Config.AOTIRCapture() || CTX->Config.AOTIRGenerate())) { + + auto hash = XXH3_64bits((void*)StartAddr, Length); + + auto LocalRIP = GuestRIP - AOTIRCacheEntry.VAFileStart; + auto LocalStartAddr = StartAddr - AOTIRCacheEntry.VAFileStart; + auto FileId = AOTIRCacheEntry.Entry->FileId; + // The underlying pointer and the unique_ptr deleter for RAData must + // be marshalled separately to the lambda below. Otherwise, the + // lambda can't be used as an std::function due to being non-copyable + auto RADataCopy = RAData->CreateCopy(); + auto RADataCopyDeleter = RADataCopy.get_deleter(); + auto IRListCopy = IRList->CreateCopy(); + + // The lambda is converted to std::function. This is tricky to refactor so it doesn't allocate memory through glibc. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + AOTIRCaptureCacheWriteoutQueue_Append( + [this, LocalRIP, LocalStartAddr, Length, hash, IRListCopy, RADataCopy = RADataCopy.release(), RADataCopyDeleter, FileId]() { + // It is guaranteed via AOTIRCaptureCacheWriteoutLock and AOTIRCaptureCacheWriteoutFlusing that this will not run concurrently + // Memory coherency is guaranteed via AOTIRCaptureCacheWriteoutLock + + auto* AotFile = &AOTIRCaptureCacheMap[FileId]; + + if (!AotFile->Stream) { + AotFile->Stream = AOTIRWriter(FileId); + uint64_t tag = FEXCore::IR::AOTIR_COOKIE; + AotFile->Stream->Write(&tag, sizeof(tag)); + } + AotFile->AppendAOTIRCaptureCache(LocalRIP, LocalStartAddr, Length, hash, IRListCopy, RADataCopy); + RADataCopyDeleter(RADataCopy); + delete IRListCopy; + }); + + if (CTX->Config.AOTIRGenerate()) { + // cleanup memory and early exit here -- we're not running the application + Thread->CPUBackend->ClearCache(); + return true; + } + } + } + + // Insert to caches if we generated IR + if (GeneratedIR) { + // If the IR doesn't need to be retained then we can just delete it now + delete DebugData; + if (IRList->IsCopy()) { + delete IRList; + } + } + } + + return false; +} + +AOTIRCacheEntry* AOTIRCaptureCache::LoadAOTIRCacheEntry(const fextl::string& filename) { + fextl::string base_filename = FHU::Filesystem::GetFilename(filename); + + if (!base_filename.empty()) { + auto filename_hash = XXH3_64bits(filename.c_str(), filename.size()); + + auto fileid = fextl::fmt::format("{}-{}-{}{}{}", base_filename, filename_hash, + (CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? 'S' : 's', + CTX->Config.TSOEnabled ? 'T' : 't', CTX->Config.ABILocalFlags ? 'L' : 'l'); + + std::unique_lock lk(AOTIRCacheLock); + + auto Inserted = AOTIRCache.insert({fileid, AOTIRCacheEntry {.FileId = fileid, .Filename = filename}}); + auto Entry = &(Inserted.first->second); + + LOGMAN_THROW_AA_FMT(Entry->Array == nullptr, "Duplicate LoadAOTIRCacheEntry"); + + if (CTX->Config.AOTIRLoad && AOTIRLoader) { + auto streamfd = AOTIRLoader(fileid); + if (streamfd != -1) { + FEXCore::IR::LoadAOTIRCache(Entry, streamfd); + close(streamfd); + } + } + return Entry; + } + + return nullptr; +} + +void AOTIRCaptureCache::UnloadAOTIRCacheEntry(AOTIRCacheEntry* Entry) { +#ifndef _WIN32 + LOGMAN_THROW_AA_FMT(Entry != nullptr, "Removing not existing entry"); + + if (Entry->Array) { + FEXCore::Allocator::munmap(Entry->FilePtr, Entry->Size); + Entry->Array = nullptr; + Entry->FilePtr = nullptr; + Entry->Size = 0; + } +#endif +} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/AOTIR.h b/FEXCore/Source/Interface/IR/AOTIR.h index b128b8ab6..11a87a200 100644 --- a/FEXCore/Source/Interface/IR/AOTIR.h +++ b/FEXCore/Source/Interface/IR/AOTIR.h @@ -20,136 +20,133 @@ namespace FEXCore::Core { struct DebugData; } namespace FEXCore::Context { - class ContextImpl; +class ContextImpl; } namespace FEXCore::IR { - class RegisterAllocationData; - class IRListView; +class RegisterAllocationData; +class IRListView; - constexpr auto COOKIE_VERSION = [](const char CookieText[4], uint32_t Version) { - uint64_t Cookie = Version; - Cookie <<= 32; +constexpr auto COOKIE_VERSION = [](const char CookieText[4], uint32_t Version) { + uint64_t Cookie = Version; + Cookie <<= 32; - // Make the cookie text be the lower bits - Cookie |= CookieText[3]; - Cookie <<= 8; - Cookie |= CookieText[2]; - Cookie <<= 8; - Cookie |= CookieText[1]; - Cookie <<= 8; - Cookie |= CookieText[0]; + // Make the cookie text be the lower bits + Cookie |= CookieText[3]; + Cookie <<= 8; + Cookie |= CookieText[2]; + Cookie <<= 8; + Cookie |= CookieText[1]; + Cookie <<= 8; + Cookie |= CookieText[0]; - return Cookie; + return Cookie; +}; +constexpr static uint32_t AOTIR_VERSION = 0x0000'00004; +constexpr static uint64_t AOTIR_COOKIE = COOKIE_VERSION("FEXI", AOTIR_VERSION); + +struct AOTIRInlineEntry { + uint64_t GuestHash; + uint64_t GuestLength; + + /* RAData followed by IRData */ + uint8_t InlineData[0]; + + IR::RegisterAllocationData* GetRAData(); + IR::IRListView* GetIRData(); +}; + +struct AOTIRInlineIndexEntry { + uint64_t GuestStart; + uint64_t DataOffset; +}; + +struct AOTIRInlineIndex { + uint64_t Count; + uint64_t DataBase; + AOTIRInlineIndexEntry Entries[0]; + + AOTIRInlineEntry* Find(uint64_t GuestStart); + AOTIRInlineEntry* GetInlineEntry(uint64_t DataOffset); +}; + +struct AOTIRCaptureCacheEntry { + fextl::unique_ptr Stream; + fextl::map Index; + + void AppendAOTIRCaptureCache(uint64_t GuestRIP, uint64_t Start, uint64_t Length, uint64_t Hash, FEXCore::IR::IRListView* IRList, + FEXCore::IR::RegisterAllocationData* RAData); +}; + +struct AOTIRCacheEntry { + AOTIRInlineIndex* Array; + void* FilePtr; + size_t Size; + std::unique_ptr SourcecodeMap; + fextl::string FileId; + fextl::string Filename; + bool ContainsCode; +}; + +using AOTCacheType = fextl::unordered_map; + +class AOTIRCaptureCache final { +public: + using WriteOutFn = std::function; + + AOTIRCaptureCache(FEXCore::Context::ContextImpl* ctx) + : CTX {ctx} {} + + void FinalizeAOTIRCache(); + void AOTIRCaptureCacheWriteoutQueue_Flush(); + void AOTIRCaptureCacheWriteoutQueue_Append(const WriteOutFn& fn); + void WriteFilesWithCode(const Context::AOTIRCodeFileWriterFn& Writer); + + struct PreGenerateIRFetchResult { + FEXCore::IR::IRListView* IRList {}; + FEXCore::IR::RegisterAllocationData::UniquePtr RAData {}; + FEXCore::Core::DebugData* DebugData {}; + uint64_t StartAddr {}; + uint64_t Length {}; + bool GeneratedIR {}; }; - constexpr static uint32_t AOTIR_VERSION = 0x0000'00004; - constexpr static uint64_t AOTIR_COOKIE = COOKIE_VERSION("FEXI", AOTIR_VERSION); + [[nodiscard]] + PreGenerateIRFetchResult PreGenerateIRFetch(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, FEXCore::IR::IRListView* IRList); - struct AOTIRInlineEntry { - uint64_t GuestHash; - uint64_t GuestLength; + bool PostCompileCode(FEXCore::Core::InternalThreadState* Thread, void* CodePtr, uint64_t GuestRIP, uint64_t StartAddr, uint64_t Length, + FEXCore::IR::RegisterAllocationData::UniquePtr RAData, FEXCore::IR::IRListView* IRList, + FEXCore::Core::DebugData* DebugData, bool GeneratedIR); - /* RAData followed by IRData */ - uint8_t InlineData[0]; + AOTIRCacheEntry* LoadAOTIRCacheEntry(const fextl::string& filename); + void UnloadAOTIRCacheEntry(AOTIRCacheEntry* Entry); - IR::RegisterAllocationData *GetRAData(); - IR::IRListView *GetIRData(); - }; + // Callbacks + void SetAOTIRLoader(Context::AOTIRLoaderCBFn CacheReader) { + AOTIRLoader = std::move(CacheReader); + } - struct AOTIRInlineIndexEntry { - uint64_t GuestStart; - uint64_t DataOffset; - }; + void SetAOTIRWriter(Context::AOTIRWriterCBFn CacheWriter) { + AOTIRWriter = std::move(CacheWriter); + } - struct AOTIRInlineIndex { - uint64_t Count; - uint64_t DataBase; - AOTIRInlineIndexEntry Entries[0]; + void SetAOTIRRenamer(Context::AOTIRRenamerCBFn CacheRenamer) { + AOTIRRenamer = std::move(CacheRenamer); + } - AOTIRInlineEntry *Find(uint64_t GuestStart); - AOTIRInlineEntry *GetInlineEntry(uint64_t DataOffset); - }; +private: + FEXCore::Context::ContextImpl* CTX; - struct AOTIRCaptureCacheEntry { - fextl::unique_ptr Stream; - fextl::map Index; + std::shared_mutex AOTIRCacheLock; + std::shared_mutex AOTIRCaptureCacheWriteoutLock; + std::atomic AOTIRCaptureCacheWriteoutFlusing; - void AppendAOTIRCaptureCache(uint64_t GuestRIP, uint64_t Start, uint64_t Length, uint64_t Hash, FEXCore::IR::IRListView *IRList, FEXCore::IR::RegisterAllocationData *RAData); - }; + fextl::queue AOTIRCaptureCacheWriteoutQueue; - struct AOTIRCacheEntry { - AOTIRInlineIndex *Array; - void *FilePtr; - size_t Size; - std::unique_ptr SourcecodeMap; - fextl::string FileId; - fextl::string Filename; - bool ContainsCode; - }; + FEXCore::IR::AOTCacheType AOTIRCache; - using AOTCacheType = fextl::unordered_map; - - class AOTIRCaptureCache final { - public: - using WriteOutFn = std::function; - - AOTIRCaptureCache(FEXCore::Context::ContextImpl *ctx) : CTX {ctx} {} - - void FinalizeAOTIRCache(); - void AOTIRCaptureCacheWriteoutQueue_Flush(); - void AOTIRCaptureCacheWriteoutQueue_Append(const WriteOutFn &fn); - void WriteFilesWithCode(const Context::AOTIRCodeFileWriterFn &Writer); - - struct PreGenerateIRFetchResult { - FEXCore::IR::IRListView *IRList {}; - FEXCore::IR::RegisterAllocationData::UniquePtr RAData {}; - FEXCore::Core::DebugData *DebugData {}; - uint64_t StartAddr {}; - uint64_t Length {}; - bool GeneratedIR {}; - }; - [[nodiscard]] PreGenerateIRFetchResult PreGenerateIRFetch(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, FEXCore::IR::IRListView *IRList); - - bool PostCompileCode(FEXCore::Core::InternalThreadState *Thread, - void* CodePtr, - uint64_t GuestRIP, - uint64_t StartAddr, - uint64_t Length, - FEXCore::IR::RegisterAllocationData::UniquePtr RAData, - FEXCore::IR::IRListView *IRList, - FEXCore::Core::DebugData *DebugData, - bool GeneratedIR); - - AOTIRCacheEntry *LoadAOTIRCacheEntry(const fextl::string &filename); - void UnloadAOTIRCacheEntry(AOTIRCacheEntry *Entry); - - // Callbacks - void SetAOTIRLoader(Context::AOTIRLoaderCBFn CacheReader) { - AOTIRLoader = std::move(CacheReader); - } - - void SetAOTIRWriter(Context::AOTIRWriterCBFn CacheWriter) { - AOTIRWriter = std::move(CacheWriter); - } - - void SetAOTIRRenamer(Context::AOTIRRenamerCBFn CacheRenamer) { - AOTIRRenamer = std::move(CacheRenamer); - } - - private: - FEXCore::Context::ContextImpl *CTX; - - std::shared_mutex AOTIRCacheLock; - std::shared_mutex AOTIRCaptureCacheWriteoutLock; - std::atomic AOTIRCaptureCacheWriteoutFlusing; - - fextl::queue AOTIRCaptureCacheWriteoutQueue; - - FEXCore::IR::AOTCacheType AOTIRCache; - - Context::AOTIRLoaderCBFn AOTIRLoader; - Context::AOTIRWriterCBFn AOTIRWriter; - Context::AOTIRRenamerCBFn AOTIRRenamer; - fextl::unordered_map AOTIRCaptureCacheMap; - }; -} + Context::AOTIRLoaderCBFn AOTIRLoader; + Context::AOTIRWriterCBFn AOTIRWriter; + Context::AOTIRRenamerCBFn AOTIRRenamer; + fextl::unordered_map AOTIRCaptureCacheMap; +}; +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/IR.h b/FEXCore/Source/Interface/IR/IR.h index 77d1930d2..7a0a72a84 100644 --- a/FEXCore/Source/Interface/IR/IR.h +++ b/FEXCore/Source/Interface/IR/IR.h @@ -31,7 +31,8 @@ struct NodeID final { using value_type = uint32_t; constexpr NodeID() noexcept = default; - constexpr explicit NodeID(value_type Value_) noexcept : Value{Value_} {} + constexpr explicit NodeID(value_type Value_) noexcept + : Value {Value_} {} constexpr NodeID(const NodeID&) noexcept = default; constexpr NodeID& operator=(const NodeID&) noexcept = default; @@ -39,10 +40,12 @@ struct NodeID final { constexpr NodeID(NodeID&&) noexcept = default; constexpr NodeID& operator=(NodeID&&) noexcept = default; - [[nodiscard]] constexpr bool IsValid() const noexcept { + [[nodiscard]] + constexpr bool IsValid() const noexcept { return Value != 0; } - [[nodiscard]] constexpr bool IsInvalid() const noexcept { + [[nodiscard]] + constexpr bool IsInvalid() const noexcept { return !IsValid(); } constexpr void Invalidate() noexcept { @@ -51,16 +54,24 @@ struct NodeID final { [[nodiscard]] friend constexpr bool operator==(NodeID, NodeID) noexcept = default; - [[nodiscard]] friend constexpr bool operator<(NodeID lhs, NodeID rhs) noexcept { + [[nodiscard]] + friend constexpr bool + operator<(NodeID lhs, NodeID rhs) noexcept { return lhs.Value < rhs.Value; } - [[nodiscard]] friend constexpr bool operator>(NodeID lhs, NodeID rhs) noexcept { + [[nodiscard]] + friend constexpr bool + operator>(NodeID lhs, NodeID rhs) noexcept { return operator<(rhs, lhs); } - [[nodiscard]] friend constexpr bool operator<=(NodeID lhs, NodeID rhs) noexcept { + [[nodiscard]] + friend constexpr bool + operator<=(NodeID lhs, NodeID rhs) noexcept { return !operator>(lhs, rhs); } - [[nodiscard]] friend constexpr bool operator>=(NodeID lhs, NodeID rhs) noexcept { + [[nodiscard]] + friend constexpr bool + operator>=(NodeID lhs, NodeID rhs) noexcept { return !operator<(lhs, rhs); } @@ -73,7 +84,7 @@ struct NodeID final { return in; } - value_type Value{}; + value_type Value {}; }; /** @@ -103,36 +114,49 @@ struct NodeWrapperBase final { explicit NodeWrapperBase() = default; - [[nodiscard]] static NodeWrapperBase WrapOffset(NodeOffsetType Offset) { + [[nodiscard]] + static NodeWrapperBase WrapOffset(NodeOffsetType Offset) { NodeWrapperBase Wrapped; Wrapped.NodeOffset = Offset; return Wrapped; } - [[nodiscard]] static NodeWrapperBase WrapPtr(uintptr_t Base, uintptr_t Value) { + [[nodiscard]] + static NodeWrapperBase WrapPtr(uintptr_t Base, uintptr_t Value) { NodeWrapperBase Wrapped; Wrapped.SetOffset(Base, Value); return Wrapped; } - [[nodiscard]] static void *UnwrapNode(uintptr_t Base, NodeWrapperBase Node) { + [[nodiscard]] + static void* UnwrapNode(uintptr_t Base, NodeWrapperBase Node) { return Node.GetNode(Base); } - [[nodiscard]] NodeID ID() const; + [[nodiscard]] + NodeID ID() const; - [[nodiscard]] bool IsInvalid() const { return NodeOffset == 0; } + [[nodiscard]] + bool IsInvalid() const { + return NodeOffset == 0; + } - [[nodiscard]] Type *GetNode(uintptr_t Base) { + [[nodiscard]] + Type* GetNode(uintptr_t Base) { return reinterpret_cast(Base + NodeOffset); } - [[nodiscard]] const Type *GetNode(uintptr_t Base) const { + [[nodiscard]] + const Type* GetNode(uintptr_t Base) const { return reinterpret_cast(Base + NodeOffset); } - void SetOffset(uintptr_t Base, uintptr_t Value) { NodeOffset = Value - Base; } + void SetOffset(uintptr_t Base, uintptr_t Value) { + NodeOffset = Value - Base; + } - [[nodiscard]] friend constexpr bool operator==(const NodeWrapperBase&, const NodeWrapperBase&) = default; + [[nodiscard]] + friend constexpr bool + operator==(const NodeWrapperBase&, const NodeWrapperBase&) = default; }; static_assert(std::is_trivial_v>); @@ -167,154 +191,168 @@ static_assert(sizeof(OrderedNodeHeader) == sizeof(uint32_t) * 3); class OrderedNode final { friend class NodeWrapperIterator; friend class OrderedList; - public: - // These three values are laid out very specifically to make it fast to access the NodeWrappers specifically - OrderedNodeHeader Header; - uint32_t NumUses; +public: + // These three values are laid out very specifically to make it fast to access the NodeWrappers specifically + OrderedNodeHeader Header; + uint32_t NumUses; - using value_type = OrderedNodeWrapper; + using value_type = OrderedNodeWrapper; - OrderedNode() = default; + OrderedNode() = default; - /** - * @brief Appends a node to this current node - * - * Before. <-> <-> - * After. <-> <-> <-> Next - * - * @return Pointer to the node being added - */ - value_type append(uintptr_t Base, value_type Node) { - // Set Next Node's Previous to incoming node - SetPrevious(Base, Header.Next, Node); + /** + * @brief Appends a node to this current node + * + * Before. <-> <-> + * After. <-> <-> <-> Next + * + * @return Pointer to the node being added + */ + value_type append(uintptr_t Base, value_type Node) { + // Set Next Node's Previous to incoming node + SetPrevious(Base, Header.Next, Node); - // Set Incoming node's links to this node's links - SetPrevious(Base, Node, Wrapped(Base)); - SetNext(Base, Node, Header.Next); + // Set Incoming node's links to this node's links + SetPrevious(Base, Node, Wrapped(Base)); + SetNext(Base, Node, Header.Next); - // Set this node's next to the incoming node - SetNext(Base, Wrapped(Base), Node); + // Set this node's next to the incoming node + SetNext(Base, Wrapped(Base), Node); - // Return the node we are appending - return Node; + // Return the node we are appending + return Node; + } + + OrderedNode* append(uintptr_t Base, OrderedNode* Node) { + value_type WNode = Node->Wrapped(Base); + // Set Next Node's Previous to incoming node + SetPrevious(Base, Header.Next, WNode); + + // Set Incoming node's links to this node's links + SetPrevious(Base, WNode, Wrapped(Base)); + SetNext(Base, WNode, Header.Next); + + // Set this node's next to the incoming node + SetNext(Base, Wrapped(Base), WNode); + + // Return the node we are appending + return Node; + } + + /** + * @brief Prepends a node to the current node + * Before. <-> <-> + * After. <-> <-> <-> Next + * + * @return Pointer to the node being added + */ + value_type prepend(uintptr_t Base, value_type Node) { + // Set the previous node's next to the incoming node + SetNext(Base, Header.Previous, Node); + + // Set the incoming node's links + SetPrevious(Base, Node, Header.Previous); + SetNext(Base, Node, Wrapped(Base)); + + // Set the current node's link + SetPrevious(Base, Wrapped(Base), Node); + + // Return the node we are prepending + return Node; + } + + OrderedNode* prepend(uintptr_t Base, OrderedNode* Node) { + value_type WNode = Node->Wrapped(Base); + // Set the previous node's next to the incoming node + SetNext(Base, Header.Previous, WNode); + + // Set the incoming node's links + SetPrevious(Base, WNode, Header.Previous); + SetNext(Base, WNode, Wrapped(Base)); + + // Set the current node's link + SetPrevious(Base, Wrapped(Base), WNode); + + // Return the node we are prepending + return Node; + } + + /** + * @brief Gets the remaining size of the blocks from this point onward + * + * Doesn't find the head of the list + * + */ + [[nodiscard]] + size_t size(uintptr_t Base) const { + size_t Size = 1; + // Walk the list forward until we hit a sentinel + value_type Current = Header.Next; + while (Current.NodeOffset != 0) { + ++Size; + OrderedNode* RealNode = Current.GetNode(Base); + Current = RealNode->Header.Next; } + return Size; + } - OrderedNode *append(uintptr_t Base, OrderedNode *Node) { - value_type WNode = Node->Wrapped(Base); - // Set Next Node's Previous to incoming node - SetPrevious(Base, Header.Next, WNode); + void Unlink(uintptr_t Base) { + // This removes the node from the list. Orphaning it + // Before: <-> <-> + // After: + SetNext(Base, Header.Previous, Header.Next); + SetPrevious(Base, Header.Next, Header.Previous); + } - // Set Incoming node's links to this node's links - SetPrevious(Base, WNode, Wrapped(Base)); - SetNext(Base, WNode, Header.Next); + [[nodiscard]] + const IROp_Header* Op(uintptr_t Base) const { + return Header.Value.GetNode(Base); + } + [[nodiscard]] + IROp_Header* Op(uintptr_t Base) { + return Header.Value.GetNode(Base); + } - // Set this node's next to the incoming node - SetNext(Base, Wrapped(Base), WNode); + [[nodiscard]] + uint32_t GetUses() const { + return NumUses; + } - // Return the node we are appending - return Node; - } + void AddUse() { + ++NumUses; + } + void RemoveUse() { + --NumUses; + } - /** - * @brief Prepends a node to the current node - * Before. <-> <-> - * After. <-> <-> <-> Next - * - * @return Pointer to the node being added - */ - value_type prepend(uintptr_t Base, value_type Node) { - // Set the previous node's next to the incoming node - SetNext(Base, Header.Previous, Node); + [[nodiscard]] + value_type Wrapped(uintptr_t Base) const { + value_type Tmp; + Tmp.SetOffset(Base, reinterpret_cast(this)); + return Tmp; + } - // Set the incoming node's links - SetPrevious(Base, Node, Header.Previous); - SetNext(Base, Node, Wrapped(Base)); +private: + [[nodiscard]] + value_type WrappedOffset(uint32_t Offset) const { + value_type Tmp; + Tmp.NodeOffset = Offset; + return Tmp; + } - // Set the current node's link - SetPrevious(Base, Wrapped(Base), Node); + static void SetPrevious(uintptr_t Base, value_type Node, value_type New) { + OrderedNode* RealNode = Node.GetNode(Base); + RealNode->Header.Previous = New; + } - // Return the node we are prepending - return Node; - } + static void SetNext(uintptr_t Base, value_type Node, value_type New) { + OrderedNode* RealNode = Node.GetNode(Base); + RealNode->Header.Next = New; + } - OrderedNode *prepend(uintptr_t Base, OrderedNode *Node) { - value_type WNode = Node->Wrapped(Base); - // Set the previous node's next to the incoming node - SetNext(Base, Header.Previous, WNode); - - // Set the incoming node's links - SetPrevious(Base, WNode, Header.Previous); - SetNext(Base, WNode, Wrapped(Base)); - - // Set the current node's link - SetPrevious(Base, Wrapped(Base), WNode); - - // Return the node we are prepending - return Node; - } - - /** - * @brief Gets the remaining size of the blocks from this point onward - * - * Doesn't find the head of the list - * - */ - [[nodiscard]] size_t size(uintptr_t Base) const { - size_t Size = 1; - // Walk the list forward until we hit a sentinel - value_type Current = Header.Next; - while (Current.NodeOffset != 0) { - ++Size; - OrderedNode *RealNode = Current.GetNode(Base); - Current = RealNode->Header.Next; - } - return Size; - } - - void Unlink(uintptr_t Base) { - // This removes the node from the list. Orphaning it - // Before: <-> <-> - // After: - SetNext(Base, Header.Previous, Header.Next); - SetPrevious(Base, Header.Next, Header.Previous); - } - - [[nodiscard]] IROp_Header const* Op(uintptr_t Base) const { - return Header.Value.GetNode(Base); - } - [[nodiscard]] IROp_Header *Op(uintptr_t Base) { - return Header.Value.GetNode(Base); - } - - [[nodiscard]] uint32_t GetUses() const { return NumUses; } - - void AddUse() { ++NumUses; } - void RemoveUse() { --NumUses; } - - [[nodiscard]] value_type Wrapped(uintptr_t Base) const { - value_type Tmp; - Tmp.SetOffset(Base, reinterpret_cast(this)); - return Tmp; - } - - private: - [[nodiscard]] value_type WrappedOffset(uint32_t Offset) const { - value_type Tmp; - Tmp.NodeOffset = Offset; - return Tmp; - } - - static void SetPrevious(uintptr_t Base, value_type Node, value_type New) { - OrderedNode *RealNode = Node.GetNode(Base); - RealNode->Header.Previous = New; - } - - static void SetNext(uintptr_t Base, value_type Node, value_type New) { - OrderedNode *RealNode = Node.GetNode(Base); - RealNode->Header.Next = New; - } - - void SetUses(uint32_t Uses) { NumUses = Uses; } + void SetUses(uint32_t Uses) { + NumUses = Uses; + } }; static_assert(std::is_trivial_v); @@ -329,7 +367,9 @@ struct RegisterClassType final { [[nodiscard]] constexpr operator value_type() const { return Val; } - [[nodiscard]] friend constexpr bool operator==(const RegisterClassType&, const RegisterClassType&) = default; + [[nodiscard]] + friend constexpr bool + operator==(const RegisterClassType&, const RegisterClassType&) = default; }; struct CondClassType final { @@ -337,7 +377,9 @@ struct CondClassType final { [[nodiscard]] constexpr operator uint8_t() const { return Val; } - [[nodiscard]] friend constexpr bool operator==(const CondClassType&, const CondClassType&) = default; + [[nodiscard]] + friend constexpr bool + operator==(const CondClassType&, const CondClassType&) = default; }; struct MemOffsetType final { @@ -345,7 +387,9 @@ struct MemOffsetType final { [[nodiscard]] constexpr operator uint8_t() const { return Val; } - [[nodiscard]] friend constexpr bool operator==(const MemOffsetType&, const MemOffsetType&) = default; + [[nodiscard]] + friend constexpr bool + operator==(const MemOffsetType&, const MemOffsetType&) = default; }; struct TypeDefinition final { @@ -355,27 +399,33 @@ struct TypeDefinition final { return Val; } - [[nodiscard]] static constexpr TypeDefinition Create(uint8_t Bytes) { - TypeDefinition Type{}; + [[nodiscard]] + static constexpr TypeDefinition Create(uint8_t Bytes) { + TypeDefinition Type {}; Type.Val = Bytes << 8; return Type; } - [[nodiscard]] static constexpr TypeDefinition Create(uint8_t Bytes, uint8_t Elements) { - TypeDefinition Type{}; + [[nodiscard]] + static constexpr TypeDefinition Create(uint8_t Bytes, uint8_t Elements) { + TypeDefinition Type {}; Type.Val = (Bytes << 8) | (Elements & 255); return Type; } - [[nodiscard]] constexpr uint8_t Bytes() const { + [[nodiscard]] + constexpr uint8_t Bytes() const { return Val >> 8; } - [[nodiscard]] constexpr uint8_t Elements() const { + [[nodiscard]] + constexpr uint8_t Elements() const { return Val & 255; } - [[nodiscard]] friend constexpr bool operator==(const TypeDefinition&, const TypeDefinition&) = default; + [[nodiscard]] + friend constexpr bool + operator==(const TypeDefinition&, const TypeDefinition&) = default; }; static_assert(std::is_trivial_v); @@ -387,7 +437,9 @@ struct FenceType final { [[nodiscard]] constexpr operator value_type() const { return Val; } - [[nodiscard]] friend constexpr bool operator==(const FenceType&, const FenceType&) = default; + [[nodiscard]] + friend constexpr bool + operator==(const FenceType&, const FenceType&) = default; }; struct RoundType final { @@ -395,7 +447,9 @@ struct RoundType final { [[nodiscard]] constexpr operator uint8_t() const { return Val; } - [[nodiscard]] friend constexpr bool operator==(const RoundType&, const RoundType&) = default; + [[nodiscard]] + friend constexpr bool + operator==(const RoundType&, const RoundType&) = default; }; class NodeIterator; @@ -406,64 +460,79 @@ class NodeIterator; */ class NodeIterator { public: - using value_type = std::tuple; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = NodeIterator; - using const_iterator = const NodeIterator; - using reverse_iterator = iterator; - using const_reverse_iterator = const_iterator; - using iterator_category = std::bidirectional_iterator_tag; + using value_type = std::tuple; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = NodeIterator; + using const_iterator = const NodeIterator; + using reverse_iterator = iterator; + using const_reverse_iterator = const_iterator; + using iterator_category = std::bidirectional_iterator_tag; - NodeIterator(uintptr_t Base, uintptr_t IRBase) : BaseList {Base}, IRList{ IRBase } {} - explicit NodeIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) : BaseList {Base}, IRList{ IRBase }, Node {Ptr} {} + NodeIterator(uintptr_t Base, uintptr_t IRBase) + : BaseList {Base} + , IRList {IRBase} {} + explicit NodeIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) + : BaseList {Base} + , IRList {IRBase} + , Node {Ptr} {} - [[nodiscard]] bool operator==(const NodeIterator &rhs) const { + [[nodiscard]] + bool + operator==(const NodeIterator& rhs) const { return Node.NodeOffset == rhs.Node.NodeOffset; } - [[nodiscard]] bool operator!=(const NodeIterator &rhs) const { + [[nodiscard]] + bool + operator!=(const NodeIterator& rhs) const { return !operator==(rhs); } NodeIterator operator++() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + OrderedNodeHeader* RealNode = reinterpret_cast(Node.GetNode(BaseList)); Node = RealNode->Next; return *this; } NodeIterator operator--() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + OrderedNodeHeader* RealNode = reinterpret_cast(Node.GetNode(BaseList)); Node = RealNode->Previous; return *this; } - [[nodiscard]] value_type operator*() { - OrderedNode *RealNode = Node.GetNode(BaseList); - return { RealNode, RealNode->Op(IRList) }; + [[nodiscard]] + value_type + operator*() { + OrderedNode* RealNode = Node.GetNode(BaseList); + return {RealNode, RealNode->Op(IRList)}; } - [[nodiscard]] value_type operator()() { - OrderedNode *RealNode = Node.GetNode(BaseList); - return { RealNode, RealNode->Op(IRList) }; + [[nodiscard]] + value_type + operator()() { + OrderedNode* RealNode = Node.GetNode(BaseList); + return {RealNode, RealNode->Op(IRList)}; } - [[nodiscard]] NodeID ID() const { + [[nodiscard]] + NodeID ID() const { return Node.ID(); } - [[nodiscard]] static NodeIterator Invalid() { + [[nodiscard]] + static NodeIterator Invalid() { return NodeIterator(0, 0); } protected: - uintptr_t BaseList{}; - uintptr_t IRList{}; - OrderedNodeWrapper Node{}; + uintptr_t BaseList {}; + uintptr_t IRList {}; + OrderedNodeWrapper Node {}; }; // This must directly match bytes to the named opsize. @@ -498,13 +567,13 @@ enum class ShiftType : uint8_t { // This is a nop operation and will be eliminated by the compiler. static inline OpSize SizeToOpSize(uint8_t Size) { switch (Size) { - case 1: return OpSize::i8Bit; - case 2: return OpSize::i16Bit; - case 4: return OpSize::i32Bit; - case 8: return OpSize::i64Bit; - case 16: return OpSize::i128Bit; - case 32: return OpSize::i256Bit; - default: FEX_UNREACHABLE; + case 1: return OpSize::i8Bit; + case 2: return OpSize::i16Bit; + case 4: return OpSize::i32Bit; + case 8: return OpSize::i64Bit; + case 16: return OpSize::i128Bit; + case 32: return OpSize::i256Bit; + default: FEX_UNREACHABLE; } } @@ -522,12 +591,15 @@ static inline OpSize SizeToOpSize(uint8_t Size) { */ class AllNodesIterator : public NodeIterator { public: - AllNodesIterator(uintptr_t Base, uintptr_t IRBase) : NodeIterator(Base, IRBase) {} - explicit AllNodesIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) : NodeIterator(Base, IRBase, Ptr) {} - AllNodesIterator(NodeIterator other) : NodeIterator(other) {} // Allow NodeIterator to be upgraded + AllNodesIterator(uintptr_t Base, uintptr_t IRBase) + : NodeIterator(Base, IRBase) {} + explicit AllNodesIterator(uintptr_t Base, uintptr_t IRBase, OrderedNodeWrapper Ptr) + : NodeIterator(Base, IRBase, Ptr) {} + AllNodesIterator(NodeIterator other) + : NodeIterator(other) {} // Allow NodeIterator to be upgraded AllNodesIterator operator++() { - OrderedNodeHeader *RealNode = reinterpret_cast(Node.GetNode(BaseList)); + OrderedNodeHeader* RealNode = reinterpret_cast(Node.GetNode(BaseList)); auto IROp = Node.GetNode(BaseList)->Op(IRList); // If this is the last node of a codeblock, we need to continue to the next block @@ -566,7 +638,8 @@ public: return *this; } - [[nodiscard]] static AllNodesIterator Invalid() { + [[nodiscard]] + static AllNodesIterator Invalid() { return AllNodesIterator(0, 0); } }; @@ -582,54 +655,54 @@ inline NodeID NodeWrapperBase::ID() const { bool IsFragmentExit(FEXCore::IR::IROps Op); bool IsBlockExit(FEXCore::IR::IROps Op); -void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData); -fextl::unique_ptr Parse(FEXCore::Utils::IntrusivePooledAllocator &ThreadAllocator, fextl::stringstream &MapsStream); -} +void Dump(fextl::stringstream* out, const IRListView* IR, IR::RegisterAllocationData* RAData); +fextl::unique_ptr Parse(FEXCore::Utils::IntrusivePooledAllocator& ThreadAllocator, fextl::stringstream& MapsStream); +} // namespace FEXCore::IR -template <> +template<> struct std::hash { size_t operator()(const FEXCore::IR::NodeID& ID) const noexcept { - return std::hash{}(ID.Value); + return std::hash {}(ID.Value); } }; -template <> +template<> struct fmt::formatter : fmt::formatter { using Base = fmt::formatter; // Pass-through the underlying value, so IDs can // be formatted like any integral value. - template + template auto format(const FEXCore::IR::NodeID& ID, FormatContext& ctx) const { return Base::format(ID.Value, ctx); } }; -template <> +template<> struct fmt::formatter : fmt::formatter { using Base = fmt::formatter; - template + template auto format(const FEXCore::IR::RegisterClassType& Class, FormatContext& ctx) const { return Base::format(Class.Val, ctx); } }; -template <> +template<> struct fmt::formatter : fmt::formatter { using Base = fmt::formatter; - template + template auto format(const FEXCore::IR::FenceType& Fence, FormatContext& ctx) const { return Base::format(Fence.Val, ctx); } }; -template <> +template<> struct fmt::formatter : fmt::formatter> { using Base = fmt::formatter>; - template + template auto format(const FEXCore::IR::OpSize& OpSize, FormatContext& ctx) const { return Base::format(FEXCore::ToUnderlying(OpSize), ctx); } diff --git a/FEXCore/Source/Interface/IR/IRDumper.cpp b/FEXCore/Source/Interface/IR/IRDumper.cpp index 3c6d3c538..37a773879 100644 --- a/FEXCore/Source/Interface/IR/IRDumper.cpp +++ b/FEXCore/Source/Interface/IR/IRDumper.cpp @@ -17,7 +17,7 @@ $end_info$ #include #include #include -#include +#include namespace FEXCore::IR { #define IROP_GETNAME_IMPL @@ -29,56 +29,36 @@ namespace FEXCore::IR { #include -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, const SHA256Sum &Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, const SHA256Sum& Arg) { *out << "sha256:"; - for(auto byte: Arg.data) + for (auto byte : Arg.data) { *out << std::hex << std::setfill('0') << std::setw(2) << (unsigned int)byte; + } } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, uint64_t Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, uint64_t Arg) { *out << "#0x" << std::hex << Arg; } [[maybe_unused]] -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, const char* Arg) { - *out << Arg; +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, const char* Arg) { + *out << Arg; } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, CondClassType Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, CondClassType Arg) { if (Arg == COND_AL) { *out << "ALWAYS"; return; } - static constexpr std::array CondNames = { - "EQ", - "NEQ", - "UGE", - "ULT", - "MI", - "PL", - "VS", - "VC", - "UGT", - "ULE", - "SGE", - "SLT", - "SGT", - "SLE", - "ANDZ", - "ANDNZ", - "FLU", - "FGE", - "FLEU", - "FGT", - "FU", - "FNU" - }; + static constexpr std::array CondNames = {"EQ", "NEQ", "UGE", "ULT", "MI", "PL", "VS", "VC", + "UGT", "ULE", "SGE", "SLT", "SGT", "SLE", "ANDZ", "ANDNZ", + "FLU", "FGE", "FLEU", "FGT", "FU", "FNU"}; *out << CondNames[Arg]; } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, MemOffsetType Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, MemOffsetType Arg) { static constexpr std::array Names = { "SXTX", "UXTW", @@ -88,22 +68,23 @@ static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const *out << Names[Arg]; } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, RegisterClassType Arg) { - if (Arg == GPRClass.Val) +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, RegisterClassType Arg) { + if (Arg == GPRClass.Val) { *out << "GPR"; - else if (Arg == GPRFixedClass.Val) + } else if (Arg == GPRFixedClass.Val) { *out << "GPRFixed"; - else if (Arg == FPRClass.Val) + } else if (Arg == FPRClass.Val) { *out << "FPR"; - else if (Arg == FPRFixedClass.Val) + } else if (Arg == FPRFixedClass.Val) { *out << "FPRFixed"; - else if (Arg == GPRPairClass.Val) + } else if (Arg == GPRPairClass.Val) { *out << "GPRPair"; - else + } else { *out << "Unknown Registerclass " << Arg; + } } -static void PrintArg(fextl::stringstream *out, IRListView const* IR, OrderedNodeWrapper Arg, IR::RegisterAllocationData *RAData) { +static void PrintArg(fextl::stringstream* out, const IRListView* IR, OrderedNodeWrapper Arg, IR::RegisterAllocationData* RAData) { auto [CodeNode, IROp] = IR->at(Arg)(); const auto ArgID = Arg.ID(); @@ -115,14 +96,14 @@ static void PrintArg(fextl::stringstream *out, IRListView const* IR, OrderedNode auto PhyReg = RAData->GetNodeRegister(ArgID); switch (PhyReg.Class) { - case FEXCore::IR::GPRClass.Val: *out << "(GPR"; break; - case FEXCore::IR::GPRFixedClass.Val: *out << "(GPRFixed"; break; - case FEXCore::IR::FPRClass.Val: *out << "(FPR"; break; - case FEXCore::IR::FPRFixedClass.Val: *out << "(FPRFixed"; break; - case FEXCore::IR::GPRPairClass.Val: *out << "(GPRPair"; break; - case FEXCore::IR::ComplexClass.Val: *out << "(Complex"; break; - case FEXCore::IR::InvalidClass.Val: *out << "(Invalid"; break; - default: *out << "(Unknown"; break; + case FEXCore::IR::GPRClass.Val: *out << "(GPR"; break; + case FEXCore::IR::GPRFixedClass.Val: *out << "(GPRFixed"; break; + case FEXCore::IR::FPRClass.Val: *out << "(FPR"; break; + case FEXCore::IR::FPRFixedClass.Val: *out << "(FPRFixed"; break; + case FEXCore::IR::GPRPairClass.Val: *out << "(GPRPair"; break; + case FEXCore::IR::ComplexClass.Val: *out << "(Complex"; break; + case FEXCore::IR::InvalidClass.Val: *out << "(Invalid"; break; + default: *out << "(Unknown"; break; } if (PhyReg.Class != FEXCore::IR::InvalidClass.Val) { @@ -149,48 +130,44 @@ static void PrintArg(fextl::stringstream *out, IRListView const* IR, OrderedNode if (NumElements > 1) { *out << "v" << std::dec << NumElements; } - } } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::FenceType Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::FenceType Arg) { if (Arg == IR::Fence_Load) { *out << "Loads"; - } - else if (Arg == IR::Fence_Store) { + } else if (Arg == IR::Fence_Store) { *out << "Stores"; - } - else if (Arg == IR::Fence_LoadStore) { + } else if (Arg == IR::Fence_LoadStore) { *out << "LoadStores"; - } - else { + } else { *out << ""; } } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::RoundType Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::RoundType Arg) { switch (Arg) { - case FEXCore::IR::Round_Nearest: *out << "Nearest"; break; - case FEXCore::IR::Round_Negative_Infinity: *out << "-Inf"; break; - case FEXCore::IR::Round_Positive_Infinity: *out << "+Inf"; break; - case FEXCore::IR::Round_Towards_Zero: *out << "Towards Zero"; break; - case FEXCore::IR::Round_Host: *out << "Host"; break; - default: *out << ""; break; + case FEXCore::IR::Round_Nearest: *out << "Nearest"; break; + case FEXCore::IR::Round_Negative_Infinity: *out << "-Inf"; break; + case FEXCore::IR::Round_Positive_Infinity: *out << "+Inf"; break; + case FEXCore::IR::Round_Towards_Zero: *out << "Towards Zero"; break; + case FEXCore::IR::Round_Host: *out << "Host"; break; + default: *out << ""; break; } } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::SyscallFlags Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::SyscallFlags Arg) { switch (Arg) { - case FEXCore::IR::SyscallFlags::DEFAULT: *out << "Default"; break; - case FEXCore::IR::SyscallFlags::OPTIMIZETHROUGH: *out << "Optimize Through"; break; - case FEXCore::IR::SyscallFlags::NOSYNCSTATEONENTRY: *out << "No Sync State on Entry"; break; - case FEXCore::IR::SyscallFlags::NORETURN: *out << "No Return"; break; - case FEXCore::IR::SyscallFlags::NOSIDEEFFECTS: *out << "No Side Effects"; break; - default: *out << ""; break; + case FEXCore::IR::SyscallFlags::DEFAULT: *out << "Default"; break; + case FEXCore::IR::SyscallFlags::OPTIMIZETHROUGH: *out << "Optimize Through"; break; + case FEXCore::IR::SyscallFlags::NOSYNCSTATEONENTRY: *out << "No Sync State on Entry"; break; + case FEXCore::IR::SyscallFlags::NORETURN: *out << "No Return"; break; + case FEXCore::IR::SyscallFlags::NOSIDEEFFECTS: *out << "No Side Effects"; break; + default: *out << ""; break; } } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::NamedVectorConstant Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::NamedVectorConstant Arg) { *out << [Arg] { // clang-format off switch (Arg) { @@ -231,48 +208,48 @@ static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const }(); } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::OpSize Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::OpSize Arg) { switch (Arg) { - case OpSize::i8Bit: *out << "i8"; break; - case OpSize::i16Bit: *out << "i16"; break; - case OpSize::i32Bit: *out << "i32"; break; - case OpSize::i64Bit: *out << "i64"; break; - case OpSize::i128Bit: *out << "i128"; break; - case OpSize::i256Bit: *out << "i256"; break; - default: *out << ""; break; + case OpSize::i8Bit: *out << "i8"; break; + case OpSize::i16Bit: *out << "i16"; break; + case OpSize::i32Bit: *out << "i32"; break; + case OpSize::i64Bit: *out << "i64"; break; + case OpSize::i128Bit: *out << "i128"; break; + case OpSize::i256Bit: *out << "i256"; break; + default: *out << ""; break; } } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::FloatCompareOp Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::FloatCompareOp Arg) { switch (Arg) { - case FloatCompareOp::EQ: *out << "FEQ"; break; - case FloatCompareOp::LT: *out << "FLT"; break; - case FloatCompareOp::LE: *out << "FLE"; break; - case FloatCompareOp::UNO: *out << "UNO"; break; - case FloatCompareOp::NEQ: *out << "NEQ"; break; - case FloatCompareOp::ORD: *out << "ORD"; break; - default: *out << ""; break; + case FloatCompareOp::EQ: *out << "FEQ"; break; + case FloatCompareOp::LT: *out << "FLT"; break; + case FloatCompareOp::LE: *out << "FLE"; break; + case FloatCompareOp::UNO: *out << "UNO"; break; + case FloatCompareOp::NEQ: *out << "NEQ"; break; + case FloatCompareOp::ORD: *out << "ORD"; break; + default: *out << ""; break; } } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::BreakDefinition Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::BreakDefinition Arg) { *out << "{" << Arg.ErrorRegister << "."; *out << static_cast(Arg.Signal) << "."; *out << static_cast(Arg.TrapNumber) << "."; *out << static_cast(Arg.si_code) << "}"; } -static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::ShiftType Arg) { +static void PrintArg(fextl::stringstream* out, [[maybe_unused]] const IRListView* IR, FEXCore::IR::ShiftType Arg) { switch (Arg) { - case ShiftType::LSL: *out << "LSL"; break; - case ShiftType::LSR: *out << "LSR"; break; - case ShiftType::ASR: *out << "ASR"; break; - case ShiftType::ROR: *out << "ROR"; break; - default: *out << ""; break; + case ShiftType::LSL: *out << "LSL"; break; + case ShiftType::LSR: *out << "LSR"; break; + case ShiftType::ASR: *out << "ASR"; break; + case ShiftType::ROR: *out << "ROR"; break; + default: *out << ""; break; } } -void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData) { +void Dump(fextl::stringstream* out, const IRListView* IR, IR::RegisterAllocationData* RAData) { auto HeaderOp = IR->GetHeader(); int8_t CurrentIndent = 0; @@ -284,7 +261,8 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation ++CurrentIndent; AddIndent(); - *out << "(%0) " << "IRHeader "; + *out << "(%0) " + << "IRHeader "; *out << "%" << HeaderOp->Blocks.ID() << ", "; *out << "#" << std::dec << HeaderOp->OriginalRIP << ", "; *out << "#" << std::dec << HeaderOp->BlockCount << ", "; @@ -295,7 +273,8 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation auto BlockIROp = BlockHeader->C(); AddIndent(); - *out << "(%" << IR->GetID(BlockNode) << ") " << "CodeBlock "; + *out << "(%" << IR->GetID(BlockNode) << ") " + << "CodeBlock "; *out << "%" << BlockIROp->Begin.ID() << ", "; *out << "%" << BlockIROp->Last.ID() << std::endl; @@ -325,14 +304,14 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation if (RAData) { auto PhyReg = RAData->GetNodeRegister(ID); switch (PhyReg.Class) { - case FEXCore::IR::GPRClass.Val: *out << "(GPR"; break; - case FEXCore::IR::GPRFixedClass.Val: *out << "(GPRFixed"; break; - case FEXCore::IR::FPRClass.Val: *out << "(FPR"; break; - case FEXCore::IR::FPRFixedClass.Val: *out << "(FPRFixed"; break; - case FEXCore::IR::GPRPairClass.Val: *out << "(GPRPair"; break; - case FEXCore::IR::ComplexClass.Val: *out << "(Complex"; break; - case FEXCore::IR::InvalidClass.Val: *out << "(Invalid"; break; - default: *out << "(Unknown"; break; + case FEXCore::IR::GPRClass.Val: *out << "(GPR"; break; + case FEXCore::IR::GPRFixedClass.Val: *out << "(GPRFixed"; break; + case FEXCore::IR::FPRClass.Val: *out << "(FPR"; break; + case FEXCore::IR::FPRFixedClass.Val: *out << "(FPRFixed"; break; + case FEXCore::IR::GPRPairClass.Val: *out << "(GPRPair"; break; + case FEXCore::IR::ComplexClass.Val: *out << "(Complex"; break; + case FEXCore::IR::InvalidClass.Val: *out << "(Invalid"; break; + default: *out << "(Unknown"; break; } if (PhyReg.Class != FEXCore::IR::InvalidClass.Val) { *out << std::dec << (uint32_t)PhyReg.Reg << ")"; @@ -348,8 +327,7 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation } *out << " = "; - } - else { + } else { uint32_t ElementSize = IROp->ElementSize; if (!IROp->ElementSize) { @@ -369,19 +347,18 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation } *out << Name; - #define IROP_ARGPRINTER_HELPER - #include - default: *out << ""; break; - } - - //*out << " (" << std::dec << CodeNode->GetUses() << ")"; - - *out << "\n"; +#define IROP_ARGPRINTER_HELPER +#include + default: *out << ""; break; } + + //*out << " (" << std::dec << CodeNode->GetUses() << ")"; + + *out << "\n"; } - - CurrentIndent = std::max(0, CurrentIndent - 1); } -} + CurrentIndent = std::max(0, CurrentIndent - 1); +} +} } diff --git a/FEXCore/Source/Interface/IR/IREmitter.cpp b/FEXCore/Source/Interface/IR/IREmitter.cpp index 0da4e8e41..25ae958e1 100644 --- a/FEXCore/Source/Interface/IR/IREmitter.cpp +++ b/FEXCore/Source/Interface/IR/IREmitter.cpp @@ -20,77 +20,69 @@ namespace FEXCore::IR { bool IsFragmentExit(FEXCore::IR::IROps Op) { switch (Op) { - case OP_EXITFUNCTION: - case OP_BREAK: - return true; - default: - return false; + case OP_EXITFUNCTION: + case OP_BREAK: return true; + default: return false; } } bool IsBlockExit(FEXCore::IR::IROps Op) { - switch(Op) { - case OP_JUMP: - case OP_CONDJUMP: - return true; - default: - return IsFragmentExit(Op); + switch (Op) { + case OP_JUMP: + case OP_CONDJUMP: return true; + default: return IsFragmentExit(Op); } } -FEXCore::IR::RegisterClassType IREmitter::WalkFindRegClass(OrderedNode *Node) { +FEXCore::IR::RegisterClassType IREmitter::WalkFindRegClass(OrderedNode* Node) { auto Class = GetOpRegClass(Node); switch (Class) { - case GPRClass: - case GPRPairClass: - case FPRClass: - case GPRFixedClass: - case FPRFixedClass: - case InvalidClass: - return Class; - default: break; + case GPRClass: + case GPRPairClass: + case FPRClass: + case GPRFixedClass: + case FPRFixedClass: + case InvalidClass: return Class; + default: break; } // Complex case, needs to be handled on an op by op basis uintptr_t DataBegin = DualListData.DataBegin(); - FEXCore::IR::IROp_Header *IROp = Node->Op(DataBegin); + FEXCore::IR::IROp_Header* IROp = Node->Op(DataBegin); switch (IROp->Op) { - case IROps::OP_LOADREGISTER: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IROps::OP_LOADCONTEXT: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IROps::OP_LOADCONTEXTINDEXED: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IROps::OP_FILLREGISTER: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IROps::OP_LOADMEM: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IROps::OP_LOADMEMTSO: { - auto Op = IROp->C(); - return Op->Class; - break; - } - default: - LOGMAN_MSG_A_FMT("Unhandled op type: {} {} in argument class validation", - ToUnderlying(IROp->Op), GetOpName(Node)); - break; + case IROps::OP_LOADREGISTER: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IROps::OP_LOADCONTEXT: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IROps::OP_LOADCONTEXTINDEXED: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IROps::OP_FILLREGISTER: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IROps::OP_LOADMEM: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IROps::OP_LOADMEMTSO: { + auto Op = IROp->C(); + return Op->Class; + break; + } + default: LOGMAN_MSG_A_FMT("Unhandled op type: {} {} in argument class validation", ToUnderlying(IROp->Op), GetOpName(Node)); break; } return InvalidClass; } @@ -105,7 +97,7 @@ void IREmitter::ResetWorkingList() { CurrentCodeBlock = nullptr; } -void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator Begin, AllNodesIterator End) { +void IREmitter::ReplaceAllUsesWithRange(OrderedNode* Node, OrderedNode* NewNode, AllNodesIterator Begin, AllNodesIterator End) { uintptr_t ListBegin = DualListData.ListBegin(); auto NodeId = Node->Wrapped(ListBegin).ID(); @@ -130,23 +122,23 @@ void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, } } -void IREmitter::ReplaceNodeArgument(OrderedNode *Node, uint8_t Arg, OrderedNode *NewArg) { +void IREmitter::ReplaceNodeArgument(OrderedNode* Node, uint8_t Arg, OrderedNode* NewArg) { uintptr_t ListBegin = DualListData.ListBegin(); uintptr_t DataBegin = DualListData.DataBegin(); - FEXCore::IR::IROp_Header *IROp = Node->Op(DataBegin); + FEXCore::IR::IROp_Header* IROp = Node->Op(DataBegin); OrderedNodeWrapper OldArgWrapper = IROp->Args[Arg]; - OrderedNode *OldArg = OldArgWrapper.GetNode(ListBegin); + OrderedNode* OldArg = OldArgWrapper.GetNode(ListBegin); OldArg->RemoveUse(); NewArg->AddUse(); IROp->Args[Arg].NodeOffset = NewArg->Wrapped(ListBegin).NodeOffset; } -void IREmitter::RemoveArgUses(OrderedNode *Node) { +void IREmitter::RemoveArgUses(OrderedNode* Node) { uintptr_t ListBegin = DualListData.ListBegin(); uintptr_t DataBegin = DualListData.DataBegin(); - FEXCore::IR::IROp_Header *IROp = Node->Op(DataBegin); + FEXCore::IR::IROp_Header* IROp = Node->Op(DataBegin); const uint8_t NumArgs = IR::GetArgs(IROp->Op); for (uint8_t i = 0; i < NumArgs; ++i) { @@ -155,7 +147,7 @@ void IREmitter::RemoveArgUses(OrderedNode *Node) { } } -void IREmitter::Remove(OrderedNode *Node) { +void IREmitter::Remove(OrderedNode* Node) { RemoveArgUses(Node); Node->Unlink(DualListData.ListBegin()); @@ -174,8 +166,9 @@ IREmitter::IRPair IREmitter::CreateNewCodeBlockAfter(OrderedNode // Find last block auto LastBlock = CurrentCodeBlock; - while (LastBlock->Header.Next.GetNode(DualListData.ListBegin()) != InvalidNode) + while (LastBlock->Header.Next.GetNode(DualListData.ListBegin()) != InvalidNode) { LastBlock = LastBlock->Header.Next.GetNode(DualListData.ListBegin()); + } // Append it after the last block LinkCodeBlocks(LastBlock, CodeNode); @@ -186,34 +179,34 @@ IREmitter::IRPair IREmitter::CreateNewCodeBlockAfter(OrderedNode return CodeNode; } -void IREmitter::SetCurrentCodeBlock(OrderedNode *Node) { +void IREmitter::SetCurrentCodeBlock(OrderedNode* Node) { CurrentCodeBlock = Node; - LOGMAN_THROW_A_FMT(Node->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Node wasn't codeblock. It was '{}'", IR::GetName(Node->Op(DualListData.DataBegin())->Op)); + LOGMAN_THROW_A_FMT(Node->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Node wasn't codeblock. It was '{}'", + IR::GetName(Node->Op(DualListData.DataBegin())->Op)); SetWriteCursor(Node->Op(DualListData.DataBegin())->CW()->Begin.GetNode(DualListData.ListBegin())); } -void IREmitter::ReplaceWithConstant(OrderedNode *Node, uint64_t Value) { - auto Header = Node->Op(DualListData.DataBegin()); +void IREmitter::ReplaceWithConstant(OrderedNode* Node, uint64_t Value) { + auto Header = Node->Op(DualListData.DataBegin()); - if (IRSizes[Header->Op] >= sizeof(IROp_Constant)) { - // Unlink any arguments the node currently has - RemoveArgUses(Node); + if (IRSizes[Header->Op] >= sizeof(IROp_Constant)) { + // Unlink any arguments the node currently has + RemoveArgUses(Node); - // Overwrite data with the new constant op - Header->Op = OP_CONSTANT; - auto Const = Header->CW(); - Const->Constant = Value; - } else { - // Fallback path for when the node to overwrite is too small - auto cursor = GetWriteCursor(); - SetWriteCursor(Node); + // Overwrite data with the new constant op + Header->Op = OP_CONSTANT; + auto Const = Header->CW(); + Const->Constant = Value; + } else { + // Fallback path for when the node to overwrite is too small + auto cursor = GetWriteCursor(); + SetWriteCursor(Node); - auto NewNode = _Constant(Value); - ReplaceAllUsesWith(Node, NewNode); + auto NewNode = _Constant(Value); + ReplaceAllUsesWith(Node, NewNode); - SetWriteCursor(cursor); - } + SetWriteCursor(cursor); } - } +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/IREmitter.h b/FEXCore/Source/Interface/IR/IREmitter.h index ebb974671..d7e90f8c9 100644 --- a/FEXCore/Source/Interface/IR/IREmitter.h +++ b/FEXCore/Source/Interface/IR/IREmitter.h @@ -20,36 +20,40 @@ class Pass; class PassManager; class IREmitter { -friend class FEXCore::IR::Pass; -friend class FEXCore::IR::PassManager; + friend class FEXCore::IR::Pass; + friend class FEXCore::IR::PassManager; - public: - IREmitter(FEXCore::Utils::IntrusivePooledAllocator &ThreadAllocator) - : DualListData {ThreadAllocator, 8 * 1024 * 1024} { - ReownOrClaimBuffer(); - ResetWorkingList(); - } +public: + IREmitter(FEXCore::Utils::IntrusivePooledAllocator& ThreadAllocator) + : DualListData {ThreadAllocator, 8 * 1024 * 1024} { + ReownOrClaimBuffer(); + ResetWorkingList(); + } - virtual ~IREmitter() = default; + virtual ~IREmitter() = default; - void ReownOrClaimBuffer() { - DualListData.ReownOrClaimBuffer(); - } + void ReownOrClaimBuffer() { + DualListData.ReownOrClaimBuffer(); + } - void DelayedDisownBuffer() { - DualListData.DelayedDisownBuffer(); - } + void DelayedDisownBuffer() { + DualListData.DelayedDisownBuffer(); + } - IRListView ViewIR() { return IRListView(&DualListData, false); } - IRListView *CreateIRCopy() { return new IRListView(&DualListData, true); } - void ResetWorkingList(); + IRListView ViewIR() { + return IRListView(&DualListData, false); + } + IRListView* CreateIRCopy() { + return new IRListView(&DualListData, true); + } + void ResetWorkingList(); /** * @name IR allocation routines * * @{ */ - FEXCore::IR::RegisterClassType WalkFindRegClass(OrderedNode *Node); + FEXCore::IR::RegisterClassType WalkFindRegClass(OrderedNode* Node); // These handlers add cost to the constructor and destructor // If it becomes an issue then blow them away @@ -69,119 +73,112 @@ friend class FEXCore::IR::PassManager; IRPair _Jump() { return _Jump(InvalidNode); } - IRPair _CondJump(OrderedNode *ssa0, CondClassType cond = {COND_NEQ}) { + IRPair _CondJump(OrderedNode* ssa0, CondClassType cond = {COND_NEQ}) { return _CondJump(ssa0, _Constant(0), InvalidNode, InvalidNode, cond, GetOpSize(ssa0)); } - IRPair _CondJump(OrderedNode *ssa0, OrderedNode *ssa1, OrderedNode *ssa2, CondClassType cond = {COND_NEQ}) { + IRPair _CondJump(OrderedNode* ssa0, OrderedNode* ssa1, OrderedNode* ssa2, CondClassType cond = {COND_NEQ}) { return _CondJump(ssa0, _Constant(0), ssa1, ssa2, cond, GetOpSize(ssa0)); } // TODO: Work to remove this implicit sized Select implementation. - IRPair _Select(uint8_t Cond, OrderedNode *ssa0, OrderedNode *ssa1, OrderedNode *ssa2, OrderedNode *ssa3, uint8_t CompareSize = 0) { - if (CompareSize == 0) + IRPair _Select(uint8_t Cond, OrderedNode* ssa0, OrderedNode* ssa1, OrderedNode* ssa2, OrderedNode* ssa3, uint8_t CompareSize = 0) { + if (CompareSize == 0) { CompareSize = std::max(4, std::max(GetOpSize(ssa0), GetOpSize(ssa1))); + } - return _Select(IR::SizeToOpSize(std::max(4, std::max(GetOpSize(ssa2), GetOpSize(ssa3)))), IR::SizeToOpSize(CompareSize), CondClassType{Cond}, ssa0, ssa1, ssa2, ssa3); + return _Select(IR::SizeToOpSize(std::max(4, std::max(GetOpSize(ssa2), GetOpSize(ssa3)))), + IR::SizeToOpSize(CompareSize), CondClassType {Cond}, ssa0, ssa1, ssa2, ssa3); } - IRPair _LoadMem(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode *ssa0, uint8_t Align = 1) { + IRPair _LoadMem(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode* ssa0, uint8_t Align = 1) { return _LoadMem(Class, Size, ssa0, Invalid(), Align, MEM_OFFSET_SXTX, 1); } - IRPair _LoadMemTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode *ssa0, uint8_t Align = 1) { + IRPair _LoadMemTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode* ssa0, uint8_t Align = 1) { return _LoadMemTSO(Class, Size, ssa0, Invalid(), Align, MEM_OFFSET_SXTX, 1); } - IRPair _StoreMem(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode *Addr, OrderedNode *Value, uint8_t Align = 1) { + IRPair _StoreMem(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode* Addr, OrderedNode* Value, uint8_t Align = 1) { return _StoreMem(Class, Size, Value, Addr, Invalid(), Align, MEM_OFFSET_SXTX, 1); } - IRPair _StoreMemTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode *Addr, OrderedNode *Value, uint8_t Align = 1) { + IRPair + _StoreMemTSO(FEXCore::IR::RegisterClassType Class, uint8_t Size, OrderedNode* Addr, OrderedNode* Value, uint8_t Align = 1) { return _StoreMemTSO(Class, Size, Value, Addr, Invalid(), Align, MEM_OFFSET_SXTX, 1); } - OrderedNode *Invalid() { + OrderedNode* Invalid() { return InvalidNode; } - void SetJumpTarget(IR::IROp_Jump *Op, OrderedNode *Target) { - LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, - "Tried setting Jump target to %{} {}", - Target->Wrapped(DualListData.ListBegin()).ID(), - IR::GetName(Target->Op(DualListData.DataBegin())->Op)); + void SetJumpTarget(IR::IROp_Jump* Op, OrderedNode* Target) { + LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Tried setting Jump target to %{} {}", + Target->Wrapped(DualListData.ListBegin()).ID(), IR::GetName(Target->Op(DualListData.DataBegin())->Op)); Op->Header.Args[0].NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset; } - void SetTrueJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) { - LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, - "Tried setting CondJump target to %{} {}", - Target->Wrapped(DualListData.ListBegin()).ID(), - IR::GetName(Target->Op(DualListData.DataBegin())->Op)); + void SetTrueJumpTarget(IR::IROp_CondJump* Op, OrderedNode* Target) { + LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Tried setting CondJump target to %{} {}", + Target->Wrapped(DualListData.ListBegin()).ID(), IR::GetName(Target->Op(DualListData.DataBegin())->Op)); Op->TrueBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset; } - void SetFalseJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) { - LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, - "Tried setting CondJump target to %{} {}", - Target->Wrapped(DualListData.ListBegin()).ID(), - IR::GetName(Target->Op(DualListData.DataBegin())->Op)); + void SetFalseJumpTarget(IR::IROp_CondJump* Op, OrderedNode* Target) { + LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Tried setting CondJump target to %{} {}", + Target->Wrapped(DualListData.ListBegin()).ID(), IR::GetName(Target->Op(DualListData.DataBegin())->Op)); Op->FalseBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset; } - void SetJumpTarget(IRPair Op, OrderedNode *Target) { - LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, - "Tried setting Jump target to %{} {}", - Target->Wrapped(DualListData.ListBegin()).ID(), - IR::GetName(Target->Op(DualListData.DataBegin())->Op)); + void SetJumpTarget(IRPair Op, OrderedNode* Target) { + LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Tried setting Jump target to %{} {}", + Target->Wrapped(DualListData.ListBegin()).ID(), IR::GetName(Target->Op(DualListData.DataBegin())->Op)); Op.first->Header.Args[0].NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset; } - void SetTrueJumpTarget(IRPair Op, OrderedNode *Target) { - LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, - "Tried setting CondJump target to %{} {}", - Target->Wrapped(DualListData.ListBegin()).ID(), - IR::GetName(Target->Op(DualListData.DataBegin())->Op)); + void SetTrueJumpTarget(IRPair Op, OrderedNode* Target) { + LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Tried setting CondJump target to %{} {}", + Target->Wrapped(DualListData.ListBegin()).ID(), IR::GetName(Target->Op(DualListData.DataBegin())->Op)); Op.first->TrueBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset; } - void SetFalseJumpTarget(IRPair Op, OrderedNode *Target) { - LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, - "Tried setting CondJump target to %{} {}", - Target->Wrapped(DualListData.ListBegin()).ID(), - IR::GetName(Target->Op(DualListData.DataBegin())->Op)); + void SetFalseJumpTarget(IRPair Op, OrderedNode* Target) { + LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Tried setting CondJump target to %{} {}", + Target->Wrapped(DualListData.ListBegin()).ID(), IR::GetName(Target->Op(DualListData.DataBegin())->Op)); Op.first->FalseBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset; } /** @} */ FEXCore::IR::RegisterClassType WalkFindRegClass(OrderedNodeWrapper ssa) { - OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin()); - return WalkFindRegClass(RealNode); + OrderedNode* RealNode = ssa.GetNode(DualListData.ListBegin()); + return WalkFindRegClass(RealNode); } - bool IsValueConstant(OrderedNodeWrapper ssa, uint64_t *Constant = nullptr) { - OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin()); - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin()); - if (IROp->Op == OP_CONSTANT) { - auto Op = IROp->C(); - if (Constant) *Constant = Op->Constant; - return true; - } - return false; + bool IsValueConstant(OrderedNodeWrapper ssa, uint64_t* Constant = nullptr) { + OrderedNode* RealNode = ssa.GetNode(DualListData.ListBegin()); + FEXCore::IR::IROp_Header* IROp = RealNode->Op(DualListData.DataBegin()); + if (IROp->Op == OP_CONSTANT) { + auto Op = IROp->C(); + if (Constant) { + *Constant = Op->Constant; + } + return true; + } + return false; } bool IsValueInlineConstant(OrderedNodeWrapper ssa) { - OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin()); - FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin()); - if (IROp->Op == OP_INLINECONSTANT) { - return true; - } - return false; + OrderedNode* RealNode = ssa.GetNode(DualListData.ListBegin()); + FEXCore::IR::IROp_Header* IROp = RealNode->Op(DualListData.DataBegin()); + if (IROp->Op == OP_INLINECONSTANT) { + return true; + } + return false; } - FEXCore::IR::IROp_Header *GetOpHeader(OrderedNodeWrapper ssa) { - OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin()); + FEXCore::IR::IROp_Header* GetOpHeader(OrderedNodeWrapper ssa) { + OrderedNode* RealNode = ssa.GetNode(DualListData.ListBegin()); return RealNode->Op(DualListData.DataBegin()); } - OrderedNode *UnwrapNode(OrderedNodeWrapper ssa) { + OrderedNode* UnwrapNode(OrderedNodeWrapper ssa) { return ssa.GetNode(DualListData.ListBegin()); } - OrderedNodeWrapper WrapNode(OrderedNode *node) { + OrderedNodeWrapper WrapNode(OrderedNode* node) { return node->Wrapped(DualListData.ListBegin()); } @@ -192,23 +189,23 @@ friend class FEXCore::IR::PassManager; // Overwrite a node with a constant // Depending on what node has been overwritten, there might be some unallocated space around the node // Because we are overwriting the node, we don't have to worry about update all the arguments which use it - void ReplaceWithConstant(OrderedNode *Node, uint64_t Value); + void ReplaceWithConstant(OrderedNode* Node, uint64_t Value); - void ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator Begin, AllNodesIterator End); + void ReplaceAllUsesWithRange(OrderedNode* Node, OrderedNode* NewNode, AllNodesIterator Begin, AllNodesIterator End); - void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After) { + void ReplaceUsesWithAfter(OrderedNode* Node, OrderedNode* NewNode, AllNodesIterator After) { ++After; ReplaceAllUsesWithRange(Node, NewNode, After, AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin())); } - void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, OrderedNode *After) { + void ReplaceUsesWithAfter(OrderedNode* Node, OrderedNode* NewNode, OrderedNode* After) { auto Wrapped = After->Wrapped(DualListData.ListBegin()); AllNodesIterator It = AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin(), Wrapped); ReplaceUsesWithAfter(Node, NewNode, It); } - void ReplaceAllUsesWith(OrderedNode *Node, OrderedNode *NewNode) { + void ReplaceAllUsesWith(OrderedNode* Node, OrderedNode* NewNode) { auto Start = AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin(), Node->Wrapped(DualListData.ListBegin())); ReplaceAllUsesWithRange(Node, NewNode, Start, AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin())); @@ -223,34 +220,36 @@ friend class FEXCore::IR::PassManager; } } - void ReplaceNodeArgument(OrderedNode *Node, uint8_t Arg, OrderedNode *NewArg); + void ReplaceNodeArgument(OrderedNode* Node, uint8_t Arg, OrderedNode* NewArg); - void Remove(OrderedNode *Node); + void Remove(OrderedNode* Node); - void SetPackedRFLAG(bool Lower8, OrderedNode *Src); - OrderedNode *GetPackedRFLAG(bool Lower8); + void SetPackedRFLAG(bool Lower8, OrderedNode* Src); + OrderedNode* GetPackedRFLAG(bool Lower8); - void CopyData(IREmitter const &rhs) { - LOGMAN_THROW_A_FMT(rhs.DualListData.DataBackingSize() <= DualListData.DataBackingSize(), "Trying to take ownership of data that is too large"); - LOGMAN_THROW_A_FMT(rhs.DualListData.ListBackingSize() <= DualListData.ListBackingSize(), "Trying to take ownership of data that is too large"); + void CopyData(const IREmitter& rhs) { + LOGMAN_THROW_A_FMT(rhs.DualListData.DataBackingSize() <= DualListData.DataBackingSize(), "Trying to take ownership of data that is too " + "large"); + LOGMAN_THROW_A_FMT(rhs.DualListData.ListBackingSize() <= DualListData.ListBackingSize(), "Trying to take ownership of data that is too " + "large"); DualListData.CopyData(rhs.DualListData); InvalidNode = rhs.InvalidNode->Wrapped(rhs.DualListData.ListBegin()).GetNode(DualListData.ListBegin()); CurrentWriteCursor = rhs.CurrentWriteCursor; CodeBlocks = rhs.CodeBlocks; - for (auto& CodeBlock: CodeBlocks) { + for (auto& CodeBlock : CodeBlocks) { CodeBlock = CodeBlock->Wrapped(rhs.DualListData.ListBegin()).GetNode(DualListData.ListBegin()); } } - void SetWriteCursor(OrderedNode *Node) { + void SetWriteCursor(OrderedNode* Node) { CurrentWriteCursor = Node; } - OrderedNode *GetWriteCursor() { + OrderedNode* GetWriteCursor() { return CurrentWriteCursor; } - OrderedNode *GetCurrentBlock() { + OrderedNode* GetCurrentBlock() { return CurrentCodeBlock; } @@ -270,7 +269,7 @@ friend class FEXCore::IR::PassManager; CodeBlocks.emplace_back(CodeNode); - SetWriteCursor(nullptr);// Orphan from any future nodes + SetWriteCursor(nullptr); // Orphan from any future nodes auto Begin = _BeginBlock(CodeNode); CodeNode.first->Begin = Begin.Node->Wrapped(DualListData.ListBegin()); @@ -292,64 +291,66 @@ friend class FEXCore::IR::PassManager; * * @{ */ /** @} */ - void LinkCodeBlocks(OrderedNode *CodeNode, OrderedNode *Next) { + void LinkCodeBlocks(OrderedNode* CodeNode, OrderedNode* Next) { #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - FEXCore::IR::IROp_CodeBlock *CurrentIROp = + FEXCore::IR::IROp_CodeBlock* CurrentIROp = #endif - CodeNode->Op(DualListData.DataBegin())->CW(); + CodeNode->Op(DualListData.DataBegin())->CW(); LOGMAN_THROW_A_FMT(CurrentIROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid"); CodeNode->append(DualListData.ListBegin(), Next); } - IRPair CreateNewCodeBlockAtEnd() { return CreateNewCodeBlockAfter(nullptr); } + IRPair CreateNewCodeBlockAtEnd() { + return CreateNewCodeBlockAfter(nullptr); + } IRPair CreateNewCodeBlockAfter(OrderedNode* insertAfter); - void SetCurrentCodeBlock(OrderedNode *Node); + void SetCurrentCodeBlock(OrderedNode* Node); - protected: - void RemoveArgUses(OrderedNode *Node); +protected: + void RemoveArgUses(OrderedNode* Node); - OrderedNode *CreateNode(IROp_Header *Op) { - uintptr_t ListBegin = DualListData.ListBegin(); - size_t Size = sizeof(OrderedNode); - void *Ptr = DualListData.ListAllocate(Size); - OrderedNode *Node = new (Ptr) OrderedNode(); - Node->Header.Value.SetOffset(DualListData.DataBegin(), reinterpret_cast(Op)); + OrderedNode* CreateNode(IROp_Header* Op) { + uintptr_t ListBegin = DualListData.ListBegin(); + size_t Size = sizeof(OrderedNode); + void* Ptr = DualListData.ListAllocate(Size); + OrderedNode* Node = new (Ptr) OrderedNode(); + Node->Header.Value.SetOffset(DualListData.DataBegin(), reinterpret_cast(Op)); - if (CurrentWriteCursor) { - CurrentWriteCursor->append(ListBegin, Node); - } - CurrentWriteCursor = Node; - return Node; + if (CurrentWriteCursor) { + CurrentWriteCursor->append(ListBegin, Node); } + CurrentWriteCursor = Node; + return Node; + } - OrderedNode *GetNode(uint32_t SSANode) { - uintptr_t ListBegin = DualListData.ListBegin(); - OrderedNode *Node = reinterpret_cast(ListBegin + SSANode * sizeof(OrderedNode)); - return Node; - } + OrderedNode* GetNode(uint32_t SSANode) { + uintptr_t ListBegin = DualListData.ListBegin(); + OrderedNode* Node = reinterpret_cast(ListBegin + SSANode * sizeof(OrderedNode)); + return Node; + } - OrderedNode *EmplaceOrphanedNode(OrderedNode *OldNode) { - size_t Size = sizeof(OrderedNode); - OrderedNode *Ptr = reinterpret_cast(DualListData.ListAllocate(Size)); - memcpy(Ptr, OldNode, Size); - return Ptr; - } + OrderedNode* EmplaceOrphanedNode(OrderedNode* OldNode) { + size_t Size = sizeof(OrderedNode); + OrderedNode* Ptr = reinterpret_cast(DualListData.ListAllocate(Size)); + memcpy(Ptr, OldNode, Size); + return Ptr; + } - virtual void SaveNZCV(IROps Op) { - // Overriden by dispatcher, stubbed for IR tests - } + virtual void SaveNZCV(IROps Op) { + // Overriden by dispatcher, stubbed for IR tests + } - OrderedNode *CurrentWriteCursor = nullptr; + OrderedNode* CurrentWriteCursor = nullptr; - // These could be combined with a little bit of work to be more efficient with memory usage. Isn't a big deal - DualIntrusiveAllocatorThreadPool DualListData; + // These could be combined with a little bit of work to be more efficient with memory usage. Isn't a big deal + DualIntrusiveAllocatorThreadPool DualListData; - OrderedNode *InvalidNode; - OrderedNode *CurrentCodeBlock{}; - fextl::vector CodeBlocks; - uint64_t Entry; + OrderedNode* InvalidNode; + OrderedNode* CurrentCodeBlock {}; + fextl::vector CodeBlocks; + uint64_t Entry; }; -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/IRParser.cpp b/FEXCore/Source/Interface/IR/IRParser.cpp index 1c941de86..58d41ad3c 100644 --- a/FEXCore/Source/Interface/IR/IRParser.cpp +++ b/FEXCore/Source/Interface/IR/IRParser.cpp @@ -31,23 +31,23 @@ $end_info$ namespace FEXCore::IR { namespace { -enum class DecodeFailure { - DECODE_OKAY, - DECODE_UNKNOWN_TYPE, - DECODE_INVALID, - DECODE_INVALIDCHAR, - DECODE_INVALIDRANGE, - DECODE_INVALIDREGISTERCLASS, - DECODE_UNKNOWN_SSA, - DECODE_INVALID_CONDFLAG, - DECODE_INVALID_MEMOFFSETTYPE, - DECODE_INVALID_FENCETYPE, - DECODE_INVALID_BREAKTYPE, - DECODE_INVALID_OPSIZE, -}; + enum class DecodeFailure { + DECODE_OKAY, + DECODE_UNKNOWN_TYPE, + DECODE_INVALID, + DECODE_INVALIDCHAR, + DECODE_INVALIDRANGE, + DECODE_INVALIDREGISTERCLASS, + DECODE_UNKNOWN_SSA, + DECODE_INVALID_CONDFLAG, + DECODE_INVALID_MEMOFFSETTYPE, + DECODE_INVALID_FENCETYPE, + DECODE_INVALID_BREAKTYPE, + DECODE_INVALID_OPSIZE, + }; -fextl::string DecodeErrorToString(DecodeFailure Failure) { - switch (Failure) { + fextl::string DecodeErrorToString(DecodeFailure Failure) { + switch (Failure) { case DecodeFailure::DECODE_OKAY: return "Okay"; case DecodeFailure::DECODE_UNKNOWN_TYPE: return "Unknown Type"; case DecodeFailure::DECODE_INVALID: return "Invalid"; @@ -60,387 +60,414 @@ fextl::string DecodeErrorToString(DecodeFailure Failure) { case DecodeFailure::DECODE_INVALID_FENCETYPE: return "Invalid Fence Type"; case DecodeFailure::DECODE_INVALID_BREAKTYPE: return "Invalid Break Reason Type"; case DecodeFailure::DECODE_INVALID_OPSIZE: return "Invalid Operation size name"; + } + return "Unknown Error"; } - return "Unknown Error"; -} -class IRParser: public FEXCore::IR::IREmitter { + class IRParser : public FEXCore::IR::IREmitter { public: - template - std::pair DecodeValue(const fextl::string &Arg) { - return {DecodeFailure::DECODE_UNKNOWN_TYPE, {}}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg.at(0) != '#') return {DecodeFailure::DECODE_INVALIDCHAR, 0}; - - uint8_t Result = strtoul(&Arg.at(1), nullptr, 0); - if (errno == ERANGE) return {DecodeFailure::DECODE_INVALIDRANGE, 0}; - return {DecodeFailure::DECODE_OKAY, Result}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg.at(0) != '#') return {DecodeFailure::DECODE_INVALIDCHAR, 0}; - - uint8_t Result = strtoul(&Arg.at(1), nullptr, 0); - if (errno == ERANGE || Result > 1) return {DecodeFailure::DECODE_INVALIDRANGE, 0}; - return {DecodeFailure::DECODE_OKAY, Result != 0}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg.at(0) != '#') return {DecodeFailure::DECODE_INVALIDCHAR, 0}; - - uint16_t Result = strtoul(&Arg.at(1), nullptr, 0); - if (errno == ERANGE) return {DecodeFailure::DECODE_INVALIDRANGE, 0}; - return {DecodeFailure::DECODE_OKAY, Result}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg.at(0) != '#') return {DecodeFailure::DECODE_INVALIDCHAR, 0}; - - uint32_t Result = strtoul(&Arg.at(1), nullptr, 0); - if (errno == ERANGE) return {DecodeFailure::DECODE_INVALIDRANGE, 0}; - return {DecodeFailure::DECODE_OKAY, Result}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg.at(0) != '#') return {DecodeFailure::DECODE_INVALIDCHAR, 0}; - - uint64_t Result = strtoull(&Arg.at(1), nullptr, 0); - if (errno == ERANGE) return {DecodeFailure::DECODE_INVALIDRANGE, 0}; - return {DecodeFailure::DECODE_OKAY, Result}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg.at(0) != '#') return {DecodeFailure::DECODE_INVALIDCHAR, 0}; - - int64_t Result = (int64_t)strtoull(&Arg.at(1), nullptr, 0); - if (errno == ERANGE) return {DecodeFailure::DECODE_INVALIDRANGE, 0}; - return {DecodeFailure::DECODE_OKAY, Result}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - IR::SHA256Sum Result; - - if (Arg.at(0) != 's' || Arg.at(1) != 'h' || Arg.at(2) != 'a' || Arg.at(3) != '2' || Arg.at(4) != '5' || Arg.at(5) != '6' || Arg.at(6) != ':') - return {DecodeFailure::DECODE_INVALIDCHAR, Result}; - - auto GetDigit = [](const fextl::string &Arg, int pos, uint8_t *val) { - auto chr = Arg.at(pos); - if (chr >= '0' && chr <= '9') { - *val = chr - '0'; - return true; - } else if (chr >= 'a' && chr <= 'f') { - *val = 10 + chr - 'a'; - return true; - } else { - return false; - } - }; - - for (size_t i = 0; i < sizeof(Result.data); i++) { - uint8_t high, low; - if (!GetDigit(Arg, 7 + 2 * i + 0, &high) || !GetDigit(Arg, 7 + 2 * i + 1, &low)) { - return {DecodeFailure::DECODE_INVALIDRANGE, Result}; - } - Result.data[i] = high * 16 + low; + template + std::pair DecodeValue(const fextl::string& Arg) { + return {DecodeFailure::DECODE_UNKNOWN_TYPE, {}}; } - return {DecodeFailure::DECODE_OKAY, Result}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg == "GPR") { - return {DecodeFailure::DECODE_OKAY, FEXCore::IR::GPRClass}; - } - else if (Arg == "FPR") { - return {DecodeFailure::DECODE_OKAY, FEXCore::IR::FPRClass}; - } - else if (Arg == "GPRFixed") { - return {DecodeFailure::DECODE_OKAY, FEXCore::IR::GPRFixedClass}; - } - else if (Arg == "FPRFixed") { - return {DecodeFailure::DECODE_OKAY, FEXCore::IR::FPRFixedClass}; - } - else if (Arg == "GPRPair") { - return {DecodeFailure::DECODE_OKAY, FEXCore::IR::GPRPairClass}; - } - else if (Arg == "Complex") { - return {DecodeFailure::DECODE_OKAY, FEXCore::IR::ComplexClass}; - } - - return {DecodeFailure::DECODE_INVALIDREGISTERCLASS, FEXCore::IR::InvalidClass}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - uint8_t Size{}, Elements{1}; - int NumArgs = sscanf(Arg.c_str(), "i%hhdv%hhd", &Size, &Elements); - - if (NumArgs != 1 && NumArgs != 2) { - return {DecodeFailure::DECODE_INVALID, {}}; - } - - return {DecodeFailure::DECODE_OKAY, FEXCore::IR::TypeDefinition::Create(Size / 8, Elements)}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - static constexpr std::array CondNames = { - "EQ", - "NEQ", - "UGE", - "ULT", - "MI", - "PL", - "VS", - "VC", - "UGT", - "ULE", - "SGE", - "SLT", - "SGT", - "SLE", - "ANDZ", - "ANDNZ", - "FLU", - "FGE", - "FLEU", - "FGT", - "FU", - "FNU" - }; - - for (size_t i = 0; i < CondNames.size(); ++i) { - if (CondNames[i] == Arg) { - return {DecodeFailure::DECODE_OKAY, CondClassType{static_cast(i)}}; - } - } - return {DecodeFailure::DECODE_INVALID_CONDFLAG, {}}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - static constexpr std::array Names = { - "SXTX", - "UXTW", - "SXTW", - }; - - for (size_t i = 0; i < Names.size(); ++i) { - if (Names[i] == Arg) { - return {DecodeFailure::DECODE_OKAY, MemOffsetType{static_cast(i)}}; - } - } - return {DecodeFailure::DECODE_INVALID_MEMOFFSETTYPE, {}}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - static constexpr std::array Names = { - "Loads", - "Stores", - "LoadStores", - }; - - for (size_t i = 0; i < Names.size(); ++i) { - if (Names[i] == Arg) { - return {DecodeFailure::DECODE_OKAY, FenceType{static_cast(i)}}; - } - } - return {DecodeFailure::DECODE_INVALID_FENCETYPE, {}}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - uint32_t tmp{}; - fextl::stringstream ss{Arg}; - BreakDefinition Reason{}; - - // Seek past '{' - ss.seekg(1, std::ios::cur); - ss >> Reason.ErrorRegister; - - // Seek past '.' - ss.seekg(1, std::ios::cur); - ss >> tmp; - Reason.Signal = tmp; - - // Seek past '.' - ss.seekg(1, std::ios::cur); - ss >> tmp; - Reason.TrapNumber = tmp; - - // Seek past '.' - ss.seekg(1, std::ios::cur); - ss >> tmp; - Reason.si_code = tmp; - - if (ss.fail()) { - return {DecodeFailure::DECODE_INVALIDCHAR, {}}; - } - else { - return {DecodeFailure::DECODE_OKAY, Reason}; - } - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - static constexpr std::array, 6> Names = {{ - { "i8", OpSize::i8Bit }, - { "i16", OpSize::i16Bit }, - { "i32", OpSize::i32Bit }, - { "i64", OpSize::i64Bit }, - { "i128", OpSize::i128Bit }, - { "i256", OpSize::i256Bit }, - }}; - - for (size_t i = 0; i < Names.size(); ++i) { - if (Names[i].first == Arg) { - return {DecodeFailure::DECODE_OKAY, Names[i].second}; - } - } - return {DecodeFailure::DECODE_INVALID_OPSIZE, {}}; - } - - template<> - std::pair DecodeValue(const fextl::string &Arg) { - if (Arg.at(0) != '%') return {DecodeFailure::DECODE_INVALIDCHAR, 0}; - - // Strip off the type qualifier from the ssa value - fextl::string SSAName = FEXCore::StringUtils::Trim(Arg); - const size_t ArgEnd = SSAName.find_first_of(' '); - - if (ArgEnd != fextl::string::npos) { - SSAName = SSAName.substr(0, ArgEnd); - } - - // Forward declarations may make this not succed - auto Op = SSANameMapper.find(SSAName); - if (Op == SSANameMapper.end()) { - return {DecodeFailure::DECODE_UNKNOWN_SSA, nullptr}; - } - - return {DecodeFailure::DECODE_OKAY, Op->second}; - } - - struct LineDefinition { - size_t LineNumber; - bool HasDefinition{}; - fextl::string Definition{}; - FEXCore::IR::TypeDefinition Size{}; - fextl::string IROp{}; - FEXCore::IR::IROps OpEnum; - bool HasArgs{}; - fextl::vector Args; - OrderedNode *Node{}; - }; - - fextl::vector Lines; - fextl::unordered_map SSANameMapper; - fextl::vector Defs; - LineDefinition *CurrentDef{}; - fextl::unordered_map NameToOpMap; - - IRParser(FEXCore::Utils::IntrusivePooledAllocator &ThreadAllocator, fextl::stringstream &MapsStream) - : IREmitter {ThreadAllocator} { - InitializeNameMap(); - - fextl::string Line; - while (std::getline(MapsStream, Line)) { - if (MapsStream.eof()) break; - if (MapsStream.fail()) { - LogMan::Msg::EFmt("Failed to getline on line: {}", Lines.size()); - return; - } - Lines.emplace_back(Line); - } - - ResetWorkingList(); - Loaded = Parse(); - } - - bool Loaded = false; - - bool Parse() { - const auto CheckPrintError = [&](const LineDefinition &Def, DecodeFailure Failure) -> bool { - if (Failure != DecodeFailure::DECODE_OKAY) { - LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); - LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); - LogMan::Msg::EFmt("Value Couldn't be decoded due to {}", DecodeErrorToString(Failure)); - return false; + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg.at(0) != '#') { + return {DecodeFailure::DECODE_INVALIDCHAR, 0}; } - return true; - }; + uint8_t Result = strtoul(&Arg.at(1), nullptr, 0); + if (errno == ERANGE) { + return {DecodeFailure::DECODE_INVALIDRANGE, 0}; + } + return {DecodeFailure::DECODE_OKAY, Result}; + } - const auto CheckPrintErrorArg = [&](const LineDefinition &Def, DecodeFailure Failure, size_t Arg) -> bool { - if (Failure != DecodeFailure::DECODE_OKAY) { - LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); - LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); - LogMan::Msg::EFmt("Argument Number {}: {}", Arg + 1, Def.Args[Arg]); - LogMan::Msg::EFmt("Value Couldn't be decoded due to {}", DecodeErrorToString(Failure)); - return false; + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg.at(0) != '#') { + return {DecodeFailure::DECODE_INVALIDCHAR, 0}; } - return true; - }; + uint8_t Result = strtoul(&Arg.at(1), nullptr, 0); + if (errno == ERANGE || Result > 1) { + return {DecodeFailure::DECODE_INVALIDRANGE, 0}; + } + return {DecodeFailure::DECODE_OKAY, Result != 0}; + } - // String parse every line for our definitions - for (size_t i = 0; i < Lines.size(); ++i) { - fextl::string Line = Lines[i]; - LineDefinition Def{}; - CurrentDef = &Def; - Def.LineNumber = i; - - Line = FEXCore::StringUtils::Trim(Line); - - // Skip empty lines - if (Line.empty()) { - continue; + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg.at(0) != '#') { + return {DecodeFailure::DECODE_INVALIDCHAR, 0}; } - if (Line[0] == ';') { - // This is a comment line - // Skip it - continue; + uint16_t Result = strtoul(&Arg.at(1), nullptr, 0); + if (errno == ERANGE) { + return {DecodeFailure::DECODE_INVALIDRANGE, 0}; + } + return {DecodeFailure::DECODE_OKAY, Result}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg.at(0) != '#') { + return {DecodeFailure::DECODE_INVALIDCHAR, 0}; } - size_t CurrentPos{}; - // Let's see if this node is assigning something first - if (Line[0] == '%') { - size_t DefinitionEnd = fextl::string::npos; - if ((DefinitionEnd = Line.find_first_of('=', CurrentPos)) != fextl::string::npos) { - Def.Definition = Line.substr(0, DefinitionEnd); - Def.Definition = FEXCore::StringUtils::Trim(Def.Definition); - Def.HasDefinition = true; - CurrentPos = DefinitionEnd + 1; // +1 to ensure we go past then assignment - } - else { - LogMan::Msg::EFmt("Error on Line: {}", i); - LogMan::Msg::EFmt("{}", Lines[i]); - LogMan::Msg::EFmt("SSA declaration without assignment"); + uint32_t Result = strtoul(&Arg.at(1), nullptr, 0); + if (errno == ERANGE) { + return {DecodeFailure::DECODE_INVALIDRANGE, 0}; + } + return {DecodeFailure::DECODE_OKAY, Result}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg.at(0) != '#') { + return {DecodeFailure::DECODE_INVALIDCHAR, 0}; + } + + uint64_t Result = strtoull(&Arg.at(1), nullptr, 0); + if (errno == ERANGE) { + return {DecodeFailure::DECODE_INVALIDRANGE, 0}; + } + return {DecodeFailure::DECODE_OKAY, Result}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg.at(0) != '#') { + return {DecodeFailure::DECODE_INVALIDCHAR, 0}; + } + + int64_t Result = (int64_t)strtoull(&Arg.at(1), nullptr, 0); + if (errno == ERANGE) { + return {DecodeFailure::DECODE_INVALIDRANGE, 0}; + } + return {DecodeFailure::DECODE_OKAY, Result}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + IR::SHA256Sum Result; + + if (Arg.at(0) != 's' || Arg.at(1) != 'h' || Arg.at(2) != 'a' || Arg.at(3) != '2' || Arg.at(4) != '5' || Arg.at(5) != '6' || Arg.at(6) != ':') { + return {DecodeFailure::DECODE_INVALIDCHAR, Result}; + } + + auto GetDigit = [](const fextl::string& Arg, int pos, uint8_t* val) { + auto chr = Arg.at(pos); + if (chr >= '0' && chr <= '9') { + *val = chr - '0'; + return true; + } else if (chr >= 'a' && chr <= 'f') { + *val = 10 + chr - 'a'; + return true; + } else { return false; } + }; + + for (size_t i = 0; i < sizeof(Result.data); i++) { + uint8_t high, low; + if (!GetDigit(Arg, 7 + 2 * i + 0, &high) || !GetDigit(Arg, 7 + 2 * i + 1, &low)) { + return {DecodeFailure::DECODE_INVALIDRANGE, Result}; + } + Result.data[i] = high * 16 + low; } - // Check if we are pulling in some IR from the IR Printer - // Prints (%%d) at the start of lines without a definition - if (Line[0] == '(') { - size_t DefinitionEnd = fextl::string::npos; - if ((DefinitionEnd = Line.find_first_of(')', CurrentPos)) != fextl::string::npos) { - size_t SSAEnd = fextl::string::npos; - if ((SSAEnd = Line.find_last_of(' ', DefinitionEnd)) != fextl::string::npos) { - fextl::string Type = Line.substr(SSAEnd + 1, DefinitionEnd - SSAEnd - 1); + return {DecodeFailure::DECODE_OKAY, Result}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg == "GPR") { + return {DecodeFailure::DECODE_OKAY, FEXCore::IR::GPRClass}; + } else if (Arg == "FPR") { + return {DecodeFailure::DECODE_OKAY, FEXCore::IR::FPRClass}; + } else if (Arg == "GPRFixed") { + return {DecodeFailure::DECODE_OKAY, FEXCore::IR::GPRFixedClass}; + } else if (Arg == "FPRFixed") { + return {DecodeFailure::DECODE_OKAY, FEXCore::IR::FPRFixedClass}; + } else if (Arg == "GPRPair") { + return {DecodeFailure::DECODE_OKAY, FEXCore::IR::GPRPairClass}; + } else if (Arg == "Complex") { + return {DecodeFailure::DECODE_OKAY, FEXCore::IR::ComplexClass}; + } + + return {DecodeFailure::DECODE_INVALIDREGISTERCLASS, FEXCore::IR::InvalidClass}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + uint8_t Size {}, Elements {1}; + int NumArgs = sscanf(Arg.c_str(), "i%hhdv%hhd", &Size, &Elements); + + if (NumArgs != 1 && NumArgs != 2) { + return {DecodeFailure::DECODE_INVALID, {}}; + } + + return {DecodeFailure::DECODE_OKAY, FEXCore::IR::TypeDefinition::Create(Size / 8, Elements)}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + static constexpr std::array CondNames = {"EQ", "NEQ", "UGE", "ULT", "MI", "PL", "VS", "VC", + "UGT", "ULE", "SGE", "SLT", "SGT", "SLE", "ANDZ", "ANDNZ", + "FLU", "FGE", "FLEU", "FGT", "FU", "FNU"}; + + for (size_t i = 0; i < CondNames.size(); ++i) { + if (CondNames[i] == Arg) { + return {DecodeFailure::DECODE_OKAY, CondClassType {static_cast(i)}}; + } + } + return {DecodeFailure::DECODE_INVALID_CONDFLAG, {}}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + static constexpr std::array Names = { + "SXTX", + "UXTW", + "SXTW", + }; + + for (size_t i = 0; i < Names.size(); ++i) { + if (Names[i] == Arg) { + return {DecodeFailure::DECODE_OKAY, MemOffsetType {static_cast(i)}}; + } + } + return {DecodeFailure::DECODE_INVALID_MEMOFFSETTYPE, {}}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + static constexpr std::array Names = { + "Loads", + "Stores", + "LoadStores", + }; + + for (size_t i = 0; i < Names.size(); ++i) { + if (Names[i] == Arg) { + return {DecodeFailure::DECODE_OKAY, FenceType {static_cast(i)}}; + } + } + return {DecodeFailure::DECODE_INVALID_FENCETYPE, {}}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + uint32_t tmp {}; + fextl::stringstream ss {Arg}; + BreakDefinition Reason {}; + + // Seek past '{' + ss.seekg(1, std::ios::cur); + ss >> Reason.ErrorRegister; + + // Seek past '.' + ss.seekg(1, std::ios::cur); + ss >> tmp; + Reason.Signal = tmp; + + // Seek past '.' + ss.seekg(1, std::ios::cur); + ss >> tmp; + Reason.TrapNumber = tmp; + + // Seek past '.' + ss.seekg(1, std::ios::cur); + ss >> tmp; + Reason.si_code = tmp; + + if (ss.fail()) { + return {DecodeFailure::DECODE_INVALIDCHAR, {}}; + } else { + return {DecodeFailure::DECODE_OKAY, Reason}; + } + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + static constexpr std::array, 6> Names = {{ + {"i8", OpSize::i8Bit}, + {"i16", OpSize::i16Bit}, + {"i32", OpSize::i32Bit}, + {"i64", OpSize::i64Bit}, + {"i128", OpSize::i128Bit}, + {"i256", OpSize::i256Bit}, + }}; + + for (size_t i = 0; i < Names.size(); ++i) { + if (Names[i].first == Arg) { + return {DecodeFailure::DECODE_OKAY, Names[i].second}; + } + } + return {DecodeFailure::DECODE_INVALID_OPSIZE, {}}; + } + + template<> + std::pair DecodeValue(const fextl::string& Arg) { + if (Arg.at(0) != '%') { + return {DecodeFailure::DECODE_INVALIDCHAR, 0}; + } + + // Strip off the type qualifier from the ssa value + fextl::string SSAName = FEXCore::StringUtils::Trim(Arg); + const size_t ArgEnd = SSAName.find_first_of(' '); + + if (ArgEnd != fextl::string::npos) { + SSAName = SSAName.substr(0, ArgEnd); + } + + // Forward declarations may make this not succed + auto Op = SSANameMapper.find(SSAName); + if (Op == SSANameMapper.end()) { + return {DecodeFailure::DECODE_UNKNOWN_SSA, nullptr}; + } + + return {DecodeFailure::DECODE_OKAY, Op->second}; + } + + struct LineDefinition { + size_t LineNumber; + bool HasDefinition {}; + fextl::string Definition {}; + FEXCore::IR::TypeDefinition Size {}; + fextl::string IROp {}; + FEXCore::IR::IROps OpEnum; + bool HasArgs {}; + fextl::vector Args; + OrderedNode* Node {}; + }; + + fextl::vector Lines; + fextl::unordered_map SSANameMapper; + fextl::vector Defs; + LineDefinition* CurrentDef {}; + fextl::unordered_map NameToOpMap; + + IRParser(FEXCore::Utils::IntrusivePooledAllocator& ThreadAllocator, fextl::stringstream& MapsStream) + : IREmitter {ThreadAllocator} { + InitializeNameMap(); + + fextl::string Line; + while (std::getline(MapsStream, Line)) { + if (MapsStream.eof()) { + break; + } + if (MapsStream.fail()) { + LogMan::Msg::EFmt("Failed to getline on line: {}", Lines.size()); + return; + } + Lines.emplace_back(Line); + } + + ResetWorkingList(); + Loaded = Parse(); + } + + bool Loaded = false; + + bool Parse() { + const auto CheckPrintError = [&](const LineDefinition& Def, DecodeFailure Failure) -> bool { + if (Failure != DecodeFailure::DECODE_OKAY) { + LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); + LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); + LogMan::Msg::EFmt("Value Couldn't be decoded due to {}", DecodeErrorToString(Failure)); + return false; + } + + return true; + }; + + const auto CheckPrintErrorArg = [&](const LineDefinition& Def, DecodeFailure Failure, size_t Arg) -> bool { + if (Failure != DecodeFailure::DECODE_OKAY) { + LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); + LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); + LogMan::Msg::EFmt("Argument Number {}: {}", Arg + 1, Def.Args[Arg]); + LogMan::Msg::EFmt("Value Couldn't be decoded due to {}", DecodeErrorToString(Failure)); + return false; + } + + return true; + }; + + // String parse every line for our definitions + for (size_t i = 0; i < Lines.size(); ++i) { + fextl::string Line = Lines[i]; + LineDefinition Def {}; + CurrentDef = &Def; + Def.LineNumber = i; + + Line = FEXCore::StringUtils::Trim(Line); + + // Skip empty lines + if (Line.empty()) { + continue; + } + + if (Line[0] == ';') { + // This is a comment line + // Skip it + continue; + } + + size_t CurrentPos {}; + // Let's see if this node is assigning something first + if (Line[0] == '%') { + size_t DefinitionEnd = fextl::string::npos; + if ((DefinitionEnd = Line.find_first_of('=', CurrentPos)) != fextl::string::npos) { + Def.Definition = Line.substr(0, DefinitionEnd); + Def.Definition = FEXCore::StringUtils::Trim(Def.Definition); + Def.HasDefinition = true; + CurrentPos = DefinitionEnd + 1; // +1 to ensure we go past then assignment + } else { + LogMan::Msg::EFmt("Error on Line: {}", i); + LogMan::Msg::EFmt("{}", Lines[i]); + LogMan::Msg::EFmt("SSA declaration without assignment"); + return false; + } + } + + // Check if we are pulling in some IR from the IR Printer + // Prints (%%d) at the start of lines without a definition + if (Line[0] == '(') { + size_t DefinitionEnd = fextl::string::npos; + if ((DefinitionEnd = Line.find_first_of(')', CurrentPos)) != fextl::string::npos) { + size_t SSAEnd = fextl::string::npos; + if ((SSAEnd = Line.find_last_of(' ', DefinitionEnd)) != fextl::string::npos) { + fextl::string Type = Line.substr(SSAEnd + 1, DefinitionEnd - SSAEnd - 1); + Type = FEXCore::StringUtils::Trim(Type); + + auto DefinitionSize = DecodeValue(Type); + if (!CheckPrintError(Def, DefinitionSize.first)) { + return false; + } + Def.Size = DefinitionSize.second; + } + + Def.Definition = FEXCore::StringUtils::Trim(Line.substr(1, std::min(DefinitionEnd, SSAEnd) - 1)); + + CurrentPos = DefinitionEnd + 1; + } else { + LogMan::Msg::EFmt("Error on Line: {}", i); + LogMan::Msg::EFmt("{}", Lines[i]); + LogMan::Msg::EFmt("SSA value with numbered SSA provided but no closing parentheses"); + return false; + } + } + + if (Def.HasDefinition) { + // Let's check if we have a size declared with this variable + size_t NameEnd = fextl::string::npos; + if ((NameEnd = Def.Definition.find_first_of(' ')) != fextl::string::npos) { + fextl::string Type = Def.Definition.substr(NameEnd + 1); Type = FEXCore::StringUtils::Trim(Type); + Def.Definition = FEXCore::StringUtils::Trim(Def.Definition.substr(0, NameEnd)); auto DefinitionSize = DecodeValue(Type); if (!CheckPrintError(Def, DefinitionSize.first)) { @@ -449,156 +476,135 @@ class IRParser: public FEXCore::IR::IREmitter { Def.Size = DefinitionSize.second; } - Def.Definition = FEXCore::StringUtils::Trim(Line.substr(1, std::min(DefinitionEnd, SSAEnd) - 1)); - - CurrentPos = DefinitionEnd + 1; - } - else { - LogMan::Msg::EFmt("Error on Line: {}", i); - LogMan::Msg::EFmt("{}", Lines[i]); - LogMan::Msg::EFmt("SSA value with numbered SSA provided but no closing parentheses"); - return false; - } - } - - if (Def.HasDefinition) { - // Let's check if we have a size declared with this variable - size_t NameEnd = fextl::string::npos; - if ((NameEnd = Def.Definition.find_first_of(' ')) != fextl::string::npos) { - fextl::string Type = Def.Definition.substr(NameEnd + 1); - Type = FEXCore::StringUtils::Trim(Type); - Def.Definition = FEXCore::StringUtils::Trim(Def.Definition.substr(0, NameEnd)); - - auto DefinitionSize = DecodeValue(Type); - if (!CheckPrintError(Def, DefinitionSize.first)) return false; - Def.Size = DefinitionSize.second; - } - - if (Def.Definition == "%Invalid") { - LogMan::Msg::EFmt("Error on Line: {}", i); - LogMan::Msg::EFmt("{}", Lines[i]); - LogMan::Msg::EFmt("Definition tried to define reserved %Invalid ssa node"); - return false; - } - } - - // Let's get the IR op - size_t OpNameEnd = fextl::string::npos; - fextl::string RemainingLine = FEXCore::StringUtils::Trim(Line.substr(CurrentPos)); - CurrentPos = 0; - if ((OpNameEnd = RemainingLine.find_first_of(" \t\n\r\0", CurrentPos)) != fextl::string::npos) { - Def.IROp = RemainingLine.substr(CurrentPos, OpNameEnd); - Def.IROp = FEXCore::StringUtils::Trim(Def.IROp); - Def.HasArgs = true; - CurrentPos = OpNameEnd; - } - else { - if (RemainingLine.empty()) { - LogMan::Msg::EFmt("Error on Line: {}", i); - LogMan::Msg::EFmt("{}", Lines[i]); - LogMan::Msg::EFmt("Line without an IROp?"); - return false; - } - - Def.IROp = RemainingLine; - Def.HasArgs = false; - } - - if (Def.HasArgs) { - RemainingLine = - FEXCore::StringUtils::Trim(RemainingLine.substr(CurrentPos)); - if (RemainingLine.empty()) { - // How did we get here? - Def.HasArgs = false; - } - else { - while (!RemainingLine.empty()) { - const size_t ArgEnd = RemainingLine.find(','); - fextl::string Arg = FEXCore::StringUtils::Trim(RemainingLine.substr(0, ArgEnd)); - - Def.Args.emplace_back(std::move(Arg)); - - RemainingLine.erase(0, ArgEnd+1); // +1 to ensure we go past the ',' - if (ArgEnd == fextl::string::npos) - break; + if (Def.Definition == "%Invalid") { + LogMan::Msg::EFmt("Error on Line: {}", i); + LogMan::Msg::EFmt("{}", Lines[i]); + LogMan::Msg::EFmt("Definition tried to define reserved %Invalid ssa node"); + return false; } } - } - CurrentDef = &Defs.emplace_back(std::move(Def)); - } + // Let's get the IR op + size_t OpNameEnd = fextl::string::npos; + fextl::string RemainingLine = FEXCore::StringUtils::Trim(Line.substr(CurrentPos)); + CurrentPos = 0; + if ((OpNameEnd = RemainingLine.find_first_of(" \t\n\r\0", CurrentPos)) != fextl::string::npos) { + Def.IROp = RemainingLine.substr(CurrentPos, OpNameEnd); + Def.IROp = FEXCore::StringUtils::Trim(Def.IROp); + Def.HasArgs = true; + CurrentPos = OpNameEnd; + } else { + if (RemainingLine.empty()) { + LogMan::Msg::EFmt("Error on Line: {}", i); + LogMan::Msg::EFmt("{}", Lines[i]); + LogMan::Msg::EFmt("Line without an IROp?"); + return false; + } - // Ensure all of the ops are real ops - for(size_t i = 0; i < Defs.size(); ++i) { - auto &Def = Defs[i]; - auto Op = NameToOpMap.find(Def.IROp); - if (Op == NameToOpMap.end()) { - LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); - LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); - LogMan::Msg::EFmt("IROp '{}' doesn't exist", Def.IROp); - return false; - } - Def.OpEnum = Op->second; - } - - // Emit the header op - IRPair IRHeader; - { - auto &Def = Defs[0]; - CurrentDef = &Def; - if (Def.OpEnum != FEXCore::IR::IROps::OP_IRHEADER) { - LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); - LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); - LogMan::Msg::EFmt("First op needs to be IRHeader. Was '{}'", Def.IROp); - return false; - } - - auto OriginalRIP = DecodeValue(Def.Args[1]); - - if (!CheckPrintError(Def, OriginalRIP.first)) return false; - - auto CodeBlockCount = DecodeValue(Def.Args[2]); - - if (!CheckPrintError(Def, CodeBlockCount.first)) return false; - - auto InstructionCount = DecodeValue(Def.Args[3]); - - if (!CheckPrintError(Def, InstructionCount.first)) return false; - - IRHeader = _IRHeader(InvalidNode, OriginalRIP.second, CodeBlockCount.second, InstructionCount.second); - } - - SetWriteCursor(nullptr); // isolate the header from everything following - - // Initialize SSANameMapper with Invalid value - SSANameMapper.insert_or_assign("%Invalid", Invalid()); - - // Spin through the blocks and generate basic block ops - for(size_t i = 0; i < Defs.size(); ++i) { - auto &Def = Defs[i]; - if (Def.OpEnum == FEXCore::IR::IROps::OP_CODEBLOCK) { - auto CodeBlock = _CodeBlock(InvalidNode, InvalidNode); - SSANameMapper.insert_or_assign(Def.Definition, CodeBlock.Node); - Def.Node = CodeBlock.Node; - - if (i == 1) { - // First code block is the entry block - // Link the header to the first block - IRHeader.first->Blocks = CodeBlock.Node->Wrapped(DualListData.ListBegin()); + Def.IROp = RemainingLine; + Def.HasArgs = false; } - CodeBlocks.emplace_back(CodeBlock.Node); + + if (Def.HasArgs) { + RemainingLine = FEXCore::StringUtils::Trim(RemainingLine.substr(CurrentPos)); + if (RemainingLine.empty()) { + // How did we get here? + Def.HasArgs = false; + } else { + while (!RemainingLine.empty()) { + const size_t ArgEnd = RemainingLine.find(','); + fextl::string Arg = FEXCore::StringUtils::Trim(RemainingLine.substr(0, ArgEnd)); + + Def.Args.emplace_back(std::move(Arg)); + + RemainingLine.erase(0, ArgEnd + 1); // +1 to ensure we go past the ',' + if (ArgEnd == fextl::string::npos) { + break; + } + } + } + } + + CurrentDef = &Defs.emplace_back(std::move(Def)); } - } - SetWriteCursor(nullptr); // isolate the block headers too - // Spin through all the definitions and add the ops to the basic blocks - OrderedNode *CurrentBlock{}; - FEXCore::IR::IROp_CodeBlock *CurrentBlockOp{}; - for(size_t i = 1; i < Defs.size(); ++i) { - auto &Def = Defs[i]; - CurrentDef = &Def; + // Ensure all of the ops are real ops + for (size_t i = 0; i < Defs.size(); ++i) { + auto& Def = Defs[i]; + auto Op = NameToOpMap.find(Def.IROp); + if (Op == NameToOpMap.end()) { + LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); + LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); + LogMan::Msg::EFmt("IROp '{}' doesn't exist", Def.IROp); + return false; + } + Def.OpEnum = Op->second; + } - switch (Def.OpEnum) { + // Emit the header op + IRPair IRHeader; + { + auto& Def = Defs[0]; + CurrentDef = &Def; + if (Def.OpEnum != FEXCore::IR::IROps::OP_IRHEADER) { + LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); + LogMan::Msg::EFmt("{}", Lines[Def.LineNumber]); + LogMan::Msg::EFmt("First op needs to be IRHeader. Was '{}'", Def.IROp); + return false; + } + + auto OriginalRIP = DecodeValue(Def.Args[1]); + + if (!CheckPrintError(Def, OriginalRIP.first)) { + return false; + } + + auto CodeBlockCount = DecodeValue(Def.Args[2]); + + if (!CheckPrintError(Def, CodeBlockCount.first)) { + return false; + } + + auto InstructionCount = DecodeValue(Def.Args[3]); + + if (!CheckPrintError(Def, InstructionCount.first)) { + return false; + } + + IRHeader = _IRHeader(InvalidNode, OriginalRIP.second, CodeBlockCount.second, InstructionCount.second); + } + + SetWriteCursor(nullptr); // isolate the header from everything following + + // Initialize SSANameMapper with Invalid value + SSANameMapper.insert_or_assign("%Invalid", Invalid()); + + // Spin through the blocks and generate basic block ops + for (size_t i = 0; i < Defs.size(); ++i) { + auto& Def = Defs[i]; + if (Def.OpEnum == FEXCore::IR::IROps::OP_CODEBLOCK) { + auto CodeBlock = _CodeBlock(InvalidNode, InvalidNode); + SSANameMapper.insert_or_assign(Def.Definition, CodeBlock.Node); + Def.Node = CodeBlock.Node; + + if (i == 1) { + // First code block is the entry block + // Link the header to the first block + IRHeader.first->Blocks = CodeBlock.Node->Wrapped(DualListData.ListBegin()); + } + CodeBlocks.emplace_back(CodeBlock.Node); + } + } + SetWriteCursor(nullptr); // isolate the block headers too + + // Spin through all the definitions and add the ops to the basic blocks + OrderedNode* CurrentBlock {}; + FEXCore::IR::IROp_CodeBlock* CurrentBlockOp {}; + for (size_t i = 1; i < Defs.size(); ++i) { + auto& Def = Defs[i]; + CurrentDef = &Def; + + switch (Def.OpEnum) { // Special handled case FEXCore::IR::IROps::OP_IRHEADER: LogMan::Msg::EFmt("Error on Line: {}", Def.LineNumber); @@ -675,46 +681,44 @@ class IRParser: public FEXCore::IR::IREmitter { LogMan::Msg::EFmt("Unhandled Op enum '{}' in parser", Def.IROp); return false; } + } + + if (Def.HasDefinition) { + auto IROp = Def.Node->Op(DualListData.DataBegin()); + if (Def.Size.Elements()) { + IROp->Size = Def.Size.Bytes() * Def.Size.Elements(); + IROp->ElementSize = Def.Size.Bytes(); + } else { + IROp->Size = Def.Size.Bytes(); + IROp->ElementSize = 0; + } + SSANameMapper.insert_or_assign(Def.Definition, Def.Node); + } } - if (Def.HasDefinition) { - auto IROp = Def.Node->Op(DualListData.DataBegin()); - if (Def.Size.Elements()) { - IROp->Size = Def.Size.Bytes() * Def.Size.Elements(); - IROp->ElementSize = Def.Size.Bytes(); - } - else { - IROp->Size = Def.Size.Bytes(); - IROp->ElementSize = 0; - } - SSANameMapper.insert_or_assign(Def.Definition, Def.Node); - } + return true; } - return true; - } - - void InitializeNameMap() { - if (NameToOpMap.empty()) { - for (FEXCore::IR::IROps Op = FEXCore::IR::IROps::OP_DUMMY; - Op <= FEXCore::IR::IROps::OP_LAST; - Op = static_cast(static_cast(Op) + 1)) { - NameToOpMap.insert_or_assign(FEXCore::IR::GetName(Op), Op); + void InitializeNameMap() { + if (NameToOpMap.empty()) { + for (FEXCore::IR::IROps Op = FEXCore::IR::IROps::OP_DUMMY; Op <= FEXCore::IR::IROps::OP_LAST; + Op = static_cast(static_cast(Op) + 1)) { + NameToOpMap.insert_or_assign(FEXCore::IR::GetName(Op), Op); + } } } + }; + +} // namespace + +fextl::unique_ptr Parse(FEXCore::Utils::IntrusivePooledAllocator& ThreadAllocator, fextl::stringstream& MapsStream) { + auto parser = fextl::make_unique(ThreadAllocator, MapsStream); + + if (parser->Loaded) { + return parser; + } else { + return nullptr; } -}; - -} // anon namespace - -fextl::unique_ptr Parse(FEXCore::Utils::IntrusivePooledAllocator &ThreadAllocator, fextl::stringstream &MapsStream) { - auto parser = fextl::make_unique(ThreadAllocator, MapsStream); - - if (parser->Loaded) { - return parser; - } else { - return nullptr; - } } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/IntrusiveIRList.h b/FEXCore/Source/Interface/IR/IntrusiveIRList.h index c5f1e7e8e..4c298c573 100644 --- a/FEXCore/Source/Interface/IR/IntrusiveIRList.h +++ b/FEXCore/Source/Interface/IR/IntrusiveIRList.h @@ -24,102 +24,124 @@ namespace FEXCore::IR { * Can potentially support reallocation if we are smart and make sure to invalidate anything holding a true pointer */ class DualIntrusiveAllocator { - public: - [[nodiscard]] bool DataCheckSize(size_t Size) const { - size_t NewOffset = DataCurrentOffset + Size; - return NewOffset <= MemorySize; - } +public: + [[nodiscard]] + bool DataCheckSize(size_t Size) const { + size_t NewOffset = DataCurrentOffset + Size; + return NewOffset <= MemorySize; + } - [[nodiscard]] bool ListCheckSize(size_t Size) const { - size_t NewOffset = ListCurrentOffset + Size; - return NewOffset <= MemorySize; - } + [[nodiscard]] + bool ListCheckSize(size_t Size) const { + size_t NewOffset = ListCurrentOffset + Size; + return NewOffset <= MemorySize; + } - [[nodiscard]] void *DataAllocate(size_t Size) { - LOGMAN_THROW_A_FMT(DataCheckSize(Size), - "Ran out of space in DualIntrusiveAllocator during allocation"); - size_t NewOffset = DataCurrentOffset + Size; - uintptr_t NewPointer = Data + DataCurrentOffset; - DataCurrentOffset = NewOffset; - return reinterpret_cast(NewPointer); - } + [[nodiscard]] + void* DataAllocate(size_t Size) { + LOGMAN_THROW_A_FMT(DataCheckSize(Size), "Ran out of space in DualIntrusiveAllocator during allocation"); + size_t NewOffset = DataCurrentOffset + Size; + uintptr_t NewPointer = Data + DataCurrentOffset; + DataCurrentOffset = NewOffset; + return reinterpret_cast(NewPointer); + } - [[nodiscard]] void *ListAllocate(size_t Size) { - LOGMAN_THROW_A_FMT(ListCheckSize(Size), - "Ran out of space in DualIntrusiveAllocator during allocation"); - size_t NewOffset = ListCurrentOffset + Size; - uintptr_t NewPointer = List + ListCurrentOffset; - ListCurrentOffset = NewOffset; - return reinterpret_cast(NewPointer); - } + [[nodiscard]] + void* ListAllocate(size_t Size) { + LOGMAN_THROW_A_FMT(ListCheckSize(Size), "Ran out of space in DualIntrusiveAllocator during allocation"); + size_t NewOffset = ListCurrentOffset + Size; + uintptr_t NewPointer = List + ListCurrentOffset; + ListCurrentOffset = NewOffset; + return reinterpret_cast(NewPointer); + } - [[nodiscard]] size_t DataSize() const { return DataCurrentOffset; } - [[nodiscard]] size_t DataBackingSize() const { return MemorySize; } + [[nodiscard]] + size_t DataSize() const { + return DataCurrentOffset; + } + [[nodiscard]] + size_t DataBackingSize() const { + return MemorySize; + } - [[nodiscard]] size_t ListSize() const { return ListCurrentOffset; } - [[nodiscard]] size_t ListBackingSize() const { return MemorySize; } + [[nodiscard]] + size_t ListSize() const { + return ListCurrentOffset; + } + [[nodiscard]] + size_t ListBackingSize() const { + return MemorySize; + } - [[nodiscard]] uintptr_t DataBegin() const { return Data; } - [[nodiscard]] uintptr_t ListBegin() const { return List; } + [[nodiscard]] + uintptr_t DataBegin() const { + return Data; + } + [[nodiscard]] + uintptr_t ListBegin() const { + return List; + } - void Reset() { DataCurrentOffset = 0; ListCurrentOffset = 0; } + void Reset() { + DataCurrentOffset = 0; + ListCurrentOffset = 0; + } - void CopyData(DualIntrusiveAllocator const &rhs) { - DataCurrentOffset = rhs.DataCurrentOffset; - ListCurrentOffset = rhs.ListCurrentOffset; - memcpy(reinterpret_cast(Data), reinterpret_cast(rhs.Data), DataCurrentOffset); - memcpy(reinterpret_cast(List), reinterpret_cast(rhs.List), ListCurrentOffset); - } + void CopyData(const DualIntrusiveAllocator& rhs) { + DataCurrentOffset = rhs.DataCurrentOffset; + ListCurrentOffset = rhs.ListCurrentOffset; + memcpy(reinterpret_cast(Data), reinterpret_cast(rhs.Data), DataCurrentOffset); + memcpy(reinterpret_cast(List), reinterpret_cast(rhs.List), ListCurrentOffset); + } - protected: - DualIntrusiveAllocator(size_t Size) - : MemorySize {Size} { - } +protected: + DualIntrusiveAllocator(size_t Size) + : MemorySize {Size} {} - uintptr_t Data; - uintptr_t List; - size_t DataCurrentOffset {0}; - size_t ListCurrentOffset {0}; - size_t MemorySize; + uintptr_t Data; + uintptr_t List; + size_t DataCurrentOffset {0}; + size_t ListCurrentOffset {0}; + size_t MemorySize; }; class DualIntrusiveAllocatorMalloc final : public DualIntrusiveAllocator { - public: - DualIntrusiveAllocatorMalloc(size_t Size) - : DualIntrusiveAllocator {Size} { - Data = reinterpret_cast(FEXCore::Allocator::malloc(Size * 2)); - List = reinterpret_cast(Data + Size); - } +public: + DualIntrusiveAllocatorMalloc(size_t Size) + : DualIntrusiveAllocator {Size} { + Data = reinterpret_cast(FEXCore::Allocator::malloc(Size * 2)); + List = reinterpret_cast(Data + Size); + } - ~DualIntrusiveAllocatorMalloc() { - FEXCore::Allocator::free(reinterpret_cast(Data)); - } + ~DualIntrusiveAllocatorMalloc() { + FEXCore::Allocator::free(reinterpret_cast(Data)); + } }; class DualIntrusiveAllocatorThreadPool final : public DualIntrusiveAllocator { - public: - DualIntrusiveAllocatorThreadPool(FEXCore::Utils::IntrusivePooledAllocator &ThreadAllocator, size_t Size) - : DualIntrusiveAllocator {Size} - , PoolObject{ThreadAllocator, Size * 2} { - // Claim a buffer on allocation - PoolObject.ReownOrClaimBuffer(); - } +public: + DualIntrusiveAllocatorThreadPool(FEXCore::Utils::IntrusivePooledAllocator& ThreadAllocator, size_t Size) + : DualIntrusiveAllocator {Size} + , PoolObject {ThreadAllocator, Size * 2} { + // Claim a buffer on allocation + PoolObject.ReownOrClaimBuffer(); + } - ~DualIntrusiveAllocatorThreadPool() { - PoolObject.UnclaimBuffer(); - } + ~DualIntrusiveAllocatorThreadPool() { + PoolObject.UnclaimBuffer(); + } - void ReownOrClaimBuffer() { - Data = PoolObject.ReownOrClaimBuffer(); - List = Data + MemorySize; - } + void ReownOrClaimBuffer() { + Data = PoolObject.ReownOrClaimBuffer(); + List = Data + MemorySize; + } - void DelayedDisownBuffer() { - PoolObject.DelayedDisownBuffer(); - } + void DelayedDisownBuffer() { + PoolObject.DelayedDisownBuffer(); + } - private: - Utils::FixedSizePooledAllocation PoolObject; +private: + Utils::FixedSizePooledAllocation PoolObject; }; class IRListView final : public FEXCore::Allocator::FEXAllocOperators { @@ -130,9 +152,9 @@ class IRListView final : public FEXCore::Allocator::FEXAllocOperators { public: IRListView() = delete; - IRListView(IRListView &&) = delete; + IRListView(IRListView&&) = delete; - IRListView(DualIntrusiveAllocator *Data, bool _IsCopy) { + IRListView(DualIntrusiveAllocator* Data, bool _IsCopy) { SetCopy(_IsCopy); DataSize = Data->DataSize(); ListSize = Data->ListSize(); @@ -142,15 +164,14 @@ public: ListDataInternal = reinterpret_cast(reinterpret_cast(IRDataInternal) + DataSize); memcpy(IRDataInternal, reinterpret_cast(Data->DataBegin()), DataSize); memcpy(ListDataInternal, reinterpret_cast(Data->ListBegin()), ListSize); - } - else { + } else { // We are just pointing to the data IRDataInternal = reinterpret_cast(Data->DataBegin()); ListDataInternal = reinterpret_cast(Data->ListBegin()); } } - IRListView(IRListView *Old, bool _IsCopy) { + IRListView(IRListView* Old, bool _IsCopy) { SetCopy(_IsCopy); DataSize = Old->DataSize; ListSize = Old->ListSize; @@ -167,23 +188,23 @@ public: ~IRListView() { if (IsCopy()) { - FEXCore::Allocator::free (IRDataInternal); + FEXCore::Allocator::free(IRDataInternal); // ListData is just offset from IRData } } void Serialize(FEXCore::Context::AOTIRWriter& stream) const { - void *nul = nullptr; - //void *IRDataInternal; + void* nul = nullptr; + // void *IRDataInternal; stream.Write((const char*)&nul, sizeof(nul)); - //void *ListDataInternal; + // void *ListDataInternal; stream.Write((const char*)&nul, sizeof(nul)); - //size_t DataSize; + // size_t DataSize; stream.Write((const char*)&DataSize, sizeof(DataSize)); - //size_t ListSize; + // size_t ListSize; stream.Write((const char*)&ListSize, sizeof(ListSize)); - //uint64_t Flags; - uint64_t WrittenFlags = FLAG_Shared; //on disk format always has the Shared flag + // uint64_t Flags; + uint64_t WrittenFlags = FLAG_Shared; // on disk format always has the Shared flag stream.Write((const char*)&WrittenFlags, sizeof(WrittenFlags)); // inline data @@ -191,39 +212,58 @@ public: stream.Write((const char*)GetListData(), ListSize); } - void Serialize(uint8_t *ptr) const { - void *nul = nullptr; - //void *IRDataInternal; - memcpy(ptr, &nul, sizeof(nul)); ptr += sizeof(nul); - //void *ListDataInternal; - memcpy(ptr, &nul, sizeof(nul)); ptr += sizeof(nul); - //size_t DataSize; - memcpy(ptr, &DataSize, sizeof(DataSize)); ptr += sizeof(DataSize); - //size_t ListSize; - memcpy(ptr, &ListSize, sizeof(ListSize)); ptr += sizeof(ListSize); - //uint64_t Flags; - uint64_t WrittenFlags = FLAG_Shared; //on disk format always has the Shared flag - memcpy(ptr, &WrittenFlags, sizeof(WrittenFlags)); ptr += sizeof(WrittenFlags); + void Serialize(uint8_t* ptr) const { + void* nul = nullptr; + // void *IRDataInternal; + memcpy(ptr, &nul, sizeof(nul)); + ptr += sizeof(nul); + // void *ListDataInternal; + memcpy(ptr, &nul, sizeof(nul)); + ptr += sizeof(nul); + // size_t DataSize; + memcpy(ptr, &DataSize, sizeof(DataSize)); + ptr += sizeof(DataSize); + // size_t ListSize; + memcpy(ptr, &ListSize, sizeof(ListSize)); + ptr += sizeof(ListSize); + // uint64_t Flags; + uint64_t WrittenFlags = FLAG_Shared; // on disk format always has the Shared flag + memcpy(ptr, &WrittenFlags, sizeof(WrittenFlags)); + ptr += sizeof(WrittenFlags); // inline data - memcpy(ptr, (const void*)GetData(), DataSize); ptr += DataSize; - memcpy(ptr, (const void*)GetListData(), ListSize); ptr += ListSize; + memcpy(ptr, (const void*)GetData(), DataSize); + ptr += DataSize; + memcpy(ptr, (const void*)GetListData(), ListSize); + ptr += ListSize; } - [[nodiscard]] size_t GetInlineSize() const { + [[nodiscard]] + size_t GetInlineSize() const { static_assert(sizeof(*this) == 40); return sizeof(*this) + DataSize + ListSize; } - [[nodiscard]] IRListView *CreateCopy() { + [[nodiscard]] + IRListView* CreateCopy() { return new IRListView(this, true); } - [[nodiscard]] size_t GetDataSize() const { return DataSize; } - [[nodiscard]] size_t GetListSize() const { return ListSize; } - [[nodiscard]] size_t GetSSACount() const { return ListSize / sizeof(OrderedNode); } + [[nodiscard]] + size_t GetDataSize() const { + return DataSize; + } + [[nodiscard]] + size_t GetListSize() const { + return ListSize; + } + [[nodiscard]] + size_t GetSSACount() const { + return ListSize / sizeof(OrderedNode); + } - [[nodiscard]] bool IsCopy() const { + [[nodiscard]] + bool IsCopy() const { return (Flags & FLAG_IsCopy) != 0; } void SetCopy(bool Set) { @@ -234,7 +274,8 @@ public: } } - [[nodiscard]] bool IsShared() const { + [[nodiscard]] + bool IsShared() const { return (Flags & FLAG_Shared) != 0; } void SetShared(bool Set) { @@ -245,94 +286,112 @@ public: } } - [[nodiscard]] NodeID GetID(const OrderedNode *Node) const { + [[nodiscard]] + NodeID GetID(const OrderedNode* Node) const { return Node->Wrapped(GetListData()).ID(); } - [[nodiscard]] OrderedNode* GetHeaderNode() const { + [[nodiscard]] + OrderedNode* GetHeaderNode() const { OrderedNodeWrapper Wrapped; Wrapped.NodeOffset = sizeof(OrderedNode); return Wrapped.GetNode(GetListData()); } - [[nodiscard]] IROp_IRHeader *GetHeader() const { + [[nodiscard]] + IROp_IRHeader* GetHeader() const { return GetOp(GetHeaderNode()); } - template - [[nodiscard]] T *GetOp(OrderedNode *Node) const { + template + [[nodiscard]] + T* GetOp(OrderedNode* Node) const { auto OpHeader = Node->Op(GetData()); auto Op = OpHeader->template CW(); // If we are casting to something narrower than just the header, check the opcode. if constexpr (!std::is_same::value) { - LOGMAN_THROW_A_FMT(Op->OPCODE == Op->Header.Op, "Expected Node to be '{}'. Found '{}' instead", GetName(Op->OPCODE), GetName(Op->Header.Op)); + LOGMAN_THROW_A_FMT(Op->OPCODE == Op->Header.Op, "Expected Node to be '{}'. Found '{}' instead", GetName(Op->OPCODE), + GetName(Op->Header.Op)); } return Op; } - template - [[nodiscard]] T *GetOp(OrderedNodeWrapper Wrapper) const { + template + [[nodiscard]] + T* GetOp(OrderedNodeWrapper Wrapper) const { auto Node = Wrapper.GetNode(GetListData()); return GetOp(Node); } - [[nodiscard]] OrderedNode* GetNode(OrderedNodeWrapper Wrapper) const { + [[nodiscard]] + OrderedNode* GetNode(OrderedNodeWrapper Wrapper) const { return Wrapper.GetNode(GetListData()); } ///< Gets an OrderedNode from the IRListView as an OrderedNodeWrapper. - [[nodiscard]] OrderedNodeWrapper WrapNode(OrderedNode *Node) const { + [[nodiscard]] + OrderedNodeWrapper WrapNode(OrderedNode* Node) const { return Node->Wrapped(GetListData()); } private: struct BlockRange { using iterator = NodeIterator; - const IRListView *View; + const IRListView* View; - BlockRange(const IRListView *parent) : View(parent) {}; + BlockRange(const IRListView* parent) + : View(parent) {}; - [[nodiscard]] iterator begin() const noexcept { + [[nodiscard]] + iterator begin() const noexcept { auto Header = View->GetHeader(); return iterator(View->GetListData(), View->GetData(), Header->Blocks); } - [[nodiscard]] iterator end() const noexcept { + [[nodiscard]] + iterator end() const noexcept { return iterator(View->GetListData(), View->GetData()); } }; struct CodeRange { using iterator = NodeIterator; - const IRListView *View; + const IRListView* View; const OrderedNodeWrapper BlockWrapper; - CodeRange(const IRListView *parent, OrderedNodeWrapper block) : View(parent), BlockWrapper(block) {}; + CodeRange(const IRListView* parent, OrderedNodeWrapper block) + : View(parent) + , BlockWrapper(block) {}; - [[nodiscard]] iterator begin() const noexcept { + [[nodiscard]] + iterator begin() const noexcept { auto Block = View->GetOp(BlockWrapper); return iterator(View->GetListData(), View->GetData(), Block->Begin); } - [[nodiscard]] iterator end() const noexcept { + [[nodiscard]] + iterator end() const noexcept { return iterator(View->GetListData(), View->GetData()); } }; struct AllCodeRange { using iterator = AllNodesIterator; // Diffrent Iterator - const IRListView *View; + const IRListView* View; - AllCodeRange(const IRListView *parent) : View(parent) {}; + AllCodeRange(const IRListView* parent) + : View(parent) {}; - [[nodiscard]] iterator begin() const noexcept { + [[nodiscard]] + iterator begin() const noexcept { auto Header = View->GetHeader(); return iterator(View->GetListData(), View->GetData(), Header->Blocks); } - [[nodiscard]] iterator end() const noexcept { + [[nodiscard]] + iterator end() const noexcept { return iterator(View->GetListData(), View->GetData()); } }; @@ -340,19 +399,23 @@ private: public: using iterator = NodeIterator; - [[nodiscard]] BlockRange GetBlocks() const { + [[nodiscard]] + BlockRange GetBlocks() const { return BlockRange(this); } - [[nodiscard]] CodeRange GetCode(const OrderedNode *block) const { + [[nodiscard]] + CodeRange GetCode(const OrderedNode* block) const { return CodeRange(this, block->Wrapped(GetListData())); } - [[nodiscard]] AllCodeRange GetAllCode() const { + [[nodiscard]] + AllCodeRange GetAllCode() const { return AllCodeRange(this); } - [[nodiscard]] iterator begin() const noexcept { + [[nodiscard]] + iterator begin() const noexcept { OrderedNodeWrapper Wrapped; Wrapped.NodeOffset = sizeof(OrderedNode); return iterator(GetListData(), GetData(), Wrapped); @@ -363,7 +426,8 @@ public: * * @return Our iterator sentinel to ensure ending correctly */ - [[nodiscard]] iterator end() const noexcept { + [[nodiscard]] + iterator end() const noexcept { OrderedNodeWrapper Wrapped; Wrapped.NodeOffset = 0; return iterator(GetListData(), GetData(), Wrapped); @@ -373,33 +437,38 @@ public: * @brief Convert a OrderedNodeWrapper to an interator that we can iterate over * @return Iterator for this op */ - [[nodiscard]] iterator at(OrderedNodeWrapper Wrapped) const noexcept { + [[nodiscard]] + iterator at(OrderedNodeWrapper Wrapped) const noexcept { return iterator(GetListData(), GetData(), Wrapped); } - [[nodiscard]] iterator at(NodeID ID) const noexcept { + [[nodiscard]] + iterator at(NodeID ID) const noexcept { OrderedNodeWrapper Wrapped; Wrapped.NodeOffset = ID.Value * sizeof(OrderedNode); return iterator(GetListData(), GetData(), Wrapped); } - [[nodiscard]] iterator at(const OrderedNode *Node) const noexcept { + [[nodiscard]] + iterator at(const OrderedNode* Node) const noexcept { const auto ListData = GetListData(); auto Wrapped = Node->Wrapped(ListData); return iterator(ListData, GetData(), Wrapped); } - [[nodiscard]] uintptr_t GetData() const { + [[nodiscard]] + uintptr_t GetData() const { return reinterpret_cast(IRDataInternal ? IRDataInternal : InlineData); } - [[nodiscard]] uintptr_t GetListData() const { + [[nodiscard]] + uintptr_t GetListData() const { return reinterpret_cast(ListDataInternal ? ListDataInternal : &InlineData[DataSize]); } private: - void *IRDataInternal; - void *ListDataInternal; + void* IRDataInternal; + void* ListDataInternal; size_t DataSize; size_t ListSize; uint64_t Flags {0}; @@ -413,5 +482,4 @@ struct IRListViewDeleter { } } }; -} - +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/PassManager.cpp b/FEXCore/Source/Interface/IR/PassManager.cpp index 6fa908d55..2f33cf136 100644 --- a/FEXCore/Source/Interface/IR/PassManager.cpp +++ b/FEXCore/Source/Interface/IR/PassManager.cpp @@ -66,7 +66,7 @@ void PassManager::Finalize() { } } -void PassManager::AddDefaultPasses(FEXCore::Context::ContextImpl *ctx, bool InlineConstants) { +void PassManager::AddDefaultPasses(FEXCore::Context::ContextImpl* ctx, bool InlineConstants) { FEX_CONFIG_OPT(DisablePasses, O0); if (!DisablePasses()) { @@ -80,8 +80,7 @@ void PassManager::AddDefaultPasses(FEXCore::Context::ContextImpl *ctx, bool Inli InsertPass(CreateDeadStoreElimination(ctx->HostFeatures.SupportsAVX)); InsertPass(CreatePassDeadCodeElimination()); - InsertPass(CreateConstProp( - InlineConstants, ctx->HostFeatures.SupportsTSOImm9, Is64BitMode())); + InsertPass(CreateConstProp(InlineConstants, ctx->HostFeatures.SupportsTSOImm9, Is64BitMode())); InsertPass(CreateDeadFlagCalculationEliminination()); @@ -106,20 +105,20 @@ void PassManager::InsertRegisterAllocationPass(bool SupportsAVX) { InsertPass(IR::CreateRegisterAllocationPass(GetPass("Compaction"), SupportsAVX), "RA"); } -bool PassManager::Run(IREmitter *IREmit) { +bool PassManager::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::Run"); bool Changed = false; - for (auto const &Pass : Passes) { + for (const auto& Pass : Passes) { Changed |= Pass->Run(IREmit); } #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - for (auto const &Pass : ValidationPasses) { + for (const auto& Pass : ValidationPasses) { Changed |= Pass->Run(IREmit); } #endif return Changed; } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/PassManager.h b/FEXCore/Source/Interface/IR/PassManager.h index 08efd124d..703af6e1a 100644 --- a/FEXCore/Source/Interface/IR/PassManager.h +++ b/FEXCore/Source/Interface/IR/PassManager.h @@ -18,7 +18,7 @@ $end_info$ #include namespace FEXCore::Context { - class ContextImpl; +class ContextImpl; } namespace FEXCore::HLE { @@ -32,20 +32,20 @@ class IREmitter; class Pass { public: virtual ~Pass() = default; - virtual bool Run(IREmitter *IREmit) = 0; + virtual bool Run(IREmitter* IREmit) = 0; - void RegisterPassManager(PassManager *_Manager) { + void RegisterPassManager(PassManager* _Manager) { Manager = _Manager; } protected: - PassManager *Manager; + PassManager* Manager; }; class PassManager final { friend class InlineCallOptimization; public: - void AddDefaultPasses(FEXCore::Context::ContextImpl *ctx, bool InlineConstants); + void AddDefaultPasses(FEXCore::Context::ContextImpl* ctx, bool InlineConstants); void AddDefaultValidationPasses(); Pass* InsertPass(fextl::unique_ptr Pass, fextl::string Name = "") { auto PassPtr = InsertAt(Passes.end(), std::move(Pass))->get(); @@ -58,7 +58,7 @@ public: void InsertRegisterAllocationPass(bool SupportsAVX); - bool Run(IREmitter *IREmit); + bool Run(IREmitter* IREmit); bool HasPass(fextl::string Name) const { return NameToPassMaping.contains(Name); @@ -73,14 +73,14 @@ public: return NameToPassMaping[Name]; } - void RegisterSyscallHandler(FEXCore::HLE::SyscallHandler *Handler) { + void RegisterSyscallHandler(FEXCore::HLE::SyscallHandler* Handler) { SyscallHandler = Handler; } void Finalize(); protected: - FEXCore::HLE::SyscallHandler *SyscallHandler; + FEXCore::HLE::SyscallHandler* SyscallHandler; private: using PassArrayType = fextl::vector>; @@ -106,5 +106,4 @@ private: FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); FEX_CONFIG_OPT(PassManagerDumpIR, PASSMANAGERDUMPIR); }; -} - +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes.h b/FEXCore/Source/Interface/IR/Passes.h index 770fa7ae1..4178b3453 100644 --- a/FEXCore/Source/Interface/IR/Passes.h +++ b/FEXCore/Source/Interface/IR/Passes.h @@ -4,7 +4,7 @@ #include namespace FEXCore { - class CPUIDEmu; +class CPUIDEmu; } namespace FEXCore::Utils { @@ -16,27 +16,23 @@ class Pass; class RegisterAllocationPass; class RegisterAllocationData; -fextl::unique_ptr -CreateConstProp(bool InlineConstants, bool SupportsTSOImm9, bool Is64BitMode); +fextl::unique_ptr CreateConstProp(bool InlineConstants, bool SupportsTSOImm9, bool Is64BitMode); fextl::unique_ptr CreateContextLoadStoreElimination(bool SupportsAVX); fextl::unique_ptr CreateInlineCallOptimization(const FEXCore::CPUIDEmu* CPUID); fextl::unique_ptr CreateDeadFlagCalculationEliminination(); fextl::unique_ptr CreateDeadStoreElimination(bool SupportsAVX); fextl::unique_ptr CreatePassDeadCodeElimination(); -fextl::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator); -fextl::unique_ptr -CreateRegisterAllocationPass(FEXCore::IR::Pass *CompactionPass, - bool SupportsAVX); +fextl::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator& Allocator); +fextl::unique_ptr CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool SupportsAVX); fextl::unique_ptr CreateLongDivideEliminationPass(); namespace Validation { -fextl::unique_ptr CreateIRValidation(); -fextl::unique_ptr CreateRAValidation(); -fextl::unique_ptr CreateValueDominanceValidation(); -} + fextl::unique_ptr CreateIRValidation(); + fextl::unique_ptr CreateRAValidation(); + fextl::unique_ptr CreateValueDominanceValidation(); +} // namespace Validation namespace Debug { -fextl::unique_ptr CreateIRDumper(); + fextl::unique_ptr CreateIRDumper(); } -} - +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index 3e45670ad..38277b5ae 100644 --- a/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -7,7 +7,7 @@ $end_info$ */ -//aarch64 heuristics +// aarch64 heuristics #include "aarch64/assembler-aarch64.h" #include "aarch64/cpu-aarch64.h" #include "aarch64/disasm-aarch64.h" @@ -57,11 +57,18 @@ static bool HasConsecutiveBits(uint64_t imm, unsigned width) { return ((imm ^ (imm >> 1)) & ((1ULL << (width - 1)) - 1)) == 0; } -//aarch64 heuristics -static bool IsImmLogical(uint64_t imm, unsigned width) { if (width < 32) width = 32; return vixl::aarch64::Assembler::IsImmLogical(imm, width); } -static bool IsImmAddSub(uint64_t imm) { return vixl::aarch64::Assembler::IsImmAddSub(imm); } +// aarch64 heuristics +static bool IsImmLogical(uint64_t imm, unsigned width) { + if (width < 32) { + width = 32; + } + return vixl::aarch64::Assembler::IsImmLogical(imm, width); +} +static bool IsImmAddSub(uint64_t imm) { + return vixl::aarch64::Assembler::IsImmAddSub(imm); +} static bool IsMemoryScale(uint64_t Scale, uint8_t AccessSize) { - return Scale == AccessSize; + return Scale == AccessSize; } static bool IsSIMM9Range(uint64_t imm) { @@ -72,31 +79,28 @@ static bool IsSIMM9Range(uint64_t imm) { } static bool IsImmMemory(uint64_t imm, uint8_t AccessSize) { - if (IsSIMM9Range(imm)) + if (IsSIMM9Range(imm)) { return true; - else if ( (imm & (AccessSize-1)) == 0 && imm/AccessSize <= 4095 ) + } else if ((imm & (AccessSize - 1)) == 0 && imm / AccessSize <= 4095) { return true; - else { + } else { return false; } } static bool IsTSOImm9(uint64_t imm) { // RCPC2 only has a 9-bit signed offset - if (IsSIMM9Range(imm)) + if (IsSIMM9Range(imm)) { return true; - else { + } else { return false; } } -using MemExtendedAddrResult = - std::tuple; +using MemExtendedAddrResult = std::tuple; // If this optimization doesn't succeed, it will return the nullopt -static std::optional -MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, - IROp_Header *AddressHeader) { +static std::optional MemExtendedAddressing(IREmitter* IREmit, uint8_t AccessSize, IROp_Header* AddressHeader) { // Try to optimize: AddShift Base, LSHL(Offset, Scale) if (AddressHeader->Op == OP_ADDSHIFT) { auto AddShift = AddressHeader->C(); @@ -105,13 +109,9 @@ MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, if (IsMemoryScale(Scale, AccessSize)) { // remove shift as it can be folded to the mem op return std::make_optional( - std::make_tuple(MEM_OFFSET_SXTX, (uint8_t)Scale, - IREmit->UnwrapNode(AddShift->Src2), - IREmit->UnwrapNode(AddShift->Src1))); + std::make_tuple(MEM_OFFSET_SXTX, (uint8_t)Scale, IREmit->UnwrapNode(AddShift->Src2), IREmit->UnwrapNode(AddShift->Src1))); } else if (Scale == 1) { - return std::make_optional(std::make_tuple( - MEM_OFFSET_SXTX, 1, IREmit->UnwrapNode(AddShift->Src2), - IREmit->UnwrapNode(AddShift->Src1))); + return std::make_optional(std::make_tuple(MEM_OFFSET_SXTX, 1, IREmit->UnwrapNode(AddShift->Src2), IREmit->UnwrapNode(AddShift->Src1))); } } @@ -127,15 +127,12 @@ MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, if (IREmit->IsValueConstant(Src0Header->Args[1], &Scale)) { if (IsMemoryScale(Scale, AccessSize)) { // remove mul as it can be folded to the mem op - return std::make_optional( - std::make_tuple(MEM_OFFSET_SXTX, (uint8_t)Scale, - IREmit->UnwrapNode(AddressHeader->Args[1]), - IREmit->UnwrapNode(Src0Header->Args[0]))); + return std::make_optional(std::make_tuple(MEM_OFFSET_SXTX, (uint8_t)Scale, IREmit->UnwrapNode(AddressHeader->Args[1]), + IREmit->UnwrapNode(Src0Header->Args[0]))); } else if (Scale == 1) { // remove nop mul - return std::make_optional(std::make_tuple( - MEM_OFFSET_SXTX, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), - IREmit->UnwrapNode(Src0Header->Args[0]))); + return std::make_optional( + std::make_tuple(MEM_OFFSET_SXTX, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), IREmit->UnwrapNode(Src0Header->Args[0]))); } } } @@ -143,18 +140,15 @@ MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, else if (Src0Header->Op == OP_LSHL) { uint64_t Constant2; if (IREmit->IsValueConstant(Src0Header->Args[1], &Constant2)) { - uint64_t Scale = 1<UnwrapNode(AddressHeader->Args[1]), - IREmit->UnwrapNode(Src0Header->Args[0]))); + std::make_tuple(MEM_OFFSET_SXTX, Scale, IREmit->UnwrapNode(AddressHeader->Args[1]), IREmit->UnwrapNode(Src0Header->Args[0]))); } else if (Scale == 1) { // remove nop shift - return std::make_optional(std::make_tuple( - MEM_OFFSET_SXTX, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), - IREmit->UnwrapNode(Src0Header->Args[0]))); + return std::make_optional( + std::make_tuple(MEM_OFFSET_SXTX, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), IREmit->UnwrapNode(Src0Header->Args[0]))); } } } @@ -163,10 +157,9 @@ MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, else if (Src0Header->Op == OP_BFE) { auto Bfe = Src0Header->C(); if (Bfe->lsb == 0 && Bfe->Width == 32) { - //todo: arm can also scale here - return std::make_optional(std::make_tuple( - MEM_OFFSET_UXTW, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), - IREmit->UnwrapNode(Src0Header->Args[0]))); + // todo: arm can also scale here + return std::make_optional( + std::make_tuple(MEM_OFFSET_UXTW, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), IREmit->UnwrapNode(Src0Header->Args[0]))); } } // Try to optimize: Base + (s32)Offset @@ -174,9 +167,8 @@ MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, auto Sbfe = Src0Header->C(); if (Sbfe->lsb == 0 && Sbfe->Width == 32) { // todo: arm can also scale here - return std::make_optional(std::make_tuple( - MEM_OFFSET_SXTW, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), - IREmit->UnwrapNode(Src0Header->Args[0]))); + return std::make_optional( + std::make_tuple(MEM_OFFSET_SXTW, 1, IREmit->UnwrapNode(AddressHeader->Args[1]), IREmit->UnwrapNode(Src0Header->Args[0]))); } } #endif @@ -194,8 +186,8 @@ MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, // Only optimize in 32bits reg+const where const < 16Kb. if (Arg1H->Size == 4 && IREmit->IsValueConstant(Arg1_, &ConstVal)) { // Base is Arg0, Constant (Displacement in Arg1) - OrderedNode *Base = Arg0; - OrderedNode *Cnt = Arg1; + OrderedNode* Base = Arg0; + OrderedNode* Cnt = Arg1; int32_t Val32 = (int32_t)ConstVal; if (Val32 > -16384 && Val32 < 0) { @@ -218,7 +210,7 @@ MemExtendedAddressing(IREmitter *IREmit, uint8_t AccessSize, return std::nullopt; } -static OrderedNodeWrapper RemoveUselessMasking(IREmitter *IREmit, OrderedNodeWrapper src, uint64_t mask) { +static OrderedNodeWrapper RemoveUselessMasking(IREmitter* IREmit, OrderedNodeWrapper src, uint64_t mask) { #if 1 // HOTFIX: We need to clear up the meaning of opsize and dest size. See #594 return src; #else @@ -232,8 +224,8 @@ static OrderedNodeWrapper RemoveUselessMasking(IREmitter *IREmit, OrderedNodeWra } else if (IROp->Op == OP_BFE) { auto Op = IROp->C(); if (Op->lsb == 0) { - uint64_t imm = 1ULL << (Op->Width-1); - imm = (imm-1) *2 + 1; + uint64_t imm = 1ULL << (Op->Width - 1); + imm = (imm - 1) * 2 + 1; if ((imm & mask) == mask) { return RemoveUselessMasking(IREmit, IROp->Args[0], mask); @@ -245,7 +237,7 @@ static OrderedNodeWrapper RemoveUselessMasking(IREmitter *IREmit, OrderedNodeWra #endif } -static bool IsBfeAlreadyDone(IREmitter *IREmit, OrderedNodeWrapper src, uint64_t Width) { +static bool IsBfeAlreadyDone(IREmitter* IREmit, OrderedNodeWrapper src, uint64_t Width) { auto IROp = IREmit->GetOpHeader(src); if (IROp->Op == OP_BFE) { auto Op = IROp->C(); @@ -258,26 +250,24 @@ static bool IsBfeAlreadyDone(IREmitter *IREmit, OrderedNodeWrapper src, uint64_t class ConstProp final : public FEXCore::IR::Pass { public: - explicit ConstProp(bool DoInlineConstants, bool SupportsTSOImm9, - bool Is64BitMode) - : InlineConstants(DoInlineConstants), SupportsTSOImm9{SupportsTSOImm9}, - Is64BitMode(Is64BitMode) {} + explicit ConstProp(bool DoInlineConstants, bool SupportsTSOImm9, bool Is64BitMode) + : InlineConstants(DoInlineConstants) + , SupportsTSOImm9 {SupportsTSOImm9} + , Is64BitMode(Is64BitMode) {} - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; bool InlineConstants; private: - bool HandleConstantPools(IREmitter *IREmit, const IRListView& CurrentIR); - void LoadMemStoreMemImmediatePooling(IREmitter *IREmit, const IRListView& CurrentIR); - bool ZextAndMaskingElimination(IREmitter *IREmit, const IRListView& CurrentIR, - OrderedNode* CodeNode, IROp_Header* IROp); - bool ConstantPropagation(IREmitter *IREmit, const IRListView& CurrentIR, - OrderedNode* CodeNode, IROp_Header* IROp); - bool ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR); + bool HandleConstantPools(IREmitter* IREmit, const IRListView& CurrentIR); + void LoadMemStoreMemImmediatePooling(IREmitter* IREmit, const IRListView& CurrentIR); + bool ZextAndMaskingElimination(IREmitter* IREmit, const IRListView& CurrentIR, OrderedNode* CodeNode, IROp_Header* IROp); + bool ConstantPropagation(IREmitter* IREmit, const IRListView& CurrentIR, OrderedNode* CodeNode, IROp_Header* IROp); + bool ConstantInlining(IREmitter* IREmit, const IRListView& CurrentIR); struct ConstPoolData { - OrderedNode *Node; + OrderedNode* Node; IR::NodeID NodeID; }; fextl::unordered_map ConstPool; @@ -285,7 +275,7 @@ private: // Pool inline constant generation. These are typically very small and pool efficiently. fextl::robin_map InlineConstantGen; - OrderedNode *CreateInlineConstant(IREmitter *IREmit, uint64_t Constant) { + OrderedNode* CreateInlineConstant(IREmitter* IREmit, uint64_t Constant) { const auto it = InlineConstantGen.find(Constant); if (it != InlineConstantGen.end()) { return it->second; @@ -293,7 +283,7 @@ private: auto Result = InlineConstantGen.insert_or_assign(Constant, IREmit->_InlineConstant(Constant)); return Result.first->second; } - bool SupportsTSOImm9{}; + bool SupportsTSOImm9 {}; bool Is64BitMode; // This is a heuristic to limit constant pool live ranges to reduce RA interference pressure. // If the range is unbounded then RA interference pressure seems to increase to the point @@ -302,7 +292,7 @@ private: constexpr static uint32_t CONSTANT_POOL_RANGE_LIMIT = 200; }; -bool ConstProp::HandleConstantPools(IREmitter *IREmit, const IRListView& CurrentIR) { +bool ConstProp::HandleConstantPools(IREmitter* IREmit, const IRListView& CurrentIR) { bool Changed = false; // constants are pooled per block @@ -343,7 +333,7 @@ bool ConstProp::HandleConstantPools(IREmitter *IREmit, const IRListView& Current // LoadMem / StoreMem imm pooling // If imms are close by, use address gen to generate the values instead of using a new imm -void ConstProp::LoadMemStoreMemImmediatePooling(IREmitter *IREmit, const IRListView& CurrentIR) { +void ConstProp::LoadMemStoreMemImmediatePooling(IREmitter* IREmit, const IRListView& CurrentIR) { for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { if (IROp->Op == OP_LOADMEM || IROp->Op == OP_STOREMEM) { @@ -353,15 +343,14 @@ void ConstProp::LoadMemStoreMemImmediatePooling(IREmitter *IREmit, const IRListV if (IROp->Op == OP_LOADMEM) { AddrIndex = IR::IROp_LoadMem::Addr_Index; OffsetIndex = IR::IROp_LoadMem::Offset_Index; - } - else { + } else { AddrIndex = IR::IROp_StoreMem::Addr_Index; OffsetIndex = IR::IROp_StoreMem::Offset_Index; } uint64_t Addr; if (IREmit->IsValueConstant(IROp->Args[AddrIndex], &Addr) && IROp->Args[OffsetIndex].IsInvalid()) { - for (auto& Const: AddressgenConsts) { + for (auto& Const : AddressgenConsts) { if ((Addr - Const.second) < 65536) { IREmit->ReplaceNodeArgument(CodeNode, AddrIndex, Const.first); IREmit->ReplaceNodeArgument(CodeNode, OffsetIndex, IREmit->_Constant(Addr - Const.second)); @@ -371,8 +360,7 @@ void ConstProp::LoadMemStoreMemImmediatePooling(IREmitter *IREmit, const IRListV AddressgenConsts[IREmit->UnwrapNode(IROp->Args[AddrIndex])] = Addr; } - doneOp: - ; +doneOp:; } IREmit->SetWriteCursor(CodeNode); } @@ -380,229 +368,915 @@ void ConstProp::LoadMemStoreMemImmediatePooling(IREmitter *IREmit, const IRListV } } -bool ConstProp::ZextAndMaskingElimination(IREmitter *IREmit, const IRListView& CurrentIR, - OrderedNode* CodeNode, IROp_Header* IROp) { +bool ConstProp::ZextAndMaskingElimination(IREmitter* IREmit, const IRListView& CurrentIR, OrderedNode* CodeNode, IROp_Header* IROp) { bool Changed = false; switch (IROp->Op) { - // Generic handling - case OP_OR: - case OP_XOR: - case OP_NOT: - case OP_ADD: - case OP_SUB: - case OP_MUL: - case OP_UMUL: - case OP_DIV: - case OP_UDIV: - case OP_LSHR: - case OP_ASHR: - case OP_LSHL: - case OP_ROR: { - for (int i = 0; i < IR::GetArgs(IROp->Op); i++) { - auto newArg = RemoveUselessMasking(IREmit, IROp->Args[i], getMask(IROp)); - if (newArg.ID() != IROp->Args[i].ID()) { - IREmit->ReplaceNodeArgument(CodeNode, i, IREmit->UnwrapNode(newArg)); - Changed = true; - } - } - break; - } - case OP_AND: { - // if AND's arguments are imms, they are masking - for (int i = 0; i < IR::GetArgs(IROp->Op); i++) { - uint64_t imm = 0; - if (!IREmit->IsValueConstant(IROp->Args[i^1], &imm)) - continue; - - auto newArg = RemoveUselessMasking(IREmit, IROp->Args[i], imm); - - if (newArg.ID() != IROp->Args[i].ID()) { - IREmit->ReplaceNodeArgument(CodeNode, i, IREmit->UnwrapNode(newArg)); - Changed = true; - } - } - break; - } - - case OP_BFE: { - auto Op = IROp->C(); - - // Is this value already BFE'd? - if (IsBfeAlreadyDone(IREmit, Op->Src, Op->Width)) { - IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Src)); - //printf("Removed BFE once \n"); - break; - } - - // Is this value already ZEXT'd? - if (Op->lsb == 0) { - //LoadMem, LoadMemTSO & LoadContext ZExt - auto source = Op->Src; - auto sourceHeader = IREmit->GetOpHeader(source); - - if (Op->Width >= (sourceHeader->Size*8) && - (sourceHeader->Op == OP_LOADMEM || sourceHeader->Op == OP_LOADMEMTSO || sourceHeader->Op == OP_LOADCONTEXT) - ) { - //printf("Eliminated needless zext bfe\n"); - // Load mem / load ctx zexts, no need to vmem - IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(source)); - break; - } - } - - // BFE does implicit masking, remove any masks leading to this, if possible - uint64_t imm = 1ULL << (Op->Width-1); - imm = (imm-1) *2 + 1; - imm <<= Op->lsb; - - auto newArg = RemoveUselessMasking(IREmit, Op->Src, imm); - - if (newArg.ID() != Op->Src.ID()) { - IREmit->ReplaceNodeArgument(CodeNode, Op->Src_Index, IREmit->UnwrapNode(newArg)); + // Generic handling + case OP_OR: + case OP_XOR: + case OP_NOT: + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_UMUL: + case OP_DIV: + case OP_UDIV: + case OP_LSHR: + case OP_ASHR: + case OP_LSHL: + case OP_ROR: { + for (int i = 0; i < IR::GetArgs(IROp->Op); i++) { + auto newArg = RemoveUselessMasking(IREmit, IROp->Args[i], getMask(IROp)); + if (newArg.ID() != IROp->Args[i].ID()) { + IREmit->ReplaceNodeArgument(CodeNode, i, IREmit->UnwrapNode(newArg)); Changed = true; } - break; } + break; + } + case OP_AND: { + // if AND's arguments are imms, they are masking + for (int i = 0; i < IR::GetArgs(IROp->Op); i++) { + uint64_t imm = 0; + if (!IREmit->IsValueConstant(IROp->Args[i ^ 1], &imm)) { + continue; + } - case OP_SBFE: { - auto Op = IROp->C(); + auto newArg = RemoveUselessMasking(IREmit, IROp->Args[i], imm); - // BFE does implicit masking - uint64_t imm = 1ULL << (Op->Width-1); - imm = (imm-1) *2 + 1; - imm <<= Op->lsb; - - auto newArg = RemoveUselessMasking(IREmit, Op->Src, imm); - - if (newArg.ID() != Op->Src.ID()) { - IREmit->ReplaceNodeArgument(CodeNode, Op->Src_Index, IREmit->UnwrapNode(newArg)); + if (newArg.ID() != IROp->Args[i].ID()) { + IREmit->ReplaceNodeArgument(CodeNode, i, IREmit->UnwrapNode(newArg)); Changed = true; } + } + break; + } + + case OP_BFE: { + auto Op = IROp->C(); + + // Is this value already BFE'd? + if (IsBfeAlreadyDone(IREmit, Op->Src, Op->Width)) { + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Src)); + // printf("Removed BFE once \n"); break; } - case OP_VMOV: { - // elim from load mem - auto source = IROp->Args[0]; + // Is this value already ZEXT'd? + if (Op->lsb == 0) { + // LoadMem, LoadMemTSO & LoadContext ZExt + auto source = Op->Src; auto sourceHeader = IREmit->GetOpHeader(source); - if (IROp->Size >= sourceHeader->Size && - (sourceHeader->Op == OP_LOADMEM || sourceHeader->Op == OP_LOADMEMTSO || sourceHeader->Op == OP_LOADCONTEXT) - ) { - //printf("Eliminated needless zext VMOV\n"); - // Load mem / load ctx zexts, no need to vmem + if (Op->Width >= (sourceHeader->Size * 8) && + (sourceHeader->Op == OP_LOADMEM || sourceHeader->Op == OP_LOADMEMTSO || sourceHeader->Op == OP_LOADCONTEXT)) { + // printf("Eliminated needless zext bfe\n"); + // Load mem / load ctx zexts, no need to vmem IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(source)); - } else if (IROp->Size == sourceHeader->Size) { - // VMOV of same size - // XXX: This is unsafe of an optimization since in some cases we can't see through garbage data in the upper bits of a vector - // RCLSE generates VMOV instructions which are being used as a zero extension - //printf("printf vmov of same size?!\n"); - //IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(source)); + break; } - break; } - default: - break; + + // BFE does implicit masking, remove any masks leading to this, if possible + uint64_t imm = 1ULL << (Op->Width - 1); + imm = (imm - 1) * 2 + 1; + imm <<= Op->lsb; + + auto newArg = RemoveUselessMasking(IREmit, Op->Src, imm); + + if (newArg.ID() != Op->Src.ID()) { + IREmit->ReplaceNodeArgument(CodeNode, Op->Src_Index, IREmit->UnwrapNode(newArg)); + Changed = true; + } + break; + } + + case OP_SBFE: { + auto Op = IROp->C(); + + // BFE does implicit masking + uint64_t imm = 1ULL << (Op->Width - 1); + imm = (imm - 1) * 2 + 1; + imm <<= Op->lsb; + + auto newArg = RemoveUselessMasking(IREmit, Op->Src, imm); + + if (newArg.ID() != Op->Src.ID()) { + IREmit->ReplaceNodeArgument(CodeNode, Op->Src_Index, IREmit->UnwrapNode(newArg)); + Changed = true; + } + break; + } + + case OP_VMOV: { + // elim from load mem + auto source = IROp->Args[0]; + auto sourceHeader = IREmit->GetOpHeader(source); + + if (IROp->Size >= sourceHeader->Size && + (sourceHeader->Op == OP_LOADMEM || sourceHeader->Op == OP_LOADMEMTSO || sourceHeader->Op == OP_LOADCONTEXT)) { + // printf("Eliminated needless zext VMOV\n"); + // Load mem / load ctx zexts, no need to vmem + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(source)); + } else if (IROp->Size == sourceHeader->Size) { + // VMOV of same size + // XXX: This is unsafe of an optimization since in some cases we can't see through garbage data in the upper bits of a vector + // RCLSE generates VMOV instructions which are being used as a zero extension + // printf("printf vmov of same size?!\n"); + // IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(source)); + } + break; + } + default: break; } return Changed; } // constprop + some more per instruction logic -bool ConstProp::ConstantPropagation(IREmitter *IREmit, const IRListView& CurrentIR, - OrderedNode* CodeNode, IROp_Header* IROp) { - bool Changed = false; +bool ConstProp::ConstantPropagation(IREmitter* IREmit, const IRListView& CurrentIR, OrderedNode* CodeNode, IROp_Header* IROp) { + bool Changed = false; + switch (IROp->Op) { + case OP_LOADMEMTSO: { + auto Op = IROp->CW(); + auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + + if (Op->Class == FEXCore::IR::FPRClass && AddressHeader->Op == OP_ADD && AddressHeader->Size == 8) { + // TODO: LRCPC3 supports a vector unscaled offset like LRCPC2. + // Support once hardware is available to use this. + auto MaybeMemAddr = MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); + if (!MaybeMemAddr) { + break; + } + auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; + Op->OffsetType = OffsetType; + Op->OffsetScale = OffsetScale; + IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + + Changed = true; + } + break; + } + + case OP_STOREMEMTSO: { + auto Op = IROp->CW(); + auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + + if (Op->Class == FEXCore::IR::FPRClass && AddressHeader->Op == OP_ADD && AddressHeader->Size == 8) { + // TODO: LRCPC3 supports a vector unscaled offset like LRCPC2. + // Support once hardware is available to use this. + auto MaybeMemAddr = MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); + if (!MaybeMemAddr) { + break; + } + auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; + Op->OffsetType = OffsetType; + Op->OffsetScale = OffsetScale; + IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + + Changed = true; + } + break; + } + + case OP_LOADMEM: { + auto Op = IROp->CW(); + auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + + if (AddressHeader->Op == OP_ADD && ((Is64BitMode && AddressHeader->Size == 8) || (!Is64BitMode && AddressHeader->Size == 4))) { + auto MaybeMemAddr = MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); + if (!MaybeMemAddr) { + break; + } + auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; + + Op->OffsetType = OffsetType; + Op->OffsetScale = OffsetScale; + IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + + Changed = true; + } + break; + } + + case OP_STOREMEM: { + auto Op = IROp->CW(); + auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + + if (AddressHeader->Op == OP_ADD && ((Is64BitMode && AddressHeader->Size == 8) || (!Is64BitMode && AddressHeader->Size == 4))) { + auto MaybeMemAddr = MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); + if (!MaybeMemAddr) { + break; + } + auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; + + Op->OffsetType = OffsetType; + Op->OffsetScale = OffsetScale; + IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + + Changed = true; + } + break; + } + + case OP_PREFETCH: { + auto Op = IROp->CW(); + auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + + const bool SupportedOp = AddressHeader->Op == OP_ADD || AddressHeader->Op == OP_ADDSHIFT; + + if (SupportedOp && ((Is64BitMode && AddressHeader->Size == 8) || (!Is64BitMode && AddressHeader->Size == 4))) { + auto MaybeMemAddr = MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); + if (!MaybeMemAddr) { + break; + } + auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; + + Op->OffsetType = OffsetType; + Op->OffsetScale = OffsetScale; + IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + + Changed = true; + } + break; + } + + case OP_ADD: + case OP_SUB: + case OP_ADDWITHFLAGS: + case OP_SUBWITHFLAGS: { + auto Op = IROp->C(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + bool IsConstant1 = IREmit->IsValueConstant(Op->Header.Args[0], &Constant1); + bool IsConstant2 = IREmit->IsValueConstant(Op->Header.Args[1], &Constant2); + + if (IsConstant1 && IsConstant2 && IROp->Op == OP_ADD) { + uint64_t NewConstant = (Constant1 + Constant2) & getMask(Op); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (IsConstant1 && IsConstant2 && IROp->Op == OP_SUB) { + uint64_t NewConstant = (Constant1 - Constant2) & getMask(Op); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (IsConstant2 && !IsImmAddSub(Constant2) && IsImmAddSub(-Constant2)) { + // If the second argument is constant, the immediate is not ImmAddSub, but when negated is. + // So, negate the operation to negate (and inline) the constant. + if (IROp->Op == OP_ADD) { + IROp->Op = OP_SUB; + } else if (IROp->Op == OP_SUB) { + IROp->Op = OP_ADD; + } else if (IROp->Op == OP_ADDWITHFLAGS) { + IROp->Op = OP_SUBWITHFLAGS; + } else if (IROp->Op == OP_SUBWITHFLAGS) { + IROp->Op = OP_ADDWITHFLAGS; + } + + // Set the write cursor to just before this operation. + auto CodeIter = CurrentIR.at(CodeNode); + --CodeIter; + IREmit->SetWriteCursor(std::get<0>(*CodeIter)); + + // Negate the constant. + auto NegConstant = IREmit->_Constant(-Constant2); + + // Replace the second source with the negated constant. + IREmit->ReplaceNodeArgument(CodeNode, Op->Src2_Index, NegConstant); + Changed = true; + } + break; + } + case OP_SUBSHIFT: { + auto Op = IROp->C(); + + uint64_t Constant1, Constant2; + if (IREmit->IsValueConstant(IROp->Args[0], &Constant1) && IREmit->IsValueConstant(IROp->Args[1], &Constant2) && + Op->Shift == IR::ShiftType::LSL) { + // Optimize the LSL case when we know both sources are constant. + // This is a pattern that shows up with direction flag calculations if DF was set just before the operation. + uint64_t NewConstant = (Constant1 - (Constant2 << Op->ShiftAmount)) & getMask(Op); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } + break; + } + case OP_AND: { + auto Op = IROp->CW(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = (Constant1 & Constant2) & getMask(Op); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (Constant2 == 1) { + // happens from flag calcs + auto val = IREmit->GetOpHeader(Op->Header.Args[0]); + + uint64_t Constant3; + if (val->Op == OP_SELECT && IREmit->IsValueConstant(val->Args[2], &Constant2) && IREmit->IsValueConstant(val->Args[3], &Constant3) && + Constant2 == 1 && Constant3 == 0) { + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); + Changed = true; + } + } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { + // AND with same value results in original value + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); + Changed = true; + } + break; + } + case OP_OR: { + auto Op = IROp->CW(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = Constant1 | Constant2; + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { + // OR with same value results in original value + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); + Changed = true; + } + break; + } + case OP_ORLSHL: { + auto Op = IROp->CW(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = Constant1 | (Constant2 << Op->BitShift); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } + break; + } + case OP_ORLSHR: { + auto Op = IROp->CW(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = Constant1 | (Constant2 >> Op->BitShift); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } + break; + } + case OP_XOR: { + auto Op = IROp->C(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = Constant1 ^ Constant2; + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { + // XOR with same value results to zero + IREmit->SetWriteCursor(CodeNode); + IREmit->ReplaceAllUsesWith(CodeNode, IREmit->_Constant(0)); + Changed = true; + } else { + // XOR with zero results in the nonzero source + for (unsigned i = 0; i < 2; ++i) { + if (!IREmit->IsValueConstant(Op->Header.Args[i], &Constant1)) { + continue; + } + + if (Constant1 != 0) { + continue; + } + + IREmit->SetWriteCursor(CodeNode); + OrderedNode* Arg = CurrentIR.GetNode(Op->Header.Args[1 - i]); + IREmit->ReplaceAllUsesWith(CodeNode, Arg); + Changed = true; + break; + } + } + break; + } + case OP_NEG: { + auto Op = IROp->CW(); + uint64_t Constant {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant)) { + uint64_t NewConstant = -Constant; + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } + break; + } + case OP_LSHL: { + auto Op = IROp->CW(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + // Shifts mask the shift amount by 63 or 31 depending on operating size; + uint64_t ShiftMask = IROp->Size == 8 ? 63 : 31; + uint64_t NewConstant = (Constant1 << (Constant2 & ShiftMask)) & getMask(Op); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && Constant2 == 0) { + IREmit->SetWriteCursor(CodeNode); + OrderedNode* Arg = CurrentIR.GetNode(Op->Header.Args[0]); + IREmit->ReplaceAllUsesWith(CodeNode, Arg); + Changed = true; + } else { + auto newArg = RemoveUselessMasking(IREmit, Op->Header.Args[1], IROp->Size * 8 - 1); + if (newArg.ID() != Op->Header.Args[1].ID()) { + IREmit->ReplaceNodeArgument(CodeNode, 1, IREmit->UnwrapNode(newArg)); + Changed = true; + } + } + break; + } + case OP_LSHR: { + auto Op = IROp->CW(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + // Shifts mask the shift amount by 63 or 31 depending on operating size; + uint64_t ShiftMask = IROp->Size == 8 ? 63 : 31; + uint64_t NewConstant = (Constant1 >> (Constant2 & ShiftMask)) & getMask(Op); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && Constant2 == 0) { + IREmit->SetWriteCursor(CodeNode); + OrderedNode* Arg = CurrentIR.GetNode(Op->Header.Args[0]); + IREmit->ReplaceAllUsesWith(CodeNode, Arg); + Changed = true; + } else { + auto newArg = RemoveUselessMasking(IREmit, Op->Header.Args[1], IROp->Size * 8 - 1); + if (newArg.ID() != Op->Header.Args[1].ID()) { + IREmit->ReplaceNodeArgument(CodeNode, 1, IREmit->UnwrapNode(newArg)); + Changed = true; + } + } + break; + } + case OP_BFE: { + auto Op = IROp->C(); + uint64_t Constant; + if (IROp->Size <= 8 && IREmit->IsValueConstant(Op->Src, &Constant)) { + uint64_t SourceMask = Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); + SourceMask <<= Op->lsb; + + uint64_t NewConstant = (Constant & SourceMask) >> Op->lsb; + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (IROp->Size == CurrentIR.GetOp(Op->Header.Args[0])->Size && Op->Width == (IROp->Size * 8) && Op->lsb == 0) { + // A BFE that extracts all bits results in original value + // XXX - This is broken for now - see https://github.com/FEX-Emu/FEX/issues/351 + // IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); + // Changed = true; + } else if (Op->Width == 1 && Op->lsb == 0) { + // common from flag codegen + auto val = IREmit->GetOpHeader(Op->Header.Args[0]); + + uint64_t Constant2 {}; + uint64_t Constant3 {}; + if (val->Op == OP_SELECT && IREmit->IsValueConstant(val->Args[2], &Constant2) && IREmit->IsValueConstant(val->Args[3], &Constant3) && + Constant2 == 1 && Constant3 == 0) { + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); + Changed = true; + } + } + + break; + } + case OP_SBFE: { + auto Op = IROp->C(); + uint64_t Constant; + if (IREmit->IsValueConstant(Op->Src, &Constant)) { + // SBFE of a constant can be converted to a constant. + uint64_t SourceMask = Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); + uint64_t DestSizeInBits = IROp->Size * 8; + uint64_t DestMask = DestSizeInBits == 64 ? ~0ULL : ((1ULL << DestSizeInBits) - 1); + SourceMask <<= Op->lsb; + + int64_t NewConstant = (Constant & SourceMask) >> Op->lsb; + NewConstant <<= 64 - Op->Width; + NewConstant >>= 64 - Op->Width; + NewConstant &= DestMask; + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + + Changed = true; + } + break; + } + case OP_BFI: { + auto Op = IROp->C(); + uint64_t ConstantDest {}; + uint64_t ConstantSrc {}; + bool DestIsConstant = IREmit->IsValueConstant(Op->Header.Args[0], &ConstantDest); + bool SrcIsConstant = IREmit->IsValueConstant(Op->Header.Args[1], &ConstantSrc); + + if (DestIsConstant && SrcIsConstant) { + uint64_t SourceMask = Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); + uint64_t NewConstant = ConstantDest & ~(SourceMask << Op->lsb); + NewConstant |= (ConstantSrc & SourceMask) << Op->lsb; + + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (SrcIsConstant && HasConsecutiveBits(ConstantSrc, Op->Width)) { + // We are trying to insert constant, if it is a bitfield of only set bits then we can orr or and it. + IREmit->SetWriteCursor(CodeNode); + uint64_t SourceMask = Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); + uint64_t NewConstant = SourceMask << Op->lsb; + + if (ConstantSrc & 1) { + auto orr = IREmit->_Or(IR::SizeToOpSize(IROp->Size), CurrentIR.GetNode(Op->Header.Args[0]), IREmit->_Constant(NewConstant)); + IREmit->ReplaceAllUsesWith(CodeNode, orr); + Changed = true; + } else { + // We are wanting to clear the bitfield. + auto andn = IREmit->_Andn(IR::SizeToOpSize(IROp->Size), CurrentIR.GetNode(Op->Header.Args[0]), IREmit->_Constant(NewConstant)); + IREmit->ReplaceAllUsesWith(CodeNode, andn); + Changed = true; + } + } + break; + } + case OP_MUL: { + auto Op = IROp->C(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + uint64_t NewConstant = (Constant1 * Constant2) & getMask(Op); + IREmit->ReplaceWithConstant(CodeNode, NewConstant); + Changed = true; + } else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && std::popcount(Constant2) == 1) { + if (IROp->Size == 4 || IROp->Size == 8) { + uint64_t amt = std::countr_zero(Constant2); + IREmit->SetWriteCursor(CodeNode); + auto shift = IREmit->_Lshl(IR::SizeToOpSize(IROp->Size), CurrentIR.GetNode(Op->Header.Args[0]), IREmit->_Constant(amt)); + IREmit->ReplaceAllUsesWith(CodeNode, shift); + Changed = true; + } + } + break; + } + case OP_SELECT: { + auto Op = IROp->C(); + uint64_t Constant1 {}; + uint64_t Constant2 {}; + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && Op->Cond == COND_EQ) { + + Constant1 &= getMask(Op); + Constant2 &= getMask(Op); + + bool is_true = Constant1 == Constant2; + + IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[is_true ? 2 : 3])); + Changed = true; + } + break; + } + default: break; + } + + return Changed; +} + +bool ConstProp::ConstantInlining(IREmitter* IREmit, const IRListView& CurrentIR) { + InlineConstantGen.clear(); + bool Changed = false; + + for (auto [CodeNode, IROp] : CurrentIR.GetAllCode()) { switch (IROp->Op) { - case OP_LOADMEMTSO: { - auto Op = IROp->CW(); - auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + case OP_LSHR: + case OP_ASHR: + case OP_ROR: + case OP_LSHL: { + auto Op = IROp->C(); - if (Op->Class == FEXCore::IR::FPRClass && AddressHeader->Op == OP_ADD && AddressHeader->Size == 8) { - // TODO: LRCPC3 supports a vector unscaled offset like LRCPC2. - // Support once hardware is available to use this. - auto MaybeMemAddr = - MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); - if (!MaybeMemAddr) { - break; + uint64_t Constant2 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); + + // this shouldn't be here, but rather on the emitter themselves or the constprop transformation? + if (IROp->Size <= 4) { + Constant2 &= 31; + } else { + Constant2 &= 63; } - auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; - Op->OffsetType = OffsetType; - Op->OffsetScale = OffsetScale; - IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); Changed = true; } break; } + case OP_ADD: + case OP_SUB: + case OP_ADDNZCV: + case OP_SUBNZCV: + case OP_ADDWITHFLAGS: + case OP_SUBWITHFLAGS: { + auto Op = IROp->C(); - case OP_STOREMEMTSO: { - auto Op = IROp->CW(); - auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + uint64_t Constant2 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + // We don't allow 8/16-bit operations to have constants, since no + // constant would be in bounds after the JIT's 24/16 shift. + if (IsImmAddSub(Constant2) && Op->Header.Size >= 4) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - if (Op->Class == FEXCore::IR::FPRClass && AddressHeader->Op == OP_ADD && AddressHeader->Size == 8) { - // TODO: LRCPC3 supports a vector unscaled offset like LRCPC2. - // Support once hardware is available to use this. - auto MaybeMemAddr = - MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); - if (!MaybeMemAddr) { - break; + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; } - auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; - Op->OffsetType = OffsetType; - Op->OffsetScale = OffsetScale; - IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + } else if (IROp->Op == OP_SUBNZCV || IROp->Op == OP_SUBWITHFLAGS || IROp->Op == OP_SUB) { + // TODO: Generalize this + uint64_t Constant1 {}; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { + if (Constant1 == 0) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); + IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); + Changed = true; + } + } + } - Changed = true; + break; + } + case OP_ADC: + case OP_ADCWITHFLAGS: { + auto Op = IROp->C(); + + uint64_t Constant1 {}; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { + if (Constant1 == 0) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); + IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); + Changed = true; + } + } + + break; + } + case OP_RMIFNZCV: { + auto Op = IROp->C(); + + uint64_t Constant1 {}; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { + if (Constant1 == 0) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); + IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); + Changed = true; + } + } + + break; + } + case OP_CONDADDNZCV: + case OP_CONDSUBNZCV: { + auto Op = IROp->C(); + + uint64_t Constant2 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + if (IsImmAddSub(Constant2)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); + + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; + } + } + + uint64_t Constant1 {}; + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { + if (Constant1 == 0) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); + IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); + Changed = true; + } } break; } + case OP_TESTNZ: { + auto Op = IROp->C(); + uint64_t Constant1 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant1)) { + if (IsImmLogical(Constant1, IROp->Size * 8)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); + + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant1)); + + Changed = true; + } + } + break; + } + case OP_SELECT: { + auto Op = IROp->C(); + + uint64_t Constant1 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant1)) { + if (IsImmAddSub(Constant1)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); + + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant1)); + + Changed = true; + } + } + + uint64_t AllOnes = IROp->Size == 8 ? 0xffff'ffff'ffff'ffffull : 0xffff'ffffull; + + uint64_t Constant2 {}; + uint64_t Constant3 {}; + if (IREmit->IsValueConstant(Op->Header.Args[2], &Constant2) && IREmit->IsValueConstant(Op->Header.Args[3], &Constant3) && + (Constant2 == 1 || Constant2 == AllOnes) && Constant3 == 0) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[2])); + + IREmit->ReplaceNodeArgument(CodeNode, 2, CreateInlineConstant(IREmit, Constant2)); + IREmit->ReplaceNodeArgument(CodeNode, 3, CreateInlineConstant(IREmit, Constant3)); + } + + break; + } + case OP_NZCVSELECT: { + auto Op = IROp->C(); + + uint64_t AllOnes = IROp->Size == 8 ? 0xffff'ffff'ffff'ffffull : 0xffff'ffffull; + + // We always allow source 1 to be zero, but source 0 can only be a + // special 1/~0 constant if source 1 is 0. + uint64_t Constant0 {}; + uint64_t Constant1 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant1) && Constant1 == 0) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant1)); + + if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant0) && (Constant0 == 1 || Constant0 == AllOnes)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); + + IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, Constant0)); + } + } + + break; + } + case OP_CONDJUMP: { + auto Op = IROp->C(); + + uint64_t Constant2 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + if (IsImmAddSub(Constant2)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); + + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; + } + } + break; + } + case OP_EXITFUNCTION: { + auto Op = IROp->C(); + + uint64_t Constant {}; + if (IREmit->IsValueConstant(Op->NewRIP, &Constant)) { + + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->NewRIP)); + + IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, Constant)); + + Changed = true; + } else { + auto NewRIP = IREmit->GetOpHeader(Op->NewRIP); + if (NewRIP->Op == OP_ENTRYPOINTOFFSET) { + auto EO = NewRIP->C(); + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->NewRIP)); + + IREmit->ReplaceNodeArgument(CodeNode, 0, IREmit->_InlineEntrypointOffset(IR::SizeToOpSize(EO->Header.Size), EO->Offset)); + Changed = true; + } + } + break; + } + case OP_OR: + case OP_XOR: + case OP_AND: + case OP_ANDWITHFLAGS: + case OP_ANDN: { + auto Op = IROp->CW(); + + uint64_t Constant2 {}; + if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { + if (IsImmLogical(Constant2, IROp->Size * 8)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); + + IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; + } + } + break; + } case OP_LOADMEM: { auto Op = IROp->CW(); - auto AddressHeader = IREmit->GetOpHeader(Op->Addr); - if (AddressHeader->Op == OP_ADD && - ((Is64BitMode && AddressHeader->Size == 8) || - (!Is64BitMode && AddressHeader->Size == 4))) { - auto MaybeMemAddr = - MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); - if (!MaybeMemAddr) { - break; + uint64_t Constant2 {}; + if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { + if (IsImmMemory(Constant2, IROp->Size)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); + + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; } - auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; + } + break; + } + case OP_STOREMEM: { + auto Op = IROp->CW(); - Op->OffsetType = OffsetType; - Op->OffsetScale = OffsetScale; - IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + uint64_t Constant2 {}; + if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { + if (IsImmMemory(Constant2, IROp->Size)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); + + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; + } + } + break; + } + case OP_LOADMEMTSO: { + auto Op = IROp->CW(); + + uint64_t Constant2 {}; + if (SupportsTSOImm9) { + if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { + if (IsTSOImm9(Constant2)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); + + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; + } + } + } + break; + } + case OP_STOREMEMTSO: { + auto Op = IROp->CW(); + + uint64_t Constant2 {}; + if (SupportsTSOImm9) { + if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { + if (IsTSOImm9(Constant2)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); + + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); + + Changed = true; + } + } + } + break; + } + case OP_MEMCPY: { + auto Op = IROp->CW(); + + uint64_t Constant {}; + if (IREmit->IsValueConstant(Op->Direction, &Constant)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Direction)); + + IREmit->ReplaceNodeArgument(CodeNode, Op->Direction_Index, CreateInlineConstant(IREmit, Constant)); Changed = true; } break; } + case OP_MEMSET: { + auto Op = IROp->CW(); - case OP_STOREMEM: { - auto Op = IROp->CW(); - auto AddressHeader = IREmit->GetOpHeader(Op->Addr); + uint64_t Constant {}; + if (IREmit->IsValueConstant(Op->Direction, &Constant)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Direction)); - if (AddressHeader->Op == OP_ADD && - ((Is64BitMode && AddressHeader->Size == 8) || - (!Is64BitMode && AddressHeader->Size == 4))) { - auto MaybeMemAddr = - MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); - if (!MaybeMemAddr) { - break; - } - auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; - - Op->OffsetType = OffsetType; - Op->OffsetScale = OffsetScale; - IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset + IREmit->ReplaceNodeArgument(CodeNode, Op->Direction_Index, CreateInlineConstant(IREmit, Constant)); Changed = true; } @@ -611,781 +1285,27 @@ bool ConstProp::ConstantPropagation(IREmitter *IREmit, const IRListView& Current case OP_PREFETCH: { auto Op = IROp->CW(); - auto AddressHeader = IREmit->GetOpHeader(Op->Addr); - const bool SupportedOp = - AddressHeader->Op == OP_ADD || - AddressHeader->Op == OP_ADDSHIFT; + uint64_t Constant2 {}; + if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { + if (IsImmMemory(Constant2, IROp->Size)) { + IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); - if (SupportedOp && - ((Is64BitMode && AddressHeader->Size == 8) || - (!Is64BitMode && AddressHeader->Size == 4))) { - auto MaybeMemAddr = - MemExtendedAddressing(IREmit, IROp->Size, AddressHeader); - if (!MaybeMemAddr) { - break; - } - auto [OffsetType, OffsetScale, Arg0, Arg1] = *MaybeMemAddr; + IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); - Op->OffsetType = OffsetType; - Op->OffsetScale = OffsetScale; - IREmit->ReplaceNodeArgument(CodeNode, Op->Addr_Index, Arg0); // Addr - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, Arg1); // Offset - - Changed = true; - } - break; - } - - case OP_ADD: - case OP_SUB: - case OP_ADDWITHFLAGS: - case OP_SUBWITHFLAGS: { - auto Op = IROp->C(); - uint64_t Constant1{}; - uint64_t Constant2{}; - bool IsConstant1 = IREmit->IsValueConstant(Op->Header.Args[0], &Constant1); - bool IsConstant2 = IREmit->IsValueConstant(Op->Header.Args[1], &Constant2); - - if (IsConstant1 && IsConstant2 && IROp->Op == OP_ADD) { - uint64_t NewConstant = (Constant1 + Constant2) & getMask(Op) ; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } else if (IsConstant1 && IsConstant2 && IROp->Op == OP_SUB) { - uint64_t NewConstant = (Constant1 - Constant2) & getMask(Op) ; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - else if (IsConstant2 && !IsImmAddSub(Constant2) && IsImmAddSub(-Constant2)) { - // If the second argument is constant, the immediate is not ImmAddSub, but when negated is. - // So, negate the operation to negate (and inline) the constant. - if (IROp->Op == OP_ADD) - IROp->Op = OP_SUB; - else if (IROp->Op == OP_SUB) - IROp->Op = OP_ADD; - else if (IROp->Op == OP_ADDWITHFLAGS) - IROp->Op = OP_SUBWITHFLAGS; - else if (IROp->Op == OP_SUBWITHFLAGS) - IROp->Op = OP_ADDWITHFLAGS; - - // Set the write cursor to just before this operation. - auto CodeIter = CurrentIR.at(CodeNode); - --CodeIter; - IREmit->SetWriteCursor(std::get<0>(*CodeIter)); - - // Negate the constant. - auto NegConstant = IREmit->_Constant(-Constant2); - - // Replace the second source with the negated constant. - IREmit->ReplaceNodeArgument(CodeNode, Op->Src2_Index, NegConstant); - Changed = true; - } - break; - } - case OP_SUBSHIFT: { - auto Op = IROp->C(); - - uint64_t Constant1, Constant2; - if (IREmit->IsValueConstant(IROp->Args[0], &Constant1) && - IREmit->IsValueConstant(IROp->Args[1], &Constant2) && - Op->Shift == IR::ShiftType::LSL) { - // Optimize the LSL case when we know both sources are constant. - // This is a pattern that shows up with direction flag calculations if DF was set just before the operation. - uint64_t NewConstant = (Constant1 - (Constant2 << Op->ShiftAmount)) & getMask(Op); - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - break; - } - case OP_AND: { - auto Op = IROp->CW(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = (Constant1 & Constant2) & getMask(Op) ; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } else if (Constant2 == 1) { - // happens from flag calcs - auto val = IREmit->GetOpHeader(Op->Header.Args[0]); - - uint64_t Constant3; - if (val->Op == OP_SELECT && - IREmit->IsValueConstant(val->Args[2], &Constant2) && - IREmit->IsValueConstant(val->Args[3], &Constant3) && - Constant2 == 1 && - Constant3 == 0) - { - IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); - Changed = true; - } - } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { - // AND with same value results in original value - IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); - Changed = true; - } - break; - } - case OP_OR: { - auto Op = IROp->CW(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = Constant1 | Constant2; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { - // OR with same value results in original value - IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); - Changed = true; - } - break; - } - case OP_ORLSHL: { - auto Op = IROp->CW(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = Constant1 | (Constant2 << Op->BitShift); - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - break; - } - case OP_ORLSHR: { - auto Op = IROp->CW(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = Constant1 | (Constant2 >> Op->BitShift); - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - break; - } - case OP_XOR: { - auto Op = IROp->C(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = Constant1 ^ Constant2; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } else if (Op->Header.Args[0].ID() == Op->Header.Args[1].ID()) { - // XOR with same value results to zero - IREmit->SetWriteCursor(CodeNode); - IREmit->ReplaceAllUsesWith(CodeNode, IREmit->_Constant(0)); - Changed = true; - } else { - // XOR with zero results in the nonzero source - for (unsigned i = 0; i < 2; ++i) { - if (!IREmit->IsValueConstant(Op->Header.Args[i], &Constant1)) - continue; - - if (Constant1 != 0) - continue; - - IREmit->SetWriteCursor(CodeNode); - OrderedNode *Arg = CurrentIR.GetNode(Op->Header.Args[1 - i]); - IREmit->ReplaceAllUsesWith(CodeNode, Arg); - Changed = true; - break; - } - } - break; - } - case OP_NEG: { - auto Op = IROp->CW(); - uint64_t Constant{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant)) { - uint64_t NewConstant = -Constant; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - break; - } - case OP_LSHL: { - auto Op = IROp->CW(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - // Shifts mask the shift amount by 63 or 31 depending on operating size; - uint64_t ShiftMask = IROp->Size == 8 ? 63 : 31; - uint64_t NewConstant = (Constant1 << (Constant2 & ShiftMask)) & getMask(Op); - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && - Constant2 == 0) { - IREmit->SetWriteCursor(CodeNode); - OrderedNode *Arg = CurrentIR.GetNode(Op->Header.Args[0]); - IREmit->ReplaceAllUsesWith(CodeNode, Arg); - Changed = true; - } else { - auto newArg = RemoveUselessMasking(IREmit, Op->Header.Args[1], IROp->Size * 8 - 1); - if (newArg.ID() != Op->Header.Args[1].ID()) { - IREmit->ReplaceNodeArgument(CodeNode, 1, IREmit->UnwrapNode(newArg)); - Changed = true; - } - } - break; - } - case OP_LSHR: { - auto Op = IROp->CW(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - // Shifts mask the shift amount by 63 or 31 depending on operating size; - uint64_t ShiftMask = IROp->Size == 8 ? 63 : 31; - uint64_t NewConstant = (Constant1 >> (Constant2 & ShiftMask)) & getMask(Op); - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && - Constant2 == 0) { - IREmit->SetWriteCursor(CodeNode); - OrderedNode *Arg = CurrentIR.GetNode(Op->Header.Args[0]); - IREmit->ReplaceAllUsesWith(CodeNode, Arg); - Changed = true; - } else { - auto newArg = RemoveUselessMasking(IREmit, Op->Header.Args[1], IROp->Size * 8 - 1); - if (newArg.ID() != Op->Header.Args[1].ID()) { - IREmit->ReplaceNodeArgument(CodeNode, 1, IREmit->UnwrapNode(newArg)); - Changed = true; - } - } - break; - } - case OP_BFE: { - auto Op = IROp->C(); - uint64_t Constant; - if (IROp->Size <= 8 && IREmit->IsValueConstant(Op->Src, &Constant)) { - uint64_t SourceMask = Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); - SourceMask <<= Op->lsb; - - uint64_t NewConstant = (Constant & SourceMask) >> Op->lsb; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } else if (IROp->Size == CurrentIR.GetOp(Op->Header.Args[0])->Size && Op->Width == (IROp->Size * 8) && Op->lsb == 0 ) { - // A BFE that extracts all bits results in original value - // XXX - This is broken for now - see https://github.com/FEX-Emu/FEX/issues/351 - // IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); - // Changed = true; - } else if (Op->Width == 1 && Op->lsb == 0) { - // common from flag codegen - auto val = IREmit->GetOpHeader(Op->Header.Args[0]); - - uint64_t Constant2{}; - uint64_t Constant3{}; - if (val->Op == OP_SELECT && - IREmit->IsValueConstant(val->Args[2], &Constant2) && - IREmit->IsValueConstant(val->Args[3], &Constant3) && - Constant2 == 1 && - Constant3 == 0) - { - IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[0])); - Changed = true; - } - } - - break; - } - case OP_SBFE: { - auto Op = IROp->C(); - uint64_t Constant; - if (IREmit->IsValueConstant(Op->Src, &Constant)) { - // SBFE of a constant can be converted to a constant. - uint64_t SourceMask = - Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); - uint64_t DestSizeInBits = IROp->Size * 8; - uint64_t DestMask = - DestSizeInBits == 64 ? ~0ULL : ((1ULL << DestSizeInBits) - 1); - SourceMask <<= Op->lsb; - - int64_t NewConstant = (Constant & SourceMask) >> Op->lsb; - NewConstant <<= 64 - Op->Width; - NewConstant >>= 64 - Op->Width; - NewConstant &= DestMask; - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - - Changed = true; - } - break; - } - case OP_BFI: { - auto Op = IROp->C(); - uint64_t ConstantDest{}; - uint64_t ConstantSrc{}; - bool DestIsConstant = IREmit->IsValueConstant(Op->Header.Args[0], &ConstantDest); - bool SrcIsConstant = IREmit->IsValueConstant(Op->Header.Args[1], &ConstantSrc); - - if (DestIsConstant && SrcIsConstant) { - uint64_t SourceMask = Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); - uint64_t NewConstant = ConstantDest & ~(SourceMask << Op->lsb); - NewConstant |= (ConstantSrc & SourceMask) << Op->lsb; - - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } - else if (SrcIsConstant && HasConsecutiveBits(ConstantSrc, Op->Width)) { - // We are trying to insert constant, if it is a bitfield of only set bits then we can orr or and it. - IREmit->SetWriteCursor(CodeNode); - uint64_t SourceMask = Op->Width == 64 ? ~0ULL : ((1ULL << Op->Width) - 1); - uint64_t NewConstant = SourceMask << Op->lsb; - - if (ConstantSrc & 1) { - auto orr = IREmit->_Or(IR::SizeToOpSize(IROp->Size), CurrentIR.GetNode(Op->Header.Args[0]), IREmit->_Constant(NewConstant)); - IREmit->ReplaceAllUsesWith(CodeNode, orr); - Changed = true; - } - else { - // We are wanting to clear the bitfield. - auto andn = IREmit->_Andn(IR::SizeToOpSize(IROp->Size), CurrentIR.GetNode(Op->Header.Args[0]), IREmit->_Constant(NewConstant)); - IREmit->ReplaceAllUsesWith(CodeNode, andn); Changed = true; } } break; } - case OP_MUL: { - auto Op = IROp->C(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - uint64_t NewConstant = (Constant1 * Constant2) & getMask(Op); - IREmit->ReplaceWithConstant(CodeNode, NewConstant); - Changed = true; - } else if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && std::popcount(Constant2) == 1) { - if (IROp->Size == 4 || IROp->Size == 8) { - uint64_t amt = std::countr_zero(Constant2); - IREmit->SetWriteCursor(CodeNode); - auto shift = IREmit->_Lshl(IR::SizeToOpSize(IROp->Size), CurrentIR.GetNode(Op->Header.Args[0]), IREmit->_Constant(amt)); - IREmit->ReplaceAllUsesWith(CodeNode, shift); - Changed = true; - } - } - break; - } - case OP_SELECT: { - auto Op = IROp->C(); - uint64_t Constant1{}; - uint64_t Constant2{}; - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1) && - IREmit->IsValueConstant(Op->Header.Args[1], &Constant2) && - Op->Cond == COND_EQ) { - - Constant1 &= getMask(Op); - Constant2 &= getMask(Op); - - bool is_true = Constant1 == Constant2; - - IREmit->ReplaceAllUsesWith(CodeNode, CurrentIR.GetNode(Op->Header.Args[is_true ? 2 : 3])); - Changed = true; - } - break; - } - default: - break; - } - - return Changed; -} - -bool ConstProp::ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR) { - InlineConstantGen.clear(); - bool Changed = false; - - for (auto [CodeNode, IROp] : CurrentIR.GetAllCode()) { - switch(IROp->Op) { - case OP_LSHR: - case OP_ASHR: - case OP_ROR: - case OP_LSHL: - { - auto Op = IROp->C(); - - uint64_t Constant2{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - - // this shouldn't be here, but rather on the emitter themselves or the constprop transformation? - if (IROp->Size <=4) - Constant2 &= 31; - else - Constant2 &= 63; - - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - break; - } - case OP_ADD: - case OP_SUB: - case OP_ADDNZCV: - case OP_SUBNZCV: - case OP_ADDWITHFLAGS: - case OP_SUBWITHFLAGS: - { - auto Op = IROp->C(); - - uint64_t Constant2{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - // We don't allow 8/16-bit operations to have constants, since no - // constant would be in bounds after the JIT's 24/16 shift. - if (IsImmAddSub(Constant2) && Op->Header.Size >= 4) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } else if (IROp->Op == OP_SUBNZCV || IROp->Op == OP_SUBWITHFLAGS || IROp->Op == OP_SUB) { - // TODO: Generalize this - uint64_t Constant1{}; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { - if (Constant1 == 0) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); - IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); - Changed = true; - } - } - } - - break; - } - case OP_ADC: - case OP_ADCWITHFLAGS: - { - auto Op = IROp->C(); - - uint64_t Constant1{}; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { - if (Constant1 == 0) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); - IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); - Changed = true; - } - } - - break; - } - case OP_RMIFNZCV: - { - auto Op = IROp->C(); - - uint64_t Constant1{}; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { - if (Constant1 == 0) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); - IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); - Changed = true; - } - } - - break; - } - case OP_CONDADDNZCV: - case OP_CONDSUBNZCV: - { - auto Op = IROp->C(); - - uint64_t Constant2{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - if (IsImmAddSub(Constant2)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - - uint64_t Constant1{}; - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { - if (Constant1 == 0) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); - IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0)); - Changed = true; - } - } - break; - } - case OP_TESTNZ: - { - auto Op = IROp->C(); - - uint64_t Constant1{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant1)) { - if (IsImmLogical(Constant1, IROp->Size * 8)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant1)); - - Changed = true; - } - } - break; - } - case OP_SELECT: - { - auto Op = IROp->C(); - - uint64_t Constant1{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant1)) { - if (IsImmAddSub(Constant1)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant1)); - - Changed = true; - } - } - - uint64_t AllOnes = IROp->Size == 8 ? 0xffff'ffff'ffff'ffffull : 0xffff'ffffull; - - uint64_t Constant2{}; - uint64_t Constant3{}; - if (IREmit->IsValueConstant(Op->Header.Args[2], &Constant2) && - IREmit->IsValueConstant(Op->Header.Args[3], &Constant3) && - (Constant2 == 1 || Constant2 == AllOnes) && - Constant3 == 0) - { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[2])); - - IREmit->ReplaceNodeArgument(CodeNode, 2, CreateInlineConstant(IREmit, Constant2)); - IREmit->ReplaceNodeArgument(CodeNode, 3, CreateInlineConstant(IREmit, Constant3)); - } - - break; - } - case OP_NZCVSELECT: - { - auto Op = IROp->C(); - - uint64_t AllOnes = IROp->Size == 8 ? 0xffff'ffff'ffff'ffffull : 0xffff'ffffull; - - // We always allow source 1 to be zero, but source 0 can only be a - // special 1/~0 constant if source 1 is 0. - uint64_t Constant0{}; - uint64_t Constant1{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant1) && - Constant1 == 0) - { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant1)); - - if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant0) && - (Constant0 == 1 || Constant0 == AllOnes)) - { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0])); - - IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, Constant0)); - } - } - - break; - } - case OP_CONDJUMP: - { - auto Op = IROp->C(); - - uint64_t Constant2{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - if (IsImmAddSub(Constant2)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - break; - } - case OP_EXITFUNCTION: - { - auto Op = IROp->C(); - - uint64_t Constant{}; - if (IREmit->IsValueConstant(Op->NewRIP, &Constant)) { - - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->NewRIP)); - - IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, Constant)); - - Changed = true; - } else { - auto NewRIP = IREmit->GetOpHeader(Op->NewRIP); - if (NewRIP->Op == OP_ENTRYPOINTOFFSET) { - auto EO = NewRIP->C(); - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->NewRIP)); - - IREmit->ReplaceNodeArgument(CodeNode, 0, IREmit->_InlineEntrypointOffset(IR::SizeToOpSize(EO->Header.Size), EO->Offset)); - Changed = true; - } - } - break; - } - case OP_OR: - case OP_XOR: - case OP_AND: - case OP_ANDWITHFLAGS: - case OP_ANDN: - { - auto Op = IROp->CW(); - - uint64_t Constant2{}; - if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) { - if (IsImmLogical(Constant2, IROp->Size * 8)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1])); - - IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - break; - } - case OP_LOADMEM: - { - auto Op = IROp->CW(); - - uint64_t Constant2{}; - if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { - if (IsImmMemory(Constant2, IROp->Size)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); - - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - break; - } - case OP_STOREMEM: - { - auto Op = IROp->CW(); - - uint64_t Constant2{}; - if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { - if (IsImmMemory(Constant2, IROp->Size)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); - - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - break; - } - case OP_LOADMEMTSO: - { - auto Op = IROp->CW(); - - uint64_t Constant2{}; - if (SupportsTSOImm9) { - if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { - if (IsTSOImm9(Constant2)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); - - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - } - break; - } - case OP_STOREMEMTSO: - { - auto Op = IROp->CW(); - - uint64_t Constant2{}; - if (SupportsTSOImm9) { - if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { - if (IsTSOImm9(Constant2)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); - - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - } - break; - } - case OP_MEMCPY: - { - auto Op = IROp->CW(); - - uint64_t Constant{}; - if (IREmit->IsValueConstant(Op->Direction, &Constant)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Direction)); - - IREmit->ReplaceNodeArgument(CodeNode, Op->Direction_Index, CreateInlineConstant(IREmit, Constant)); - - Changed = true; - } - break; - } - case OP_MEMSET: - { - auto Op = IROp->CW(); - - uint64_t Constant{}; - if (IREmit->IsValueConstant(Op->Direction, &Constant)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Direction)); - - IREmit->ReplaceNodeArgument(CodeNode, Op->Direction_Index, CreateInlineConstant(IREmit, Constant)); - - Changed = true; - } - break; - } - - case OP_PREFETCH: - { - auto Op = IROp->CW(); - - uint64_t Constant2{}; - if (Op->OffsetType == MEM_OFFSET_SXTX && IREmit->IsValueConstant(Op->Offset, &Constant2)) { - if (IsImmMemory(Constant2, IROp->Size)) { - IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Offset)); - - IREmit->ReplaceNodeArgument(CodeNode, Op->Offset_Index, CreateInlineConstant(IREmit, Constant2)); - - Changed = true; - } - } - break; - } - default: - break; + default: break; } } return Changed; } -bool ConstProp::Run(IREmitter *IREmit) { +bool ConstProp::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::ConstProp"); bool Changed = false; @@ -1415,9 +1335,7 @@ bool ConstProp::Run(IREmitter *IREmit) { return Changed; } -fextl::unique_ptr -CreateConstProp(bool InlineConstants, bool SupportsTSOImm9, bool Is64BitMode) { - return fextl::make_unique(InlineConstants, SupportsTSOImm9, - Is64BitMode); -} +fextl::unique_ptr CreateConstProp(bool InlineConstants, bool SupportsTSOImm9, bool Is64BitMode) { + return fextl::make_unique(InlineConstants, SupportsTSOImm9, Is64BitMode); } +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp b/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp index 14a234a37..466529987 100644 --- a/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp @@ -16,13 +16,13 @@ $end_info$ namespace FEXCore::IR { class DeadCodeElimination final : public FEXCore::IR::Pass { - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: - void markUsed(OrderedNodeWrapper *CodeOp, IROp_Header *IROp); + void markUsed(OrderedNodeWrapper* CodeOp, IROp_Header* IROp); }; -bool DeadCodeElimination::Run(IREmitter *IREmit) { +bool DeadCodeElimination::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::DCE"); auto CurrentIR = IREmit->ViewIR(); bool Changed = false; @@ -42,62 +42,47 @@ bool DeadCodeElimination::Run(IREmitter *IREmit) { bool HasSideEffects = IR::HasSideEffects(IROp->Op); switch (IROp->Op) { - case OP_SYSCALL: - case OP_INLINESYSCALL: { - FEXCore::IR::SyscallFlags Flags{}; - if (IROp->Op == OP_SYSCALL) { - auto Op = IROp->C(); - Flags = Op->Flags; - } - else { - auto Op = IROp->C(); - Flags = Op->Flags; - } - - if ((Flags & FEXCore::IR::SyscallFlags::NOSIDEEFFECTS) == FEXCore::IR::SyscallFlags::NOSIDEEFFECTS) { - HasSideEffects = false; - } - - break; + case OP_SYSCALL: + case OP_INLINESYSCALL: { + FEXCore::IR::SyscallFlags Flags {}; + if (IROp->Op == OP_SYSCALL) { + auto Op = IROp->C(); + Flags = Op->Flags; + } else { + auto Op = IROp->C(); + Flags = Op->Flags; } - case OP_ATOMICFETCHADD: - case OP_ATOMICFETCHSUB: - case OP_ATOMICFETCHAND: - case OP_ATOMICFETCHCLR: - case OP_ATOMICFETCHOR: - case OP_ATOMICFETCHXOR: - case OP_ATOMICFETCHNEG: { - // If the result of the atomic fetch is completely unused, convert it to a non-fetching atomic operation. - if (CodeNode->GetUses() == 0) { - switch (IROp->Op) { - case OP_ATOMICFETCHADD: - IROp->Op = OP_ATOMICADD; - break; - case OP_ATOMICFETCHSUB: - IROp->Op = OP_ATOMICSUB; - break; - case OP_ATOMICFETCHAND: - IROp->Op = OP_ATOMICAND; - break; - case OP_ATOMICFETCHCLR: - IROp->Op = OP_ATOMICCLR; - break; - case OP_ATOMICFETCHOR: - IROp->Op = OP_ATOMICOR; - break; - case OP_ATOMICFETCHXOR: - IROp->Op = OP_ATOMICXOR; - break; - case OP_ATOMICFETCHNEG: - IROp->Op = OP_ATOMICNEG; - break; - default: FEX_UNREACHABLE; - } - Changed = true; - } - break; + + if ((Flags & FEXCore::IR::SyscallFlags::NOSIDEEFFECTS) == FEXCore::IR::SyscallFlags::NOSIDEEFFECTS) { + HasSideEffects = false; } - default: break; + + break; + } + case OP_ATOMICFETCHADD: + case OP_ATOMICFETCHSUB: + case OP_ATOMICFETCHAND: + case OP_ATOMICFETCHCLR: + case OP_ATOMICFETCHOR: + case OP_ATOMICFETCHXOR: + case OP_ATOMICFETCHNEG: { + // If the result of the atomic fetch is completely unused, convert it to a non-fetching atomic operation. + if (CodeNode->GetUses() == 0) { + switch (IROp->Op) { + case OP_ATOMICFETCHADD: IROp->Op = OP_ATOMICADD; break; + case OP_ATOMICFETCHSUB: IROp->Op = OP_ATOMICSUB; break; + case OP_ATOMICFETCHAND: IROp->Op = OP_ATOMICAND; break; + case OP_ATOMICFETCHCLR: IROp->Op = OP_ATOMICCLR; break; + case OP_ATOMICFETCHOR: IROp->Op = OP_ATOMICOR; break; + case OP_ATOMICFETCHXOR: IROp->Op = OP_ATOMICXOR; break; + case OP_ATOMICFETCHNEG: IROp->Op = OP_ATOMICNEG; break; + default: FEX_UNREACHABLE; + } + Changed = true; + } + break; + } + default: break; } // Skip over anything that has side effects @@ -119,12 +104,10 @@ bool DeadCodeElimination::Run(IREmitter *IREmit) { return Changed; } -void DeadCodeElimination::markUsed(OrderedNodeWrapper *CodeOp, IROp_Header *IROp) { - -} +void DeadCodeElimination::markUsed(OrderedNodeWrapper* CodeOp, IROp_Header* IROp) {} fextl::unique_ptr CreatePassDeadCodeElimination() { return fextl::make_unique(); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index 1fd7eca1b..64fdcabc8 100644 --- a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -28,450 +28,449 @@ $end_info$ #include namespace { - struct ContextMemberClassification { - size_t Offset; - uint16_t Size; - }; +struct ContextMemberClassification { + size_t Offset; + uint16_t Size; +}; - enum class LastAccessType { - NONE = (0b000 << 0), ///< Was never previously accessed - WRITE = (0b001 << 0), ///< Was fully overwritten - READ = (0b010 << 0), ///< Was fully read - INVALID = (0b011 << 0), ///< Accessing this is invalid - MASK = (0b011 << 0), - PARTIAL = (0b100 << 0), - PARTIAL_WRITE = (PARTIAL | WRITE), ///< Was partially written - PARTIAL_READ = (PARTIAL | READ), ///< Was partially read - }; - FEX_DEF_NUM_OPS(LastAccessType); +enum class LastAccessType { + NONE = (0b000 << 0), ///< Was never previously accessed + WRITE = (0b001 << 0), ///< Was fully overwritten + READ = (0b010 << 0), ///< Was fully read + INVALID = (0b011 << 0), ///< Accessing this is invalid + MASK = (0b011 << 0), + PARTIAL = (0b100 << 0), + PARTIAL_WRITE = (PARTIAL | WRITE), ///< Was partially written + PARTIAL_READ = (PARTIAL | READ), ///< Was partially read +}; +FEX_DEF_NUM_OPS(LastAccessType); - static bool IsWriteAccess(LastAccessType Type) { - return (Type & LastAccessType::MASK) == LastAccessType::WRITE; - } +static bool IsWriteAccess(LastAccessType Type) { + return (Type & LastAccessType::MASK) == LastAccessType::WRITE; +} - static bool IsReadAccess(LastAccessType Type) { - return (Type & LastAccessType::MASK) == LastAccessType::READ; - } +static bool IsReadAccess(LastAccessType Type) { + return (Type & LastAccessType::MASK) == LastAccessType::READ; +} - [[maybe_unused]] - static bool IsInvalidAccess(LastAccessType Type) { - return (Type & LastAccessType::MASK) == LastAccessType::INVALID; - } +[[maybe_unused]] +static bool IsInvalidAccess(LastAccessType Type) { + return (Type & LastAccessType::MASK) == LastAccessType::INVALID; +} - [[maybe_unused]] - static bool IsPartialAccess(LastAccessType Type) { - return (Type & LastAccessType::PARTIAL) == LastAccessType::PARTIAL; - } +[[maybe_unused]] +static bool IsPartialAccess(LastAccessType Type) { + return (Type & LastAccessType::PARTIAL) == LastAccessType::PARTIAL; +} - [[maybe_unused]] - static bool IsFullAccess(LastAccessType Type) { - return (Type & LastAccessType::PARTIAL) == LastAccessType::NONE; - } +[[maybe_unused]] +static bool IsFullAccess(LastAccessType Type) { + return (Type & LastAccessType::PARTIAL) == LastAccessType::NONE; +} - struct ContextMemberInfo { - ContextMemberClassification Class; - LastAccessType Accessed; - FEXCore::IR::RegisterClassType AccessRegClass; - uint32_t AccessOffset; - uint8_t AccessSize; - ///< The last value that was loaded or stored. - FEXCore::IR::OrderedNode *ValueNode; - ///< With a store access, the store node that is doing the operation. - FEXCore::IR::OrderedNode *StoreNode; - }; +struct ContextMemberInfo { + ContextMemberClassification Class; + LastAccessType Accessed; + FEXCore::IR::RegisterClassType AccessRegClass; + uint32_t AccessOffset; + uint8_t AccessSize; + ///< The last value that was loaded or stored. + FEXCore::IR::OrderedNode* ValueNode; + ///< With a store access, the store node that is doing the operation. + FEXCore::IR::OrderedNode* StoreNode; +}; - struct ContextInfo { - fextl::vector Lookup; - fextl::vector ClassificationInfo; - }; +struct ContextInfo { + fextl::vector Lookup; + fextl::vector ClassificationInfo; +}; - static void ClassifyContextStruct(ContextInfo *ContextClassificationInfo, bool SupportsAVX) { - auto ContextClassification = &ContextClassificationInfo->ClassificationInfo; +static void ClassifyContextStruct(ContextInfo* ContextClassificationInfo, bool SupportsAVX) { + auto ContextClassification = &ContextClassificationInfo->ClassificationInfo; - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, rip), - sizeof(FEXCore::Core::CPUState::rip), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, rip), + sizeof(FEXCore::Core::CPUState::rip), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i) { - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, gregs[0]) + sizeof(FEXCore::Core::CPUState::gregs[0]) * i, - FEXCore::Core::CPUState::GPR_REG_SIZE, - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - } - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, es_idx), - sizeof(FEXCore::Core::CPUState::es_idx), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, cs_idx), - sizeof(FEXCore::Core::CPUState::cs_idx), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, ss_idx), - sizeof(FEXCore::Core::CPUState::ss_idx), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, ds_idx), - sizeof(FEXCore::Core::CPUState::ds_idx), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, gs_idx), - sizeof(FEXCore::Core::CPUState::gs_idx), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, fs_idx), - sizeof(FEXCore::Core::CPUState::fs_idx), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, _pad), - sizeof(FEXCore::Core::CPUState::_pad), - }, - LastAccessType::INVALID, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, es_cached), - sizeof(FEXCore::Core::CPUState::es_cached), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, cs_cached), - sizeof(FEXCore::Core::CPUState::cs_cached), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, ss_cached), - sizeof(FEXCore::Core::CPUState::ss_cached), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, ds_cached), - sizeof(FEXCore::Core::CPUState::ds_cached), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, gs_cached), - sizeof(FEXCore::Core::CPUState::gs_cached), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, fs_cached), - sizeof(FEXCore::Core::CPUState::fs_cached), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, InlineJITBlockHeader), - sizeof(FEXCore::Core::CPUState::InlineJITBlockHeader), - }, - LastAccessType::INVALID, - FEXCore::IR::InvalidClass, - }); - - if (SupportsAVX) { - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i) { - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, xmm.avx.data[0][0]) + FEXCore::Core::CPUState::XMM_AVX_REG_SIZE * i, - FEXCore::Core::CPUState::XMM_AVX_REG_SIZE, - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - } - } else { - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i) { - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, xmm.sse.data[0][0]) + FEXCore::Core::CPUState::XMM_SSE_REG_SIZE * i, - FEXCore::Core::CPUState::XMM_SSE_REG_SIZE, - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - } - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, xmm.sse.pad[0][0]), - static_cast(FEXCore::Core::CPUState::XMM_SSE_REG_SIZE * FEXCore::Core::CPUState::NUM_XMMS), - }, - LastAccessType::INVALID, - FEXCore::IR::InvalidClass, - }); - } - - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_FLAGS; ++i) { - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, flags[0]) + sizeof(FEXCore::Core::CPUState::flags[0]) * i, - FEXCore::Core::CPUState::FLAG_SIZE, - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - } - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, pf_raw), - sizeof(FEXCore::Core::CPUState::pf_raw), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, af_raw), - sizeof(FEXCore::Core::CPUState::af_raw), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, mm[0][0]) + sizeof(FEXCore::Core::CPUState::mm[0]) * i, - FEXCore::Core::CPUState::MM_REG_SIZE - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - } - - // GDTs - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GDTS; ++i) { - ContextClassification->emplace_back(ContextMemberInfo{ - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, gdt[0]) + sizeof(FEXCore::Core::CPUState::gdt[0]) * i, - sizeof(FEXCore::Core::CPUState::gdt[0]), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - } - - // FCW + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i) { ContextClassification->emplace_back(ContextMemberInfo { ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, FCW), - sizeof(FEXCore::Core::CPUState::FCW), + offsetof(FEXCore::Core::CPUState, gregs[0]) + sizeof(FEXCore::Core::CPUState::gregs[0]) * i, + FEXCore::Core::CPUState::GPR_REG_SIZE, }, LastAccessType::NONE, FEXCore::IR::InvalidClass, }); - - // AbridgedFTW - ContextClassification->emplace_back(ContextMemberInfo { - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, AbridgedFTW), - sizeof(FEXCore::Core::CPUState::AbridgedFTW), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - // _pad2 - ContextClassification->emplace_back(ContextMemberInfo { - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, _pad2), - sizeof(FEXCore::Core::CPUState::_pad2), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - // DeferredSignalRefCount - ContextClassification->emplace_back(ContextMemberInfo { - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, DeferredSignalRefCount), - sizeof(FEXCore::Core::CPUState::DeferredSignalRefCount), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - // DeferredSignalFaultAddress - ContextClassification->emplace_back(ContextMemberInfo { - ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, DeferredSignalFaultAddress), - sizeof(FEXCore::Core::CPUState::DeferredSignalFaultAddress), - }, - LastAccessType::NONE, - FEXCore::IR::InvalidClass, - }); - - - [[maybe_unused]] size_t ClassifiedStructSize{}; - ContextClassificationInfo->Lookup.reserve(sizeof(FEXCore::Core::CPUState)); - for (auto &it : *ContextClassification) { - LOGMAN_THROW_A_FMT(it.Class.Offset == ContextClassificationInfo->Lookup.size(), "Offset mismatch (offset={})", it.Class.Offset); - for (int i = 0; i < it.Class.Size; i++) { - ContextClassificationInfo->Lookup.push_back(&it); - } - ClassifiedStructSize += it.Class.Size; - } - - LOGMAN_THROW_AA_FMT(ClassifiedStructSize == sizeof(FEXCore::Core::CPUState), - "Classified CPUStruct size doesn't match real CPUState struct size! {} (classified) != {} (real)", - ClassifiedStructSize, sizeof(FEXCore::Core::CPUState)); - - LOGMAN_THROW_A_FMT(ContextClassificationInfo->Lookup.size() == sizeof(FEXCore::Core::CPUState), - "Classified lookup size doesn't match real CPUState struct size! {} (classified) != {} (real)", - ContextClassificationInfo->Lookup.size(), sizeof(FEXCore::Core::CPUState)); } - static void ResetClassificationAccesses(ContextInfo *ContextClassificationInfo, bool SupportsAVX) { - auto ContextClassification = &ContextClassificationInfo->ClassificationInfo; + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, es_idx), + sizeof(FEXCore::Core::CPUState::es_idx), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); - auto SetAccess = [&](size_t Offset, LastAccessType Access) { - ContextClassification->at(Offset).Accessed = Access; - ContextClassification->at(Offset).AccessRegClass = FEXCore::IR::InvalidClass; - ContextClassification->at(Offset).AccessOffset = 0; - ContextClassification->at(Offset).StoreNode = nullptr; - }; - size_t Offset = 0; - SetAccess(Offset++, LastAccessType::NONE); - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i) { - SetAccess(Offset++, LastAccessType::NONE); - } + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, cs_idx), + sizeof(FEXCore::Core::CPUState::cs_idx), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); - // Segment indexes - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, ss_idx), + sizeof(FEXCore::Core::CPUState::ss_idx), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); - // Pad - SetAccess(Offset++, LastAccessType::INVALID); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, ds_idx), + sizeof(FEXCore::Core::CPUState::ds_idx), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); - // Segments - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, gs_idx), + sizeof(FEXCore::Core::CPUState::gs_idx), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); - // Pad2 - SetAccess(Offset++, LastAccessType::INVALID); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, fs_idx), + sizeof(FEXCore::Core::CPUState::fs_idx), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, _pad), + sizeof(FEXCore::Core::CPUState::_pad), + }, + LastAccessType::INVALID, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, es_cached), + sizeof(FEXCore::Core::CPUState::es_cached), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, cs_cached), + sizeof(FEXCore::Core::CPUState::cs_cached), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, ss_cached), + sizeof(FEXCore::Core::CPUState::ss_cached), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, ds_cached), + sizeof(FEXCore::Core::CPUState::ds_cached), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, gs_cached), + sizeof(FEXCore::Core::CPUState::gs_cached), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, fs_cached), + sizeof(FEXCore::Core::CPUState::fs_cached), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, InlineJITBlockHeader), + sizeof(FEXCore::Core::CPUState::InlineJITBlockHeader), + }, + LastAccessType::INVALID, + FEXCore::IR::InvalidClass, + }); + + if (SupportsAVX) { for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i) { - SetAccess(Offset++, LastAccessType::NONE); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, xmm.avx.data[0][0]) + FEXCore::Core::CPUState::XMM_AVX_REG_SIZE * i, + FEXCore::Core::CPUState::XMM_AVX_REG_SIZE, + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + } + } else { + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i) { + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, xmm.sse.data[0][0]) + FEXCore::Core::CPUState::XMM_SSE_REG_SIZE * i, + FEXCore::Core::CPUState::XMM_SSE_REG_SIZE, + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); } - if (!SupportsAVX) { - SetAccess(Offset++, LastAccessType::NONE); - } - - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_FLAGS; ++i) { - SetAccess(Offset++, LastAccessType::NONE); - } - - // PF/AF - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { - SetAccess(Offset++, LastAccessType::NONE); - } - - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GDTS; ++i) { - SetAccess(Offset++, LastAccessType::NONE); - } - - SetAccess(Offset++, LastAccessType::NONE); - SetAccess(Offset++, LastAccessType::NONE); - - SetAccess(Offset++, LastAccessType::INVALID); - SetAccess(Offset++, LastAccessType::INVALID); - SetAccess(Offset++, LastAccessType::INVALID); + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, xmm.sse.pad[0][0]), + static_cast(FEXCore::Core::CPUState::XMM_SSE_REG_SIZE * FEXCore::Core::CPUState::NUM_XMMS), + }, + LastAccessType::INVALID, + FEXCore::IR::InvalidClass, + }); } - struct BlockInfo { - fextl::vector Predecessors; - fextl::vector Successors; - ContextInfo IncomingClassifiedStruct; - ContextInfo OutgoingClassifiedStruct; + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_FLAGS; ++i) { + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, flags[0]) + sizeof(FEXCore::Core::CPUState::flags[0]) * i, + FEXCore::Core::CPUState::FLAG_SIZE, + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + } + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, pf_raw), + sizeof(FEXCore::Core::CPUState::pf_raw), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, af_raw), + sizeof(FEXCore::Core::CPUState::af_raw), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification {offsetof(FEXCore::Core::CPUState, mm[0][0]) + sizeof(FEXCore::Core::CPUState::mm[0]) * i, + FEXCore::Core::CPUState::MM_REG_SIZE}, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + } + + // GDTs + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GDTS; ++i) { + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, gdt[0]) + sizeof(FEXCore::Core::CPUState::gdt[0]) * i, + sizeof(FEXCore::Core::CPUState::gdt[0]), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + } + + // FCW + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, FCW), + sizeof(FEXCore::Core::CPUState::FCW), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + // AbridgedFTW + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, AbridgedFTW), + sizeof(FEXCore::Core::CPUState::AbridgedFTW), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + // _pad2 + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, _pad2), + sizeof(FEXCore::Core::CPUState::_pad2), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + // DeferredSignalRefCount + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, DeferredSignalRefCount), + sizeof(FEXCore::Core::CPUState::DeferredSignalRefCount), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + // DeferredSignalFaultAddress + ContextClassification->emplace_back(ContextMemberInfo { + ContextMemberClassification { + offsetof(FEXCore::Core::CPUState, DeferredSignalFaultAddress), + sizeof(FEXCore::Core::CPUState::DeferredSignalFaultAddress), + }, + LastAccessType::NONE, + FEXCore::IR::InvalidClass, + }); + + + [[maybe_unused]] size_t ClassifiedStructSize {}; + ContextClassificationInfo->Lookup.reserve(sizeof(FEXCore::Core::CPUState)); + for (auto& it : *ContextClassification) { + LOGMAN_THROW_A_FMT(it.Class.Offset == ContextClassificationInfo->Lookup.size(), "Offset mismatch (offset={})", it.Class.Offset); + for (int i = 0; i < it.Class.Size; i++) { + ContextClassificationInfo->Lookup.push_back(&it); + } + ClassifiedStructSize += it.Class.Size; + } + + LOGMAN_THROW_AA_FMT(ClassifiedStructSize == sizeof(FEXCore::Core::CPUState), + "Classified CPUStruct size doesn't match real CPUState struct size! {} (classified) != {} (real)", + ClassifiedStructSize, sizeof(FEXCore::Core::CPUState)); + + LOGMAN_THROW_A_FMT(ContextClassificationInfo->Lookup.size() == sizeof(FEXCore::Core::CPUState), + "Classified lookup size doesn't match real CPUState struct size! {} (classified) != {} (real)", + ContextClassificationInfo->Lookup.size(), sizeof(FEXCore::Core::CPUState)); +} + +static void ResetClassificationAccesses(ContextInfo* ContextClassificationInfo, bool SupportsAVX) { + auto ContextClassification = &ContextClassificationInfo->ClassificationInfo; + + auto SetAccess = [&](size_t Offset, LastAccessType Access) { + ContextClassification->at(Offset).Accessed = Access; + ContextClassification->at(Offset).AccessRegClass = FEXCore::IR::InvalidClass; + ContextClassification->at(Offset).AccessOffset = 0; + ContextClassification->at(Offset).StoreNode = nullptr; }; + size_t Offset = 0; + SetAccess(Offset++, LastAccessType::NONE); + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i) { + SetAccess(Offset++, LastAccessType::NONE); + } + + // Segment indexes + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + + // Pad + SetAccess(Offset++, LastAccessType::INVALID); + + // Segments + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + + // Pad2 + SetAccess(Offset++, LastAccessType::INVALID); + + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i) { + SetAccess(Offset++, LastAccessType::NONE); + } + + if (!SupportsAVX) { + SetAccess(Offset++, LastAccessType::NONE); + } + + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_FLAGS; ++i) { + SetAccess(Offset++, LastAccessType::NONE); + } + + // PF/AF + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { + SetAccess(Offset++, LastAccessType::NONE); + } + + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_GDTS; ++i) { + SetAccess(Offset++, LastAccessType::NONE); + } + + SetAccess(Offset++, LastAccessType::NONE); + SetAccess(Offset++, LastAccessType::NONE); + + SetAccess(Offset++, LastAccessType::INVALID); + SetAccess(Offset++, LastAccessType::INVALID); + SetAccess(Offset++, LastAccessType::INVALID); +} + +struct BlockInfo { + fextl::vector Predecessors; + fextl::vector Successors; + ContextInfo IncomingClassifiedStruct; + ContextInfo OutgoingClassifiedStruct; +}; class RCLSE final : public FEXCore::IR::Pass { public: - explicit RCLSE(bool SupportsAVX_) : SupportsAVX{SupportsAVX_} { + explicit RCLSE(bool SupportsAVX_) + : SupportsAVX {SupportsAVX_} { ClassifyContextStruct(&ClassifiedStruct, SupportsAVX); DCE = FEXCore::IR::CreatePassDeadCodeElimination(); } - bool Run(FEXCore::IR::IREmitter *IREmit) override; + bool Run(FEXCore::IR::IREmitter* IREmit) override; private: fextl::unique_ptr DCE; @@ -480,32 +479,36 @@ private: bool SupportsAVX; - ContextMemberInfo *FindMemberInfo(ContextInfo *ClassifiedInfo, uint32_t Offset, uint8_t Size); - ContextMemberInfo *RecordAccess(ContextMemberInfo *Info, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, LastAccessType AccessType, FEXCore::IR::OrderedNode *Node, FEXCore::IR::OrderedNode *StoreNode = nullptr); - ContextMemberInfo *RecordAccess(ContextInfo *ClassifiedInfo, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, LastAccessType AccessType, FEXCore::IR::OrderedNode *Node, FEXCore::IR::OrderedNode *StoreNode = nullptr); + ContextMemberInfo* FindMemberInfo(ContextInfo* ClassifiedInfo, uint32_t Offset, uint8_t Size); + ContextMemberInfo* RecordAccess(ContextMemberInfo* Info, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, + LastAccessType AccessType, FEXCore::IR::OrderedNode* Node, FEXCore::IR::OrderedNode* StoreNode = nullptr); + ContextMemberInfo* RecordAccess(ContextInfo* ClassifiedInfo, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, + LastAccessType AccessType, FEXCore::IR::OrderedNode* Node, FEXCore::IR::OrderedNode* StoreNode = nullptr); - bool HandleLoadFlag(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInfo, FEXCore::IR::OrderedNode *CodeNode, unsigned Flag); + bool HandleLoadFlag(FEXCore::IR::IREmitter* IREmit, ContextInfo* LocalInfo, FEXCore::IR::OrderedNode* CodeNode, unsigned Flag); // Classify context loads and stores. - bool ClassifyContextLoad(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInfo, FEXCore::IR::RegisterClassType Class, uint32_t Offset, uint8_t Size, FEXCore::IR::OrderedNode *CodeNode, FEXCore::IR::NodeIterator BlockEnd); - bool ClassifyContextStore(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInfo, FEXCore::IR::RegisterClassType Class, uint32_t Offset, uint8_t Size, FEXCore::IR::OrderedNode *CodeNode, FEXCore::IR::OrderedNode *ValueNode); + bool ClassifyContextLoad(FEXCore::IR::IREmitter* IREmit, ContextInfo* LocalInfo, FEXCore::IR::RegisterClassType Class, uint32_t Offset, + uint8_t Size, FEXCore::IR::OrderedNode* CodeNode, FEXCore::IR::NodeIterator BlockEnd); + bool ClassifyContextStore(FEXCore::IR::IREmitter* IREmit, ContextInfo* LocalInfo, FEXCore::IR::RegisterClassType Class, uint32_t Offset, + uint8_t Size, FEXCore::IR::OrderedNode* CodeNode, FEXCore::IR::OrderedNode* ValueNode); // Block local Passes - bool RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit); + bool RedundantStoreLoadElimination(FEXCore::IR::IREmitter* IREmit); }; -ContextMemberInfo *RCLSE::FindMemberInfo(ContextInfo *ContextClassificationInfo, uint32_t Offset, uint8_t Size) { +ContextMemberInfo* RCLSE::FindMemberInfo(ContextInfo* ContextClassificationInfo, uint32_t Offset, uint8_t Size) { return ContextClassificationInfo->Lookup.at(Offset); } -ContextMemberInfo *RCLSE::RecordAccess(ContextMemberInfo *Info, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, LastAccessType AccessType, FEXCore::IR::OrderedNode *ValueNode, FEXCore::IR::OrderedNode *StoreNode) { +ContextMemberInfo* RCLSE::RecordAccess(ContextMemberInfo* Info, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, + LastAccessType AccessType, FEXCore::IR::OrderedNode* ValueNode, FEXCore::IR::OrderedNode* StoreNode) { LOGMAN_THROW_AA_FMT((Offset + Size) <= (Info->Class.Offset + Info->Class.Size), "Access to context item went over member size"); LOGMAN_THROW_AA_FMT(Info->Accessed != LastAccessType::INVALID, "Tried to access invalid member"); // If we aren't fully overwriting the member then it is a partial write that we need to track if (Size < Info->Class.Size) { - AccessType = AccessType == LastAccessType::WRITE ? LastAccessType::PARTIAL_WRITE - : LastAccessType::PARTIAL_READ; + AccessType = AccessType == LastAccessType::WRITE ? LastAccessType::PARTIAL_WRITE : LastAccessType::PARTIAL_READ; } if (Size > Info->Class.Size) { LOGMAN_MSG_A_FMT("Can't handle this"); @@ -516,23 +519,25 @@ ContextMemberInfo *RCLSE::RecordAccess(ContextMemberInfo *Info, FEXCore::IR::Reg Info->AccessOffset = Offset; Info->AccessSize = Size; Info->ValueNode = ValueNode; - if (StoreNode != nullptr) + if (StoreNode != nullptr) { Info->StoreNode = StoreNode; + } return Info; } -ContextMemberInfo *RCLSE::RecordAccess(ContextInfo *ClassifiedInfo, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, LastAccessType AccessType, FEXCore::IR::OrderedNode *ValueNode, FEXCore::IR::OrderedNode *StoreNode) { - ContextMemberInfo *Info = FindMemberInfo(ClassifiedInfo, Offset, Size); +ContextMemberInfo* RCLSE::RecordAccess(ContextInfo* ClassifiedInfo, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, + LastAccessType AccessType, FEXCore::IR::OrderedNode* ValueNode, FEXCore::IR::OrderedNode* StoreNode) { + ContextMemberInfo* Info = FindMemberInfo(ClassifiedInfo, Offset, Size); return RecordAccess(Info, RegClass, Offset, Size, AccessType, ValueNode, StoreNode); } -bool RCLSE::ClassifyContextLoad(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInfo, FEXCore::IR::RegisterClassType Class, uint32_t Offset, uint8_t Size, FEXCore::IR::OrderedNode *CodeNode, FEXCore::IR::NodeIterator BlockEnd) { +bool RCLSE::ClassifyContextLoad(FEXCore::IR::IREmitter* IREmit, ContextInfo* LocalInfo, FEXCore::IR::RegisterClassType Class, + uint32_t Offset, uint8_t Size, FEXCore::IR::OrderedNode* CodeNode, FEXCore::IR::NodeIterator BlockEnd) { auto Info = FindMemberInfo(LocalInfo, Offset, Size); ContextMemberInfo PreviousMemberInfoCopy = *Info; RecordAccess(Info, Class, Offset, Size, LastAccessType::READ, CodeNode); - if (PreviousMemberInfoCopy.AccessRegClass == Info->AccessRegClass && - PreviousMemberInfoCopy.AccessOffset == Info->AccessOffset && + if (PreviousMemberInfoCopy.AccessRegClass == Info->AccessRegClass && PreviousMemberInfoCopy.AccessOffset == Info->AccessOffset && PreviousMemberInfoCopy.AccessSize == Size) { // This optimizes two cases: // - Previous access was a load, and we have a redundant load of the same value. @@ -545,16 +550,14 @@ bool RCLSE::ClassifyContextLoad(FEXCore::IR::IREmitter *IREmit, ContextInfo *Loc return false; } -bool RCLSE::ClassifyContextStore(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInfo, FEXCore::IR::RegisterClassType Class, uint32_t Offset, uint8_t Size, FEXCore::IR::OrderedNode *CodeNode, FEXCore::IR::OrderedNode *ValueNode) { +bool RCLSE::ClassifyContextStore(FEXCore::IR::IREmitter* IREmit, ContextInfo* LocalInfo, FEXCore::IR::RegisterClassType Class, + uint32_t Offset, uint8_t Size, FEXCore::IR::OrderedNode* CodeNode, FEXCore::IR::OrderedNode* ValueNode) { auto Info = FindMemberInfo(LocalInfo, Offset, Size); ContextMemberInfo PreviousMemberInfoCopy = *Info; - RecordAccess(Info, Class, Offset, Size, LastAccessType::WRITE, ValueNode, - CodeNode); + RecordAccess(Info, Class, Offset, Size, LastAccessType::WRITE, ValueNode, CodeNode); - if (PreviousMemberInfoCopy.AccessRegClass == Info->AccessRegClass && - PreviousMemberInfoCopy.AccessOffset == Info->AccessOffset && - PreviousMemberInfoCopy.AccessSize == Size && - PreviousMemberInfoCopy.Accessed == LastAccessType::WRITE) { + if (PreviousMemberInfoCopy.AccessRegClass == Info->AccessRegClass && PreviousMemberInfoCopy.AccessOffset == Info->AccessOffset && + PreviousMemberInfoCopy.AccessSize == Size && PreviousMemberInfoCopy.Accessed == LastAccessType::WRITE) { // This optimizes redundant stores with no intervening load IREmit->Remove(PreviousMemberInfoCopy.StoreNode); return true; @@ -564,7 +567,7 @@ bool RCLSE::ClassifyContextStore(FEXCore::IR::IREmitter *IREmit, ContextInfo *Lo return false; } -bool RCLSE::HandleLoadFlag(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInfo, FEXCore::IR::OrderedNode *CodeNode, unsigned Flag) { +bool RCLSE::HandleLoadFlag(FEXCore::IR::IREmitter* IREmit, ContextInfo* LocalInfo, FEXCore::IR::OrderedNode* CodeNode, unsigned Flag) { const auto FlagOffset = offsetof(FEXCore::Core::CPUState, flags[Flag]); auto Info = FindMemberInfo(LocalInfo, FlagOffset, 1); LastAccessType LastAccess = Info->Accessed; @@ -576,8 +579,7 @@ bool RCLSE::HandleLoadFlag(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInf IREmit->ReplaceAllUsesWith(CodeNode, LastValueNode); RecordAccess(Info, FEXCore::IR::GPRClass, FlagOffset, 1, LastAccessType::READ, LastValueNode); return true; - } - else if (IsReadAccess(LastAccess)) { + } else if (IsReadAccess(LastAccess)) { IREmit->ReplaceAllUsesWith(CodeNode, LastValueNode); RecordAccess(Info, FEXCore::IR::GPRClass, FlagOffset, 1, LastAccessType::READ, LastValueNode); return true; @@ -618,7 +620,7 @@ bool RCLSE::HandleLoadFlag(FEXCore::IR::IREmitter *IREmit, ContextInfo *LocalInf * (%%176) StoreContext %175 i128, 0x10, 0xa0 */ -bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { +bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter* IREmit) { using namespace FEXCore; using namespace FEXCore::IR; @@ -628,7 +630,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { // XXX: Walk the list and calculate the control flow - ContextInfo &LocalInfo = ClassifiedStruct; + ContextInfo& LocalInfo = ClassifiedStruct; for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { auto BlockOp = BlockHeader->CW(); @@ -640,35 +642,28 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { if (IROp->Op == OP_STORECONTEXT) { auto Op = IROp->CW(); Changed |= ClassifyContextStore(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, CurrentIR.GetNode(Op->Value)); - } - else if (IROp->Op == OP_STOREREGISTER) { + } else if (IROp->Op == OP_STOREREGISTER) { auto Op = IROp->CW(); Changed |= ClassifyContextStore(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, CurrentIR.GetNode(Op->Value)); - } - else if (IROp->Op == OP_LOADREGISTER) { + } else if (IROp->Op == OP_LOADREGISTER) { auto Op = IROp->CW(); Changed |= ClassifyContextLoad(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, BlockEnd); - } - else if (IROp->Op == OP_LOADCONTEXT) { + } else if (IROp->Op == OP_LOADCONTEXT) { auto Op = IROp->CW(); Changed |= ClassifyContextLoad(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, BlockEnd); - } - else if (IROp->Op == OP_STOREFLAG) { + } else if (IROp->Op == OP_STOREFLAG) { const auto Op = IROp->CW(); const auto FlagOffset = offsetof(FEXCore::Core::CPUState, flags[0]) + Op->Flag; auto Info = FindMemberInfo(&LocalInfo, FlagOffset, 1); auto LastStoreNode = Info->StoreNode; - RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, FlagOffset, - 1, LastAccessType::WRITE, CurrentIR.GetNode(Op->Header.Args[0]), CodeNode); + RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, FlagOffset, 1, LastAccessType::WRITE, CurrentIR.GetNode(Op->Header.Args[0]), CodeNode); // Flags don't alias, so we can take the simple route here. Kill any flags that have been overwritten - if (LastStoreNode != nullptr) - { + if (LastStoreNode != nullptr) { IREmit->Remove(LastStoreNode); Changed = true; } - } - else if (IROp->Op == OP_INVALIDATEFLAGS) { + } else if (IROp->Op == OP_INVALIDATEFLAGS) { auto Op = IROp->CW(); // Loop through non-reserved flag stores and eliminate unused ones. @@ -682,33 +677,26 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { auto LastStoreNode = Info->StoreNode; // Flags don't alias, so we can take the simple route here. Kill any flags that have been invalidated without a read. - if (LastStoreNode != nullptr) - { + if (LastStoreNode != nullptr) { IREmit->SetWriteCursor(CodeNode); - RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, FlagOffset, - 1, LastAccessType::WRITE, IREmit->_Constant(0), CodeNode); + RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, FlagOffset, 1, LastAccessType::WRITE, IREmit->_Constant(0), CodeNode); IREmit->Remove(LastStoreNode); Changed = true; } } - } - else if (IROp->Op == OP_LOADFLAG) { + } else if (IROp->Op == OP_LOADFLAG) { const auto Op = IROp->CW(); Changed |= HandleLoadFlag(IREmit, &LocalInfo, CodeNode, Op->Flag); - } - else if (IROp->Op == OP_LOADDF) { + } else if (IROp->Op == OP_LOADDF) { Changed |= HandleLoadFlag(IREmit, &LocalInfo, CodeNode, X86State::RFLAG_DF_RAW_LOC); - } - else if (IROp->Op == OP_SYSCALL || - IROp->Op == OP_INLINESYSCALL) { - FEXCore::IR::SyscallFlags Flags{}; + } else if (IROp->Op == OP_SYSCALL || IROp->Op == OP_INLINESYSCALL) { + FEXCore::IR::SyscallFlags Flags {}; if (IROp->Op == OP_SYSCALL) { auto Op = IROp->C(); Flags = Op->Flags; - } - else { + } else { auto Op = IROp->C(); Flags = Op->Flags; } @@ -717,10 +705,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { // We can't track through these ResetClassificationAccesses(&LocalInfo, SupportsAVX); } - } - else if (IROp->Op == OP_STORECONTEXTINDEXED || - IROp->Op == OP_LOADCONTEXTINDEXED || - IROp->Op == OP_BREAK) { + } else if (IROp->Op == OP_STORECONTEXTINDEXED || IROp->Op == OP_LOADCONTEXTINDEXED || IROp->Op == OP_BREAK) { // We can't track through these ResetClassificationAccesses(&LocalInfo, SupportsAVX); } @@ -732,12 +717,12 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) { return Changed; } -bool RCLSE::Run(FEXCore::IR::IREmitter *IREmit) { +bool RCLSE::Run(FEXCore::IR::IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::RCLSE"); bool Changed = false; // Run up to 5 times - for( int i = 0; i < 5 && RedundantStoreLoadElimination(IREmit); i++) { + for (int i = 0; i < 5 && RedundantStoreLoadElimination(IREmit); i++) { Changed = true; DCE->Run(IREmit); } @@ -745,7 +730,7 @@ bool RCLSE::Run(FEXCore::IR::IREmitter *IREmit) { return Changed; } -} +} // namespace namespace FEXCore::IR { @@ -753,4 +738,4 @@ fextl::unique_ptr CreateContextLoadStoreElimination(bool Supp return fextl::make_unique(SupportsAVX); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp b/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp index 4b3a2d46b..01929d12a 100644 --- a/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp @@ -26,9 +26,10 @@ constexpr int PropagationRounds = 5; class DeadStoreElimination final : public FEXCore::IR::Pass { public: - explicit DeadStoreElimination(bool SupportsAVX_) : SupportsAVX{SupportsAVX_} {} + explicit DeadStoreElimination(bool SupportsAVX_) + : SupportsAVX {SupportsAVX_} {} - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: bool SupportsAVX; @@ -36,29 +37,28 @@ private: bool IsFPR(uint32_t Offset) const { const auto [begin, end] = [this]() -> std::pair { if (SupportsAVX) { - return { - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[0][0]), - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[16][0]) - }; + return {offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[0][0]), + offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[16][0])}; } else { - return { - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[0][0]), - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[16][0]) - }; + return {offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[0][0]), + offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[16][0])}; } }(); - if (Offset < begin || Offset >= end) + if (Offset < begin || Offset >= end) { return false; + } return true; } bool IsTrackedWriteFPR(uint32_t Offset, uint8_t Size) const { - if (Size != 16 && Size != 8 && Size != 4) + if (Size != 16 && Size != 8 && Size != 4) { return false; - if (Offset & 15) + } + if (Offset & 15) { return false; + } return IsFPR(Offset); } @@ -70,56 +70,61 @@ private: const auto begin = offsetof(Core::CpuStateFrame, State.xmm.avx.data[0][0]); - const auto regSize = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE - : Core::CPUState::XMM_SSE_REG_SIZE; + const auto regSize = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; const auto regn = (Offset - begin) / regSize; const auto bitn = regn * 3; - if (!IsTrackedWriteFPR(Offset, Size)) + if (!IsTrackedWriteFPR(Offset, Size)) { return 7UL << (bitn); + } - if (Size == 16) - return 7UL << (bitn); - else if (Size == 8) - return 3UL << (bitn); - else if (Size == 4) - return 1UL << (bitn); - else + if (Size == 16) { + return 7UL << (bitn); + } else if (Size == 8) { + return 3UL << (bitn); + } else if (Size == 4) { + return 1UL << (bitn); + } else { LOGMAN_MSG_A_FMT("Unexpected FPR size {}", Size); + } return 7UL << (bitn); // Return maximum on failure case } }; struct FlagInfo { - uint64_t reads { 0 }; - uint64_t writes { 0 }; - uint64_t kill { 0 }; + uint64_t reads {0}; + uint64_t writes {0}; + uint64_t kill {0}; }; struct GPRInfo { - uint32_t reads { 0 }; - uint32_t writes { 0 }; - uint32_t kill { 0 }; + uint32_t reads {0}; + uint32_t writes {0}; + uint32_t kill {0}; }; bool IsFullGPR(uint32_t Offset, uint8_t Size) { - if (Size != 8) + if (Size != 8) { return false; - if (Offset & 7) + } + if (Offset & 7) { return false; + } - if (Offset < 8 || Offset >= (17 * 8)) + if (Offset < 8 || Offset >= (17 * 8)) { return false; + } return true; } bool IsGPR(uint32_t Offset) { - if (Offset < 8 || Offset >= (17 * 8)) + if (Offset < 8 || Offset >= (17 * 8)) { return false; + } return true; } @@ -129,13 +134,13 @@ uint32_t GPRBit(uint32_t Offset) { return 0; } - return 1 << ((Offset - 8)/8); + return 1 << ((Offset - 8) / 8); } struct FPRInfo { - uint64_t reads { 0 }; - uint64_t writes { 0 }; - uint64_t kill { 0 }; + uint64_t reads {0}; + uint64_t writes {0}; + uint64_t kill {0}; }; struct Info { @@ -155,7 +160,7 @@ struct Info { * Third pass removes the dead stores. * */ -bool DeadStoreElimination::Run(IREmitter *IREmit) { +bool DeadStoreElimination::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::DSE"); fextl::unordered_map InfoMap; @@ -170,21 +175,23 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) { for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { - auto ClassifyRegisterStore = [this](Info &BlockInfo, uint32_t Offset, uint8_t Size) { + auto ClassifyRegisterStore = [this](Info& BlockInfo, uint32_t Offset, uint8_t Size) { //// GPR //// - if (IsFullGPR(Offset, Size)) + if (IsFullGPR(Offset, Size)) { BlockInfo.gpr.writes |= GPRBit(Offset); - else + } else { BlockInfo.gpr.reads |= GPRBit(Offset); + } //// FPR //// - if (IsTrackedWriteFPR(Offset, Size)) + if (IsTrackedWriteFPR(Offset, Size)) { BlockInfo.fpr.writes |= FPRBit(Offset, Size); - else + } else { BlockInfo.fpr.reads |= FPRBit(Offset, Size); + } }; - auto ClassifyRegisterLoad = [this](Info &BlockInfo, uint32_t Offset, uint8_t Size) { + auto ClassifyRegisterLoad = [this](Info& BlockInfo, uint32_t Offset, uint8_t Size) { //// GPR //// BlockInfo.gpr.reads |= GPRBit(Offset); @@ -199,7 +206,7 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) { auto& BlockInfo = InfoMap[BlockNode]; BlockInfo.flag.writes |= 1UL << Op->Flag; - } else if (IROp->Op == OP_INVALIDATEFLAGS) { + } else if (IROp->Op == OP_INVALIDATEFLAGS) { auto Op = IROp->C(); auto& BlockInfo = InfoMap[BlockNode]; @@ -233,8 +240,7 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) { // Pass 2 // Compute flags/gprs/fprs that are stored, but always ovewritten in the next blocks // Propagate the information a few times to eliminate more - for (int i = 0; i < PropagationRounds; i++) - { + for (int i = 0; i < PropagationRounds; i++) { for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { auto CodeBlock = BlockIROp->C(); @@ -242,7 +248,7 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) { if (IROp->Op == OP_JUMP) { auto Op = IROp->C(); - OrderedNode *TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); + OrderedNode* TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); auto& BlockInfo = InfoMap[BlockNode]; auto& TargetInfo = InfoMap[TargetNode]; @@ -276,8 +282,8 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) { } else if (IROp->Op == OP_CONDJUMP) { auto Op = IROp->C(); - OrderedNode *TrueTargetNode = CurrentIR.GetNode(Op->TrueBlock); - OrderedNode *FalseTargetNode = CurrentIR.GetNode(Op->FalseBlock); + OrderedNode* TrueTargetNode = CurrentIR.GetNode(Op->TrueBlock); + OrderedNode* FalseTargetNode = CurrentIR.GetNode(Op->FalseBlock); auto& BlockInfo = InfoMap[BlockNode]; auto& TrueTargetInfo = InfoMap[TrueTargetNode]; @@ -321,8 +327,9 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) { for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { - auto RemoveDeadRegisterStore = [this](FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode *CodeNode, Info &BlockInfo, uint32_t Offset, uint8_t Size) -> bool { - bool Changed{}; + auto RemoveDeadRegisterStore = [this](FEXCore::IR::IREmitter* IREmit, FEXCore::IR::OrderedNode* CodeNode, Info& BlockInfo, + uint32_t Offset, uint8_t Size) -> bool { + bool Changed {}; //// GPRs //// // If this OP_STOREREGISTER is never read, remove it if (BlockInfo.gpr.kill & GPRBit(Offset)) { @@ -369,4 +376,4 @@ fextl::unique_ptr CreateDeadStoreElimination(bool SupportsAVX return fextl::make_unique(SupportsAVX); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index a146ed557..1c763a004 100644 --- a/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -32,27 +32,27 @@ static_assert(sizeof(RemapNode) == 4); class IRCompaction final : public FEXCore::IR::Pass { public: - IRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator); - bool Run(IREmitter *IREmit) override; + IRCompaction(FEXCore::Utils::IntrusivePooledAllocator& Allocator); + bool Run(IREmitter* IREmit) override; private: static constexpr size_t AlignSize = 0x2000; OpDispatchBuilder LocalBuilder; fextl::vector OldToNewRemap; struct CodeBlockData { - OrderedNode *OldNode; - OrderedNode *NewNode; + OrderedNode* OldNode; + OrderedNode* NewNode; }; - fextl::vector GeneratedCodeBlocks{}; + fextl::vector GeneratedCodeBlocks {}; }; -IRCompaction::IRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator) +IRCompaction::IRCompaction(FEXCore::Utils::IntrusivePooledAllocator& Allocator) : LocalBuilder {Allocator} { OldToNewRemap.resize(AlignSize); } -bool IRCompaction::Run(IREmitter *IREmit) { +bool IRCompaction::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::IRCompaction"); LocalBuilder.ReownOrClaimBuffer(); @@ -63,9 +63,9 @@ bool IRCompaction::Run(IREmitter *IREmit) { if (OldToNewRemap.size() < NodeCount) { OldToNewRemap.resize(std::max(OldToNewRemap.size() * 2U, AlignUp(NodeCount, AlignSize))); } - #ifndef NDEBUG - memset(&OldToNewRemap.at(0), 0xFF, NodeCount * sizeof(RemapNode)); - #endif +#ifndef NDEBUG + memset(&OldToNewRemap.at(0), 0xFF, NodeCount * sizeof(RemapNode)); +#endif GeneratedCodeBlocks.clear(); @@ -98,7 +98,8 @@ bool IRCompaction::Run(IREmitter *IREmit) { // Zero is always zero(invalid) OldToNewRemap[0].NodeID.Invalidate(); - auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->OriginalRIP, HeaderOp->BlockCount, HeaderOp->NumHostInstructions); + auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->OriginalRIP, + HeaderOp->BlockCount, HeaderOp->NumHostInstructions); OldToNewRemap[CurrentIR.GetID(HeaderNode).Value].NodeID = LocalIR.GetID(LocalHeaderOp.Node); @@ -109,7 +110,7 @@ bool IRCompaction::Run(IREmitter *IREmit) { auto LocalBlockIRNode = LocalBuilder._CodeBlock(LocalHeaderOp, LocalHeaderOp); // Use LocalHeaderOp as a dummy arg for now OldToNewRemap[CurrentIR.GetID(BlockNode).Value].NodeID = LocalIR.GetID(LocalBlockIRNode.Node); - GeneratedCodeBlocks.emplace_back(CodeBlockData{BlockNode, LocalBlockIRNode}); + GeneratedCodeBlocks.emplace_back(CodeBlockData {BlockNode, LocalBlockIRNode}); } // Link the IRHeader to the first code block @@ -118,13 +119,13 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Copy all of our IR ops over to the new location - for (auto &Block : GeneratedCodeBlocks) { + for (auto& Block : GeneratedCodeBlocks) { // Isolate block contents from any previous headers/blocks LocalBuilder.SetWriteCursor(nullptr); - CodeBlockData FirstNode{}; - CodeBlockData LastNode{}; + CodeBlockData FirstNode {}; + CodeBlockData LastNode {}; uint32_t i {}; for (auto [CodeNode, IROp] : CurrentIR.GetCode(Block.OldNode)) { const size_t OpSize = FEXCore::IR::GetSize(IROp->Op); @@ -166,7 +167,7 @@ bool IRCompaction::Run(IREmitter *IREmit) { { // Fixup the arguments of all the IROps - for (auto &Block : GeneratedCodeBlocks) { + for (auto& Block : GeneratedCodeBlocks) { #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED auto BlockIROp = LocalIR.GetOp(Block.NewNode); LOGMAN_THROW_AA_FMT(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block"); @@ -182,10 +183,9 @@ bool IRCompaction::Run(IREmitter *IREmit) { const auto OldArg = LocalIROp->Args[i].ID(); const auto NewArg = OldToNewRemap[OldArg.Value].NodeID; - #ifndef NDEBUG - LOGMAN_THROW_A_FMT(NewArg.Value != UINT32_MAX, - "Tried remapping unfound node %{}", OldArg); - #endif +#ifndef NDEBUG + LOGMAN_THROW_A_FMT(NewArg.Value != UINT32_MAX, "Tried remapping unfound node %{}", OldArg); +#endif LocalIROp->Args[i].NodeOffset = NewArg.Value * sizeof(OrderedNode); } @@ -221,8 +221,8 @@ bool IRCompaction::Run(IREmitter *IREmit) { return true; } -fextl::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator) { +fextl::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator& Allocator) { return fextl::make_unique(Allocator); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/IRDumperPass.cpp b/FEXCore/Source/Interface/IR/Passes/IRDumperPass.cpp index e3f8c2d2f..235b87b1d 100644 --- a/FEXCore/Source/Interface/IR/Passes/IRDumperPass.cpp +++ b/FEXCore/Source/Interface/IR/Passes/IRDumperPass.cpp @@ -18,39 +18,36 @@ namespace FEXCore::IR::Debug { class IRDumper final : public FEXCore::IR::Pass { public: IRDumper(); - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: FEX_CONFIG_OPT(DumpIR, DUMPIR); - bool DumpToFile{}; - bool DumpToLog{}; + bool DumpToFile {}; + bool DumpToLog {}; }; IRDumper::IRDumper() { const auto DumpIRStr = DumpIR(); if (DumpIRStr == "stderr" || DumpIRStr == "stdout" || DumpIRStr == "no") { // Intentionally do nothing - } - else if (DumpIRStr == "server") { + } else if (DumpIRStr == "server") { DumpToLog = true; - } - else { + } else { DumpToFile = true; } } -bool IRDumper::Run(IREmitter *IREmit) { +bool IRDumper::Run(IREmitter* IREmit) { auto RAPass = Manager->GetPass("RA"); - IR::RegisterAllocationData* RA{}; + IR::RegisterAllocationData* RA {}; if (RAPass) { RA = RAPass->GetAllocationData(); } - FEXCore::File::File FD{}; + FEXCore::File::File FD {}; if (DumpIR() == "stderr") { FD = FEXCore::File::File::GetStdERR(); - } - else if (DumpIR() == "stdout") { + } else if (DumpIR() == "stdout") { FD = FEXCore::File::File::GetStdOUT(); } @@ -62,9 +59,7 @@ bool IRDumper::Run(IREmitter *IREmit) { if (DumpToFile) { const auto fileName = fextl::fmt::format("{}/{:x}{}", DumpIR(), HeaderOp->OriginalRIP, RA ? "-post.ir" : "-pre.ir"); FD = FEXCore::File::File(fileName.c_str(), - FEXCore::File::FileModes::WRITE | - FEXCore::File::FileModes::CREATE | - FEXCore::File::FileModes::TRUNCATE); + FEXCore::File::FileModes::WRITE | FEXCore::File::FileModes::CREATE | FEXCore::File::FileModes::TRUNCATE); } if (FD.IsValid() || DumpToLog) { @@ -72,8 +67,7 @@ bool IRDumper::Run(IREmitter *IREmit) { FEXCore::IR::Dump(&out, &IR, RA); if (FD.IsValid()) { fextl::fmt::print(FD, "IR-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", HeaderOp->OriginalRIP, out.str()); - } - else { + } else { LogMan::Msg::IFmt("IR-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", HeaderOp->OriginalRIP, out.str()); } } @@ -84,4 +78,4 @@ bool IRDumper::Run(IREmitter *IREmit) { fextl::unique_ptr CreateIRDumper() { return fextl::make_unique(); } -} +} // namespace FEXCore::IR::Debug diff --git a/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 29b696ef8..7c2e0c1b1 100644 --- a/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -32,7 +32,7 @@ IRValidation::~IRValidation() { NodeIsLive.Free(); } -bool IRValidation::Run(IREmitter *IREmit) { +bool IRValidation::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::IRValidation"); bool HadError = false; @@ -57,7 +57,7 @@ bool IRValidation::Run(IREmitter *IREmit) { LOGMAN_THROW_A_FMT(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader"); #endif - IR::RegisterAllocationData * RAData{}; + IR::RegisterAllocationData* RAData {}; if (Manager->HasPass("RA")) { RAData = Manager->GetPass("RA")->GetAllocationData(); } @@ -73,7 +73,7 @@ bool IRValidation::Run(IREmitter *IREmit) { } const auto BlockID = CurrentIR.GetID(BlockNode); - BlockInfo *CurrentBlock = &OffsetToBlockMap.try_emplace(BlockID).first->second; + BlockInfo* CurrentBlock = &OffsetToBlockMap.try_emplace(BlockID).first->second; for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { const auto ID = CurrentIR.GetID(CodeNode); @@ -97,7 +97,7 @@ bool IRValidation::Run(IREmitter *IREmit) { auto PhyReg = RAData->GetNodeRegister(ID); FEXCore::IR::RegisterClassType ExpectedClass = IR::GetRegClass(IROp->Op); - FEXCore::IR::RegisterClassType AssignedClass = FEXCore::IR::RegisterClassType{PhyReg.Class}; + FEXCore::IR::RegisterClassType AssignedClass = FEXCore::IR::RegisterClassType {PhyReg.Class}; // If no register class was assigned if (AssignedClass == IR::InvalidClass) { @@ -112,10 +112,10 @@ bool IRValidation::Run(IREmitter *IREmit) { } // Assigned class wasn't the expected class and it is a non-complex op - if (AssignedClass != ExpectedClass && - ExpectedClass != IR::ComplexClass) { + if (AssignedClass != ExpectedClass && ExpectedClass != IR::ComplexClass) { HadWarning |= true; - Warnings << "%" << ID << ": Destination had register class " << AssignedClass.Val << " When register class " << ExpectedClass.Val << " Was expected" << std::endl; + Warnings << "%" << ID << ": Destination had register class " << AssignedClass.Val << " When register class " + << ExpectedClass.Val << " Was expected" << std::endl; } } } @@ -145,60 +145,57 @@ bool IRValidation::Run(IREmitter *IREmit) { NodeIsLive.Set(ID.Value); switch (IROp->Op) { - case IR::OP_EXITFUNCTION: { - CurrentBlock->HasExit = true; + case IR::OP_EXITFUNCTION: { + CurrentBlock->HasExit = true; break; + } + case IR::OP_CONDJUMP: { + auto Op = IROp->C(); + + OrderedNode* TrueTargetNode = CurrentIR.GetNode(Op->TrueBlock); + OrderedNode* FalseTargetNode = CurrentIR.GetNode(Op->FalseBlock); + + CurrentBlock->Successors.emplace_back(TrueTargetNode); + CurrentBlock->Successors.emplace_back(FalseTargetNode); + + const FEXCore::IR::IROp_Header* TrueTargetOp = CurrentIR.GetOp(TrueTargetNode); + const FEXCore::IR::IROp_Header* FalseTargetOp = CurrentIR.GetOp(FalseTargetNode); + + if (TrueTargetOp->Op != OP_CODEBLOCK) { + HadError |= true; + Errors << "CondJump %" << ID << ": True Target Jumps to Op that isn't the begining of a block" << std::endl; + } else { + auto Block = OffsetToBlockMap.try_emplace(Op->TrueBlock.ID()).first; + Block->second.Predecessors.emplace_back(BlockNode); } - case IR::OP_CONDJUMP: { - auto Op = IROp->C(); - OrderedNode *TrueTargetNode = CurrentIR.GetNode(Op->TrueBlock); - OrderedNode *FalseTargetNode = CurrentIR.GetNode(Op->FalseBlock); - - CurrentBlock->Successors.emplace_back(TrueTargetNode); - CurrentBlock->Successors.emplace_back(FalseTargetNode); - - FEXCore::IR::IROp_Header const *TrueTargetOp = CurrentIR.GetOp(TrueTargetNode); - FEXCore::IR::IROp_Header const *FalseTargetOp = CurrentIR.GetOp(FalseTargetNode); - - if (TrueTargetOp->Op != OP_CODEBLOCK) { - HadError |= true; - Errors << "CondJump %" << ID << ": True Target Jumps to Op that isn't the begining of a block" << std::endl; - } - else { - auto Block = OffsetToBlockMap.try_emplace(Op->TrueBlock.ID()).first; - Block->second.Predecessors.emplace_back(BlockNode); - } - - if (FalseTargetOp->Op != OP_CODEBLOCK) { - HadError |= true; - Errors << "CondJump %" << ID << ": False Target Jumps to Op that isn't the begining of a block" << std::endl; - } - else { - auto Block = OffsetToBlockMap.try_emplace(Op->FalseBlock.ID()).first; - Block->second.Predecessors.emplace_back(BlockNode); - } - - break; + if (FalseTargetOp->Op != OP_CODEBLOCK) { + HadError |= true; + Errors << "CondJump %" << ID << ": False Target Jumps to Op that isn't the begining of a block" << std::endl; + } else { + auto Block = OffsetToBlockMap.try_emplace(Op->FalseBlock.ID()).first; + Block->second.Predecessors.emplace_back(BlockNode); } - case IR::OP_JUMP: { - auto Op = IROp->C(); - OrderedNode *TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); - CurrentBlock->Successors.emplace_back(TargetNode); - FEXCore::IR::IROp_Header const *TargetOp = CurrentIR.GetOp(TargetNode); - if (TargetOp->Op != OP_CODEBLOCK) { - HadError |= true; - Errors << "Jump %" << ID << ": Jump to Op that isn't the begining of a block" << std::endl; - } - else { - auto Block = OffsetToBlockMap.try_emplace(Op->Header.Args[0].ID()).first; - Block->second.Predecessors.emplace_back(BlockNode); - } - break; + break; + } + case IR::OP_JUMP: { + auto Op = IROp->C(); + OrderedNode* TargetNode = CurrentIR.GetNode(Op->Header.Args[0]); + CurrentBlock->Successors.emplace_back(TargetNode); + + const FEXCore::IR::IROp_Header* TargetOp = CurrentIR.GetOp(TargetNode); + if (TargetOp->Op != OP_CODEBLOCK) { + HadError |= true; + Errors << "Jump %" << ID << ": Jump to Op that isn't the begining of a block" << std::endl; + } else { + auto Block = OffsetToBlockMap.try_emplace(Op->Header.Args[0].ID()).first; + Block->second.Predecessors.emplace_back(BlockNode); } - default: - // LOGMAN_MSG_A_FMT("Unknown IR Op: {}({})", IROp->Op, FEXCore::IR::GetName(IROp->Op)); + break; + } + default: + // LOGMAN_MSG_A_FMT("Unknown IR Op: {}({})", IROp->Op, FEXCore::IR::GetName(IROp->Op)); break; } } @@ -241,7 +238,7 @@ bool IRValidation::Run(IREmitter *IREmit) { } for (uint32_t i = 0; i < CurrentIR.GetSSACount(); i++) { - auto [Node, IROp] = CurrentIR.at(IR::NodeID{i})(); + auto [Node, IROp] = CurrentIR.at(IR::NodeID {i})(); if (Node->NumUses != Uses[i] && IROp->Op != OP_CODEBLOCK && IROp->Op != OP_IRHEADER) { HadError |= true; Errors << "%" << i << " Has " << Uses[i] << " Uses, but reports " << Node->NumUses << std::endl; @@ -275,4 +272,4 @@ bool IRValidation::Run(IREmitter *IREmit) { fextl::unique_ptr CreateIRValidation() { return fextl::make_unique(); } -} +} // namespace FEXCore::IR::Validation diff --git a/FEXCore/Source/Interface/IR/Passes/IRValidation.h b/FEXCore/Source/Interface/IR/Passes/IRValidation.h index 91c72b685..1a28de4d8 100644 --- a/FEXCore/Source/Interface/IR/Passes/IRValidation.h +++ b/FEXCore/Source/Interface/IR/Passes/IRValidation.h @@ -10,7 +10,7 @@ namespace FEXCore::IR::Validation { struct BlockInfo { bool HasExit; - OrderedNode const *BlockNode; + const OrderedNode* BlockNode; fextl::vector Predecessors; fextl::vector Successors; @@ -21,15 +21,15 @@ class RAValidation; class IRValidation final : public FEXCore::IR::Pass { public: ~IRValidation(); - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: BitSet NodeIsLive; - OrderedNode *EntryBlock; + OrderedNode* EntryBlock; fextl::unordered_map OffsetToBlockMap; - size_t MaxNodes{}; + size_t MaxNodes {}; friend class RAValidation; }; -} +} // namespace FEXCore::IR::Validation diff --git a/FEXCore/Source/Interface/IR/Passes/InlineCallOptimization.cpp b/FEXCore/Source/Interface/IR/Passes/InlineCallOptimization.cpp index 8a0e7f4d0..709b8dba9 100644 --- a/FEXCore/Source/Interface/IR/Passes/InlineCallOptimization.cpp +++ b/FEXCore/Source/Interface/IR/Passes/InlineCallOptimization.cpp @@ -23,12 +23,12 @@ class InlineCallOptimization final : public FEXCore::IR::Pass { public: InlineCallOptimization(const FEXCore::CPUIDEmu* CPUID) : CPUID {CPUID} {} - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: const FEXCore::CPUIDEmu* CPUID; }; -bool InlineCallOptimization::Run(IREmitter *IREmit) { +bool InlineCallOptimization::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::SyscallOpt"); bool Changed = false; @@ -60,15 +60,10 @@ bool InlineCallOptimization::Run(IREmitter *IREmit) { if (SyscallDef.HostSyscallNumber != -1) { IREmit->SetWriteCursor(CodeNode); // Skip Args[0] since that is the syscallid - auto InlineSyscall = IREmit->_InlineSyscall( - CurrentIR.GetNode(IROp->Args[1]), - CurrentIR.GetNode(IROp->Args[2]), - CurrentIR.GetNode(IROp->Args[3]), - CurrentIR.GetNode(IROp->Args[4]), - CurrentIR.GetNode(IROp->Args[5]), - CurrentIR.GetNode(IROp->Args[6]), - SyscallDef.HostSyscallNumber, - Op->Flags); + auto InlineSyscall = + IREmit->_InlineSyscall(CurrentIR.GetNode(IROp->Args[1]), CurrentIR.GetNode(IROp->Args[2]), CurrentIR.GetNode(IROp->Args[3]), + CurrentIR.GetNode(IROp->Args[4]), CurrentIR.GetNode(IROp->Args[5]), CurrentIR.GetNode(IROp->Args[6]), + SyscallDef.HostSyscallNumber, Op->Flags); // Replace all syscall uses with this inline one IREmit->ReplaceAllUsesWith(CodeNode, InlineSyscall); @@ -81,11 +76,10 @@ bool InlineCallOptimization::Run(IREmitter *IREmit) { Changed = true; } - } - else if (IROp->Op == FEXCore::IR::OP_CPUID) { + } else if (IROp->Op == FEXCore::IR::OP_CPUID) { auto Op = IROp->CW(); - uint64_t ConstantFunction{}, ConstantLeaf{}; + uint64_t ConstantFunction {}, ConstantLeaf {}; bool IsConstantFunction = IREmit->IsValueConstant(Op->Function, &ConstantFunction); bool IsConstantLeaf = IREmit->IsValueConstant(Op->Leaf, &ConstantLeaf); // If the CPUID function is constant then we can try and optimize. @@ -113,12 +107,12 @@ bool InlineCallOptimization::Run(IREmitter *IREmit) { else if (IROp->Op == FEXCore::IR::OP_XGETBV) { auto Op = IROp->CW(); - uint64_t ConstantFunction{}; - if (IREmit->IsValueConstant(Op->Function, &ConstantFunction) && - CPUID->DoesXCRFunctionReportConstantData(ConstantFunction)) { + uint64_t ConstantFunction {}; + if (IREmit->IsValueConstant(Op->Function, &ConstantFunction) && CPUID->DoesXCRFunctionReportConstantData(ConstantFunction)) { const auto ConstantXCRResult = CPUID->RunXCRFunction(ConstantFunction); IREmit->SetWriteCursor(CodeNode); - auto ElementPair = IREmit->_CreateElementPair(IR::OpSize::i64Bit, IREmit->_Constant(ConstantXCRResult.eax), IREmit->_Constant(ConstantXCRResult.edx)); + auto ElementPair = + IREmit->_CreateElementPair(IR::OpSize::i64Bit, IREmit->_Constant(ConstantXCRResult.eax), IREmit->_Constant(ConstantXCRResult.edx)); // Replace all xgetbv uses with this inline one IREmit->ReplaceAllUsesWith(CodeNode, ElementPair); Changed = true; @@ -132,4 +126,4 @@ fextl::unique_ptr CreateInlineCallOptimization(const FEXCore: return fextl::make_unique(CPUID); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp b/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp index 03d3cf14f..f1033f9f7 100644 --- a/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp +++ b/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp @@ -18,13 +18,13 @@ namespace FEXCore::IR { class LongDivideEliminationPass final : public FEXCore::IR::Pass { public: - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: - bool IsZeroOp(IREmitter *IREmit, OrderedNodeWrapper Arg); - bool IsSextOp(IREmitter *IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper); + bool IsZeroOp(IREmitter* IREmit, OrderedNodeWrapper Arg); + bool IsSextOp(IREmitter* IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper); }; -bool LongDivideEliminationPass::IsZeroOp(IREmitter *IREmit, OrderedNodeWrapper Arg) { +bool LongDivideEliminationPass::IsZeroOp(IREmitter* IREmit, OrderedNodeWrapper Arg) { uint64_t Value; if (IREmit->IsValueConstant(Arg, &Value)) { @@ -34,11 +34,11 @@ bool LongDivideEliminationPass::IsZeroOp(IREmitter *IREmit, OrderedNodeWrapper A return false; } -bool LongDivideEliminationPass::IsSextOp(IREmitter *IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper) { +bool LongDivideEliminationPass::IsSextOp(IREmitter* IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper) { // We need to check if the upper source is a sext of the lower source auto UpperIROp = IREmit->GetOpHeader(Upper); if (UpperIROp->Op == OP_SBFE) { - auto Op = UpperIROp->C(); + auto Op = UpperIROp->C(); if (Op->Width == 1 && Op->lsb == 63) { // CQO: OrderedNode *Upper = _Sbfe(1, Size * 8 - 1, Src); // If the lower is the upper in this case then it can be optimized @@ -48,7 +48,7 @@ bool LongDivideEliminationPass::IsSextOp(IREmitter *IREmit, OrderedNodeWrapper L return false; } -bool LongDivideEliminationPass::Run(IREmitter *IREmit) { +bool LongDivideEliminationPass::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::LDE"); bool Changed = false; @@ -58,41 +58,36 @@ bool LongDivideEliminationPass::Run(IREmitter *IREmit) { for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) { for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { if (IROp->Size == 8) { - if (IROp->Op == OP_LDIV || - IROp->Op == OP_LREM) { + if (IROp->Op == OP_LDIV || IROp->Op == OP_LREM) { auto Op = IROp->C(); // Check upper Op to see if it came from a CQO // CQO: OrderedNode *Upper = _Sbfe(1, Size * 8 - 1, Src); // If it does then it we only need a 64bit SDIV if (IsSextOp(IREmit, Op->Lower, Op->Upper)) { IREmit->SetWriteCursor(CodeNode); - OrderedNode *Lower = CurrentIR.GetNode(Op->Lower); - OrderedNode *Divisor = CurrentIR.GetNode(Op->Divisor); - OrderedNode *SDivOp{}; + OrderedNode* Lower = CurrentIR.GetNode(Op->Lower); + OrderedNode* Divisor = CurrentIR.GetNode(Op->Divisor); + OrderedNode* SDivOp {}; if (IROp->Op == OP_LDIV) { SDivOp = IREmit->_Div(OpSize::i64Bit, Lower, Divisor); - } - else { + } else { SDivOp = IREmit->_Rem(OpSize::i64Bit, Lower, Divisor); } IREmit->ReplaceAllUsesWith(CodeNode, SDivOp); Changed = true; } - } - else if (IROp->Op == OP_LUDIV || - IROp->Op == OP_LUREM) { + } else if (IROp->Op == OP_LUDIV || IROp->Op == OP_LUREM) { auto Op = IROp->C(); // Check upper Op to see if it came from a zeroing op // If it does then it we only need a 64bit UDIV if (IsZeroOp(IREmit, Op->Upper)) { IREmit->SetWriteCursor(CodeNode); - OrderedNode *Lower = CurrentIR.GetNode(Op->Lower); - OrderedNode *Divisor = CurrentIR.GetNode(Op->Divisor); - OrderedNode *UDivOp{}; + OrderedNode* Lower = CurrentIR.GetNode(Op->Lower); + OrderedNode* Divisor = CurrentIR.GetNode(Op->Divisor); + OrderedNode* UDivOp {}; if (IROp->Op == OP_LUDIV) { UDivOp = IREmit->_UDiv(OpSize::i64Bit, Lower, Divisor); - } - else { + } else { UDivOp = IREmit->_URem(OpSize::i64Bit, Lower, Divisor); } IREmit->ReplaceAllUsesWith(CodeNode, UDivOp); @@ -111,4 +106,4 @@ bool LongDivideEliminationPass::Run(IREmitter *IREmit) { fextl::unique_ptr CreateLongDivideEliminationPass() { return fextl::make_unique(); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp b/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp index 6f95ecbab..eb9f87f74 100644 --- a/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp @@ -20,11 +20,11 @@ namespace FEXCore::IR::Validation { // Hold the mapping of physical registers to the SSA id it holds at any given point in the IR struct RegState { - static constexpr IR::NodeID UninitializedValue{0}; - static constexpr IR::NodeID InvalidReg {0xffff'ffff}; - static constexpr IR::NodeID CorruptedPair {0xffff'fffe}; - static constexpr IR::NodeID ClobberedValue {0xffff'fffd}; - static constexpr IR::NodeID StaticAssigned {0xffff'ff00}; + static constexpr IR::NodeID UninitializedValue {0}; + static constexpr IR::NodeID InvalidReg {0xffff'ffff}; + static constexpr IR::NodeID CorruptedPair {0xffff'fffe}; + static constexpr IR::NodeID ClobberedValue {0xffff'fffd}; + static constexpr IR::NodeID StaticAssigned {0xffff'ff00}; // This class makes some assumptions about how the host registers are arranged and mapped to virtual registers: // 1. There will be less than 32 GPRs and 32 FPRs @@ -41,24 +41,20 @@ struct RegState { // PhysicalRegisters aren't fully mapped until assembly emission // We need to apply a generic mapping here to catch any aliasing switch (Reg.Class) { - case GPRClass: - GPRs[Reg.Reg] = ssa; - return true; + case GPRClass: GPRs[Reg.Reg] = ssa; return true; case GPRFixedClass: // On arm64, there are 16 Fixed and 9 normal GPRsFixed[Reg.Reg] = ssa; return true; - case FPRClass: - FPRs[Reg.Reg] = ssa; - return true; + case FPRClass: FPRs[Reg.Reg] = ssa; return true; case FPRFixedClass: // On arm64, there are 16 Fixed and 12 normal FPRsFixed[Reg.Reg] = ssa; return true; case GPRPairClass: // Alias paired registers onto both - GPRs[Reg.Reg*2] = ssa; - GPRs[Reg.Reg*2 + 1] = ssa; + GPRs[Reg.Reg * 2] = ssa; + GPRs[Reg.Reg * 2 + 1] = ssa; return true; } return false; @@ -68,18 +64,14 @@ struct RegState { // Or an error value there isn't a (sane) SSA id IR::NodeID Get(PhysicalRegister Reg) const { switch (Reg.Class) { - case GPRClass: - return GPRs[Reg.Reg]; - case GPRFixedClass: - return GPRsFixed[Reg.Reg]; - case FPRClass: - return FPRs[Reg.Reg]; - case FPRFixedClass: - return FPRsFixed[Reg.Reg]; + case GPRClass: return GPRs[Reg.Reg]; + case GPRFixedClass: return GPRsFixed[Reg.Reg]; + case FPRClass: return FPRs[Reg.Reg]; + case FPRFixedClass: return FPRsFixed[Reg.Reg]; case GPRPairClass: // Make sure both halves of the Pair contain the same SSA - if (GPRs[Reg.Reg*2] == GPRs[Reg.Reg*2 + 1]) { - return GPRs[Reg.Reg*2]; + if (GPRs[Reg.Reg * 2] == GPRs[Reg.Reg * 2 + 1]) { + return GPRs[Reg.Reg * 2]; } return CorruptedPair; } @@ -147,25 +139,25 @@ struct RegState { // Mark them as Clobbered. // Useful for backwards edges, where using an SSA from before the void Filter(IR::NodeID MaxSSA) { - for (auto &gpr : GPRs) { + for (auto& gpr : GPRs) { if (gpr > MaxSSA) { gpr = ClobberedValue; } } - for (auto &gpr : GPRsFixed) { + for (auto& gpr : GPRsFixed) { if (gpr > MaxSSA) { gpr = ClobberedValue; } } - for (auto &fpr : FPRs) { + for (auto& fpr : FPRs) { if (fpr > MaxSSA) { fpr = ClobberedValue; } } - for (auto &fpr : FPRsFixed) { + for (auto& fpr : FPRsFixed) { if (fpr > MaxSSA) { fpr = ClobberedValue; } @@ -188,13 +180,13 @@ private: fextl::unordered_map Spills; public: - uint32_t Version{}; // Used to force regeneration of RegStates after following backward edges + uint32_t Version {}; // Used to force regeneration of RegStates after following backward edges }; class RAValidation final : public FEXCore::IR::Pass { public: ~RAValidation() {} - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: // Holds the calculated RegState at the exit of each block @@ -205,8 +197,10 @@ private: }; -bool RAValidation::Run(IREmitter *IREmit) { - if (!Manager->HasPass("RA")) return false; +bool RAValidation::Run(IREmitter* IREmit) { + if (!Manager->HasPass("RA")) { + return false; + } FEXCORE_PROFILE_SCOPED("PassManager::RAValidation"); @@ -229,8 +223,7 @@ bool RAValidation::Run(IREmitter *IREmit) { auto CurrentIR = IREmit->ViewIR(); uint32_t CurrentVersion = 1; // Incremented every backwards edge - while (!BlocksToVisit.empty()) - { + while (!BlocksToVisit.empty()) { auto BlockNode = BlocksToVisit.front(); const auto BlockID = CurrentIR.GetID(BlockNode); auto& BlockInfo = OffsetToBlockMap[BlockID]; @@ -275,7 +268,7 @@ bool RAValidation::Run(IREmitter *IREmit) { auto& BlockRegState = BlockExitState.try_emplace(BlockID).first->second; bool EmptyRegState = true; - auto Intersect = [&] (RegState& Other) { + auto Intersect = [&](RegState& Other) { if (EmptyRegState) { BlockRegState = Other; EmptyRegState = false; @@ -306,8 +299,9 @@ bool RAValidation::Run(IREmitter *IREmit) { const auto ArgID = Arg.ID(); const auto PhyReg = RAData->GetNodeRegister(ArgID); - if (PhyReg.IsInvalid()) + if (PhyReg.IsInvalid()) { return; + } auto CurrentSSAAtReg = BlockRegState.Get(PhyReg); if (CurrentSSAAtReg == RegState::InvalidReg) { @@ -316,30 +310,28 @@ bool RAValidation::Run(IREmitter *IREmit) { } else if (CurrentSSAAtReg == RegState::CorruptedPair) { HadError |= true; - auto Lower = BlockRegState.Get(PhysicalRegister(GPRClass, uint8_t(PhyReg.Reg*2) + 1)); - auto Upper = BlockRegState.Get(PhysicalRegister(GPRClass, PhyReg.Reg*2 + 1)); + auto Lower = BlockRegState.Get(PhysicalRegister(GPRClass, uint8_t(PhyReg.Reg * 2) + 1)); + auto Upper = BlockRegState.Get(PhysicalRegister(GPRClass, PhyReg.Reg * 2 + 1)); - Errors << fextl::fmt::format("%{}: Arg[{}] expects paired reg{} to contain %{}, but it actually contains {{%{}, %{}}}\n", - ID, i, PhyReg.Reg, ArgID, Lower, Upper); + Errors << fextl::fmt::format("%{}: Arg[{}] expects paired reg{} to contain %{}, but it actually contains {{%{}, %{}}}\n", ID, i, + PhyReg.Reg, ArgID, Lower, Upper); } else if (CurrentSSAAtReg == RegState::UninitializedValue) { HadError |= true; - Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it is uninitialized\n", - ID, i, PhyReg.Reg, ArgID); + Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it is uninitialized\n", ID, i, PhyReg.Reg, ArgID); } else if (CurrentSSAAtReg == RegState::ClobberedValue) { HadError |= true; - Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but contents vary depending on control flow\n", - ID, i, PhyReg.Reg, ArgID); + Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but contents vary depending on control flow\n", ID, i, + PhyReg.Reg, ArgID); } else if (CurrentSSAAtReg != ArgID) { HadError |= true; - Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it actually contains %{}\n", - ID, i, PhyReg.Reg, ArgID, CurrentSSAAtReg); + Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it actually contains %{}\n", ID, i, PhyReg.Reg, + ArgID, CurrentSSAAtReg); } }; - switch (IROp->Op) - { + switch (IROp->Op) { case OP_SPILLREGISTER: { auto SpillRegister = IROp->C(); CheckArg(0, SpillRegister->Value); @@ -359,15 +351,15 @@ bool RAValidation::Run(IREmitter *IREmit) { if (Value == RegState::UninitializedValue) { HadError |= true; Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but was undefined in at least one control flow path\n", - ID, ExpectedValue, FillRegister->Slot); + ID, ExpectedValue, FillRegister->Slot); } else if (Value == RegState::ClobberedValue) { HadError |= true; - Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but contents vary depending on control flow\n", - ID, ExpectedValue, FillRegister->Slot); + Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but contents vary depending on control flow\n", ID, + ExpectedValue, FillRegister->Slot); } else if (Value != ExpectedValue) { HadError |= true; - Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but it actually contains %{}\n", - ID, ExpectedValue, FillRegister->Slot, Value); + Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but it actually contains %{}\n", ID, ExpectedValue, + FillRegister->Slot, Value); } break; } @@ -444,7 +436,6 @@ bool RAValidation::Run(IREmitter *IREmit) { Errors << "(Backwards): "; } Errors << fextl::fmt::format("Block {} ", SuccessorID); - } Errors << "\n\n"; @@ -452,7 +443,6 @@ bool RAValidation::Run(IREmitter *IREmit) { break; } - } if (HadError) { @@ -471,4 +461,4 @@ bool RAValidation::Run(IREmitter *IREmit) { fextl::unique_ptr CreateRAValidation() { return fextl::make_unique(); } -} +} // namespace FEXCore::IR::Validation diff --git a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index 4248d08ae..856645fc2 100644 --- a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -53,271 +53,259 @@ struct FlagInfo { class DeadFlagCalculationEliminination final : public FEXCore::IR::Pass { public: - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; private: - FlagInfo Classify(IROp_Header *Node); + FlagInfo Classify(IROp_Header* Node); unsigned FlagForOffset(unsigned Offset); unsigned FlagsForCondClassType(CondClassType Cond); }; -unsigned -DeadFlagCalculationEliminination::FlagForOffset(unsigned Offset) -{ - return Offset == offsetof(FEXCore::Core::CPUState, pf_raw) ? FLAG_P : - Offset == offsetof(FEXCore::Core::CPUState, af_raw) ? FLAG_A : - 0; +unsigned DeadFlagCalculationEliminination::FlagForOffset(unsigned Offset) { + return Offset == offsetof(FEXCore::Core::CPUState, pf_raw) ? FLAG_P : Offset == offsetof(FEXCore::Core::CPUState, af_raw) ? FLAG_A : 0; }; -unsigned -DeadFlagCalculationEliminination::FlagsForCondClassType(CondClassType Cond) -{ +unsigned DeadFlagCalculationEliminination::FlagsForCondClassType(CondClassType Cond) { switch (Cond) { - case COND_AL: - return 0; + case COND_AL: return 0; case COND_MI: - case COND_PL: - return FLAG_N; + case COND_PL: return FLAG_N; case COND_EQ: - case COND_NEQ: - return FLAG_Z; + case COND_NEQ: return FLAG_Z; case COND_UGE: - case COND_ULT: - return FLAG_C; + case COND_ULT: return FLAG_C; case COND_VS: case COND_VC: case COND_FU: - case COND_FNU: - return FLAG_V; + case COND_FNU: return FLAG_V; case COND_UGT: - case COND_ULE: - return FLAG_Z | FLAG_C; + case COND_ULE: return FLAG_Z | FLAG_C; case COND_SGE: case COND_SLT: case COND_FLU: - case COND_FGE: - return FLAG_N | FLAG_V; + case COND_FGE: return FLAG_N | FLAG_V; case COND_SGT: case COND_SLE: case COND_FLEU: - case COND_FGT: - return FLAG_N | FLAG_Z | FLAG_V; + case COND_FGT: return FLAG_N | FLAG_Z | FLAG_V; - default: - LOGMAN_THROW_AA_FMT(false, "unknown cond class type"); - return FLAG_NZCV; + default: LOGMAN_THROW_AA_FMT(false, "unknown cond class type"); return FLAG_NZCV; } } -FlagInfo -DeadFlagCalculationEliminination::Classify(IROp_Header *IROp) -{ +FlagInfo DeadFlagCalculationEliminination::Classify(IROp_Header* IROp) { switch (IROp->Op) { - case OP_ANDWITHFLAGS: - return { - .Write = FLAG_NZCV, - .CanReplace = true, - .Replacement = OP_AND, - }; + case OP_ANDWITHFLAGS: + return { + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_AND, + }; - case OP_ADDWITHFLAGS: - return { - .Write = FLAG_NZCV, - .CanReplace = true, - .Replacement = OP_ADD, - }; + case OP_ADDWITHFLAGS: + return { + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_ADD, + }; - case OP_SUBWITHFLAGS: - return { - .Write = FLAG_NZCV, - .CanReplace = true, - .Replacement = OP_SUB, - }; + case OP_SUBWITHFLAGS: + return { + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_SUB, + }; - case OP_ADCWITHFLAGS: - return { - .Read = FLAG_C, - .Write = FLAG_NZCV, - .CanReplace = true, - .Replacement = OP_ADC, - }; + case OP_ADCWITHFLAGS: + return { + .Read = FLAG_C, + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_ADC, + }; - case OP_SBBWITHFLAGS: - return { - .Read = FLAG_C, - .Write = FLAG_NZCV, - .CanReplace = true, - .Replacement = OP_SBB, - }; + case OP_SBBWITHFLAGS: + return { + .Read = FLAG_C, + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_SBB, + }; - case OP_SHIFTFLAGS: - // _ShiftFlags conditionally sets NZCV+PF, which we model here as a - // read-modify-write. Logically, it also conditionally makes AF undefined, - // which we model by omitting AF from both Read and Write sets (since - // "cond ? AF : undef" may be optimized to "AF"). - return { - .Read = FLAG_NZCV | FLAG_P, - .Write = FLAG_NZCV | FLAG_P, - .CanEliminate = true, - }; + case OP_SHIFTFLAGS: + // _ShiftFlags conditionally sets NZCV+PF, which we model here as a + // read-modify-write. Logically, it also conditionally makes AF undefined, + // which we model by omitting AF from both Read and Write sets (since + // "cond ? AF : undef" may be optimized to "AF"). + return { + .Read = FLAG_NZCV | FLAG_P, + .Write = FLAG_NZCV | FLAG_P, + .CanEliminate = true, + }; - case OP_ADDNZCV: - case OP_SUBNZCV: - case OP_TESTNZ: - case OP_FCMP: - case OP_STORENZCV: - return { - .Write = FLAG_NZCV, - .CanEliminate = true, - }; + case OP_ADDNZCV: + case OP_SUBNZCV: + case OP_TESTNZ: + case OP_FCMP: + case OP_STORENZCV: + return { + .Write = FLAG_NZCV, + .CanEliminate = true, + }; - case OP_AXFLAG: - // Per the Arm spec, axflag reads Z/V/C but not N. It writes all flags. - return { - .Read = FLAG_ZCV, - .Write = FLAG_NZCV, - .CanEliminate = true, - }; + case OP_AXFLAG: + // Per the Arm spec, axflag reads Z/V/C but not N. It writes all flags. + return { + .Read = FLAG_ZCV, + .Write = FLAG_NZCV, + .CanEliminate = true, + }; - case OP_CMPPAIRZ: - return { - .Write = FLAG_Z, - .CanEliminate = true, - }; + case OP_CMPPAIRZ: + return { + .Write = FLAG_Z, + .CanEliminate = true, + }; - case OP_CARRYINVERT: - return { - .Read = FLAG_C, - .Write = FLAG_C, - .CanEliminate = true, - }; + case OP_CARRYINVERT: + return { + .Read = FLAG_C, + .Write = FLAG_C, + .CanEliminate = true, + }; - case OP_SETSMALLNZV: - return { - .Write = FLAG_N | FLAG_Z | FLAG_V, - .CanEliminate = true, - }; + case OP_SETSMALLNZV: + return { + .Write = FLAG_N | FLAG_Z | FLAG_V, + .CanEliminate = true, + }; - case OP_LOADNZCV: - return {.Read = FLAG_NZCV}; + case OP_LOADNZCV: return {.Read = FLAG_NZCV}; - case OP_ADC: - case OP_SBB: - return {.Read = FLAG_C}; - - case OP_ADCNZCV: - case OP_SBBNZCV: - return { - .Read = FLAG_C, - .Write = FLAG_NZCV, - .CanEliminate = true, - }; + case OP_ADC: + case OP_SBB: return {.Read = FLAG_C}; - case OP_NZCVSELECT: { - auto Op = IROp->CW(); - return {.Read = FlagsForCondClassType(Op->Cond)}; - } + case OP_ADCNZCV: + case OP_SBBNZCV: + return { + .Read = FLAG_C, + .Write = FLAG_NZCV, + .CanEliminate = true, + }; - case OP_NEG: { - auto Op = IROp->CW(); - return {.Read = FlagsForCondClassType(Op->Cond)}; - } + case OP_NZCVSELECT: { + auto Op = IROp->CW(); + return {.Read = FlagsForCondClassType(Op->Cond)}; + } - case OP_CONDJUMP: { - auto Op = IROp->CW(); - if (!Op->FromNZCV) - break; + case OP_NEG: { + auto Op = IROp->CW(); + return {.Read = FlagsForCondClassType(Op->Cond)}; + } - return {.Read = FlagsForCondClassType(Op->Cond)}; - } - - case OP_CONDSUBNZCV: - case OP_CONDADDNZCV: { - auto Op = IROp->CW(); - return { - .Read = FlagsForCondClassType(Op->Cond), - .Write = FLAG_NZCV, - .CanEliminate = true, - }; - } - - case OP_RMIFNZCV: { - auto Op = IROp->CW(); - - static_assert(FLAG_N == (1 << 3), "rmif mask lines up with our bits"); - static_assert(FLAG_Z == (1 << 2), "rmif mask lines up with our bits"); - static_assert(FLAG_C == (1 << 1), "rmif mask lines up with our bits"); - static_assert(FLAG_V == (1 << 0), "rmif mask lines up with our bits"); - - return { - .Write = Op->Mask, - .CanEliminate = true, - }; - } - - case OP_INVALIDATEFLAGS: { - auto Op = IROp->CW(); - unsigned Flags = 0; - - // TODO: Make this translation less silly - if (Op->Flags & (1u << X86State::RFLAG_SF_RAW_LOC)) - Flags |= FLAG_N; - - if (Op->Flags & (1u << X86State::RFLAG_ZF_RAW_LOC)) - Flags |= FLAG_Z; - - if (Op->Flags & (1u << X86State::RFLAG_CF_RAW_LOC)) - Flags |= FLAG_C; - - if (Op->Flags & (1u << X86State::RFLAG_OF_RAW_LOC)) - Flags |= FLAG_V; - - if (Op->Flags & (1u << X86State::RFLAG_PF_RAW_LOC)) - Flags |= FLAG_P; - - if (Op->Flags & (1u << X86State::RFLAG_AF_RAW_LOC)) - Flags |= FLAG_A; - - // The mental model of InvalidateFlags is writing undefined values to all - // of the selected flags, allowing the write-after-write optimizations to - // optimize invalidate-after-write for free. - return { - .Write = Flags, - .CanEliminate = true, - }; - } - - case OP_LOADREGISTER: { - auto Op = IROp->CW(); - if (Op->Class != GPRClass || Op->StaticClass != GPRFixedClass) - break; - - return {.Read = FlagForOffset(Op->Offset)}; - } - - case OP_STOREREGISTER: { - auto Op = IROp->CW(); - if (Op->Class != GPRClass || Op->StaticClass != GPRFixedClass) - break; - - LOGMAN_THROW_A_FMT(!Op->IsPrewrite, "PF/AF writes are fixed-form"); - unsigned Flag = FlagForOffset(Op->Offset); - - return { - .Write = Flag, - .CanEliminate = Flag != 0, - }; - } - - default: + case OP_CONDJUMP: { + auto Op = IROp->CW(); + if (!Op->FromNZCV) { break; + } + + return {.Read = FlagsForCondClassType(Op->Cond)}; + } + + case OP_CONDSUBNZCV: + case OP_CONDADDNZCV: { + auto Op = IROp->CW(); + return { + .Read = FlagsForCondClassType(Op->Cond), + .Write = FLAG_NZCV, + .CanEliminate = true, + }; + } + + case OP_RMIFNZCV: { + auto Op = IROp->CW(); + + static_assert(FLAG_N == (1 << 3), "rmif mask lines up with our bits"); + static_assert(FLAG_Z == (1 << 2), "rmif mask lines up with our bits"); + static_assert(FLAG_C == (1 << 1), "rmif mask lines up with our bits"); + static_assert(FLAG_V == (1 << 0), "rmif mask lines up with our bits"); + + return { + .Write = Op->Mask, + .CanEliminate = true, + }; + } + + case OP_INVALIDATEFLAGS: { + auto Op = IROp->CW(); + unsigned Flags = 0; + + // TODO: Make this translation less silly + if (Op->Flags & (1u << X86State::RFLAG_SF_RAW_LOC)) { + Flags |= FLAG_N; + } + + if (Op->Flags & (1u << X86State::RFLAG_ZF_RAW_LOC)) { + Flags |= FLAG_Z; + } + + if (Op->Flags & (1u << X86State::RFLAG_CF_RAW_LOC)) { + Flags |= FLAG_C; + } + + if (Op->Flags & (1u << X86State::RFLAG_OF_RAW_LOC)) { + Flags |= FLAG_V; + } + + if (Op->Flags & (1u << X86State::RFLAG_PF_RAW_LOC)) { + Flags |= FLAG_P; + } + + if (Op->Flags & (1u << X86State::RFLAG_AF_RAW_LOC)) { + Flags |= FLAG_A; + } + + // The mental model of InvalidateFlags is writing undefined values to all + // of the selected flags, allowing the write-after-write optimizations to + // optimize invalidate-after-write for free. + return { + .Write = Flags, + .CanEliminate = true, + }; + } + + case OP_LOADREGISTER: { + auto Op = IROp->CW(); + if (Op->Class != GPRClass || Op->StaticClass != GPRFixedClass) { + break; + } + + return {.Read = FlagForOffset(Op->Offset)}; + } + + case OP_STOREREGISTER: { + auto Op = IROp->CW(); + if (Op->Class != GPRClass || Op->StaticClass != GPRFixedClass) { + break; + } + + LOGMAN_THROW_A_FMT(!Op->IsPrewrite, "PF/AF writes are fixed-form"); + unsigned Flag = FlagForOffset(Op->Offset); + + return { + .Write = Flag, + .CanEliminate = Flag != 0, + }; + } + + default: break; } return {.Trivial = true}; @@ -326,7 +314,7 @@ DeadFlagCalculationEliminination::Classify(IROp_Header *IROp) /** * @brief This pass removes flag calculations that will otherwise be unused INSIDE of that block */ -bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { +bool DeadFlagCalculationEliminination::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::DFE"); bool Changed = false; @@ -392,8 +380,9 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { // If we eliminated the instruction, we eliminate its read too. This // check is required to ensure the pass converges locally in a single // iteration. - if (!Eliminated) + if (!Eliminated) { FlagsRead |= Info.Read; + } } } @@ -412,4 +401,4 @@ fextl::unique_ptr CreateDeadFlagCalculationEliminination() { return fextl::make_unique(); } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 19534ac58..033152f19 100644 --- a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -58,8 +58,8 @@ namespace { struct RegisterNode { struct VolatileHeader { - IR::NodeID BlockID{UINT32_MAX}; - uint32_t SpillSlot{UINT32_MAX}; + IR::NodeID BlockID {UINT32_MAX}; + uint32_t SpillSlot {UINT32_MAX}; uint64_t Padding; }; @@ -73,40 +73,40 @@ namespace { struct RegisterSet { fextl::vector Classes; uint32_t ClassCount; - uint32_t Conflicts[ 8 * 8 * 32 * 32]; + uint32_t Conflicts[8 * 8 * 32 * 32]; }; struct LiveRange { - IR::NodeID Begin{UINT32_MAX}; - IR::NodeID End{UINT32_MAX}; - uint32_t RematCost{0}; - IR::NodeID PreWritten{0}; - PhysicalRegister PrefferedRegister{PhysicalRegister::Invalid()}; - bool Written{false}; - bool Global{false}; + IR::NodeID Begin {UINT32_MAX}; + IR::NodeID End {UINT32_MAX}; + uint32_t RematCost {0}; + IR::NodeID PreWritten {0}; + PhysicalRegister PrefferedRegister {PhysicalRegister::Invalid()}; + bool Written {false}; + bool Global {false}; }; struct SpillStackUnit { IR::NodeID Node; IR::RegisterClassType Class; LiveRange SpillRange; - IR::OrderedNode *SpilledNode; + IR::OrderedNode* SpilledNode; }; struct RegisterGraph : public FEXCore::Allocator::FEXAllocOperators { IR::RegisterAllocationData::UniquePtr AllocData; RegisterSet Set; - fextl::vector Nodes{}; - uint32_t NodeCount{}; + fextl::vector Nodes {}; + uint32_t NodeCount {}; fextl::vector SpillStack; fextl::unordered_map> BlockPredecessors; fextl::unordered_map> VisitedNodePredecessors; }; - void ResetRegisterGraph(RegisterGraph *Graph, uint64_t NodeCount); + void ResetRegisterGraph(RegisterGraph* Graph, uint64_t NodeCount); - RegisterGraph *AllocateRegisterGraph(uint32_t ClassCount) { - RegisterGraph *Graph = new RegisterGraph{}; + RegisterGraph* AllocateRegisterGraph(uint32_t ClassCount) { + RegisterGraph* Graph = new RegisterGraph {}; // Allocate the register set Graph->Set.ClassCount = ClassCount; @@ -118,24 +118,25 @@ namespace { } - void AllocatePhysicalRegisters(RegisterGraph *Graph, FEXCore::IR::RegisterClassType Class, uint32_t Count) { + void AllocatePhysicalRegisters(RegisterGraph* Graph, FEXCore::IR::RegisterClassType Class, uint32_t Count) { Graph->Set.Classes[Class].CountMask = (1 << Count) - 1; Graph->Set.Classes[Class].PhysicalCount = Count; } - void SetConflict(RegisterGraph *Graph, PhysicalRegister RegAndClass, PhysicalRegister ConflictRegAndClass) { + void SetConflict(RegisterGraph* Graph, PhysicalRegister RegAndClass, PhysicalRegister ConflictRegAndClass) { uint32_t Index = (ConflictRegAndClass.Class << 8) | RegAndClass.Raw; Graph->Set.Conflicts[Index] |= 1 << ConflictRegAndClass.Reg; } - uint32_t GetConflicts(RegisterGraph *Graph, PhysicalRegister RegAndClass, FEXCore::IR::RegisterClassType ConflictClass) { + uint32_t GetConflicts(RegisterGraph* Graph, PhysicalRegister RegAndClass, FEXCore::IR::RegisterClassType ConflictClass) { uint32_t Index = (ConflictClass.Val << 8) | RegAndClass.Raw; return Graph->Set.Conflicts[Index]; } - void VirtualAddRegisterConflict(RegisterGraph *Graph, FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, FEXCore::IR::RegisterClassType Class, uint32_t Reg) { + void VirtualAddRegisterConflict(RegisterGraph* Graph, FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, + FEXCore::IR::RegisterClassType Class, uint32_t Reg) { auto RegAndClass = PhysicalRegister(Class, Reg); auto RegAndClassConflict = PhysicalRegister(ClassConflict, RegConflict); @@ -145,11 +146,11 @@ namespace { SetConflict(Graph, RegAndClassConflict, RegAndClass); } - void FreeRegisterGraph(RegisterGraph *Graph) { + void FreeRegisterGraph(RegisterGraph* Graph) { delete Graph; } - void ResetRegisterGraph(RegisterGraph *Graph, uint64_t NodeCount) { + void ResetRegisterGraph(RegisterGraph* Graph, uint64_t NodeCount) { NodeCount = FEXCore::AlignUp(NodeCount, REGISTER_NODES_PER_PAGE); // Clear to free the Bucketlists which have unique_ptrs @@ -162,46 +163,47 @@ namespace { Graph->NodeCount = NodeCount; } - void SetNodeClass(RegisterGraph *Graph, IR::NodeID Node, FEXCore::IR::RegisterClassType Class) { + void SetNodeClass(RegisterGraph* Graph, IR::NodeID Node, FEXCore::IR::RegisterClassType Class) { Graph->AllocData->Map[Node.Value].Class = Class.Val; } - FEXCore::IR::RegisterClassType GetRegClassFromNode(FEXCore::IR::IRListView *IR, FEXCore::IR::IROp_Header *IROp) { + FEXCore::IR::RegisterClassType GetRegClassFromNode(FEXCore::IR::IRListView* IR, FEXCore::IR::IROp_Header* IROp) { using namespace FEXCore; FEXCore::IR::RegisterClassType Class = IR::GetRegClass(IROp->Op); - if (Class != FEXCore::IR::ComplexClass) + if (Class != FEXCore::IR::ComplexClass) { return Class; + } // Complex register class handling switch (IROp->Op) { - case IR::OP_LOADCONTEXT: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IR::OP_LOADREGISTER: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IR::OP_LOADCONTEXTINDEXED: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IR::OP_LOADMEM: - case IR::OP_LOADMEMTSO: { - auto Op = IROp->C(); - return Op->Class; - break; - } - case IR::OP_FILLREGISTER: { - auto Op = IROp->C(); - return Op->Class; - break; - } - default: break; + case IR::OP_LOADCONTEXT: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IR::OP_LOADREGISTER: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IR::OP_LOADCONTEXTINDEXED: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IR::OP_LOADMEM: + case IR::OP_LOADMEMTSO: { + auto Op = IROp->C(); + return Op->Class; + break; + } + case IR::OP_FILLREGISTER: { + auto Op = IROp->C(); + return Op->Class; + break; + } + default: break; } // Unreachable @@ -209,1160 +211,1127 @@ namespace { }; // Walk the IR and set the node classes - void FindNodeClasses(RegisterGraph *Graph, FEXCore::IR::IRListView *IR) { + void FindNodeClasses(RegisterGraph* Graph, FEXCore::IR::IRListView* IR) { for (auto [CodeNode, IROp] : IR->GetAllCode()) { // If the destination hasn't yet been set then set it now if (GetHasDest(IROp->Op)) { const auto ID = IR->GetID(CodeNode); Graph->AllocData->Map[ID.Value] = PhysicalRegister(GetRegClassFromNode(IR, IROp), INVALID_REG); } else { - //Graph->AllocData->Map[IR->GetID(CodeNode)] = PhysicalRegister::Invalid(); + // Graph->AllocData->Map[IR->GetID(CodeNode)] = PhysicalRegister::Invalid(); } } } } // Anonymous namespace - class ConstrainedRAPass final : public RegisterAllocationPass { - public: - ConstrainedRAPass(FEXCore::IR::Pass* _CompactionPass, bool SupportsAVX); - ~ConstrainedRAPass(); - bool Run(IREmitter *IREmit) override; +class ConstrainedRAPass final : public RegisterAllocationPass { +public: + ConstrainedRAPass(FEXCore::IR::Pass* _CompactionPass, bool SupportsAVX); + ~ConstrainedRAPass(); + bool Run(IREmitter* IREmit) override; - void AllocateRegisterSet(uint32_t ClassCount) override; - void AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) override; - void AddRegisterConflict(FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, FEXCore::IR::RegisterClassType Class, uint32_t Reg) override; + void AllocateRegisterSet(uint32_t ClassCount) override; + void AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) override; + void AddRegisterConflict(FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, FEXCore::IR::RegisterClassType Class, + uint32_t Reg) override; - /** - * @brief Returns the register and class encoded together - * Top 32bits is the class, lower 32bits is the register - */ - RegisterAllocationData* GetAllocationData() override; - RegisterAllocationData::UniquePtr PullAllocationData() override; + /** + * @brief Returns the register and class encoded together + * Top 32bits is the class, lower 32bits is the register + */ + RegisterAllocationData* GetAllocationData() override; + RegisterAllocationData::UniquePtr PullAllocationData() override; - private: - IR::NodeID SpillPointId; +private: + IR::NodeID SpillPointId; - fextl::vector> SpanStart; - fextl::vector> SpanEnd; + fextl::vector> SpanStart; + fextl::vector> SpanEnd; - RegisterGraph *Graph; - FEXCore::IR::Pass* CompactionPass; - bool SupportsAVX; + RegisterGraph* Graph; + FEXCore::IR::Pass* CompactionPass; + bool SupportsAVX; - fextl::vector LiveRanges; + fextl::vector LiveRanges; - [[nodiscard]] static constexpr uint32_t InfoMake(uint32_t id, uint32_t Class) { - return id | (Class << 24); - } - [[nodiscard]] static constexpr uint32_t InfoIDClass(uint32_t info) { - return info & 0xffff'ffff; - } - [[nodiscard]] static constexpr IR::NodeID InfoID(uint32_t info) { - return IR::NodeID{info & 0xff'ffff}; - } - [[nodiscard]] static constexpr uint32_t InfoClass(uint32_t info) { - return info & 0xff00'0000; - } - - void SpillOne(FEXCore::IR::IREmitter *IREmit); - - void CalculateLiveRange(FEXCore::IR::IRListView *IR); - void OptimizeStaticRegisters(FEXCore::IR::IRListView *IR); - void CalculateNodeInterference(FEXCore::IR::IRListView *IR); - void AllocateVirtualRegisters(); - void CalculatePredecessors(FEXCore::IR::IRListView *IR); - void RecursiveLiveRangeExpansion(FEXCore::IR::IRListView *IR, - IR::NodeID Node, IR::NodeID DefiningBlockID, - LiveRange *LiveRange, - const fextl::unordered_set &Predecessors, - fextl::unordered_set &VisitedPredecessors); - - FEXCore::IR::AllNodesIterator FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End); - FEXCore::IR::AllNodesIterator FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End); - - std::optional FindNodeToSpill(IREmitter *IREmit, - RegisterNode *RegisterNode, - IR::NodeID CurrentLocation, - LiveRange const *OpLiveRange, - int32_t RematCost = -1); - uint32_t FindSpillSlot(IR::NodeID Node, FEXCore::IR::RegisterClassType RegisterClass); - - bool RunAllocateVirtualRegisters(IREmitter *IREmit); - - uint64_t OriginalRIP; - - fextl::vector StaticMaps; - }; - - ConstrainedRAPass::ConstrainedRAPass(FEXCore::IR::Pass* _CompactionPass, bool _SupportsAVX) - : CompactionPass {_CompactionPass}, SupportsAVX{_SupportsAVX} { + [[nodiscard]] + static constexpr uint32_t InfoMake(uint32_t id, uint32_t Class) { + return id | (Class << 24); + } + [[nodiscard]] + static constexpr uint32_t InfoIDClass(uint32_t info) { + return info & 0xffff'ffff; + } + [[nodiscard]] + static constexpr IR::NodeID InfoID(uint32_t info) { + return IR::NodeID {info & 0xff'ffff}; + } + [[nodiscard]] + static constexpr uint32_t InfoClass(uint32_t info) { + return info & 0xff00'0000; } - ConstrainedRAPass::~ConstrainedRAPass() { - FreeRegisterGraph(Graph); - } + void SpillOne(FEXCore::IR::IREmitter* IREmit); - void ConstrainedRAPass::AllocateRegisterSet(uint32_t ClassCount) { - LOGMAN_THROW_AA_FMT(ClassCount <= INVALID_CLASS, "Up to {} classes supported", INVALID_CLASS); + void CalculateLiveRange(FEXCore::IR::IRListView* IR); + void OptimizeStaticRegisters(FEXCore::IR::IRListView* IR); + void CalculateNodeInterference(FEXCore::IR::IRListView* IR); + void AllocateVirtualRegisters(); + void CalculatePredecessors(FEXCore::IR::IRListView* IR); + void RecursiveLiveRangeExpansion(FEXCore::IR::IRListView* IR, IR::NodeID Node, IR::NodeID DefiningBlockID, LiveRange* LiveRange, + const fextl::unordered_set& Predecessors, fextl::unordered_set& VisitedPredecessors); - Graph = AllocateRegisterGraph(ClassCount); + FEXCore::IR::AllNodesIterator FindFirstUse(FEXCore::IR::IREmitter* IREmit, FEXCore::IR::OrderedNode* Node, + FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End); + FEXCore::IR::AllNodesIterator FindLastUseBefore(FEXCore::IR::IREmitter* IREmit, FEXCore::IR::OrderedNode* Node, + FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End); - // Add identity conflicts - for (uint32_t Class = 0; Class < INVALID_CLASS; Class++) { - for (uint32_t Reg = 0; Reg < INVALID_REG; Reg++) { - AddRegisterConflict(RegisterClassType{Class}, Reg, RegisterClassType{Class}, Reg); - } + std::optional FindNodeToSpill(IREmitter* IREmit, RegisterNode* RegisterNode, IR::NodeID CurrentLocation, + const LiveRange* OpLiveRange, int32_t RematCost = -1); + uint32_t FindSpillSlot(IR::NodeID Node, FEXCore::IR::RegisterClassType RegisterClass); + + bool RunAllocateVirtualRegisters(IREmitter* IREmit); + + uint64_t OriginalRIP; + + fextl::vector StaticMaps; +}; + +ConstrainedRAPass::ConstrainedRAPass(FEXCore::IR::Pass* _CompactionPass, bool _SupportsAVX) + : CompactionPass {_CompactionPass} + , SupportsAVX {_SupportsAVX} {} + +ConstrainedRAPass::~ConstrainedRAPass() { + FreeRegisterGraph(Graph); +} + +void ConstrainedRAPass::AllocateRegisterSet(uint32_t ClassCount) { + LOGMAN_THROW_AA_FMT(ClassCount <= INVALID_CLASS, "Up to {} classes supported", INVALID_CLASS); + + Graph = AllocateRegisterGraph(ClassCount); + + // Add identity conflicts + for (uint32_t Class = 0; Class < INVALID_CLASS; Class++) { + for (uint32_t Reg = 0; Reg < INVALID_REG; Reg++) { + AddRegisterConflict(RegisterClassType {Class}, Reg, RegisterClassType {Class}, Reg); } } +} - void ConstrainedRAPass::AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) { - LOGMAN_THROW_AA_FMT(RegisterCount <= INVALID_REG, "Up to {} regs supported", INVALID_REG); +void ConstrainedRAPass::AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) { + LOGMAN_THROW_AA_FMT(RegisterCount <= INVALID_REG, "Up to {} regs supported", INVALID_REG); - AllocatePhysicalRegisters(Graph, Class, RegisterCount); + AllocatePhysicalRegisters(Graph, Class, RegisterCount); +} + +void ConstrainedRAPass::AddRegisterConflict(FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, + FEXCore::IR::RegisterClassType Class, uint32_t Reg) { + VirtualAddRegisterConflict(Graph, ClassConflict, RegConflict, Class, Reg); +} + +RegisterAllocationData* ConstrainedRAPass::GetAllocationData() { + return Graph->AllocData.get(); +} + +RegisterAllocationData::UniquePtr ConstrainedRAPass::PullAllocationData() { + return std::move(Graph->AllocData); +} + +void ConstrainedRAPass::RecursiveLiveRangeExpansion(IR::IRListView* IR, IR::NodeID Node, IR::NodeID DefiningBlockID, LiveRange* LiveRange, + const fextl::unordered_set& Predecessors, + fextl::unordered_set& VisitedPredecessors) { + for (auto PredecessorId : Predecessors) { + if (DefiningBlockID != PredecessorId && !VisitedPredecessors.contains(PredecessorId)) { + // do the magic + VisitedPredecessors.insert(PredecessorId); + + auto [_, IROp] = *IR->at(PredecessorId); + + auto Op = IROp->C(); + const auto BeginID = Op->Begin.ID(); + const auto LastID = Op->Last.ID(); + + LOGMAN_THROW_AA_FMT(Op->Header.Op == OP_CODEBLOCK, "Block not defined by codeblock?"); + + LiveRange->Begin = std::min(LiveRange->Begin, BeginID); + LiveRange->End = std::max(LiveRange->End, BeginID); + + LiveRange->Begin = std::min(LiveRange->Begin, LastID); + LiveRange->End = std::max(LiveRange->End, LastID); + + RecursiveLiveRangeExpansion(IR, Node, DefiningBlockID, LiveRange, Graph->BlockPredecessors[PredecessorId], VisitedPredecessors); + } } +} - void ConstrainedRAPass::AddRegisterConflict(FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, FEXCore::IR::RegisterClassType Class, uint32_t Reg) { - VirtualAddRegisterConflict(Graph, ClassConflict, RegConflict, Class, Reg); +[[nodiscard]] +static uint32_t CalculateRematCost(IROps Op) { + constexpr uint32_t DEFAULT_REMAT_COST = 1000; + + switch (Op) { + case IR::OP_CONSTANT: return 1; + + case IR::OP_LOADFLAG: + case IR::OP_LOADCONTEXT: + case IR::OP_LOADREGISTER: return 10; + + case IR::OP_LOADMEM: + case IR::OP_LOADMEMTSO: return 100; + + case IR::OP_FILLREGISTER: return DEFAULT_REMAT_COST + 1; + + default: return DEFAULT_REMAT_COST; } +} - RegisterAllocationData* ConstrainedRAPass::GetAllocationData() { - return Graph->AllocData.get(); - } +void ConstrainedRAPass::CalculateLiveRange(FEXCore::IR::IRListView* IR) { + using namespace FEXCore; + size_t Nodes = IR->GetSSACount(); + LiveRanges.clear(); + LiveRanges.resize(Nodes); - RegisterAllocationData::UniquePtr ConstrainedRAPass::PullAllocationData() { - return std::move(Graph->AllocData); - } + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { + const auto BlockNodeID = IR->GetID(BlockNode); + for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { + const auto Node = IR->GetID(CodeNode); + auto& NodeLiveRange = LiveRanges[Node.Value]; - void ConstrainedRAPass::RecursiveLiveRangeExpansion(IR::IRListView *IR, - IR::NodeID Node, IR::NodeID DefiningBlockID, - LiveRange *LiveRange, - const fextl::unordered_set &Predecessors, - fextl::unordered_set &VisitedPredecessors) { - for (auto PredecessorId: Predecessors) { - if (DefiningBlockID != PredecessorId && !VisitedPredecessors.contains(PredecessorId)) { - // do the magic - VisitedPredecessors.insert(PredecessorId); - - auto [_, IROp] = *IR->at(PredecessorId); - - auto Op = IROp->C(); - const auto BeginID = Op->Begin.ID(); - const auto LastID = Op->Last.ID(); - - LOGMAN_THROW_AA_FMT(Op->Header.Op == OP_CODEBLOCK, "Block not defined by codeblock?"); - - LiveRange->Begin = std::min(LiveRange->Begin, BeginID); - LiveRange->End = std::max(LiveRange->End, BeginID); - - LiveRange->Begin = std::min(LiveRange->Begin, LastID); - LiveRange->End = std::max(LiveRange->End, LastID); - - RecursiveLiveRangeExpansion(IR, Node, DefiningBlockID, LiveRange, - Graph->BlockPredecessors[PredecessorId], - VisitedPredecessors); + // If the destination hasn't yet been set then set it now + if (GetHasDest(IROp->Op)) { + LOGMAN_THROW_AA_FMT(NodeLiveRange.Begin.Value == UINT32_MAX, "Node begin already defined?"); + NodeLiveRange.Begin = Node; + // Default to ending right where after it starts + NodeLiveRange.End = IR::NodeID {Node.Value + 1}; } - } - } - [[nodiscard]] static uint32_t CalculateRematCost(IROps Op) { - constexpr uint32_t DEFAULT_REMAT_COST = 1000; + // Calculate remat cost + NodeLiveRange.RematCost = CalculateRematCost(IROp->Op); - switch (Op) { - case IR::OP_CONSTANT: - return 1; + // Set this node's block ID + Graph->Nodes[Node.Value].Head.BlockID = BlockNodeID; - case IR::OP_LOADFLAG: - case IR::OP_LOADCONTEXT: - case IR::OP_LOADREGISTER: - return 10; + // FillRegister's SSA arg is only there for verification, and we don't want it + // to impact the live range. + if (IROp->Op == OP_FILLREGISTER) { + continue; + } - case IR::OP_LOADMEM: - case IR::OP_LOADMEMTSO: - return 100; + const uint8_t NumArgs = IR::GetRAArgs(IROp->Op); + for (uint8_t i = 0; i < NumArgs; ++i) { + const auto& Arg = IROp->Args[i]; - case IR::OP_FILLREGISTER: - return DEFAULT_REMAT_COST + 1; - - default: - return DEFAULT_REMAT_COST; - } - } - - void ConstrainedRAPass::CalculateLiveRange(FEXCore::IR::IRListView *IR) { - using namespace FEXCore; - size_t Nodes = IR->GetSSACount(); - LiveRanges.clear(); - LiveRanges.resize(Nodes); - - for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { - const auto BlockNodeID = IR->GetID(BlockNode); - for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { - const auto Node = IR->GetID(CodeNode); - auto& NodeLiveRange = LiveRanges[Node.Value]; - - // If the destination hasn't yet been set then set it now - if (GetHasDest(IROp->Op)) { - LOGMAN_THROW_AA_FMT(NodeLiveRange.Begin.Value == UINT32_MAX, - "Node begin already defined?"); - NodeLiveRange.Begin = Node; - // Default to ending right where after it starts - NodeLiveRange.End = IR::NodeID{Node.Value + 1}; + if (Arg.IsInvalid()) { + continue; } - - // Calculate remat cost - NodeLiveRange.RematCost = CalculateRematCost(IROp->Op); - - // Set this node's block ID - Graph->Nodes[Node.Value].Head.BlockID = BlockNodeID; - - // FillRegister's SSA arg is only there for verification, and we don't want it - // to impact the live range. - if (IROp->Op == OP_FILLREGISTER) { + if (IR->GetOp(Arg)->Op == OP_INLINECONSTANT) { + continue; + } + if (IR->GetOp(Arg)->Op == OP_INLINEENTRYPOINTOFFSET) { + continue; + } + if (IR->GetOp(Arg)->Op == OP_IRHEADER) { continue; } - const uint8_t NumArgs = IR::GetRAArgs(IROp->Op); - for (uint8_t i = 0; i < NumArgs; ++i) { - const auto& Arg = IROp->Args[i]; + const auto ArgNode = Arg.ID(); + auto& ArgNodeLiveRange = LiveRanges[ArgNode.Value]; + LOGMAN_THROW_AA_FMT(ArgNodeLiveRange.Begin.Value != UINT32_MAX, "%{} used by %{} before defined?", ArgNode, Node); - if (Arg.IsInvalid()) { - continue; - } - if (IR->GetOp(Arg)->Op == OP_INLINECONSTANT) { - continue; - } - if (IR->GetOp(Arg)->Op == OP_INLINEENTRYPOINTOFFSET) { - continue; - } - if (IR->GetOp(Arg)->Op == OP_IRHEADER) { - continue; - } + const auto ArgNodeBlockID = Graph->Nodes[ArgNode.Value].Head.BlockID; + if (ArgNodeBlockID == BlockNodeID) { + // Set the node end to be at least here + ArgNodeLiveRange.End = Node; + } else { + ArgNodeLiveRange.Global = true; - const auto ArgNode = Arg.ID(); - auto& ArgNodeLiveRange = LiveRanges[ArgNode.Value]; - LOGMAN_THROW_AA_FMT(ArgNodeLiveRange.Begin.Value != UINT32_MAX, - "%{} used by %{} before defined?", ArgNode, Node); + // Grow the live range to include this use + ArgNodeLiveRange.Begin = std::min(ArgNodeLiveRange.Begin, Node); + ArgNodeLiveRange.End = std::max(ArgNodeLiveRange.End, Node); - const auto ArgNodeBlockID = Graph->Nodes[ArgNode.Value].Head.BlockID; - if (ArgNodeBlockID == BlockNodeID) { - // Set the node end to be at least here - ArgNodeLiveRange.End = Node; - } else { - ArgNodeLiveRange.Global = true; + // Can't spill this range, it is MB + ArgNodeLiveRange.RematCost = -1; - // Grow the live range to include this use - ArgNodeLiveRange.Begin = std::min(ArgNodeLiveRange.Begin, Node); - ArgNodeLiveRange.End = std::max(ArgNodeLiveRange.End, Node); + // Include any blocks this value passes through in the live range + RecursiveLiveRangeExpansion(IR, ArgNode, ArgNodeBlockID, &ArgNodeLiveRange, Graph->BlockPredecessors[BlockNodeID], + Graph->VisitedNodePredecessors[ArgNode]); + } + } + } + } +} - // Can't spill this range, it is MB - ArgNodeLiveRange.RematCost = -1; +void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView* IR) { - // Include any blocks this value passes through in the live range - RecursiveLiveRangeExpansion(IR, ArgNode, ArgNodeBlockID, &ArgNodeLiveRange, - Graph->BlockPredecessors[BlockNodeID], - Graph->VisitedNodePredecessors[ArgNode]); - } + // Helpers + + // Is an OP_STOREREGISTER eligible to write directly to the SRA reg? + auto IsPreWritable = [this](uint8_t Size, RegisterClassType StaticClass) { + LOGMAN_THROW_A_FMT(StaticClass == GPRFixedClass || StaticClass == FPRFixedClass, "Unexpected static class {}", StaticClass); + if (StaticClass == GPRFixedClass) { + return Size == 8 || Size == 4; + } else if (StaticClass == FPRFixedClass) { + return Size == 16 || (Size == 32 && SupportsAVX); + } + return false; // Unknown + }; + + // Is an OP_LOADREGISTER eligible to read directly from the SRA reg? + auto IsAliasable = [this](uint8_t Size, RegisterClassType StaticClass, uint32_t Offset) { + LOGMAN_THROW_A_FMT(StaticClass == GPRFixedClass || StaticClass == FPRFixedClass, "Unexpected static class {}", StaticClass); + if (StaticClass == GPRFixedClass) { + // We need more meta info to support not-size-of-reg + return (Size == 8 || Size == 4) && ((Offset & 7) == 0); + } else if (StaticClass == FPRFixedClass) { + // We need more meta info to support not-size-of-reg + if (Size == 32 && SupportsAVX && (Offset & 31) == 0) { + return true; + } + return (Size == 16 /*|| Size == 8 || Size == 4*/) && ((Offset & 15) == 0); + } + return false; // Unknown + }; + + const auto GetFPRBeginAndEnd = [this]() -> std::pair { + if (SupportsAVX) { + return { + offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[0][0]), + offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[16][0]), + }; + } else { + return { + offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[0][0]), + offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[16][0]), + }; + } + }; + + // Get SRA Reg and Class from a Context offset + const auto GetRegAndClassFromOffset = [&, this](uint32_t Offset) { + const auto beginGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0]); + const auto endGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[16]); + const auto pf = offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw); + const auto af = offsetof(FEXCore::Core::CpuStateFrame, State.af_raw); + + const auto [beginFpr, endFpr] = GetFPRBeginAndEnd(); + + LOGMAN_THROW_AA_FMT((Offset >= beginGpr && Offset < endGpr) || (Offset >= beginFpr && Offset < endFpr) || (Offset == pf) || (Offset == af), + "Unexpected Offset {}", Offset); + + unsigned FlagOffset = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount - 2; + + if (Offset == pf) { + return PhysicalRegister(GPRFixedClass, FlagOffset); + } else if (Offset == af) { + return PhysicalRegister(GPRFixedClass, FlagOffset + 1); + } else if (Offset >= beginGpr && Offset < endGpr) { + auto reg = (Offset - beginGpr) / Core::CPUState::GPR_REG_SIZE; + return PhysicalRegister(GPRFixedClass, reg); + } else if (Offset >= beginFpr && Offset < endFpr) { + const auto size = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; + const auto reg = (Offset - beginFpr) / size; + return PhysicalRegister(FPRFixedClass, reg); + } + + return PhysicalRegister::Invalid(); + }; + + auto GprSize = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount; + auto MapsSize = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount + Graph->Set.Classes[FPRFixedClass.Val].PhysicalCount; + StaticMaps.resize(MapsSize); + + // Get a StaticMap entry from context offset + const auto GetStaticMapFromOffset = [&](uint32_t Offset) -> LiveRange** { + const auto beginGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0]); + const auto endGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[16]); + const auto pf = offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw); + const auto af = offsetof(FEXCore::Core::CpuStateFrame, State.af_raw); + + const auto [beginFpr, endFpr] = GetFPRBeginAndEnd(); + + LOGMAN_THROW_AA_FMT((Offset >= beginGpr && Offset < endGpr) || (Offset >= beginFpr && Offset < endFpr) || (Offset == pf) || (Offset == af), + "Unexpected Offset {}", Offset); + + unsigned FlagOffset = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount - 2; + + if (Offset == pf) { + return &StaticMaps[FlagOffset]; + } else if (Offset == af) { + return &StaticMaps[FlagOffset + 1]; + } else if (Offset >= beginGpr && Offset < endGpr) { + auto reg = (Offset - beginGpr) / Core::CPUState::GPR_REG_SIZE; + return &StaticMaps[reg]; + } else if (Offset >= beginFpr && Offset < endFpr) { + const auto size = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; + const auto reg = (Offset - beginFpr) / size; + return &StaticMaps[GprSize + reg]; + } + + return nullptr; + }; + + // Get a StaticMap entry from reg and class + const auto GetStaticMapFromReg = [&](IR::PhysicalRegister PhyReg) -> LiveRange** { + LOGMAN_THROW_A_FMT(PhyReg.Class == GPRFixedClass.Val || PhyReg.Class == FPRFixedClass.Val, "Unexpected Class {}", PhyReg.Class); + + if (PhyReg.Class == GPRFixedClass.Val) { + return &StaticMaps[PhyReg.Reg]; + } else if (PhyReg.Class == FPRFixedClass.Val) { + return &StaticMaps[GprSize + PhyReg.Reg]; + } + + return nullptr; + }; + + // First pass: Mark pre-writes + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { + for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { + const auto Node = IR->GetID(CodeNode); + + if (IROp->Op == OP_STOREREGISTER) { + auto Op = IROp->C(); + const auto OpID = Op->Value.ID(); + auto& OpLiveRange = LiveRanges[OpID.Value]; + + if (IsPreWritable(IROp->Size, Op->StaticClass) && OpLiveRange.PrefferedRegister.IsInvalid() && !OpLiveRange.Global) { + + // Pre-write and sra-allocate in the defining node - this might be undone if a read before the actual store happens + SRA_DEBUG("Prewritting ssa{} (Store in ssa{})\n", OpID, Node); + OpLiveRange.PrefferedRegister = GetRegAndClassFromOffset(Op->Offset); + OpLiveRange.PreWritten = Node; + SetNodeClass(Graph, OpID, Op->StaticClass); } } } } - void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView *IR) { + // Second pass: + // - Demote pre-writes if read after pre-write + // - Mark read-aliases + // - Demote read-aliases if SRA reg is written before the alias's last read + for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { + memset(StaticMaps.data(), 0, MapsSize * sizeof(LiveRange*)); + for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { + const auto Node = IR->GetID(CodeNode); + auto& NodeLiveRange = LiveRanges[Node.Value]; - // Helpers + // Check for read-after-write and demote if it happens + const uint8_t NumArgs = IR::GetRAArgs(IROp->Op); + for (uint8_t i = 0; i < NumArgs; ++i) { + const auto& Arg = IROp->Args[i]; - // Is an OP_STOREREGISTER eligible to write directly to the SRA reg? - auto IsPreWritable = [this](uint8_t Size, RegisterClassType StaticClass) { - LOGMAN_THROW_A_FMT(StaticClass == GPRFixedClass || StaticClass == FPRFixedClass, "Unexpected static class {}", StaticClass); - if (StaticClass == GPRFixedClass) { - return Size == 8 || Size == 4; - } else if (StaticClass == FPRFixedClass) { - return Size == 16 || (Size == 32 && SupportsAVX); - } - return false; // Unknown - }; - - // Is an OP_LOADREGISTER eligible to read directly from the SRA reg? - auto IsAliasable = [this](uint8_t Size, RegisterClassType StaticClass, uint32_t Offset) { - LOGMAN_THROW_A_FMT(StaticClass == GPRFixedClass || StaticClass == FPRFixedClass, "Unexpected static class {}", StaticClass); - if (StaticClass == GPRFixedClass) { - // We need more meta info to support not-size-of-reg - return (Size == 8 || Size == 4) && ((Offset & 7) == 0); - } else if (StaticClass == FPRFixedClass) { - // We need more meta info to support not-size-of-reg - if (Size == 32 && SupportsAVX && (Offset & 31) == 0) { - return true; + if (Arg.IsInvalid()) { + continue; } - return (Size == 16 /*|| Size == 8 || Size == 4*/) && ((Offset & 15) == 0); - } - return false; // Unknown - }; - - const auto GetFPRBeginAndEnd = [this]() -> std::pair { - if (SupportsAVX) { - return { - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[0][0]), - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[16][0]), - }; - } else { - return { - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[0][0]), - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[16][0]), - }; - } - }; - - // Get SRA Reg and Class from a Context offset - const auto GetRegAndClassFromOffset = [&, this](uint32_t Offset) { - const auto beginGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0]); - const auto endGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[16]); - const auto pf = offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw); - const auto af = offsetof(FEXCore::Core::CpuStateFrame, State.af_raw); - - const auto [beginFpr, endFpr] = GetFPRBeginAndEnd(); - - LOGMAN_THROW_AA_FMT((Offset >= beginGpr && Offset < endGpr) || (Offset >= beginFpr && Offset < endFpr) || (Offset == pf) || (Offset == af), "Unexpected Offset {}", Offset); - - unsigned FlagOffset = - Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount - 2; - - if (Offset == pf) { - return PhysicalRegister(GPRFixedClass, FlagOffset); - } else if (Offset == af) { - return PhysicalRegister(GPRFixedClass, FlagOffset + 1); - } else if (Offset >= beginGpr && Offset < endGpr) { - auto reg = (Offset - beginGpr) / Core::CPUState::GPR_REG_SIZE; - return PhysicalRegister(GPRFixedClass, reg); - } else if (Offset >= beginFpr && Offset < endFpr) { - const auto size = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE - : Core::CPUState::XMM_SSE_REG_SIZE; - const auto reg = (Offset - beginFpr) / size; - return PhysicalRegister(FPRFixedClass, reg); + if (IR->GetOp(Arg)->Op == OP_INLINECONSTANT) { + continue; + } + if (IR->GetOp(Arg)->Op == OP_INLINEENTRYPOINTOFFSET) { + continue; + } + if (IR->GetOp(Arg)->Op == OP_IRHEADER) { + continue; } - return PhysicalRegister::Invalid(); - }; + const auto ArgNode = Arg.ID(); + auto& ArgNodeLiveRange = LiveRanges[ArgNode.Value]; - auto GprSize = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount; - auto MapsSize = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount + Graph->Set.Classes[FPRFixedClass.Val].PhysicalCount; - StaticMaps.resize(MapsSize); - - // Get a StaticMap entry from context offset - const auto GetStaticMapFromOffset = [&](uint32_t Offset) -> LiveRange** { - const auto beginGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0]); - const auto endGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[16]); - const auto pf = offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw); - const auto af = offsetof(FEXCore::Core::CpuStateFrame, State.af_raw); - - const auto [beginFpr, endFpr] = GetFPRBeginAndEnd(); - - LOGMAN_THROW_AA_FMT((Offset >= beginGpr && Offset < endGpr) || (Offset >= beginFpr && Offset < endFpr) || (Offset == pf) || (Offset == af), "Unexpected Offset {}", Offset); - - unsigned FlagOffset = - Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount - 2; - - if (Offset == pf) { - return &StaticMaps[FlagOffset]; - } else if (Offset == af) { - return &StaticMaps[FlagOffset + 1]; - } else if (Offset >= beginGpr && Offset < endGpr) { - auto reg = (Offset - beginGpr) / Core::CPUState::GPR_REG_SIZE; - return &StaticMaps[reg]; - } else if (Offset >= beginFpr && Offset < endFpr) { - const auto size = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE - : Core::CPUState::XMM_SSE_REG_SIZE; - const auto reg = (Offset - beginFpr) / size; - return &StaticMaps[GprSize + reg]; - } - - return nullptr; - }; - - // Get a StaticMap entry from reg and class - const auto GetStaticMapFromReg = [&](IR::PhysicalRegister PhyReg) -> LiveRange** { - LOGMAN_THROW_A_FMT(PhyReg.Class == GPRFixedClass.Val || PhyReg.Class == FPRFixedClass.Val, "Unexpected Class {}", PhyReg.Class); - - if (PhyReg.Class == GPRFixedClass.Val) { - return &StaticMaps[PhyReg.Reg]; - } else if (PhyReg.Class == FPRFixedClass.Val) { - return &StaticMaps[GprSize + PhyReg.Reg]; - } - - return nullptr; - }; - - // First pass: Mark pre-writes - for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { - for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { - const auto Node = IR->GetID(CodeNode); - - if (IROp->Op == OP_STOREREGISTER) { - auto Op = IROp->C(); - const auto OpID = Op->Value.ID(); - auto& OpLiveRange = LiveRanges[OpID.Value]; - - if (IsPreWritable(IROp->Size, Op->StaticClass) - && OpLiveRange.PrefferedRegister.IsInvalid() - && !OpLiveRange.Global) { - - // Pre-write and sra-allocate in the defining node - this might be undone if a read before the actual store happens - SRA_DEBUG("Prewritting ssa{} (Store in ssa{})\n", OpID, Node); - OpLiveRange.PrefferedRegister = GetRegAndClassFromOffset(Op->Offset); - OpLiveRange.PreWritten = Node; - SetNodeClass(Graph, OpID, Op->StaticClass); - } + // ACCESSED after write, let's not SRA this one + if (ArgNodeLiveRange.Written) { + SRA_DEBUG("Demoting ssa{} because accessed after write in ssa{}\n", ArgNode, Node); + ArgNodeLiveRange.PrefferedRegister = PhysicalRegister::Invalid(); + auto ArgNodeNode = IR->GetNode(Arg); + SetNodeClass(Graph, ArgNode, GetRegClassFromNode(IR, ArgNodeNode->Op(IR->GetData()))); } } - } - // Second pass: - // - Demote pre-writes if read after pre-write - // - Mark read-aliases - // - Demote read-aliases if SRA reg is written before the alias's last read - for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { - memset(StaticMaps.data(), 0, MapsSize * sizeof(LiveRange*)); - for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { - const auto Node = IR->GetID(CodeNode); - auto& NodeLiveRange = LiveRanges[Node.Value]; - - // Check for read-after-write and demote if it happens - const uint8_t NumArgs = IR::GetRAArgs(IROp->Op); - for (uint8_t i = 0; i < NumArgs; ++i) { - const auto& Arg = IROp->Args[i]; - - if (Arg.IsInvalid()) { - continue; - } - if (IR->GetOp(Arg)->Op == OP_INLINECONSTANT) { - continue; - } - if (IR->GetOp(Arg)->Op == OP_INLINEENTRYPOINTOFFSET) { - continue; - } - if (IR->GetOp(Arg)->Op == OP_IRHEADER) { - continue; - } - - const auto ArgNode = Arg.ID(); - auto& ArgNodeLiveRange = LiveRanges[ArgNode.Value]; - - // ACCESSED after write, let's not SRA this one - if (ArgNodeLiveRange.Written) { - SRA_DEBUG("Demoting ssa{} because accessed after write in ssa{}\n", ArgNode, Node); - ArgNodeLiveRange.PrefferedRegister = PhysicalRegister::Invalid(); - auto ArgNodeNode = IR->GetNode(Arg); - SetNodeClass(Graph, ArgNode, GetRegClassFromNode(IR, ArgNodeNode->Op(IR->GetData()))); + // This op defines a span + if (GetHasDest(IROp->Op)) { + // If this is a pre-write, update the StaticMap so we track writes + if (!NodeLiveRange.PrefferedRegister.IsInvalid()) { + SRA_DEBUG("ssa{} is a pre-write\n", Node); + auto StaticMap = GetStaticMapFromReg(NodeLiveRange.PrefferedRegister); + if ((*StaticMap)) { + SRA_DEBUG("Markng ssa{} as written because ssa{} writes to sra{}\n", (*StaticMap) - &LiveRanges[0], Node, -1 /*vreg*/); + (*StaticMap)->Written = true; } + (*StaticMap) = &NodeLiveRange; } - // This op defines a span - if (GetHasDest(IROp->Op)) { - // If this is a pre-write, update the StaticMap so we track writes - if (!NodeLiveRange.PrefferedRegister.IsInvalid()) { - SRA_DEBUG("ssa{} is a pre-write\n", Node); - auto StaticMap = GetStaticMapFromReg(NodeLiveRange.PrefferedRegister); - if ((*StaticMap)) { - SRA_DEBUG("Markng ssa{} as written because ssa{} writes to sra{}\n", - (*StaticMap) - &LiveRanges[0], Node, -1 /*vreg*/); - (*StaticMap)->Written = true; - } - (*StaticMap) = &NodeLiveRange; - } - - // Opcode is an SRA read - // Check if - // - There is not a pre-write before this read. If there is one, demote to no pre-write - // - Try to read-alias if possible - if (IROp->Op == OP_LOADREGISTER) { - auto Op = IROp->C(); - - auto StaticMap = GetStaticMapFromOffset(Op->Offset); - - // Make sure there wasn't a store pre-written before this read - if ((*StaticMap) && (*StaticMap)->PreWritten.IsValid()) { - const auto ID = IR::NodeID((*StaticMap) - &LiveRanges[0]); - - SRA_DEBUG("ssa{} cannot be a pre-write because ssa{} reads from sra{} before storereg", - ID, Node, -1 /*vreg*/); - (*StaticMap)->PrefferedRegister = PhysicalRegister::Invalid(); - (*StaticMap)->PreWritten.Invalidate(); - SetNodeClass(Graph, ID, Op->Class); - } - - // if not sra-allocated and full size, sra-allocate - if (!NodeLiveRange.Global && NodeLiveRange.PrefferedRegister.IsInvalid()) { - // only full size reads can be aliased - if (IsAliasable(IROp->Size, Op->StaticClass, Op->Offset)) { - // We can only track a single active span. - // Marking here as written is overly agressive, but - // there might be write(s) later on the instruction stream - if ((*StaticMap)) { - SRA_DEBUG( - "Marking ssa{} as written because ssa{} re-loads sra{}, " - "and we can't track possible future writes\n", - (*StaticMap) - &LiveRanges[0], Node, -1 /*vreg*/); - (*StaticMap)->Written = true; - } - - NodeLiveRange.PrefferedRegister = GetRegAndClassFromOffset(Op->Offset); //0, 1, and so on - (*StaticMap) = &NodeLiveRange; - SetNodeClass(Graph, Node, Op->StaticClass); - SRA_DEBUG("Marking ssa{} as allocated to sra{}\n", Node, -1 /*vreg*/); - } - } - } - } - - // OP is an OP_STOREREGISTER - // - If there was a matching pre-write, clear the pre-write flag as the register is no longer pre-written - // - Mark the SRA span as written, so that any further reads demote it from read-aliases if they happen - if (IROp->Op == OP_STOREREGISTER) { - const auto Op = IROp->C(); - const auto OpID = Op->Value.ID(); - auto& OpLiveRange = LiveRanges[OpID.Value]; + // Opcode is an SRA read + // Check if + // - There is not a pre-write before this read. If there is one, demote to no pre-write + // - Try to read-alias if possible + if (IROp->Op == OP_LOADREGISTER) { + auto Op = IROp->C(); auto StaticMap = GetStaticMapFromOffset(Op->Offset); - // if a read pending, it has been writting - if ((*StaticMap)) { - // writes to self don't invalidate the span - if ((*StaticMap)->PreWritten != Node) { - SRA_DEBUG("Marking ssa{} as written because ssa{} writes to sra{} with value ssa{}. Write size is {}\n", - ID, Node, -1 /*vreg*/, OpID, IROp->Size); - (*StaticMap)->Written = true; + + // Make sure there wasn't a store pre-written before this read + if ((*StaticMap) && (*StaticMap)->PreWritten.IsValid()) { + const auto ID = IR::NodeID((*StaticMap) - &LiveRanges[0]); + + SRA_DEBUG("ssa{} cannot be a pre-write because ssa{} reads from sra{} before storereg", ID, Node, -1 /*vreg*/); + (*StaticMap)->PrefferedRegister = PhysicalRegister::Invalid(); + (*StaticMap)->PreWritten.Invalidate(); + SetNodeClass(Graph, ID, Op->Class); + } + + // if not sra-allocated and full size, sra-allocate + if (!NodeLiveRange.Global && NodeLiveRange.PrefferedRegister.IsInvalid()) { + // only full size reads can be aliased + if (IsAliasable(IROp->Size, Op->StaticClass, Op->Offset)) { + // We can only track a single active span. + // Marking here as written is overly agressive, but + // there might be write(s) later on the instruction stream + if ((*StaticMap)) { + SRA_DEBUG("Marking ssa{} as written because ssa{} re-loads sra{}, " + "and we can't track possible future writes\n", + (*StaticMap) - &LiveRanges[0], Node, -1 /*vreg*/); + (*StaticMap)->Written = true; + } + + NodeLiveRange.PrefferedRegister = GetRegAndClassFromOffset(Op->Offset); // 0, 1, and so on + (*StaticMap) = &NodeLiveRange; + SetNodeClass(Graph, Node, Op->StaticClass); + SRA_DEBUG("Marking ssa{} as allocated to sra{}\n", Node, -1 /*vreg*/); } } - if (OpLiveRange.PreWritten == Node) { - // no longer pre-written - OpLiveRange.PreWritten.Invalidate(); - SRA_DEBUG("Marking ssa{} as no longer pre-written as ssa{} is a storereg for sra{}\n", - OpID, Node, -1 /*vreg*/); + } + } + + // OP is an OP_STOREREGISTER + // - If there was a matching pre-write, clear the pre-write flag as the register is no longer pre-written + // - Mark the SRA span as written, so that any further reads demote it from read-aliases if they happen + if (IROp->Op == OP_STOREREGISTER) { + const auto Op = IROp->C(); + const auto OpID = Op->Value.ID(); + auto& OpLiveRange = LiveRanges[OpID.Value]; + + auto StaticMap = GetStaticMapFromOffset(Op->Offset); + // if a read pending, it has been writting + if ((*StaticMap)) { + // writes to self don't invalidate the span + if ((*StaticMap)->PreWritten != Node) { + SRA_DEBUG("Marking ssa{} as written because ssa{} writes to sra{} with value ssa{}. Write size is {}\n", ID, Node, -1 /*vreg*/, + OpID, IROp->Size); + (*StaticMap)->Written = true; } } + if (OpLiveRange.PreWritten == Node) { + // no longer pre-written + OpLiveRange.PreWritten.Invalidate(); + SRA_DEBUG("Marking ssa{} as no longer pre-written as ssa{} is a storereg for sra{}\n", OpID, Node, -1 /*vreg*/); + } } } } +} - void ConstrainedRAPass::CalculateNodeInterference(FEXCore::IR::IRListView *IR) { - const auto AddInterference = [this](IR::NodeID Node1, IR::NodeID Node2) { - RegisterNode *Node = &Graph->Nodes[Node1.Value]; - Node->Interferences.Append(Node2); - }; +void ConstrainedRAPass::CalculateNodeInterference(FEXCore::IR::IRListView* IR) { + const auto AddInterference = [this](IR::NodeID Node1, IR::NodeID Node2) { + RegisterNode* Node = &Graph->Nodes[Node1.Value]; + Node->Interferences.Append(Node2); + }; - const uint32_t NodeCount = IR->GetSSACount(); + const uint32_t NodeCount = IR->GetSSACount(); - // Now that we have all the live ranges calculated we need to add them to our interference graph + // Now that we have all the live ranges calculated we need to add them to our interference graph - const auto GetClass = [](PhysicalRegister PhyReg) { - if (PhyReg.Class == IR::GPRPairClass.Val) - return IR::GPRClass.Val; - else - return (uint32_t)PhyReg.Class; - }; - - // SpanStart/SpanEnd assume SSA id will fit in 24bits - LOGMAN_THROW_AA_FMT(NodeCount <= 0xff'ffff, "Block too large for Spans"); - - SpanStart.resize(NodeCount); - SpanEnd.resize(NodeCount); - for (uint32_t i = 0; i < NodeCount; ++i) { - const auto& NodeLiveRange = LiveRanges[i]; - - if (NodeLiveRange.Begin.Value != UINT32_MAX) { - LOGMAN_THROW_A_FMT(NodeLiveRange.Begin < NodeLiveRange.End , "Span must Begin before Ending"); - - const auto Class = GetClass(Graph->AllocData->Map[i]); - SpanStart[NodeLiveRange.Begin.Value].Append(InfoMake(i, Class)); - SpanEnd[NodeLiveRange.End.Value] .Append(InfoMake(i, Class)); - } + const auto GetClass = [](PhysicalRegister PhyReg) { + if (PhyReg.Class == IR::GPRPairClass.Val) { + return IR::GPRClass.Val; + } else { + return (uint32_t)PhyReg.Class; } + }; - BucketList<32, uint32_t> Active; - for (size_t OpNodeId = 0; OpNodeId < IR->GetSSACount(); OpNodeId++) { - // Expire end intervals first - SpanEnd[OpNodeId].Iterate([&](uint32_t EdgeInfo) { - Active.Erase(InfoIDClass(EdgeInfo)); - }); + // SpanStart/SpanEnd assume SSA id will fit in 24bits + LOGMAN_THROW_AA_FMT(NodeCount <= 0xff'ffff, "Block too large for Spans"); - // Add starting invervals - SpanStart[OpNodeId].Iterate([&](uint32_t EdgeInfo) { - // Starts here - Active.Iterate([&](uint32_t ActiveInfo) { - if (InfoClass(ActiveInfo) == InfoClass(EdgeInfo)) { - AddInterference(InfoID(ActiveInfo), InfoID(EdgeInfo)); - AddInterference(InfoID(EdgeInfo), InfoID(ActiveInfo)); - } - }); - Active.Append(EdgeInfo); - }); + SpanStart.resize(NodeCount); + SpanEnd.resize(NodeCount); + for (uint32_t i = 0; i < NodeCount; ++i) { + const auto& NodeLiveRange = LiveRanges[i]; + + if (NodeLiveRange.Begin.Value != UINT32_MAX) { + LOGMAN_THROW_A_FMT(NodeLiveRange.Begin < NodeLiveRange.End, "Span must Begin before Ending"); + + const auto Class = GetClass(Graph->AllocData->Map[i]); + SpanStart[NodeLiveRange.Begin.Value].Append(InfoMake(i, Class)); + SpanEnd[NodeLiveRange.End.Value].Append(InfoMake(i, Class)); } - - LOGMAN_THROW_AA_FMT(Active.Items[0] == 0, "Interference bug"); - SpanStart.clear(); - SpanEnd.clear(); } - void ConstrainedRAPass::AllocateVirtualRegisters() { - for (uint32_t i = 0; i < Graph->NodeCount; ++i) { - RegisterNode *CurrentNode = &Graph->Nodes[i]; - auto &CurrentRegAndClass = Graph->AllocData->Map[i]; - if (CurrentRegAndClass == PhysicalRegister::Invalid()) - continue; + BucketList<32, uint32_t> Active; + for (size_t OpNodeId = 0; OpNodeId < IR->GetSSACount(); OpNodeId++) { + // Expire end intervals first + SpanEnd[OpNodeId].Iterate([&](uint32_t EdgeInfo) { Active.Erase(InfoIDClass(EdgeInfo)); }); - auto LiveRange = &LiveRanges[i]; - - FEXCore::IR::RegisterClassType RegClass = FEXCore::IR::RegisterClassType{CurrentRegAndClass.Class}; - auto RegAndClass = PhysicalRegister::Invalid(); - RegisterClass *RAClass = &Graph->Set.Classes[RegClass]; - - if (!LiveRange->PrefferedRegister.IsInvalid()) { - RegAndClass = LiveRange->PrefferedRegister; - } else { - uint32_t RegisterConflicts = 0; - CurrentNode->Interferences.Iterate([&](const IR::NodeID InterferenceNode) { - RegisterConflicts |= GetConflicts(Graph, Graph->AllocData->Map[InterferenceNode.Value], {RegClass}); - }); - - RegisterConflicts = (~RegisterConflicts) & RAClass->CountMask; - - int Reg = FindFirstSetBit(RegisterConflicts); - if (Reg != 0) { - RegAndClass = PhysicalRegister({RegClass}, Reg-1); + // Add starting invervals + SpanStart[OpNodeId].Iterate([&](uint32_t EdgeInfo) { + // Starts here + Active.Iterate([&](uint32_t ActiveInfo) { + if (InfoClass(ActiveInfo) == InfoClass(EdgeInfo)) { + AddInterference(InfoID(ActiveInfo), InfoID(EdgeInfo)); + AddInterference(InfoID(EdgeInfo), InfoID(ActiveInfo)); } + }); + Active.Append(EdgeInfo); + }); + } + + LOGMAN_THROW_AA_FMT(Active.Items[0] == 0, "Interference bug"); + SpanStart.clear(); + SpanEnd.clear(); +} + +void ConstrainedRAPass::AllocateVirtualRegisters() { + for (uint32_t i = 0; i < Graph->NodeCount; ++i) { + RegisterNode* CurrentNode = &Graph->Nodes[i]; + auto& CurrentRegAndClass = Graph->AllocData->Map[i]; + if (CurrentRegAndClass == PhysicalRegister::Invalid()) { + continue; + } + + auto LiveRange = &LiveRanges[i]; + + FEXCore::IR::RegisterClassType RegClass = FEXCore::IR::RegisterClassType {CurrentRegAndClass.Class}; + auto RegAndClass = PhysicalRegister::Invalid(); + RegisterClass* RAClass = &Graph->Set.Classes[RegClass]; + + if (!LiveRange->PrefferedRegister.IsInvalid()) { + RegAndClass = LiveRange->PrefferedRegister; + } else { + uint32_t RegisterConflicts = 0; + CurrentNode->Interferences.Iterate([&](const IR::NodeID InterferenceNode) { + RegisterConflicts |= GetConflicts(Graph, Graph->AllocData->Map[InterferenceNode.Value], {RegClass}); + }); + + RegisterConflicts = (~RegisterConflicts) & RAClass->CountMask; + + int Reg = FindFirstSetBit(RegisterConflicts); + if (Reg != 0) { + RegAndClass = PhysicalRegister({RegClass}, Reg - 1); } + } - // If we failed to find a virtual register then use INVALID_REG and mark allocation as failed - if (RegAndClass.IsInvalid()) { - RegAndClass = IR::PhysicalRegister(RegClass, INVALID_REG); - HadFullRA = false; - SpillPointId = IR::NodeID{i}; + // If we failed to find a virtual register then use INVALID_REG and mark allocation as failed + if (RegAndClass.IsInvalid()) { + RegAndClass = IR::PhysicalRegister(RegClass, INVALID_REG); + HadFullRA = false; + SpillPointId = IR::NodeID {i}; - CurrentRegAndClass = RegAndClass; - // Must spill and restart + CurrentRegAndClass = RegAndClass; + // Must spill and restart + return; + } + + CurrentRegAndClass = RegAndClass; + } +} + +FEXCore::IR::AllNodesIterator ConstrainedRAPass::FindFirstUse(FEXCore::IR::IREmitter* IREmit, FEXCore::IR::OrderedNode* Node, + FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End) { + using namespace FEXCore::IR; + const auto SearchID = IREmit->ViewIR().GetID(Node); + + while (1) { + auto [RealNode, IROp] = Begin(); + + const uint8_t NumArgs = FEXCore::IR::GetRAArgs(IROp->Op); + for (uint8_t i = 0; i < NumArgs; ++i) { + const auto ArgNode = IROp->Args[i].ID(); + if (ArgNode == SearchID) { + return Begin; + } + } + + // CodeLast is inclusive. So we still need to dump the CodeLast op as well + if (Begin == End) { + break; + } + + ++Begin; + } + + return AllNodesIterator::Invalid(); +} + +FEXCore::IR::AllNodesIterator ConstrainedRAPass::FindLastUseBefore(FEXCore::IR::IREmitter* IREmit, FEXCore::IR::OrderedNode* Node, + FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End) { + auto CurrentIR = IREmit->ViewIR(); + const auto SearchID = CurrentIR.GetID(Node); + + while (1) { + using namespace FEXCore::IR; + auto [RealNode, IROp] = End(); + + if (Node == RealNode) { + // We walked back all the way to the definition of the IR op + return End; + } + + const uint8_t NumArgs = FEXCore::IR::GetRAArgs(IROp->Op); + for (uint8_t i = 0; i < NumArgs; ++i) { + const auto ArgNode = IROp->Args[i].ID(); + if (ArgNode == SearchID) { + return End; + } + } + + // CodeLast is inclusive. So we still need to dump the CodeLast op as well + if (Begin == End) { + break; + } + + --End; + } + + return FEXCore::IR::AllNodesIterator::Invalid(); +} + +std::optional ConstrainedRAPass::FindNodeToSpill(IREmitter* IREmit, RegisterNode* RegisterNode, IR::NodeID CurrentLocation, + const LiveRange* OpLiveRange, int32_t RematCost) { + auto IR = IREmit->ViewIR(); + + IR::NodeID InterferenceIdToSpill {}; + uint32_t InterferenceFarthestNextUse = 0; + + IR::OrderedNodeWrapper NodeOpBegin = IR::OrderedNodeWrapper::WrapOffset(CurrentLocation.Value * sizeof(IR::OrderedNode)); + IR::OrderedNodeWrapper NodeOpEnd = IR::OrderedNodeWrapper::WrapOffset(OpLiveRange->End.Value * sizeof(IR::OrderedNode)); + auto NodeOpBeginIter = IR.at(NodeOpBegin); + auto NodeOpEndIter = IR.at(NodeOpEnd); + + // Couldn't find register to spill + // Be more aggressive + if (InterferenceIdToSpill.IsInvalid()) { + RegisterNode->Interferences.Iterate([&](IR::NodeID InterferenceNode) { + auto* InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; + if (InterferenceLiveRange->RematCost == -1 || (RematCost != -1 && InterferenceLiveRange->RematCost != RematCost)) { return; } - CurrentRegAndClass = RegAndClass; - } + // if ((RegisterNode->Head.RegAndClass>>32) != (InterferenceNode->Head.RegAndClass>>32)) + // return; + + // If this node's live range fully encompasses the live range of the interference node + // then spilling that interference node will not lower RA + // | Our Node | Interference | + // | ========================================== | + // | 0 - Assign | | + // | 1 | Assign | + // | 2 | | + // | 3 | Last Use | + // | 4 | | + // | 5 - Last Use | | + // | Range - (0, 5] | (1, 3] | + if (OpLiveRange->Begin <= InterferenceLiveRange->Begin && OpLiveRange->End >= InterferenceLiveRange->End) { + return; + } + + auto [InterferenceOrderedNode, _] = IR.at(InterferenceNode)(); + auto InterferenceNodeOpBeginIter = IR.at(InterferenceLiveRange->Begin); + auto InterferenceNodeOpEndIter = IR.at(InterferenceLiveRange->End); + + // If the nodes live range is entirely encompassed by the interference node's range + // then spilling that range will /potentially/ lower RA + // Will only lower register pressure if the interference node does NOT have a use inside of + // this live range's use + // | Our Node | Interference | + // | ========================================== | + // | 0 | Assign | + // | 1 - Assign | (No Use) | + // | 2 | (No Use) | + // | 3 - Last Use | (No Use) | + // | 4 | | + // | 5 | Last Use | + // | Range - (1, 3] | (0, 5] | + if (CurrentLocation > InterferenceLiveRange->Begin && OpLiveRange->End < InterferenceLiveRange->End) { + + // This will only save register pressure if the interference node + // does NOT have a use inside of this this node's live range + // Search only inside the source node's live range to see if there is a use + auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, NodeOpEndIter); + if (FirstUseLocation == IR::NodeIterator::Invalid()) { + // Looks like there isn't a usage of this interference node inside our node's live range + // This means it is safe to spill this node and it'll result in in lower RA + // Proper calculation of cost to spill would be to calculate the two distances from + // (Node->Begin - InterferencePrevUse) + (InterferenceNextUse - Node->End) + // This would ensure something will spill earlier if its previous use and next use are farther away + auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); + auto InterferenceNodePrevUse = FindLastUseBefore(IREmit, InterferenceOrderedNode, InterferenceNodeOpBeginIter, NodeOpBeginIter); + LOGMAN_THROW_A_FMT(InterferenceNodeNextUse != IR::NodeIterator::Invalid(), "Couldn't find next usage of op"); + // If there is no use of the interference op prior to our op then it only has initial definition + if (InterferenceNodePrevUse == IR::NodeIterator::Invalid()) { + InterferenceNodePrevUse = InterferenceNodeOpBeginIter; + } + + const auto NextUseDistance = InterferenceNodeNextUse.ID().Value - CurrentLocation.Value; + if (NextUseDistance >= InterferenceFarthestNextUse) { + InterferenceIdToSpill = InterferenceNode; + InterferenceFarthestNextUse = NextUseDistance; + } + } + } + }); } - FEXCore::IR::AllNodesIterator ConstrainedRAPass::FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End) { - using namespace FEXCore::IR; - const auto SearchID = IREmit->ViewIR().GetID(Node); - while(1) { - auto [RealNode, IROp] = Begin(); + if (InterferenceIdToSpill.IsInvalid()) { + RegisterNode->Interferences.Iterate([&](IR::NodeID InterferenceNode) { + auto* InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; + if (InterferenceLiveRange->RematCost == -1 || (RematCost != -1 && InterferenceLiveRange->RematCost != RematCost)) { + return; + } - const uint8_t NumArgs = FEXCore::IR::GetRAArgs(IROp->Op); - for (uint8_t i = 0; i < NumArgs; ++i) { - const auto ArgNode = IROp->Args[i].ID(); - if (ArgNode == SearchID) { - return Begin; + // If this node's live range fully encompasses the live range of the interference node + // then spilling that interference node will not lower RA + // | Our Node | Interference | + // | ========================================== | + // | 0 - Assign | | + // | 1 | Assign | + // | 2 | | + // | 3 | Last Use | + // | 4 | | + // | 5 - Last Use | | + // | Range - (0, 5] | (1, 3] | + if (OpLiveRange->Begin <= InterferenceLiveRange->Begin && OpLiveRange->End >= InterferenceLiveRange->End) { + return; + } + + auto [InterferenceOrderedNode, _] = IR.at(InterferenceNode)(); + auto InterferenceNodeOpEndIter = IR.at(InterferenceLiveRange->End); + + bool Found {}; + + // If the node's live range intersects the interference node + // but the interference node only overlaps the beginning of our live range + // then spilling the register will lower register pressure if there is not + // a use of the interference register at the same node as assignment + // (So we can spill just before current node assignment) + // | Our Node | Interference | + // | ========================================== | + // | 0 | Assign | + // | 1 - Assign | (No Use) | + // | 2 | (No Use) | + // | 3 | Last Use | + // | 4 | | + // | 5 - Last Use | | + // | Range - (1, 5] | (0, 3] | + if (!Found && CurrentLocation > InterferenceLiveRange->Begin && OpLiveRange->End > InterferenceLiveRange->End) { + auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, NodeOpBeginIter); + + if (FirstUseLocation == IR::NodeIterator::Invalid()) { + // This means that the assignment of our register doesn't use this interference node + // So we are safe to spill this interference node before assignment of our current node + const auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); + const auto NextUseDistance = InterferenceNodeNextUse.ID().Value - CurrentLocation.Value; + if (NextUseDistance >= InterferenceFarthestNextUse) { + Found = true; + + InterferenceIdToSpill = InterferenceNode; + InterferenceFarthestNextUse = NextUseDistance; + } } } - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (Begin == End) { - break; + // If the node's live range intersects the interference node + // but the interference node only overlaps the end of our live range + // then spilling the register will lower register pressure if there is + // not a use of the interference register at the same node as the other node's + // last use + // | Our Node | Interference | + // | ========================================== | + // | 0 - Assign | | + // | 1 | | + // | 2 | Assign | + // | 3 - Last Use | (No Use) | + // | 4 | (No Use) | + // | 5 | Last Use | + // | Range - (1, 3] | (2, 5] | + + // XXX: This route has a bug in it so it is purposely disabled for now + if (false && !Found && CurrentLocation <= InterferenceLiveRange->Begin && OpLiveRange->End <= InterferenceLiveRange->End) { + auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpEndIter, NodeOpEndIter); + + if (FirstUseLocation == IR::NodeIterator::Invalid()) { + // This means that the assignment of our the interference register doesn't overlap + // with the final usage of our register, we can spill it and reduce usage + const auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); + const auto NextUseDistance = InterferenceNodeNextUse.ID().Value - CurrentLocation.Value; + if (NextUseDistance >= InterferenceFarthestNextUse) { + Found = true; + + InterferenceIdToSpill = InterferenceNode; + InterferenceFarthestNextUse = NextUseDistance; + } + } } - - ++Begin; - } - - return AllNodesIterator::Invalid(); + }); } - FEXCore::IR::AllNodesIterator ConstrainedRAPass::FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End) { - auto CurrentIR = IREmit->ViewIR(); - const auto SearchID = CurrentIR.GetID(Node); - - while (1) { - using namespace FEXCore::IR; - auto [RealNode, IROp] = End(); - - if (Node == RealNode) { - // We walked back all the way to the definition of the IR op - return End; - } - - const uint8_t NumArgs = FEXCore::IR::GetRAArgs(IROp->Op); - for (uint8_t i = 0; i < NumArgs; ++i) { - const auto ArgNode = IROp->Args[i].ID(); - if (ArgNode == SearchID) { - return End; - } - } - - // CodeLast is inclusive. So we still need to dump the CodeLast op as well - if (Begin == End) { - break; - } - - --End; - } - - return FEXCore::IR::AllNodesIterator::Invalid(); + // If we are looking for a specific node then we can safely return not found + if (RematCost != -1 && InterferenceIdToSpill.IsInvalid()) { + return std::nullopt; } - std::optional ConstrainedRAPass::FindNodeToSpill(IREmitter *IREmit, - RegisterNode *RegisterNode, - IR::NodeID CurrentLocation, - LiveRange const *OpLiveRange, - int32_t RematCost) { - auto IR = IREmit->ViewIR(); + // Heuristics failed to spill ? + if (InterferenceIdToSpill.IsInvalid()) { + // Panic spill: Spill any value not used by the current op + fextl::set CurrentNodes; - IR::NodeID InterferenceIdToSpill{}; - uint32_t InterferenceFarthestNextUse = 0; + // Get all used nodes for current IR op + { + auto CurrentNode = IR.GetNode(NodeOpBegin); + auto IROp = CurrentNode->Op(IR.GetData()); - IR::OrderedNodeWrapper NodeOpBegin = IR::OrderedNodeWrapper::WrapOffset(CurrentLocation.Value * sizeof(IR::OrderedNode)); - IR::OrderedNodeWrapper NodeOpEnd = IR::OrderedNodeWrapper::WrapOffset(OpLiveRange->End.Value * sizeof(IR::OrderedNode)); - auto NodeOpBeginIter = IR.at(NodeOpBegin); - auto NodeOpEndIter = IR.at(NodeOpEnd); + CurrentNodes.insert(NodeOpBegin.ID()); - // Couldn't find register to spill - // Be more aggressive - if (InterferenceIdToSpill.IsInvalid()) { - RegisterNode->Interferences.Iterate([&](IR::NodeID InterferenceNode) { - auto *InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; - if (InterferenceLiveRange->RematCost == -1 || - (RematCost != -1 && InterferenceLiveRange->RematCost != RematCost)) { - return; - } - - //if ((RegisterNode->Head.RegAndClass>>32) != (InterferenceNode->Head.RegAndClass>>32)) - // return; - - // If this node's live range fully encompasses the live range of the interference node - // then spilling that interference node will not lower RA - // | Our Node | Interference | - // | ========================================== | - // | 0 - Assign | | - // | 1 | Assign | - // | 2 | | - // | 3 | Last Use | - // | 4 | | - // | 5 - Last Use | | - // | Range - (0, 5] | (1, 3] | - if (OpLiveRange->Begin <= InterferenceLiveRange->Begin && - OpLiveRange->End >= InterferenceLiveRange->End) { - return; - } - - auto [InterferenceOrderedNode, _] = IR.at(InterferenceNode)(); - auto InterferenceNodeOpBeginIter = IR.at(InterferenceLiveRange->Begin); - auto InterferenceNodeOpEndIter = IR.at(InterferenceLiveRange->End); - - // If the nodes live range is entirely encompassed by the interference node's range - // then spilling that range will /potentially/ lower RA - // Will only lower register pressure if the interference node does NOT have a use inside of - // this live range's use - // | Our Node | Interference | - // | ========================================== | - // | 0 | Assign | - // | 1 - Assign | (No Use) | - // | 2 | (No Use) | - // | 3 - Last Use | (No Use) | - // | 4 | | - // | 5 | Last Use | - // | Range - (1, 3] | (0, 5] | - if (CurrentLocation > InterferenceLiveRange->Begin && - OpLiveRange->End < InterferenceLiveRange->End) { - - // This will only save register pressure if the interference node - // does NOT have a use inside of this this node's live range - // Search only inside the source node's live range to see if there is a use - auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, NodeOpEndIter); - if (FirstUseLocation == IR::NodeIterator::Invalid()) { - // Looks like there isn't a usage of this interference node inside our node's live range - // This means it is safe to spill this node and it'll result in in lower RA - // Proper calculation of cost to spill would be to calculate the two distances from - // (Node->Begin - InterferencePrevUse) + (InterferenceNextUse - Node->End) - // This would ensure something will spill earlier if its previous use and next use are farther away - auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); - auto InterferenceNodePrevUse = FindLastUseBefore(IREmit, InterferenceOrderedNode, InterferenceNodeOpBeginIter, NodeOpBeginIter); - LOGMAN_THROW_A_FMT(InterferenceNodeNextUse != IR::NodeIterator::Invalid(), "Couldn't find next usage of op"); - // If there is no use of the interference op prior to our op then it only has initial definition - if (InterferenceNodePrevUse == IR::NodeIterator::Invalid()) { - InterferenceNodePrevUse = InterferenceNodeOpBeginIter; - } - - const auto NextUseDistance = InterferenceNodeNextUse.ID().Value - CurrentLocation.Value; - if (NextUseDistance >= InterferenceFarthestNextUse) { - InterferenceIdToSpill = InterferenceNode; - InterferenceFarthestNextUse = NextUseDistance; - } - } - } - }); - } - - - if (InterferenceIdToSpill.IsInvalid()) { - RegisterNode->Interferences.Iterate([&](IR::NodeID InterferenceNode) { - auto *InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; - if (InterferenceLiveRange->RematCost == -1 || - (RematCost != -1 && InterferenceLiveRange->RematCost != RematCost)) { - return; - } - - // If this node's live range fully encompasses the live range of the interference node - // then spilling that interference node will not lower RA - // | Our Node | Interference | - // | ========================================== | - // | 0 - Assign | | - // | 1 | Assign | - // | 2 | | - // | 3 | Last Use | - // | 4 | | - // | 5 - Last Use | | - // | Range - (0, 5] | (1, 3] | - if (OpLiveRange->Begin <= InterferenceLiveRange->Begin && - OpLiveRange->End >= InterferenceLiveRange->End) { - return; - } - - auto [InterferenceOrderedNode, _] = IR.at(InterferenceNode)(); - auto InterferenceNodeOpEndIter = IR.at(InterferenceLiveRange->End); - - bool Found{}; - - // If the node's live range intersects the interference node - // but the interference node only overlaps the beginning of our live range - // then spilling the register will lower register pressure if there is not - // a use of the interference register at the same node as assignment - // (So we can spill just before current node assignment) - // | Our Node | Interference | - // | ========================================== | - // | 0 | Assign | - // | 1 - Assign | (No Use) | - // | 2 | (No Use) | - // | 3 | Last Use | - // | 4 | | - // | 5 - Last Use | | - // | Range - (1, 5] | (0, 3] | - if (!Found && - CurrentLocation > InterferenceLiveRange->Begin && - OpLiveRange->End > InterferenceLiveRange->End) { - auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, NodeOpBeginIter); - - if (FirstUseLocation == IR::NodeIterator::Invalid()) { - // This means that the assignment of our register doesn't use this interference node - // So we are safe to spill this interference node before assignment of our current node - const auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); - const auto NextUseDistance = InterferenceNodeNextUse.ID().Value - CurrentLocation.Value; - if (NextUseDistance >= InterferenceFarthestNextUse) { - Found = true; - - InterferenceIdToSpill = InterferenceNode; - InterferenceFarthestNextUse = NextUseDistance; - } - } - } - - // If the node's live range intersects the interference node - // but the interference node only overlaps the end of our live range - // then spilling the register will lower register pressure if there is - // not a use of the interference register at the same node as the other node's - // last use - // | Our Node | Interference | - // | ========================================== | - // | 0 - Assign | | - // | 1 | | - // | 2 | Assign | - // | 3 - Last Use | (No Use) | - // | 4 | (No Use) | - // | 5 | Last Use | - // | Range - (1, 3] | (2, 5] | - - // XXX: This route has a bug in it so it is purposely disabled for now - if (false && !Found && - CurrentLocation <= InterferenceLiveRange->Begin && - OpLiveRange->End <= InterferenceLiveRange->End) { - auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpEndIter, NodeOpEndIter); - - if (FirstUseLocation == IR::NodeIterator::Invalid()) { - // This means that the assignment of our the interference register doesn't overlap - // with the final usage of our register, we can spill it and reduce usage - const auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter); - const auto NextUseDistance = InterferenceNodeNextUse.ID().Value - CurrentLocation.Value; - if (NextUseDistance >= InterferenceFarthestNextUse) { - Found = true; - - InterferenceIdToSpill = InterferenceNode; - InterferenceFarthestNextUse = NextUseDistance; - } - } - } - }); - } - - // If we are looking for a specific node then we can safely return not found - if (RematCost != -1 && InterferenceIdToSpill.IsInvalid()) { - return std::nullopt; - } - - // Heuristics failed to spill ? - if (InterferenceIdToSpill.IsInvalid()) { - // Panic spill: Spill any value not used by the current op - fextl::set CurrentNodes; - - // Get all used nodes for current IR op - { - auto CurrentNode = IR.GetNode(NodeOpBegin); - auto IROp = CurrentNode->Op(IR.GetData()); - - CurrentNodes.insert(NodeOpBegin.ID()); - - for (int i = 0; i < IR::GetRAArgs(IROp->Op); i++) { - CurrentNodes.insert(IROp->Args[i].ID()); - } + for (int i = 0; i < IR::GetRAArgs(IROp->Op); i++) { + CurrentNodes.insert(IROp->Args[i].ID()); } + } - RegisterNode->Interferences.Find([&](IR::NodeID InterferenceNode) { - auto *InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; - if (InterferenceLiveRange->RematCost == -1 || - (RematCost != -1 && InterferenceLiveRange->RematCost != RematCost)) { - return false; - } - - if (!CurrentNodes.contains(InterferenceNode)) { - InterferenceIdToSpill = InterferenceNode; - LogMan::Msg::DFmt("[RIP: 0x{:x}] Panic spilling %{}, Live Range[{}, {})", OriginalRIP, InterferenceIdToSpill, InterferenceLiveRange->Begin, InterferenceLiveRange->End); - return true; - } + RegisterNode->Interferences.Find([&](IR::NodeID InterferenceNode) { + auto* InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; + if (InterferenceLiveRange->RematCost == -1 || (RematCost != -1 && InterferenceLiveRange->RematCost != RematCost)) { return false; - }); - } + } - if (InterferenceIdToSpill.IsInvalid()) { - int j = 0; - LogMan::Msg::DFmt("node %{}, was dumped in to virtual reg {}. Live Range[{}, {})", - CurrentLocation, -1, - OpLiveRange->Begin, OpLiveRange->End); - - RegisterNode->Interferences.Iterate([&](IR::NodeID InterferenceNode) { - auto *InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; - - LogMan::Msg::DFmt("\tInt{}: %{} Remat: {} [{}, {})", j++, InterferenceNode, InterferenceLiveRange->RematCost, InterferenceLiveRange->Begin, InterferenceLiveRange->End); - }); - } - LOGMAN_THROW_A_FMT(InterferenceIdToSpill.IsValid(), "Couldn't find Node to spill"); - - return InterferenceIdToSpill; + if (!CurrentNodes.contains(InterferenceNode)) { + InterferenceIdToSpill = InterferenceNode; + LogMan::Msg::DFmt("[RIP: 0x{:x}] Panic spilling %{}, Live Range[{}, {})", OriginalRIP, InterferenceIdToSpill, + InterferenceLiveRange->Begin, InterferenceLiveRange->End); + return true; + } + return false; + }); } - uint32_t ConstrainedRAPass::FindSpillSlot(IR::NodeID Node, FEXCore::IR::RegisterClassType RegisterClass) { - RegisterNode& CurrentNode = Graph->Nodes[Node.Value]; - const auto& NodeLiveRange = LiveRanges[Node.Value]; + if (InterferenceIdToSpill.IsInvalid()) { + int j = 0; + LogMan::Msg::DFmt("node %{}, was dumped in to virtual reg {}. Live Range[{}, {})", CurrentLocation, -1, OpLiveRange->Begin, OpLiveRange->End); - if (ReuseSpillSlots) { - for (uint32_t i = 0; i < Graph->SpillStack.size(); ++i) { - SpillStackUnit& SpillUnit = Graph->SpillStack[i]; + RegisterNode->Interferences.Iterate([&](IR::NodeID InterferenceNode) { + auto* InterferenceLiveRange = &LiveRanges[InterferenceNode.Value]; - if (NodeLiveRange.Begin <= SpillUnit.SpillRange.End && - SpillUnit.SpillRange.Begin <= NodeLiveRange.End) { - SpillUnit.SpillRange.Begin = std::min(SpillUnit.SpillRange.Begin, NodeLiveRange.Begin); - SpillUnit.SpillRange.End = std::max(SpillUnit.SpillRange.End, NodeLiveRange.End); - CurrentNode.Head.SpillSlot = i; - return i; - } + LogMan::Msg::DFmt("\tInt{}: %{} Remat: {} [{}, {})", j++, InterferenceNode, InterferenceLiveRange->RematCost, + InterferenceLiveRange->Begin, InterferenceLiveRange->End); + }); + } + LOGMAN_THROW_A_FMT(InterferenceIdToSpill.IsValid(), "Couldn't find Node to spill"); + + return InterferenceIdToSpill; +} + +uint32_t ConstrainedRAPass::FindSpillSlot(IR::NodeID Node, FEXCore::IR::RegisterClassType RegisterClass) { + RegisterNode& CurrentNode = Graph->Nodes[Node.Value]; + const auto& NodeLiveRange = LiveRanges[Node.Value]; + + if (ReuseSpillSlots) { + for (uint32_t i = 0; i < Graph->SpillStack.size(); ++i) { + SpillStackUnit& SpillUnit = Graph->SpillStack[i]; + + if (NodeLiveRange.Begin <= SpillUnit.SpillRange.End && SpillUnit.SpillRange.Begin <= NodeLiveRange.End) { + SpillUnit.SpillRange.Begin = std::min(SpillUnit.SpillRange.Begin, NodeLiveRange.Begin); + SpillUnit.SpillRange.End = std::max(SpillUnit.SpillRange.End, NodeLiveRange.End); + CurrentNode.Head.SpillSlot = i; + return i; + } + } + } + + // Couldn't find a spill slot so just make a new one + auto StackItem = Graph->SpillStack.emplace_back(SpillStackUnit {Node, RegisterClass}); + StackItem.SpillRange.Begin = NodeLiveRange.Begin; + StackItem.SpillRange.End = NodeLiveRange.End; + CurrentNode.Head.SpillSlot = SpillSlotCount; + SpillSlotCount++; + return CurrentNode.Head.SpillSlot; +} + +void ConstrainedRAPass::SpillOne(FEXCore::IR::IREmitter* IREmit) { + using namespace FEXCore; + + auto IR = IREmit->ViewIR(); + auto LastCursor = IREmit->GetWriteCursor(); + auto [CodeNode, IROp] = IR.at(SpillPointId)(); + + LOGMAN_THROW_AA_FMT(GetHasDest(IROp->Op), "Can't spill with no dest"); + + const auto Node = IR.GetID(CodeNode); + RegisterNode* CurrentNode = &Graph->Nodes[Node.Value]; + auto& CurrentRegAndClass = Graph->AllocData->Map[Node.Value]; + LiveRange* OpLiveRange = &LiveRanges[Node.Value]; + + // If this node is allocated above the number of physical registers + // we have then we need to search the interference list and spill the one + // that is cheapest + const bool NeedsToSpill = CurrentRegAndClass.Reg == INVALID_REG; + + if (NeedsToSpill) { + bool Spilled = false; + + // First let's just check for constants that we can just rematerialize instead of spilling + if (const auto InterferenceNode = FindNodeToSpill(IREmit, CurrentNode, Node, OpLiveRange, 1)) { + // We want to end the live range of this value here and continue it on first use + auto [ConstantNode, _] = IR.at(*InterferenceNode)(); + auto ConstantIROp = IR.GetOp(ConstantNode); + + // First op post Spill + auto NextIter = IR.at(CodeNode); + auto FirstUseLocation = FindFirstUse(IREmit, ConstantNode, NextIter, NodeIterator::Invalid()); + + LOGMAN_THROW_A_FMT(FirstUseLocation != IR::NodeIterator::Invalid(), "At %{} Spilling Op %{} but Failure to find op use", Node, + *InterferenceNode); + + if (FirstUseLocation != IR::NodeIterator::Invalid()) { + --FirstUseLocation; + auto [FirstUseOrderedNode, _] = FirstUseLocation(); + IREmit->SetWriteCursor(FirstUseOrderedNode); + auto FilledConstant = IREmit->_Constant(ConstantIROp->Constant); + IREmit->ReplaceUsesWithAfter(ConstantNode, FilledConstant, FirstUseLocation); + Spilled = true; } } - // Couldn't find a spill slot so just make a new one - auto StackItem = Graph->SpillStack.emplace_back(SpillStackUnit{Node, RegisterClass}); - StackItem.SpillRange.Begin = NodeLiveRange.Begin; - StackItem.SpillRange.End = NodeLiveRange.End; - CurrentNode.Head.SpillSlot = SpillSlotCount; - SpillSlotCount++; - return CurrentNode.Head.SpillSlot; - } - - void ConstrainedRAPass::SpillOne(FEXCore::IR::IREmitter *IREmit) { - using namespace FEXCore; - - auto IR = IREmit->ViewIR(); - auto LastCursor = IREmit->GetWriteCursor(); - auto [CodeNode, IROp] = IR.at(SpillPointId)(); - - LOGMAN_THROW_AA_FMT(GetHasDest(IROp->Op), "Can't spill with no dest"); - - const auto Node = IR.GetID(CodeNode); - RegisterNode *CurrentNode = &Graph->Nodes[Node.Value]; - auto &CurrentRegAndClass = Graph->AllocData->Map[Node.Value]; - LiveRange *OpLiveRange = &LiveRanges[Node.Value]; - - // If this node is allocated above the number of physical registers - // we have then we need to search the interference list and spill the one - // that is cheapest - const bool NeedsToSpill = CurrentRegAndClass.Reg == INVALID_REG; - - if (NeedsToSpill) { - bool Spilled = false; - - // First let's just check for constants that we can just rematerialize instead of spilling - if (const auto InterferenceNode = FindNodeToSpill(IREmit, CurrentNode, Node, OpLiveRange, 1)) { - // We want to end the live range of this value here and continue it on first use - auto [ConstantNode, _] = IR.at(*InterferenceNode)(); - auto ConstantIROp = IR.GetOp(ConstantNode); - - // First op post Spill - auto NextIter = IR.at(CodeNode); - auto FirstUseLocation = FindFirstUse(IREmit, ConstantNode, NextIter, NodeIterator::Invalid()); - - LOGMAN_THROW_A_FMT(FirstUseLocation != IR::NodeIterator::Invalid(), - "At %{} Spilling Op %{} but Failure to find op use", - Node, *InterferenceNode); - - if (FirstUseLocation != IR::NodeIterator::Invalid()) { - --FirstUseLocation; - auto [FirstUseOrderedNode, _] = FirstUseLocation(); - IREmit->SetWriteCursor(FirstUseOrderedNode); - auto FilledConstant = IREmit->_Constant(ConstantIROp->Constant); - IREmit->ReplaceUsesWithAfter(ConstantNode, FilledConstant, FirstUseLocation); - Spilled = true; - } - } - - // If we didn't remat a constant then we need to do some real spilling - if (!Spilled) { - if (const auto InterferenceNode = FindNodeToSpill(IREmit, CurrentNode, Node, OpLiveRange)) { - const auto InterferenceRegClass = IR::RegisterClassType{Graph->AllocData->Map[InterferenceNode->Value].Class}; - const uint32_t SpillSlot = FindSpillSlot(*InterferenceNode, InterferenceRegClass); + // If we didn't remat a constant then we need to do some real spilling + if (!Spilled) { + if (const auto InterferenceNode = FindNodeToSpill(IREmit, CurrentNode, Node, OpLiveRange)) { + const auto InterferenceRegClass = IR::RegisterClassType {Graph->AllocData->Map[InterferenceNode->Value].Class}; + const uint32_t SpillSlot = FindSpillSlot(*InterferenceNode, InterferenceRegClass); #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - LOGMAN_THROW_A_FMT(SpillSlot != UINT32_MAX, "Interference Node doesn't have a spill slot!"); - LOGMAN_THROW_A_FMT(InterferenceRegClass != UINT32_MAX, "Interference node never assigned a register class?"); + LOGMAN_THROW_A_FMT(SpillSlot != UINT32_MAX, "Interference Node doesn't have a spill slot!"); + LOGMAN_THROW_A_FMT(InterferenceRegClass != UINT32_MAX, "Interference node never assigned a register class?"); #endif - // This is the op that we need to dump - auto [InterferenceOrderedNode, InterferenceIROp] = IR.at(*InterferenceNode)(); + // This is the op that we need to dump + auto [InterferenceOrderedNode, InterferenceIROp] = IR.at(*InterferenceNode)(); - // This will find the last use of this definition - // Walks from CodeBegin -> BlockBegin to find the last Use - // Which this is walking backwards to find the first use - auto LastUseIterator = FindLastUseBefore(IREmit, InterferenceOrderedNode, NodeIterator::Invalid(), IR.at(CodeNode)); - if (LastUseIterator != AllNodesIterator::Invalid()) { - auto [LastUseNode, LastUseIROp] = LastUseIterator(); + // This will find the last use of this definition + // Walks from CodeBegin -> BlockBegin to find the last Use + // Which this is walking backwards to find the first use + auto LastUseIterator = FindLastUseBefore(IREmit, InterferenceOrderedNode, NodeIterator::Invalid(), IR.at(CodeNode)); + if (LastUseIterator != AllNodesIterator::Invalid()) { + auto [LastUseNode, LastUseIROp] = LastUseIterator(); - // Set the write cursor to point of last usage - IREmit->SetWriteCursor(LastUseNode); - } else { - // There is no last use -- use the definition as last use - IREmit->SetWriteCursor(InterferenceOrderedNode); - } + // Set the write cursor to point of last usage + IREmit->SetWriteCursor(LastUseNode); + } else { + // There is no last use -- use the definition as last use + IREmit->SetWriteCursor(InterferenceOrderedNode); + } - // Actually spill the node now - auto SpillOp = IREmit->_SpillRegister(InterferenceOrderedNode, SpillSlot, InterferenceRegClass); - SpillOp.first->Header.Size = InterferenceIROp->Size; - SpillOp.first->Header.ElementSize = InterferenceIROp->ElementSize; + // Actually spill the node now + auto SpillOp = IREmit->_SpillRegister(InterferenceOrderedNode, SpillSlot, InterferenceRegClass); + SpillOp.first->Header.Size = InterferenceIROp->Size; + SpillOp.first->Header.ElementSize = InterferenceIROp->ElementSize; - { - // Search from the point of spilling to find the first use - // Set the write cursor to the first location found and fill at that point - auto FirstIter = IR.at(SpillOp.Node); - // Just past the spill - ++FirstIter; - auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, FirstIter, NodeIterator::Invalid()); + { + // Search from the point of spilling to find the first use + // Set the write cursor to the first location found and fill at that point + auto FirstIter = IR.at(SpillOp.Node); + // Just past the spill + ++FirstIter; + auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, FirstIter, NodeIterator::Invalid()); - LOGMAN_THROW_A_FMT(FirstUseLocation != NodeIterator::Invalid(), - "At %{} Spilling Op %{} but Failure to find op use", - Node, *InterferenceNode); + LOGMAN_THROW_A_FMT(FirstUseLocation != NodeIterator::Invalid(), "At %{} Spilling Op %{} but Failure to find op use", Node, + *InterferenceNode); - if (FirstUseLocation != IR::NodeIterator::Invalid()) { - // We want to fill just before the first use - --FirstUseLocation; - auto [FirstUseOrderedNode, _] = FirstUseLocation(); + if (FirstUseLocation != IR::NodeIterator::Invalid()) { + // We want to fill just before the first use + --FirstUseLocation; + auto [FirstUseOrderedNode, _] = FirstUseLocation(); - IREmit->SetWriteCursor(FirstUseOrderedNode); + IREmit->SetWriteCursor(FirstUseOrderedNode); - auto FilledInterference = IREmit->_FillRegister(InterferenceOrderedNode, SpillSlot, InterferenceRegClass); - FilledInterference.first->Header.Size = InterferenceIROp->Size; - FilledInterference.first->Header.ElementSize = InterferenceIROp->ElementSize; - IREmit->ReplaceUsesWithAfter(InterferenceOrderedNode, - FilledInterference, - FilledInterference); - } + auto FilledInterference = IREmit->_FillRegister(InterferenceOrderedNode, SpillSlot, InterferenceRegClass); + FilledInterference.first->Header.Size = InterferenceIROp->Size; + FilledInterference.first->Header.ElementSize = InterferenceIROp->ElementSize; + IREmit->ReplaceUsesWithAfter(InterferenceOrderedNode, FilledInterference, FilledInterference); } } - IREmit->SetWriteCursor(LastCursor); } + IREmit->SetWriteCursor(LastCursor); } } - - bool ConstrainedRAPass::RunAllocateVirtualRegisters(FEXCore::IR::IREmitter *IREmit) { - using namespace FEXCore; - bool Changed = false; - - auto IR = IREmit->ViewIR(); - - uint32_t SSACount = IR.GetSSACount(); - - ResetRegisterGraph(Graph, SSACount); - FindNodeClasses(Graph, &IR); - CalculateLiveRange(&IR); - OptimizeStaticRegisters(&IR); - CalculateNodeInterference(&IR); - AllocateVirtualRegisters(); - - return Changed; - } - - - void ConstrainedRAPass::CalculatePredecessors(FEXCore::IR::IRListView *IR) { - Graph->BlockPredecessors.clear(); - - for (auto [BlockNode, BlockIROp] : IR->GetBlocks()) { - auto CodeBlock = BlockIROp->C(); - - auto IROp = IR->GetNode(IR->GetNode(CodeBlock->Last)->Header.Previous)->Op(IR->GetData()); - if (IROp->Op == OP_JUMP) { - auto Op = IROp->C(); - Graph->BlockPredecessors[Op->TargetBlock.ID()].insert(IR->GetID(BlockNode)); - } else if (IROp->Op == OP_CONDJUMP) { - auto Op = IROp->C(); - Graph->BlockPredecessors[Op->TrueBlock.ID()].insert(IR->GetID(BlockNode)); - Graph->BlockPredecessors[Op->FalseBlock.ID()].insert(IR->GetID(BlockNode)); - } - } - } - - bool ConstrainedRAPass::Run(IREmitter *IREmit) { - FEXCORE_PROFILE_SCOPED("PassManager::RA"); - bool Changed = false; - - auto IR = IREmit->ViewIR(); - - auto HeaderOp = IR.GetHeader(); - OriginalRIP = HeaderOp->OriginalRIP; - SpillSlotCount = 0; - Graph->SpillStack.clear(); - - CalculatePredecessors(&IR); - - while (1) { - HadFullRA = true; - - // Virtual allocation pass runs the compaction pass per run - Changed |= RunAllocateVirtualRegisters(IREmit); - - if (HadFullRA) { - break; - } - - SpillOne(IREmit); - Changed = true; - // We need to rerun compaction after spilling - CompactionPass->Run(IREmit); - } - - Graph->AllocData->SpillSlotCount = Graph->SpillStack.size(); - - return Changed; - } - - fextl::unique_ptr CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool SupportsAVX) { - return fextl::make_unique(CompactionPass, SupportsAVX); - } } + +bool ConstrainedRAPass::RunAllocateVirtualRegisters(FEXCore::IR::IREmitter* IREmit) { + using namespace FEXCore; + bool Changed = false; + + auto IR = IREmit->ViewIR(); + + uint32_t SSACount = IR.GetSSACount(); + + ResetRegisterGraph(Graph, SSACount); + FindNodeClasses(Graph, &IR); + CalculateLiveRange(&IR); + OptimizeStaticRegisters(&IR); + CalculateNodeInterference(&IR); + AllocateVirtualRegisters(); + + return Changed; +} + + +void ConstrainedRAPass::CalculatePredecessors(FEXCore::IR::IRListView* IR) { + Graph->BlockPredecessors.clear(); + + for (auto [BlockNode, BlockIROp] : IR->GetBlocks()) { + auto CodeBlock = BlockIROp->C(); + + auto IROp = IR->GetNode(IR->GetNode(CodeBlock->Last)->Header.Previous)->Op(IR->GetData()); + if (IROp->Op == OP_JUMP) { + auto Op = IROp->C(); + Graph->BlockPredecessors[Op->TargetBlock.ID()].insert(IR->GetID(BlockNode)); + } else if (IROp->Op == OP_CONDJUMP) { + auto Op = IROp->C(); + Graph->BlockPredecessors[Op->TrueBlock.ID()].insert(IR->GetID(BlockNode)); + Graph->BlockPredecessors[Op->FalseBlock.ID()].insert(IR->GetID(BlockNode)); + } + } +} + +bool ConstrainedRAPass::Run(IREmitter* IREmit) { + FEXCORE_PROFILE_SCOPED("PassManager::RA"); + bool Changed = false; + + auto IR = IREmit->ViewIR(); + + auto HeaderOp = IR.GetHeader(); + OriginalRIP = HeaderOp->OriginalRIP; + SpillSlotCount = 0; + Graph->SpillStack.clear(); + + CalculatePredecessors(&IR); + + while (1) { + HadFullRA = true; + + // Virtual allocation pass runs the compaction pass per run + Changed |= RunAllocateVirtualRegisters(IREmit); + + if (HadFullRA) { + break; + } + + SpillOne(IREmit); + Changed = true; + // We need to rerun compaction after spilling + CompactionPass->Run(IREmit); + } + + Graph->AllocData->SpillSlotCount = Graph->SpillStack.size(); + + return Changed; +} + +fextl::unique_ptr CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool SupportsAVX) { + return fextl::make_unique(CompactionPass, SupportsAVX); +} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h index 69a68103e..85730e221 100644 --- a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h +++ b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h @@ -17,48 +17,51 @@ struct RegisterAllocationDataDeleter; struct RegisterClassType; class RegisterAllocationPass : public FEXCore::IR::Pass { - public: - bool HasFullRA() const { return HadFullRA; } +public: + bool HasFullRA() const { + return HadFullRA; + } - virtual void AllocateRegisterSet(uint32_t ClassCount) = 0; - virtual void AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) = 0; + virtual void AllocateRegisterSet(uint32_t ClassCount) = 0; + virtual void AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) = 0; - /** - * @brief Adds a conflict between the two registers (and their respective classes) so if one is allocated then the other can not be allocated in - * the same live range. - * - * Conflict is added both directions, so only necessary to add a conflict one way - * - * ex: - * AddRegisters(GPRClass, 2); -> {x0, x1} added to register class GPR - * AddRegisters(PairClass, 1); -> {{x0, x1}} pair added to class GPR - * AddRegisterConflict(GPRClass, 0, PairClass, 0); -> Make sure the pair interferes with x0 - * AddRegisterConflict(GPRClass, 1, PairClass, 1); -> Make sure the pair interferes with x1 - */ - virtual void AddRegisterConflict(FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, FEXCore::IR::RegisterClassType Class, uint32_t Reg) = 0; + /** + * @brief Adds a conflict between the two registers (and their respective classes) so if one is allocated then the other can not be + * allocated in the same live range. + * + * Conflict is added both directions, so only necessary to add a conflict one way + * + * ex: + * AddRegisters(GPRClass, 2); -> {x0, x1} added to register class GPR + * AddRegisters(PairClass, 1); -> {{x0, x1}} pair added to class GPR + * AddRegisterConflict(GPRClass, 0, PairClass, 0); -> Make sure the pair interferes with x0 + * AddRegisterConflict(GPRClass, 1, PairClass, 1); -> Make sure the pair interferes with x1 + */ + virtual void AddRegisterConflict(FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, FEXCore::IR::RegisterClassType Class, + uint32_t Reg) = 0; - /** - * @name Inference graph handling - * @{ */ + /** + * @name Inference graph handling + * @{ */ - /** - * @brief Returns the register and class map array - */ - virtual RegisterAllocationData *GetAllocationData() = 0; + /** + * @brief Returns the register and class map array + */ + virtual RegisterAllocationData* GetAllocationData() = 0; - /** - * @brief Returns and transfers ownership of the register and class map array - */ - virtual std::unique_ptr PullAllocationData() = 0; - /** @} */ + /** + * @brief Returns and transfers ownership of the register and class map array + */ + virtual std::unique_ptr PullAllocationData() = 0; + /** @} */ - protected: - bool HasSpills {}; - // Debug option to disable split slot reuse - // Can be useful for testing if there is a bug with spill slots - constexpr static bool ReuseSpillSlots {true}; - uint32_t SpillSlotCount {}; - bool HadFullRA {}; +protected: + bool HasSpills {}; + // Debug option to disable split slot reuse + // Can be useful for testing if there is a bug with spill slots + constexpr static bool ReuseSpillSlots {true}; + uint32_t SpillSlotCount {}; + bool HadFullRA {}; }; -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp b/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp index fcc261609..dd8939ff4 100644 --- a/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp +++ b/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp @@ -26,10 +26,10 @@ $end_info$ namespace FEXCore::IR::Validation { class ValueDominanceValidation final : public FEXCore::IR::Pass { public: - bool Run(IREmitter *IREmit) override; + bool Run(IREmitter* IREmit) override; }; -bool ValueDominanceValidation::Run(IREmitter *IREmit) { +bool ValueDominanceValidation::Run(IREmitter* IREmit) { FEXCORE_PROFILE_SCOPED("PassManager::ValueDominanceValidation"); bool HadError = false; @@ -45,20 +45,23 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { const uint8_t NumArgs = IR::GetRAArgs(IROp->Op); for (uint32_t i = 0; i < NumArgs; ++i) { - if (IROp->Args[i].IsInvalid()) continue; + if (IROp->Args[i].IsInvalid()) { + continue; + } // We do not validate the location of inline constants because it's // irrelevant, they're ignored by RA and always inlined to where they // need to be. This lets us pool inline constants globally. IROps Op = CurrentIR.GetOp(IROp->Args[i])->Op; - if (Op == OP_IRHEADER || Op == OP_INLINECONSTANT) continue; + if (Op == OP_IRHEADER || Op == OP_INLINECONSTANT) { + continue; + } OrderedNodeWrapper Arg = IROp->Args[i]; // If the SSA argument is not defined INSIDE the block, we have // cross-block liveness, which we forbid in the IR to simplify RA. - if (!(Arg.ID() >= BlockIROp->Begin.ID() && - Arg.ID() < BlockIROp->Last.ID())) { + if (!(Arg.ID() >= BlockIROp->Begin.ID() && Arg.ID() < BlockIROp->Last.ID())) { HadError |= true; Errors << "Inst %" << CodeID << ": Arg[" << i << "] %" << Arg.ID() << " definition not local!" << std::endl; continue; @@ -100,4 +103,4 @@ fextl::unique_ptr CreateValueDominanceValidation() { return fextl::make_unique(); } -} +} // namespace FEXCore::IR::Validation diff --git a/FEXCore/Source/Interface/IR/RegisterAllocationData.h b/FEXCore/Source/Interface/IR/RegisterAllocationData.h index 4c8d9f325..d5bf5c6ca 100644 --- a/FEXCore/Source/Interface/IR/RegisterAllocationData.h +++ b/FEXCore/Source/Interface/IR/RegisterAllocationData.h @@ -11,16 +11,18 @@ union PhysicalRegister { uint8_t Raw; struct { // 32 maximum physical registers - uint8_t Reg: 5; + uint8_t Reg : 5; // 8 Maximum classes - uint8_t Class: 3; + uint8_t Class : 3; }; - bool operator==(const PhysicalRegister &Other) const { + bool operator==(const PhysicalRegister& Other) const { return Raw == Other.Raw; } - PhysicalRegister(RegisterClassType Class, uint8_t Reg) : Reg(Reg), Class(Class.Val) { } + PhysicalRegister(RegisterClassType Class, uint8_t Reg) + : Reg(Reg) + , Class(Class.Val) {} static const PhysicalRegister Invalid() { return PhysicalRegister(InvalidClass, InvalidReg); @@ -38,36 +40,38 @@ struct RegisterAllocationDataDeleter; // This class is serialized, can't have any holes in the structure // otherwise ASAN complains about reading uninitialized memory class FEX_PACKED RegisterAllocationData { - public: - uint32_t SpillSlotCount {}; - uint32_t MapCount {}; - bool IsShared {false}; - PhysicalRegister Map[0]; +public: + uint32_t SpillSlotCount {}; + uint32_t MapCount {}; + bool IsShared {false}; + PhysicalRegister Map[0]; - PhysicalRegister GetNodeRegister(NodeID Node) const { - return Map[Node.Value]; - } - uint32_t SpillSlots() const { return SpillSlotCount; } + PhysicalRegister GetNodeRegister(NodeID Node) const { + return Map[Node.Value]; + } + uint32_t SpillSlots() const { + return SpillSlotCount; + } - static size_t Size(uint32_t NodeCount) { - return sizeof(RegisterAllocationData) + NodeCount * sizeof(Map[0]); - } + static size_t Size(uint32_t NodeCount) { + return sizeof(RegisterAllocationData) + NodeCount * sizeof(Map[0]); + } - using UniquePtr = std::unique_ptr; + using UniquePtr = std::unique_ptr; - static UniquePtr Create(uint32_t NodeCount); + static UniquePtr Create(uint32_t NodeCount); - UniquePtr CreateCopy() const; + UniquePtr CreateCopy() const; - void Serialize(FEXCore::Context::AOTIRWriter& stream) const { - stream.Write((const char*)&SpillSlotCount, sizeof(SpillSlotCount)); - stream.Write((const char*)&MapCount, sizeof(MapCount)); - // RAData (inline) - // In file, IsShared is always set - bool _IsShared = true; - stream.Write((const char*)&_IsShared, sizeof(IsShared)); - stream.Write((const char*)&Map[0], sizeof(Map[0]) * MapCount); - } + void Serialize(FEXCore::Context::AOTIRWriter& stream) const { + stream.Write((const char*)&SpillSlotCount, sizeof(SpillSlotCount)); + stream.Write((const char*)&MapCount, sizeof(MapCount)); + // RAData (inline) + // In file, IsShared is always set + bool _IsShared = true; + stream.Write((const char*)&_IsShared, sizeof(IsShared)); + stream.Write((const char*)&Map[0], sizeof(Map[0]) * MapCount); + } }; struct RegisterAllocationDataDeleter { @@ -84,7 +88,7 @@ inline auto RegisterAllocationData::Create(uint32_t NodeCount) -> UniquePtr { Ret->SpillSlotCount = 0; Ret->MapCount = NodeCount; Ret->IsShared = false; - return UniquePtr { Ret }; + return UniquePtr {Ret}; } inline auto RegisterAllocationData::CreateCopy() const -> UniquePtr { @@ -93,7 +97,7 @@ inline auto RegisterAllocationData::CreateCopy() const -> UniquePtr { copy->SpillSlotCount = SpillSlotCount; copy->MapCount = MapCount; copy->IsShared = IsShared; - return UniquePtr { copy }; + return UniquePtr {copy}; } -} +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Utils/Allocator.cpp b/FEXCore/Source/Utils/Allocator.cpp index 16464be8d..f518ed362 100644 --- a/FEXCore/Source/Utils/Allocator.cpp +++ b/FEXCore/Source/Utils/Allocator.cpp @@ -27,328 +27,322 @@ #include extern "C" { - typedef void* (*mmap_hook_type)( - void *addr, size_t length, int prot, int flags, - int fd, off_t offset); - typedef int (*munmap_hook_type)(void *addr, size_t length); +typedef void* (*mmap_hook_type)(void* addr, size_t length, int prot, int flags, int fd, off_t offset); +typedef int (*munmap_hook_type)(void* addr, size_t length); #ifdef ENABLE_JEMALLOC - extern mmap_hook_type je___mmap_hook; - extern munmap_hook_type je___munmap_hook; +extern mmap_hook_type je___mmap_hook; +extern munmap_hook_type je___munmap_hook; #endif } namespace fextl::pmr { - static fextl::pmr::default_resource FEXDefaultResource; - std::pmr::memory_resource* get_default_resource() { - return &FEXDefaultResource; - } +static fextl::pmr::default_resource FEXDefaultResource; +std::pmr::memory_resource* get_default_resource() { + return &FEXDefaultResource; } +} // namespace fextl::pmr #ifndef _WIN32 namespace FEXCore::Allocator { - MMAP_Hook mmap {::mmap}; - MUNMAP_Hook munmap {::munmap}; +MMAP_Hook mmap {::mmap}; +MUNMAP_Hook munmap {::munmap}; - uint64_t HostVASize{}; +uint64_t HostVASize {}; - using GLIBC_MALLOC_Hook = void*(*)(size_t, const void *caller); - using GLIBC_REALLOC_Hook = void*(*)(void*, size_t, const void *caller); - using GLIBC_FREE_Hook = void(*)(void*, const void *caller); +using GLIBC_MALLOC_Hook = void* (*)(size_t, const void* caller); +using GLIBC_REALLOC_Hook = void* (*)(void*, size_t, const void* caller); +using GLIBC_FREE_Hook = void (*)(void*, const void* caller); - fextl::unique_ptr Alloc64{}; +fextl::unique_ptr Alloc64 {}; - void *FEX_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - void *Result = Alloc64->Mmap(addr, length, prot, flags, fd, offset); - if (Result >= (void*)-4096) { - errno = -(uint64_t)Result; - return (void*)-1; - } - return Result; +void* FEX_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + void* Result = Alloc64->Mmap(addr, length, prot, flags, fd, offset); + if (Result >= (void*)-4096) { + errno = -(uint64_t)Result; + return (void*)-1; } - int FEX_munmap(void *addr, size_t length) { - int Result = Alloc64->Munmap(addr, length); + return Result; +} +int FEX_munmap(void* addr, size_t length) { + int Result = Alloc64->Munmap(addr, length); - if (Result != 0) { - errno = -Result; - return -1; - } - return Result; + if (Result != 0) { + errno = -Result; + return -1; + } + return Result; +} + +// This function disables glibc's ability to allocate memory through the `sbrk` interface. +// This is run early in the lifecycle of FEX in order to make sure no 64-bit pointers can make it to the guest 32-bit application. +// +// How this works is that this allocates a single page at the current sbrk pointer (aligned upward to page size). This makes it +// so that when the sbrk syscall is used to allocate more memory, it fails with an ENOMEM since it runs in to the allocated guard page. +// +// glibc notices the sbrk failure and falls back to regular mmap based allocations when this occurs. Ensuring that memory can still be allocated. +void* DisableSBRKAllocations() { + void* INVALID_PTR = reinterpret_cast(~0ULL); + // Get the starting sbrk pointer. + void* StartingSBRK = sbrk(0); + if (StartingSBRK == INVALID_PTR) { + // If sbrk is already returning invalid pointers then nothing to do here. + return INVALID_PTR; } - // This function disables glibc's ability to allocate memory through the `sbrk` interface. - // This is run early in the lifecycle of FEX in order to make sure no 64-bit pointers can make it to the guest 32-bit application. - // - // How this works is that this allocates a single page at the current sbrk pointer (aligned upward to page size). This makes it - // so that when the sbrk syscall is used to allocate more memory, it fails with an ENOMEM since it runs in to the allocated guard page. - // - // glibc notices the sbrk failure and falls back to regular mmap based allocations when this occurs. Ensuring that memory can still be allocated. - void *DisableSBRKAllocations() { - void* INVALID_PTR = reinterpret_cast(~0ULL); - // Get the starting sbrk pointer. - void *StartingSBRK = sbrk(0); - if (StartingSBRK == INVALID_PTR) { - // If sbrk is already returning invalid pointers then nothing to do here. - return INVALID_PTR; - } - - // Now allocate the next page after the sbrk address to ensure it can't grow. - // In most cases at the start of `main` this will already be page aligned, which means subsequent `sbrk` - // calls won't allocate any memory through that. - void* AlignedBRK = reinterpret_cast(FEXCore::AlignUp(reinterpret_cast(StartingSBRK), FEXCore::Utils::FEX_PAGE_SIZE)); - void *AfterBRK = mmap(AlignedBRK, FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_NORESERVE, -1, 0); - if (AfterBRK == INVALID_PTR) { - // Couldn't allocate the page after the aligned brk? This should never happen. - // FEXCore::LogMan isn't configured yet so we just need to print the message. - fextl::fmt::print("Couldn't allocate page after SBRK.\n"); - FEX_TRAP_EXECUTION; - return INVALID_PTR; - } - - // Now that the page after sbrk is allocated, FEX needs to consume the remaining sbrk space. - // This will be anywhere from [0, 4096) bytes. - // Start allocating from 1024 byte increments just to make any steps a bit faster. - intptr_t IncrementAmount = 1024; - for (; IncrementAmount != 0; IncrementAmount >>= 1) { - while (sbrk(IncrementAmount) != INVALID_PTR); - } - return AlignedBRK; + // Now allocate the next page after the sbrk address to ensure it can't grow. + // In most cases at the start of `main` this will already be page aligned, which means subsequent `sbrk` + // calls won't allocate any memory through that. + void* AlignedBRK = reinterpret_cast(FEXCore::AlignUp(reinterpret_cast(StartingSBRK), FEXCore::Utils::FEX_PAGE_SIZE)); + void* AfterBRK = + mmap(AlignedBRK, FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_NORESERVE, -1, 0); + if (AfterBRK == INVALID_PTR) { + // Couldn't allocate the page after the aligned brk? This should never happen. + // FEXCore::LogMan isn't configured yet so we just need to print the message. + fextl::fmt::print("Couldn't allocate page after SBRK.\n"); + FEX_TRAP_EXECUTION; + return INVALID_PTR; } - void ReenableSBRKAllocations(void* Ptr) { - const void* INVALID_PTR = reinterpret_cast(~0ULL); - if (Ptr != INVALID_PTR) { - munmap(Ptr, FEXCore::Utils::FEX_PAGE_SIZE); - } + // Now that the page after sbrk is allocated, FEX needs to consume the remaining sbrk space. + // This will be anywhere from [0, 4096) bytes. + // Start allocating from 1024 byte increments just to make any steps a bit faster. + intptr_t IncrementAmount = 1024; + for (; IncrementAmount != 0; IncrementAmount >>= 1) { + while (sbrk(IncrementAmount) != INVALID_PTR) + ; } + return AlignedBRK; +} + +void ReenableSBRKAllocations(void* Ptr) { + const void* INVALID_PTR = reinterpret_cast(~0ULL); + if (Ptr != INVALID_PTR) { + munmap(Ptr, FEXCore::Utils::FEX_PAGE_SIZE); + } +} #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - void SetupHooks() { - Alloc64 = Alloc::OSAllocator::Create64BitAllocator(); +void SetupHooks() { + Alloc64 = Alloc::OSAllocator::Create64BitAllocator(); #ifdef ENABLE_JEMALLOC - je___mmap_hook = FEX_mmap; - je___munmap_hook = FEX_munmap; + je___mmap_hook = FEX_mmap; + je___munmap_hook = FEX_munmap; #endif - FEXCore::Allocator::mmap = FEX_mmap; - FEXCore::Allocator::munmap = FEX_munmap; - } + FEXCore::Allocator::mmap = FEX_mmap; + FEXCore::Allocator::munmap = FEX_munmap; +} - void ClearHooks() { +void ClearHooks() { #ifdef ENABLE_JEMALLOC - je___mmap_hook = ::mmap; - je___munmap_hook = ::munmap; + je___mmap_hook = ::mmap; + je___munmap_hook = ::munmap; #endif - FEXCore::Allocator::mmap = ::mmap; - FEXCore::Allocator::munmap = ::munmap; + FEXCore::Allocator::mmap = ::mmap; + FEXCore::Allocator::munmap = ::munmap; - // XXX: This is currently a leak. - // We can't work around this yet until static initializers that allocate memory are completely removed from our codebase - // Luckily we only remove this on process shutdown, so the kernel will do the cleanup for us - Alloc64.release(); - } + // XXX: This is currently a leak. + // We can't work around this yet until static initializers that allocate memory are completely removed from our codebase + // Luckily we only remove this on process shutdown, so the kernel will do the cleanup for us + Alloc64.release(); +} #pragma GCC diagnostic pop - FEX_DEFAULT_VISIBILITY size_t DetermineVASize() { - if (HostVASize) { - return HostVASize; - } +FEX_DEFAULT_VISIBILITY size_t DetermineVASize() { + if (HostVASize) { + return HostVASize; + } - static constexpr std::array TLBSizes = { - 57, - 52, - 48, - 47, - 42, - 39, - 36, + static constexpr std::array TLBSizes = { + 57, 52, 48, 47, 42, 39, 36, + }; + + for (auto Bits : TLBSizes) { + uintptr_t Size = 1ULL << Bits; + // Just try allocating + // We can't actually determine VA size on ARM safely + auto Find = [](uintptr_t Size) -> bool { + for (int i = 0; i < 64; ++i) { + // Try grabbing a some of the top pages of the range + // x86 allocates some high pages in the top end + void* Ptr = ::mmap(reinterpret_cast(Size - FEXCore::Utils::FEX_PAGE_SIZE * i), FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, + MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (Ptr != (void*)~0ULL) { + ::munmap(Ptr, FEXCore::Utils::FEX_PAGE_SIZE); + if (Ptr == (void*)(Size - FEXCore::Utils::FEX_PAGE_SIZE * i)) { + return true; + } + } + } + return false; }; - for (auto Bits : TLBSizes) { - uintptr_t Size = 1ULL << Bits; - // Just try allocating - // We can't actually determine VA size on ARM safely - auto Find = [](uintptr_t Size) -> bool { - for (int i = 0; i < 64; ++i) { - // Try grabbing a some of the top pages of the range - // x86 allocates some high pages in the top end - void *Ptr = ::mmap(reinterpret_cast(Size - FEXCore::Utils::FEX_PAGE_SIZE * i), FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (Ptr != (void*)~0ULL) { - ::munmap(Ptr, FEXCore::Utils::FEX_PAGE_SIZE); - if (Ptr == (void*)(Size - FEXCore::Utils::FEX_PAGE_SIZE * i)) { - return true; - } - } - } - return false; - }; - - if (Find(Size)) { - HostVASize = Bits; - return Bits; - } + if (Find(Size)) { + HostVASize = Bits; + return Bits; } - - LOGMAN_MSG_A_FMT("Couldn't determine host VA size"); - FEX_UNREACHABLE; } - #define STEAL_LOG(...) // fprintf(stderr, __VA_ARGS__) + LOGMAN_MSG_A_FMT("Couldn't determine host VA size"); + FEX_UNREACHABLE; +} - fextl::vector CollectMemoryGaps(uintptr_t Begin, uintptr_t End, int MapsFD) { - fextl::vector Regions; +#define STEAL_LOG(...) // fprintf(stderr, __VA_ARGS__) - uintptr_t RegionEnd = 0; +fextl::vector CollectMemoryGaps(uintptr_t Begin, uintptr_t End, int MapsFD) { + fextl::vector Regions; - char Buffer[2048]; - const char *Cursor = Buffer; - ssize_t Remaining = 0; + uintptr_t RegionEnd = 0; - bool EndOfFileReached = false; + char Buffer[2048]; + const char* Cursor = Buffer; + ssize_t Remaining = 0; - while (true) { - const auto line_begin = Cursor; - auto line_end = std::find(line_begin, Cursor + Remaining, '\n'); + bool EndOfFileReached = false; - // Check if the buffered data covers the entire line. - // If not, try buffering more data. - if (line_end == Cursor + Remaining) { - if (EndOfFileReached) { - // No more data to buffer. Add remaining memory and return. - const auto MapBegin = std::max(RegionEnd, Begin); - STEAL_LOG("[%d] EndOfFile; MapBegin: %016lX MapEnd: %016lX\n", __LINE__, MapBegin, End); - if (End > MapBegin) { - Regions.push_back({(void*)MapBegin, End - MapBegin}); - } + while (true) { + const auto line_begin = Cursor; + auto line_end = std::find(line_begin, Cursor + Remaining, '\n'); - return Regions; - } - - // Move pending content back to the beginning, then buffer more data. - std::copy(Cursor, Cursor + Remaining, std::begin(Buffer)); - auto PendingBytes = Remaining; - do { - Remaining = read(MapsFD, Buffer + PendingBytes, sizeof(Buffer) - PendingBytes); - } while (Remaining == -1 && errno == EAGAIN); - - if (Remaining < sizeof(Buffer) - PendingBytes) { - EndOfFileReached = true; - } - - Remaining += PendingBytes; - - Cursor = Buffer; - continue; - } - - // Parse mapped region in the format "fffff7cc3000-fffff7cc4000 r--p ..." - { - uintptr_t RegionBegin; - auto result = std::from_chars(Cursor, line_end, RegionBegin, 16); - LogMan::Throw::AFmt(result.ec == std::errc{} && *result.ptr == '-', "Unexpected line format"); - Cursor = result.ptr + 1; - - // Add gap between the previous region and the current one + // Check if the buffered data covers the entire line. + // If not, try buffering more data. + if (line_end == Cursor + Remaining) { + if (EndOfFileReached) { + // No more data to buffer. Add remaining memory and return. const auto MapBegin = std::max(RegionEnd, Begin); - const auto MapEnd = std::min(RegionBegin, End); - if (MapEnd > MapBegin) { - Regions.push_back({(void*)MapBegin, MapEnd - MapBegin}); + STEAL_LOG("[%d] EndOfFile; MapBegin: %016lX MapEnd: %016lX\n", __LINE__, MapBegin, End); + if (End > MapBegin) { + Regions.push_back({(void*)MapBegin, End - MapBegin}); } - result = std::from_chars(Cursor, line_end, RegionEnd, 16); - LogMan::Throw::AFmt(result.ec == std::errc{} && *result.ptr == ' ', "Unexpected line format"); - Cursor = result.ptr + 1; - - STEAL_LOG("[%d] parsed line: RegionBegin=%016lX RegionEnd=%016lX\n", __LINE__, RegionBegin, RegionEnd); - - if (RegionEnd >= End) { - // Early return if we are completely beyond the allocation space. - return Regions; - } + return Regions; } - Remaining -= line_end + 1 - line_begin; - Cursor = line_end + 1; + // Move pending content back to the beginning, then buffer more data. + std::copy(Cursor, Cursor + Remaining, std::begin(Buffer)); + auto PendingBytes = Remaining; + do { + Remaining = read(MapsFD, Buffer + PendingBytes, sizeof(Buffer) - PendingBytes); + } while (Remaining == -1 && errno == EAGAIN); + + if (Remaining < sizeof(Buffer) - PendingBytes) { + EndOfFileReached = true; + } + + Remaining += PendingBytes; + + Cursor = Buffer; + continue; } - FEX_UNREACHABLE; - } - fextl::vector StealMemoryRegion(uintptr_t Begin, uintptr_t End) { - const uintptr_t StackLocation_u64 = reinterpret_cast(alloca(0)); - - const int MapsFD = open("/proc/self/maps", O_RDONLY); - LogMan::Throw::AFmt(MapsFD != -1, "Failed to open /proc/self/maps"); - - auto Regions = CollectMemoryGaps(Begin, End, MapsFD); - close(MapsFD); - - // If the memory bounds include the stack, blocking all memory regions will - // limit the stack size to the current value. To allow some stack growth, - // we don't block the memory gap directly below the stack memory but - // instead map it as readable+writable. + // Parse mapped region in the format "fffff7cc3000-fffff7cc4000 r--p ..." { - auto StackRegionIt = - std::find_if(Regions.begin(), Regions.end(), - [StackLocation_u64](auto& Region) { - return reinterpret_cast(Region.Ptr) + Region.Size > StackLocation_u64; - }); + uintptr_t RegionBegin; + auto result = std::from_chars(Cursor, line_end, RegionBegin, 16); + LogMan::Throw::AFmt(result.ec == std::errc {} && *result.ptr == '-', "Unexpected line format"); + Cursor = result.ptr + 1; - // If no gap crossing the stack pointer was found but the SP is within - // the given bounds, the stack mapping is right after the last gap. - bool IsStackMapping = StackRegionIt != Regions.end() || StackLocation_u64 <= End; + // Add gap between the previous region and the current one + const auto MapBegin = std::max(RegionEnd, Begin); + const auto MapEnd = std::min(RegionBegin, End); + if (MapEnd > MapBegin) { + Regions.push_back({(void*)MapBegin, MapEnd - MapBegin}); + } - if (IsStackMapping && StackRegionIt != Regions.begin() && - reinterpret_cast(std::prev(StackRegionIt)->Ptr) + std::prev(StackRegionIt)->Size <= End) { - // Allocate the region under the stack as READ | WRITE so the stack can still grow - --StackRegionIt; + result = std::from_chars(Cursor, line_end, RegionEnd, 16); + LogMan::Throw::AFmt(result.ec == std::errc {} && *result.ptr == ' ', "Unexpected line format"); + Cursor = result.ptr + 1; - auto Alloc = mmap(StackRegionIt->Ptr, StackRegionIt->Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED, -1, 0); + STEAL_LOG("[%d] parsed line: RegionBegin=%016lX RegionEnd=%016lX\n", __LINE__, RegionBegin, RegionEnd); - LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({:x},{:x}) failed", StackRegionIt->Ptr, StackRegionIt->Size); - LogMan::Throw::AFmt(Alloc == StackRegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(StackRegionIt->Ptr)); - - Regions.erase(StackRegionIt); + if (RegionEnd >= End) { + // Early return if we are completely beyond the allocation space. + return Regions; } } - // Block remaining memory gaps - for (auto RegionIt = Regions.begin(); RegionIt != Regions.end(); ++RegionIt) { - auto Alloc = mmap(RegionIt->Ptr, RegionIt->Size, PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0); - - LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({:x},{:x}) failed", RegionIt->Ptr, RegionIt->Size); - LogMan::Throw::AFmt(Alloc == RegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(RegionIt->Ptr)); - } - - return Regions; + Remaining -= line_end + 1 - line_begin; + Cursor = line_end + 1; } + FEX_UNREACHABLE; +} - fextl::vector Steal48BitVA() { - size_t Bits = FEXCore::Allocator::DetermineVASize(); - if (Bits < 48) { - return {}; - } +fextl::vector StealMemoryRegion(uintptr_t Begin, uintptr_t End) { + const uintptr_t StackLocation_u64 = reinterpret_cast(alloca(0)); - uintptr_t Begin48BitVA = 0x0'8000'0000'0000ULL; - uintptr_t End48BitVA = 0x1'0000'0000'0000ULL; - return StealMemoryRegion(Begin48BitVA, End48BitVA); - } + const int MapsFD = open("/proc/self/maps", O_RDONLY); + LogMan::Throw::AFmt(MapsFD != -1, "Failed to open /proc/self/maps"); - void ReclaimMemoryRegion(const fextl::vector &Regions) { - for (const auto &Region: Regions) { - ::munmap(Region.Ptr, Region.Size); + auto Regions = CollectMemoryGaps(Begin, End, MapsFD); + close(MapsFD); + + // If the memory bounds include the stack, blocking all memory regions will + // limit the stack size to the current value. To allow some stack growth, + // we don't block the memory gap directly below the stack memory but + // instead map it as readable+writable. + { + auto StackRegionIt = std::find_if(Regions.begin(), Regions.end(), [StackLocation_u64](auto& Region) { + return reinterpret_cast(Region.Ptr) + Region.Size > StackLocation_u64; + }); + + // If no gap crossing the stack pointer was found but the SP is within + // the given bounds, the stack mapping is right after the last gap. + bool IsStackMapping = StackRegionIt != Regions.end() || StackLocation_u64 <= End; + + if (IsStackMapping && StackRegionIt != Regions.begin() && + reinterpret_cast(std::prev(StackRegionIt)->Ptr) + std::prev(StackRegionIt)->Size <= End) { + // Allocate the region under the stack as READ | WRITE so the stack can still grow + --StackRegionIt; + + auto Alloc = + mmap(StackRegionIt->Ptr, StackRegionIt->Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED, -1, 0); + + LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({:x},{:x}) failed", StackRegionIt->Ptr, StackRegionIt->Size); + LogMan::Throw::AFmt(Alloc == StackRegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(StackRegionIt->Ptr)); + + Regions.erase(StackRegionIt); } } - void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) { - if (Alloc64) { - Alloc64->LockBeforeFork(Thread); - } + // Block remaining memory gaps + for (auto RegionIt = Regions.begin(); RegionIt != Regions.end(); ++RegionIt) { + auto Alloc = mmap(RegionIt->Ptr, RegionIt->Size, PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0); + + LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({:x},{:x}) failed", RegionIt->Ptr, RegionIt->Size); + LogMan::Throw::AFmt(Alloc == RegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(RegionIt->Ptr)); } - void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child) { - if (Alloc64) { - Alloc64->UnlockAfterFork(Thread, Child); - } + return Regions; +} + +fextl::vector Steal48BitVA() { + size_t Bits = FEXCore::Allocator::DetermineVASize(); + if (Bits < 48) { + return {}; + } + + uintptr_t Begin48BitVA = 0x0'8000'0000'0000ULL; + uintptr_t End48BitVA = 0x1'0000'0000'0000ULL; + return StealMemoryRegion(Begin48BitVA, End48BitVA); +} + +void ReclaimMemoryRegion(const fextl::vector& Regions) { + for (const auto& Region : Regions) { + ::munmap(Region.Ptr, Region.Size); } } + +void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) { + if (Alloc64) { + Alloc64->LockBeforeFork(Thread); + } +} + +void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child) { + if (Alloc64) { + Alloc64->UnlockAfterFork(Thread, Child); + } +} +} // namespace FEXCore::Allocator #endif diff --git a/FEXCore/Source/Utils/Allocator.h b/FEXCore/Source/Utils/Allocator.h index 5a26f72b4..a30605a80 100644 --- a/FEXCore/Source/Utils/Allocator.h +++ b/FEXCore/Source/Utils/Allocator.h @@ -6,6 +6,6 @@ struct InternalThreadState; } namespace FEXCore::Allocator { - void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread); - void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child); -} +void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread); +void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child); +} // namespace FEXCore::Allocator diff --git a/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp b/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp index a2e097f4d..0ae548dc1 100644 --- a/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp +++ b/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp @@ -30,190 +30,190 @@ namespace Alloc::OSAllocator { - thread_local FEXCore::Core::InternalThreadState *TLSThread{}; +thread_local FEXCore::Core::InternalThreadState* TLSThread {}; - void RegisterTLSData(FEXCore::Core::InternalThreadState *Thread) { - TLSThread = Thread; +void RegisterTLSData(FEXCore::Core::InternalThreadState* Thread) { + TLSThread = Thread; +} + +void UninstallTLSData(FEXCore::Core::InternalThreadState* Thread) { + TLSThread = nullptr; +} + +class OSAllocator_64Bit final : public Alloc::HostAllocator { +public: + OSAllocator_64Bit(); + virtual ~OSAllocator_64Bit(); + void* AllocateSlab(size_t Size) override { + return nullptr; + } + void DeallocateSlab(void* Ptr, size_t Size) override {} + + void* Mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) override; + int Munmap(void* addr, size_t length) override; + + void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) override { + AllocationMutex.lock(); } - void UninstallTLSData(FEXCore::Core::InternalThreadState *Thread) { - TLSThread = nullptr; + void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child) override { + if (Child) { + AllocationMutex.StealAndDropActiveLocks(); + } else { + AllocationMutex.unlock(); + } } - class OSAllocator_64Bit final : public Alloc::HostAllocator { - public: - OSAllocator_64Bit(); - virtual ~OSAllocator_64Bit(); - void *AllocateSlab(size_t Size) override { return nullptr; } - void DeallocateSlab(void *Ptr, size_t Size) override {} +private: + // Upper bound is the maximum virtual address space of the host processor + uintptr_t UPPER_BOUND = (1ULL << 57); - void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override; - int Munmap(void *addr, size_t length) override; + // Lower bound is the starting of the range just past the lower 32bits + constexpr static uintptr_t LOWER_BOUND = 0x1'0000'0000ULL; - void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) override { - AllocationMutex.lock(); - } + uintptr_t UPPER_BOUND_PAGE = UPPER_BOUND / FEXCore::Utils::FEX_PAGE_SIZE; + constexpr static uintptr_t LOWER_BOUND_PAGE = LOWER_BOUND / FEXCore::Utils::FEX_PAGE_SIZE; - void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child) override { - if (Child) { - AllocationMutex.StealAndDropActiveLocks(); - } - else { - AllocationMutex.unlock(); - } - } - - private: - // Upper bound is the maximum virtual address space of the host processor - uintptr_t UPPER_BOUND = (1ULL << 57); - - // Lower bound is the starting of the range just past the lower 32bits - constexpr static uintptr_t LOWER_BOUND = 0x1'0000'0000ULL; - - uintptr_t UPPER_BOUND_PAGE = UPPER_BOUND / FEXCore::Utils::FEX_PAGE_SIZE; - constexpr static uintptr_t LOWER_BOUND_PAGE = LOWER_BOUND / FEXCore::Utils::FEX_PAGE_SIZE; - - struct ReservedVMARegion { - uintptr_t Base; - // Could be number of pages if we want to pack this in to 12 bytes - uint64_t RegionSize; - }; - - bool MergeReservedRegionIfPossible(ReservedVMARegion *Region, uintptr_t NextPtr, uint64_t NextSize) { - constexpr uint64_t MaxReservedRegionSize = 64ULL * 1024 * 1024 * 1024; // 64GB - uintptr_t RegionEnd = Region->Base + Region->RegionSize; - uint64_t NewRegionSize = Region->RegionSize + NextSize; - if (RegionEnd == NextPtr && - NewRegionSize <= MaxReservedRegionSize) { - // Append the contiguous region - Region->RegionSize = NewRegionSize; - return true; - } - return false; - } - - struct LiveVMARegion { - ReservedVMARegion *SlabInfo; - uint64_t FreeSpace{}; - uint64_t NumManagedPages{}; - uint32_t LastPageAllocation{}; - bool HadMunmap{}; - - // Align UsedPages so it pads to the next page. - // Necessary to take advantage of madvise zero page pooling. - using FlexBitElementType = uint64_t; - alignas(4096) FEXCore::FlexBitSet UsedPages; - - // This returns the size of the LiveVMARegion in addition to the flex set that tracks the used data - // The LiveVMARegion lives at the start of the VMA region which means on initialization we need to set that - // tracked ranged as used immediately - static size_t GetSizeWithFlexSet(size_t Size) { - // One element per page - - // 0x10'0000'0000 bytes - // 0x100'0000 Pages - // 1 bit per page for tracking means 0x20'0000 (Pages / 8) bytes of flex space - // Which is 2MB of tracking - uint64_t NumElements = (Size >> FEXCore::Utils::FEX_PAGE_SHIFT) * sizeof(FlexBitElementType); - return sizeof(LiveVMARegion) + FEXCore::FlexBitSet::Size(NumElements); - } - - static void InitializeVMARegionUsed(LiveVMARegion *Region, size_t AdditionalSize) { - size_t SizeOfLiveRegion = FEXCore::AlignUp(LiveVMARegion::GetSizeWithFlexSet(Region->SlabInfo->RegionSize), FEXCore::Utils::FEX_PAGE_SIZE); - size_t SizePlusManagedData = SizeOfLiveRegion + AdditionalSize; - - Region->FreeSpace = Region->SlabInfo->RegionSize - SizePlusManagedData; - - size_t NumManagedPages = SizePlusManagedData >> FEXCore::Utils::FEX_PAGE_SHIFT; - size_t ManagedSize = NumManagedPages << FEXCore::Utils::FEX_PAGE_SHIFT; - - // Use madvise to set the full tracking region to zero. - // This ensures unused pages are zero, while not having the backing pages consuming memory. - ::madvise(Region->UsedPages.Memory + ManagedSize, (Region->SlabInfo->RegionSize >> FEXCore::Utils::FEX_PAGE_SHIFT) - ManagedSize, MADV_DONTNEED); - - // Use madvise to claim WILLNEED on the beginning pages for initial state tracking. - // Improves performance of the following MemClear by not doing a page level fault dance for data necessary to track >170TB of used pages. - ::madvise(Region->UsedPages.Memory, ManagedSize, MADV_WILLNEED); - - // Set our reserved pages - Region->UsedPages.MemSet(NumManagedPages); - Region->LastPageAllocation = NumManagedPages; - Region->NumManagedPages = NumManagedPages; - } - }; - - static_assert(sizeof(LiveVMARegion) == 4096, "Needs to be the size of a page"); - - static_assert(std::is_trivially_copyable::value, "Needs to be trivially copyable"); - static_assert(offsetof(LiveVMARegion, UsedPages) == sizeof(LiveVMARegion), "FlexBitSet needs to be at the end"); - - using ReservedRegionListType = fex_pmr::list; - using LiveRegionListType = fex_pmr::list; - ReservedRegionListType *ReservedRegions{}; - LiveRegionListType *LiveRegions{}; - - Alloc::ForwardOnlyIntrusiveArenaAllocator *ObjectAlloc{}; - FEXCore::ForkableUniqueMutex AllocationMutex; - void DetermineVASize(); - - LiveVMARegion *MakeRegionActive(ReservedRegionListType::iterator ReservedIterator, uint64_t UsedSize) { - ReservedVMARegion *ReservedRegion = *ReservedIterator; - - ReservedRegions->erase(ReservedIterator); - - // mprotect the new region we've allocated - size_t SizeOfLiveRegion = FEXCore::AlignUp(LiveVMARegion::GetSizeWithFlexSet(ReservedRegion->RegionSize), FEXCore::Utils::FEX_PAGE_SIZE); - size_t SizePlusManagedData = UsedSize + SizeOfLiveRegion; - - [[maybe_unused]] auto Res = mprotect(reinterpret_cast(ReservedRegion->Base), SizePlusManagedData, PROT_READ | PROT_WRITE); - - if (Res == -1) { - LOGMAN_MSG_A_FMT("Couldn't mprotect region: {} '{}' Likely occurs when running out of memory or Maximum VMAs", errno, strerror(errno)); - } - - LiveVMARegion *LiveRange = new (reinterpret_cast(ReservedRegion->Base)) LiveVMARegion(); - - // Copy over the reserved data - LiveRange->SlabInfo = ReservedRegion; - - // Initialize VMA - LiveVMARegion::InitializeVMARegionUsed(LiveRange, UsedSize); - - // Add to our active tracked ranges - auto LiveIter = LiveRegions->emplace_back(LiveRange); - return LiveIter; - } - - // 32-bit old kernel workarounds - fextl::vector Steal32BitIfOldKernel(); - - void AllocateMemoryRegions(fextl::vector const &Ranges); - LiveVMARegion *FindLiveRegionForAddress(uintptr_t Addr, uintptr_t AddrEnd); + struct ReservedVMARegion { + uintptr_t Base; + // Could be number of pages if we want to pack this in to 12 bytes + uint64_t RegionSize; }; + bool MergeReservedRegionIfPossible(ReservedVMARegion* Region, uintptr_t NextPtr, uint64_t NextSize) { + constexpr uint64_t MaxReservedRegionSize = 64ULL * 1024 * 1024 * 1024; // 64GB + uintptr_t RegionEnd = Region->Base + Region->RegionSize; + uint64_t NewRegionSize = Region->RegionSize + NextSize; + if (RegionEnd == NextPtr && NewRegionSize <= MaxReservedRegionSize) { + // Append the contiguous region + Region->RegionSize = NewRegionSize; + return true; + } + return false; + } + + struct LiveVMARegion { + ReservedVMARegion* SlabInfo; + uint64_t FreeSpace {}; + uint64_t NumManagedPages {}; + uint32_t LastPageAllocation {}; + bool HadMunmap {}; + + // Align UsedPages so it pads to the next page. + // Necessary to take advantage of madvise zero page pooling. + using FlexBitElementType = uint64_t; + alignas(4096) FEXCore::FlexBitSet UsedPages; + + // This returns the size of the LiveVMARegion in addition to the flex set that tracks the used data + // The LiveVMARegion lives at the start of the VMA region which means on initialization we need to set that + // tracked ranged as used immediately + static size_t GetSizeWithFlexSet(size_t Size) { + // One element per page + + // 0x10'0000'0000 bytes + // 0x100'0000 Pages + // 1 bit per page for tracking means 0x20'0000 (Pages / 8) bytes of flex space + // Which is 2MB of tracking + uint64_t NumElements = (Size >> FEXCore::Utils::FEX_PAGE_SHIFT) * sizeof(FlexBitElementType); + return sizeof(LiveVMARegion) + FEXCore::FlexBitSet::Size(NumElements); + } + + static void InitializeVMARegionUsed(LiveVMARegion* Region, size_t AdditionalSize) { + size_t SizeOfLiveRegion = FEXCore::AlignUp(LiveVMARegion::GetSizeWithFlexSet(Region->SlabInfo->RegionSize), FEXCore::Utils::FEX_PAGE_SIZE); + size_t SizePlusManagedData = SizeOfLiveRegion + AdditionalSize; + + Region->FreeSpace = Region->SlabInfo->RegionSize - SizePlusManagedData; + + size_t NumManagedPages = SizePlusManagedData >> FEXCore::Utils::FEX_PAGE_SHIFT; + size_t ManagedSize = NumManagedPages << FEXCore::Utils::FEX_PAGE_SHIFT; + + // Use madvise to set the full tracking region to zero. + // This ensures unused pages are zero, while not having the backing pages consuming memory. + ::madvise(Region->UsedPages.Memory + ManagedSize, (Region->SlabInfo->RegionSize >> FEXCore::Utils::FEX_PAGE_SHIFT) - ManagedSize, + MADV_DONTNEED); + + // Use madvise to claim WILLNEED on the beginning pages for initial state tracking. + // Improves performance of the following MemClear by not doing a page level fault dance for data necessary to track >170TB of used pages. + ::madvise(Region->UsedPages.Memory, ManagedSize, MADV_WILLNEED); + + // Set our reserved pages + Region->UsedPages.MemSet(NumManagedPages); + Region->LastPageAllocation = NumManagedPages; + Region->NumManagedPages = NumManagedPages; + } + }; + + static_assert(sizeof(LiveVMARegion) == 4096, "Needs to be the size of a page"); + + static_assert(std::is_trivially_copyable::value, "Needs to be trivially copyable"); + static_assert(offsetof(LiveVMARegion, UsedPages) == sizeof(LiveVMARegion), "FlexBitSet needs to be at the end"); + + using ReservedRegionListType = fex_pmr::list; + using LiveRegionListType = fex_pmr::list; + ReservedRegionListType* ReservedRegions {}; + LiveRegionListType* LiveRegions {}; + + Alloc::ForwardOnlyIntrusiveArenaAllocator* ObjectAlloc {}; + FEXCore::ForkableUniqueMutex AllocationMutex; + void DetermineVASize(); + + LiveVMARegion* MakeRegionActive(ReservedRegionListType::iterator ReservedIterator, uint64_t UsedSize) { + ReservedVMARegion* ReservedRegion = *ReservedIterator; + + ReservedRegions->erase(ReservedIterator); + + // mprotect the new region we've allocated + size_t SizeOfLiveRegion = FEXCore::AlignUp(LiveVMARegion::GetSizeWithFlexSet(ReservedRegion->RegionSize), FEXCore::Utils::FEX_PAGE_SIZE); + size_t SizePlusManagedData = UsedSize + SizeOfLiveRegion; + + [[maybe_unused]] auto Res = mprotect(reinterpret_cast(ReservedRegion->Base), SizePlusManagedData, PROT_READ | PROT_WRITE); + + if (Res == -1) { + LOGMAN_MSG_A_FMT("Couldn't mprotect region: {} '{}' Likely occurs when running out of memory or Maximum VMAs", errno, strerror(errno)); + } + + LiveVMARegion* LiveRange = new (reinterpret_cast(ReservedRegion->Base)) LiveVMARegion(); + + // Copy over the reserved data + LiveRange->SlabInfo = ReservedRegion; + + // Initialize VMA + LiveVMARegion::InitializeVMARegionUsed(LiveRange, UsedSize); + + // Add to our active tracked ranges + auto LiveIter = LiveRegions->emplace_back(LiveRange); + return LiveIter; + } + + // 32-bit old kernel workarounds + fextl::vector Steal32BitIfOldKernel(); + + void AllocateMemoryRegions(const fextl::vector& Ranges); + LiveVMARegion* FindLiveRegionForAddress(uintptr_t Addr, uintptr_t AddrEnd); +}; + void OSAllocator_64Bit::DetermineVASize() { size_t Bits = FEXCore::Allocator::DetermineVASize(); uintptr_t Size = 1ULL << Bits; UPPER_BOUND = Size; - #if _M_X86_64 // Last page cannot be allocated on x86 - UPPER_BOUND -= FEXCore::Utils::FEX_PAGE_SIZE; - #endif +#if _M_X86_64 // Last page cannot be allocated on x86 + UPPER_BOUND -= FEXCore::Utils::FEX_PAGE_SIZE; +#endif UPPER_BOUND_PAGE = UPPER_BOUND / FEXCore::Utils::FEX_PAGE_SIZE; } -OSAllocator_64Bit::LiveVMARegion *OSAllocator_64Bit::FindLiveRegionForAddress(uintptr_t Addr, uintptr_t AddrEnd) { - LiveVMARegion *LiveRegion{}; +OSAllocator_64Bit::LiveVMARegion* OSAllocator_64Bit::FindLiveRegionForAddress(uintptr_t Addr, uintptr_t AddrEnd) { + LiveVMARegion* LiveRegion {}; // Check active slabs to see if we can fit this for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) { uintptr_t RegionBegin = (*it)->SlabInfo->Base; uintptr_t RegionEnd = RegionBegin + (*it)->SlabInfo->RegionSize; - if (Addr >= RegionBegin && - Addr < RegionEnd) { + if (Addr >= RegionBegin && Addr < RegionEnd) { LiveRegion = *it; // Leave our loop break; @@ -226,10 +226,9 @@ OSAllocator_64Bit::LiveVMARegion *OSAllocator_64Bit::FindLiveRegionForAddress(ui // Didn't have a slab that fit this range // Check our reserved regions to see if we have one that fits for (auto it = ReservedRegions->begin(); it != ReservedRegions->end(); ++it) { - ReservedVMARegion *ReservedRegion = *it; + ReservedVMARegion* ReservedRegion = *it; uintptr_t RegionEnd = ReservedRegion->Base + ReservedRegion->RegionSize; - if (Addr >= ReservedRegion->Base && - AddrEnd < RegionEnd) { + if (Addr >= ReservedRegion->Base && AddrEnd < RegionEnd) { // Found one, let's make it active LiveRegion = MakeRegionActive(it, 0); break; @@ -240,9 +239,8 @@ OSAllocator_64Bit::LiveVMARegion *OSAllocator_64Bit::FindLiveRegionForAddress(ui return LiveRegion; } -void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - if (addr != 0 && - addr < reinterpret_cast(LOWER_BOUND)) { +void* OSAllocator_64Bit::Mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + if (addr != 0 && addr < reinterpret_cast(LOWER_BOUND)) { // If we are asked to allocate something outside of the 64-bit space // Then we need to just hand this to the OS return ::mmap(addr, length, prot, flags, fd, offset); @@ -255,8 +253,7 @@ void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, in } // If FD is provided then offset must also be page aligned - if (fd != -1 && - offset & ~FEXCore::Utils::FEX_PAGE_MASK) { + if (fd != -1 && offset & ~FEXCore::Utils::FEX_PAGE_MASK) { return reinterpret_cast(-EINVAL); } @@ -274,24 +271,23 @@ void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, in // This needs a mutex to be thread safe auto lk = FEXCore::GuardSignalDeferringSectionWithFallback(AllocationMutex, TLSThread); - uint64_t AllocatedOffset{}; - LiveVMARegion *LiveRegion{}; + uint64_t AllocatedOffset {}; + LiveVMARegion* LiveRegion {}; if (Fixed || Addr != 0) { LiveRegion = FindLiveRegionForAddress(Addr, AddrEnd); } - again: +again: - auto CheckIfRangeFits = [&AllocatedOffset](LiveVMARegion *Region, uint64_t length, int prot, int flags, int fd, off_t offset, uint64_t StartingPosition = 0) -> std::pair { - uint64_t AllocatedPage{~0ULL}; + auto CheckIfRangeFits = [&AllocatedOffset](LiveVMARegion* Region, uint64_t length, int prot, int flags, int fd, off_t offset, + uint64_t StartingPosition = 0) -> std::pair { + uint64_t AllocatedPage {~0ULL}; uint64_t NumberOfPages = length >> FEXCore::Utils::FEX_PAGE_SHIFT; if (Region->FreeSpace >= length) { uint64_t LastAllocation = - StartingPosition ? - (StartingPosition - Region->SlabInfo->Base) >> FEXCore::Utils::FEX_PAGE_SHIFT - : Region->LastPageAllocation; + StartingPosition ? (StartingPosition - Region->SlabInfo->Base) >> FEXCore::Utils::FEX_PAGE_SHIFT : Region->LastPageAllocation; size_t RegionNumberOfPages = Region->SlabInfo->RegionSize >> FEXCore::Utils::FEX_PAGE_SHIFT; @@ -320,11 +316,7 @@ void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, in AllocatedOffset = Region->SlabInfo->Base + AllocatedPage * FEXCore::Utils::FEX_PAGE_SIZE; // We need to setup protections for this - void *MMapResult = ::mmap(reinterpret_cast(AllocatedOffset), - length, - prot, - (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED, - fd, offset); + void* MMapResult = ::mmap(reinterpret_cast(AllocatedOffset), length, prot, (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED, fd, offset); if (MMapResult == MAP_FAILED) { return std::make_pair(Region, reinterpret_cast(-errno)); @@ -345,19 +337,13 @@ void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, in if (Fits.first && Fits.second == reinterpret_cast(Addr)) { // We fit correctly AllocatedOffset = Addr; - } - else { + } else { // Intersected with something that already existed return reinterpret_cast(-EEXIST); } - } - else { + } else { // We need to mmap the file to this location - void *MMapResult = ::mmap(reinterpret_cast(Addr), - length, - prot, - (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED, - fd, offset); + void* MMapResult = ::mmap(reinterpret_cast(Addr), length, prot, (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED, fd, offset); if (MMapResult == MAP_FAILED) { return reinterpret_cast(-errno); @@ -367,8 +353,7 @@ void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, in } // Fall through to live region tracking } - } - else { + } else { // Check our active slabs to see if we can fit the allocation // Slightly different than fixed since it doesn't need exact placement if (LiveRegion && Addr != 0) { @@ -378,8 +363,7 @@ void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, in if (Fits.first && Fits.second == reinterpret_cast(Addr)) { // We fit correctly AllocatedOffset = Addr; - } - else { + } else { // Couldn't fit // We can continue past this point still LiveRegion = nullptr; @@ -438,7 +422,7 @@ void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, in return reinterpret_cast(AllocatedOffset); } -int OSAllocator_64Bit::Munmap(void *addr, size_t length) { +int OSAllocator_64Bit::Munmap(void* addr, size_t length) { if (addr < reinterpret_cast(LOWER_BOUND)) { // If we are asked to allocate something outside of the 64-bit space // Then we need to just hand this to the OS @@ -471,11 +455,10 @@ int OSAllocator_64Bit::Munmap(void *addr, size_t length) { uintptr_t RegionBegin = (*it)->SlabInfo->Base; uintptr_t RegionEnd = RegionBegin + (*it)->SlabInfo->RegionSize; - if (RegionBegin <= PtrBegin && - RegionEnd > PtrEnd) { + if (RegionBegin <= PtrBegin && RegionEnd > PtrEnd) { // Live region fully encompasses slab range - uint64_t FreedPages{}; + uint64_t FreedPages {}; uint32_t SlabPageBegin = (PtrBegin - RegionBegin) >> FEXCore::Utils::FEX_PAGE_SHIFT; uint64_t PagesToFree = length >> FEXCore::Utils::FEX_PAGE_SHIFT; @@ -483,8 +466,7 @@ int OSAllocator_64Bit::Munmap(void *addr, size_t length) { FreedPages += (*it)->UsedPages.TestAndClear(SlabPageBegin + i) ? 1 : 0; } - if (FreedPages != 0) - { + if (FreedPages != 0) { // If we were contiuous freeing then make sure to give back the physical address space // If the region was locked then madvise won't remove the physical backing // This woul be a bug in the frontend application @@ -512,16 +494,16 @@ int OSAllocator_64Bit::Munmap(void *addr, size_t length) { fextl::vector OSAllocator_64Bit::Steal32BitIfOldKernel() { // First calculate kernel version - struct utsname buf{}; + struct utsname buf {}; if (uname(&buf) == -1) { return {}; } - int32_t Major{}; - int32_t Minor{}; - int32_t Patch{}; - char Tmp{}; - fextl::istringstream ss{buf.release}; + int32_t Major {}; + int32_t Minor {}; + int32_t Patch {}; + char Tmp {}; + fextl::istringstream ss {buf.release}; ss >> Major; ss.read(&Tmp, 1); ss >> Minor; @@ -541,8 +523,8 @@ fextl::vector OSAllocator_64Bit::Steal32BitIfO return FEXCore::Allocator::StealMemoryRegion(LOWER_BOUND_32, UPPER_BOUND_32); } -void OSAllocator_64Bit::AllocateMemoryRegions(fextl::vector const &Ranges) { - for (auto [Ptr, AllocationSize]: Ranges) { +void OSAllocator_64Bit::AllocateMemoryRegions(const fextl::vector& Ranges) { + for (auto [Ptr, AllocationSize] : Ranges) { if (!ObjectAlloc) { auto MaxSize = std::min(size_t(64) * 1024 * 1024, AllocationSize); @@ -564,7 +546,7 @@ void OSAllocator_64Bit::AllocateMemoryRegions(fextl::vectornew_construct(); + ReservedVMARegion* Region = ObjectAlloc->new_construct(); Region->Base = reinterpret_cast(Ptr); Region->RegionSize = AllocationSize; ReservedRegions->emplace_back(Region); @@ -602,4 +584,4 @@ OSAllocator_64Bit::~OSAllocator_64Bit() { fextl::unique_ptr Create64BitAllocator() { return fextl::make_unique(); } -} +} // namespace Alloc::OSAllocator diff --git a/FEXCore/Source/Utils/Allocator/FlexBitSet.h b/FEXCore/Source/Utils/Allocator/FlexBitSet.h index 9d4d08467..ad221d1e8 100644 --- a/FEXCore/Source/Utils/Allocator/FlexBitSet.h +++ b/FEXCore/Source/Utils/Allocator/FlexBitSet.h @@ -51,8 +51,8 @@ struct FlexBitSet final { // TODO: Make {Forward,Backward}ScanForRange faster // Currently these functions test a single bit at a time, which is fairly costly. // The compiler emits a full element load per iteration, wasting a bunch of time on loads. - // If we change these functions to have a pre-amble and post-amble to align the primary loop to the element size then this can go significantly - // faster. + // If we change these functions to have a pre-amble and post-amble to align the primary loop to the element size then this can go + // significantly faster. // // Once the element scanning is aligned to the element size, we can then use native count leading zero(CLZ) and count trailing zero(CTZ) // instructions on a full element to scan uint64_t elements per loop iteration. @@ -70,8 +70,7 @@ struct FlexBitSet final { template BitsetScanResults BackwardScanForRange(size_t BeginningElement, size_t ElementCount, size_t MinimumElement) { bool FoundHole {}; - for (size_t CurrentPage = BeginningElement; - CurrentPage >= (MinimumElement + ElementCount);) { + for (size_t CurrentPage = BeginningElement; CurrentPage >= (MinimumElement + ElementCount);) { size_t Remaining = ElementCount; LOGMAN_THROW_AA_FMT(Remaining <= CurrentPage, "Scanning less than available range"); @@ -91,10 +90,9 @@ struct FlexBitSet final { // Didn't find a slab range CurrentPage -= Remaining; - } - else { + } else { // We have a slab range - return BitsetScanResults{CurrentPage - ElementCount, FoundHole}; + return BitsetScanResults {CurrentPage - ElementCount, FoundHole}; } } @@ -110,8 +108,7 @@ struct FlexBitSet final { BitsetScanResults ForwardScanForRange(size_t BeginningElement, size_t ElementCount, size_t ElementsInSet) { bool FoundHole {}; - for (size_t CurrentElement = BeginningElement; - CurrentElement < (ElementsInSet - ElementCount);) { + for (size_t CurrentElement = BeginningElement; CurrentElement < (ElementsInSet - ElementCount);) { // If we have enough free space, check if we have enough free pages that are contiguous size_t Remaining = ElementCount; @@ -133,8 +130,7 @@ struct FlexBitSet final { // Didn't find a slab range CurrentElement += Remaining; - } - else { + } else { // We have a slab range return BitsetScanResults {CurrentElement, FoundHole}; } diff --git a/FEXCore/Source/Utils/Allocator/HostAllocator.h b/FEXCore/Source/Utils/Allocator/HostAllocator.h index f09a9bc5e..846e7cd19 100644 --- a/FEXCore/Source/Utils/Allocator/HostAllocator.h +++ b/FEXCore/Source/Utils/Allocator/HostAllocator.h @@ -12,39 +12,43 @@ struct InternalThreadState; } namespace Alloc { - // HostAllocator is just a page pased slab allocator - // Similar to mmap and munmap only mapping at the page level - class HostAllocator { - public: - HostAllocator() = default; - virtual ~HostAllocator() = default; - virtual void *AllocateSlab(size_t Size) = 0; - virtual void DeallocateSlab(void *Ptr, size_t Size) = 0; +// HostAllocator is just a page pased slab allocator +// Similar to mmap and munmap only mapping at the page level +class HostAllocator { +public: + HostAllocator() = default; + virtual ~HostAllocator() = default; + virtual void* AllocateSlab(size_t Size) = 0; + virtual void DeallocateSlab(void* Ptr, size_t Size) = 0; - virtual void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { return nullptr; } - virtual int Munmap(void *addr, size_t length) { return -1; } + virtual void* Mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + return nullptr; + } + virtual int Munmap(void* addr, size_t length) { + return -1; + } - virtual void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) {} - virtual void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child) {} - }; + virtual void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) {} + virtual void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child) {} +}; - class GlobalAllocator { - public: - HostAllocator *Alloc{}; - GlobalAllocator(HostAllocator *_Alloc) - : Alloc {_Alloc} {} +class GlobalAllocator { +public: + HostAllocator* Alloc {}; + GlobalAllocator(HostAllocator* _Alloc) + : Alloc {_Alloc} {} - virtual ~GlobalAllocator() = default; - virtual void *malloc(size_t Size) = 0; - virtual void *calloc(size_t num, size_t size) = 0; - virtual void *realloc(void *ptr, size_t size) = 0; - virtual void *memalign(size_t alignment, size_t size) = 0; - virtual void free(void *ptr) = 0; - }; -} + virtual ~GlobalAllocator() = default; + virtual void* malloc(size_t Size) = 0; + virtual void* calloc(size_t num, size_t size) = 0; + virtual void* realloc(void* ptr, size_t size) = 0; + virtual void* memalign(size_t alignment, size_t size) = 0; + virtual void free(void* ptr) = 0; +}; +} // namespace Alloc namespace Alloc::OSAllocator { -void RegisterTLSData(FEXCore::Core::InternalThreadState *Thread); -void UninstallTLSData(FEXCore::Core::InternalThreadState *Thread); +void RegisterTLSData(FEXCore::Core::InternalThreadState* Thread); +void UninstallTLSData(FEXCore::Core::InternalThreadState* Thread); fextl::unique_ptr Create64BitAllocator(); -} +} // namespace Alloc::OSAllocator diff --git a/FEXCore/Source/Utils/Allocator/IntrusiveArenaAllocator.h b/FEXCore/Source/Utils/Allocator/IntrusiveArenaAllocator.h index 85cdf844a..876ed8356 100644 --- a/FEXCore/Source/Utils/Allocator/IntrusiveArenaAllocator.h +++ b/FEXCore/Source/Utils/Allocator/IntrusiveArenaAllocator.h @@ -16,177 +16,184 @@ namespace fex_pmr = std::pmr; #include namespace Alloc { - class ForwardOnlyIntrusiveArenaAllocator final : public fex_pmr::memory_resource { - public: - ForwardOnlyIntrusiveArenaAllocator(void* Ptr, size_t _Size) - : Begin {reinterpret_cast(Ptr)} - , Size {_Size} { - LastAllocation = sizeof(ForwardOnlyIntrusiveArenaAllocator); - } +class ForwardOnlyIntrusiveArenaAllocator final : public fex_pmr::memory_resource { +public: + ForwardOnlyIntrusiveArenaAllocator(void* Ptr, size_t _Size) + : Begin {reinterpret_cast(Ptr)} + , Size {_Size} { + LastAllocation = sizeof(ForwardOnlyIntrusiveArenaAllocator); + } - ~ForwardOnlyIntrusiveArenaAllocator() = default; + ~ForwardOnlyIntrusiveArenaAllocator() = default; - template - U *new_construct(Args&&... args) { - void *Ptr = do_allocate(sizeof(U), std::alignment_of::value); - return new (Ptr) U(args...); - } + template + U* new_construct(Args&&... args) { + void* Ptr = do_allocate(sizeof(U), std::alignment_of::value); + return new (Ptr) U(args...); + } - template - U *new_construct(U *Class, Args&&... args) { - void *Ptr = do_allocate(sizeof(U), std::alignment_of::value); - return new (Ptr) U(args...); - } + template + U* new_construct(U* Class, Args&&... args) { + void* Ptr = do_allocate(sizeof(U), std::alignment_of::value); + return new (Ptr) U(args...); + } - size_t AmountAllocated() const { return LastAllocation; } + size_t AmountAllocated() const { + return LastAllocation; + } - private: - void *do_allocate(std::size_t bytes, std::size_t alignment) override { - size_t PreviousAligned = FEXCore::AlignUp(LastAllocation, alignment); - size_t NewOffset = PreviousAligned + bytes; - - if (NewOffset > Size) { - return nullptr; - } - - LastAllocation = NewOffset; - - return reinterpret_cast(Begin + PreviousAligned); - } - - void do_deallocate(void*, std::size_t, std::size_t) override { - // Do nothing - } - - bool do_is_equal(const fex_pmr::memory_resource& other) const noexcept override { - // Only if the allocator pointers are the same are they equal - if (this == &other) { - return true; - } - // We don't share state with another allocator so we can't share anything - return false; - } - - uintptr_t Begin; - size_t Size; - size_t LastAllocation{}; - }; - - class IntrusiveArenaAllocator final : public fex_pmr::memory_resource { - public: - IntrusiveArenaAllocator(void* Ptr, size_t _Size) - : Begin {reinterpret_cast(Ptr)} - , Size {_Size} { - uint64_t NumberOfPages = _Size / FEXCore::Utils::FEX_PAGE_SIZE; - uint64_t UsedBits = FEXCore::AlignUp(sizeof(IntrusiveArenaAllocator) + - Size / FEXCore::Utils::FEX_PAGE_SIZE / 8, FEXCore::Utils::FEX_PAGE_SIZE); - for (size_t i = 0; i < UsedBits; ++i) { - UsedPages.Set(i); - } - - FreePages = NumberOfPages - UsedBits; - } - - template - U *new_construct(Args&&... args) { - void *Ptr = do_allocate(sizeof(U), std::alignment_of::value); - return new (Ptr) U(args...); - } - - template - U *new_construct(U *Class, Args&&... args) { - void *Ptr = do_allocate(sizeof(U), std::alignment_of::value); - return new (Ptr) U(args...); - } - - uintptr_t GetSlabBase() const { return Begin; } - uint64_t GetSlabSize() const { return Size; } - uint64_t GetFreePages() const { return FreePages; } - - private: - void *do_allocate(std::size_t bytes, std::size_t alignment) override { - std::scoped_lock lk{AllocationMutex}; - - size_t NumberPages = FEXCore::AlignUp(bytes, FEXCore::Utils::FEX_PAGE_SIZE) / FEXCore::Utils::FEX_PAGE_SIZE; - - uintptr_t AllocatedOffset{}; - - try_again: - for (uintptr_t CurrentPage = LastAllocatedPageOffset; CurrentPage <= (Size - NumberPages);) { - size_t Remaining = NumberPages; - - while (Remaining) { - if (UsedPages[CurrentPage + Remaining - 1]) { - // Has an intersecting range - break; - } - --Remaining; - } - - if (Remaining) { - // Didn't find an allocation range - CurrentPage += Remaining; - } - else { - // We have a range to allocate - AllocatedOffset = CurrentPage; - break; - } - } - - if (!AllocatedOffset && LastAllocatedPageOffset != 0) { - // Try again but starting from the beginning - LastAllocatedPageOffset = 0; - // Using goto so we don't have recursive mutex shenanigans - goto try_again; - } - - // Allocated offset must be valid or zero at this point - if (AllocatedOffset) { - // Map the range as no longer available - for (size_t i = 0; i < NumberPages; ++i) { - UsedPages.Set(AllocatedOffset + i); - } - - LastAllocatedPageOffset = AllocatedOffset + NumberPages; - - // Now convert this base page to a pointer and return it - return reinterpret_cast(Begin + AllocatedOffset * FEXCore::Utils::FEX_PAGE_SIZE); - } +private: + void* do_allocate(std::size_t bytes, std::size_t alignment) override { + size_t PreviousAligned = FEXCore::AlignUp(LastAllocation, alignment); + size_t NewOffset = PreviousAligned + bytes; + if (NewOffset > Size) { return nullptr; } - void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override { - std::scoped_lock lk{AllocationMutex}; + LastAllocation = NewOffset; - uintptr_t PageOffset = (reinterpret_cast(p) - Begin) / FEXCore::Utils::FEX_PAGE_SIZE; - size_t NumPages = FEXCore::AlignUp(bytes, FEXCore::Utils::FEX_PAGE_SIZE) / FEXCore::Utils::FEX_PAGE_SIZE; + return reinterpret_cast(Begin + PreviousAligned); + } - // Walk the allocation list and deallocate - uint64_t FreedPages{}; - for (size_t i = 0; i < NumPages; ++i) { - FreedPages += UsedPages.TestAndClear(PageOffset + i) ? 1 : 0; - } - FreePages += FreedPages; + void do_deallocate(void*, std::size_t, std::size_t) override { + // Do nothing + } + + bool do_is_equal(const fex_pmr::memory_resource& other) const noexcept override { + // Only if the allocator pointers are the same are they equal + if (this == &other) { + return true; + } + // We don't share state with another allocator so we can't share anything + return false; + } + + uintptr_t Begin; + size_t Size; + size_t LastAllocation {}; +}; + +class IntrusiveArenaAllocator final : public fex_pmr::memory_resource { +public: + IntrusiveArenaAllocator(void* Ptr, size_t _Size) + : Begin {reinterpret_cast(Ptr)} + , Size {_Size} { + uint64_t NumberOfPages = _Size / FEXCore::Utils::FEX_PAGE_SIZE; + uint64_t UsedBits = + FEXCore::AlignUp(sizeof(IntrusiveArenaAllocator) + Size / FEXCore::Utils::FEX_PAGE_SIZE / 8, FEXCore::Utils::FEX_PAGE_SIZE); + for (size_t i = 0; i < UsedBits; ++i) { + UsedPages.Set(i); } - bool do_is_equal(const fex_pmr::memory_resource& other) const noexcept override { - // Only if the allocator pointers are the same are they equal - if (this == &other) { - return true; + FreePages = NumberOfPages - UsedBits; + } + + template + U* new_construct(Args&&... args) { + void* Ptr = do_allocate(sizeof(U), std::alignment_of::value); + return new (Ptr) U(args...); + } + + template + U* new_construct(U* Class, Args&&... args) { + void* Ptr = do_allocate(sizeof(U), std::alignment_of::value); + return new (Ptr) U(args...); + } + + uintptr_t GetSlabBase() const { + return Begin; + } + uint64_t GetSlabSize() const { + return Size; + } + uint64_t GetFreePages() const { + return FreePages; + } + +private: + void* do_allocate(std::size_t bytes, std::size_t alignment) override { + std::scoped_lock lk {AllocationMutex}; + + size_t NumberPages = FEXCore::AlignUp(bytes, FEXCore::Utils::FEX_PAGE_SIZE) / FEXCore::Utils::FEX_PAGE_SIZE; + + uintptr_t AllocatedOffset {}; + +try_again: + for (uintptr_t CurrentPage = LastAllocatedPageOffset; CurrentPage <= (Size - NumberPages);) { + size_t Remaining = NumberPages; + + while (Remaining) { + if (UsedPages[CurrentPage + Remaining - 1]) { + // Has an intersecting range + break; + } + --Remaining; + } + + if (Remaining) { + // Didn't find an allocation range + CurrentPage += Remaining; + } else { + // We have a range to allocate + AllocatedOffset = CurrentPage; + break; } - // We don't share state with another allocator so we can't share anything - return false; } - uintptr_t Begin; - size_t Size; - uint64_t FreePages{}; - size_t LastAllocatedPageOffset{}; - std::mutex AllocationMutex{}; - // For up to 64GB regions this will require up to 2MB tracking - // Needs to be the last element - FEXCore::FlexBitSet UsedPages; - }; -} + if (!AllocatedOffset && LastAllocatedPageOffset != 0) { + // Try again but starting from the beginning + LastAllocatedPageOffset = 0; + // Using goto so we don't have recursive mutex shenanigans + goto try_again; + } + + // Allocated offset must be valid or zero at this point + if (AllocatedOffset) { + // Map the range as no longer available + for (size_t i = 0; i < NumberPages; ++i) { + UsedPages.Set(AllocatedOffset + i); + } + + LastAllocatedPageOffset = AllocatedOffset + NumberPages; + + // Now convert this base page to a pointer and return it + return reinterpret_cast(Begin + AllocatedOffset * FEXCore::Utils::FEX_PAGE_SIZE); + } + + return nullptr; + } + + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override { + std::scoped_lock lk {AllocationMutex}; + + uintptr_t PageOffset = (reinterpret_cast(p) - Begin) / FEXCore::Utils::FEX_PAGE_SIZE; + size_t NumPages = FEXCore::AlignUp(bytes, FEXCore::Utils::FEX_PAGE_SIZE) / FEXCore::Utils::FEX_PAGE_SIZE; + + // Walk the allocation list and deallocate + uint64_t FreedPages {}; + for (size_t i = 0; i < NumPages; ++i) { + FreedPages += UsedPages.TestAndClear(PageOffset + i) ? 1 : 0; + } + FreePages += FreedPages; + } + + bool do_is_equal(const fex_pmr::memory_resource& other) const noexcept override { + // Only if the allocator pointers are the same are they equal + if (this == &other) { + return true; + } + // We don't share state with another allocator so we can't share anything + return false; + } + + uintptr_t Begin; + size_t Size; + uint64_t FreePages {}; + size_t LastAllocatedPageOffset {}; + std::mutex AllocationMutex {}; + // For up to 64GB regions this will require up to 2MB tracking + // Needs to be the last element + FEXCore::FlexBitSet UsedPages; +}; +} // namespace Alloc diff --git a/FEXCore/Source/Utils/AllocatorOverride.cpp b/FEXCore/Source/Utils/AllocatorOverride.cpp index 410af5542..63ed66eed 100644 --- a/FEXCore/Source/Utils/AllocatorOverride.cpp +++ b/FEXCore/Source/Utils/AllocatorOverride.cpp @@ -11,147 +11,147 @@ #include extern "C" { - // The majority of FEX internal code should avoid using the glibc allocator. To ensure glibc allocations don't accidentally slip - // in, FEX overrides these glibc functions with faulting variants. - // - // A notable exception is thunks, which should still use glibc allocations and avoid using `fextl::` namespace. - // - // Other minor exceptions throughout FEX use the `YesIKnowImNotSupposedToUseTheGlibcAllocator` helper to temporarily disable faulting. +// The majority of FEX internal code should avoid using the glibc allocator. To ensure glibc allocations don't accidentally slip +// in, FEX overrides these glibc functions with faulting variants. +// +// A notable exception is thunks, which should still use glibc allocations and avoid using `fextl::` namespace. +// +// Other minor exceptions throughout FEX use the `YesIKnowImNotSupposedToUseTheGlibcAllocator` helper to temporarily disable faulting. #define GLIBC_ALIAS_FUNCTION(func) __attribute__((alias(#func), visibility("default"))) - extern void *__libc_calloc(size_t, size_t); - void *calloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_calloc); +extern void* __libc_calloc(size_t, size_t); +void* calloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_calloc); - extern void __libc_free(void*); - void free(void*) GLIBC_ALIAS_FUNCTION(fault_free); +extern void __libc_free(void*); +void free(void*) GLIBC_ALIAS_FUNCTION(fault_free); - extern void *__libc_malloc(size_t); - void *malloc(size_t) GLIBC_ALIAS_FUNCTION(fault_malloc); +extern void* __libc_malloc(size_t); +void* malloc(size_t) GLIBC_ALIAS_FUNCTION(fault_malloc); - extern void *__libc_memalign(size_t, size_t); - void *memalign(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_memalign); +extern void* __libc_memalign(size_t, size_t); +void* memalign(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_memalign); - extern void *__libc_realloc(void*, size_t); - void *realloc(void*, size_t) GLIBC_ALIAS_FUNCTION(fault_realloc); +extern void* __libc_realloc(void*, size_t); +void* realloc(void*, size_t) GLIBC_ALIAS_FUNCTION(fault_realloc); - extern void *__libc_valloc(size_t); - void *valloc(size_t) GLIBC_ALIAS_FUNCTION(fault_valloc); +extern void* __libc_valloc(size_t); +void* valloc(size_t) GLIBC_ALIAS_FUNCTION(fault_valloc); - extern int __posix_memalign(void **, size_t, size_t); - int posix_memalign(void **, size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_posix_memalign); +extern int __posix_memalign(void**, size_t, size_t); +int posix_memalign(void**, size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_posix_memalign); - extern size_t __malloc_usable_size(void*); - size_t malloc_usable_size(void*) GLIBC_ALIAS_FUNCTION(fault_malloc_usable_size); +extern size_t __malloc_usable_size(void*); +size_t malloc_usable_size(void*) GLIBC_ALIAS_FUNCTION(fault_malloc_usable_size); - // Reuse __libc_memalign - void *aligned_alloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_aligned_alloc); +// Reuse __libc_memalign +void* aligned_alloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_aligned_alloc); } namespace FEXCore::Allocator { - // Enable or disable allocation faulting globally. - static bool GlobalEvaluate{}; +// Enable or disable allocation faulting globally. +static bool GlobalEvaluate {}; - // Enable or disable allocation faulting per-thread. - static thread_local uint64_t SkipEvalForThread{}; +// Enable or disable allocation faulting per-thread. +static thread_local uint64_t SkipEvalForThread {}; - // Internal memory allocation hooks to allow non-faulting allocations through. - auto calloc_ptr = __libc_calloc; - auto free_ptr = __libc_free; - auto malloc_ptr = __libc_malloc; - auto memalign_ptr = __libc_memalign; - auto realloc_ptr = __libc_realloc; - auto valloc_ptr = __libc_valloc; - auto posix_memalign_ptr = ::posix_memalign; - auto malloc_usable_size_ptr = ::malloc_usable_size; - auto aligned_alloc_ptr = __libc_memalign; +// Internal memory allocation hooks to allow non-faulting allocations through. +auto calloc_ptr = __libc_calloc; +auto free_ptr = __libc_free; +auto malloc_ptr = __libc_malloc; +auto memalign_ptr = __libc_memalign; +auto realloc_ptr = __libc_realloc; +auto valloc_ptr = __libc_valloc; +auto posix_memalign_ptr = ::posix_memalign; +auto malloc_usable_size_ptr = ::malloc_usable_size; +auto aligned_alloc_ptr = __libc_memalign; - // Constructor for per-thread allocation faulting check. - YesIKnowImNotSupposedToUseTheGlibcAllocator::YesIKnowImNotSupposedToUseTheGlibcAllocator() { - ++SkipEvalForThread; - } - - // Destructor for per-thread allocation faulting check. - YesIKnowImNotSupposedToUseTheGlibcAllocator::~YesIKnowImNotSupposedToUseTheGlibcAllocator() { - --SkipEvalForThread; - } - - // Hard disabling of per-thread allocation fault checking. - // No coming back from this, used on thread destruction. - FEX_DEFAULT_VISIBILITY void YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable() { - // Just set it to half of its maximum value so it never wraps back around. - SkipEvalForThread = std::numeric_limits::max() / 2; - } - - // Enable global fault checking. - void SetupFaultEvaluate() { - GlobalEvaluate = true; - } - - // Disable global fault checking. - void ClearFaultEvaluate() { - GlobalEvaluate = false; - } - - // Evaluate if a glibc hooked allocation should fault. - void EvaluateReturnAddress(void* Return) { - if (!GlobalEvaluate) { - // Fault evaluation disabled globally. - return; - } - - if (SkipEvalForThread) { - // Fault evaluation currently disabled for this thread. - return; - } - - // We don't know where we are when allocating. Make sure to be safe and generate the string on the stack. - // Print an error message to let a developer know that an allocation faulted. - char Tmp[512]; - auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast(Return)); - Tmp[Res.size] = 0; - write(STDERR_FILENO, Tmp, Res.size); - - // Trap the execution to stop FEX in its tracks. - FEX_TRAP_EXECUTION; - } +// Constructor for per-thread allocation faulting check. +YesIKnowImNotSupposedToUseTheGlibcAllocator::YesIKnowImNotSupposedToUseTheGlibcAllocator() { + ++SkipEvalForThread; } +// Destructor for per-thread allocation faulting check. +YesIKnowImNotSupposedToUseTheGlibcAllocator::~YesIKnowImNotSupposedToUseTheGlibcAllocator() { + --SkipEvalForThread; +} + +// Hard disabling of per-thread allocation fault checking. +// No coming back from this, used on thread destruction. +FEX_DEFAULT_VISIBILITY void YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable() { + // Just set it to half of its maximum value so it never wraps back around. + SkipEvalForThread = std::numeric_limits::max() / 2; +} + +// Enable global fault checking. +void SetupFaultEvaluate() { + GlobalEvaluate = true; +} + +// Disable global fault checking. +void ClearFaultEvaluate() { + GlobalEvaluate = false; +} + +// Evaluate if a glibc hooked allocation should fault. +void EvaluateReturnAddress(void* Return) { + if (!GlobalEvaluate) { + // Fault evaluation disabled globally. + return; + } + + if (SkipEvalForThread) { + // Fault evaluation currently disabled for this thread. + return; + } + + // We don't know where we are when allocating. Make sure to be safe and generate the string on the stack. + // Print an error message to let a developer know that an allocation faulted. + char Tmp[512]; + auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast(Return)); + Tmp[Res.size] = 0; + write(STDERR_FILENO, Tmp, Res.size); + + // Trap the execution to stop FEX in its tracks. + FEX_TRAP_EXECUTION; +} +} // namespace FEXCore::Allocator + extern "C" { - // These are the glibc allocator override symbols. - // These will override the glibc allocators and then check if the allocation should fault. - void *fault_calloc(size_t n, size_t size) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::calloc_ptr(n, size); - } - void fault_free(void* ptr) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - FEXCore::Allocator::free_ptr(ptr); - } - void *fault_malloc(size_t size) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::malloc_ptr(size); - } - void *fault_memalign(size_t align, size_t s) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::memalign_ptr(align, s); - } - void *fault_realloc(void* ptr, size_t size) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::realloc_ptr(ptr, size); - } - void *fault_valloc(size_t size) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::valloc_ptr(size); - } - int fault_posix_memalign(void ** r, size_t a, size_t s) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::posix_memalign_ptr(r, a, s); - } - size_t fault_malloc_usable_size(void *ptr) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::malloc_usable_size_ptr(ptr); - } - void *fault_aligned_alloc(size_t a, size_t s) { - FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); - return FEXCore::Allocator::aligned_alloc_ptr(a, s); - } +// These are the glibc allocator override symbols. +// These will override the glibc allocators and then check if the allocation should fault. +void* fault_calloc(size_t n, size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::calloc_ptr(n, size); +} +void fault_free(void* ptr) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + FEXCore::Allocator::free_ptr(ptr); +} +void* fault_malloc(size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::malloc_ptr(size); +} +void* fault_memalign(size_t align, size_t s) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::memalign_ptr(align, s); +} +void* fault_realloc(void* ptr, size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::realloc_ptr(ptr, size); +} +void* fault_valloc(size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::valloc_ptr(size); +} +int fault_posix_memalign(void** r, size_t a, size_t s) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::posix_memalign_ptr(r, a, s); +} +size_t fault_malloc_usable_size(void* ptr) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::malloc_usable_size_ptr(ptr); +} +void* fault_aligned_alloc(size_t a, size_t s) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr(__builtin_return_address(0))); + return FEXCore::Allocator::aligned_alloc_ptr(a, s); +} } diff --git a/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp b/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp index 4bc40275a..10013d3aa 100644 --- a/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp +++ b/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp @@ -16,9 +16,9 @@ namespace FEXCore::ArchHelpers::Arm64 { FEXCORE_TELEMETRY_STATIC_INIT(SplitLock, TYPE_HAS_SPLIT_LOCKS); FEXCORE_TELEMETRY_STATIC_INIT(SplitLock16B, TYPE_16BYTE_SPLIT); -FEXCORE_TELEMETRY_STATIC_INIT(Cas16Tear, TYPE_CAS_16BIT_TEAR); -FEXCORE_TELEMETRY_STATIC_INIT(Cas32Tear, TYPE_CAS_32BIT_TEAR); -FEXCORE_TELEMETRY_STATIC_INIT(Cas64Tear, TYPE_CAS_64BIT_TEAR); +FEXCORE_TELEMETRY_STATIC_INIT(Cas16Tear, TYPE_CAS_16BIT_TEAR); +FEXCORE_TELEMETRY_STATIC_INIT(Cas32Tear, TYPE_CAS_32BIT_TEAR); +FEXCORE_TELEMETRY_STATIC_INIT(Cas64Tear, TYPE_CAS_64BIT_TEAR); FEXCORE_TELEMETRY_STATIC_INIT(Cas128Tear, TYPE_CAS_128BIT_TEAR); static void ClearICache(void* Begin, std::size_t Length) { @@ -26,20 +26,19 @@ static void ClearICache(void* Begin, std::size_t Length) { } static __uint128_t LoadAcquire128(uint64_t Addr) { - __uint128_t Result{}; + __uint128_t Result {}; uint64_t Lower; uint64_t Upper; // This specifically avoids using std::atomic<__uint128_t> // std::atomic helper does a ldaxp + stxp pair that crashes when the page is only mapped readable __asm volatile( -R"( + R"( ldaxp %[ResultLower], %[ResultUpper], [%[Addr]]; clrex; )" - : [ResultLower] "=r" (Lower) - , [ResultUpper] "=r" (Upper) - : [Addr] "r" (Addr) - : "memory"); + : [ResultLower] "=r"(Lower), [ResultUpper] "=r"(Upper) + : [Addr] "r"(Addr) + : "memory"); Result = Upper; Result <<= 64; Result |= Lower; @@ -47,32 +46,32 @@ R"( } static uint64_t LoadAcquire64(uint64_t Addr) { - std::atomic *Atom = reinterpret_cast*>(Addr); + std::atomic* Atom = reinterpret_cast*>(Addr); return Atom->load(std::memory_order_acquire); } -static bool StoreCAS64(uint64_t &Expected, uint64_t Val, uint64_t Addr) { - std::atomic *Atom = reinterpret_cast*>(Addr); +static bool StoreCAS64(uint64_t& Expected, uint64_t Val, uint64_t Addr) { + std::atomic* Atom = reinterpret_cast*>(Addr); return Atom->compare_exchange_strong(Expected, Val); } static uint32_t LoadAcquire32(uint64_t Addr) { - std::atomic *Atom = reinterpret_cast*>(Addr); + std::atomic* Atom = reinterpret_cast*>(Addr); return Atom->load(std::memory_order_acquire); } -static bool StoreCAS32(uint32_t &Expected, uint32_t Val, uint64_t Addr) { - std::atomic *Atom = reinterpret_cast*>(Addr); +static bool StoreCAS32(uint32_t& Expected, uint32_t Val, uint64_t Addr) { + std::atomic* Atom = reinterpret_cast*>(Addr); return Atom->compare_exchange_strong(Expected, Val); } static uint8_t LoadAcquire8(uint64_t Addr) { - std::atomic *Atom = reinterpret_cast*>(Addr); + std::atomic* Atom = reinterpret_cast*>(Addr); return Atom->load(std::memory_order_acquire); } -static bool StoreCAS8(uint8_t &Expected, uint8_t Val, uint64_t Addr) { - std::atomic *Atom = reinterpret_cast*>(Addr); +static bool StoreCAS8(uint8_t& Expected, uint8_t Val, uint64_t Addr) { + std::atomic* Atom = reinterpret_cast*>(Addr); return Atom->compare_exchange_strong(Expected, Val); } @@ -82,8 +81,8 @@ uint16_t DoLoad16(uint64_t Addr) { // Address crosses over 16byte or 64byte threshold // Needs two loads uint64_t AddrUpper = Addr + 1; - uint8_t ActualUpper{}; - uint8_t ActualLower{}; + uint8_t ActualUpper {}; + uint8_t ActualLower {}; // Careful ordering here ActualUpper = LoadAcquire8(AddrUpper); ActualLower = LoadAcquire8(Addr); @@ -92,8 +91,7 @@ uint16_t DoLoad16(uint64_t Addr) { Result <<= 8; Result |= ActualLower; return Result; - } - else { + } else { AlignmentMask = 0b111; if ((Addr & AlignmentMask) == 7) { // Crosses 8byte boundary @@ -107,8 +105,7 @@ uint16_t DoLoad16(uint64_t Addr) { // Zexts the result uint16_t Result = TmpResult >> (Alignment * 8); return Result; - } - else { + } else { AlignmentMask = 0b11; if ((Addr & AlignmentMask) == 3) { // Crosses 4byte boundary @@ -116,21 +113,20 @@ uint16_t DoLoad16(uint64_t Addr) { uint64_t Alignment = Addr & AlignmentMask; Addr &= ~AlignmentMask; - std::atomic *Atomic = reinterpret_cast*>(Addr); + std::atomic* Atomic = reinterpret_cast*>(Addr); uint64_t TmpResult = Atomic->load(); // Zexts the result uint16_t Result = TmpResult >> (Alignment * 8); return Result; - } - else { + } else { // Fits within 4byte boundary // Only needs 32bit Load // Only alignment offset will be 1 here uint64_t Alignment = Addr & AlignmentMask; Addr &= ~AlignmentMask; - std::atomic *Atomic = reinterpret_cast*>(Addr); + std::atomic* Atomic = reinterpret_cast*>(Addr); uint32_t TmpResult = Atomic->load(); // Zexts the result @@ -159,8 +155,7 @@ uint32_t DoLoad32(uint64_t Addr) { Result <<= 32; Result |= ActualLower; return Result >> (Alignment * 8); - } - else { + } else { AlignmentMask = 0b111; if ((Addr & AlignmentMask) >= 5) { // Crosses 8byte boundary @@ -172,15 +167,14 @@ uint32_t DoLoad32(uint64_t Addr) { __uint128_t TmpResult = LoadAcquire128(Addr); return TmpResult >> (Alignment * 8); - } - else { + } else { // Fits within 8byte boundary // Only needs 64bit CAS // Alignments can be [1,5) uint64_t Alignment = Addr & AlignmentMask; Addr &= ~AlignmentMask; - std::atomic *Atomic = reinterpret_cast*>(Addr); + std::atomic* Atomic = reinterpret_cast*>(Addr); uint64_t TmpResult = Atomic->load(); return TmpResult >> (Alignment * 8); @@ -197,8 +191,8 @@ uint64_t DoLoad64(uint64_t Addr) { // Crosses a 16byte boundary // Needs two 8 byte loads - uint64_t ActualUpper{}; - uint64_t ActualLower{}; + uint64_t ActualUpper {}; + uint64_t ActualLower {}; // Careful ordering here ActualUpper = LoadAcquire64(AddrUpper); ActualLower = LoadAcquire64(Addr); @@ -207,8 +201,7 @@ uint64_t DoLoad64(uint64_t Addr) { Result <<= 64; Result |= ActualLower; return Result >> (Alignment * 8); - } - else { + } else { // Fits within a 16byte region uint64_t Alignment = Addr & AlignmentMask; Addr &= ~AlignmentMask; @@ -235,17 +228,18 @@ std::pair DoLoad128(uint64_t Addr) { } Bytes; }; - AlignedData *Data = reinterpret_cast(alloca(sizeof(AlignedData))); + AlignedData* Data = reinterpret_cast(alloca(sizeof(AlignedData))); Data->Large.Upper = LoadAcquire128(AddrUpper); Data->Large.Lower = LoadAcquire128(Addr); - uint64_t ResultLower{}, ResultUpper{}; + uint64_t ResultLower {}, ResultUpper {}; memcpy(&ResultLower, &Data->Bytes.Data[Alignment], sizeof(uint64_t)); memcpy(&ResultUpper, &Data->Bytes.Data[Alignment + sizeof(uint64_t)], sizeof(uint64_t)); return {ResultLower, ResultUpper}; } -static bool RunCASPAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg1, uint32_t DesiredReg2, uint32_t ExpectedReg1, uint32_t ExpectedReg2, uint32_t AddressReg) { +static bool RunCASPAL(uint64_t* GPRs, uint32_t Size, uint32_t DesiredReg1, uint32_t DesiredReg2, uint32_t ExpectedReg1, + uint32_t ExpectedReg2, uint32_t AddressReg) { if (Size == 0) { // 32bit uint64_t Addr = GPRs[AddressReg]; @@ -281,8 +275,8 @@ static bool RunCASPAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg1, uint3 __uint128_t Mask = ~0ULL; Mask <<= Alignment * 8; __uint128_t NegMask = ~Mask; - __uint128_t TmpExpected{}; - __uint128_t TmpDesired{}; + __uint128_t TmpExpected {}; + __uint128_t TmpDesired {}; __uint128_t Desired = DesiredUpper; Desired <<= 32; @@ -320,8 +314,7 @@ static bool RunCASPAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg1, uint3 if (StoreCAS64(TmpExpectedLower, TmpDesiredLower, Addr)) { // Stored successfully return true; - } - else { + } else { // CAS managed to tear, we can't really solve this // Continue down the path to let the guest know values weren't expected FEXCORE_TELEMETRY_SET(Cas128Tear, 1); @@ -331,8 +324,7 @@ static bool RunCASPAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg1, uint3 TmpExpected = TmpExpectedUpper; TmpExpected <<= 64; TmpExpected |= TmpExpectedLower; - } - else { + } else { // Mismatch up front TmpExpected = TmpActual; } @@ -364,18 +356,17 @@ static bool RunCASPAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg1, uint3 GPRs[ExpectedReg2] = FailedResult >> 32; return true; } - } - else { + } else { // Fits within a 16byte region uint64_t Alignment = Addr & 0b1111; Addr &= ~0b1111ULL; - std::atomic<__uint128_t> *Atomic128 = reinterpret_cast*>(Addr); + std::atomic<__uint128_t>* Atomic128 = reinterpret_cast*>(Addr); __uint128_t Mask = ~0ULL; Mask <<= Alignment * 8; __uint128_t NegMask = ~Mask; - __uint128_t TmpExpected{}; - __uint128_t TmpDesired{}; + __uint128_t TmpExpected {}; + __uint128_t TmpDesired {}; __uint128_t Desired = (uint64_t)DesiredUpper << 32 | DesiredLower; Desired <<= Alignment * 8; @@ -399,8 +390,7 @@ static bool RunCASPAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg1, uint3 if (CASResult) { // Successful, so we are done return true; - } - else { + } else { // Not successful // Now we need to check the results to see if we need to try again __uint128_t FailedResultOurBits = TmpExpected & Mask; @@ -425,7 +415,7 @@ static bool RunCASPAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg1, uint3 return false; } -bool HandleCASPAL(uint32_t Instr, uint64_t *GPRs) { +bool HandleCASPAL(uint32_t Instr, uint64_t* GPRs) { uint32_t Size = (Instr >> 30) & 1; uint32_t DesiredReg1 = Instr & 0b11111; @@ -437,7 +427,7 @@ bool HandleCASPAL(uint32_t Instr, uint64_t *GPRs) { return RunCASPAL(GPRs, Size, DesiredReg1, DesiredReg2, ExpectedReg1, ExpectedReg2, AddressReg); } -uint64_t HandleCASPAL_ARMv8(uint32_t Instr, uintptr_t ProgramCounter, uint64_t *GPRs) { +uint64_t HandleCASPAL_ARMv8(uint32_t Instr, uintptr_t ProgramCounter, uint64_t* GPRs) { // caspair // [1] ldaxp(TMP2.W(), TMP3.W(), MemOperand(MemSrc)); <-- DataReg & AddrReg // [2] cmp(TMP2.W(), Expected.first.W()); <-- ExpectedReg1 @@ -452,20 +442,20 @@ uint64_t HandleCASPAL_ARMv8(uint32_t Instr, uintptr_t ProgramCounter, uint64_t * // [11] mov(Dst.second.W(), TMP3.W()); // [12] clrex(); - uint32_t *PC = (uint32_t*)ProgramCounter; + uint32_t* PC = (uint32_t*)ProgramCounter; uint32_t Size = (Instr >> 30) & 1; uint32_t AddrReg = (Instr >> 5) & 0x1F; uint32_t DataReg = Instr & 0x1F; uint32_t DataReg2 = (Instr >> 10) & 0x1F; - uint32_t ExpectedReg1{}; - uint32_t ExpectedReg2{}; + uint32_t ExpectedReg1 {}; + uint32_t ExpectedReg2 {}; - uint32_t DesiredReg1{}; - uint32_t DesiredReg2{}; + uint32_t DesiredReg1 {}; + uint32_t DesiredReg2 {}; - if(Size == 1) { + if (Size == 1) { // 64-bit pair happens on paranoid vector loads // [1] ldaxp(TMP1, TMP2, MemSrc); // [2] clrex(); @@ -476,8 +466,7 @@ uint64_t HandleCASPAL_ARMv8(uint32_t Instr, uintptr_t ProgramCounter, uint64_t * // [3] cbnz(TMP3, &B); // < Overwritten with DMB if (DataReg == 31) { - } - else { + } else { uint32_t NextInstr = PC[1]; if ((NextInstr & ArchHelpers::Arm64::CLREX_MASK) == ArchHelpers::Arm64::CLREX_INST) { uint64_t Addr = GPRs[AddrReg]; @@ -498,25 +487,25 @@ uint64_t HandleCASPAL_ARMv8(uint32_t Instr, uintptr_t ProgramCounter, uint64_t * return 0; } - //Only 32-bit pairs - for(int i = 1; i < 10; i++) { + // Only 32-bit pairs + for (int i = 1; i < 10; i++) { uint32_t NextInstr = PC[i]; if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_INST || (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_SHIFT_INST) { - ExpectedReg1 = GetRmReg(NextInstr); + ExpectedReg1 = GetRmReg(NextInstr); } else if ((NextInstr & ArchHelpers::Arm64::CCMP_MASK) == ArchHelpers::Arm64::CCMP_INST) { - ExpectedReg2 = GetRmReg(NextInstr); + ExpectedReg2 = GetRmReg(NextInstr); } else if ((NextInstr & ArchHelpers::Arm64::STLXP_MASK) == ArchHelpers::Arm64::STLXP_INST) { - DesiredReg1 = (NextInstr & 0x1F); - DesiredReg2 = (NextInstr >> 10) & 0x1F; + DesiredReg1 = (NextInstr & 0x1F); + DesiredReg2 = (NextInstr >> 10) & 0x1F; } } - //mov expected into the temp registers used by JIT + // mov expected into the temp registers used by JIT GPRs[DataReg] = GPRs[ExpectedReg1]; GPRs[DataReg2] = GPRs[ExpectedReg2]; - if(RunCASPAL(GPRs, Size, DesiredReg1, DesiredReg2, DataReg, DataReg2, AddrReg)) { + if (RunCASPAL(GPRs, Size, DesiredReg1, DesiredReg2, DataReg, DataReg2, AddrReg)) { return 9 * sizeof(uint32_t); // skip to mov + clrex } else { return 0; @@ -524,12 +513,12 @@ uint64_t HandleCASPAL_ARMv8(uint32_t Instr, uintptr_t ProgramCounter, uint64_t * } static bool HandleAtomicVectorStore(uint32_t Instr, uintptr_t ProgramCounter) { - uint32_t *PC = (uint32_t*)ProgramCounter; + uint32_t* PC = (uint32_t*)ProgramCounter; uint32_t Size = (Instr >> 30) & 1; uint32_t DataReg = Instr & 0x1F; - if(Size == 1) { + if (Size == 1) { // 64-bit pair happens on paranoid vector stores // [0] ldaxp(xzr, TMP3, MemSrc); // <- Can hit SIGBUS. Overwritten with DMB // [1] stlxp(TMP3, TMP1, TMP2, MemSrc); // <- Can also hit SIGBUS @@ -539,12 +528,7 @@ static bool HandleAtomicVectorStore(uint32_t Instr, uintptr_t ProgramCounter) { uint32_t AddrReg = (NextInstr >> 5) & 0x1F; DataReg = NextInstr & 0x1F; uint32_t DataReg2 = (NextInstr >> 10) & 0x1F; - uint32_t STP = - (0b10 << 30) | - (0b101001000000000 << 15) | - (DataReg2 << 10) | - (AddrReg << 5) | - DataReg; + uint32_t STP = (0b10 << 30) | (0b101001000000000 << 15) | (DataReg2 << 10) | (AddrReg << 5) | DataReg; PC[0] = DMB; PC[1] = STP; @@ -558,19 +542,14 @@ static bool HandleAtomicVectorStore(uint32_t Instr, uintptr_t ProgramCounter) { return false; } -template +template using CASExpectedFn = T (*)(T Src, T Expected); -template +template using CASDesiredFn = T (*)(T Src, T Desired); template -static -uint16_t DoCAS16( - uint16_t DesiredSrc, - uint16_t ExpectedSrc, - uint64_t Addr, - CASExpectedFn ExpectedFunction, - CASDesiredFn DesiredFunction) { +static uint16_t DoCAS16(uint16_t DesiredSrc, uint16_t ExpectedSrc, uint64_t Addr, CASExpectedFn ExpectedFunction, + CASDesiredFn DesiredFunction) { if ((Addr & 63) == 63) { FEXCORE_TELEMETRY_SET(SplitLock, 1); @@ -586,8 +565,8 @@ uint16_t DoCAS16( uint64_t AddrUpper = Addr + 1; while (1) { - uint8_t ActualUpper{}; - uint8_t ActualLower{}; + uint8_t ActualUpper {}; + uint8_t ActualLower {}; // Careful ordering here ActualUpper = LoadAcquire8(AddrUpper); ActualLower = LoadAcquire8(Addr); @@ -605,14 +584,12 @@ uint16_t DoCAS16( uint8_t ExpectedUpper = Expected >> 8; bool Tear = false; - if (ActualUpper == ExpectedUpper && - ActualLower == ExpectedLower) { + if (ActualUpper == ExpectedUpper && ActualLower == ExpectedLower) { if (StoreCAS8(ExpectedUpper, DesiredUpper, AddrUpper)) { if (StoreCAS8(ExpectedLower, DesiredLower, Addr)) { // Stored successfully return Expected; - } - else { + } else { // CAS managed to tear, we can't really solve this // Continue down the path to let the guest know values weren't expected Tear = true; @@ -635,19 +612,16 @@ uint16_t DoCAS16( // If we are retrying and tearing then we can't do anything here // XXX: Resolve with TME return FailedResult; - } - else { + } else { // We can retry safely } - } - else { + } else { // Without Retry (CAS) then we have failed regardless of tear // CAS failed but handled successfully return FailedResult; } } - } - else { + } else { AlignmentMask = 0b111; if ((Addr & AlignmentMask) == 7) { // Crosses 8byte boundary @@ -655,13 +629,13 @@ uint16_t DoCAS16( // Fits within a 16byte region uint64_t Alignment = Addr & 0b1111; Addr &= ~0b1111ULL; - std::atomic<__uint128_t> *Atomic128 = reinterpret_cast*>(Addr); + std::atomic<__uint128_t>* Atomic128 = reinterpret_cast*>(Addr); __uint128_t Mask = 0xFFFF; Mask <<= Alignment * 8; __uint128_t NegMask = ~Mask; - __uint128_t TmpExpected{}; - __uint128_t TmpDesired{}; + __uint128_t TmpExpected {}; + __uint128_t TmpDesired {}; while (1) { TmpExpected = Atomic128->load(); @@ -685,8 +659,7 @@ uint16_t DoCAS16( if (CASResult) { // Successful, so we are done return Expected >> (Alignment * 8); - } - else { + } else { if constexpr (Retry) { // If we failed but we have enabled retry then just retry without checking results // CAS can't retry but atomic memory ops need to retry until passing @@ -710,8 +683,7 @@ uint16_t DoCAS16( return FailedResult; } } - } - else { + } else { AlignmentMask = 0b11; if ((Addr & AlignmentMask) == 3) { // Crosses 4byte boundary @@ -724,10 +696,10 @@ uint16_t DoCAS16( uint64_t NegMask = ~Mask; - uint64_t TmpExpected{}; - uint64_t TmpDesired{}; + uint64_t TmpExpected {}; + uint64_t TmpDesired {}; - std::atomic *Atomic = reinterpret_cast*>(Addr); + std::atomic* Atomic = reinterpret_cast*>(Addr); while (1) { TmpExpected = Atomic->load(); @@ -750,8 +722,7 @@ uint16_t DoCAS16( if (CASResult) { // Successful, so we are done return Expected >> (Alignment * 8); - } - else { + } else { if constexpr (Retry) { // If we failed but we have enabled retry then just retry without checking results // CAS can't retry but atomic memory ops need to retry until passing @@ -776,8 +747,7 @@ uint16_t DoCAS16( return FailedResult; } } - } - else { + } else { // Fits within 4byte boundary // Only needs 32bit CAS // Only alignment offset will be 1 here @@ -789,10 +759,10 @@ uint16_t DoCAS16( uint32_t NegMask = ~Mask; - uint32_t TmpExpected{}; - uint32_t TmpDesired{}; + uint32_t TmpExpected {}; + uint32_t TmpDesired {}; - std::atomic *Atomic = reinterpret_cast*>(Addr); + std::atomic* Atomic = reinterpret_cast*>(Addr); while (1) { TmpExpected = Atomic->load(); @@ -816,8 +786,7 @@ uint16_t DoCAS16( if (CASResult) { // Successful, so we are done return Expected >> (Alignment * 8); - } - else { + } else { if constexpr (Retry) { // If we failed but we have enabled retry then just retry without checking results // CAS can't retry but atomic memory ops need to retry until passing @@ -848,13 +817,8 @@ uint16_t DoCAS16( } template -static -uint32_t DoCAS32( - uint32_t DesiredSrc, - uint32_t ExpectedSrc, - uint64_t Addr, - CASExpectedFn ExpectedFunction, - CASDesiredFn DesiredFunction) { +static uint32_t DoCAS32(uint32_t DesiredSrc, uint32_t ExpectedSrc, uint64_t Addr, CASExpectedFn ExpectedFunction, + CASDesiredFn DesiredFunction) { if ((Addr & 63) > 60) { FEXCORE_TELEMETRY_SET(SplitLock, 1); @@ -905,8 +869,7 @@ uint32_t DoCAS32( if (StoreCAS32(TmpExpectedLower, TmpDesiredLower, Addr)) { // Stored successfully return Expected; - } - else { + } else { // CAS managed to tear, we can't really solve this // Continue down the path to let the guest know values weren't expected Tear = true; @@ -917,8 +880,7 @@ uint32_t DoCAS32( TmpExpected = TmpExpectedUpper; TmpExpected <<= 32; TmpExpected |= TmpExpectedLower; - } - else { + } else { // Mismatch up front TmpExpected = TmpActual; } @@ -943,19 +905,16 @@ uint32_t DoCAS32( // If we are retrying and tearing then we can't do anything here // XXX: Resolve with TME return FailedResult; - } - else { + } else { // We can retry safely } - } - else { + } else { // Without Retry (CAS) then we have failed regardless of tear // CAS failed but handled successfully return FailedResult; } } - } - else { + } else { AlignmentMask = 0b111; if ((Addr & AlignmentMask) >= 5) { // Crosses 8byte boundary @@ -963,13 +922,13 @@ uint32_t DoCAS32( // Fits within a 16byte region uint64_t Alignment = Addr & 0b1111; Addr &= ~0b1111ULL; - std::atomic<__uint128_t> *Atomic128 = reinterpret_cast*>(Addr); + std::atomic<__uint128_t>* Atomic128 = reinterpret_cast*>(Addr); __uint128_t Mask = ~0U; Mask <<= Alignment * 8; __uint128_t NegMask = ~Mask; - __uint128_t TmpExpected{}; - __uint128_t TmpDesired{}; + __uint128_t TmpExpected {}; + __uint128_t TmpDesired {}; while (1) { __uint128_t TmpActual = Atomic128->load(); @@ -991,8 +950,7 @@ uint32_t DoCAS32( if (CASResult) { // Stored successfully return Expected; - } - else { + } else { if constexpr (Retry) { // If we failed but we have enabled retry then just retry without checking results // CAS can't retry but atomic memory ops need to retry until passing @@ -1017,8 +975,7 @@ uint32_t DoCAS32( return FailedResult; } } - } - else { + } else { // Fits within 8byte boundary // Only needs 64bit CAS // Alignments can be [1,5) @@ -1030,10 +987,10 @@ uint32_t DoCAS32( uint64_t NegMask = ~Mask; - uint64_t TmpExpected{}; - uint64_t TmpDesired{}; + uint64_t TmpExpected {}; + uint64_t TmpDesired {}; - std::atomic *Atomic = reinterpret_cast*>(Addr); + std::atomic* Atomic = reinterpret_cast*>(Addr); while (1) { uint64_t TmpActual = Atomic->load(); @@ -1054,8 +1011,7 @@ uint32_t DoCAS32( if (CASResult) { // Stored successfully return Expected; - } - else { + } else { if constexpr (Retry) { // If we failed but we have enabled retry then just retry without checking results // CAS can't retry but atomic memory ops need to retry until passing @@ -1086,13 +1042,8 @@ uint32_t DoCAS32( } template -static -uint64_t DoCAS64( - uint64_t DesiredSrc, - uint64_t ExpectedSrc, - uint64_t Addr, - CASExpectedFn ExpectedFunction, - CASDesiredFn DesiredFunction) { +static uint64_t DoCAS64(uint64_t DesiredSrc, uint64_t ExpectedSrc, uint64_t Addr, CASExpectedFn ExpectedFunction, + CASDesiredFn DesiredFunction) { if ((Addr & 63) > 56) { FEXCORE_TELEMETRY_SET(SplitLock, 1); @@ -1112,8 +1063,8 @@ uint64_t DoCAS64( __uint128_t Mask = ~0ULL; Mask <<= Alignment * 8; __uint128_t NegMask = ~Mask; - __uint128_t TmpExpected{}; - __uint128_t TmpDesired{}; + __uint128_t TmpExpected {}; + __uint128_t TmpDesired {}; while (1) { __uint128_t LoadOrderUpper = LoadAcquire64(AddrUpper); @@ -1145,8 +1096,7 @@ uint64_t DoCAS64( if (StoreCAS64(TmpExpectedLower, TmpDesiredLower, Addr)) { // Stored successfully return Expected; - } - else { + } else { // CAS managed to tear, we can't really solve this // Continue down the path to let the guest know values weren't expected Tear = true; @@ -1157,8 +1107,7 @@ uint64_t DoCAS64( TmpExpected = TmpExpectedUpper; TmpExpected <<= 64; TmpExpected |= TmpExpectedLower; - } - else { + } else { // Mismatch up front TmpExpected = TmpActual; } @@ -1183,29 +1132,26 @@ uint64_t DoCAS64( // If we are retrying and tearing then we can't do anything here // XXX: Resolve with TME return FailedResult; - } - else { + } else { // We can retry safely } - } - else { + } else { // Without Retry (CAS) then we have failed regardless of tear // CAS failed but handled successfully return FailedResult; } } - } - else { + } else { // Fits within a 16byte region uint64_t Alignment = Addr & AlignmentMask; Addr &= ~AlignmentMask; - std::atomic<__uint128_t> *Atomic128 = reinterpret_cast*>(Addr); + std::atomic<__uint128_t>* Atomic128 = reinterpret_cast*>(Addr); __uint128_t Mask = ~0ULL; Mask <<= Alignment * 8; __uint128_t NegMask = ~Mask; - __uint128_t TmpExpected{}; - __uint128_t TmpDesired{}; + __uint128_t TmpExpected {}; + __uint128_t TmpDesired {}; while (1) { __uint128_t TmpActual = Atomic128->load(); @@ -1227,8 +1173,7 @@ uint64_t DoCAS64( if (CASResult) { // Stored successfully return Expected; - } - else { + } else { if constexpr (Retry) { // If we failed but we have enabled retry then just retry without checking results // CAS can't retry but atomic memory ops need to retry until passing @@ -1256,7 +1201,7 @@ uint64_t DoCAS64( } } -static bool RunCASAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg, uint32_t ExpectedReg, uint32_t AddressReg) { +static bool RunCASAL(uint64_t* GPRs, uint32_t Size, uint32_t DesiredReg, uint32_t ExpectedReg, uint32_t AddressReg) { uint64_t Addr = GPRs[AddressReg]; // Cross-cacheline CAS doesn't work on ARM @@ -1271,9 +1216,7 @@ static bool RunCASAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg, uint32_ // Only need to handle 16, 32, 64 if (Size == 2) { auto Res = DoCAS16( - GPRs[DesiredReg], - GPRs[ExpectedReg], - Addr, + GPRs[DesiredReg], GPRs[ExpectedReg], Addr, [](uint16_t, uint16_t Expected) -> uint16_t { // Expected is just Expected return Expected; @@ -1289,12 +1232,9 @@ static bool RunCASAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg, uint32_ GPRs[ExpectedReg] = Res; } return true; - } - else if (Size == 4) { + } else if (Size == 4) { auto Res = DoCAS32( - GPRs[DesiredReg], - GPRs[ExpectedReg], - Addr, + GPRs[DesiredReg], GPRs[ExpectedReg], Addr, [](uint32_t, uint32_t Expected) -> uint32_t { // Expected is just Expected return Expected; @@ -1310,12 +1250,9 @@ static bool RunCASAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg, uint32_ GPRs[ExpectedReg] = Res; } return true; - } - else if (Size == 8) { + } else if (Size == 8) { auto Res = DoCAS64( - GPRs[DesiredReg], - GPRs[ExpectedReg], - Addr, + GPRs[DesiredReg], GPRs[ExpectedReg], Addr, [](uint64_t, uint64_t Expected) -> uint64_t { // Expected is just Expected return Expected; @@ -1336,7 +1273,7 @@ static bool RunCASAL(uint64_t *GPRs, uint32_t Size, uint32_t DesiredReg, uint32_ return false; } -static bool HandleCASAL(uint64_t *GPRs, uint32_t Instr) { +static bool HandleCASAL(uint64_t* GPRs, uint32_t Instr) { uint32_t Size = 1 << (Instr >> 30); uint32_t DesiredReg = Instr & 0b11111; @@ -1345,7 +1282,7 @@ static bool HandleCASAL(uint64_t *GPRs, uint32_t Instr) { return RunCASAL(GPRs, Size, DesiredReg, ExpectedReg, AddressReg); } -static bool HandleAtomicMemOp(uint32_t Instr, uint64_t *GPRs) { +static bool HandleAtomicMemOp(uint32_t Instr, uint64_t* GPRs) { uint32_t Size = 1 << (Instr >> 30); uint32_t ResultReg = Instr & 0b11111; uint32_t SourceReg = (Instr >> 16) & 0b11111; @@ -1380,43 +1317,27 @@ static bool HandleAtomicMemOp(uint32_t Instr, uint64_t *GPRs) { return Desired; }; - CASDesiredFn DesiredFunction{}; + CASDesiredFn DesiredFunction {}; switch (Op) { - case ATOMIC_ADD_OP: - DesiredFunction = ADDDesired; - break; - case ATOMIC_CLR_OP: - DesiredFunction = CLRDesired; - break; - case ATOMIC_EOR_OP: - DesiredFunction = EORDesired; - break; - case ATOMIC_SET_OP: - DesiredFunction = SETDesired; - break; - case ATOMIC_SWAP_OP: - DesiredFunction = SWAPDesired; - break; - default: - LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", Op); - return false; + case ATOMIC_ADD_OP: DesiredFunction = ADDDesired; break; + case ATOMIC_CLR_OP: DesiredFunction = CLRDesired; break; + case ATOMIC_EOR_OP: DesiredFunction = EORDesired; break; + case ATOMIC_SET_OP: DesiredFunction = SETDesired; break; + case ATOMIC_SWAP_OP: DesiredFunction = SWAPDesired; break; + default: LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", Op); return false; } - auto Res = DoCAS16( - GPRs[SourceReg], - 0, // Unused - Addr, - NOPExpected, - DesiredFunction); + auto Res = DoCAS16(GPRs[SourceReg], + 0, // Unused + Addr, NOPExpected, DesiredFunction); // If we passed and our destination register is not zero // Then we need to update the result register with what was in memory if (ResultReg != 31) { GPRs[ResultReg] = Res; } return true; - } - else if (Size == 4) { + } else if (Size == 4) { auto NOPExpected = [](uint32_t SrcVal, uint32_t) -> uint32_t { return SrcVal; }; @@ -1441,43 +1362,27 @@ static bool HandleAtomicMemOp(uint32_t Instr, uint64_t *GPRs) { return Desired; }; - CASDesiredFn DesiredFunction{}; + CASDesiredFn DesiredFunction {}; switch (Op) { - case ATOMIC_ADD_OP: - DesiredFunction = ADDDesired; - break; - case ATOMIC_CLR_OP: - DesiredFunction = CLRDesired; - break; - case ATOMIC_EOR_OP: - DesiredFunction = EORDesired; - break; - case ATOMIC_SET_OP: - DesiredFunction = SETDesired; - break; - case ATOMIC_SWAP_OP: - DesiredFunction = SWAPDesired; - break; - default: - LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", Op); - return false; + case ATOMIC_ADD_OP: DesiredFunction = ADDDesired; break; + case ATOMIC_CLR_OP: DesiredFunction = CLRDesired; break; + case ATOMIC_EOR_OP: DesiredFunction = EORDesired; break; + case ATOMIC_SET_OP: DesiredFunction = SETDesired; break; + case ATOMIC_SWAP_OP: DesiredFunction = SWAPDesired; break; + default: LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", Op); return false; } - auto Res = DoCAS32( - GPRs[SourceReg], - 0, // Unused - Addr, - NOPExpected, - DesiredFunction); + auto Res = DoCAS32(GPRs[SourceReg], + 0, // Unused + Addr, NOPExpected, DesiredFunction); // If we passed and our destination register is not zero // Then we need to update the result register with what was in memory if (ResultReg != 31) { GPRs[ResultReg] = Res; } return true; - } - else if (Size == 8) { + } else if (Size == 8) { auto NOPExpected = [](uint64_t SrcVal, uint64_t) -> uint64_t { return SrcVal; }; @@ -1502,35 +1407,20 @@ static bool HandleAtomicMemOp(uint32_t Instr, uint64_t *GPRs) { return Desired; }; - CASDesiredFn DesiredFunction{}; + CASDesiredFn DesiredFunction {}; switch (Op) { - case ATOMIC_ADD_OP: - DesiredFunction = ADDDesired; - break; - case ATOMIC_CLR_OP: - DesiredFunction = CLRDesired; - break; - case ATOMIC_EOR_OP: - DesiredFunction = EORDesired; - break; - case ATOMIC_SET_OP: - DesiredFunction = SETDesired; - break; - case ATOMIC_SWAP_OP: - DesiredFunction = SWAPDesired; - break; - default: - LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", Op); - return false; + case ATOMIC_ADD_OP: DesiredFunction = ADDDesired; break; + case ATOMIC_CLR_OP: DesiredFunction = CLRDesired; break; + case ATOMIC_EOR_OP: DesiredFunction = EORDesired; break; + case ATOMIC_SET_OP: DesiredFunction = SETDesired; break; + case ATOMIC_SWAP_OP: DesiredFunction = SWAPDesired; break; + default: LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", Op); return false; } - auto Res = DoCAS64( - GPRs[SourceReg], - 0, // Unused - Addr, - NOPExpected, - DesiredFunction); + auto Res = DoCAS64(GPRs[SourceReg], + 0, // Unused + Addr, NOPExpected, DesiredFunction); // If we passed and our destination register is not zero // Then we need to update the result register with what was in memory if (ResultReg != 31) { @@ -1542,7 +1432,7 @@ static bool HandleAtomicMemOp(uint32_t Instr, uint64_t *GPRs) { return false; } -static bool HandleAtomicLoad(uint32_t Instr, uint64_t *GPRs, int64_t Offset) { +static bool HandleAtomicLoad(uint32_t Instr, uint64_t* GPRs, int64_t Offset) { uint32_t Size = 1 << (Instr >> 30); uint32_t ResultReg = Instr & 0b11111; @@ -1557,16 +1447,14 @@ static bool HandleAtomicLoad(uint32_t Instr, uint64_t *GPRs, int64_t Offset) { GPRs[ResultReg] = Res; } return true; - } - else if (Size == 4) { + } else if (Size == 4) { auto Res = DoLoad32(Addr); // We set the result register if it isn't a zero register if (ResultReg != 31) { GPRs[ResultReg] = Res; } return true; - } - else if (Size == 8) { + } else if (Size == 8) { auto Res = DoLoad64(Addr); // We set the result register if it isn't a zero register if (ResultReg != 31) { @@ -1578,7 +1466,7 @@ static bool HandleAtomicLoad(uint32_t Instr, uint64_t *GPRs, int64_t Offset) { return false; } -static bool HandleAtomicStore(uint32_t Instr, uint64_t *GPRs, int64_t Offset) { +static bool HandleAtomicStore(uint32_t Instr, uint64_t* GPRs, int64_t Offset) { uint32_t Size = 1 << (Instr >> 30); uint32_t DataReg = Instr & 0x1F; @@ -1601,8 +1489,7 @@ static bool HandleAtomicStore(uint32_t Instr, uint64_t *GPRs, int64_t Offset) { return Desired; }); return true; - } - else if (Size == 4) { + } else if (Size == 4) { DoCAS32( GPRs[DataReg], 0, // Unused @@ -1616,8 +1503,7 @@ static bool HandleAtomicStore(uint32_t Instr, uint64_t *GPRs, int64_t Offset) { return Desired; }); return true; - } - else if (Size == 8) { + } else if (Size == 8) { DoCAS64( GPRs[DataReg], 0, // Unused @@ -1636,8 +1522,7 @@ static bool HandleAtomicStore(uint32_t Instr, uint64_t *GPRs, int64_t Offset) { return false; } -static uint64_t HandleCAS_NoAtomics(uintptr_t ProgramCounter, uint64_t *GPRs) -{ +static uint64_t HandleCAS_NoAtomics(uintptr_t ProgramCounter, uint64_t* GPRs) { // ARMv8.0 CAS // [1] ldaxrb(TMP2.W(), MemOperand(MemSrc)) // [2] cmp (TMP2.W(), Expected.W()) @@ -1649,40 +1534,39 @@ static uint64_t HandleCAS_NoAtomics(uintptr_t ProgramCounter, uint64_t *GPRs) // [8] mov (.., TMP2.W()); // [9] clrex - uint32_t *PC = (uint32_t*)ProgramCounter; + uint32_t* PC = (uint32_t*)ProgramCounter; uint32_t Instr = PC[0]; uint32_t Size = 1 << (Instr >> 30); uint32_t AddressReg = GetRnReg(Instr); - uint32_t ResultReg = GetRdReg(Instr); //TMP2 + uint32_t ResultReg = GetRdReg(Instr); // TMP2 uint32_t DesiredReg = 0; uint32_t ExpectedReg = 0; for (size_t i = 1; i < 6; ++i) { - uint32_t NextInstr = PC[i]; - if ((NextInstr & ArchHelpers::Arm64::STLXR_MASK) == ArchHelpers::Arm64::STLXR_INST) { - #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - // Just double check that the memory destination matches - const uint32_t StoreAddressReg = GetRnReg(NextInstr); - LOGMAN_THROW_A_FMT(StoreAddressReg == AddressReg, "StoreExclusive memory register didn't match the store exclusive register"); - #endif - DesiredReg = GetRdReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_INST || - (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_SHIFT_INST) { - ExpectedReg = GetRmReg(NextInstr); - } + uint32_t NextInstr = PC[i]; + if ((NextInstr & ArchHelpers::Arm64::STLXR_MASK) == ArchHelpers::Arm64::STLXR_INST) { +#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED + // Just double check that the memory destination matches + const uint32_t StoreAddressReg = GetRnReg(NextInstr); + LOGMAN_THROW_A_FMT(StoreAddressReg == AddressReg, "StoreExclusive memory register didn't match the store exclusive register"); +#endif + DesiredReg = GetRdReg(NextInstr); + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_INST || + (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_SHIFT_INST) { + ExpectedReg = GetRmReg(NextInstr); + } } - //set up CASAL by doing mov(TMP2, Expected) + // set up CASAL by doing mov(TMP2, Expected) GPRs[ResultReg] = GPRs[ExpectedReg]; - if(RunCASAL(GPRs, Size, DesiredReg, ResultReg, AddressReg)) { - return 7 * sizeof(uint32_t); //jump to mov to allocated register + if (RunCASAL(GPRs, Size, DesiredReg, ResultReg, AddressReg)) { + return 7 * sizeof(uint32_t); // jump to mov to allocated register } else { return 0; } } -static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_t *GPRs) { - uint32_t *PC = (uint32_t*)ProgramCounter; +static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_t* GPRs) { + uint32_t* PC = (uint32_t*)ProgramCounter; uint32_t Instr = PC[0]; // Atomic Add @@ -1746,48 +1630,38 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::ADD_SHIFT_INST) { AtomicOp = ExclusiveAtomicPairType::TYPE_ADD; DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::SUB_INST || - (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::SUB_SHIFT_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::SUB_INST || + (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::SUB_SHIFT_INST) { uint32_t RnReg = GetRnReg(NextInstr); if (RnReg == REGISTER_MASK) { // Zero reg means neg AtomicOp = ExclusiveAtomicPairType::TYPE_NEG; - } - else { + } else { AtomicOp = ExclusiveAtomicPairType::TYPE_SUB; } DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_INST || - (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_SHIFT_INST ) { - return HandleCAS_NoAtomics(ProgramCounter, GPRs); //ARMv8.0 CAS - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::AND_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_INST || + (NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::CMP_SHIFT_INST) { + return HandleCAS_NoAtomics(ProgramCounter, GPRs); // ARMv8.0 CAS + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::AND_INST) { AtomicOp = ExclusiveAtomicPairType::TYPE_AND; DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::BIC_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::BIC_INST) { AtomicOp = ExclusiveAtomicPairType::TYPE_BIC; DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::OR_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::OR_INST) { AtomicOp = ExclusiveAtomicPairType::TYPE_OR; DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::ORN_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::ORN_INST) { AtomicOp = ExclusiveAtomicPairType::TYPE_ORN; DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::EOR_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::EOR_INST) { AtomicOp = ExclusiveAtomicPairType::TYPE_EOR; DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::EON_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::ALU_OP_MASK) == ArchHelpers::Arm64::EON_INST) { AtomicOp = ExclusiveAtomicPairType::TYPE_EON; DataSourceReg = GetRmReg(NextInstr); - } - else if ((NextInstr & ArchHelpers::Arm64::STLXR_MASK) == ArchHelpers::Arm64::STLXR_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::STLXR_MASK) == ArchHelpers::Arm64::STLXR_INST) { #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED // Just double check that the memory destination matches const uint32_t StoreAddressReg = GetRnReg(NextInstr); @@ -1802,14 +1676,12 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ // Source is directly in STLXR DataSourceReg = StoreResultReg; } - } - else if ((NextInstr & ArchHelpers::Arm64::CBNZ_MASK) == ArchHelpers::Arm64::CBNZ_INST) { + } else if ((NextInstr & ArchHelpers::Arm64::CBNZ_MASK) == ArchHelpers::Arm64::CBNZ_INST) { // Found the CBNZ, we want to skip to just after this instruction when done NumInstructionsToSkip = i + 1; // This is the last instruction we care about. Leave now break; - } - else { + } else { LogMan::Msg::AFmt("Unknown instruction 0x{:08x}", NextInstr); } } @@ -1864,159 +1736,79 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ if (Size == 2) { using AtomicType = uint16_t; - CASDesiredFn DesiredFunction{}; + CASDesiredFn DesiredFunction {}; switch (AtomicOp) { - case ExclusiveAtomicPairType::TYPE_SWAP: - DesiredFunction = SWAPDesired; - break; - case ExclusiveAtomicPairType::TYPE_ADD: - DesiredFunction = ADDDesired; - break; - case ExclusiveAtomicPairType::TYPE_SUB: - DesiredFunction = SUBDesired; - break; - case ExclusiveAtomicPairType::TYPE_AND: - DesiredFunction = ANDDesired; - break; - case ExclusiveAtomicPairType::TYPE_BIC: - DesiredFunction = BICDesired; - break; - case ExclusiveAtomicPairType::TYPE_OR: - DesiredFunction = ORDesired; - break; - case ExclusiveAtomicPairType::TYPE_ORN: - DesiredFunction = ORNDesired; - break; - case ExclusiveAtomicPairType::TYPE_EOR: - DesiredFunction = EORDesired; - break; - case ExclusiveAtomicPairType::TYPE_EON: - DesiredFunction = EONDesired; - break; - case ExclusiveAtomicPairType::TYPE_NEG: - DesiredFunction = NEGDesired; - break; - default: - LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", - FEXCore::ToUnderlying(AtomicOp)); - return false; + case ExclusiveAtomicPairType::TYPE_SWAP: DesiredFunction = SWAPDesired; break; + case ExclusiveAtomicPairType::TYPE_ADD: DesiredFunction = ADDDesired; break; + case ExclusiveAtomicPairType::TYPE_SUB: DesiredFunction = SUBDesired; break; + case ExclusiveAtomicPairType::TYPE_AND: DesiredFunction = ANDDesired; break; + case ExclusiveAtomicPairType::TYPE_BIC: DesiredFunction = BICDesired; break; + case ExclusiveAtomicPairType::TYPE_OR: DesiredFunction = ORDesired; break; + case ExclusiveAtomicPairType::TYPE_ORN: DesiredFunction = ORNDesired; break; + case ExclusiveAtomicPairType::TYPE_EOR: DesiredFunction = EORDesired; break; + case ExclusiveAtomicPairType::TYPE_EON: DesiredFunction = EONDesired; break; + case ExclusiveAtomicPairType::TYPE_NEG: DesiredFunction = NEGDesired; break; + default: LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", FEXCore::ToUnderlying(AtomicOp)); return false; } - auto Res = DoCAS16( - GPRs[DataSourceReg], - 0, // Unused - Addr, - NOPExpected, - DesiredFunction); + auto Res = DoCAS16(GPRs[DataSourceReg], + 0, // Unused + Addr, NOPExpected, DesiredFunction); if (AtomicFetch && ResultReg != 31) { // On atomic fetch then we store the resulting value back in to the loadacquire destination register // We want the memory value BEFORE the ALU op GPRs[ResultReg] = Res; } - } - else if (Size == 4) { + } else if (Size == 4) { using AtomicType = uint32_t; - CASDesiredFn DesiredFunction{}; + CASDesiredFn DesiredFunction {}; switch (AtomicOp) { - case ExclusiveAtomicPairType::TYPE_SWAP: - DesiredFunction = SWAPDesired; - break; - case ExclusiveAtomicPairType::TYPE_ADD: - DesiredFunction = ADDDesired; - break; - case ExclusiveAtomicPairType::TYPE_SUB: - DesiredFunction = SUBDesired; - break; - case ExclusiveAtomicPairType::TYPE_AND: - DesiredFunction = ANDDesired; - break; - case ExclusiveAtomicPairType::TYPE_BIC: - DesiredFunction = BICDesired; - break; - case ExclusiveAtomicPairType::TYPE_OR: - DesiredFunction = ORDesired; - break; - case ExclusiveAtomicPairType::TYPE_ORN: - DesiredFunction = ORNDesired; - break; - case ExclusiveAtomicPairType::TYPE_EOR: - DesiredFunction = EORDesired; - break; - case ExclusiveAtomicPairType::TYPE_EON: - DesiredFunction = EONDesired; - break; - case ExclusiveAtomicPairType::TYPE_NEG: - DesiredFunction = NEGDesired; - break; - default: - LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", - FEXCore::ToUnderlying(AtomicOp)); - return false; + case ExclusiveAtomicPairType::TYPE_SWAP: DesiredFunction = SWAPDesired; break; + case ExclusiveAtomicPairType::TYPE_ADD: DesiredFunction = ADDDesired; break; + case ExclusiveAtomicPairType::TYPE_SUB: DesiredFunction = SUBDesired; break; + case ExclusiveAtomicPairType::TYPE_AND: DesiredFunction = ANDDesired; break; + case ExclusiveAtomicPairType::TYPE_BIC: DesiredFunction = BICDesired; break; + case ExclusiveAtomicPairType::TYPE_OR: DesiredFunction = ORDesired; break; + case ExclusiveAtomicPairType::TYPE_ORN: DesiredFunction = ORNDesired; break; + case ExclusiveAtomicPairType::TYPE_EOR: DesiredFunction = EORDesired; break; + case ExclusiveAtomicPairType::TYPE_EON: DesiredFunction = EONDesired; break; + case ExclusiveAtomicPairType::TYPE_NEG: DesiredFunction = NEGDesired; break; + default: LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", FEXCore::ToUnderlying(AtomicOp)); return false; } - auto Res = DoCAS32( - GPRs[DataSourceReg], - 0, // Unused - Addr, - NOPExpected, - DesiredFunction); + auto Res = DoCAS32(GPRs[DataSourceReg], + 0, // Unused + Addr, NOPExpected, DesiredFunction); if (AtomicFetch && ResultReg != 31) { // On atomic fetch then we store the resulting value back in to the loadacquire destination register // We want the memory value BEFORE the ALU op GPRs[ResultReg] = Res; } - } - else if (Size == 8) { + } else if (Size == 8) { using AtomicType = uint64_t; - CASDesiredFn DesiredFunction{}; + CASDesiredFn DesiredFunction {}; switch (AtomicOp) { - case ExclusiveAtomicPairType::TYPE_SWAP: - DesiredFunction = SWAPDesired; - break; - case ExclusiveAtomicPairType::TYPE_ADD: - DesiredFunction = ADDDesired; - break; - case ExclusiveAtomicPairType::TYPE_SUB: - DesiredFunction = SUBDesired; - break; - case ExclusiveAtomicPairType::TYPE_AND: - DesiredFunction = ANDDesired; - break; - case ExclusiveAtomicPairType::TYPE_BIC: - DesiredFunction = BICDesired; - break; - case ExclusiveAtomicPairType::TYPE_OR: - DesiredFunction = ORDesired; - break; - case ExclusiveAtomicPairType::TYPE_ORN: - DesiredFunction = ORNDesired; - break; - case ExclusiveAtomicPairType::TYPE_EOR: - DesiredFunction = EORDesired; - break; - case ExclusiveAtomicPairType::TYPE_EON: - DesiredFunction = EONDesired; - break; - case ExclusiveAtomicPairType::TYPE_NEG: - DesiredFunction = NEGDesired; - break; - default: - LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", - FEXCore::ToUnderlying(AtomicOp)); - return false; + case ExclusiveAtomicPairType::TYPE_SWAP: DesiredFunction = SWAPDesired; break; + case ExclusiveAtomicPairType::TYPE_ADD: DesiredFunction = ADDDesired; break; + case ExclusiveAtomicPairType::TYPE_SUB: DesiredFunction = SUBDesired; break; + case ExclusiveAtomicPairType::TYPE_AND: DesiredFunction = ANDDesired; break; + case ExclusiveAtomicPairType::TYPE_BIC: DesiredFunction = BICDesired; break; + case ExclusiveAtomicPairType::TYPE_OR: DesiredFunction = ORDesired; break; + case ExclusiveAtomicPairType::TYPE_ORN: DesiredFunction = ORNDesired; break; + case ExclusiveAtomicPairType::TYPE_EOR: DesiredFunction = EORDesired; break; + case ExclusiveAtomicPairType::TYPE_EON: DesiredFunction = EONDesired; break; + case ExclusiveAtomicPairType::TYPE_NEG: DesiredFunction = NEGDesired; break; + default: LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}", FEXCore::ToUnderlying(AtomicOp)); return false; } - auto Res = DoCAS64( - GPRs[DataSourceReg], - 0, // Unused - Addr, - NOPExpected, - DesiredFunction); + auto Res = DoCAS64(GPRs[DataSourceReg], + 0, // Unused + Addr, NOPExpected, DesiredFunction); if (AtomicFetch && ResultReg != 31) { // On atomic fetch then we store the resulting value back in to the loadacquire destination register // We want the memory value BEFORE the ALU op @@ -2028,7 +1820,9 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ return NumInstructionsToSkip * 4; } -[[nodiscard]] std::pair HandleUnalignedAccess(FEXCore::Core::InternalThreadState *Thread, bool ParanoidTSO, uintptr_t ProgramCounter, uint64_t *GPRs) { +[[nodiscard]] +std::pair +HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, bool ParanoidTSO, uintptr_t ProgramCounter, uint64_t* GPRs) { #ifdef _M_ARM_64 constexpr bool is_arm64 = true; #else @@ -2038,7 +1832,7 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ constexpr auto NotHandled = std::make_pair(false, 0); if constexpr (is_arm64) { - uint32_t *PC = (uint32_t*)ProgramCounter; + uint32_t* PC = (uint32_t*)ProgramCounter; uint32_t Instr = PC[0]; // 1 = 16bit @@ -2050,47 +1844,40 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ // ParanoidTSO path doesn't modify any code. if (ParanoidTSO) [[unlikely]] { - if ((Instr & LDAXR_MASK) == LDAR_INST || // LDAR* + if ((Instr & LDAXR_MASK) == LDAR_INST || // LDAR* (Instr & LDAXR_MASK) == LDAPR_INST) { // LDAPR* if (ArchHelpers::Arm64::HandleAtomicLoad(Instr, GPRs, 0)) { // Skip this instruction now return std::make_pair(true, 4); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDAR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } - } - else if ( (Instr & LDAXR_MASK) == STLR_INST) { // STLR* + } else if ((Instr & LDAXR_MASK) == STLR_INST) { // STLR* if (ArchHelpers::Arm64::HandleAtomicStore(Instr, GPRs, 0)) { // Skip this instruction now return std::make_pair(true, 4); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS STLR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } - } - else if ((Instr & RCPC2_MASK) == LDAPUR_INST) { // LDAPUR* + } else if ((Instr & RCPC2_MASK) == LDAPUR_INST) { // LDAPUR* // Extract the 9-bit offset from the instruction int32_t Offset = static_cast(Instr) << 11 >> 23; if (ArchHelpers::Arm64::HandleAtomicLoad(Instr, GPRs, Offset)) { // Skip this instruction now return std::make_pair(true, 4); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDAPUR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } - } - else if ((Instr & RCPC2_MASK) == STLUR_INST) { // STLUR* + } else if ((Instr & RCPC2_MASK) == STLUR_INST) { // STLUR* // Extract the 9-bit offset from the instruction int32_t Offset = static_cast(Instr) << 11 >> 23; if (ArchHelpers::Arm64::HandleAtomicStore(Instr, GPRs, Offset)) { // Skip this instruction now return std::make_pair(true, 4); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDLUR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } @@ -2099,14 +1886,14 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ const auto Frame = Thread->CurrentFrame; const uint64_t BlockBegin = Frame->State.InlineJITBlockHeader; - auto InlineHeader = reinterpret_cast(BlockBegin); - auto InlineTail = reinterpret_cast(Frame->State.InlineJITBlockHeader + InlineHeader->OffsetToBlockTail); + auto InlineHeader = reinterpret_cast(BlockBegin); + auto InlineTail = reinterpret_cast(Frame->State.InlineJITBlockHeader + InlineHeader->OffsetToBlockTail); // Lock code mutex during any SIGBUS handling that potentially changes code. // Need to be careful to not read any code part-way through modification. FEXCore::Utils::SpinWaitLock::UniqueSpinMutex lk(&InlineTail->SpinLockFutex); - if ((Instr & LDAXR_MASK) == LDAR_INST || // LDAR* + if ((Instr & LDAXR_MASK) == LDAR_INST || // LDAR* (Instr & LDAXR_MASK) == LDAPR_INST) { // LDAPR* uint32_t LDR = 0b0011'1000'0111'1111'0110'1000'0000'0000; LDR |= Size << 30; @@ -2117,8 +1904,7 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ ClearICache(&PC[-1], 16); // With the instruction modified, now execute again. return std::make_pair(true, 0); - } - else if ( (Instr & LDAXR_MASK) == STLR_INST) { // STLR* + } else if ((Instr & LDAXR_MASK) == STLR_INST) { // STLR* uint32_t STR = 0b0011'1000'0011'1111'0110'1000'0000'0000; STR |= Size << 30; STR |= AddrReg << 5; @@ -2128,8 +1914,7 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ ClearICache(&PC[-1], 16); // Back up one instruction and have another go return std::make_pair(true, -4); - } - else if ((Instr & RCPC2_MASK) == LDAPUR_INST) { // LDAPUR* + } else if ((Instr & RCPC2_MASK) == LDAPUR_INST) { // LDAPUR* // Extract the 9-bit offset from the instruction uint32_t LDUR = 0b0011'1000'0100'0000'0000'0000'0000'0000; LDUR |= Size << 30; @@ -2141,84 +1926,70 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ ClearICache(&PC[-1], 16); // With the instruction modified, now execute again. return std::make_pair(true, 0); - } - else if ((Instr & RCPC2_MASK) == STLUR_INST) { // STLUR* + } else if ((Instr & RCPC2_MASK) == STLUR_INST) { // STLUR* uint32_t STUR = 0b0011'1000'0000'0000'0000'0000'0000'0000; STUR |= Size << 30; STUR |= AddrReg << 5; STUR |= DataReg; STUR |= Instr & (0b1'1111'1111 << 9); - PC[-1] = DMB; // Back-patch the half-barrier. + PC[-1] = DMB; // Back-patch the half-barrier. PC[0] = STUR; ClearICache(&PC[-1], 16); // Back up one instruction and have another go return std::make_pair(true, -4); - } - else if ((Instr & ArchHelpers::Arm64::LDAXP_MASK) == ArchHelpers::Arm64::LDAXP_INST) { // LDAXP - //Should be compare and swap pair only. LDAXP not used elsewhere + } else if ((Instr & ArchHelpers::Arm64::LDAXP_MASK) == ArchHelpers::Arm64::LDAXP_INST) { // LDAXP + // Should be compare and swap pair only. LDAXP not used elsewhere uint64_t BytesToSkip = ArchHelpers::Arm64::HandleCASPAL_ARMv8(Instr, ProgramCounter, GPRs); if (BytesToSkip) { // Skip this instruction now return std::make_pair(true, BytesToSkip); - } - else { + } else { if (ArchHelpers::Arm64::HandleAtomicVectorStore(Instr, ProgramCounter)) { return std::make_pair(true, 0); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDAXP: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } } - } - else if ((Instr & ArchHelpers::Arm64::STLXP_MASK) == ArchHelpers::Arm64::STLXP_INST) { // STLXP - //Should not trigger - middle of an LDAXP/STAXP pair. + } else if ((Instr & ArchHelpers::Arm64::STLXP_MASK) == ArchHelpers::Arm64::STLXP_INST) { // STLXP + // Should not trigger - middle of an LDAXP/STAXP pair. LogMan::Msg::EFmt("Unhandled JIT SIGBUS STLXP: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; - } - else if ((Instr & ArchHelpers::Arm64::CASPAL_MASK) == ArchHelpers::Arm64::CASPAL_INST) { // CASPAL + } else if ((Instr & ArchHelpers::Arm64::CASPAL_MASK) == ArchHelpers::Arm64::CASPAL_INST) { // CASPAL if (ArchHelpers::Arm64::HandleCASPAL(Instr, GPRs)) { // Skip this instruction now return std::make_pair(true, 4); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS CASPAL: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } - } - else if ((Instr & ArchHelpers::Arm64::CASAL_MASK) == ArchHelpers::Arm64::CASAL_INST) { // CASAL + } else if ((Instr & ArchHelpers::Arm64::CASAL_MASK) == ArchHelpers::Arm64::CASAL_INST) { // CASAL if (ArchHelpers::Arm64::HandleCASAL(GPRs, Instr)) { // Skip this instruction now return std::make_pair(true, 4); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS CASAL: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } - } - else if ((Instr & ArchHelpers::Arm64::ATOMIC_MEM_MASK) == ArchHelpers::Arm64::ATOMIC_MEM_INST) { // Atomic memory op + } else if ((Instr & ArchHelpers::Arm64::ATOMIC_MEM_MASK) == ArchHelpers::Arm64::ATOMIC_MEM_INST) { // Atomic memory op if (ArchHelpers::Arm64::HandleAtomicMemOp(Instr, GPRs)) { // Skip this instruction now return std::make_pair(true, 4); - } - else { + } else { uint8_t Op = (PC[0] >> 12) & 0xF; LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}: PC: 0x{:x} Instruction: 0x{:08x}\n", Op, ProgramCounter, PC[0]); return NotHandled; } - } - else if ((Instr & ArchHelpers::Arm64::LDAXR_MASK) == ArchHelpers::Arm64::LDAXR_INST) { // LDAXR* + } else if ((Instr & ArchHelpers::Arm64::LDAXR_MASK) == ArchHelpers::Arm64::LDAXR_INST) { // LDAXR* uint64_t BytesToSkip = ArchHelpers::Arm64::HandleAtomicLoadstoreExclusive(ProgramCounter, GPRs); if (BytesToSkip) { // Skip this instruction now return std::make_pair(true, BytesToSkip); - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDAXR: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } - } - else { + } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); return NotHandled; } @@ -2227,4 +1998,4 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ } -} +} // namespace FEXCore::ArchHelpers::Arm64 diff --git a/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp b/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp index 434d378fe..242754b73 100644 --- a/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp +++ b/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp @@ -11,22 +11,23 @@ namespace FEXCore::ArchHelpers::Arm64 { // Obvously such a configuration can't do the actual arm64-specific stuff -bool HandleCASPAL(void *_ucontext, void *_info, uint32_t Instr) { - ERROR_AND_DIE_FMT("HandleCASPAL Not Implemented"); +bool HandleCASPAL(void* _ucontext, void* _info, uint32_t Instr) { + ERROR_AND_DIE_FMT("HandleCASPAL Not Implemented"); } -bool HandleCASAL(void *_ucontext, void *_info, uint32_t Instr) { - ERROR_AND_DIE_FMT("HandleCASAL Not Implemented"); +bool HandleCASAL(void* _ucontext, void* _info, uint32_t Instr) { + ERROR_AND_DIE_FMT("HandleCASAL Not Implemented"); } -bool HandleAtomicMemOp(void *_ucontext, void *_info, uint32_t Instr) { - ERROR_AND_DIE_FMT("HandleAtomicMemOp Not Implemented"); +bool HandleAtomicMemOp(void* _ucontext, void* _info, uint32_t Instr) { + ERROR_AND_DIE_FMT("HandleAtomicMemOp Not Implemented"); } -std::pair HandleUnalignedAccess(FEXCore::Core::InternalThreadState *Thread, bool ParanoidTSO, uintptr_t ProgramCounter, uint64_t *GPRs) { +std::pair +HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, bool ParanoidTSO, uintptr_t ProgramCounter, uint64_t* GPRs) { ERROR_AND_DIE_FMT("HandleAtomicMemOp Not Implemented"); } #endif -} +} // namespace FEXCore::ArchHelpers::Arm64 diff --git a/FEXCore/Source/Utils/BucketList.h b/FEXCore/Source/Utils/BucketList.h index 58e657801..fc0f0d1c0 100644 --- a/FEXCore/Source/Utils/BucketList.h +++ b/FEXCore/Source/Utils/BucketList.h @@ -7,136 +7,135 @@ namespace FEXCore { - // BucketList is an optimized container, it includes an inline array of Size - // and can overflow to a linked list of further buckets - // - // To optimize for best performance, Size should be big enough to allocate one or two - // buckets for the typical case - // Picking a Size so sizeof(Bucket<...>) is a power of two is also a small win - template - struct BucketList { - static constexpr size_t Size = _Size; +// BucketList is an optimized container, it includes an inline array of Size +// and can overflow to a linked list of further buckets +// +// To optimize for best performance, Size should be big enough to allocate one or two +// buckets for the typical case +// Picking a Size so sizeof(Bucket<...>) is a power of two is also a small win +template +struct BucketList { + static constexpr size_t Size = _Size; - T Items[Size]; - fextl::unique_ptr> Next; + T Items[Size]; + fextl::unique_ptr> Next; - void Clear() { - Items[0] = T{}; - #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - for (size_t i = 1; i < Size; i++) { - Items[i] = T{0xDEADBEEF}; + void Clear() { + Items[0] = T {}; +#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED + for (size_t i = 1; i < Size; i++) { + Items[i] = T {0xDEADBEEF}; + } +#endif + Next.reset(); + } + + BucketList() { + Clear(); + } + + template + void Iterate(EnumeratorFn Enumerator) const { + size_t i = 0; + auto Bucket = this; + + while (true) { + auto Item = Bucket->Items[i]; + if (Item == T {}) { + break; + } + + Enumerator(Item); + + if (++i == Size) { + LOGMAN_THROW_A_FMT(Bucket->Next != nullptr, "Interference bug"); + Bucket = Bucket->Next.get(); + i = 0; } - #endif - Next.reset(); } + } - BucketList() { - Clear(); - } + template + bool Find(EnumeratorFn Enumerator) const { + size_t i = 0; + auto Bucket = this; - template - void Iterate(EnumeratorFn Enumerator) const { - size_t i = 0; - auto Bucket = this; + while (true) { + auto Item = Bucket->Items[i]; + if (Item == T {}) { + break; + } - while (true) { - auto Item = Bucket->Items[i]; - if (Item == T{}) { - break; - } + if (Enumerator(Item)) { + return true; + } - Enumerator(Item); - - if (++i == Size) { - LOGMAN_THROW_A_FMT(Bucket->Next != nullptr, "Interference bug"); - Bucket = Bucket->Next.get(); - i = 0; - } + if (++i == Size) { + LOGMAN_THROW_A_FMT(Bucket->Next != nullptr, "Bucket in bad state"); + Bucket = Bucket->Next.get(); + i = 0; } } - template - bool Find(EnumeratorFn Enumerator) const { - size_t i = 0; - auto Bucket = this; + return false; + } - while (true) { - auto Item = Bucket->Items[i]; - if (Item == T{}) { - break; - } + void Append(T Val) { + auto that = this; - if (Enumerator(Item)) - return true; - - if (++i == Size) { - LOGMAN_THROW_A_FMT(Bucket->Next != nullptr, "Bucket in bad state"); - Bucket = Bucket->Next.get(); - i = 0; - } - } - - return false; + while (that->Next) { + that = that->Next.get(); } - void Append(T Val) { - auto that = this; + size_t i; + for (i = 0; i < Size; i++) { + if (that->Items[i] == T {}) { + that->Items[i] = Val; + break; + } + } - while (that->Next) { + if (i < (Size - 1)) { + that->Items[i + 1] = T {}; + } else { + that->Next = fextl::make_unique>(); + } + } + void Erase(T Val) { + size_t i = 0; + auto that = this; + auto foundThat = this; + size_t foundI = 0; + + while (true) { + if (that->Items[i] == Val) { + foundThat = that; + foundI = i; + break; + } else if (++i == Size) { + i = 0; + LOGMAN_THROW_A_FMT(that->Next != nullptr, "Bucket::Erase but element not contained"); that = that->Next.get(); } + } - size_t i; - for (i = 0; i < Size; i++) { - if (that->Items[i] == T{}) { - that->Items[i] = Val; + while (true) { + if (that->Items[i] == T {}) { + foundThat->Items[foundI] = that->Items[i - 1]; + that->Items[i - 1] = T {}; + break; + } else if (++i == Size) { + if (that->Next->Items[0] == T {}) { + that->Next.reset(); + foundThat->Items[foundI] = that->Items[Size - 1]; + that->Items[Size - 1] = T {}; break; } - } - - if (i < (Size-1)) { - that->Items[i+1] = T{}; - } else { - that->Next = fextl::make_unique>(); + i = 0; + that = that->Next.get(); } } - void Erase(T Val) { - size_t i = 0; - auto that = this; - auto foundThat = this; - size_t foundI = 0; + } +}; - while (true) { - if (that->Items[i] == Val) { - foundThat = that; - foundI = i; - break; - } - else if (++i == Size) { - i = 0; - LOGMAN_THROW_A_FMT(that->Next != nullptr, "Bucket::Erase but element not contained"); - that = that->Next.get(); - } - } - - while (true) { - if (that->Items[i] == T{}) { - foundThat->Items[foundI] = that->Items[i-1]; - that->Items[i-1] = T{}; - break; - } - else if (++i == Size) { - if (that->Next->Items[0] == T{}) { - that->Next.reset(); - foundThat->Items[foundI] = that->Items[Size-1]; - that->Items[Size-1] = T{}; - break; - } - i = 0; - that = that->Next.get(); - } - } - } - }; - -} // namespace +} // namespace FEXCore diff --git a/FEXCore/Source/Utils/CPUInfo.cpp b/FEXCore/Source/Utils/CPUInfo.cpp index 07b9b0754..f0683e4ac 100644 --- a/FEXCore/Source/Utils/CPUInfo.cpp +++ b/FEXCore/Source/Utils/CPUInfo.cpp @@ -13,24 +13,24 @@ namespace FEXCore::CPUInfo { #ifndef _WIN32 - uint32_t CalculateNumberOfCPUs() { - char Tmp[PATH_MAX]; - size_t CPUs = 1; +uint32_t CalculateNumberOfCPUs() { + char Tmp[PATH_MAX]; + size_t CPUs = 1; - for (;; ++CPUs) { - auto Size = fmt::format_to_n(Tmp, sizeof(Tmp), "/sys/devices/system/cpu/cpu{}", CPUs); - Tmp[Size.size] = 0; - if (!FHU::Filesystem::Exists(Tmp)) { - break; - } + for (;; ++CPUs) { + auto Size = fmt::format_to_n(Tmp, sizeof(Tmp), "/sys/devices/system/cpu/cpu{}", CPUs); + Tmp[Size.size] = 0; + if (!FHU::Filesystem::Exists(Tmp)) { + break; } + } - return CPUs; - } -#else - uint32_t CalculateNumberOfCPUs() { - // May not return correct number of cores if some are parked. - return std::thread::hardware_concurrency(); - } -#endif + return CPUs; } +#else +uint32_t CalculateNumberOfCPUs() { + // May not return correct number of cores if some are parked. + return std::thread::hardware_concurrency(); +} +#endif +} // namespace FEXCore::CPUInfo diff --git a/FEXCore/Source/Utils/Config.h b/FEXCore/Source/Utils/Config.h index f9198dbf6..89c528b4e 100644 --- a/FEXCore/Source/Utils/Config.h +++ b/FEXCore/Source/Utils/Config.h @@ -2,5 +2,5 @@ #include namespace FEXCore::Config { - fextl::string const& GetTelemetryDirectory(); +const fextl::string& GetTelemetryDirectory(); } diff --git a/FEXCore/Source/Utils/FileLoading.cpp b/FEXCore/Source/Utils/FileLoading.cpp index 71e6c8317..bd46a3396 100644 --- a/FEXCore/Source/Utils/FileLoading.cpp +++ b/FEXCore/Source/Utils/FileLoading.cpp @@ -14,34 +14,32 @@ namespace FEXCore::FileLoading { #ifndef _WIN32 template -static bool LoadFileImpl(T &Data, const fextl::string &Filepath, size_t FixedSize) { +static bool LoadFileImpl(T& Data, const fextl::string& Filepath, size_t FixedSize) { int FD = open(Filepath.c_str(), O_RDONLY); if (FD == -1) { return false; } - size_t FileSize{}; + size_t FileSize {}; if (FixedSize == 0) { struct stat buf; if (fstat(FD, &buf) == 0) { FileSize = buf.st_size; } - } - else { + } else { FileSize = FixedSize; } ssize_t Read = -1; - bool LoadedFile{}; + bool LoadedFile {}; if (FileSize) { // File size is known upfront Data.resize(FileSize); Read = pread(FD, &Data.at(0), FileSize, 0); LoadedFile = Read == FileSize; - } - else { + } else { // The file is either empty or its size is unknown (e.g. procfs data). // Try reading in chunks instead ssize_t CurrentOffset = 0; @@ -68,7 +66,7 @@ static bool LoadFileImpl(T &Data, const fextl::string &Filepath, size_t FixedSiz return LoadedFile; } -ssize_t LoadFileToBuffer(const fextl::string &Filepath, std::span Buffer) { +ssize_t LoadFileToBuffer(const fextl::string& Filepath, std::span Buffer) { int FD = open(Filepath.c_str(), O_RDONLY); if (FD == -1) { @@ -82,7 +80,7 @@ ssize_t LoadFileToBuffer(const fextl::string &Filepath, std::span Buffer) #else template -static bool LoadFileImpl(T &Data, const fextl::string &Filepath, size_t FixedSize) { +static bool LoadFileImpl(T& Data, const fextl::string& Filepath, size_t FixedSize) { std::ifstream f(Filepath, std::ios::binary | std::ios::ate); if (f.fail()) { return false; @@ -94,19 +92,19 @@ static bool LoadFileImpl(T &Data, const fextl::string &Filepath, size_t FixedSiz return !f.fail(); } -ssize_t LoadFileToBuffer(const fextl::string &Filepath, std::span Buffer) { +ssize_t LoadFileToBuffer(const fextl::string& Filepath, std::span Buffer) { std::ifstream f(Filepath, std::ios::binary | std::ios::ate); return f.readsome(Buffer.data(), Buffer.size()); } #endif -bool LoadFile(fextl::vector &Data, const fextl::string &Filepath, size_t FixedSize) { +bool LoadFile(fextl::vector& Data, const fextl::string& Filepath, size_t FixedSize) { return LoadFileImpl(Data, Filepath, FixedSize); } -bool LoadFile(fextl::string &Data, const fextl::string &Filepath, size_t FixedSize) { +bool LoadFile(fextl::string& Data, const fextl::string& Filepath, size_t FixedSize) { return LoadFileImpl(Data, Filepath, FixedSize); } -} +} // namespace FEXCore::FileLoading diff --git a/FEXCore/Source/Utils/ForcedAssert.cpp b/FEXCore/Source/Utils/ForcedAssert.cpp index e9f38c098..ef27f7182 100644 --- a/FEXCore/Source/Utils/ForcedAssert.cpp +++ b/FEXCore/Source/Utils/ForcedAssert.cpp @@ -1,15 +1,12 @@ // SPDX-License-Identifier: MIT namespace FEXCore::Assert { - // This function can not be inlined - [[noreturn]] - __attribute__((noinline, naked)) - void ForcedAssert() { +// This function can not be inlined +[[noreturn]] +__attribute__((noinline, naked)) void ForcedAssert() { #ifdef _M_X86_64 - asm volatile("ud2"); + asm volatile("ud2"); #else - asm volatile("hlt #1"); + asm volatile("hlt #1"); #endif - } } - - +} // namespace FEXCore::Assert diff --git a/FEXCore/Source/Utils/LogManager.cpp b/FEXCore/Source/Utils/LogManager.cpp index 74697f5ff..b0cfd75e2 100644 --- a/FEXCore/Source/Utils/LogManager.cpp +++ b/FEXCore/Source/Utils/LogManager.cpp @@ -17,33 +17,41 @@ $end_info$ namespace LogMan { namespace Throw { -fextl::vector Handlers; -void InstallHandler(ThrowHandler Handler) { Handlers.emplace_back(Handler); } -void UnInstallHandlers() { Handlers.clear(); } - -void MFmt(const char *fmt, const fmt::format_args& args) { - auto msg = fextl::fmt::vformat(fmt, args); - - for (auto& Handler : Handlers) { - Handler(msg.c_str()); + fextl::vector Handlers; + void InstallHandler(ThrowHandler Handler) { + Handlers.emplace_back(Handler); + } + void UnInstallHandlers() { + Handlers.clear(); } - FEX_TRAP_EXECUTION; -} + void MFmt(const char* fmt, const fmt::format_args& args) { + auto msg = fextl::fmt::vformat(fmt, args); + + for (auto& Handler : Handlers) { + Handler(msg.c_str()); + } + + FEX_TRAP_EXECUTION; + } } // namespace Throw namespace Msg { -fextl::vector Handlers; -void InstallHandler(MsgHandler Handler) { Handlers.emplace_back(Handler); } -void UnInstallHandlers() { Handlers.clear(); } + fextl::vector Handlers; + void InstallHandler(MsgHandler Handler) { + Handlers.emplace_back(Handler); + } + void UnInstallHandlers() { + Handlers.clear(); + } -void MFmtImpl(DebugLevels level, const char* fmt, const fmt::format_args& args) { - const auto msg = fextl::fmt::vformat(fmt, args); + void MFmtImpl(DebugLevels level, const char* fmt, const fmt::format_args& args) { + const auto msg = fextl::fmt::vformat(fmt, args); - for (auto& Handler : Handlers) { - Handler(level, msg.c_str()); + for (auto& Handler : Handlers) { + Handler(level, msg.c_str()); + } } -} } // namespace Msg } // namespace LogMan diff --git a/FEXCore/Source/Utils/MemberFunctionToPointer.h b/FEXCore/Source/Utils/MemberFunctionToPointer.h index 962dcac84..6d85ddb73 100644 --- a/FEXCore/Source/Utils/MemberFunctionToPointer.h +++ b/FEXCore/Source/Utils/MemberFunctionToPointer.h @@ -12,68 +12,72 @@ namespace FEXCore::Utils { * * Has additional validation to ensure we aren't casting a class member that is invalid */ -template +template class MemberFunctionToPointerCast final { - public: - MemberFunctionToPointerCast(PointerToMemberType Function) { - memcpy(&PMF, &Function, sizeof(PMF)); - } +public: + MemberFunctionToPointerCast(PointerToMemberType Function) { + memcpy(&PMF, &Function, sizeof(PMF)); + } - uintptr_t GetConvertedPointer() const { + uintptr_t GetConvertedPointer() const { #ifdef _M_X86_64 - // Itanium C++ ABI (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers) - // Low bit of ptr specifies if this Member function pointer is virtual or not - // Throw an assert if we were trying to cast a virtual member - LOGMAN_THROW_AA_FMT((PMF.ptr & 1) == 0, "C++ Pointer-To-Member representation didn't have low bit set to 0. Are you trying to cast a virtual member?"); + // Itanium C++ ABI (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers) + // Low bit of ptr specifies if this Member function pointer is virtual or not + // Throw an assert if we were trying to cast a virtual member + LOGMAN_THROW_AA_FMT((PMF.ptr & 1) == 0, "C++ Pointer-To-Member representation didn't have low bit set to 0. Are you trying to cast a " + "virtual member?"); #elif defined(_M_ARM_64) - // C++ ABI for the Arm 64-bit Architecture (IHI 0059E) - // 4.2.1 Representation of pointer to member function - // Differs from Itanium specification - LOGMAN_THROW_AA_FMT(PMF.adj == 0, "C++ Pointer-To-Member representation didn't have adj == 0. Are you trying to cast a virtual member?"); + // C++ ABI for the Arm 64-bit Architecture (IHI 0059E) + // 4.2.1 Representation of pointer to member function + // Differs from Itanium specification + LOGMAN_THROW_AA_FMT(PMF.adj == 0, "C++ Pointer-To-Member representation didn't have adj == 0. Are you trying to cast a virtual " + "member?"); #else #error Don't know how to cast Member to function here. Likely just Itanium #endif - return PMF.ptr; - } + return PMF.ptr; + } - // Gets the vtable entry position of a virtual member function. - size_t GetVTableOffset() const { + // Gets the vtable entry position of a virtual member function. + size_t GetVTableOffset() const { #ifdef _M_X86_64 - // Itanium C++ ABI (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers) - // Low bit of ptr specifies if this Member function pointer is virtual or not - // Throw an assert if we are not loading a virtual member. - LOGMAN_THROW_AA_FMT((PMF.ptr & 1) == 1, "C++ Pointer-To-Member representation didn't have low bit set to 1. This cast only works for virtual members."); - return PMF.ptr & ~1ULL; + // Itanium C++ ABI (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers) + // Low bit of ptr specifies if this Member function pointer is virtual or not + // Throw an assert if we are not loading a virtual member. + LOGMAN_THROW_AA_FMT((PMF.ptr & 1) == 1, "C++ Pointer-To-Member representation didn't have low bit set to 1. This cast only works for " + "virtual members."); + return PMF.ptr & ~1ULL; #elif defined(_M_ARM_64) - // C++ ABI for the Arm 64-bit Architecture (IHI 0059E) - // 4.2.1 Representation of pointer to member function - // Differs from Itanium specification - LOGMAN_THROW_AA_FMT((PMF.adj & 1) == 1, "C++ Pointer-To-Member representation didn't have adj == 1. This cast only works for virtual members."); - return PMF.ptr; + // C++ ABI for the Arm 64-bit Architecture (IHI 0059E) + // 4.2.1 Representation of pointer to member function + // Differs from Itanium specification + LOGMAN_THROW_AA_FMT((PMF.adj & 1) == 1, "C++ Pointer-To-Member representation didn't have adj == 1. This cast only works for virtual " + "members."); + return PMF.ptr; #else #error Don't know how to cast Member to function here. Likely just Itanium #endif - } + } - // Gets the pointer to the vtable entry for the object passed it. - template - uintptr_t GetVTableEntry(Class *VirtualClass) const { - // VTable is always stored at the beginning of a class object. - uintptr_t *VTable = *reinterpret_cast(VirtualClass); + // Gets the pointer to the vtable entry for the object passed it. + template + uintptr_t GetVTableEntry(Class* VirtualClass) const { + // VTable is always stored at the beginning of a class object. + uintptr_t* VTable = *reinterpret_cast(VirtualClass); - size_t Offset = GetVTableOffset() / sizeof(void*); - return VTable[Offset]; - } + size_t Offset = GetVTableOffset() / sizeof(void*); + return VTable[Offset]; + } - private: - struct PointerToMember { - uintptr_t ptr; - uintptr_t adj; - }; +private: + struct PointerToMember { + uintptr_t ptr; + uintptr_t adj; + }; - PointerToMember PMF; + PointerToMember PMF; - // Ensure the representation of PointerToMember matches - static_assert(sizeof(PMF) == sizeof(PointerToMemberType)); + // Ensure the representation of PointerToMember matches + static_assert(sizeof(PMF) == sizeof(PointerToMemberType)); }; -} +} // namespace FEXCore::Utils diff --git a/FEXCore/Source/Utils/Profiler.cpp b/FEXCore/Source/Utils/Profiler.cpp index eae497674..c48928aae 100644 --- a/FEXCore/Source/Utils/Profiler.cpp +++ b/FEXCore/Source/Utils/Profiler.cpp @@ -20,71 +20,70 @@ #ifdef ENABLE_FEXCORE_PROFILER #if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS namespace FEXCore::Profiler { - ProfilerBlock::ProfilerBlock(std::string_view const Format) - : DurationBegin {GetTime()} - , Format {Format} { - } +ProfilerBlock::ProfilerBlock(std::string_view const Format) + : DurationBegin {GetTime()} + , Format {Format} {} - ProfilerBlock::~ProfilerBlock() { - auto Duration = GetTime() - DurationBegin; - TraceObject(Format, Duration); - } +ProfilerBlock::~ProfilerBlock() { + auto Duration = GetTime() - DurationBegin; + TraceObject(Format, Duration); } +} // namespace FEXCore::Profiler namespace GPUVis { - // ftrace FD for writing trace data. - // Needs to be a raw FD since we hold this open for the entire application execution. - static int TraceFD {-1}; +// ftrace FD for writing trace data. +// Needs to be a raw FD since we hold this open for the entire application execution. +static int TraceFD {-1}; - // Need to search the paths to find the real trace path - static std::array TraceFSDirectories { - "/sys/kernel/tracing", - "/sys/kernel/debug/tracing", - }; +// Need to search the paths to find the real trace path +static std::array TraceFSDirectories { + "/sys/kernel/tracing", + "/sys/kernel/debug/tracing", +}; - static bool IsTraceFS(char const* Path) { - struct statfs stat; - if (statfs(Path, &stat)) { - return false; - } - return stat.f_type == TRACEFS_MAGIC; +static bool IsTraceFS(const char* Path) { + struct statfs stat; + if (statfs(Path, &stat)) { + return false; } + return stat.f_type == TRACEFS_MAGIC; +} - void Init() { - for (auto Path : TraceFSDirectories) { - if (IsTraceFS(Path)) { - fextl::string FilePath = fextl::fmt::format("{}/trace_marker", Path); - TraceFD = open(FilePath.c_str(), O_WRONLY | O_CLOEXEC); - if (TraceFD != -1) { - // Opened TraceFD, early exit - break; - } +void Init() { + for (auto Path : TraceFSDirectories) { + if (IsTraceFS(Path)) { + fextl::string FilePath = fextl::fmt::format("{}/trace_marker", Path); + TraceFD = open(FilePath.c_str(), O_WRONLY | O_CLOEXEC); + if (TraceFD != -1) { + // Opened TraceFD, early exit + break; } } } +} - void Shutdown() { - if (TraceFD != -1) { - close(TraceFD); - TraceFD = -1; - } - } - - void TraceObject(std::string_view const Format, uint64_t Duration) { - if (TraceFD != -1) { - // Print the duration as something that began negative duration ago - fextl::string Event = fextl::fmt::format("{} (lduration=-{})\n", Format, Duration); - write(TraceFD, Event.c_str(), Event.size()); - } - } - - void TraceObject(std::string_view const Format) { - if (TraceFD != -1) { - fextl::string Event = fextl::fmt::format("{}\n", Format); - write(TraceFD, Format.data(), Format.size()); - } +void Shutdown() { + if (TraceFD != -1) { + close(TraceFD); + TraceFD = -1; } } + +void TraceObject(std::string_view const Format, uint64_t Duration) { + if (TraceFD != -1) { + // Print the duration as something that began negative duration ago + fextl::string Event = fextl::fmt::format("{} (lduration=-{})\n", Format, Duration); + write(TraceFD, Event.c_str(), Event.size()); + } +} + +void TraceObject(std::string_view const Format) { + if (TraceFD != -1) { + fextl::string Event = fextl::fmt::format("{}\n", Format); + write(TraceFD, Format.data(), Format.size()); + } +} +} // namespace GPUVis #else #error Unknown profiler backend #endif @@ -92,29 +91,28 @@ namespace GPUVis { namespace FEXCore::Profiler { #ifdef ENABLE_FEXCORE_PROFILER - void Init() { +void Init() { #if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS - GPUVis::Init(); -#endif - } - - void Shutdown() { -#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS - GPUVis::Shutdown(); -#endif - } - - void TraceObject(std::string_view const Format, uint64_t Duration) { -#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS - GPUVis::TraceObject(Format, Duration); -#endif - } - - void TraceObject(std::string_view const Format) { -#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS - GPUVis::TraceObject(Format); -#endif - - } + GPUVis::Init(); #endif } + +void Shutdown() { +#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS + GPUVis::Shutdown(); +#endif +} + +void TraceObject(std::string_view const Format, uint64_t Duration) { +#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS + GPUVis::TraceObject(Format, Duration); +#endif +} + +void TraceObject(std::string_view const Format) { +#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS + GPUVis::TraceObject(Format); +#endif +} +#endif +} // namespace FEXCore::Profiler diff --git a/FEXCore/Source/Utils/SpinWaitLock.cpp b/FEXCore/Source/Utils/SpinWaitLock.cpp index b2f011ade..f6b2ff416 100644 --- a/FEXCore/Source/Utils/SpinWaitLock.cpp +++ b/FEXCore/Source/Utils/SpinWaitLock.cpp @@ -2,26 +2,25 @@ namespace FEXCore::Utils::SpinWaitLock { #ifdef _M_ARM_64 - constexpr uint64_t NanosecondsInSecond = 1'000'000'000ULL; +constexpr uint64_t NanosecondsInSecond = 1'000'000'000ULL; - static uint32_t GetCycleCounterFrequency() { - uint64_t Result{}; - __asm("mrs %[Res], CNTFRQ_EL0" - : [Res] "=r" (Result)); - return Result; - } - - static uint64_t CalculateCyclesPerNanosecond() { - // Snapdragon devices historically use a 19.2Mhz cycle counter frequency - // This means that the number of cycles per nanosecond ends up being 52.0833... - // - // ARMv8.6 and ARMv9.1 requires the cycle counter frequency to be 1Ghz. - // This means the number of cycles per nanosecond ends up being 1. - uint64_t CounterFrequency = GetCycleCounterFrequency(); - return NanosecondsInSecond / CounterFrequency; - } - - uint32_t CycleCounterFrequency = GetCycleCounterFrequency(); - uint64_t CyclesPerNanosecond = CalculateCyclesPerNanosecond(); -#endif +static uint32_t GetCycleCounterFrequency() { + uint64_t Result {}; + __asm("mrs %[Res], CNTFRQ_EL0" : [Res] "=r"(Result)); + return Result; } + +static uint64_t CalculateCyclesPerNanosecond() { + // Snapdragon devices historically use a 19.2Mhz cycle counter frequency + // This means that the number of cycles per nanosecond ends up being 52.0833... + // + // ARMv8.6 and ARMv9.1 requires the cycle counter frequency to be 1Ghz. + // This means the number of cycles per nanosecond ends up being 1. + uint64_t CounterFrequency = GetCycleCounterFrequency(); + return NanosecondsInSecond / CounterFrequency; +} + +uint32_t CycleCounterFrequency = GetCycleCounterFrequency(); +uint64_t CyclesPerNanosecond = CalculateCyclesPerNanosecond(); +#endif +} // namespace FEXCore::Utils::SpinWaitLock diff --git a/FEXCore/Source/Utils/SpinWaitLock.h b/FEXCore/Source/Utils/SpinWaitLock.h index ed821e22e..2b42848ba 100644 --- a/FEXCore/Source/Utils/SpinWaitLock.h +++ b/FEXCore/Source/Utils/SpinWaitLock.h @@ -4,297 +4,280 @@ #include namespace FEXCore::Utils::SpinWaitLock { - /** - * @brief This provides routines to implement implement an "efficient spin-loop" using ARM's WFE and exclusive monitor interfaces. - * - * Spin-loops on mobile devices with a battery can be a bad idea as they burn a bunch of power. This attempts to mitigate some of the impact - * by putting the CPU in to a lower-power state using WFE. - * On platforms tested, WFE will put the CPU in to a lower power state for upwards of 52ns per WFE. Which isn't a significant amount of time - * but should still have power savings. Ideally WFE would be able to keep the CPU in a lower power state for longer. This also has the added benefit - * that atomics aren't abusing the caches when spinning on a cacheline, which has knock-on powersaving benefits. - * - * FEAT_WFxT adds a new instruction with a timeout, but since the spurious wake-up is so aggressive it isn't worth using. - * - * It should be noted that this implementation has a few dozen cycles of start-up time. Which means the overhead for invoking this implementation is - * slightly higher than a true spin-loop. The hot loop body itself is only three instructions so it is quite efficient. - * - * On non-ARM platforms it is truly a spin-loop, which is okay for debugging only. - */ +/** + * @brief This provides routines to implement implement an "efficient spin-loop" using ARM's WFE and exclusive monitor interfaces. + * + * Spin-loops on mobile devices with a battery can be a bad idea as they burn a bunch of power. This attempts to mitigate some of the impact + * by putting the CPU in to a lower-power state using WFE. + * On platforms tested, WFE will put the CPU in to a lower power state for upwards of 52ns per WFE. Which isn't a significant amount of time + * but should still have power savings. Ideally WFE would be able to keep the CPU in a lower power state for longer. This also has the added + * benefit that atomics aren't abusing the caches when spinning on a cacheline, which has knock-on powersaving benefits. + * + * FEAT_WFxT adds a new instruction with a timeout, but since the spurious wake-up is so aggressive it isn't worth using. + * + * It should be noted that this implementation has a few dozen cycles of start-up time. Which means the overhead for invoking this + * implementation is slightly higher than a true spin-loop. The hot loop body itself is only three instructions so it is quite efficient. + * + * On non-ARM platforms it is truly a spin-loop, which is okay for debugging only. + */ #ifdef _M_ARM_64 #define LOADEXCLUSIVE(LoadExclusiveOp, RegSize) \ /* Prime the exclusive monitor with the passed in address. */ \ - #LoadExclusiveOp " %" #RegSize "[Result], [%[Futex]];" + #LoadExclusiveOp " %" #RegSize "[Result], [%[Futex]];" #define SPINLOOP_BODY(LoadAtomicOp, RegSize) \ /* WFE will wait for either the memory to change or spurious wake-up. */ \ - "wfe;" \ - /* Load with acquire to get the result of memory. */ \ - #LoadAtomicOp " %" #RegSize "[Result], [%[Futex]]; " + "wfe;" /* Load with acquire to get the result of memory. */ \ + #LoadAtomicOp " %" #RegSize "[Result], [%[Futex]]; " -#define SPINLOOP_WFE_LDX_8BIT LOADEXCLUSIVE(ldaxrb, w) +#define SPINLOOP_WFE_LDX_8BIT LOADEXCLUSIVE(ldaxrb, w) #define SPINLOOP_WFE_LDX_16BIT LOADEXCLUSIVE(ldaxrh, w) -#define SPINLOOP_WFE_LDX_32BIT LOADEXCLUSIVE(ldaxr, w) -#define SPINLOOP_WFE_LDX_64BIT LOADEXCLUSIVE(ldaxr, x) +#define SPINLOOP_WFE_LDX_32BIT LOADEXCLUSIVE(ldaxr, w) +#define SPINLOOP_WFE_LDX_64BIT LOADEXCLUSIVE(ldaxr, x) -#define SPINLOOP_8BIT SPINLOOP_BODY(ldarb, w) +#define SPINLOOP_8BIT SPINLOOP_BODY(ldarb, w) #define SPINLOOP_16BIT SPINLOOP_BODY(ldarh, w) -#define SPINLOOP_32BIT SPINLOOP_BODY(ldar, w) -#define SPINLOOP_64BIT SPINLOOP_BODY(ldar, x) +#define SPINLOOP_32BIT SPINLOOP_BODY(ldar, w) +#define SPINLOOP_64BIT SPINLOOP_BODY(ldar, x) - extern uint32_t CycleCounterFrequency; - extern uint64_t CyclesPerNanosecond; +extern uint32_t CycleCounterFrequency; +extern uint64_t CyclesPerNanosecond; - ///< Get the raw cycle counter which is synchronizing. - /// `CNTVCTSS_EL0` also does the same thing, but requires the FEAT_ECV feature. - static inline uint64_t GetCycleCounter() { - uint64_t Result{}; - __asm volatile(R"( +///< Get the raw cycle counter which is synchronizing. +/// `CNTVCTSS_EL0` also does the same thing, but requires the FEAT_ECV feature. +static inline uint64_t GetCycleCounter() { + uint64_t Result {}; + __asm volatile(R"( isb; mrs %[Res], CNTVCT_EL0; )" - : [Res] "=r" (Result)); - return Result; + : [Res] "=r"(Result)); + return Result; +} + +///< Converts nanoseconds to number of cycles. +/// If the cycle counter is 1Ghz then this is a direct 1:1 map. +static inline uint64_t ConvertNanosecondsToCycles(const std::chrono::nanoseconds& Nanoseconds) { + const auto NanosecondCount = Nanoseconds.count(); + return NanosecondCount / CyclesPerNanosecond; +} + +static inline uint8_t LoadExclusive(uint8_t* Futex) { + uint8_t Result {}; + __asm volatile(SPINLOOP_WFE_LDX_8BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +static inline uint16_t LoadExclusive(uint16_t* Futex) { + uint16_t Result {}; + __asm volatile(SPINLOOP_WFE_LDX_16BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +static inline uint32_t LoadExclusive(uint32_t* Futex) { + uint32_t Result {}; + __asm volatile(SPINLOOP_WFE_LDX_32BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +static inline uint64_t LoadExclusive(uint64_t* Futex) { + uint64_t Result {}; + __asm volatile(SPINLOOP_WFE_LDX_64BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +static inline uint8_t WFELoadAtomic(uint8_t* Futex) { + uint8_t Result {}; + __asm volatile(SPINLOOP_8BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +static inline uint16_t WFELoadAtomic(uint16_t* Futex) { + uint16_t Result {}; + __asm volatile(SPINLOOP_16BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +static inline uint32_t WFELoadAtomic(uint32_t* Futex) { + uint32_t Result {}; + __asm volatile(SPINLOOP_32BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +static inline uint64_t WFELoadAtomic(uint64_t* Futex) { + uint64_t Result {}; + __asm volatile(SPINLOOP_64BIT : [Result] "=r"(Result), [Futex] "+r"(Futex)::"memory"); + + return Result; +} + +template +static inline void Wait(T* Futex, TT ExpectedValue) { + std::atomic* AtomicFutex = reinterpret_cast*>(Futex); + T Result = AtomicFutex->load(); + + // Early exit if possible. + if (Result == ExpectedValue) { + return; } - ///< Converts nanoseconds to number of cycles. - /// If the cycle counter is 1Ghz then this is a direct 1:1 map. - static inline uint64_t ConvertNanosecondsToCycles(std::chrono::nanoseconds const &Nanoseconds) { - const auto NanosecondCount = Nanoseconds.count(); - return NanosecondCount / CyclesPerNanosecond; - } + do { + Result = LoadExclusive(Futex); + if (Result == ExpectedValue) { + return; + } + Result = WFELoadAtomic(Futex); + } while (Result != ExpectedValue); +} - static inline uint8_t LoadExclusive(uint8_t *Futex) { - uint8_t Result{}; - __asm volatile(SPINLOOP_WFE_LDX_8BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); +template void Wait(uint8_t*, uint8_t); +template void Wait(uint16_t*, uint16_t); +template void Wait(uint32_t*, uint32_t); +template void Wait(uint64_t*, uint64_t); - return Result; - } +template +static inline bool Wait(T* Futex, TT ExpectedValue, const std::chrono::nanoseconds& Timeout) { + std::atomic* AtomicFutex = reinterpret_cast*>(Futex); - static inline uint16_t LoadExclusive(uint16_t *Futex) { - uint16_t Result{}; - __asm volatile(SPINLOOP_WFE_LDX_16BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); + T Result = AtomicFutex->load(); - return Result; - } - - static inline uint32_t LoadExclusive(uint32_t *Futex) { - uint32_t Result{}; - __asm volatile(SPINLOOP_WFE_LDX_32BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); - - return Result; - } - - static inline uint64_t LoadExclusive(uint64_t *Futex) { - uint64_t Result{}; - __asm volatile(SPINLOOP_WFE_LDX_64BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); - - return Result; - } - - static inline uint8_t WFELoadAtomic(uint8_t *Futex) { - uint8_t Result{}; - __asm volatile(SPINLOOP_8BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); - - return Result; - } - - static inline uint16_t WFELoadAtomic(uint16_t *Futex) { - uint16_t Result{}; - __asm volatile(SPINLOOP_16BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); - - return Result; - } - - static inline uint32_t WFELoadAtomic(uint32_t *Futex) { - uint32_t Result{}; - __asm volatile(SPINLOOP_32BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); - - return Result; - } - - static inline uint64_t WFELoadAtomic(uint64_t *Futex) { - uint64_t Result{}; - __asm volatile(SPINLOOP_64BIT - : [Result] "=r" (Result) - , [Futex] "+r" (Futex) - :: "memory"); - - return Result; - } - - template - static inline void Wait(T *Futex, TT ExpectedValue) { - std::atomic *AtomicFutex = reinterpret_cast*>(Futex); - T Result = AtomicFutex->load(); - - // Early exit if possible. - if (Result == ExpectedValue) return; - - do { - Result = LoadExclusive(Futex); - if (Result == ExpectedValue) return; - Result = WFELoadAtomic(Futex); - } while (Result != ExpectedValue); - } - - template - void Wait(uint8_t*, uint8_t); - template - void Wait(uint16_t*, uint16_t); - template - void Wait(uint32_t*, uint32_t); - template - void Wait(uint64_t*, uint64_t); - - template - static inline bool Wait(T *Futex, TT ExpectedValue, std::chrono::nanoseconds const &Timeout) { - std::atomic *AtomicFutex = reinterpret_cast*>(Futex); - - T Result = AtomicFutex->load(); - - // Early exit if possible. - if (Result == ExpectedValue) return true; - - const auto TimeoutCycles = ConvertNanosecondsToCycles(Timeout); - const auto Begin = GetCycleCounter(); - - do { - Result = LoadExclusive(Futex); - if (Result == ExpectedValue) return true; - Result = WFELoadAtomic(Futex); - - const auto CurrentCycleCounter = GetCycleCounter(); - if ((CurrentCycleCounter - Begin) >= TimeoutCycles) { - // Couldn't get value before timeout. - return false; - } - } while (Result != ExpectedValue); - - // We got our result. + // Early exit if possible. + if (Result == ExpectedValue) { return true; } - template - bool Wait(uint8_t*, uint8_t, std::chrono::nanoseconds const &); - template - bool Wait(uint16_t*, uint16_t, std::chrono::nanoseconds const &); - template - bool Wait(uint32_t*, uint32_t, std::chrono::nanoseconds const &); - template - bool Wait(uint64_t*, uint64_t, std::chrono::nanoseconds const &); + const auto TimeoutCycles = ConvertNanosecondsToCycles(Timeout); + const auto Begin = GetCycleCounter(); + + do { + Result = LoadExclusive(Futex); + if (Result == ExpectedValue) { + return true; + } + Result = WFELoadAtomic(Futex); + + const auto CurrentCycleCounter = GetCycleCounter(); + if ((CurrentCycleCounter - Begin) >= TimeoutCycles) { + // Couldn't get value before timeout. + return false; + } + } while (Result != ExpectedValue); + + // We got our result. + return true; +} + +template bool Wait(uint8_t*, uint8_t, const std::chrono::nanoseconds&); +template bool Wait(uint16_t*, uint16_t, const std::chrono::nanoseconds&); +template bool Wait(uint32_t*, uint32_t, const std::chrono::nanoseconds&); +template bool Wait(uint64_t*, uint64_t, const std::chrono::nanoseconds&); #else - template - static inline void Wait(T *Futex, TT ExpectedValue) { - std::atomic *AtomicFutex = reinterpret_cast*>(Futex); - T Result = AtomicFutex->load(); +template +static inline void Wait(T* Futex, TT ExpectedValue) { + std::atomic* AtomicFutex = reinterpret_cast*>(Futex); + T Result = AtomicFutex->load(); - // Early exit if possible. - if (Result == ExpectedValue) return; - - do { - Result = AtomicFutex->load(); - } while (Result != ExpectedValue); + // Early exit if possible. + if (Result == ExpectedValue) { + return; } - template - static inline bool Wait(T *Futex, TT ExpectedValue, std::chrono::nanoseconds const &Timeout) { - std::atomic *AtomicFutex = reinterpret_cast*>(Futex); + do { + Result = AtomicFutex->load(); + } while (Result != ExpectedValue); +} - T Result = AtomicFutex->load(); +template +static inline bool Wait(T* Futex, TT ExpectedValue, const std::chrono::nanoseconds& Timeout) { + std::atomic* AtomicFutex = reinterpret_cast*>(Futex); - // Early exit if possible. - if (Result == ExpectedValue) return true; + T Result = AtomicFutex->load(); - const auto Begin = std::chrono::high_resolution_clock::now(); - - do { - Result = AtomicFutex->load(); - - const auto CurrentCycleCounter = std::chrono::high_resolution_clock::now(); - if ((CurrentCycleCounter - Begin) >= Timeout) { - // Couldn't get value before timeout. - return false; - } - } while (Result != ExpectedValue); - - // We got our result. + // Early exit if possible. + if (Result == ExpectedValue) { return true; } + + const auto Begin = std::chrono::high_resolution_clock::now(); + + do { + Result = AtomicFutex->load(); + + const auto CurrentCycleCounter = std::chrono::high_resolution_clock::now(); + if ((CurrentCycleCounter - Begin) >= Timeout) { + // Couldn't get value before timeout. + return false; + } + } while (Result != ExpectedValue); + + // We got our result. + return true; +} #endif - template - static inline void lock(T *Futex) { - std::atomic *AtomicFutex = reinterpret_cast*>(Futex); - T Expected{}; - T Desired {1}; +template +static inline void lock(T* Futex) { + std::atomic* AtomicFutex = reinterpret_cast*>(Futex); + T Expected {}; + T Desired {1}; - // Try to CAS immediately. - if (AtomicFutex->compare_exchange_strong(Expected, Desired)) return; - - do { - // Wait until the futex is unlocked. - Wait(Futex, 0); - Expected = 0; - } while (!AtomicFutex->compare_exchange_strong(Expected, Desired)); + // Try to CAS immediately. + if (AtomicFutex->compare_exchange_strong(Expected, Desired)) { + return; } - template - static inline bool try_lock(T *Futex) { - std::atomic *AtomicFutex = reinterpret_cast*>(Futex); - T Expected{}; - T Desired {1}; + do { + // Wait until the futex is unlocked. + Wait(Futex, 0); + Expected = 0; + } while (!AtomicFutex->compare_exchange_strong(Expected, Desired)); +} - // Try to CAS immediately. - if (AtomicFutex->compare_exchange_strong(Expected, Desired)) return true; +template +static inline bool try_lock(T* Futex) { + std::atomic* AtomicFutex = reinterpret_cast*>(Futex); + T Expected {}; + T Desired {1}; - return false; + // Try to CAS immediately. + if (AtomicFutex->compare_exchange_strong(Expected, Desired)) { + return true; } - template - static inline void unlock(T *Futex) { - std::atomic *AtomicFutex = reinterpret_cast*>(Futex); - AtomicFutex->store(0); - } + return false; +} + +template +static inline void unlock(T* Futex) { + std::atomic* AtomicFutex = reinterpret_cast*>(Futex); + AtomicFutex->store(0); +} #undef SPINLOOP_8BIT #undef SPINLOOP_16BIT #undef SPINLOOP_32BIT #undef SPINLOOP_64BIT - template - class UniqueSpinMutex final { - public: - UniqueSpinMutex(T *Futex) - : Futex {Futex} { - FEXCore::Utils::SpinWaitLock::lock(Futex); - } +template +class UniqueSpinMutex final { +public: + UniqueSpinMutex(T* Futex) + : Futex {Futex} { + FEXCore::Utils::SpinWaitLock::lock(Futex); + } - ~UniqueSpinMutex() { - FEXCore::Utils::SpinWaitLock::unlock(Futex); - } - private: - T *Futex; - }; -} + ~UniqueSpinMutex() { + FEXCore::Utils::SpinWaitLock::unlock(Futex); + } +private: + T* Futex; +}; +} // namespace FEXCore::Utils::SpinWaitLock diff --git a/FEXCore/Source/Utils/Telemetry.cpp b/FEXCore/Source/Utils/Telemetry.cpp index 411620325..d6e124d03 100644 --- a/FEXCore/Source/Utils/Telemetry.cpp +++ b/FEXCore/Source/Utils/Telemetry.cpp @@ -16,75 +16,72 @@ namespace FEXCore::Telemetry { #ifndef FEX_DISABLE_TELEMETRY - static std::array TelemetryValues = {{ }}; - const std::array TelemetryNames { - "64byte Split Locks", - "16byte Split atomics", - "VEX instructions (AVX)", - "EVEX instructions (AVX512)", - "16bit CAS Tear", - "32bit CAS Tear", - "64bit CAS Tear", - "128bit CAS Tear", - "Crash mask", - "Write 32-bit Segment ES", - "Write 32-bit Segment SS", - "Write 32-bit Segment CS", - "Write 32-bit Segment DS", - "Uses 32-bit Segment ES", - "Uses 32-bit Segment SS", - "Uses 32-bit Segment CS", - "Uses 32-bit Segment DS", - "Non-Canonical 64-bit address access", - }; +static std::array TelemetryValues = {{}}; +const std::array TelemetryNames { + "64byte Split Locks", + "16byte Split atomics", + "VEX instructions (AVX)", + "EVEX instructions (AVX512)", + "16bit CAS Tear", + "32bit CAS Tear", + "64bit CAS Tear", + "128bit CAS Tear", + "Crash mask", + "Write 32-bit Segment ES", + "Write 32-bit Segment SS", + "Write 32-bit Segment CS", + "Write 32-bit Segment DS", + "Uses 32-bit Segment ES", + "Uses 32-bit Segment SS", + "Uses 32-bit Segment CS", + "Uses 32-bit Segment DS", + "Non-Canonical 64-bit address access", +}; - static bool Enabled {true}; - void Initialize() { - FEX_CONFIG_OPT(DisableTelemetry, DISABLETELEMETRY); - if (DisableTelemetry) { - Enabled = false; - return; - } - - auto DataDirectory = Config::GetTelemetryDirectory(); - - // Ensure the folder structure is created for our configuration - if (!FHU::Filesystem::Exists(DataDirectory) && - !FHU::Filesystem::CreateDirectories(DataDirectory)) { - LogMan::Msg::IFmt("Couldn't create telemetry Folder"); - } +static bool Enabled {true}; +void Initialize() { + FEX_CONFIG_OPT(DisableTelemetry, DISABLETELEMETRY); + if (DisableTelemetry) { + Enabled = false; + return; } - void Shutdown(fextl::string const &ApplicationName) { - if (!Enabled) { - return; - } + auto DataDirectory = Config::GetTelemetryDirectory(); - auto DataDirectory = Config::GetTelemetryDirectory() + ApplicationName + ".telem"; - - // Retain a single backup if the telemetry already existed. - auto Backup = DataDirectory + ".bck"; - - // Failure on rename is okay. - (void)FHU::Filesystem::RenameFile(DataDirectory, Backup); - - auto File = FEXCore::File::File(DataDirectory.c_str(), - FEXCore::File::FileModes::WRITE | - FEXCore::File::FileModes::CREATE | - FEXCore::File::FileModes::TRUNCATE); - - if (File.IsValid()) { - for (size_t i = 0; i < TelemetryType::TYPE_LAST; ++i) { - auto &Name = TelemetryNames.at(i); - auto &Data = TelemetryValues.at(i); - fextl::fmt::print(File, "{}: {}\n", Name, *Data); - } - File.Flush(); - } + // Ensure the folder structure is created for our configuration + if (!FHU::Filesystem::Exists(DataDirectory) && !FHU::Filesystem::CreateDirectories(DataDirectory)) { + LogMan::Msg::IFmt("Couldn't create telemetry Folder"); } - - Value &GetTelemetryValue(TelemetryType Type) { - return TelemetryValues.at(Type); - } -#endif } + +void Shutdown(const fextl::string& ApplicationName) { + if (!Enabled) { + return; + } + + auto DataDirectory = Config::GetTelemetryDirectory() + ApplicationName + ".telem"; + + // Retain a single backup if the telemetry already existed. + auto Backup = DataDirectory + ".bck"; + + // Failure on rename is okay. + (void)FHU::Filesystem::RenameFile(DataDirectory, Backup); + + auto File = FEXCore::File::File(DataDirectory.c_str(), + FEXCore::File::FileModes::WRITE | FEXCore::File::FileModes::CREATE | FEXCore::File::FileModes::TRUNCATE); + + if (File.IsValid()) { + for (size_t i = 0; i < TelemetryType::TYPE_LAST; ++i) { + auto& Name = TelemetryNames.at(i); + auto& Data = TelemetryValues.at(i); + fextl::fmt::print(File, "{}: {}\n", Name, *Data); + } + File.Flush(); + } +} + +Value& GetTelemetryValue(TelemetryType Type) { + return TelemetryValues.at(Type); +} +#endif +} // namespace FEXCore::Telemetry diff --git a/FEXCore/Source/Utils/Threads.cpp b/FEXCore/Source/Utils/Threads.cpp index 1e826f84e..828faf728 100644 --- a/FEXCore/Source/Utils/Threads.cpp +++ b/FEXCore/Source/Utils/Threads.cpp @@ -18,47 +18,43 @@ #endif namespace FEXCore::Threads { - fextl::unique_ptr CreateThread_Default( - ThreadFunc Func, - void* Arg) { - ERROR_AND_DIE_FMT("Frontend didn't setup thread creation!"); - } +fextl::unique_ptr CreateThread_Default(ThreadFunc Func, void* Arg) { + ERROR_AND_DIE_FMT("Frontend didn't setup thread creation!"); +} - void CleanupAfterFork_Default() { - ERROR_AND_DIE_FMT("Frontend didn't setup thread creation!"); - } +void CleanupAfterFork_Default() { + ERROR_AND_DIE_FMT("Frontend didn't setup thread creation!"); +} - static FEXCore::Threads::Pointers Ptrs = { - .CreateThread = CreateThread_Default, - .CleanupAfterFork = CleanupAfterFork_Default, - }; +static FEXCore::Threads::Pointers Ptrs = { + .CreateThread = CreateThread_Default, + .CleanupAfterFork = CleanupAfterFork_Default, +}; - fextl::unique_ptr FEXCore::Threads::Thread::Create( - ThreadFunc Func, - void* Arg) { - return Ptrs.CreateThread(Func, Arg); - } +fextl::unique_ptr FEXCore::Threads::Thread::Create(ThreadFunc Func, void* Arg) { + return Ptrs.CreateThread(Func, Arg); +} - void FEXCore::Threads::Thread::CleanupAfterFork() { - return Ptrs.CleanupAfterFork(); - } +void FEXCore::Threads::Thread::CleanupAfterFork() { + return Ptrs.CleanupAfterFork(); +} - void FEXCore::Threads::Thread::SetInternalPointers(Pointers const &_Ptrs) { - memcpy(&Ptrs, &_Ptrs, sizeof(FEXCore::Threads::Pointers)); - } +void FEXCore::Threads::Thread::SetInternalPointers(const Pointers& _Ptrs) { + memcpy(&Ptrs, &_Ptrs, sizeof(FEXCore::Threads::Pointers)); +} - uint64_t SetSignalMask(uint64_t Mask) { +uint64_t SetSignalMask(uint64_t Mask) { #ifndef _WIN32 - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &Mask, 8); - return Mask; + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &Mask, 8); + return Mask; #endif - } +} - void SetThreadName(const char *name) { +void SetThreadName(const char* name) { #ifndef _WIN32 pthread_setname_np(pthread_self(), name); #else // TODO: #endif - } } +} // namespace FEXCore::Threads diff --git a/FEXCore/include/FEXCore/Config/Config.h b/FEXCore/include/FEXCore/Config/Config.h index 38c2aa535..fec86a984 100644 --- a/FEXCore/include/FEXCore/Config/Config.h +++ b/FEXCore/include/FEXCore/Config/Config.h @@ -19,109 +19,110 @@ namespace FEXCore::Config { namespace Handler { static inline std::optional CoreHandler(std::string_view Value) { - if (Value == "irjit") + if (Value == "irjit") { return "0"; + } #ifdef _M_X86_64 - else if (Value == "host") + else if (Value == "host") { return "1"; + } #endif return "0"; } static inline std::optional SMCCheckHandler(std::string_view Value) { - if (Value == "none") + if (Value == "none") { return "0"; - else if (Value == "mtrack") + } else if (Value == "mtrack") { return "1"; - else if (Value == "full") + } else if (Value == "full") { return "2"; + } return "0"; } static inline std::optional CacheObjectCodeHandler(std::string_view Value) { - if (Value == "none") + if (Value == "none") { return "0"; - else if (Value == "read") + } else if (Value == "read") { return "1"; - else if (Value == "write") + } else if (Value == "write") { return "2"; + } return "0"; } -} +} // namespace Handler - enum ConfigOption { +enum ConfigOption { #define OPT_BASE(type, group, enum, json, default) CONFIG_##enum, #include - }; +}; #define ENUMDEFINES #include - enum ConfigCore { - CONFIG_IRJIT, - CONFIG_CUSTOM, - }; +enum ConfigCore { + CONFIG_IRJIT, + CONFIG_CUSTOM, +}; - enum ConfigSMCChecks { - CONFIG_SMC_NONE, - CONFIG_SMC_MTRACK, - CONFIG_SMC_FULL, - }; +enum ConfigSMCChecks { + CONFIG_SMC_NONE, + CONFIG_SMC_MTRACK, + CONFIG_SMC_FULL, +}; - enum ConfigObjectCodeHandler { - CONFIG_NONE, - CONFIG_READ, - CONFIG_READWRITE, - }; +enum ConfigObjectCodeHandler { + CONFIG_NONE, + CONFIG_READ, + CONFIG_READWRITE, +}; - enum class LayerType { - LAYER_GLOBAL_MAIN, ///< /usr/share/fex-emu/Config.json by default - LAYER_MAIN, - LAYER_ARGUMENTS, - LAYER_GLOBAL_STEAM_APP, - LAYER_GLOBAL_APP, - LAYER_LOCAL_STEAM_APP, - LAYER_LOCAL_APP, - LAYER_USER_OVERRIDE, - LAYER_ENVIRONMENT, - LAYER_TOP, - }; +enum class LayerType { + LAYER_GLOBAL_MAIN, ///< /usr/share/fex-emu/Config.json by default + LAYER_MAIN, + LAYER_ARGUMENTS, + LAYER_GLOBAL_STEAM_APP, + LAYER_GLOBAL_APP, + LAYER_LOCAL_STEAM_APP, + LAYER_LOCAL_APP, + LAYER_USER_OVERRIDE, + LAYER_ENVIRONMENT, + LAYER_TOP, +}; - template - static inline std::optional EnumParser(ArrayPairType const &EnumPairs, std::string_view const View) { - uint64_t EnumMask{}; - auto Results = std::from_chars(View.data(), View.data() + View.size(), EnumMask); - if (Results.ec == std::errc()) { - // If the data is a valid number, just pass it through. - return std::nullopt; - } - - auto Begin = 0; - auto End = View.find_first_of(','); - std::string_view Option = View.substr(Begin, End); - while (Option.size() != 0) { - auto EnumValue = std::find_if(EnumPairs.begin(), EnumPairs.end(), - [Option](const PairTypes &Value) -> bool { - return Value.first == Option; - }); - - if (EnumValue == EnumPairs.end()) { - LogMan::Msg::IFmt("Skipping Unknown option: {}", Option); - } - else { - EnumMask |= FEXCore::ToUnderlying(EnumValue->second); - } - - if (End == std::string::npos) { - break; - } - Begin = End + 1; - End = View.find_first_of(',', Begin); - Option = View.substr(Begin, End - Begin); - } - - return fextl::fmt::format("{}", EnumMask); +template +static inline std::optional EnumParser(const ArrayPairType& EnumPairs, std::string_view const View) { + uint64_t EnumMask {}; + auto Results = std::from_chars(View.data(), View.data() + View.size(), EnumMask); + if (Results.ec == std::errc()) { + // If the data is a valid number, just pass it through. + return std::nullopt; } + auto Begin = 0; + auto End = View.find_first_of(','); + std::string_view Option = View.substr(Begin, End); + while (Option.size() != 0) { + auto EnumValue = + std::find_if(EnumPairs.begin(), EnumPairs.end(), [Option](const PairTypes& Value) -> bool { return Value.first == Option; }); + + if (EnumValue == EnumPairs.end()) { + LogMan::Msg::IFmt("Skipping Unknown option: {}", Option); + } else { + EnumMask |= FEXCore::ToUnderlying(EnumValue->second); + } + + if (End == std::string::npos) { + break; + } + Begin = End + 1; + End = View.find_first_of(',', Begin); + Option = View.substr(Begin, End - Begin); + } + + return fextl::fmt::format("{}", EnumMask); +} + namespace DefaultValues { #define P(x) x #define OPT_BASE(type, group, enum, json, default) extern const P(type) P(enum); @@ -129,178 +130,200 @@ namespace DefaultValues { #define OPT_STRARRAY(group, enum, json, default) OPT_STR(group, enum, json, default) #include -namespace Type { + namespace Type { #define OPT_BASE(type, group, enum, json, default) using P(enum) = P(type); #define OPT_STR(group, enum, json, default) using P(enum) = fextl::string; #define OPT_STRARRAY(group, enum, json, default) OPT_STR(group, enum, json, default) #include -} + } // namespace Type #define FEX_CONFIG_OPT(name, enum) \ - FEXCore::Config::Value name {FEXCore::Config::CONFIG_##enum, FEXCore::Config::DefaultValues::enum} + FEXCore::Config::Value name { \ + FEXCore::Config::CONFIG_##enum, \ + FEXCore::Config::DefaultValues::enum \ + } #undef P -} +} // namespace DefaultValues - FEX_DEFAULT_VISIBILITY void SetDataDirectory(std::string_view Path); - FEX_DEFAULT_VISIBILITY void SetConfigDirectory(const std::string_view Path, bool Global); - FEX_DEFAULT_VISIBILITY void SetConfigFileLocation(std::string_view Path, bool Global); +FEX_DEFAULT_VISIBILITY void SetDataDirectory(std::string_view Path); +FEX_DEFAULT_VISIBILITY void SetConfigDirectory(const std::string_view Path, bool Global); +FEX_DEFAULT_VISIBILITY void SetConfigFileLocation(std::string_view Path, bool Global); - FEX_DEFAULT_VISIBILITY fextl::string const& GetDataDirectory(); - FEX_DEFAULT_VISIBILITY fextl::string const& GetConfigDirectory(bool Global); - FEX_DEFAULT_VISIBILITY fextl::string const& GetConfigFileLocation(bool Global = false); - FEX_DEFAULT_VISIBILITY fextl::string GetApplicationConfig(const std::string_view Program, bool Global); +FEX_DEFAULT_VISIBILITY const fextl::string& GetDataDirectory(); +FEX_DEFAULT_VISIBILITY const fextl::string& GetConfigDirectory(bool Global); +FEX_DEFAULT_VISIBILITY const fextl::string& GetConfigFileLocation(bool Global = false); +FEX_DEFAULT_VISIBILITY fextl::string GetApplicationConfig(const std::string_view Program, bool Global); - using LayerValue = fextl::list; - using LayerOptions = fextl::unordered_map; +using LayerValue = fextl::list; +using LayerOptions = fextl::unordered_map; - class FEX_DEFAULT_VISIBILITY Layer { - public: - explicit Layer(const LayerType _Type); - virtual ~Layer(); +class FEX_DEFAULT_VISIBILITY Layer { +public: + explicit Layer(const LayerType _Type); + virtual ~Layer(); - virtual void Load() = 0; + virtual void Load() = 0; - bool OptionExists(ConfigOption Option) const { - return OptionMap.find(Option) != OptionMap.end(); + bool OptionExists(ConfigOption Option) const { + return OptionMap.find(Option) != OptionMap.end(); + } + + std::optional All(ConfigOption Option) { + const auto it = OptionMap.find(Option); + if (it == OptionMap.end()) { + return std::nullopt; } - std::optional - All(ConfigOption Option) { - const auto it = OptionMap.find(Option); - if (it == OptionMap.end()) { - return std::nullopt; - } + return &it->second; + } - return &it->second; + std::optional Get(ConfigOption Option) { + const auto it = OptionMap.find(Option); + if (it == OptionMap.end()) { + return std::nullopt; } - std::optional - Get(ConfigOption Option) { - const auto it = OptionMap.find(Option); - if (it == OptionMap.end()) { - return std::nullopt; - } + return &it->second.front(); + } - return &it->second.front(); + void Set(ConfigOption Option, const char* Data) { + OptionMap[Option].emplace_back(fextl::string(Data)); + } + + void Set(ConfigOption Option, std::string_view Data) { + OptionMap[Option].emplace_back(fextl::string(Data)); + } + + void Set(ConfigOption Option, fextl::string Data) { + OptionMap[Option].emplace_back(std::move(Data)); + } + + void Set(ConfigOption Option, std::optional Data) { + if (Data) { + OptionMap[Option].emplace_back(std::move(*Data)); + } + } + + void EraseSet(ConfigOption Option, std::string_view Data) { + Erase(Option); + Set(Option, Data); + } + + void Erase(ConfigOption Option) { + OptionMap.erase(Option); + } + + LayerType GetLayerType() const { + return Type; + } + const LayerOptions& GetOptionMap() const { + return OptionMap; + } + +protected: + const LayerType Type; + LayerOptions OptionMap; +}; + +FEX_DEFAULT_VISIBILITY void Initialize(); +FEX_DEFAULT_VISIBILITY void Shutdown(); + +FEX_DEFAULT_VISIBILITY void Load(); +FEX_DEFAULT_VISIBILITY void ReloadMetaLayer(); +FEX_DEFAULT_VISIBILITY fextl::string FindContainer(); +FEX_DEFAULT_VISIBILITY fextl::string FindContainerPrefix(); + +FEX_DEFAULT_VISIBILITY void AddLayer(fextl::unique_ptr _Layer); + +FEX_DEFAULT_VISIBILITY bool Exists(ConfigOption Option); +FEX_DEFAULT_VISIBILITY std::optional All(ConfigOption Option); +FEX_DEFAULT_VISIBILITY std::optional Get(ConfigOption Option); + +FEX_DEFAULT_VISIBILITY void Set(ConfigOption Option, std::string_view Data); +FEX_DEFAULT_VISIBILITY void Erase(ConfigOption Option); +FEX_DEFAULT_VISIBILITY void EraseSet(ConfigOption Option, std::string_view Data); + +template +class FEX_DEFAULT_VISIBILITY Value { +public: + template + requires (!std::is_same_v) + Value(FEXCore::Config::ConfigOption _Option, TT Default) + : Option {_Option} { + ValueData = GetIfExists(Option, Default); + } + + template + requires (std::is_same_v) + Value(FEXCore::Config::ConfigOption _Option, TT Default) + : Option {_Option} { + ValueData = GetIfExists(Option, Default); + GetListIfExists(Option, &AppendList); + } + + template + requires (std::is_same_v) + Value(FEXCore::Config::ConfigOption _Option, std::string_view Default) + : Option {_Option} { + ValueData = GetIfExists(Option, Default); + GetListIfExists(Option, &AppendList); + } + + template + requires (!std::is_same_v) + Value(FEXCore::Config::ConfigOption _Option) + : Option {_Option} { + if (!FEXCore::Config::Exists(Option)) { + ERROR_AND_DIE_FMT("FEXCore::Config::Value has no value"); } - void Set(ConfigOption Option, const char *Data) { - OptionMap[Option].emplace_back(fextl::string(Data)); + ValueData = Get(Option); + } + + template + requires (std::is_same_v) + Value(FEXCore::Config::ConfigOption _Option) + : Option {_Option} { + if (!FEXCore::Config::Exists(Option)) { + ERROR_AND_DIE_FMT("FEXCore::Config::Value has no value"); } - void Set(ConfigOption Option, std::string_view Data) { - OptionMap[Option].emplace_back(fextl::string(Data)); - } + ValueData = GetIfExists(Option); + GetListIfExists(Option, &AppendList); + } - void Set(ConfigOption Option, fextl::string Data) { - OptionMap[Option].emplace_back(std::move(Data)); - } + operator T() const { + return ValueData; + } - void Set(ConfigOption Option, std::optional Data) { - if (Data) { - OptionMap[Option].emplace_back(std::move(*Data)); - } - } + template + requires (!std::is_same_v) + T operator()() const { + return ValueData; + } - void EraseSet(ConfigOption Option, std::string_view Data) { - Erase(Option); - Set(Option, Data); - } + template + requires (std::is_same_v) + const T& operator()() const { + return ValueData; + } - void Erase(ConfigOption Option) { - OptionMap.erase(Option); - } + Value(T Value) { + ValueData = std::move(Value); + } + fextl::list& All() { + return AppendList; + } - LayerType GetLayerType() const { return Type; } - const LayerOptions &GetOptionMap() const { return OptionMap; } +private: + FEXCore::Config::ConfigOption Option; + T ValueData; + fextl::list AppendList; - protected: - const LayerType Type; - LayerOptions OptionMap; - }; + static T Get(FEXCore::Config::ConfigOption Option); + static T GetIfExists(FEXCore::Config::ConfigOption Option, T Default); + static T GetIfExists(FEXCore::Config::ConfigOption Option, std::string_view Default); - FEX_DEFAULT_VISIBILITY void Initialize(); - FEX_DEFAULT_VISIBILITY void Shutdown(); - - FEX_DEFAULT_VISIBILITY void Load(); - FEX_DEFAULT_VISIBILITY void ReloadMetaLayer(); - FEX_DEFAULT_VISIBILITY fextl::string FindContainer(); - FEX_DEFAULT_VISIBILITY fextl::string FindContainerPrefix(); - - FEX_DEFAULT_VISIBILITY void AddLayer(fextl::unique_ptr _Layer); - - FEX_DEFAULT_VISIBILITY bool Exists(ConfigOption Option); - FEX_DEFAULT_VISIBILITY std::optional All(ConfigOption Option); - FEX_DEFAULT_VISIBILITY std::optional Get(ConfigOption Option); - - FEX_DEFAULT_VISIBILITY void Set(ConfigOption Option, std::string_view Data); - FEX_DEFAULT_VISIBILITY void Erase(ConfigOption Option); - FEX_DEFAULT_VISIBILITY void EraseSet(ConfigOption Option, std::string_view Data); - - template - class FEX_DEFAULT_VISIBILITY Value { - public: - template requires (!std::is_same_v) - Value(FEXCore::Config::ConfigOption _Option, TT Default) - : Option {_Option} { - ValueData = GetIfExists(Option, Default); - } - - template requires (std::is_same_v) - Value(FEXCore::Config::ConfigOption _Option, TT Default) - : Option {_Option} { - ValueData = GetIfExists(Option, Default); - GetListIfExists(Option, &AppendList); - } - - template requires (std::is_same_v) - Value(FEXCore::Config::ConfigOption _Option, std::string_view Default) - : Option {_Option} { - ValueData = GetIfExists(Option, Default); - GetListIfExists(Option, &AppendList); - } - - template requires (!std::is_same_v) - Value(FEXCore::Config::ConfigOption _Option) - : Option {_Option} { - if (!FEXCore::Config::Exists(Option)) { - ERROR_AND_DIE_FMT("FEXCore::Config::Value has no value"); - } - - ValueData = Get(Option); - } - - template requires (std::is_same_v) - Value(FEXCore::Config::ConfigOption _Option) - : Option {_Option} { - if (!FEXCore::Config::Exists(Option)) { - ERROR_AND_DIE_FMT("FEXCore::Config::Value has no value"); - } - - ValueData = GetIfExists(Option); - GetListIfExists(Option, &AppendList); - } - - operator T() const { return ValueData; } - - template requires (!std::is_same_v) - T operator()() const { return ValueData; } - - template requires (std::is_same_v) - const T& operator()() const { return ValueData; } - - Value(T Value) { ValueData = std::move(Value); } - fextl::list &All() { return AppendList; } - - private: - FEXCore::Config::ConfigOption Option; - T ValueData; - fextl::list AppendList; - - static T Get(FEXCore::Config::ConfigOption Option); - static T GetIfExists(FEXCore::Config::ConfigOption Option, T Default); - static T GetIfExists(FEXCore::Config::ConfigOption Option, std::string_view Default); - - static void GetListIfExists(FEXCore::Config::ConfigOption Option, fextl::list *List); - }; -} + static void GetListIfExists(FEXCore::Config::ConfigOption Option, fextl::list* List); +}; +} // namespace FEXCore::Config diff --git a/FEXCore/include/FEXCore/Core/CPUID.h b/FEXCore/include/FEXCore/Core/CPUID.h index 9f1f7b45a..0e3c77f73 100644 --- a/FEXCore/include/FEXCore/Core/CPUID.h +++ b/FEXCore/include/FEXCore/Core/CPUID.h @@ -3,12 +3,11 @@ #include namespace FEXCore::CPUID { - struct FunctionResults { - uint32_t eax, ebx, ecx, edx; - }; - - struct XCRResults { - uint32_t eax, edx; - }; -} +struct FunctionResults { + uint32_t eax, ebx, ecx, edx; +}; +struct XCRResults { + uint32_t eax, edx; +}; +} // namespace FEXCore::CPUID diff --git a/FEXCore/include/FEXCore/Core/Context.h b/FEXCore/include/FEXCore/Core/Context.h index 07ee049a9..8528d0fd8 100644 --- a/FEXCore/include/FEXCore/Core/Context.h +++ b/FEXCore/include/FEXCore/Core/Context.h @@ -18,264 +18,272 @@ #include namespace FEXCore { - class CodeLoader; - class HostFeatures; - class ForkableSharedMutex; -} +class CodeLoader; +class HostFeatures; +class ForkableSharedMutex; +} // namespace FEXCore namespace FEXCore::Core { - struct CPUState; - struct InternalThreadState; -} +struct CPUState; +struct InternalThreadState; +} // namespace FEXCore::Core namespace FEXCore::CPU { - class CPUBackend; +class CPUBackend; } namespace FEXCore::HLE { - struct SyscallArguments; - class SyscallHandler; -} +struct SyscallArguments; +class SyscallHandler; +} // namespace FEXCore::HLE namespace FEXCore::IR { - struct AOTIRCacheEntry; - class IREmitter; -} +struct AOTIRCacheEntry; +class IREmitter; +} // namespace FEXCore::IR namespace FEXCore::Context { - class Context; - enum ExitReason { - EXIT_NONE, - EXIT_WAITING, - EXIT_ASYNC_RUN, - EXIT_SHUTDOWN, - EXIT_DEBUG, - EXIT_UNKNOWNERROR, - }; +class Context; +enum ExitReason { + EXIT_NONE, + EXIT_WAITING, + EXIT_ASYNC_RUN, + EXIT_SHUTDOWN, + EXIT_DEBUG, + EXIT_UNKNOWNERROR, +}; - enum OperatingMode { - MODE_32BIT, - MODE_64BIT, - }; +enum OperatingMode { + MODE_32BIT, + MODE_64BIT, +}; - struct CustomIRResult { - void *Creator; - void *Data; +struct CustomIRResult { + void* Creator; + void* Data; - explicit operator bool() const noexcept { return !lock; } + explicit operator bool() const noexcept { + return !lock; + } - CustomIRResult(std::unique_lock &&lock, void *Creator, void *Data): - Creator(Creator), Data(Data), lock(std::move(lock)) { } + CustomIRResult(std::unique_lock&& lock, void* Creator, void* Data) + : Creator(Creator) + , Data(Data) + , lock(std::move(lock)) {} - private: - std::unique_lock lock; - }; +private: + std::unique_lock lock; +}; + +/** + * @brief IR Serialization handler class. + */ +class AOTIRWriter { +public: + virtual ~AOTIRWriter() = default; + virtual void Write(const void* Data, size_t Size) = 0; + virtual size_t Offset() = 0; + virtual void Close() = 0; +}; + +struct VDSOSigReturn { + void* VDSO_kernel_sigreturn; + void* VDSO_kernel_rt_sigreturn; +}; + +struct ThreadsState { + FEXCore::Core::InternalThreadState* ParentThread; + fextl::vector* Threads; +}; + +using CodeRangeInvalidationFn = std::function; + +using CustomCPUFactoryType = std::function(Context*, Core::InternalThreadState* Thread)>; +using CustomIREntrypointHandler = std::function; + +using ExitHandler = std::function; + +using AOTIRCodeFileWriterFn = std::function; +using AOTIRLoaderCBFn = std::function; +using AOTIRRenamerCBFn = std::function; +using AOTIRWriterCBFn = std::function(const fextl::string&)>; + +class Context { +public: + virtual ~Context() = default; + /** + * @brief [[threadsafe]] Create a new FEXCore context object + * + * This is necessary to do when running threaded contexts + * + * @return a new context object + */ + FEX_DEFAULT_VISIBILITY static fextl::unique_ptr CreateNewContext(); /** - * @brief IR Serialization handler class. + * @brief Allows setting up in memory code and other things prior to launchign code execution + * + * @param CTX The context that we created + * @param Loader The loader that will be doing all the code loading + * + * @return true if we loaded code */ - class AOTIRWriter { - public: - virtual ~AOTIRWriter() = default; - virtual void Write(const void* Data, size_t Size) = 0; - virtual size_t Offset() = 0; - virtual void Close() = 0; - }; + FEX_DEFAULT_VISIBILITY virtual bool InitCore() = 0; - struct VDSOSigReturn { - void *VDSO_kernel_sigreturn; - void *VDSO_kernel_rt_sigreturn; - }; + FEX_DEFAULT_VISIBILITY virtual void SetExitHandler(ExitHandler handler) = 0; + FEX_DEFAULT_VISIBILITY virtual ExitHandler GetExitHandler() const = 0; - struct ThreadsState { - FEXCore::Core::InternalThreadState* ParentThread; - fextl::vector* Threads; - }; + /** + * @brief Runs the CPU core until it exits + * + * If an Exit handler has been registered, this function won't return until the core + * has shutdown. + * + * @param CTX The context that we created + * + * @return The ExitReason for the parentthread. + */ + FEX_DEFAULT_VISIBILITY virtual ExitReason RunUntilExit(FEXCore::Core::InternalThreadState* Thread) = 0; - using CodeRangeInvalidationFn = std::function; + /** + * @brief Executes the supplied thread context on the current thread until a return is requested + */ + FEX_DEFAULT_VISIBILITY virtual void ExecuteThread(FEXCore::Core::InternalThreadState* Thread) = 0; - using CustomCPUFactoryType = std::function(Context*, Core::InternalThreadState *Thread)>; - using CustomIREntrypointHandler = std::function; + FEX_DEFAULT_VISIBILITY virtual void CompileRIP(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP) = 0; + FEX_DEFAULT_VISIBILITY virtual void CompileRIPCount(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestRIP, uint64_t MaxInst) = 0; - using ExitHandler = std::function; + /** + * @brief Allows the frontend to pass in a custom CPUBackend creation factory + * + * This allows the frontend to have its own frontend. Typically for debugging + * + * @param CTX The context that we created + * @param Factory The factory that the context will call if the DefaultCore config ise set to CUSTOM + */ + FEX_DEFAULT_VISIBILITY virtual void SetCustomCPUBackendFactory(CustomCPUFactoryType Factory) = 0; - using AOTIRCodeFileWriterFn = std::function; - using AOTIRLoaderCBFn = std::function; - using AOTIRRenamerCBFn = std::function; - using AOTIRWriterCBFn = std::function(const fextl::string&)>; + /** + * @brief Retrieves a feature struct indicating certain supported aspects from + * the hose. + * + * @param CTX A valid non-null context instance. + */ + FEX_DEFAULT_VISIBILITY virtual HostFeatures GetHostFeatures() const = 0; - class Context { - public: - virtual ~Context() = default; - /** - * @brief [[threadsafe]] Create a new FEXCore context object - * - * This is necessary to do when running threaded contexts - * - * @return a new context object - */ - FEX_DEFAULT_VISIBILITY static fextl::unique_ptr CreateNewContext(); + FEX_DEFAULT_VISIBILITY virtual void HandleCallback(FEXCore::Core::InternalThreadState* Thread, uint64_t RIP) = 0; - /** - * @brief Allows setting up in memory code and other things prior to launchign code execution - * - * @param CTX The context that we created - * @param Loader The loader that will be doing all the code loading - * - * @return true if we loaded code - */ - FEX_DEFAULT_VISIBILITY virtual bool InitCore() = 0; + ///< State reconstruction helpers + ///< Reconstructs the guest RIP from the passed in thread context and related Host PC. + FEX_DEFAULT_VISIBILITY virtual uint64_t RestoreRIPFromHostPC(FEXCore::Core::InternalThreadState* Thread, uint64_t HostPC) = 0; + /** + * @brief Reconstructs a compacted EFLAGS from FEX's internal EFLAG representation. + * + * @param Thread The thread getting the state reconstructed + * @param WasInJIT If the code was in the JIT at the time. + * @param HostGPRs The host Arm64 GPRs at the point of state inside the JIT. + * @param PSTATE The Arm64 PState value. + * + * If WasInJIT is false then HostGPRs and PSTATE is ignored, with the assumption that the FEX JIT has already stored all state in to the + * ThreadState object. + * + * @return x86 EFLAGS reconstructed + */ + FEX_DEFAULT_VISIBILITY virtual uint32_t + ReconstructCompactedEFLAGS(FEXCore::Core::InternalThreadState* Thread, bool WasInJIT, uint64_t* HostGPRs, uint64_t PSTATE) = 0; + ///< Sets FEX's internal EFLAGS representation to the passed in compacted form. + FEX_DEFAULT_VISIBILITY virtual void SetFlagsFromCompactedEFLAGS(FEXCore::Core::InternalThreadState* Thread, uint32_t EFLAGS) = 0; - FEX_DEFAULT_VISIBILITY virtual void SetExitHandler(ExitHandler handler) = 0; - FEX_DEFAULT_VISIBILITY virtual ExitHandler GetExitHandler() const = 0; + /** + * @brief Create a new thread object that doesn't inherit any state. + * Used to create FEX thread objects in preparation for creating a true OS thread. + * + * @param InitialRIP The starting RIP of this thread + * @param StackPointer The starting RSP of this thread + * @param NewThreadState The thread state to inherit from if not nullptr. + * @param ParentTID The thread ID that the parent is inheriting from + * + * @return A new InternalThreadState object for using with a new guest thread. + */ - /** - * @brief Runs the CPU core until it exits - * - * If an Exit handler has been registered, this function won't return until the core - * has shutdown. - * - * @param CTX The context that we created - * - * @return The ExitReason for the parentthread. - */ - FEX_DEFAULT_VISIBILITY virtual ExitReason RunUntilExit(FEXCore::Core::InternalThreadState *Thread) = 0; + FEX_DEFAULT_VISIBILITY virtual FEXCore::Core::InternalThreadState* + CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState = nullptr, uint64_t ParentTID = 0) = 0; - /** - * @brief Executes the supplied thread context on the current thread until a return is requested - */ - FEX_DEFAULT_VISIBILITY virtual void ExecuteThread(FEXCore::Core::InternalThreadState *Thread) = 0; - - FEX_DEFAULT_VISIBILITY virtual void CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) = 0; - FEX_DEFAULT_VISIBILITY virtual void CompileRIPCount(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP, uint64_t MaxInst) = 0; - - /** - * @brief Allows the frontend to pass in a custom CPUBackend creation factory - * - * This allows the frontend to have its own frontend. Typically for debugging - * - * @param CTX The context that we created - * @param Factory The factory that the context will call if the DefaultCore config ise set to CUSTOM - */ - FEX_DEFAULT_VISIBILITY virtual void SetCustomCPUBackendFactory(CustomCPUFactoryType Factory) = 0; - - /** - * @brief Retrieves a feature struct indicating certain supported aspects from - * the hose. - * - * @param CTX A valid non-null context instance. - */ - FEX_DEFAULT_VISIBILITY virtual HostFeatures GetHostFeatures() const = 0; - - FEX_DEFAULT_VISIBILITY virtual void HandleCallback(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP) = 0; - - ///< State reconstruction helpers - ///< Reconstructs the guest RIP from the passed in thread context and related Host PC. - FEX_DEFAULT_VISIBILITY virtual uint64_t RestoreRIPFromHostPC(FEXCore::Core::InternalThreadState *Thread, uint64_t HostPC) = 0; - /** - * @brief Reconstructs a compacted EFLAGS from FEX's internal EFLAG representation. - * - * @param Thread The thread getting the state reconstructed - * @param WasInJIT If the code was in the JIT at the time. - * @param HostGPRs The host Arm64 GPRs at the point of state inside the JIT. - * @param PSTATE The Arm64 PState value. - * - * If WasInJIT is false then HostGPRs and PSTATE is ignored, with the assumption that the FEX JIT has already stored all state in to the - * ThreadState object. - * - * @return x86 EFLAGS reconstructed - */ - FEX_DEFAULT_VISIBILITY virtual uint32_t ReconstructCompactedEFLAGS(FEXCore::Core::InternalThreadState *Thread, bool WasInJIT, uint64_t *HostGPRs, uint64_t PSTATE) = 0; - ///< Sets FEX's internal EFLAGS representation to the passed in compacted form. - FEX_DEFAULT_VISIBILITY virtual void SetFlagsFromCompactedEFLAGS(FEXCore::Core::InternalThreadState *Thread, uint32_t EFLAGS) = 0; - - /** - * @brief Create a new thread object that doesn't inherit any state. - * Used to create FEX thread objects in preparation for creating a true OS thread. - * - * @param InitialRIP The starting RIP of this thread - * @param StackPointer The starting RSP of this thread - * @param NewThreadState The thread state to inherit from if not nullptr. - * @param ParentTID The thread ID that the parent is inheriting from - * - * @return A new InternalThreadState object for using with a new guest thread. - */ - - FEX_DEFAULT_VISIBILITY virtual FEXCore::Core::InternalThreadState* CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState *NewThreadState = nullptr, uint64_t ParentTID = 0) = 0; - - FEX_DEFAULT_VISIBILITY virtual void ExecutionThread(FEXCore::Core::InternalThreadState *Thread) = 0; - FEX_DEFAULT_VISIBILITY virtual void DestroyThread(FEXCore::Core::InternalThreadState *Thread, bool NeedsTLSUninstall = false) = 0; + FEX_DEFAULT_VISIBILITY virtual void ExecutionThread(FEXCore::Core::InternalThreadState* Thread) = 0; + FEX_DEFAULT_VISIBILITY virtual void DestroyThread(FEXCore::Core::InternalThreadState* Thread, bool NeedsTLSUninstall = false) = 0; #ifndef _WIN32 - FEX_DEFAULT_VISIBILITY virtual void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) {} - FEX_DEFAULT_VISIBILITY virtual void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child) {} + FEX_DEFAULT_VISIBILITY virtual void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) {} + FEX_DEFAULT_VISIBILITY virtual void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child) {} #endif - FEX_DEFAULT_VISIBILITY virtual void SetSignalDelegator(FEXCore::SignalDelegator *SignalDelegation) = 0; - FEX_DEFAULT_VISIBILITY virtual void SetSyscallHandler(FEXCore::HLE::SyscallHandler *Handler) = 0; + FEX_DEFAULT_VISIBILITY virtual void SetSignalDelegator(FEXCore::SignalDelegator* SignalDelegation) = 0; + FEX_DEFAULT_VISIBILITY virtual void SetSyscallHandler(FEXCore::HLE::SyscallHandler* Handler) = 0; - FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::FunctionResults RunCPUIDFunction(uint32_t Function, uint32_t Leaf) = 0; - FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::XCRResults RunXCRFunction(uint32_t Function) = 0; - FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::FunctionResults RunCPUIDFunctionName(uint32_t Function, uint32_t Leaf, uint32_t CPU) = 0; + FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::FunctionResults RunCPUIDFunction(uint32_t Function, uint32_t Leaf) = 0; + FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::XCRResults RunXCRFunction(uint32_t Function) = 0; + FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::FunctionResults RunCPUIDFunctionName(uint32_t Function, uint32_t Leaf, uint32_t CPU) = 0; - FEX_DEFAULT_VISIBILITY virtual FEXCore::IR::AOTIRCacheEntry *LoadAOTIRCacheEntry(const fextl::string& Name) = 0; - FEX_DEFAULT_VISIBILITY virtual void UnloadAOTIRCacheEntry(FEXCore::IR::AOTIRCacheEntry *Entry) = 0; + FEX_DEFAULT_VISIBILITY virtual FEXCore::IR::AOTIRCacheEntry* LoadAOTIRCacheEntry(const fextl::string& Name) = 0; + FEX_DEFAULT_VISIBILITY virtual void UnloadAOTIRCacheEntry(FEXCore::IR::AOTIRCacheEntry* Entry) = 0; - FEX_DEFAULT_VISIBILITY virtual void SetAOTIRLoader(AOTIRLoaderCBFn CacheReader) = 0; - FEX_DEFAULT_VISIBILITY virtual void SetAOTIRWriter(AOTIRWriterCBFn CacheWriter) = 0; - FEX_DEFAULT_VISIBILITY virtual void SetAOTIRRenamer(AOTIRRenamerCBFn CacheRenamer) = 0; + FEX_DEFAULT_VISIBILITY virtual void SetAOTIRLoader(AOTIRLoaderCBFn CacheReader) = 0; + FEX_DEFAULT_VISIBILITY virtual void SetAOTIRWriter(AOTIRWriterCBFn CacheWriter) = 0; + FEX_DEFAULT_VISIBILITY virtual void SetAOTIRRenamer(AOTIRRenamerCBFn CacheRenamer) = 0; - FEX_DEFAULT_VISIBILITY virtual void FinalizeAOTIRCache() = 0; - FEX_DEFAULT_VISIBILITY virtual void WriteFilesWithCode(AOTIRCodeFileWriterFn Writer) = 0; + FEX_DEFAULT_VISIBILITY virtual void FinalizeAOTIRCache() = 0; + FEX_DEFAULT_VISIBILITY virtual void WriteFilesWithCode(AOTIRCodeFileWriterFn Writer) = 0; - FEX_DEFAULT_VISIBILITY virtual void ClearCodeCache(FEXCore::Core::InternalThreadState *Thread) = 0; - FEX_DEFAULT_VISIBILITY virtual void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) = 0; - FEX_DEFAULT_VISIBILITY virtual void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length, CodeRangeInvalidationFn callback) = 0; - FEX_DEFAULT_VISIBILITY virtual FEXCore::ForkableSharedMutex &GetCodeInvalidationMutex() = 0; + FEX_DEFAULT_VISIBILITY virtual void ClearCodeCache(FEXCore::Core::InternalThreadState* Thread) = 0; + FEX_DEFAULT_VISIBILITY virtual void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) = 0; + FEX_DEFAULT_VISIBILITY virtual void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length, + CodeRangeInvalidationFn callback) = 0; + FEX_DEFAULT_VISIBILITY virtual FEXCore::ForkableSharedMutex& GetCodeInvalidationMutex() = 0; - FEX_DEFAULT_VISIBILITY virtual void MarkMemoryShared(FEXCore::Core::InternalThreadState *Thread) = 0; + FEX_DEFAULT_VISIBILITY virtual void MarkMemoryShared(FEXCore::Core::InternalThreadState* Thread) = 0; - FEX_DEFAULT_VISIBILITY virtual void ConfigureAOTGen(FEXCore::Core::InternalThreadState *Thread, fextl::set *ExternalBranches, uint64_t SectionMaxAddress) = 0; - - /** - * @brief Checks if a PC is inside of a thread's JIT code buffer. - * - * @param Thread Which thread's code buffers to check inside of. - * @param Address The PC to check against. - * - * @return true if PC is inside the thread's code buffers. - */ - FEX_DEFAULT_VISIBILITY virtual bool IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState *Thread, uintptr_t Address) const = 0; - - /** - * @brief Allows the frontend to register its own thunk handlers independent of what is controlled in the backend. - * - * @param CTX A valid non-null context instance. - * @param Definitions A vector of thunk definitions that the frontend controls - */ - FEX_DEFAULT_VISIBILITY virtual void AppendThunkDefinitions(fextl::vector const& Definitions) = 0; - - FEX_DEFAULT_VISIBILITY virtual void GetVDSOSigReturn(VDSOSigReturn *VDSOPointers) = 0; - - /** - * @brief Informs the context if hardware TSO is supported. - * Once hardware TSO is enabled, then TSO emulation through atomics is disabled and relies on the hardware. - * - * @param HardwareTSOSupported If the hardware supports the TSO memory model or not. - */ - FEX_DEFAULT_VISIBILITY virtual void SetHardwareTSOSupport(bool HardwareTSOSupported) = 0; - - /** - * @brief Enable exiting the JIT when HLT is hit. - * - * This is to workaround a bug in Wine's longjump function which breaks our unittests. - * - */ - FEX_DEFAULT_VISIBILITY virtual void EnableExitOnHLT() = 0; - - private: - }; + FEX_DEFAULT_VISIBILITY virtual void + ConfigureAOTGen(FEXCore::Core::InternalThreadState* Thread, fextl::set* ExternalBranches, uint64_t SectionMaxAddress) = 0; /** - * @brief This initializes internal FEXCore state that is shared between contexts and requires overhead to setup + * @brief Checks if a PC is inside of a thread's JIT code buffer. + * + * @param Thread Which thread's code buffers to check inside of. + * @param Address The PC to check against. + * + * @return true if PC is inside the thread's code buffers. */ - FEX_DEFAULT_VISIBILITY void InitializeStaticTables(OperatingMode Mode = MODE_64BIT); -} + FEX_DEFAULT_VISIBILITY virtual bool IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState* Thread, uintptr_t Address) const = 0; + + /** + * @brief Allows the frontend to register its own thunk handlers independent of what is controlled in the backend. + * + * @param CTX A valid non-null context instance. + * @param Definitions A vector of thunk definitions that the frontend controls + */ + FEX_DEFAULT_VISIBILITY virtual void AppendThunkDefinitions(const fextl::vector& Definitions) = 0; + + FEX_DEFAULT_VISIBILITY virtual void GetVDSOSigReturn(VDSOSigReturn* VDSOPointers) = 0; + + /** + * @brief Informs the context if hardware TSO is supported. + * Once hardware TSO is enabled, then TSO emulation through atomics is disabled and relies on the hardware. + * + * @param HardwareTSOSupported If the hardware supports the TSO memory model or not. + */ + FEX_DEFAULT_VISIBILITY virtual void SetHardwareTSOSupport(bool HardwareTSOSupported) = 0; + + /** + * @brief Enable exiting the JIT when HLT is hit. + * + * This is to workaround a bug in Wine's longjump function which breaks our unittests. + * + */ + FEX_DEFAULT_VISIBILITY virtual void EnableExitOnHLT() = 0; + +private: +}; + +/** + * @brief This initializes internal FEXCore state that is shared between contexts and requires overhead to setup + */ +FEX_DEFAULT_VISIBILITY void InitializeStaticTables(OperatingMode Mode = MODE_64BIT); +} // namespace FEXCore::Context diff --git a/FEXCore/include/FEXCore/Core/CoreState.h b/FEXCore/include/FEXCore/Core/CoreState.h index be759ecdd..3a7ff0583 100644 --- a/FEXCore/include/FEXCore/Core/CoreState.h +++ b/FEXCore/include/FEXCore/Core/CoreState.h @@ -15,334 +15,335 @@ #include namespace FEXCore::Core { - // Wrapper around std::atomic using std::memory_order_relaxed. - // This allows compilers to emit more performant code at the expense of visibly tearing. - // In particular, increments/decrements may visibly tear if a signal is received half-way through. - // - // Prefer std::atomic with default memory ordering unless you really know what you're doing. - // Primarily this ensure program ordering when signals are concerned. - template - class NonAtomicRefCounter { - public: - void Increment(T Value) { - // Specifically avoiding fetch_add here because that will turn in to ldxr+stxr or lock xadd. - // FEX very specifically wants to use simple loadstore instructions for this - // - // ARM64 ex: - // ldr x0, [x1]; - // add x0, x0, #1; - // str x0, [x1]; - // - // x86-64 ex: - // inc qword [rax]; - auto Current = AtomicVariable.load(std::memory_order_relaxed); - AtomicVariable.store(Current + Value, std::memory_order_relaxed); - } +// Wrapper around std::atomic using std::memory_order_relaxed. +// This allows compilers to emit more performant code at the expense of visibly tearing. +// In particular, increments/decrements may visibly tear if a signal is received half-way through. +// +// Prefer std::atomic with default memory ordering unless you really know what you're doing. +// Primarily this ensure program ordering when signals are concerned. +template +class NonAtomicRefCounter { +public: + void Increment(T Value) { + // Specifically avoiding fetch_add here because that will turn in to ldxr+stxr or lock xadd. + // FEX very specifically wants to use simple loadstore instructions for this + // + // ARM64 ex: + // ldr x0, [x1]; + // add x0, x0, #1; + // str x0, [x1]; + // + // x86-64 ex: + // inc qword [rax]; + auto Current = AtomicVariable.load(std::memory_order_relaxed); + AtomicVariable.store(Current + Value, std::memory_order_relaxed); + } - // Returns original value. - // x86-64 needs to know the result on decrement. - T Decrement(T Value) { - // Specifically avoiding fetch_sub here because that will turn into ldxr+stxr or lock xadd. - // FEX very specifically wants to use simple loadstore instructions for this - // - // ARM64 ex: - // ldr x0, [x1]; - // sub x0, x0, #1; - // str x0, [x1]; - // - // x86-64 ex: - // dec qword [rax]; - auto Current = AtomicVariable.load(std::memory_order_relaxed); - AtomicVariable.store(Current - Value, std::memory_order_relaxed); - return Current; - } + // Returns original value. + // x86-64 needs to know the result on decrement. + T Decrement(T Value) { + // Specifically avoiding fetch_sub here because that will turn into ldxr+stxr or lock xadd. + // FEX very specifically wants to use simple loadstore instructions for this + // + // ARM64 ex: + // ldr x0, [x1]; + // sub x0, x0, #1; + // str x0, [x1]; + // + // x86-64 ex: + // dec qword [rax]; + auto Current = AtomicVariable.load(std::memory_order_relaxed); + AtomicVariable.store(Current - Value, std::memory_order_relaxed); + return Current; + } - T Load() const { - return AtomicVariable.load(std::memory_order_relaxed); - } + T Load() const { + return AtomicVariable.load(std::memory_order_relaxed); + } - void Store(T Value) { - AtomicVariable.store(Value, std::memory_order_relaxed); - } + void Store(T Value) { + AtomicVariable.store(Value, std::memory_order_relaxed); + } - private: - std::atomic AtomicVariable; - }; - static_assert(std::is_standard_layout_v>, "Needs to be standard layout"); - static_assert(std::is_trivially_copyable_v>, "needs to be trivially copyable"); - static_assert(sizeof(NonAtomicRefCounter) == sizeof(uint64_t), "Needs to be correct size"); +private: + std::atomic AtomicVariable; +}; +static_assert(std::is_standard_layout_v>, "Needs to be standard layout"); +static_assert(std::is_trivially_copyable_v>, "needs to be trivially copyable"); +static_assert(sizeof(NonAtomicRefCounter) == sizeof(uint64_t), "Needs to be correct size"); - struct CPUState { - // Allows more efficient handling of the register - // file in the event AVX is not supported. - union XMMRegs { - struct AVX { - uint64_t data[16][4]; - }; - struct SSE { - uint64_t data[16][2]; - uint64_t pad[16][2]; - }; - - AVX avx; - SSE sse; +struct CPUState { + // Allows more efficient handling of the register + // file in the event AVX is not supported. + union XMMRegs { + struct AVX { + uint64_t data[16][4]; + }; + struct SSE { + uint64_t data[16][2]; + uint64_t pad[16][2]; }; - uint64_t rip{}; ///< Current core's RIP. May not be entirely accurate while JIT is active - uint64_t gregs[16]{}; - // Raw segment register indexes - uint16_t es_idx{}, cs_idx{}, ss_idx{}, ds_idx{}; - uint16_t gs_idx{}, fs_idx{}; - uint16_t _pad[2]; + AVX avx; + SSE sse; + }; - // Segment registers holding base addresses - uint32_t es_cached{}, cs_cached{}, ss_cached{}, ds_cached{}; - uint64_t gs_cached{}; - uint64_t fs_cached{}; - uint64_t InlineJITBlockHeader{}; - XMMRegs xmm{}; - uint8_t flags[48]{}; - uint64_t pf_raw{}; - uint64_t af_raw{}; - uint64_t mm[8][2]{}; + uint64_t rip {}; ///< Current core's RIP. May not be entirely accurate while JIT is active + uint64_t gregs[16] {}; + // Raw segment register indexes + uint16_t es_idx {}, cs_idx {}, ss_idx {}, ds_idx {}; + uint16_t gs_idx {}, fs_idx {}; + uint16_t _pad[2]; - // 32bit x86 state - struct { - uint32_t base; - } gdt[32]{}; - uint16_t FCW { 0x37F }; - uint8_t AbridgedFTW{}; + // Segment registers holding base addresses + uint32_t es_cached {}, cs_cached {}, ss_cached {}, ds_cached {}; + uint64_t gs_cached {}; + uint64_t fs_cached {}; + uint64_t InlineJITBlockHeader {}; + XMMRegs xmm {}; + uint8_t flags[48] {}; + uint64_t pf_raw {}; + uint64_t af_raw {}; + uint64_t mm[8][2] {}; - uint8_t _pad2[5]; - // Reference counter for FEX's per-thread deferred signals. - // Counts the nesting depth of program sections that cause signals to be deferred. - NonAtomicRefCounter DeferredSignalRefCount; - // Since this memory region is thread local, we use NonAtomicRefCounter for fast atomic access. - NonAtomicRefCounter *DeferredSignalFaultAddress; + // 32bit x86 state + struct { + uint32_t base; + } gdt[32] {}; + uint16_t FCW {0x37F}; + uint8_t AbridgedFTW {}; - static constexpr size_t FLAG_SIZE = sizeof(flags[0]); - static constexpr size_t GDT_SIZE = sizeof(gdt[0]); - static constexpr size_t GPR_REG_SIZE = sizeof(gregs[0]); - static constexpr size_t XMM_AVX_REG_SIZE = sizeof(xmm.avx.data[0]); - static constexpr size_t XMM_SSE_REG_SIZE = XMM_AVX_REG_SIZE / 2; - static constexpr size_t MM_REG_SIZE = sizeof(mm[0]); + uint8_t _pad2[5]; + // Reference counter for FEX's per-thread deferred signals. + // Counts the nesting depth of program sections that cause signals to be deferred. + NonAtomicRefCounter DeferredSignalRefCount; + // Since this memory region is thread local, we use NonAtomicRefCounter for fast atomic access. + NonAtomicRefCounter* DeferredSignalFaultAddress; - // Only the first 32 bits are defined. - static constexpr size_t NUM_EFLAG_BITS = 32; - static constexpr size_t NUM_FLAGS = sizeof(flags) / FLAG_SIZE; - static constexpr size_t NUM_GDTS = sizeof(gdt) / GDT_SIZE; - static constexpr size_t NUM_GPRS = sizeof(gregs) / GPR_REG_SIZE; - static constexpr size_t NUM_XMMS = sizeof(xmm) / XMM_AVX_REG_SIZE; - static constexpr size_t NUM_MMS = sizeof(mm) / MM_REG_SIZE; - CPUState() { + static constexpr size_t FLAG_SIZE = sizeof(flags[0]); + static constexpr size_t GDT_SIZE = sizeof(gdt[0]); + static constexpr size_t GPR_REG_SIZE = sizeof(gregs[0]); + static constexpr size_t XMM_AVX_REG_SIZE = sizeof(xmm.avx.data[0]); + static constexpr size_t XMM_SSE_REG_SIZE = XMM_AVX_REG_SIZE / 2; + static constexpr size_t MM_REG_SIZE = sizeof(mm[0]); + + // Only the first 32 bits are defined. + static constexpr size_t NUM_EFLAG_BITS = 32; + static constexpr size_t NUM_FLAGS = sizeof(flags) / FLAG_SIZE; + static constexpr size_t NUM_GDTS = sizeof(gdt) / GDT_SIZE; + static constexpr size_t NUM_GPRS = sizeof(gregs) / GPR_REG_SIZE; + static constexpr size_t NUM_XMMS = sizeof(xmm) / XMM_AVX_REG_SIZE; + static constexpr size_t NUM_MMS = sizeof(mm) / MM_REG_SIZE; + CPUState() { #ifndef NDEBUG - // Initialize default CPU state - rip = ~0ULL; - // Initialize xmm state with garbage to catch spurious incorrect xmm usage. - for (auto& xmm : xmm.avx.data) { - xmm[0] = 0xDEADBEEFULL; - xmm[1] = 0xBAD0DAD1ULL; - xmm[2] = 0xDEADCAFEULL; - xmm[3] = 0xBAD2CAD3ULL; - } + // Initialize default CPU state + rip = ~0ULL; + // Initialize xmm state with garbage to catch spurious incorrect xmm usage. + for (auto& xmm : xmm.avx.data) { + xmm[0] = 0xDEADBEEFULL; + xmm[1] = 0xBAD0DAD1ULL; + xmm[2] = 0xDEADCAFEULL; + xmm[3] = 0xBAD2CAD3ULL; + } #endif - flags[X86State::RFLAG_RESERVED_LOC] = 1; ///< Reserved - Always 1. - flags[X86State::RFLAG_IF_LOC] = 1; ///< Interrupt flag - Always 1. + flags[X86State::RFLAG_RESERVED_LOC] = 1; ///< Reserved - Always 1. + flags[X86State::RFLAG_IF_LOC] = 1; ///< Interrupt flag - Always 1. - // DF needs to be initialized to 0 to comply with the Linux ABI. However, - // we encode DF as 1/-1 within the JIT, so we have to write 0x1 here to - // zero DF. - flags[X86State::RFLAG_DF_RAW_LOC] = 0x1; - } - }; - static_assert(std::is_trivially_copyable_v, "Needs to be trivial"); - static_assert(std::is_standard_layout_v, "This needs to be standard layout"); - static_assert(offsetof(CPUState, xmm) % 32 == 0, "xmm needs to be 256-bit aligned!"); - static_assert(offsetof(CPUState, mm) % 16 == 0, "mm needs to be 128-bit aligned!"); - static_assert(offsetof(CPUState, DeferredSignalRefCount) % 8 == 0, "Needs to be 8-byte aligned"); + // DF needs to be initialized to 0 to comply with the Linux ABI. However, + // we encode DF as 1/-1 within the JIT, so we have to write 0x1 here to + // zero DF. + flags[X86State::RFLAG_DF_RAW_LOC] = 0x1; + } +}; +static_assert(std::is_trivially_copyable_v, "Needs to be trivial"); +static_assert(std::is_standard_layout_v, "This needs to be standard layout"); +static_assert(offsetof(CPUState, xmm) % 32 == 0, "xmm needs to be 256-bit aligned!"); +static_assert(offsetof(CPUState, mm) % 16 == 0, "mm needs to be 128-bit aligned!"); +static_assert(offsetof(CPUState, DeferredSignalRefCount) % 8 == 0, "Needs to be 8-byte aligned"); - struct InternalThreadState; +struct InternalThreadState; - enum FallbackHandlerIndex { - OPINDEX_F80CVTTO_4 = 0, - OPINDEX_F80CVTTO_8, - OPINDEX_F80CVT_4, - OPINDEX_F80CVT_8, - OPINDEX_F80CVTINT_2, - OPINDEX_F80CVTINT_4, - OPINDEX_F80CVTINT_8, - OPINDEX_F80CVTINT_TRUNC2, - OPINDEX_F80CVTINT_TRUNC4, - OPINDEX_F80CVTINT_TRUNC8, - OPINDEX_F80CMP_0, - OPINDEX_F80CMP_1, - OPINDEX_F80CMP_2, - OPINDEX_F80CMP_3, - OPINDEX_F80CMP_4, - OPINDEX_F80CMP_5, - OPINDEX_F80CMP_6, - OPINDEX_F80CMP_7, - OPINDEX_F80CVTTOINT_2, - OPINDEX_F80CVTTOINT_4, +enum FallbackHandlerIndex { + OPINDEX_F80CVTTO_4 = 0, + OPINDEX_F80CVTTO_8, + OPINDEX_F80CVT_4, + OPINDEX_F80CVT_8, + OPINDEX_F80CVTINT_2, + OPINDEX_F80CVTINT_4, + OPINDEX_F80CVTINT_8, + OPINDEX_F80CVTINT_TRUNC2, + OPINDEX_F80CVTINT_TRUNC4, + OPINDEX_F80CVTINT_TRUNC8, + OPINDEX_F80CMP_0, + OPINDEX_F80CMP_1, + OPINDEX_F80CMP_2, + OPINDEX_F80CMP_3, + OPINDEX_F80CMP_4, + OPINDEX_F80CMP_5, + OPINDEX_F80CMP_6, + OPINDEX_F80CMP_7, + OPINDEX_F80CVTTOINT_2, + OPINDEX_F80CVTTOINT_4, - // Unary - OPINDEX_F80ROUND, - OPINDEX_F80F2XM1, - OPINDEX_F80TAN, - OPINDEX_F80SQRT, - OPINDEX_F80SIN, - OPINDEX_F80COS, - OPINDEX_F80XTRACT_EXP, - OPINDEX_F80XTRACT_SIG, - OPINDEX_F80BCDSTORE, - OPINDEX_F80BCDLOAD, + // Unary + OPINDEX_F80ROUND, + OPINDEX_F80F2XM1, + OPINDEX_F80TAN, + OPINDEX_F80SQRT, + OPINDEX_F80SIN, + OPINDEX_F80COS, + OPINDEX_F80XTRACT_EXP, + OPINDEX_F80XTRACT_SIG, + OPINDEX_F80BCDSTORE, + OPINDEX_F80BCDLOAD, - // Binary - OPINDEX_F80ADD, - OPINDEX_F80SUB, - OPINDEX_F80MUL, - OPINDEX_F80DIV, - OPINDEX_F80FYL2X, - OPINDEX_F80ATAN, - OPINDEX_F80FPREM1, - OPINDEX_F80FPREM, - OPINDEX_F80SCALE, + // Binary + OPINDEX_F80ADD, + OPINDEX_F80SUB, + OPINDEX_F80MUL, + OPINDEX_F80DIV, + OPINDEX_F80FYL2X, + OPINDEX_F80ATAN, + OPINDEX_F80FPREM1, + OPINDEX_F80FPREM, + OPINDEX_F80SCALE, - // Double Precision - OPINDEX_F64SIN, - OPINDEX_F64COS, - OPINDEX_F64TAN, - OPINDEX_F64ATAN, - OPINDEX_F64F2XM1, - OPINDEX_F64FYL2X, - OPINDEX_F64FPREM, - OPINDEX_F64FPREM1, - OPINDEX_F64SCALE, + // Double Precision + OPINDEX_F64SIN, + OPINDEX_F64COS, + OPINDEX_F64TAN, + OPINDEX_F64ATAN, + OPINDEX_F64F2XM1, + OPINDEX_F64FYL2X, + OPINDEX_F64FPREM, + OPINDEX_F64FPREM1, + OPINDEX_F64SCALE, - // SSE4.2 string instructions - OPINDEX_VPCMPESTRX, - OPINDEX_VPCMPISTRX, + // SSE4.2 string instructions + OPINDEX_VPCMPESTRX, + OPINDEX_VPCMPISTRX, - // Maximum - OPINDEX_MAX, - }; + // Maximum + OPINDEX_MAX, +}; - struct JITPointers { +struct JITPointers { + struct { + // Process specific + + uint64_t PrintValue {}; + uint64_t PrintVectorValue {}; + uint64_t ThreadRemoveCodeEntryFromJIT {}; + uint64_t CPUIDObj {}; + uint64_t CPUIDFunction {}; + uint64_t XCRFunction {}; + uint64_t SyscallHandlerObj {}; + uint64_t SyscallHandlerFunc {}; + uint64_t ExitFunctionLink {}; + + // Handles returning/calling ARM64EC code from the JIT, expects the target PC in TMP3 + uint64_t ExitFunctionEC {}; + + uint64_t FallbackHandlerPointers[FallbackHandlerIndex::OPINDEX_MAX]; + uint64_t NamedVectorConstantPointers[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX]; + uint64_t IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_MAX]; + uint64_t TelemetryValueAddresses[FEXCore::Telemetry::TYPE_LAST]; + + // Thread Specific + /** + * @name Dispatcher pointers + * @{ */ + uint64_t DispatcherLoopTop {}; + uint64_t DispatcherLoopTopFillSRA {}; + uint64_t ExitFunctionLinker {}; + uint64_t ThreadStopHandlerSpillSRA {}; + uint64_t ThreadPauseHandlerSpillSRA {}; + uint64_t UnimplementedInstructionHandler {}; + uint64_t GuestSignal_SIGILL {}; + uint64_t GuestSignal_SIGTRAP {}; + uint64_t GuestSignal_SIGSEGV {}; + uint64_t SignalReturnHandler {}; + uint64_t SignalReturnHandlerRT {}; + uint64_t L1Pointer {}; + uint64_t L2Pointer {}; + /** @} */ + + // Copy of process-wide named vector constants data. + alignas(16) uint64_t NamedVectorConstants[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX][2]; + } Common; + + union { struct { // Process specific - - uint64_t PrintValue{}; - uint64_t PrintVectorValue{}; - uint64_t ThreadRemoveCodeEntryFromJIT{}; - uint64_t CPUIDObj{}; - uint64_t CPUIDFunction{}; - uint64_t XCRFunction{}; - uint64_t SyscallHandlerObj{}; - uint64_t SyscallHandlerFunc{}; - uint64_t ExitFunctionLink{}; - - // Handles returning/calling ARM64EC code from the JIT, expects the target PC in TMP3 - uint64_t ExitFunctionEC{}; - - uint64_t FallbackHandlerPointers[FallbackHandlerIndex::OPINDEX_MAX]; - uint64_t NamedVectorConstantPointers[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX]; - uint64_t IndexedNamedVectorConstantPointers[FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_MAX]; - uint64_t TelemetryValueAddresses[FEXCore::Telemetry::TYPE_LAST]; + uint64_t LUDIV {}; + uint64_t LDIV {}; + uint64_t LUREM {}; + uint64_t LREM {}; // Thread Specific + /** * @name Dispatcher pointers * @{ */ - uint64_t DispatcherLoopTop{}; - uint64_t DispatcherLoopTopFillSRA{}; - uint64_t ExitFunctionLinker{}; - uint64_t ThreadStopHandlerSpillSRA{}; - uint64_t ThreadPauseHandlerSpillSRA{}; - uint64_t UnimplementedInstructionHandler{}; - uint64_t GuestSignal_SIGILL{}; - uint64_t GuestSignal_SIGTRAP{}; - uint64_t GuestSignal_SIGSEGV{}; - uint64_t SignalReturnHandler{}; - uint64_t SignalReturnHandlerRT{}; - uint64_t L1Pointer{}; - uint64_t L2Pointer{}; + uint64_t LUDIVHandler {}; + uint64_t LDIVHandler {}; + uint64_t LUREMHandler {}; + uint64_t LREMHandler {}; /** @} */ + } AArch64; - // Copy of process-wide named vector constants data. - alignas(16) uint64_t NamedVectorConstants[FEXCore::IR::NamedVectorConstant::NAMED_VECTOR_CONST_POOL_MAX][2]; - } Common; - - union { - struct { - // Process specific - uint64_t LUDIV{}; - uint64_t LDIV{}; - uint64_t LUREM{}; - uint64_t LREM{}; - - // Thread Specific - - /** - * @name Dispatcher pointers - * @{ */ - uint64_t LUDIVHandler{}; - uint64_t LDIVHandler{}; - uint64_t LUREMHandler{}; - uint64_t LREMHandler{}; - /** @} */ - } AArch64; - - struct { - // None so far - } X86; - }; + struct { + // None so far + } X86; }; +}; - // Each guest JIT frame has one of these - struct CpuStateFrame { - CPUState State; +// Each guest JIT frame has one of these +struct CpuStateFrame { + CPUState State; - /** - * @brief Stack location for the CPU backends to return the stack pointer to - * - * Allows the CPU cores to do a long jump out of their execution and safely shut down - */ - uint64_t ReturningStackLocation{}; + /** + * @brief Stack location for the CPU backends to return the stack pointer to + * + * Allows the CPU cores to do a long jump out of their execution and safely shut down + */ + uint64_t ReturningStackLocation {}; - /** - * @brief If we are in an inline syscall we need to store a bit of additional information about this - * - * ARM64: - * - Bit 15: In syscall - * - Bit 14-0: Number of static registers spilled - */ - uint64_t InSyscallInfo{}; + /** + * @brief If we are in an inline syscall we need to store a bit of additional information about this + * + * ARM64: + * - Bit 15: In syscall + * - Bit 14-0: Number of static registers spilled + */ + uint64_t InSyscallInfo {}; - uint32_t SignalHandlerRefCounter{}; + uint32_t SignalHandlerRefCounter {}; - struct alignas(8) SynchronousFaultDataStruct { - bool FaultToTopAndGeneratedException{}; - uint8_t Signal; - uint8_t TrapNo; - uint8_t si_code; - uint16_t err_code; - uint16_t _pad : 16; - } SynchronousFaultData; + struct alignas(8) SynchronousFaultDataStruct { + bool FaultToTopAndGeneratedException {}; + uint8_t Signal; + uint8_t TrapNo; + uint8_t si_code; + uint16_t err_code; + uint16_t _pad : 16; + } SynchronousFaultData; - InternalThreadState* Thread; + InternalThreadState* Thread; - // Pointers that the JIT needs to load to remove relocations - JITPointers Pointers; - }; - static_assert(offsetof(CpuStateFrame, State) == 0, "CPUState must be first member in CpuStateFrame"); - static_assert(offsetof(CpuStateFrame, State.rip) == 0, "rip must be zero offset in CpuStateFrame"); - static_assert(offsetof(CpuStateFrame, Pointers) % 8 == 0, "JITPointers need to be aligned to 8 bytes"); - static_assert(offsetof(CpuStateFrame, Pointers) + sizeof(CpuStateFrame::Pointers) <= 32760, "JITPointers maximum pointer needs to be less than architecture maximum 32768"); + // Pointers that the JIT needs to load to remove relocations + JITPointers Pointers; +}; +static_assert(offsetof(CpuStateFrame, State) == 0, "CPUState must be first member in CpuStateFrame"); +static_assert(offsetof(CpuStateFrame, State.rip) == 0, "rip must be zero offset in CpuStateFrame"); +static_assert(offsetof(CpuStateFrame, Pointers) % 8 == 0, "JITPointers need to be aligned to 8 bytes"); +static_assert(offsetof(CpuStateFrame, Pointers) + sizeof(CpuStateFrame::Pointers) <= 32760, "JITPointers maximum pointer needs to be less " + "than architecture maximum 32768"); - static_assert(std::is_standard_layout::value, "This needs to be standard layout"); - static_assert(sizeof(CpuStateFrame::SynchronousFaultData) == 8, "This needs to be 8 bytes"); - static_assert(std::alignment_of_v == 8, "This needs to be 8 bytes"); - static_assert(offsetof(CpuStateFrame, SynchronousFaultData) % 8 == 0, "This needs to be aligned"); -} +static_assert(std::is_standard_layout::value, "This needs to be standard layout"); +static_assert(sizeof(CpuStateFrame::SynchronousFaultData) == 8, "This needs to be 8 bytes"); +static_assert(std::alignment_of_v == 8, "This needs to be 8 bytes"); +static_assert(offsetof(CpuStateFrame, SynchronousFaultData) % 8 == 0, "This needs to be aligned"); +} // namespace FEXCore::Core diff --git a/FEXCore/include/FEXCore/Core/HostFeatures.h b/FEXCore/include/FEXCore/Core/HostFeatures.h index 016c4db1e..ff7f0d0cb 100644 --- a/FEXCore/include/FEXCore/Core/HostFeatures.h +++ b/FEXCore/include/FEXCore/Core/HostFeatures.h @@ -4,43 +4,43 @@ namespace FEXCore { class HostFeatures final { - public: - HostFeatures(); +public: + HostFeatures(); - /** - * @brief Backend features that change how codegen is generated from IR - * - * Specifically things that affect the IR->Codegen process - * Not the x86->IR process - */ - uint32_t DCacheLineSize{}; - uint32_t ICacheLineSize{}; - bool SupportsAES{}; - bool SupportsCRC{}; - bool SupportsCLZERO{}; - bool SupportsAtomics{}; - bool SupportsRCPC{}; - bool SupportsTSOImm9{}; - bool SupportsRAND{}; - bool Supports3DNow{}; - bool SupportsSSE4A{}; - bool SupportsAVX{}; - bool SupportsAVX2{}; - bool SupportsSVE{}; - bool SupportsSHA{}; - bool SupportsBMI1{}; - bool SupportsBMI2{}; - bool SupportsCLWB{}; - bool SupportsPMULL_128Bit{}; - bool SupportsCSSC{}; - bool SupportsFCMA{}; - bool SupportsFlagM{}; - bool SupportsFlagM2{}; - bool SupportsRPRES{}; - bool SupportsPreserveAllABI{}; + /** + * @brief Backend features that change how codegen is generated from IR + * + * Specifically things that affect the IR->Codegen process + * Not the x86->IR process + */ + uint32_t DCacheLineSize {}; + uint32_t ICacheLineSize {}; + bool SupportsAES {}; + bool SupportsCRC {}; + bool SupportsCLZERO {}; + bool SupportsAtomics {}; + bool SupportsRCPC {}; + bool SupportsTSOImm9 {}; + bool SupportsRAND {}; + bool Supports3DNow {}; + bool SupportsSSE4A {}; + bool SupportsAVX {}; + bool SupportsAVX2 {}; + bool SupportsSVE {}; + bool SupportsSHA {}; + bool SupportsBMI1 {}; + bool SupportsBMI2 {}; + bool SupportsCLWB {}; + bool SupportsPMULL_128Bit {}; + bool SupportsCSSC {}; + bool SupportsFCMA {}; + bool SupportsFlagM {}; + bool SupportsFlagM2 {}; + bool SupportsRPRES {}; + bool SupportsPreserveAllABI {}; - // Float exception behaviour - bool SupportsAFP{}; - bool SupportsFloatExceptions{}; + // Float exception behaviour + bool SupportsAFP {}; + bool SupportsFloatExceptions {}; }; -} +} // namespace FEXCore diff --git a/FEXCore/include/FEXCore/Core/SignalDelegator.h b/FEXCore/include/FEXCore/Core/SignalDelegator.h index 945ddc004..f33d1dd42 100644 --- a/FEXCore/include/FEXCore/Core/SignalDelegator.h +++ b/FEXCore/include/FEXCore/Core/SignalDelegator.h @@ -34,61 +34,61 @@ namespace Core { FAULT_SIGILL = 4, #endif }; -} - class SignalDelegator { - public: - virtual ~SignalDelegator() = default; +} // namespace Core +class SignalDelegator { +public: + virtual ~SignalDelegator() = default; - struct SignalDelegatorConfig { - bool SupportsAVX{}; + struct SignalDelegatorConfig { + bool SupportsAVX {}; - // Dispatcher information - uint64_t DispatcherBegin; - uint64_t DispatcherEnd; + // Dispatcher information + uint64_t DispatcherBegin; + uint64_t DispatcherEnd; - // Dispatcher entrypoint. - uint64_t AbsoluteLoopTopAddress{}; - uint64_t AbsoluteLoopTopAddressFillSRA{}; + // Dispatcher entrypoint. + uint64_t AbsoluteLoopTopAddress {}; + uint64_t AbsoluteLoopTopAddressFillSRA {}; - // Signal return pointers. - uint64_t SignalHandlerReturnAddress{}; - uint64_t SignalHandlerReturnAddressRT{}; + // Signal return pointers. + uint64_t SignalHandlerReturnAddress {}; + uint64_t SignalHandlerReturnAddressRT {}; - // Pause handlers. - uint64_t PauseReturnInstruction{}; - uint64_t ThreadPauseHandlerAddressSpillSRA{}; - uint64_t ThreadPauseHandlerAddress{}; + // Pause handlers. + uint64_t PauseReturnInstruction {}; + uint64_t ThreadPauseHandlerAddressSpillSRA {}; + uint64_t ThreadPauseHandlerAddress {}; - // Stop handlers. - uint64_t ThreadStopHandlerAddressSpillSRA; - uint64_t ThreadStopHandlerAddress{}; + // Stop handlers. + uint64_t ThreadStopHandlerAddressSpillSRA; + uint64_t ThreadStopHandlerAddress {}; - // SRA information. - uint16_t SRAGPRCount; - uint16_t SRAFPRCount; + // SRA information. + uint16_t SRAGPRCount; + uint16_t SRAFPRCount; - // SRA index mapping. - uint8_t SRAGPRMapping[16]; - uint8_t SRAFPRMapping[16]; - }; - - void SetConfig(const SignalDelegatorConfig& _Config) { - Config = _Config; - } - - const SignalDelegatorConfig &GetConfig() const { - return Config; - } - - /** - * @brief Signals a thread with a specific core event. - * - * @param Thread Which thread to signal. - * @param Event Which event to signal the event with. - */ - virtual void SignalThread(FEXCore::Core::InternalThreadState *Thread, Core::SignalEvent Event) = 0; - - protected: - SignalDelegatorConfig Config; + // SRA index mapping. + uint8_t SRAGPRMapping[16]; + uint8_t SRAFPRMapping[16]; }; -} + + void SetConfig(const SignalDelegatorConfig& _Config) { + Config = _Config; + } + + const SignalDelegatorConfig& GetConfig() const { + return Config; + } + + /** + * @brief Signals a thread with a specific core event. + * + * @param Thread Which thread to signal. + * @param Event Which event to signal the event with. + */ + virtual void SignalThread(FEXCore::Core::InternalThreadState* Thread, Core::SignalEvent Event) = 0; + +protected: + SignalDelegatorConfig Config; +}; +} // namespace FEXCore diff --git a/FEXCore/include/FEXCore/Core/X86Enums.h b/FEXCore/include/FEXCore/Core/X86Enums.h index 12460b6db..a9456895f 100644 --- a/FEXCore/include/FEXCore/Core/X86Enums.h +++ b/FEXCore/include/FEXCore/Core/X86Enums.h @@ -8,46 +8,46 @@ namespace FEXCore::X86State { * @name The ordered of the GPRs from name to index * @{ */ enum X86Reg : uint32_t { - REG_RAX = 0, - REG_RCX = 1, - REG_RDX = 2, - REG_RBX = 3, - REG_RSP = 4, - REG_RBP = 5, - REG_RSI = 6, - REG_RDI = 7, - REG_R8 = 8, - REG_R9 = 9, - REG_R10 = 10, - REG_R11 = 11, - REG_R12 = 12, - REG_R13 = 13, - REG_R14 = 14, - REG_R15 = 15, - REG_XMM_0 = 16, - REG_XMM_1 = 17, - REG_XMM_2 = 18, - REG_XMM_3 = 19, - REG_XMM_4 = 20, - REG_XMM_5 = 21, - REG_XMM_6 = 22, - REG_XMM_7 = 23, - REG_XMM_8 = 24, - REG_XMM_9 = 25, - REG_XMM_10 = 26, - REG_XMM_11 = 27, - REG_XMM_12 = 28, - REG_XMM_13 = 29, - REG_XMM_14 = 30, - REG_XMM_15 = 31, - REG_MM_0 = 32, - REG_MM_1 = 33, - REG_MM_2 = 34, - REG_MM_3 = 35, - REG_MM_4 = 36, - REG_MM_5 = 37, - REG_MM_6 = 38, - REG_MM_7 = 39, + REG_RAX = 0, + REG_RCX = 1, + REG_RDX = 2, + REG_RBX = 3, + REG_RSP = 4, + REG_RBP = 5, + REG_RSI = 6, + REG_RDI = 7, + REG_R8 = 8, + REG_R9 = 9, + REG_R10 = 10, + REG_R11 = 11, + REG_R12 = 12, + REG_R13 = 13, + REG_R14 = 14, + REG_R15 = 15, + REG_XMM_0 = 16, + REG_XMM_1 = 17, + REG_XMM_2 = 18, + REG_XMM_3 = 19, + REG_XMM_4 = 20, + REG_XMM_5 = 21, + REG_XMM_6 = 22, + REG_XMM_7 = 23, + REG_XMM_8 = 24, + REG_XMM_9 = 25, + REG_XMM_10 = 26, + REG_XMM_11 = 27, + REG_XMM_12 = 28, + REG_XMM_13 = 29, + REG_XMM_14 = 30, + REG_XMM_15 = 31, + REG_MM_0 = 32, + REG_MM_1 = 33, + REG_MM_2 = 34, + REG_MM_3 = 35, + REG_MM_4 = 36, + REG_MM_5 = 37, + REG_MM_6 = 38, + REG_MM_7 = 39, REG_INVALID = 255, }; /** @} */ @@ -56,88 +56,88 @@ enum X86Reg : uint32_t { * @name RFLAG register bit locations * @{ */ enum X86RegLocation : uint32_t { - RFLAG_CF_RAW_LOC = 0, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` - RFLAG_RESERVED_LOC = 1, // Reserved Bit, Read-as-1 - RFLAG_PF_RAW_LOC = 2, // Contains multiple bits, needs to be reconstructed using `ReconstructCompactedEFLAGS` - RFLAG_AF_RAW_LOC = 4, // Contains multiple bits, needs to be reconstructed using `ReconstructCompactedEFLAGS` - RFLAG_ZF_RAW_LOC = 6, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` - RFLAG_SF_RAW_LOC = 7, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` - RFLAG_TF_LOC = 8, - RFLAG_IF_LOC = 9, - RFLAG_DF_RAW_LOC = 10, // Contains multiple bits, needs to be reconstructed using `ReconstructCompactedEFLAGS` - RFLAG_OF_RAW_LOC = 11, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` - RFLAG_IOPL_LOC = 12, - RFLAG_NT_LOC = 14, - RFLAG_RF_LOC = 16, - RFLAG_VM_LOC = 17, - RFLAG_AC_LOC = 18, - RFLAG_VIF_LOC = 19, - RFLAG_VIP_LOC = 20, - RFLAG_ID_LOC = 21, + RFLAG_CF_RAW_LOC = 0, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` + RFLAG_RESERVED_LOC = 1, // Reserved Bit, Read-as-1 + RFLAG_PF_RAW_LOC = 2, // Contains multiple bits, needs to be reconstructed using `ReconstructCompactedEFLAGS` + RFLAG_AF_RAW_LOC = 4, // Contains multiple bits, needs to be reconstructed using `ReconstructCompactedEFLAGS` + RFLAG_ZF_RAW_LOC = 6, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` + RFLAG_SF_RAW_LOC = 7, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` + RFLAG_TF_LOC = 8, + RFLAG_IF_LOC = 9, + RFLAG_DF_RAW_LOC = 10, // Contains multiple bits, needs to be reconstructed using `ReconstructCompactedEFLAGS` + RFLAG_OF_RAW_LOC = 11, // Not used directly, needs to be reconstructed using `ReconstructCompactedEFLAGS` + RFLAG_IOPL_LOC = 12, + RFLAG_NT_LOC = 14, + RFLAG_RF_LOC = 16, + RFLAG_VM_LOC = 17, + RFLAG_AC_LOC = 18, + RFLAG_VIF_LOC = 19, + RFLAG_VIP_LOC = 20, + RFLAG_ID_LOC = 21, // So we can implement arm64-like flag manipulaton on the x86 jit.. // SF/ZF/CF/OF packed into a 32-bit word, matching arm64's NZCV structure (not semantics). - RFLAG_NZCV_LOC = 24, + RFLAG_NZCV_LOC = 24, RFLAG_NZCV_1_LOC = 25, RFLAG_NZCV_2_LOC = 26, RFLAG_NZCV_3_LOC = 27, -// So we can share flag handling logic, we put x87 flags after RFLAGS - X87FLAG_BASE = 32, - X87FLAG_IE_LOC = 32, - X87FLAG_DE_LOC = 33, - X87FLAG_ZE_LOC = 34, - X87FLAG_OE_LOC = 35, - X87FLAG_UE_LOC = 36, - X87FLAG_PE_LOC = 37, - X87FLAG_SF_LOC = 38, - X87FLAG_ES_LOC = 39, - X87FLAG_C0_LOC = 40, - X87FLAG_C1_LOC = 41, - X87FLAG_C2_LOC = 42, + // So we can share flag handling logic, we put x87 flags after RFLAGS + X87FLAG_BASE = 32, + X87FLAG_IE_LOC = 32, + X87FLAG_DE_LOC = 33, + X87FLAG_ZE_LOC = 34, + X87FLAG_OE_LOC = 35, + X87FLAG_UE_LOC = 36, + X87FLAG_PE_LOC = 37, + X87FLAG_SF_LOC = 38, + X87FLAG_ES_LOC = 39, + X87FLAG_C0_LOC = 40, + X87FLAG_C1_LOC = 41, + X87FLAG_C2_LOC = 42, X87FLAG_TOP_LOC = 43, // 3 Bits wide - X87FLAG_C3_LOC = 46, - X87FLAG_B_LOC = 47, + X87FLAG_C3_LOC = 46, + X87FLAG_B_LOC = 47, }; // X86 trap number definitions enum X86TrapNo : uint32_t { - X86_TRAPNO_DE = 0, // Divide-by-zero - X86_TRAPNO_DB = 1, // Debug - X86_TRAPNO_NMI = 2, // Non-maskable interrupt - X86_TRAPNO_BP = 3, // Breakpoint - X86_TRAPNO_OF = 4, // Overflow - X86_TRAPNO_BR = 5, // Bound range exceeded - X86_TRAPNO_UD = 6, // Invalid opcode - X86_TRAPNO_NM = 7, // Device not available - X86_TRAPNO_DF = 8, // Double fault - X86_TRAPNO_OLD_MF = 9, // Coprocessor segment overrun - X86_TRAPNO_TS = 10, // Invalid TSS - X86_TRAPNO_NP = 11, // Segment not present - X86_TRAPNO_SS = 12, // Stack segmentation fault - X86_TRAPNO_GP = 13, // General Protection fault - X86_TRAPNO_PF = 14, // Page fault + X86_TRAPNO_DE = 0, // Divide-by-zero + X86_TRAPNO_DB = 1, // Debug + X86_TRAPNO_NMI = 2, // Non-maskable interrupt + X86_TRAPNO_BP = 3, // Breakpoint + X86_TRAPNO_OF = 4, // Overflow + X86_TRAPNO_BR = 5, // Bound range exceeded + X86_TRAPNO_UD = 6, // Invalid opcode + X86_TRAPNO_NM = 7, // Device not available + X86_TRAPNO_DF = 8, // Double fault + X86_TRAPNO_OLD_MF = 9, // Coprocessor segment overrun + X86_TRAPNO_TS = 10, // Invalid TSS + X86_TRAPNO_NP = 11, // Segment not present + X86_TRAPNO_SS = 12, // Stack segmentation fault + X86_TRAPNO_GP = 13, // General Protection fault + X86_TRAPNO_PF = 14, // Page fault X86_TRAPNO_SPURIOUS = 15, // Spurious interrupt - X86_TRAPNO_MF = 16, // X87 float exception - X86_TRAPNO_AC = 17, // Alignment check - X86_TRAPNO_MC = 18, // Machine check - X86_TRAPNO_XF = 19, // SIMD floating point exception - X86_TRAPNO_VE = 20, // Virtualization exception - X86_TRAPNO_CP = 21, // Control protection exception - X86_TRAPNO_VC = 29, // VMM communication exception - X86_TRAPNO_IRET = 32, // IRET exception + X86_TRAPNO_MF = 16, // X87 float exception + X86_TRAPNO_AC = 17, // Alignment check + X86_TRAPNO_MC = 18, // Machine check + X86_TRAPNO_XF = 19, // SIMD floating point exception + X86_TRAPNO_VE = 20, // Virtualization exception + X86_TRAPNO_CP = 21, // Control protection exception + X86_TRAPNO_VC = 29, // VMM communication exception + X86_TRAPNO_IRET = 32, // IRET exception }; // X86 page fault error code bits // Populates siginfo gregs[REG_ERR] enum X86PageFaultBit : uint32_t { - X86_PF_PROT = (1 << 0), // 0: No page found 1: protection fault + X86_PF_PROT = (1 << 0), // 0: No page found 1: protection fault X86_PF_WRITE = (1 << 1), // 0: Access was read 1: Access was write - X86_PF_USER = (1 << 2), // 0: Kernel mode access 1: user-mode access - X86_PF_RSV = (1 << 3), // 1: Reserved bit? + X86_PF_USER = (1 << 2), // 0: Kernel mode access 1: user-mode access + X86_PF_RSV = (1 << 3), // 1: Reserved bit? X86_PF_INSTR = (1 << 4), // 1: Fault from instruction fetch - X86_PF_PK = (1 << 5), // 1: Protection keys block access - X86_PF_SGX = (1 << 6), // 1: SGX MMU fault + X86_PF_PK = (1 << 5), // 1: Protection keys block access + X86_PF_SGX = (1 << 6), // 1: SGX MMU fault }; } // namespace FEXCore::X86State diff --git a/FEXCore/include/FEXCore/Debug/InternalThreadState.h b/FEXCore/include/FEXCore/Debug/InternalThreadState.h index cc1112751..f0288680f 100644 --- a/FEXCore/include/FEXCore/Debug/InternalThreadState.h +++ b/FEXCore/include/FEXCore/Debug/InternalThreadState.h @@ -15,130 +15,127 @@ #include namespace FEXCore { - class LookupCache; - class CompileService; -} +class LookupCache; +class CompileService; +} // namespace FEXCore namespace FEXCore::Context { - class Context; +class Context; } namespace FEXCore::CPU { - class CPUBackend; - union Relocation; -} +class CPUBackend; +union Relocation; +} // namespace FEXCore::CPU namespace FEXCore::Frontend { - class Decoder; +class Decoder; } -namespace FEXCore::IR{ - class OpDispatchBuilder; - class PassManager; -} +namespace FEXCore::IR { +class OpDispatchBuilder; +class PassManager; +} // namespace FEXCore::IR namespace FEXCore::Core { - struct DebugDataSubblock { - uint32_t HostCodeOffset; - uint32_t HostCodeSize; - }; +struct DebugDataSubblock { + uint32_t HostCodeOffset; + uint32_t HostCodeSize; +}; - struct DebugDataGuestOpcode { - uint64_t GuestEntryOffset; - ptrdiff_t HostEntryOffset; - }; +struct DebugDataGuestOpcode { + uint64_t GuestEntryOffset; + ptrdiff_t HostEntryOffset; +}; - /** - * @brief Contains debug data for a block of code for later debugger analysis - * - * Needs to remain around for as long as the code could be executed at least - */ - struct DebugData : public FEXCore::Allocator::FEXAllocOperators { - uint64_t HostCodeSize; ///< The size of the code generated in the host JIT - fextl::vector Subblocks; - fextl::vector GuestOpcodes; - fextl::vector *Relocations; - }; +/** + * @brief Contains debug data for a block of code for later debugger analysis + * + * Needs to remain around for as long as the code could be executed at least + */ +struct DebugData : public FEXCore::Allocator::FEXAllocOperators { + uint64_t HostCodeSize; ///< The size of the code generated in the host JIT + fextl::vector Subblocks; + fextl::vector GuestOpcodes; + fextl::vector* Relocations; +}; - // Buffered JIT symbol tracking. - struct JITSymbolBuffer { - // Maximum buffer size to ensure we are a page in size. - constexpr static size_t BUFFER_SIZE = 4096 - (8 * 2); - // Maximum distance until the end of the buffer to do a write. - constexpr static size_t NEEDS_WRITE_DISTANCE = BUFFER_SIZE - 64; - // Maximum time threshhold to wait before a buffer write occurs. - constexpr static std::chrono::milliseconds MAXIMUM_THRESHOLD {100}; +// Buffered JIT symbol tracking. +struct JITSymbolBuffer { + // Maximum buffer size to ensure we are a page in size. + constexpr static size_t BUFFER_SIZE = 4096 - (8 * 2); + // Maximum distance until the end of the buffer to do a write. + constexpr static size_t NEEDS_WRITE_DISTANCE = BUFFER_SIZE - 64; + // Maximum time threshhold to wait before a buffer write occurs. + constexpr static std::chrono::milliseconds MAXIMUM_THRESHOLD {100}; - JITSymbolBuffer() - : LastWrite {std::chrono::steady_clock::now()} { - } - // stead_clock to ensure a monotonic increasing clock. - // In highly stressed situations this can still cause >2% CPU time in vdso_clock_gettime. - // If we need lower CPU time when JIT symbols are enabled then FEX can read the cycle counter directly. - std::chrono::steady_clock::time_point LastWrite{}; - size_t Offset{}; - char Buffer[BUFFER_SIZE]{}; - }; - static_assert(sizeof(JITSymbolBuffer) == 4096, "Ensure this is one page in size"); + JITSymbolBuffer() + : LastWrite {std::chrono::steady_clock::now()} {} + // stead_clock to ensure a monotonic increasing clock. + // In highly stressed situations this can still cause >2% CPU time in vdso_clock_gettime. + // If we need lower CPU time when JIT symbols are enabled then FEX can read the cycle counter directly. + std::chrono::steady_clock::time_point LastWrite {}; + size_t Offset {}; + char Buffer[BUFFER_SIZE] {}; +}; +static_assert(sizeof(JITSymbolBuffer) == 4096, "Ensure this is one page in size"); - struct InternalThreadState : public FEXCore::Allocator::FEXAllocOperators { - FEXCore::Core::CpuStateFrame* const CurrentFrame = &BaseFrameState; +struct InternalThreadState : public FEXCore::Allocator::FEXAllocOperators { + FEXCore::Core::CpuStateFrame* const CurrentFrame = &BaseFrameState; - struct { - std::atomic_bool Running {false}; - std::atomic_bool WaitingToStart {true}; - std::atomic_bool EarlyExit {false}; - std::atomic_bool ThreadSleeping {false}; - } RunningEvents; + struct { + std::atomic_bool Running {false}; + std::atomic_bool WaitingToStart {true}; + std::atomic_bool EarlyExit {false}; + std::atomic_bool ThreadSleeping {false}; + } RunningEvents; - FEXCore::Context::Context *CTX; - std::atomic SignalReason{SignalEvent::Nothing}; + FEXCore::Context::Context* CTX; + std::atomic SignalReason {SignalEvent::Nothing}; - fextl::unique_ptr ExecutionThread; - bool StartPaused {false}; - InterruptableConditionVariable StartRunning; - Event ThreadWaiting; + fextl::unique_ptr ExecutionThread; + bool StartPaused {false}; + InterruptableConditionVariable StartRunning; + Event ThreadWaiting; - fextl::unique_ptr OpDispatcher; + fextl::unique_ptr OpDispatcher; - fextl::unique_ptr CPUBackend; - fextl::unique_ptr LookupCache; + fextl::unique_ptr CPUBackend; + fextl::unique_ptr LookupCache; - fextl::unique_ptr FrontendDecoder; - fextl::unique_ptr PassManager; - FEXCore::HLE::ThreadManagement ThreadManager; - fextl::unique_ptr SymbolBuffer; + fextl::unique_ptr FrontendDecoder; + fextl::unique_ptr PassManager; + FEXCore::HLE::ThreadManagement ThreadManager; + fextl::unique_ptr SymbolBuffer; - int StatusCode{}; - FEXCore::Context::ExitReason ExitReason {FEXCore::Context::ExitReason::EXIT_WAITING}; - std::shared_ptr CompileService; + int StatusCode {}; + FEXCore::Context::ExitReason ExitReason {FEXCore::Context::ExitReason::EXIT_WAITING}; + std::shared_ptr CompileService; - std::shared_mutex ObjectCacheRefCounter{}; + std::shared_mutex ObjectCacheRefCounter {}; - struct DeferredSignalState { + struct DeferredSignalState { #ifndef _WIN32 - siginfo_t Info; + siginfo_t Info; #endif - int Signal; - }; - - // Queue of thread local signal frames that have been deferred. - // Async signals aren't guaranteed to be delivered in any particular order, but FEX treats them as FILO. - fextl::vector DeferredSignalFrames; - - ///< Data pointer for exclusive use by the frontend - void* FrontendPtr; - - // BaseFrameState should always be at the end, directly before the interrupt fault page - alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState{}; - - // Can be reprotected as RO to trigger an interrupt at generated code block entrypoints - alignas(FEXCore::Utils::FEX_PAGE_SIZE) uint8_t InterruptFaultPage[FEXCore::Utils::FEX_PAGE_SIZE]; + int Signal; }; - static_assert((offsetof(FEXCore::Core::InternalThreadState, InterruptFaultPage) - - offsetof(FEXCore::Core::InternalThreadState, BaseFrameState)) < 4096, - "Fault page is outside of immediate range from CPU state"); - // static_assert(std::is_standard_layout::value, "This needs to be standard layout"); -} + // Queue of thread local signal frames that have been deferred. + // Async signals aren't guaranteed to be delivered in any particular order, but FEX treats them as FILO. + fextl::vector DeferredSignalFrames; + ///< Data pointer for exclusive use by the frontend + void* FrontendPtr; + + // BaseFrameState should always be at the end, directly before the interrupt fault page + alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState {}; + + // Can be reprotected as RO to trigger an interrupt at generated code block entrypoints + alignas(FEXCore::Utils::FEX_PAGE_SIZE) uint8_t InterruptFaultPage[FEXCore::Utils::FEX_PAGE_SIZE]; +}; +static_assert( + (offsetof(FEXCore::Core::InternalThreadState, InterruptFaultPage) - offsetof(FEXCore::Core::InternalThreadState, BaseFrameState)) < 4096, + "Fault page is outside of immediate range from CPU state"); +// static_assert(std::is_standard_layout::value, "This needs to be standard layout"); +} // namespace FEXCore::Core diff --git a/FEXCore/include/FEXCore/HLE/Linux/ThreadManagement.h b/FEXCore/include/FEXCore/HLE/Linux/ThreadManagement.h index b07f30576..e0d17cdc4 100644 --- a/FEXCore/include/FEXCore/HLE/Linux/ThreadManagement.h +++ b/FEXCore/include/FEXCore/HLE/Linux/ThreadManagement.h @@ -8,22 +8,34 @@ namespace FEXCore::HLE { // Tracking relationships between thread IDs and such class ThreadManagement { public: - uint64_t GetUID() const { return UID; } - uint64_t GetGID() const { return GID; } - uint64_t GetEUID() const { return EUID; } - uint64_t GetEGID() const { return EGID; } - uint64_t GetTID() const { return TID; } - uint64_t GetPID() const { return PID; } + uint64_t GetUID() const { + return UID; + } + uint64_t GetGID() const { + return GID; + } + uint64_t GetEUID() const { + return EUID; + } + uint64_t GetEGID() const { + return EGID; + } + uint64_t GetTID() const { + return TID; + } + uint64_t GetPID() const { + return PID; + } - uint64_t UID{1000}; - uint64_t GID{1000}; - uint64_t EUID{1000}; - uint64_t EGID{1000}; - std::atomic TID{1}; - uint64_t PID{1}; - int32_t *set_child_tid{0}; - int32_t *clear_child_tid{0}; - uint64_t parent_tid{0}; - uint64_t robust_list_head{0}; + uint64_t UID {1000}; + uint64_t GID {1000}; + uint64_t EUID {1000}; + uint64_t EGID {1000}; + std::atomic TID {1}; + uint64_t PID {1}; + int32_t* set_child_tid {0}; + int32_t* clear_child_tid {0}; + uint64_t parent_tid {0}; + uint64_t robust_list_head {0}; }; -} +} // namespace FEXCore::HLE diff --git a/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h b/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h index 4b89b886d..86cc31410 100644 --- a/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h +++ b/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h @@ -10,7 +10,7 @@ #include namespace FEXCore::IR { - struct AOTIRCacheEntry; +struct AOTIRCacheEntry; } namespace FEXCore::HLE { @@ -28,19 +28,16 @@ struct SourcecodeSymbolMapping { fextl::string Name; - static fextl::string SymName(const SourcecodeSymbolMapping *Sym, const fextl::string &GuestFilename, uintptr_t HostEntry, uintptr_t FileBegin) { + static fextl::string SymName(const SourcecodeSymbolMapping* Sym, const fextl::string& GuestFilename, uintptr_t HostEntry, uintptr_t FileBegin) { if (Sym) { auto SymOffset = FileBegin - Sym->FileGuestBegin; if (SymOffset) { - return fextl::fmt::format("{}: {}+{} @{:x}", std::filesystem::path(GuestFilename).stem().string(), Sym->Name, - SymOffset, HostEntry); + return fextl::fmt::format("{}: {}+{} @{:x}", std::filesystem::path(GuestFilename).stem().string(), Sym->Name, SymOffset, HostEntry); } else { - return fextl::fmt::format("{}: {} @{:x}", std::filesystem::path(GuestFilename).stem().string(), Sym->Name, - HostEntry); + return fextl::fmt::format("{}: {} @{:x}", std::filesystem::path(GuestFilename).stem().string(), Sym->Name, HostEntry); } } else { - return fextl::fmt::format("{}: +{} @{:x}", std::filesystem::path(GuestFilename).stem().string(), FileBegin, - HostEntry); + return fextl::fmt::format("{}: +{} @{:x}", std::filesystem::path(GuestFilename).stem().string(), FileBegin, HostEntry); } } }; @@ -51,13 +48,12 @@ struct SourcecodeMap { fextl::vector SortedSymbolMappings; template - void IterateLineMappings(uintptr_t FileBegin, uintptr_t Size, const F &Callback) const { + void IterateLineMappings(uintptr_t FileBegin, uintptr_t Size, const F& Callback) const { auto Begin = FileBegin; auto End = FileBegin + Size; - auto Found = std::lower_bound(SortedLineMappings.cbegin(), SortedLineMappings.cend(), Begin, [](const auto &Range, const auto Position) { - return Range.FileGuestEnd <= Position; - }); + auto Found = std::lower_bound(SortedLineMappings.cbegin(), SortedLineMappings.cend(), Begin, + [](const auto& Range, const auto Position) { return Range.FileGuestEnd <= Position; }); while (Found != SortedLineMappings.cend()) { if (Found->FileGuestBegin < End && Found->FileGuestEnd > Begin) { @@ -69,19 +65,18 @@ struct SourcecodeMap { } } - const SourcecodeLineMapping *FindLineMapping(uintptr_t FileBegin) const { + const SourcecodeLineMapping* FindLineMapping(uintptr_t FileBegin) const { return Find(FileBegin, SortedLineMappings); } - const SourcecodeSymbolMapping *FindSymbolMapping(uintptr_t FileBegin) const { + const SourcecodeSymbolMapping* FindSymbolMapping(uintptr_t FileBegin) const { return Find(FileBegin, SortedSymbolMappings); } private: template - const typename VecT::value_type *Find(uintptr_t FileBegin, const VecT &SortedMappings) const { - auto Found = std::lower_bound(SortedMappings.cbegin(), SortedMappings.cend(), FileBegin, [](const auto &Range, const auto Position) { - return Range.FileGuestEnd <= Position; - }); + const typename VecT::value_type* Find(uintptr_t FileBegin, const VecT& SortedMappings) const { + auto Found = std::lower_bound(SortedMappings.cbegin(), SortedMappings.cend(), FileBegin, + [](const auto& Range, const auto Position) { return Range.FileGuestEnd <= Position; }); if (Found != SortedMappings.end() && Found->FileGuestBegin <= FileBegin && Found->FileGuestEnd > FileBegin) { return &(*Found); @@ -95,4 +90,4 @@ class SourcecodeResolver { public: virtual fextl::unique_ptr GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) = 0; }; -} +} // namespace FEXCore::HLE diff --git a/FEXCore/include/FEXCore/HLE/SyscallHandler.h b/FEXCore/include/FEXCore/HLE/SyscallHandler.h index 4b1c28111..be216c709 100644 --- a/FEXCore/include/FEXCore/HLE/SyscallHandler.h +++ b/FEXCore/include/FEXCore/HLE/SyscallHandler.h @@ -6,78 +6,83 @@ #include namespace FEXCore::IR { - struct AOTIRCacheEntry; +struct AOTIRCacheEntry; } namespace FEXCore::Context { - class Context; +class Context; } namespace FEXCore::Core { - struct InternalThreadState; - struct CpuStateFrame; -} +struct InternalThreadState; +struct CpuStateFrame; +} // namespace FEXCore::Core namespace FEXCore::HLE { - struct SyscallArguments { - static constexpr std::size_t MAX_ARGS = 7; - uint64_t Argument[MAX_ARGS]; - }; +struct SyscallArguments { + static constexpr std::size_t MAX_ARGS = 7; + uint64_t Argument[MAX_ARGS]; +}; - struct SyscallABI { - // Expectation is that the backend will be aware of how to modify the arguments based on numbering - // Only GPRs expected - uint8_t NumArgs; - // If the syscall has a return then it should be stored in the ABI specific syscall register - // Linux = RAX - bool HasReturn; +struct SyscallABI { + // Expectation is that the backend will be aware of how to modify the arguments based on numbering + // Only GPRs expected + uint8_t NumArgs; + // If the syscall has a return then it should be stored in the ABI specific syscall register + // Linux = RAX + bool HasReturn; - int32_t HostSyscallNumber; - }; + int32_t HostSyscallNumber; +}; - enum class SyscallOSABI { - OS_UNKNOWN, - OS_LINUX64, - OS_LINUX32, - OS_WIN64, - OS_WIN32, - OS_HANGOVER, - }; +enum class SyscallOSABI { + OS_UNKNOWN, + OS_LINUX64, + OS_LINUX32, + OS_WIN64, + OS_WIN32, + OS_HANGOVER, +}; - class SyscallHandler; - class SourcecodeResolver; +class SyscallHandler; +class SourcecodeResolver; - struct AOTIRCacheEntryLookupResult { - AOTIRCacheEntryLookupResult(FEXCore::IR::AOTIRCacheEntry *Entry, uintptr_t VAFileStart) - : Entry(Entry), VAFileStart(VAFileStart) { +struct AOTIRCacheEntryLookupResult { + AOTIRCacheEntryLookupResult(FEXCore::IR::AOTIRCacheEntry* Entry, uintptr_t VAFileStart) + : Entry(Entry) + , VAFileStart(VAFileStart) {} - } + AOTIRCacheEntryLookupResult(AOTIRCacheEntryLookupResult&&) = default; - AOTIRCacheEntryLookupResult(AOTIRCacheEntryLookupResult&&) = default; + FEXCore::IR::AOTIRCacheEntry* Entry; + uintptr_t VAFileStart; - FEXCore::IR::AOTIRCacheEntry *Entry; - uintptr_t VAFileStart; + friend class SyscallHandler; +}; - friend class SyscallHandler; - }; +class SyscallHandler { +public: + virtual ~SyscallHandler() = default; - class SyscallHandler { - public: - virtual ~SyscallHandler() = default; + virtual uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args) = 0; + virtual SyscallABI GetSyscallABI(uint64_t Syscall) = 0; + virtual FEXCore::IR::SyscallFlags GetSyscallFlags(uint64_t Syscall) const { + return FEXCore::IR::SyscallFlags::DEFAULT; + } - virtual uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) = 0; - virtual SyscallABI GetSyscallABI(uint64_t Syscall) = 0; - virtual FEXCore::IR::SyscallFlags GetSyscallFlags(uint64_t Syscall) const { return FEXCore::IR::SyscallFlags::DEFAULT; } + SyscallOSABI GetOSABI() const { + return OSABI; + } + virtual void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) {} + virtual AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestAddr) = 0; - SyscallOSABI GetOSABI() const { return OSABI; } - virtual void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) { } - virtual AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestAddr) = 0; + virtual SourcecodeResolver* GetSourcecodeResolver() { + return nullptr; + } - virtual SourcecodeResolver *GetSourcecodeResolver() { return nullptr; } + virtual void SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame) {} - virtual void SleepThread(FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame) {} - - protected: - SyscallOSABI OSABI; - }; -} +protected: + SyscallOSABI OSABI; +}; +} // namespace FEXCore::HLE diff --git a/FEXCore/include/FEXCore/IR/IR.h b/FEXCore/include/FEXCore/IR/IR.h index a6179b97a..4d579a97f 100644 --- a/FEXCore/include/FEXCore/IR/IR.h +++ b/FEXCore/include/FEXCore/IR/IR.h @@ -20,21 +20,21 @@ class RegisterAllocationPass; class RegisterAllocationData; enum class SyscallFlags : uint8_t { - DEFAULT = 0, + DEFAULT = 0, // Syscalldoesn't care about CPUState being serialized up to the syscall instruction. // Means DeadCodeElimination can optimize through a syscall operation. - OPTIMIZETHROUGH = 1 << 0, + OPTIMIZETHROUGH = 1 << 0, // Syscall only reads the passed in arguments. Doesn't read CPUState. NOSYNCSTATEONENTRY = 1 << 1, // Syscall doesn't return. Code generation after syscall return can be removed. - NORETURN = 1 << 2, + NORETURN = 1 << 2, // Syscall doesn't have any side-effects, so if the result isn't used then it can be removed. - NOSIDEEFFECTS = 1 << 3, + NOSIDEEFFECTS = 1 << 3, // Syscall doesn't return a result. // Means the resulting register shouldn't be written (Usually RAX). // Usually used with !NOSYNCSTATEONENTRY, so the syscall can modify CPU state entirely. // Then on return FEXCore picks up the new state. - NORETURNEDRESULT = 1 << 4, + NORETURNEDRESULT = 1 << 4, }; FEX_DEF_NUM_OPS(SyscallFlags) @@ -89,11 +89,15 @@ enum IndexNamedVectorConstant : uint8_t { struct SHA256Sum final { uint8_t data[32]; - [[nodiscard]] bool operator<(SHA256Sum const &rhs) const { + [[nodiscard]] + bool + operator<(const SHA256Sum& rhs) const { return memcmp(data, rhs.data, sizeof(data)) < 0; } - [[nodiscard]] bool operator==(SHA256Sum const &rhs) const { + [[nodiscard]] + bool + operator==(const SHA256Sum& rhs) const { return memcmp(data, rhs.data, sizeof(data)) == 0; } }; @@ -102,7 +106,7 @@ typedef void ThunkedFunction(void* ArgsRv); struct ThunkDefinition final { SHA256Sum Sum; - ThunkedFunction *ThunkFunction; + ThunkedFunction* ThunkFunction; }; } // namespace FEXCore::IR diff --git a/FEXCore/include/FEXCore/Utils/Allocator.h b/FEXCore/include/FEXCore/Utils/Allocator.h index b57787442..638c3a431 100644 --- a/FEXCore/include/FEXCore/Utils/Allocator.h +++ b/FEXCore/include/FEXCore/Utils/Allocator.h @@ -10,77 +10,77 @@ #include namespace FEXCore::Allocator { - FEX_DEFAULT_VISIBILITY void SetupHooks(); - FEX_DEFAULT_VISIBILITY void ClearHooks(); +FEX_DEFAULT_VISIBILITY void SetupHooks(); +FEX_DEFAULT_VISIBILITY void ClearHooks(); - FEX_DEFAULT_VISIBILITY size_t DetermineVASize(); +FEX_DEFAULT_VISIBILITY size_t DetermineVASize(); #ifdef GLIBC_ALLOCATOR_FAULT - // Glibc hooks should only fault once we are in main. - // Required since glibc allocator hooking will catch things before FEX has control. - FEX_DEFAULT_VISIBILITY void SetupFaultEvaluate(); - // Glibc hook faulting needs to be disabled when leaving main. - // Required since glibc does some state teardown after main. - FEX_DEFAULT_VISIBILITY void ClearFaultEvaluate(); +// Glibc hooks should only fault once we are in main. +// Required since glibc allocator hooking will catch things before FEX has control. +FEX_DEFAULT_VISIBILITY void SetupFaultEvaluate(); +// Glibc hook faulting needs to be disabled when leaving main. +// Required since glibc does some state teardown after main. +FEX_DEFAULT_VISIBILITY void ClearFaultEvaluate(); - class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final { - public: - FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator(); - FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator(); - FEX_DEFAULT_VISIBILITY static void HardDisable(); - }; +class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final { +public: + FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator(); + FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator(); + FEX_DEFAULT_VISIBILITY static void HardDisable(); +}; - class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final { - public: - GLIBCScopedFault() { - FEXCore::Allocator::SetupFaultEvaluate(); - } - ~GLIBCScopedFault() { - FEXCore::Allocator::ClearFaultEvaluate(); - } - }; +class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final { +public: + GLIBCScopedFault() { + FEXCore::Allocator::SetupFaultEvaluate(); + } + ~GLIBCScopedFault() { + FEXCore::Allocator::ClearFaultEvaluate(); + } +}; #else - FEX_DEFAULT_VISIBILITY inline void SetupFaultEvaluate() {} - FEX_DEFAULT_VISIBILITY inline void ClearFaultEvaluate() {} +FEX_DEFAULT_VISIBILITY inline void SetupFaultEvaluate() {} +FEX_DEFAULT_VISIBILITY inline void ClearFaultEvaluate() {} - class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final { - public: - FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator() {} - FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator() {} - FEX_DEFAULT_VISIBILITY static inline void HardDisable() {} - }; +class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final { +public: + FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator() {} + FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator() {} + FEX_DEFAULT_VISIBILITY static inline void HardDisable() {} +}; - class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final { - public: - GLIBCScopedFault() { - // nop - } - ~GLIBCScopedFault() { - // nop - } - }; +class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final { +public: + GLIBCScopedFault() { + // nop + } + ~GLIBCScopedFault() { + // nop + } +}; #endif - // Disable allocations through glibc's sbrk allocation method. - // Returns a pointer at the end of the sbrk region. - FEX_DEFAULT_VISIBILITY void *DisableSBRKAllocations(); +// Disable allocations through glibc's sbrk allocation method. +// Returns a pointer at the end of the sbrk region. +FEX_DEFAULT_VISIBILITY void* DisableSBRKAllocations(); - // Allow sbrk again. Pass in the pointer returned by `DisableSBRKAllocations` - FEX_DEFAULT_VISIBILITY void ReenableSBRKAllocations(void* Ptr); +// Allow sbrk again. Pass in the pointer returned by `DisableSBRKAllocations` +FEX_DEFAULT_VISIBILITY void ReenableSBRKAllocations(void* Ptr); - struct MemoryRegion { - void *Ptr; - size_t Size; - }; +struct MemoryRegion { + void* Ptr; + size_t Size; +}; - FEX_DEFAULT_VISIBILITY fextl::vector CollectMemoryGaps(uintptr_t Begin, uintptr_t End, int MapsFD); - FEX_DEFAULT_VISIBILITY fextl::vector StealMemoryRegion(uintptr_t Begin, uintptr_t End); - FEX_DEFAULT_VISIBILITY void ReclaimMemoryRegion(const fextl::vector & Regions); - // When running a 64-bit executable on ARM then userspace guest only gets 47 bits of VA - // This is a feature of x86-64 where the kernel gets a full 128TB of VA space - // x86-64 canonical addresses with bit 48 set will sign extend the address (Ignoring LA57) - // AArch64 canonical addresses are only up to bits 48/52 with the remainder being other things - // Use this to reserve the top 128TB of VA so the guest never see it - // Returns nullptr on host VA < 48bits - FEX_DEFAULT_VISIBILITY fextl::vector Steal48BitVA(); -} +FEX_DEFAULT_VISIBILITY fextl::vector CollectMemoryGaps(uintptr_t Begin, uintptr_t End, int MapsFD); +FEX_DEFAULT_VISIBILITY fextl::vector StealMemoryRegion(uintptr_t Begin, uintptr_t End); +FEX_DEFAULT_VISIBILITY void ReclaimMemoryRegion(const fextl::vector& Regions); +// When running a 64-bit executable on ARM then userspace guest only gets 47 bits of VA +// This is a feature of x86-64 where the kernel gets a full 128TB of VA space +// x86-64 canonical addresses with bit 48 set will sign extend the address (Ignoring LA57) +// AArch64 canonical addresses are only up to bits 48/52 with the remainder being other things +// Use this to reserve the top 128TB of VA so the guest never see it +// Returns nullptr on host VA < 48bits +FEX_DEFAULT_VISIBILITY fextl::vector Steal48BitVA(); +} // namespace FEXCore::Allocator diff --git a/FEXCore/include/FEXCore/Utils/AllocatorHooks.h b/FEXCore/include/FEXCore/Utils/AllocatorHooks.h index 8650a2de4..7dda69ead 100644 --- a/FEXCore/include/FEXCore/Utils/AllocatorHooks.h +++ b/FEXCore/include/FEXCore/Utils/AllocatorHooks.h @@ -23,141 +23,193 @@ extern "C" { // jemalloc defines nothrow on its internal C function signatures. #ifdef ENABLE_JEMALLOC #define JEMALLOC_NOTHROW __attribute__((nothrow)) - // Forward declare jemalloc functions so we don't need to pull in the jemalloc header in to the public API. - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void *je_malloc(size_t size); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void *je_calloc(size_t n, size_t size); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void *je_memalign(size_t align, size_t s); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void *je_valloc(size_t size); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern int je_posix_memalign(void** r, size_t a, size_t s); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void *je_realloc(void* ptr, size_t size); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void je_free(void* ptr); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern size_t je_malloc_usable_size(void *ptr); - FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void *je_aligned_alloc(size_t a, size_t s); +// Forward declare jemalloc functions so we don't need to pull in the jemalloc header in to the public API. +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_malloc(size_t size); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_calloc(size_t n, size_t size); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_memalign(size_t align, size_t s); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_valloc(size_t size); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern int je_posix_memalign(void** r, size_t a, size_t s); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_realloc(void* ptr, size_t size); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void je_free(void* ptr); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern size_t je_malloc_usable_size(void* ptr); +FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_aligned_alloc(size_t a, size_t s); #undef JEMALLOC_NOTHROW #endif } namespace FEXCore::Allocator { #ifdef _WIN32 - inline void *VirtualAlloc(void* Base, size_t Size, bool Execute = false) { +inline void* VirtualAlloc(void* Base, size_t Size, bool Execute = false) { #ifdef _M_ARM_64EC - MEM_EXTENDED_PARAMETER Parameter{}; - if (Execute) { - Parameter.Type = MemExtendedParameterAttributeFlags; - Parameter.ULong64 = MEM_EXTENDED_PARAMETER_EC_CODE; - }; - return ::VirtualAlloc2(nullptr, Base, Size, MEM_COMMIT | (Base ? MEM_RESERVE : 0), Execute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, - &Parameter, Execute ? 1 : 0); -#else - return ::VirtualAlloc(Base, Size, MEM_COMMIT | (Base ? MEM_RESERVE : 0), Execute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); -#endif - } - - inline void *VirtualAlloc(size_t Size, bool Execute = false) { - return VirtualAlloc(nullptr, Size, Execute); - } - - inline void VirtualFree(void *Ptr, size_t Size) { - ::VirtualFree(Ptr, Size, MEM_RELEASE); - } - inline void VirtualDontNeed(void *Ptr, size_t Size) { - // Match madvise behaviour as best as we can here. - // Protections are ignored but still required to be valid. - ::VirtualAlloc(Ptr, Size, MEM_RESET, PAGE_NOACCESS); - } - -#else - using MMAP_Hook = void*(*)(void*, size_t, int, int, int, off_t); - using MUNMAP_Hook = int(*)(void*, size_t); - - FEX_DEFAULT_VISIBILITY extern MMAP_Hook mmap; - FEX_DEFAULT_VISIBILITY extern MUNMAP_Hook munmap; - - inline void *VirtualAlloc(size_t Size, bool Execute = false) { - return FEXCore::Allocator::mmap(nullptr, Size, PROT_READ | PROT_WRITE | (Execute ? PROT_EXEC : 0), MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - } - - inline void *VirtualAlloc(void *Base, size_t Size, bool Execute = false) { - return FEXCore::Allocator::mmap(Base, Size, PROT_READ | PROT_WRITE | (Execute ? PROT_EXEC : 0), MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - } - - inline void VirtualFree(void *Ptr, size_t Size) { - FEXCore::Allocator::munmap(Ptr, Size); - } - inline void VirtualDontNeed(void *Ptr, size_t Size) { - ::madvise(reinterpret_cast(Ptr), Size, MADV_DONTNEED); - } -#endif - - // Memory allocation routines aliased to jemalloc functions. -#ifdef ENABLE_JEMALLOC - inline void *malloc(size_t size) { return ::je_malloc(size); } - inline void *calloc(size_t n, size_t size) { return ::je_calloc(n, size); } - inline void *memalign(size_t align, size_t s) { return ::je_memalign(align, s); } - inline void *valloc(size_t size) { return ::je_valloc(size); } - inline int posix_memalign(void** r, size_t a, size_t s) { return ::je_posix_memalign(r, a, s); } - inline void *realloc(void* ptr, size_t size) { return ::je_realloc(ptr, size); } - inline void free(void* ptr) { return ::je_free(ptr); } - inline size_t malloc_usable_size(void *ptr) { return ::je_malloc_usable_size(ptr); } - inline void *aligned_alloc(size_t a, size_t s) { return ::je_aligned_alloc(a, s); } - inline void aligned_free(void* ptr) { return ::je_free(ptr); } -#elif defined(_WIN32) - inline void *malloc(size_t size) { return ::malloc(size); } - inline void *calloc(size_t n, size_t size) { return ::calloc(n, size); } - inline void *memalign(size_t align, size_t s) { return ::_aligned_malloc(s, align); } - inline void *valloc(size_t size) - { - return ::_aligned_malloc(size, 4096); - } - inline int posix_memalign(void** r, size_t a, size_t s) { - void* ptr = _aligned_malloc(s, a); - if (ptr) { - *r = ptr; - } - return errno; - } - inline void *realloc(void* ptr, size_t size) { return ::realloc(ptr, size); } - inline void free(void* ptr) { return ::free(ptr); } - inline size_t malloc_usable_size(void *ptr) { return ::_msize(ptr); } - inline void *aligned_alloc(size_t a, size_t s) { return ::_aligned_malloc(s, a); } - inline void aligned_free(void* ptr) { return ::_aligned_free(ptr); } -#else - inline void *malloc(size_t size) { return ::malloc(size); } - inline void *calloc(size_t n, size_t size) { return ::calloc(n, size); } - inline void *memalign(size_t align, size_t s) { return ::memalign(align, s); } - inline void *valloc(size_t size) - { -#ifdef __ANDROID__ - return ::aligned_alloc(4096, size); -#else - return ::valloc(size); -#endif - } - inline int posix_memalign(void** r, size_t a, size_t s) { return ::posix_memalign(r, a, s); } - inline void *realloc(void* ptr, size_t size) { return ::realloc(ptr, size); } - inline void free(void* ptr) { return ::free(ptr); } - inline size_t malloc_usable_size(void *ptr) { return ::malloc_usable_size(ptr); } - inline void *aligned_alloc(size_t a, size_t s) { return ::aligned_alloc(a, s); } - inline void aligned_free(void* ptr) { return ::free(ptr); } -#endif - - struct FEXAllocOperators { - FEXAllocOperators() = default; - - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void *operator new(size_t size, std::align_val_t align) { - return FEXCore::Allocator::aligned_alloc(static_cast(align), size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } - - void operator delete(void *ptr, std::align_val_t align) { - return FEXCore::Allocator::aligned_free(ptr); - } + MEM_EXTENDED_PARAMETER Parameter {}; + if (Execute) { + Parameter.Type = MemExtendedParameterAttributeFlags; + Parameter.ULong64 = MEM_EXTENDED_PARAMETER_EC_CODE; }; + return ::VirtualAlloc2(nullptr, Base, Size, MEM_COMMIT | (Base ? MEM_RESERVE : 0), Execute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, + &Parameter, Execute ? 1 : 0); +#else + return ::VirtualAlloc(Base, Size, MEM_COMMIT | (Base ? MEM_RESERVE : 0), Execute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); +#endif } + +inline void* VirtualAlloc(size_t Size, bool Execute = false) { + return VirtualAlloc(nullptr, Size, Execute); +} + +inline void VirtualFree(void* Ptr, size_t Size) { + ::VirtualFree(Ptr, Size, MEM_RELEASE); +} +inline void VirtualDontNeed(void* Ptr, size_t Size) { + // Match madvise behaviour as best as we can here. + // Protections are ignored but still required to be valid. + ::VirtualAlloc(Ptr, Size, MEM_RESET, PAGE_NOACCESS); +} + +#else +using MMAP_Hook = void* (*)(void*, size_t, int, int, int, off_t); +using MUNMAP_Hook = int (*)(void*, size_t); + +FEX_DEFAULT_VISIBILITY extern MMAP_Hook mmap; +FEX_DEFAULT_VISIBILITY extern MUNMAP_Hook munmap; + +inline void* VirtualAlloc(size_t Size, bool Execute = false) { + return FEXCore::Allocator::mmap(nullptr, Size, PROT_READ | PROT_WRITE | (Execute ? PROT_EXEC : 0), MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +inline void* VirtualAlloc(void* Base, size_t Size, bool Execute = false) { + return FEXCore::Allocator::mmap(Base, Size, PROT_READ | PROT_WRITE | (Execute ? PROT_EXEC : 0), MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +inline void VirtualFree(void* Ptr, size_t Size) { + FEXCore::Allocator::munmap(Ptr, Size); +} +inline void VirtualDontNeed(void* Ptr, size_t Size) { + ::madvise(reinterpret_cast(Ptr), Size, MADV_DONTNEED); +} +#endif + +// Memory allocation routines aliased to jemalloc functions. +#ifdef ENABLE_JEMALLOC +inline void* malloc(size_t size) { + return ::je_malloc(size); +} +inline void* calloc(size_t n, size_t size) { + return ::je_calloc(n, size); +} +inline void* memalign(size_t align, size_t s) { + return ::je_memalign(align, s); +} +inline void* valloc(size_t size) { + return ::je_valloc(size); +} +inline int posix_memalign(void** r, size_t a, size_t s) { + return ::je_posix_memalign(r, a, s); +} +inline void* realloc(void* ptr, size_t size) { + return ::je_realloc(ptr, size); +} +inline void free(void* ptr) { + return ::je_free(ptr); +} +inline size_t malloc_usable_size(void* ptr) { + return ::je_malloc_usable_size(ptr); +} +inline void* aligned_alloc(size_t a, size_t s) { + return ::je_aligned_alloc(a, s); +} +inline void aligned_free(void* ptr) { + return ::je_free(ptr); +} +#elif defined(_WIN32) +inline void* malloc(size_t size) { + return ::malloc(size); +} +inline void* calloc(size_t n, size_t size) { + return ::calloc(n, size); +} +inline void* memalign(size_t align, size_t s) { + return ::_aligned_malloc(s, align); +} +inline void* valloc(size_t size) { + return ::_aligned_malloc(size, 4096); +} +inline int posix_memalign(void** r, size_t a, size_t s) { + void* ptr = _aligned_malloc(s, a); + if (ptr) { + *r = ptr; + } + return errno; +} +inline void* realloc(void* ptr, size_t size) { + return ::realloc(ptr, size); +} +inline void free(void* ptr) { + return ::free(ptr); +} +inline size_t malloc_usable_size(void* ptr) { + return ::_msize(ptr); +} +inline void* aligned_alloc(size_t a, size_t s) { + return ::_aligned_malloc(s, a); +} +inline void aligned_free(void* ptr) { + return ::_aligned_free(ptr); +} +#else +inline void* malloc(size_t size) { + return ::malloc(size); +} +inline void* calloc(size_t n, size_t size) { + return ::calloc(n, size); +} +inline void* memalign(size_t align, size_t s) { + return ::memalign(align, s); +} +inline void* valloc(size_t size) { +#ifdef __ANDROID__ + return ::aligned_alloc(4096, size); +#else + return ::valloc(size); +#endif +} +inline int posix_memalign(void** r, size_t a, size_t s) { + return ::posix_memalign(r, a, s); +} +inline void* realloc(void* ptr, size_t size) { + return ::realloc(ptr, size); +} +inline void free(void* ptr) { + return ::free(ptr); +} +inline size_t malloc_usable_size(void* ptr) { + return ::malloc_usable_size(ptr); +} +inline void* aligned_alloc(size_t a, size_t s) { + return ::aligned_alloc(a, s); +} +inline void aligned_free(void* ptr) { + return ::free(ptr); +} +#endif + +struct FEXAllocOperators { + FEXAllocOperators() = default; + + void* operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void* operator new(size_t size, std::align_val_t align) { + return FEXCore::Allocator::aligned_alloc(static_cast(align), size); + } + + void operator delete(void* ptr) { + return FEXCore::Allocator::free(ptr); + } + + void operator delete(void* ptr, std::align_val_t align) { + return FEXCore::Allocator::aligned_free(ptr); + } +}; +} // namespace FEXCore::Allocator diff --git a/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h b/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h index d2e59fd77..7f4721721 100644 --- a/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h +++ b/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h @@ -7,123 +7,121 @@ #include namespace FEXCore::Core { - struct InternalThreadState; +struct InternalThreadState; } namespace FEXCore::ArchHelpers::Arm64 { - constexpr uint32_t CASPAL_MASK = 0xBF'E0'FC'00; - constexpr uint32_t CASPAL_INST = 0x08'60'FC'00; +constexpr uint32_t CASPAL_MASK = 0xBF'E0'FC'00; +constexpr uint32_t CASPAL_INST = 0x08'60'FC'00; - constexpr uint32_t CASAL_MASK = 0x3F'E0'FC'00; - constexpr uint32_t CASAL_INST = 0x08'E0'FC'00; +constexpr uint32_t CASAL_MASK = 0x3F'E0'FC'00; +constexpr uint32_t CASAL_INST = 0x08'E0'FC'00; - constexpr uint32_t ATOMIC_MEM_MASK = 0x3B200C00; - constexpr uint32_t ATOMIC_MEM_INST = 0x38200000; +constexpr uint32_t ATOMIC_MEM_MASK = 0x3B200C00; +constexpr uint32_t ATOMIC_MEM_INST = 0x38200000; - constexpr uint32_t RCPC2_MASK = 0x3F'E0'0C'00; - constexpr uint32_t LDAPUR_INST = 0x19'40'00'00; - constexpr uint32_t STLUR_INST = 0x19'00'00'00; +constexpr uint32_t RCPC2_MASK = 0x3F'E0'0C'00; +constexpr uint32_t LDAPUR_INST = 0x19'40'00'00; +constexpr uint32_t STLUR_INST = 0x19'00'00'00; - constexpr uint32_t LDAXP_MASK = 0xBF'FF'80'00; - constexpr uint32_t LDAXP_INST = 0x88'7F'80'00; +constexpr uint32_t LDAXP_MASK = 0xBF'FF'80'00; +constexpr uint32_t LDAXP_INST = 0x88'7F'80'00; - constexpr uint32_t STLXP_MASK = 0xBF'E0'80'00; - constexpr uint32_t STLXP_INST = 0x88'20'80'00; +constexpr uint32_t STLXP_MASK = 0xBF'E0'80'00; +constexpr uint32_t STLXP_INST = 0x88'20'80'00; - constexpr uint32_t LDAXR_MASK = 0x3F'FF'FC'00; - constexpr uint32_t LDAXR_INST = 0x08'5F'FC'00; - constexpr uint32_t LDAR_INST = 0x08'DF'FC'00; - constexpr uint32_t LDAPR_INST = 0x38'BF'C0'00; - constexpr uint32_t STLR_INST = 0x08'9F'FC'00; +constexpr uint32_t LDAXR_MASK = 0x3F'FF'FC'00; +constexpr uint32_t LDAXR_INST = 0x08'5F'FC'00; +constexpr uint32_t LDAR_INST = 0x08'DF'FC'00; +constexpr uint32_t LDAPR_INST = 0x38'BF'C0'00; +constexpr uint32_t STLR_INST = 0x08'9F'FC'00; - constexpr uint32_t STLXR_MASK = 0x3F'E0'FC'00; - constexpr uint32_t STLXR_INST = 0x08'00'FC'00; +constexpr uint32_t STLXR_MASK = 0x3F'E0'FC'00; +constexpr uint32_t STLXR_INST = 0x08'00'FC'00; - constexpr uint32_t CBNZ_MASK = 0x7F'00'00'00; - constexpr uint32_t CBNZ_INST = 0x35'00'00'00; +constexpr uint32_t CBNZ_MASK = 0x7F'00'00'00; +constexpr uint32_t CBNZ_INST = 0x35'00'00'00; - constexpr uint32_t ALU_OP_MASK = 0x7F'20'00'00; - constexpr uint32_t ADD_INST = 0x0B'00'00'00; - constexpr uint32_t SUB_INST = 0x4B'00'00'00; - constexpr uint32_t ADD_SHIFT_INST = 0x0B'20'00'00; - constexpr uint32_t SUB_SHIFT_INST = 0x4B'20'00'00; - constexpr uint32_t CMP_INST = 0x6B'00'00'00; - constexpr uint32_t CMP_SHIFT_INST = 0x6B'20'00'00; - constexpr uint32_t AND_INST = 0x0A'00'00'00; - constexpr uint32_t BIC_INST = 0x0A'20'00'00; - constexpr uint32_t OR_INST = 0x2A'00'00'00; - constexpr uint32_t ORN_INST = 0x2A'20'00'00; - constexpr uint32_t EOR_INST = 0x4A'00'00'00; - constexpr uint32_t EON_INST = 0x4A'20'00'00; +constexpr uint32_t ALU_OP_MASK = 0x7F'20'00'00; +constexpr uint32_t ADD_INST = 0x0B'00'00'00; +constexpr uint32_t SUB_INST = 0x4B'00'00'00; +constexpr uint32_t ADD_SHIFT_INST = 0x0B'20'00'00; +constexpr uint32_t SUB_SHIFT_INST = 0x4B'20'00'00; +constexpr uint32_t CMP_INST = 0x6B'00'00'00; +constexpr uint32_t CMP_SHIFT_INST = 0x6B'20'00'00; +constexpr uint32_t AND_INST = 0x0A'00'00'00; +constexpr uint32_t BIC_INST = 0x0A'20'00'00; +constexpr uint32_t OR_INST = 0x2A'00'00'00; +constexpr uint32_t ORN_INST = 0x2A'20'00'00; +constexpr uint32_t EOR_INST = 0x4A'00'00'00; +constexpr uint32_t EON_INST = 0x4A'20'00'00; - constexpr uint32_t CCMP_MASK = 0x7F'E0'0C'10; - constexpr uint32_t CCMP_INST = 0x7A'40'00'00; +constexpr uint32_t CCMP_MASK = 0x7F'E0'0C'10; +constexpr uint32_t CCMP_INST = 0x7A'40'00'00; - constexpr uint32_t CLREX_MASK = 0xFF'FF'F0'FF; - constexpr uint32_t CLREX_INST = 0xD5'03'30'5F; +constexpr uint32_t CLREX_MASK = 0xFF'FF'F0'FF; +constexpr uint32_t CLREX_INST = 0xD5'03'30'5F; - enum ExclusiveAtomicPairType { - TYPE_SWAP, - TYPE_ADD, - TYPE_SUB, - TYPE_AND, - TYPE_BIC, - TYPE_OR, - TYPE_ORN, - TYPE_EOR, - TYPE_EON, - TYPE_NEG, // This is just a sub with zero. Need to know the differences - }; +enum ExclusiveAtomicPairType { + TYPE_SWAP, + TYPE_ADD, + TYPE_SUB, + TYPE_AND, + TYPE_BIC, + TYPE_OR, + TYPE_ORN, + TYPE_EOR, + TYPE_EON, + TYPE_NEG, // This is just a sub with zero. Need to know the differences +}; - // Load ops are 4 bits - // Acquire and release bits are independent on the instruction - constexpr uint32_t ATOMIC_ADD_OP = 0b0000; - constexpr uint32_t ATOMIC_CLR_OP = 0b0001; - constexpr uint32_t ATOMIC_EOR_OP = 0b0010; - constexpr uint32_t ATOMIC_SET_OP = 0b0011; - constexpr uint32_t ATOMIC_SMAX_OP = 0b0100; - constexpr uint32_t ATOMIC_SMIN_OP = 0b0101; - constexpr uint32_t ATOMIC_UMAX_OP = 0b0110; - constexpr uint32_t ATOMIC_UMIN_OP = 0b0111; - constexpr uint32_t ATOMIC_SWAP_OP = 0b1000; +// Load ops are 4 bits +// Acquire and release bits are independent on the instruction +constexpr uint32_t ATOMIC_ADD_OP = 0b0000; +constexpr uint32_t ATOMIC_CLR_OP = 0b0001; +constexpr uint32_t ATOMIC_EOR_OP = 0b0010; +constexpr uint32_t ATOMIC_SET_OP = 0b0011; +constexpr uint32_t ATOMIC_SMAX_OP = 0b0100; +constexpr uint32_t ATOMIC_SMIN_OP = 0b0101; +constexpr uint32_t ATOMIC_UMAX_OP = 0b0110; +constexpr uint32_t ATOMIC_UMIN_OP = 0b0111; +constexpr uint32_t ATOMIC_SWAP_OP = 0b1000; - constexpr uint32_t REGISTER_MASK = 0b11111; - constexpr uint32_t RD_OFFSET = 0; - constexpr uint32_t RN_OFFSET = 5; - constexpr uint32_t RM_OFFSET = 16; +constexpr uint32_t REGISTER_MASK = 0b11111; +constexpr uint32_t RD_OFFSET = 0; +constexpr uint32_t RN_OFFSET = 5; +constexpr uint32_t RM_OFFSET = 16; - constexpr uint32_t DMB = 0b1101'0101'0000'0011'0011'0000'1011'1111 | - 0b1011'0000'0000; // Inner shareable all +constexpr uint32_t DMB = 0b1101'0101'0000'0011'0011'0000'1011'1111 | 0b1011'0000'0000; // Inner shareable all - constexpr uint32_t DMB_LD = 0b1101'0101'0000'0011'0011'0000'1011'1111 | - 0b1101'0000'0000; // Inner shareable load +constexpr uint32_t DMB_LD = 0b1101'0101'0000'0011'0011'0000'1011'1111 | 0b1101'0000'0000; // Inner shareable load - inline uint32_t GetRdReg(uint32_t Instr) { - return (Instr >> RD_OFFSET) & REGISTER_MASK; - } - - inline uint32_t GetRnReg(uint32_t Instr) { - return (Instr >> RN_OFFSET) & REGISTER_MASK; - } - - inline uint32_t GetRmReg(uint32_t Instr) { - return (Instr >> RM_OFFSET) & REGISTER_MASK; - } - - /** - * @brief On ARM64 handles an unaligned memory access that the JIT has done. - * - * This is an OS agnostic handler where the frontend must provide FEXCore with the information necessary to know if this is safe. - * This does not check if the PC is within a JIT code buffer, the frontend must provide that safety with `CPUBackend::IsAddressInCodeBuffer`. - * - * @param ParanoidTSO If the unaligned fault needs to handled directly or can be backpatched. - * @param ProgramCounter The location in memory for the instruction that did the access - * @param GPRs The array of GPRs from the signal context. This will be modified and the host context needs to be updated on signal return. - * - * @return A pair where the first element is if the unaligned access has been handle and the second element is how many bytes to modify the host PC - * by. FEXCore will return a positive or negative offset depending on internal handling. - */ - [[nodiscard]] - FEX_DEFAULT_VISIBILITY - std::pair HandleUnalignedAccess(FEXCore::Core::InternalThreadState *Thread, bool ParanoidTSO, uintptr_t ProgramCounter, uint64_t *GPRs); +inline uint32_t GetRdReg(uint32_t Instr) { + return (Instr >> RD_OFFSET) & REGISTER_MASK; } + +inline uint32_t GetRnReg(uint32_t Instr) { + return (Instr >> RN_OFFSET) & REGISTER_MASK; +} + +inline uint32_t GetRmReg(uint32_t Instr) { + return (Instr >> RM_OFFSET) & REGISTER_MASK; +} + +/** + * @brief On ARM64 handles an unaligned memory access that the JIT has done. + * + * This is an OS agnostic handler where the frontend must provide FEXCore with the information necessary to know if this is safe. + * This does not check if the PC is within a JIT code buffer, the frontend must provide that safety with `CPUBackend::IsAddressInCodeBuffer`. + * + * @param ParanoidTSO If the unaligned fault needs to handled directly or can be backpatched. + * @param ProgramCounter The location in memory for the instruction that did the access + * @param GPRs The array of GPRs from the signal context. This will be modified and the host context needs to be updated on signal return. + * + * @return A pair where the first element is if the unaligned access has been handle and the second element is how many bytes to modify the host PC + * by. FEXCore will return a positive or negative offset depending on internal handling. + */ +[[nodiscard]] +FEX_DEFAULT_VISIBILITY std::pair +HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, bool ParanoidTSO, uintptr_t ProgramCounter, uint64_t* GPRs); +} // namespace FEXCore::ArchHelpers::Arm64 diff --git a/FEXCore/include/FEXCore/Utils/CPUInfo.h b/FEXCore/include/FEXCore/Utils/CPUInfo.h index 1207808b2..99d48c3c7 100644 --- a/FEXCore/include/FEXCore/Utils/CPUInfo.h +++ b/FEXCore/include/FEXCore/Utils/CPUInfo.h @@ -5,10 +5,10 @@ #include namespace FEXCore::CPUInfo { - /** - * @brief Calculate the number of CPUs in the system regardless of affinity mask. - * - * @return The number of CPUs in the system. - */ - FEX_DEFAULT_VISIBILITY uint32_t CalculateNumberOfCPUs(); -} +/** + * @brief Calculate the number of CPUs in the system regardless of affinity mask. + * + * @return The number of CPUs in the system. + */ +FEX_DEFAULT_VISIBILITY uint32_t CalculateNumberOfCPUs(); +} // namespace FEXCore::CPUInfo diff --git a/FEXCore/include/FEXCore/Utils/CompilerDefs.h b/FEXCore/include/FEXCore/Utils/CompilerDefs.h index 09cb1eef3..bd7070d22 100644 --- a/FEXCore/include/FEXCore/Utils/CompilerDefs.h +++ b/FEXCore/include/FEXCore/Utils/CompilerDefs.h @@ -29,7 +29,7 @@ #define FEX_UNREACHABLE __builtin_unreachable() namespace FEXCore::Assert { - // This function can not be inlined - [[noreturn]] - FEX_DEFAULT_VISIBILITY void ForcedAssert(); -} +// This function can not be inlined +[[noreturn]] +FEX_DEFAULT_VISIBILITY void ForcedAssert(); +} // namespace FEXCore::Assert diff --git a/FEXCore/include/FEXCore/Utils/EnumOperators.h b/FEXCore/include/FEXCore/Utils/EnumOperators.h index d729d2b0a..48ad8a012 100644 --- a/FEXCore/include/FEXCore/Utils/EnumOperators.h +++ b/FEXCore/include/FEXCore/Utils/EnumOperators.h @@ -2,30 +2,27 @@ #pragma once #define FEX_DEF_ENUM_CLASS_BIN_OP(Enum, Op) \ -[[maybe_unused]] \ -static constexpr Enum operator Op(Enum lhs, Enum rhs) { \ + [[maybe_unused]] static constexpr Enum operator Op(Enum lhs, Enum rhs) { \ using Type = std::underlying_type_t; \ Type _lhs = static_cast(lhs); \ Type _rhs = static_cast(rhs); \ return static_cast(_lhs Op _rhs); \ -} \ -[[maybe_unused]] \ -static constexpr uint64_t operator Op(uint64_t lhs, Enum rhs) { \ + } \ + [[maybe_unused]] static constexpr uint64_t operator Op(uint64_t lhs, Enum rhs) { \ using Type = std::underlying_type_t; \ Type _rhs = static_cast(rhs); \ return lhs Op _rhs; \ -} + } #define FEX_DEF_ENUM_CLASS_UNARY_OP(Enum, Op) \ -[[maybe_unused]] \ -static constexpr Enum operator Op(Enum rhs) { \ + [[maybe_unused]] static constexpr Enum operator Op(Enum rhs) { \ using Type = std::underlying_type_t; \ Type _rhs = static_cast(rhs); \ return static_cast(Op _rhs); \ -} + } #define FEX_DEF_NUM_OPS(Enum) \ - FEX_DEF_ENUM_CLASS_BIN_OP(Enum, |) \ - FEX_DEF_ENUM_CLASS_BIN_OP(Enum, &) \ - FEX_DEF_ENUM_CLASS_BIN_OP(Enum, ^) \ - FEX_DEF_ENUM_CLASS_UNARY_OP(Enum, ~) + FEX_DEF_ENUM_CLASS_BIN_OP(Enum, |) \ + FEX_DEF_ENUM_CLASS_BIN_OP(Enum, &) \ + FEX_DEF_ENUM_CLASS_BIN_OP(Enum, ^) \ + FEX_DEF_ENUM_CLASS_UNARY_OP(Enum, ~) diff --git a/FEXCore/include/FEXCore/Utils/EnumUtils.h b/FEXCore/include/FEXCore/Utils/EnumUtils.h index 9576e4f31..66445689b 100644 --- a/FEXCore/include/FEXCore/Utils/EnumUtils.h +++ b/FEXCore/include/FEXCore/Utils/EnumUtils.h @@ -10,47 +10,58 @@ namespace FEXCore { // Macro that defines all of the built in operators for conveniently using // enum classes as flag types without needing to define all of the basic // boilerplate. -#define FEX_DECLARE_ENUM_FLAG_OPERATORS(type) \ - [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \ - using T = std::underlying_type_t; \ - return static_cast(static_cast(a) | static_cast(b)); \ - } \ - [[nodiscard]] constexpr type operator&(type a, type b) noexcept { \ - using T = std::underlying_type_t; \ - return static_cast(static_cast(a) & static_cast(b)); \ - } \ - [[nodiscard]] constexpr type operator^(type a, type b) noexcept { \ - using T = std::underlying_type_t; \ - return static_cast(static_cast(a) ^ static_cast(b)); \ - } \ - constexpr type& operator|=(type& a, type b) noexcept { \ - a = a | b; \ - return a; \ - } \ - constexpr type& operator&=(type& a, type b) noexcept { \ - a = a & b; \ - return a; \ - } \ - constexpr type& operator^=(type& a, type b) noexcept { \ - a = a ^ b; \ - return a; \ - } \ - [[nodiscard]] constexpr type operator~(type key) noexcept { \ - using T = std::underlying_type_t; \ - return static_cast(~static_cast(key)); \ - } \ - [[nodiscard]] constexpr bool True(type key) noexcept { \ - using T = std::underlying_type_t; \ - return static_cast(key) != 0; \ - } \ - [[nodiscard]] constexpr bool False(type key) noexcept { \ - using T = std::underlying_type_t; \ - return static_cast(key) == 0; \ - } +#define FEX_DECLARE_ENUM_FLAG_OPERATORS(type) \ + [[nodiscard]] \ + constexpr type \ + operator|(type a, type b) noexcept { \ + using T = std::underlying_type_t; \ + return static_cast(static_cast(a) | static_cast(b)); \ + } \ + [[nodiscard]] \ + constexpr type \ + operator&(type a, type b) noexcept { \ + using T = std::underlying_type_t; \ + return static_cast(static_cast(a) & static_cast(b)); \ + } \ + [[nodiscard]] \ + constexpr type \ + operator^(type a, type b) noexcept { \ + using T = std::underlying_type_t; \ + return static_cast(static_cast(a) ^ static_cast(b)); \ + } \ + constexpr type& operator|=(type& a, type b) noexcept { \ + a = a | b; \ + return a; \ + } \ + constexpr type& operator&=(type& a, type b) noexcept { \ + a = a & b; \ + return a; \ + } \ + constexpr type& operator^=(type& a, type b) noexcept { \ + a = a ^ b; \ + return a; \ + } \ + [[nodiscard]] \ + constexpr type \ + operator~(type key) noexcept { \ + using T = std::underlying_type_t; \ + return static_cast(~static_cast(key)); \ + } \ + [[nodiscard]] \ + constexpr bool True(type key) noexcept { \ + using T = std::underlying_type_t; \ + return static_cast(key) != 0; \ + } \ + [[nodiscard]] \ + constexpr bool False(type key) noexcept { \ + using T = std::underlying_type_t; \ + return static_cast(key) == 0; \ + } // Equivalent to C++23's std::to_underlying. -template -[[nodiscard]] constexpr std::underlying_type_t ToUnderlying(Enum e) noexcept { +template +[[nodiscard]] +constexpr std::underlying_type_t ToUnderlying(Enum e) noexcept { return static_cast>(e); } diff --git a/FEXCore/include/FEXCore/Utils/Event.h b/FEXCore/include/FEXCore/Utils/Event.h index 52b5d53f5..3cf0de9ad 100644 --- a/FEXCore/include/FEXCore/Utils/Event.h +++ b/FEXCore/include/FEXCore/Utils/Event.h @@ -6,23 +6,23 @@ class Event final { private: -/** - * @brief Literally just an atomic bool that we are using for this class - */ -class Flag final { -public: - bool TestAndSet(bool SetValue = true) { - bool Expected = !SetValue; - return Value.compare_exchange_strong(Expected, SetValue); - } + /** + * @brief Literally just an atomic bool that we are using for this class + */ + class Flag final { + public: + bool TestAndSet(bool SetValue = true) { + bool Expected = !SetValue; + return Value.compare_exchange_strong(Expected, SetValue); + } - bool TestAndClear() { - return TestAndSet(false); - } + bool TestAndClear() { + return TestAndSet(false); + } -private: - std::atomic_bool Value {false}; -}; + private: + std::atomic_bool Value {false}; + }; public: ~Event() { @@ -44,21 +44,23 @@ public: void Wait() { // Have we signaled before we started waiting? - if (FlagObject.TestAndClear()) + if (FlagObject.TestAndClear()) { return; + } std::unique_lock lk(MutexObject); - CondObject.wait(lk, [this]{ return FlagObject.TestAndClear(); }); + CondObject.wait(lk, [this] { return FlagObject.TestAndClear(); }); } template - bool WaitFor(std::chrono::duration const& time) { + bool WaitFor(const std::chrono::duration& time) { // Have we signaled before we started waiting? - if (FlagObject.TestAndClear()) + if (FlagObject.TestAndClear()) { return true; + } std::unique_lock lk(MutexObject); - bool DidSignal = CondObject.wait_for(lk, time, [this]{ return FlagObject.TestAndClear(); }); + bool DidSignal = CondObject.wait_for(lk, time, [this] { return FlagObject.TestAndClear(); }); return DidSignal; } diff --git a/FEXCore/include/FEXCore/Utils/FPState.h b/FEXCore/include/FEXCore/Utils/FPState.h index 725933b79..824f3c55d 100644 --- a/FEXCore/include/FEXCore/Utils/FPState.h +++ b/FEXCore/include/FEXCore/Utils/FPState.h @@ -4,67 +4,62 @@ #include namespace FEXCore::FPState { - enum class X87Tag : uint8_t { - Valid = 0b00, - Zero = 0b01, - Special = 0b10, - Empty = 0b11 - }; +enum class X87Tag : uint8_t { Valid = 0b00, Zero = 0b01, Special = 0b10, Empty = 0b11 }; - static inline X87Tag GetX87Tag(uint64_t (&Reg)[2], bool Valid) { - if (!Valid) { - return X87Tag::Empty; - } +static inline X87Tag GetX87Tag(uint64_t (&Reg)[2], bool Valid) { + if (!Valid) { + return X87Tag::Empty; + } - const uint64_t Exponent = Reg[1] & 0x7fff; - if (Exponent == 0x7fff) { - // (Pseudo) NaN / Inf - return X87Tag::Special; - } + const uint64_t Exponent = Reg[1] & 0x7fff; + if (Exponent == 0x7fff) { + // (Pseudo) NaN / Inf + return X87Tag::Special; + } - const bool JBit = Reg[0] & (1ULL << 63); - if (Exponent == 0) { - const uint64_t Fraction = Reg[0] & ((1ULL << 63) - 1); - if (!JBit && !Fraction) { - return X87Tag::Zero; - } else { - // (Pseudo) Subnormal - return X87Tag::Special; - } - } - - if (JBit) { - // Normal - return X87Tag::Valid; + const bool JBit = Reg[0] & (1ULL << 63); + if (Exponent == 0) { + const uint64_t Fraction = Reg[0] & ((1ULL << 63) - 1); + if (!JBit && !Fraction) { + return X87Tag::Zero; } else { - // Invalid + // (Pseudo) Subnormal return X87Tag::Special; } } - static inline uint16_t ConvertFromAbridgedFTW(uint16_t FSW, uint64_t (&MM)[8][2], uint8_t AbridgedFTW) { - const uint32_t StackTop = (FSW >> 11) & 0b111; - - uint16_t FTW = 0; - for (uint32_t i = 0; i < 8; i++) { - // The AMD manually incorrectly states there is a direct mapping here, only the intel-manual correctly states - // the stack-relative behaviour - const uint16_t StackIndex = (i - StackTop) & 0b111; - const X87Tag Tag = GetX87Tag(MM[StackIndex], AbridgedFTW & (1 << i)); - FTW |= static_cast(Tag) << (2 * i); - } - - return FTW; - } - - static inline uint8_t ConvertToAbridgedFTW(uint16_t FTW) { - uint8_t AbridgedFTW = 0; - - for (uint32_t i = 0; i < 8; i++) { - const X87Tag Tag = static_cast((FTW >> (2 * i)) & 3); - AbridgedFTW |= ((Tag == X87Tag::Empty) ? 0 : 1) << i; - } - - return AbridgedFTW; + if (JBit) { + // Normal + return X87Tag::Valid; + } else { + // Invalid + return X87Tag::Special; } } + +static inline uint16_t ConvertFromAbridgedFTW(uint16_t FSW, uint64_t (&MM)[8][2], uint8_t AbridgedFTW) { + const uint32_t StackTop = (FSW >> 11) & 0b111; + + uint16_t FTW = 0; + for (uint32_t i = 0; i < 8; i++) { + // The AMD manually incorrectly states there is a direct mapping here, only the intel-manual correctly states + // the stack-relative behaviour + const uint16_t StackIndex = (i - StackTop) & 0b111; + const X87Tag Tag = GetX87Tag(MM[StackIndex], AbridgedFTW & (1 << i)); + FTW |= static_cast(Tag) << (2 * i); + } + + return FTW; +} + +static inline uint8_t ConvertToAbridgedFTW(uint16_t FTW) { + uint8_t AbridgedFTW = 0; + + for (uint32_t i = 0; i < 8; i++) { + const X87Tag Tag = static_cast((FTW >> (2 * i)) & 3); + AbridgedFTW |= ((Tag == X87Tag::Empty) ? 0 : 1) << i; + } + + return AbridgedFTW; +} +} // namespace FEXCore::FPState diff --git a/FEXCore/include/FEXCore/Utils/File.h b/FEXCore/include/FEXCore/Utils/File.h index 687243246..47e7ced22 100644 --- a/FEXCore/include/FEXCore/Utils/File.h +++ b/FEXCore/include/FEXCore/Utils/File.h @@ -14,249 +14,258 @@ #endif namespace FEXCore::File { - enum class FileModes : uint32_t { - READ = (1U << 0), - WRITE = (1U << 1), - CREATE = (1U << 2), - TRUNCATE = (1U << 3), +enum class FileModes : uint32_t { + READ = (1U << 0), + WRITE = (1U << 1), + CREATE = (1U << 2), + TRUNCATE = (1U << 3), +}; + +enum class SeekOp { + BEGIN, + CURRENT, + END, +}; + +FEX_DEF_NUM_OPS(FileModes) + +class File final { +public: +#ifndef _WIN32 + using FileHandleType = int; +#else + using FileHandleType = HANDLE; +#endif + + File() = default; + + File(const char* Filepath, FileModes Modes) { +#ifndef _WIN32 + auto Disp = TranslateModes(Modes); + Handle = open(Filepath, Disp, DEFAULT_USER_PERMS); + IsValidHandle = Handle != -1; +#else + auto Disp = TranslateModes(Modes); + if (Disp.CreationFlag == OPEN_ALWAYS && Disp.TruncateOnExist) { + // If Open + Truncate then try to open with truncate behaviour first. + Handle = CreateFileA(Filepath, Disp.Access, DEFAULT_SHARE_MODE, nullptr, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (Handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND) { + // File didn't exist, just open. + Handle = CreateFileA(Filepath, Disp.Access, DEFAULT_SHARE_MODE, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + } + } else { + Handle = CreateFileA(Filepath, Disp.Access, DEFAULT_SHARE_MODE, nullptr, Disp.CreationFlag, FILE_ATTRIBUTE_NORMAL, nullptr); + } + IsValidHandle = Handle != INVALID_HANDLE_VALUE; +#endif + } + + /** + * @brief Write Bytes to File + * + * @param Buffer The buffer to write. + * @param Bytes The number of bytes to write. + * + * @return The number of bytes actually written or -1 on error. + */ + ssize_t Write(const void* Buffer, size_t Bytes) { +#ifndef _WIN32 + return write(Handle, Buffer, Bytes); +#else + DWORD BytesWritten {}; + auto Result = WriteFile(Handle, Buffer, Bytes, &BytesWritten, nullptr); + if (Result) { + return BytesWritten; + } + // Some error, match Linux side. + return -1; +#endif + } + + ssize_t Write(std::string_view const Data) { + return Write(Data.data(), Data.size()); + } + + /** + * @brief Read at most Bytes in to the buffer. + * + * @param Buffer The buffer where the data is read in to. + * @param Bytes The size of the buffer. + * + * @return The number of bytes read or -1 on error. + */ + ssize_t Read(void* Buffer, size_t Bytes) { +#ifndef _WIN32 + return read(Handle, Buffer, Bytes); +#else + DWORD BytesRead {}; + auto Result = ReadFile(Handle, Buffer, Bytes, &BytesRead, nullptr); + if (Result) { + return BytesRead; + } + // Some error, match Linux side. + return -1; +#endif + } + + ~File() { + if (!IsValidHandle) { + return; + } + if (!ShouldClose) { + return; + } +#ifndef _WIN32 + close(Handle); +#else + CloseHandle(Handle); +#endif + } + + /** + * @brief Gets a File object that points to stdout + */ + static File GetStdOUT() { +#ifndef _WIN32 + return File(STDOUT_FILENO, false); +#else + return File(GetStdHandle(STD_OUTPUT_HANDLE), false); +#endif + } + + /** + * @brief Gets a File object that points to stderr + */ + static File GetStdERR() { +#ifndef _WIN32 + return File(STDERR_FILENO, false); +#else + return File(GetStdHandle(STD_ERROR_HANDLE), false); +#endif + } + + /** + * @brief Returns if the file handle is valid. + */ + bool IsValid() const { + return IsValidHandle; + } + + /** + * @brief Flush the file contents to the output file backing. + * + * @return True if the flush occured. + */ + bool Flush() { +#ifndef _WIN32 + return fsync(Handle) == 0; +#else + return FlushFileBuffers(Handle); +#endif + } + + /** + * @brief Seek the file pointer location. + * + * @param Distance The distance to travel. + * @param Op The operation from where to start the travel. + * + * @return The current file pointer location or -1. + */ + ssize_t Seek(ssize_t Distance, SeekOp Op) { +#ifndef _WIN32 + return lseek(Handle, Distance, TranslateSeek(Op)); +#else + LARGE_INTEGER NewDistance {.QuadPart = Distance}; + LARGE_INTEGER NewPointer; + auto Result = SetFilePointerEx(Handle, NewDistance, &NewPointer, TranslateSeek(Op)); + if (Result) { + return NewPointer.QuadPart; + } + // Some error, match Linux side. + return -1; +#endif + } + +protected: + + File(FileHandleType Handle, bool ShouldClose) + : ShouldClose {ShouldClose} + , IsValidHandle {true} + , Handle {Handle} {} +private: + bool ShouldClose {}; + bool IsValidHandle {}; + + FileHandleType Handle; +#ifndef _WIN32 + static constexpr int DEFAULT_USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; + + static uint32_t TranslateModes(FileModes Modes) { + uint32_t Mode {}; + if ((Modes & FileModes::READ) == FileModes::READ) { + Mode |= O_RDONLY; + } + if ((Modes & FileModes::WRITE) == FileModes::WRITE) { + Mode |= O_WRONLY; + } + if ((Modes & FileModes::CREATE) == FileModes::CREATE) { + Mode |= O_CREAT; + } + if ((Modes & FileModes::TRUNCATE) == FileModes::TRUNCATE) { + Mode |= O_TRUNC; + } + + // Always enable CLOEXEC so that the FD is closed on execve. + // FEXCore never wants to leak FDs across execve using this interface. + Mode |= O_CLOEXEC; + return Mode; + } + + static uint32_t TranslateSeek(SeekOp Op) { + switch (Op) { + case SeekOp::BEGIN: return SEEK_SET; + case SeekOp::CURRENT: return SEEK_CUR; + case SeekOp::END: return SEEK_END; + default: FEX_UNREACHABLE; + } + } +#else + static constexpr int DEFAULT_SHARE_MODE = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + struct Disposition { + uint32_t CreationFlag; + uint32_t Access; + bool TruncateOnExist; }; + static Disposition TranslateModes(FileModes Modes) { + Disposition Disp {}; + if ((Modes & FileModes::READ) == FileModes::READ) { + Disp.Access |= GENERIC_READ; + } + if ((Modes & FileModes::WRITE) == FileModes::WRITE) { + Disp.Access |= GENERIC_WRITE; + } + if ((Modes & FileModes::CREATE) == FileModes::CREATE) { + Disp.CreationFlag = CREATE_ALWAYS; + } else { + Disp.CreationFlag = OPEN_ALWAYS; + } - enum class SeekOp { - BEGIN, - CURRENT, - END, - }; + if ((Modes & FileModes::TRUNCATE) == FileModes::TRUNCATE) { + Disp.TruncateOnExist = true; + } - FEX_DEF_NUM_OPS(FileModes) + return Disp; + } - class File final { - public: -#ifndef _WIN32 - using FileHandleType = int; -#else - using FileHandleType = HANDLE; + static uint32_t TranslateSeek(SeekOp Op) { + switch (Op) { + case SeekOp::BEGIN: return FILE_BEGIN; + case SeekOp::CURRENT: return FILE_CURRENT; + case SeekOp::END: return FILE_END; + default: FEX_UNREACHABLE; + } + } #endif - - File() = default; - - File(const char *Filepath, FileModes Modes) { -#ifndef _WIN32 - auto Disp = TranslateModes(Modes); - Handle = open(Filepath, Disp, DEFAULT_USER_PERMS); - IsValidHandle = Handle != -1; -#else - auto Disp = TranslateModes(Modes); - if (Disp.CreationFlag == OPEN_ALWAYS && Disp.TruncateOnExist) { - // If Open + Truncate then try to open with truncate behaviour first. - Handle = CreateFileA(Filepath, Disp.Access, DEFAULT_SHARE_MODE, nullptr, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (Handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND) { - // File didn't exist, just open. - Handle = CreateFileA(Filepath, Disp.Access, DEFAULT_SHARE_MODE, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - } - } - else { - Handle = CreateFileA(Filepath, Disp.Access, DEFAULT_SHARE_MODE, nullptr, Disp.CreationFlag, FILE_ATTRIBUTE_NORMAL, nullptr); - } - IsValidHandle = Handle != INVALID_HANDLE_VALUE; -#endif - } - - /** - * @brief Write Bytes to File - * - * @param Buffer The buffer to write. - * @param Bytes The number of bytes to write. - * - * @return The number of bytes actually written or -1 on error. - */ - ssize_t Write(void const* Buffer, size_t Bytes) { -#ifndef _WIN32 - return write(Handle, Buffer, Bytes); -#else - DWORD BytesWritten{}; - auto Result = WriteFile(Handle, Buffer, Bytes, &BytesWritten, nullptr); - if (Result) { - return BytesWritten; - } - // Some error, match Linux side. - return -1; -#endif - } - - ssize_t Write(std::string_view const Data) { - return Write(Data.data(), Data.size()); - } - - /** - * @brief Read at most Bytes in to the buffer. - * - * @param Buffer The buffer where the data is read in to. - * @param Bytes The size of the buffer. - * - * @return The number of bytes read or -1 on error. - */ - ssize_t Read(void *Buffer, size_t Bytes) { -#ifndef _WIN32 - return read(Handle, Buffer, Bytes); -#else - DWORD BytesRead{}; - auto Result = ReadFile(Handle, Buffer, Bytes, &BytesRead, nullptr); - if (Result) { - return BytesRead; - } - // Some error, match Linux side. - return -1; -#endif - } - - ~File() { - if (!IsValidHandle) return; - if (!ShouldClose) return; -#ifndef _WIN32 - close(Handle); -#else - CloseHandle(Handle); -#endif - } - - /** - * @brief Gets a File object that points to stdout - */ - static File GetStdOUT() { -#ifndef _WIN32 - return File(STDOUT_FILENO, false); -#else - return File(GetStdHandle(STD_OUTPUT_HANDLE), false); -#endif - } - - /** - * @brief Gets a File object that points to stderr - */ - static File GetStdERR() { -#ifndef _WIN32 - return File(STDERR_FILENO, false); -#else - return File(GetStdHandle(STD_ERROR_HANDLE), false); -#endif - } - - /** - * @brief Returns if the file handle is valid. - */ - bool IsValid() const { return IsValidHandle; } - - /** - * @brief Flush the file contents to the output file backing. - * - * @return True if the flush occured. - */ - bool Flush() { -#ifndef _WIN32 - return fsync(Handle) == 0; -#else - return FlushFileBuffers(Handle); -#endif - } - - /** - * @brief Seek the file pointer location. - * - * @param Distance The distance to travel. - * @param Op The operation from where to start the travel. - * - * @return The current file pointer location or -1. - */ - ssize_t Seek(ssize_t Distance, SeekOp Op) { -#ifndef _WIN32 - return lseek(Handle, Distance, TranslateSeek(Op)); -#else - LARGE_INTEGER NewDistance { - .QuadPart = Distance - }; - LARGE_INTEGER NewPointer; - auto Result = SetFilePointerEx(Handle, NewDistance, &NewPointer, TranslateSeek(Op)); - if (Result) { - return NewPointer.QuadPart; - } - // Some error, match Linux side. - return -1; -#endif - } - - protected: - - File(FileHandleType Handle, bool ShouldClose) - : ShouldClose {ShouldClose} - , IsValidHandle {true} - , Handle {Handle} - {} - private: - bool ShouldClose{}; - bool IsValidHandle{}; - - FileHandleType Handle; -#ifndef _WIN32 - static constexpr int DEFAULT_USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; - - static uint32_t TranslateModes(FileModes Modes) { - uint32_t Mode{}; - if ((Modes & FileModes::READ) == FileModes::READ) - Mode |= O_RDONLY; - if ((Modes & FileModes::WRITE) == FileModes::WRITE) - Mode |= O_WRONLY; - if ((Modes & FileModes::CREATE) == FileModes::CREATE) - Mode |= O_CREAT; - if ((Modes & FileModes::TRUNCATE) == FileModes::TRUNCATE) - Mode |= O_TRUNC; - - // Always enable CLOEXEC so that the FD is closed on execve. - // FEXCore never wants to leak FDs across execve using this interface. - Mode |= O_CLOEXEC; - return Mode; - } - - static uint32_t TranslateSeek(SeekOp Op) { - switch (Op) { - case SeekOp::BEGIN: return SEEK_SET; - case SeekOp::CURRENT: return SEEK_CUR; - case SeekOp::END: return SEEK_END; - default: FEX_UNREACHABLE; - } - } -#else - static constexpr int DEFAULT_SHARE_MODE = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - struct Disposition { - uint32_t CreationFlag; - uint32_t Access; - bool TruncateOnExist; - }; - static Disposition TranslateModes(FileModes Modes) { - Disposition Disp{}; - if ((Modes & FileModes::READ) == FileModes::READ) - Disp.Access |= GENERIC_READ; - if ((Modes & FileModes::WRITE) == FileModes::WRITE) - Disp.Access |= GENERIC_WRITE; - if ((Modes & FileModes::CREATE) == FileModes::CREATE) - Disp.CreationFlag = CREATE_ALWAYS; - else - Disp.CreationFlag = OPEN_ALWAYS; - - if ((Modes & FileModes::TRUNCATE) == FileModes::TRUNCATE) - Disp.TruncateOnExist = true; - - return Disp; - } - - static uint32_t TranslateSeek(SeekOp Op) { - switch (Op) { - case SeekOp::BEGIN: return FILE_BEGIN; - case SeekOp::CURRENT: return FILE_CURRENT; - case SeekOp::END: return FILE_END; - default: FEX_UNREACHABLE; - } - } -#endif - - }; -} +}; +} // namespace FEXCore::File diff --git a/FEXCore/include/FEXCore/Utils/FileLoading.h b/FEXCore/include/FEXCore/Utils/FileLoading.h index 341e8e335..3d613f894 100644 --- a/FEXCore/include/FEXCore/Utils/FileLoading.h +++ b/FEXCore/include/FEXCore/Utils/FileLoading.h @@ -7,25 +7,24 @@ #include namespace FEXCore::FileLoading { - /** - * @brief Loads a filepath in to a vector of data - * - * @param Data The vector to load the file data in to - * @param Filepath The filepath to load - * - * @return true on file loaded, false on failure - */ - FEX_DEFAULT_VISIBILITY bool LoadFile(fextl::vector &Data, const fextl::string &Filepath, size_t FixedSize = 0); - FEX_DEFAULT_VISIBILITY bool LoadFile(fextl::string &Data, const fextl::string &Filepath, size_t FixedSize = 0); - - /** - * @brief Loads a filepath in to a buffer of data with a fixed size - * - * @param Filepath The filepath to load - * @param Buffer The buffer to load the data in to. Attempting to read the full size of the span - * - * @return The amount of data read or -1 on error. - */ - FEX_DEFAULT_VISIBILITY ssize_t LoadFileToBuffer(const fextl::string &Filepath, std::span Buffer); -} +/** + * @brief Loads a filepath in to a vector of data + * + * @param Data The vector to load the file data in to + * @param Filepath The filepath to load + * + * @return true on file loaded, false on failure + */ +FEX_DEFAULT_VISIBILITY bool LoadFile(fextl::vector& Data, const fextl::string& Filepath, size_t FixedSize = 0); +FEX_DEFAULT_VISIBILITY bool LoadFile(fextl::string& Data, const fextl::string& Filepath, size_t FixedSize = 0); +/** + * @brief Loads a filepath in to a buffer of data with a fixed size + * + * @param Filepath The filepath to load + * @param Buffer The buffer to load the data in to. Attempting to read the full size of the span + * + * @return The amount of data read or -1 on error. + */ +FEX_DEFAULT_VISIBILITY ssize_t LoadFileToBuffer(const fextl::string& Filepath, std::span Buffer); +} // namespace FEXCore::FileLoading diff --git a/FEXCore/include/FEXCore/Utils/InterruptableConditionVariable.h b/FEXCore/include/FEXCore/Utils/InterruptableConditionVariable.h index 7ec4efde6..d81c376c0 100644 --- a/FEXCore/include/FEXCore/Utils/InterruptableConditionVariable.h +++ b/FEXCore/include/FEXCore/Utils/InterruptableConditionVariable.h @@ -16,146 +16,141 @@ #include namespace FEXCore { - /** - * @brief A condition variable that is robust against use of longjmp in signal handlers. - * - * This is opposed to common `std::condition_variable` implementations: - * Longjmp'ing in a signal handler while interrupting a pending `wait_for()` - * call can leave the condition variable in an invalid state that breaks later - * uses of that object and may cause hangs as a consequence. - */ +/** + * @brief A condition variable that is robust against use of longjmp in signal handlers. + * + * This is opposed to common `std::condition_variable` implementations: + * Longjmp'ing in a signal handler while interrupting a pending `wait_for()` + * call can leave the condition variable in an invalid state that breaks later + * uses of that object and may cause hangs as a consequence. + */ #ifndef _WIN32 - class InterruptableConditionVariable final { - public: - bool Wait(struct timespec *Timeout = nullptr) { - while (true) { - uint32_t Expected = SIGNALED; - uint32_t Desired = UNSIGNALED; +class InterruptableConditionVariable final { +public: + bool Wait(struct timespec* Timeout = nullptr) { + while (true) { + uint32_t Expected = SIGNALED; + uint32_t Desired = UNSIGNALED; - // If the mutex was already signaled then we can early exit - if (Mutex.compare_exchange_strong(Expected, Desired)) { - return true; - } - - constexpr int Op = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; - // WAIT will keep sleeping on the futex word while it is `val` - int Result = ::syscall(SYS_futex, - &Mutex, - Op, - Desired, // val - Timeout, // Timeout/val2 - nullptr, // Addr2 - 0); // val3 - - if (Timeout && Result == -1 && errno == ETIMEDOUT) { - return false; - } - } + // If the mutex was already signaled then we can early exit + if (Mutex.compare_exchange_strong(Expected, Desired)) { + return true; } - template - bool WaitFor(std::chrono::duration const& time) { - struct timespec Timeout{}; - auto SecondsDuration = std::chrono::duration_cast(time); - Timeout.tv_sec = SecondsDuration.count(); - Timeout.tv_nsec = std::chrono::duration_cast(time - SecondsDuration).count(); - return Wait(&Timeout); + constexpr int Op = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; + // WAIT will keep sleeping on the futex word while it is `val` + int Result = ::syscall(SYS_futex, &Mutex, Op, + Desired, // val + Timeout, // Timeout/val2 + nullptr, // Addr2 + 0); // val3 + + if (Timeout && Result == -1 && errno == ETIMEDOUT) { + return false; } + } + } - void NotifyOne() { - DoNotify(1); - } + template + bool WaitFor(const std::chrono::duration& time) { + struct timespec Timeout {}; + auto SecondsDuration = std::chrono::duration_cast(time); + Timeout.tv_sec = SecondsDuration.count(); + Timeout.tv_nsec = std::chrono::duration_cast(time - SecondsDuration).count(); + return Wait(&Timeout); + } - void NotifyAll() { - // Maximum number of waiters - DoNotify(INT_MAX); - } + void NotifyOne() { + DoNotify(1); + } - private: - std::atomic Mutex{}; - constexpr static uint32_t SIGNALED = 1; - constexpr static uint32_t UNSIGNALED = 0; + void NotifyAll() { + // Maximum number of waiters + DoNotify(INT_MAX); + } - void DoNotify(int Waiters) { - uint32_t Expected = UNSIGNALED; - uint32_t Desired = SIGNALED; +private: + std::atomic Mutex {}; + constexpr static uint32_t SIGNALED = 1; + constexpr static uint32_t UNSIGNALED = 0; - // If the mutex was in an unsignaled state then signal - if (Mutex.compare_exchange_strong(Expected, Desired)) { - constexpr int Op = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; + void DoNotify(int Waiters) { + uint32_t Expected = UNSIGNALED; + uint32_t Desired = SIGNALED; - ::syscall(SYS_futex, - &Mutex, - Op, - Waiters, // val - Number of waiters to wake - 0, // val2 - &Mutex, // Addr2 - Mutex to do the operation on - 0); // val3 - } - } - }; + // If the mutex was in an unsignaled state then signal + if (Mutex.compare_exchange_strong(Expected, Desired)) { + constexpr int Op = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; + + ::syscall(SYS_futex, &Mutex, Op, + Waiters, // val - Number of waiters to wake + 0, // val2 + &Mutex, // Addr2 - Mutex to do the operation on + 0); // val3 + } + } +}; #else - class InterruptableConditionVariable final { - public: - bool Wait(struct timespec *Timeout = nullptr) { - while (true) { - uint32_t Expected = SIGNALED; - uint32_t Desired = UNSIGNALED; +class InterruptableConditionVariable final { +public: + bool Wait(struct timespec* Timeout = nullptr) { + while (true) { + uint32_t Expected = SIGNALED; + uint32_t Desired = UNSIGNALED; - // If the mutex was already signaled then we can early exit - if (Mutex.compare_exchange_strong(Expected, Desired)) { - return true; - } - // Windows only supports millisecond granularity. - const uint32_t TimeoutMS = Timeout ? Timeout->tv_sec * 1000 + (Timeout->tv_nsec / 1000000) : 0; - - // WaitOnAddress returns when the value at `Address` differs from the value at `CompareAddress`. - bool Result = WaitOnAddress(&Mutex, &Desired, 4, TimeoutMS); - - if (Timeout && Result == false && GetLastError() == ERROR_TIMEOUT) { - return false; - } - } + // If the mutex was already signaled then we can early exit + if (Mutex.compare_exchange_strong(Expected, Desired)) { + return true; } + // Windows only supports millisecond granularity. + const uint32_t TimeoutMS = Timeout ? Timeout->tv_sec * 1000 + (Timeout->tv_nsec / 1000000) : 0; - template - bool WaitFor(std::chrono::duration const& time) { - struct timespec Timeout{}; - auto SecondsDuration = std::chrono::duration_cast(time); - Timeout.tv_sec = SecondsDuration.count(); - Timeout.tv_nsec = std::chrono::duration_cast(time - SecondsDuration).count(); - return Wait(&Timeout); + // WaitOnAddress returns when the value at `Address` differs from the value at `CompareAddress`. + bool Result = WaitOnAddress(&Mutex, &Desired, 4, TimeoutMS); + + if (Timeout && Result == false && GetLastError() == ERROR_TIMEOUT) { + return false; } + } + } - void NotifyOne() { - DoNotify(false); + template + bool WaitFor(const std::chrono::duration& time) { + struct timespec Timeout {}; + auto SecondsDuration = std::chrono::duration_cast(time); + Timeout.tv_sec = SecondsDuration.count(); + Timeout.tv_nsec = std::chrono::duration_cast(time - SecondsDuration).count(); + return Wait(&Timeout); + } + + void NotifyOne() { + DoNotify(false); + } + + void NotifyAll() { + // Maximum number of waiters + DoNotify(true); + } + +private: + std::atomic Mutex {}; + constexpr static uint32_t SIGNALED = 1; + constexpr static uint32_t UNSIGNALED = 0; + + void DoNotify(bool All) { + uint32_t Expected = UNSIGNALED; + uint32_t Desired = SIGNALED; + + // If the mutex was in an unsignaled state then signal + if (Mutex.compare_exchange_strong(Expected, Desired)) { + if (All) { + WakeByAddressAll(&Mutex); + } else { + WakeByAddressSingle(&Mutex); } - - void NotifyAll() { - // Maximum number of waiters - DoNotify(true); - } - - private: - std::atomic Mutex{}; - constexpr static uint32_t SIGNALED = 1; - constexpr static uint32_t UNSIGNALED = 0; - - void DoNotify(bool All) { - uint32_t Expected = UNSIGNALED; - uint32_t Desired = SIGNALED; - - // If the mutex was in an unsignaled state then signal - if (Mutex.compare_exchange_strong(Expected, Desired)) { - if (All) { - WakeByAddressAll(&Mutex); - } - else { - WakeByAddressSingle(&Mutex); - } - } - } - }; + } + } +}; #endif -} +} // namespace FEXCore diff --git a/FEXCore/include/FEXCore/Utils/LogManager.h b/FEXCore/include/FEXCore/Utils/LogManager.h index 29cc7316d..9b97caeaf 100644 --- a/FEXCore/include/FEXCore/Utils/LogManager.h +++ b/FEXCore/include/FEXCore/Utils/LogManager.h @@ -18,25 +18,16 @@ enum DebugLevels { STDERR = 6, ///< Meant to go to STDERR }; -static inline const char *DebugLevelStr(uint32_t Level) { +static inline const char* DebugLevelStr(uint32_t Level) { switch (Level) { - case NONE: - return "NONE"; - case ASSERT: - return "ASSERT"; - case ERROR: - return "ERROR"; - case DEBUG: - return "DEBUG"; - case INFO: - return "INFO"; - case STDOUT: - return "STDOUT"; - case STDERR: - return "STDERR"; - default: - return "???"; - break; + case NONE: return "NONE"; + case ASSERT: return "ASSERT"; + case ERROR: return "ERROR"; + case DEBUG: return "DEBUG"; + case INFO: return "INFO"; + case STDOUT: return "STDOUT"; + case STDERR: return "STDERR"; + default: return "???"; break; } } @@ -46,109 +37,128 @@ constexpr DebugLevels MSG_LEVEL = INFO; // format strings as used by fmtlib (or C++ std::format). namespace Throw { -using ThrowHandler = void(*)(char const *Message); -FEX_DEFAULT_VISIBILITY void InstallHandler(ThrowHandler Handler); -FEX_DEFAULT_VISIBILITY void UnInstallHandlers(); + using ThrowHandler = void (*)(const char* Message); + FEX_DEFAULT_VISIBILITY void InstallHandler(ThrowHandler Handler); + FEX_DEFAULT_VISIBILITY void UnInstallHandlers(); -[[noreturn]] void MFmt(const char *fmt, const fmt::format_args& args); + [[noreturn]] + void MFmt(const char* fmt, const fmt::format_args& args); // AA_FMT and AAFmt are assume versions of {AA_FMT, AFmt} which will assert in debug builds if the assumption is incorrect. // In a release build these use __builtin_assume so compilers can optimize around the case that these cases always hold true. // The assume version should be preferred unless what is being checked has side effects. #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED -template -static inline void AFmt(bool Value, const char *fmt, const Args&... args) { - if (MSG_LEVEL < ASSERT || Value) { - return; + template + static inline void AFmt(bool Value, const char* fmt, const Args&... args) { + if (MSG_LEVEL < ASSERT || Value) { + return; + } + MFmt(fmt, fmt::make_format_args(args...)); } - MFmt(fmt, fmt::make_format_args(args...)); -} -template -static inline void AAFmt(bool Value, const char *fmt, const Args&... args) { - if (MSG_LEVEL < ASSERT || Value) { - return; + template + static inline void AAFmt(bool Value, const char* fmt, const Args&... args) { + if (MSG_LEVEL < ASSERT || Value) { + return; + } + MFmt(fmt, fmt::make_format_args(args...)); } - MFmt(fmt, fmt::make_format_args(args...)); -} -#define LOGMAN_THROW_A_FMT(pred, ...) do { LogMan::Throw::AFmt(pred, __VA_ARGS__); } while (0) -#define LOGMAN_THROW_AA_FMT(pred, ...) do { LogMan::Throw::AFmt(pred, __VA_ARGS__); } while (0) +#define LOGMAN_THROW_A_FMT(pred, ...) \ + do { \ + LogMan::Throw::AFmt(pred, __VA_ARGS__); \ + } while (0) +#define LOGMAN_THROW_AA_FMT(pred, ...) \ + do { \ + LogMan::Throw::AFmt(pred, __VA_ARGS__); \ + } while (0) #else -static inline void AFmt(bool, const char*, ...) {} -#define LOGMAN_THROW_A_FMT(pred, ...) do {} while (0) -static inline void AAFmt(bool pred, const char*, ...) { __builtin_assume(pred); } -#define LOGMAN_THROW_AA_FMT(pred, ...) do { __builtin_assume(pred); } while (0) + static inline void AFmt(bool, const char*, ...) {} +#define LOGMAN_THROW_A_FMT(pred, ...) \ + do { \ + } while (0) + static inline void AAFmt(bool pred, const char*, ...) { + __builtin_assume(pred); + } +#define LOGMAN_THROW_AA_FMT(pred, ...) \ + do { \ + __builtin_assume(pred); \ + } while (0) #endif } // namespace Throw namespace Msg { -using MsgHandler = void(*)(DebugLevels Level, char const *Message); -FEX_DEFAULT_VISIBILITY void InstallHandler(MsgHandler Handler); -FEX_DEFAULT_VISIBILITY void UnInstallHandlers(); + using MsgHandler = void (*)(DebugLevels Level, const char* Message); + FEX_DEFAULT_VISIBILITY void InstallHandler(MsgHandler Handler); + FEX_DEFAULT_VISIBILITY void UnInstallHandlers(); -// Fmt-capable interface. + // Fmt-capable interface. -FEX_DEFAULT_VISIBILITY void MFmtImpl(DebugLevels level, const char* fmt, const fmt::format_args& args); + FEX_DEFAULT_VISIBILITY void MFmtImpl(DebugLevels level, const char* fmt, const fmt::format_args& args); -template -static inline void MFmt(DebugLevels level, const char* fmt, const Args&... args) { + template + static inline void MFmt(DebugLevels level, const char* fmt, const Args&... args) { MFmtImpl(level, fmt, fmt::make_format_args(args...)); -} - -template -static inline void EFmt(const char* fmt, const Args&... args) { - if (MSG_LEVEL < ERROR) { - return; } - MFmtImpl(ERROR, fmt, fmt::make_format_args(args...)); -} -template -static inline void DFmt(const char* fmt, const Args&... args) { - if (MSG_LEVEL < DEBUG) { - return; + template + static inline void EFmt(const char* fmt, const Args&... args) { + if (MSG_LEVEL < ERROR) { + return; + } + MFmtImpl(ERROR, fmt, fmt::make_format_args(args...)); } - MFmtImpl(DEBUG, fmt, fmt::make_format_args(args...)); -} -template -static inline void IFmt(const char* fmt, const Args&... args) { - if (MSG_LEVEL < INFO) { - return; + template + static inline void DFmt(const char* fmt, const Args&... args) { + if (MSG_LEVEL < DEBUG) { + return; + } + MFmtImpl(DEBUG, fmt, fmt::make_format_args(args...)); } - MFmtImpl(INFO, fmt, fmt::make_format_args(args...)); -} -template -static inline void OutFmt(const char* fmt, const Args&... args) { - MFmtImpl(STDOUT, fmt, fmt::make_format_args(args...)); -} + template + static inline void IFmt(const char* fmt, const Args&... args) { + if (MSG_LEVEL < INFO) { + return; + } + MFmtImpl(INFO, fmt, fmt::make_format_args(args...)); + } -template -static inline void ErrFmt(const char* fmt, const Args&... args) { - MFmtImpl(STDERR, fmt, fmt::make_format_args(args...)); -} + template + static inline void OutFmt(const char* fmt, const Args&... args) { + MFmtImpl(STDOUT, fmt, fmt::make_format_args(args...)); + } + + template + static inline void ErrFmt(const char* fmt, const Args&... args) { + MFmtImpl(STDERR, fmt, fmt::make_format_args(args...)); + } #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED -template -static inline void AFmt(const char *fmt, const Args&... args) { - if (MSG_LEVEL < ASSERT) { - return; + template + static inline void AFmt(const char* fmt, const Args&... args) { + if (MSG_LEVEL < ASSERT) { + return; + } + MFmtImpl(ASSERT, fmt, fmt::make_format_args(args...)); + FEX_TRAP_EXECUTION; } - MFmtImpl(ASSERT, fmt, fmt::make_format_args(args...)); - FEX_TRAP_EXECUTION; -} -#define LOGMAN_MSG_A_FMT(...) do { LogMan::Msg::AFmt(__VA_ARGS__); } while (0) +#define LOGMAN_MSG_A_FMT(...) \ + do { \ + LogMan::Msg::AFmt(__VA_ARGS__); \ + } while (0) #else -template -static inline void AFmt(const char*, const Args&...) {} -#define LOGMAN_MSG_A_FMT(...) do {} while(0) + template + static inline void AFmt(const char*, const Args&...) {} +#define LOGMAN_MSG_A_FMT(...) \ + do { \ + } while (0) #endif #define WARN_ONCE_FMT(...) \ do { \ - static bool Warned{}; \ + static bool Warned {}; \ if (!Warned) { \ LogMan::Msg::DFmt(__VA_ARGS__); \ Warned = true; \ @@ -159,7 +169,7 @@ static inline void AFmt(const char*, const Args&...) {} do { \ LogMan::Msg::EFmt(__VA_ARGS__); \ FEX_TRAP_EXECUTION; \ - } while(0) + } while (0) } // namespace Msg } // namespace LogMan diff --git a/FEXCore/include/FEXCore/Utils/MathUtils.h b/FEXCore/include/FEXCore/Utils/MathUtils.h index d86aa7fa6..f62bd6a3c 100644 --- a/FEXCore/include/FEXCore/Utils/MathUtils.h +++ b/FEXCore/include/FEXCore/Utils/MathUtils.h @@ -8,19 +8,22 @@ #include namespace FEXCore { -[[nodiscard]] constexpr uint64_t AlignUp(uint64_t value, uint64_t size) { +[[nodiscard]] +constexpr uint64_t AlignUp(uint64_t value, uint64_t size) { return value + (size - value % size) % size; } -[[nodiscard]] constexpr uint64_t AlignDown(uint64_t value, uint64_t size) { +[[nodiscard]] +constexpr uint64_t AlignDown(uint64_t value, uint64_t size) { return value - value % size; } // Returns the ilog2 of a power-of-2 integer. // Asserts in the case that the passed in integer is not a power-of-2. template -requires(std::is_unsigned_v) -[[nodiscard]] constexpr T ilog2(T Value) { +requires (std::is_unsigned_v) +[[nodiscard]] +constexpr T ilog2(T Value) { LOGMAN_THROW_A_FMT(std::has_single_bit(Value), "ilog2 requires popcount to be one"); return std::countr_zero(Value); } @@ -29,8 +32,9 @@ requires(std::is_unsigned_v) // Can be a faster implementation than regular integer divide. // Divisor requires to be power-of-2, is enforced in ilog2 helper. template -requires(std::is_unsigned_v && std::is_unsigned_v) -[[nodiscard]] constexpr T DividePow2(T Dividend, TT Divisor) { +requires (std::is_unsigned_v && std::is_unsigned_v) +[[nodiscard]] +constexpr T DividePow2(T Dividend, TT Divisor) { return Dividend >> ilog2(Divisor); } } // namespace FEXCore diff --git a/FEXCore/include/FEXCore/Utils/Profiler.h b/FEXCore/include/FEXCore/Utils/Profiler.h index 5f62ab678..c7004431b 100644 --- a/FEXCore/include/FEXCore/Utils/Profiler.h +++ b/FEXCore/include/FEXCore/Utils/Profiler.h @@ -24,33 +24,40 @@ static inline uint64_t GetTime() { // A class that follows scoping rules to generate a profile duration block class ProfilerBlock final { - public: - ProfilerBlock(std::string_view const Format); +public: + ProfilerBlock(std::string_view const Format); - ~ProfilerBlock(); + ~ProfilerBlock(); - private: - uint64_t DurationBegin; - std::string_view const Format; +private: + uint64_t DurationBegin; + std::string_view const Format; }; -#define UniqueScopeName2(name, line) name ## line -#define UniqueScopeName(name, line) UniqueScopeName2(name, line) +#define UniqueScopeName2(name, line) name##line +#define UniqueScopeName(name, line) UniqueScopeName2(name, line) // Declare an instantaneous profiler event. #define FEXCORE_PROFILE_INSTANT(name) FEXCore::Profiler::TraceObject(name) // Declare a scoped profile block variable with a fixed name. -#define FEXCORE_PROFILE_SCOPED(name) \ - FEXCore::Profiler::ProfilerBlock UniqueScopeName(ScopedBlock_, __LINE__) (name) +#define FEXCORE_PROFILE_SCOPED(name) FEXCore::Profiler::ProfilerBlock UniqueScopeName(ScopedBlock_, __LINE__)(name) #else -[[maybe_unused]] static void Init() {} -[[maybe_unused]] static void Shutdown() {} -[[maybe_unused]] static void TraceObject(std::string_view const Format) {} -[[maybe_unused]] static void TraceObject(std::string_view const, uint64_t) {} +[[maybe_unused]] +static void Init() {} +[[maybe_unused]] +static void Shutdown() {} +[[maybe_unused]] +static void TraceObject(std::string_view const Format) {} +[[maybe_unused]] +static void TraceObject(std::string_view const, uint64_t) {} -#define FEXCORE_PROFILE_INSTANT(...) do {} while(0) -#define FEXCORE_PROFILE_SCOPED(...) do {} while(0) +#define FEXCORE_PROFILE_INSTANT(...) \ + do { \ + } while (0) +#define FEXCORE_PROFILE_SCOPED(...) \ + do { \ + } while (0) #endif -} +} // namespace FEXCore::Profiler diff --git a/FEXCore/include/FEXCore/Utils/SignalScopeGuards.h b/FEXCore/include/FEXCore/Utils/SignalScopeGuards.h index cf6c63212..fe28910c9 100644 --- a/FEXCore/include/FEXCore/Utils/SignalScopeGuards.h +++ b/FEXCore/include/FEXCore/Utils/SignalScopeGuards.h @@ -16,228 +16,234 @@ namespace FEXCore { #ifndef _WIN32 - // Replacement for std::mutexes to deal with unlocking issues in the face of Linux fork() semantics. - // - // A fork() only clones the parent's calling thread. Other threads are silently dropped, which permanently leaves any mutexes owned by them locked. - // To address this issue, ForkableUniqueMutex and ForkableSharedMutex provide a way to forcefully remove any dangling locks and reset the mutexes to their default state. - class ForkableUniqueMutex final { - public: - ForkableUniqueMutex() - : Mutex (PTHREAD_MUTEX_INITIALIZER) { - } +// Replacement for std::mutexes to deal with unlocking issues in the face of Linux fork() semantics. +// +// A fork() only clones the parent's calling thread. Other threads are silently dropped, which permanently leaves any mutexes owned by them locked. +// To address this issue, ForkableUniqueMutex and ForkableSharedMutex provide a way to forcefully remove any dangling locks and reset the mutexes to their default state. +class ForkableUniqueMutex final { +public: + ForkableUniqueMutex() + : Mutex(PTHREAD_MUTEX_INITIALIZER) {} - // Move-only type - ForkableUniqueMutex(const ForkableUniqueMutex&) = delete; - ForkableUniqueMutex& operator=(const ForkableUniqueMutex&) = delete; - ForkableUniqueMutex(ForkableUniqueMutex &&rhs) = default; - ForkableUniqueMutex& operator=(ForkableUniqueMutex &&) = default; + // Move-only type + ForkableUniqueMutex(const ForkableUniqueMutex&) = delete; + ForkableUniqueMutex& operator=(const ForkableUniqueMutex&) = delete; + ForkableUniqueMutex(ForkableUniqueMutex&& rhs) = default; + ForkableUniqueMutex& operator=(ForkableUniqueMutex&&) = default; - void lock() { - [[maybe_unused]] const auto Result = pthread_mutex_lock(&Mutex); - LOGMAN_THROW_A_FMT(Result == 0, "{} failed to lock with {}", __func__, Result); - } - void unlock() { - [[maybe_unused]] const auto Result = pthread_mutex_unlock(&Mutex); - LOGMAN_THROW_A_FMT(Result == 0, "{} failed to unlock with {}", __func__, Result); - } - // Initialize the internal pthread object to its default initializer state. - // Should only ever be used in the child process when a Linux fork() has occured. - void StealAndDropActiveLocks() { - Mutex = PTHREAD_MUTEX_INITIALIZER; - } - private: - pthread_mutex_t Mutex; - }; + void lock() { + [[maybe_unused]] const auto Result = pthread_mutex_lock(&Mutex); + LOGMAN_THROW_A_FMT(Result == 0, "{} failed to lock with {}", __func__, Result); + } + void unlock() { + [[maybe_unused]] const auto Result = pthread_mutex_unlock(&Mutex); + LOGMAN_THROW_A_FMT(Result == 0, "{} failed to unlock with {}", __func__, Result); + } + // Initialize the internal pthread object to its default initializer state. + // Should only ever be used in the child process when a Linux fork() has occured. + void StealAndDropActiveLocks() { + Mutex = PTHREAD_MUTEX_INITIALIZER; + } +private: + pthread_mutex_t Mutex; +}; - class ForkableSharedMutex final { - public: - ForkableSharedMutex() - : Mutex (PTHREAD_RWLOCK_INITIALIZER) { - } +class ForkableSharedMutex final { +public: + ForkableSharedMutex() + : Mutex(PTHREAD_RWLOCK_INITIALIZER) {} - // Move-only type - ForkableSharedMutex(const ForkableSharedMutex&) = delete; - ForkableSharedMutex& operator=(const ForkableSharedMutex&) = delete; - ForkableSharedMutex(ForkableSharedMutex &&rhs) = default; - ForkableSharedMutex& operator=(ForkableSharedMutex &&) = default; + // Move-only type + ForkableSharedMutex(const ForkableSharedMutex&) = delete; + ForkableSharedMutex& operator=(const ForkableSharedMutex&) = delete; + ForkableSharedMutex(ForkableSharedMutex&& rhs) = default; + ForkableSharedMutex& operator=(ForkableSharedMutex&&) = default; - void lock() { - [[maybe_unused]] const auto Result = pthread_rwlock_wrlock(&Mutex); - LOGMAN_THROW_A_FMT(Result == 0, "{} failed to lock with {}", __func__, Result); - } - void unlock() { - [[maybe_unused]] const auto Result = pthread_rwlock_unlock(&Mutex); - LOGMAN_THROW_A_FMT(Result == 0, "{} failed to unlock with {}", __func__, Result); - } - void lock_shared() { - [[maybe_unused]] const auto Result = pthread_rwlock_rdlock(&Mutex); - LOGMAN_THROW_A_FMT(Result == 0, "{} failed to lock with {}", __func__, Result); - } + void lock() { + [[maybe_unused]] const auto Result = pthread_rwlock_wrlock(&Mutex); + LOGMAN_THROW_A_FMT(Result == 0, "{} failed to lock with {}", __func__, Result); + } + void unlock() { + [[maybe_unused]] const auto Result = pthread_rwlock_unlock(&Mutex); + LOGMAN_THROW_A_FMT(Result == 0, "{} failed to unlock with {}", __func__, Result); + } + void lock_shared() { + [[maybe_unused]] const auto Result = pthread_rwlock_rdlock(&Mutex); + LOGMAN_THROW_A_FMT(Result == 0, "{} failed to lock with {}", __func__, Result); + } - void unlock_shared() { - unlock(); - } + void unlock_shared() { + unlock(); + } - bool try_lock() { - const auto Result = pthread_rwlock_trywrlock(&Mutex); - return Result == 0; - } + bool try_lock() { + const auto Result = pthread_rwlock_trywrlock(&Mutex); + return Result == 0; + } - bool try_lock_shared() { - const auto Result = pthread_rwlock_tryrdlock(&Mutex); - return Result == 0; - } - // Initialize the internal pthread object to its default initializer state. - // Should only ever be used in the child process when a Linux fork() has occured. - void StealAndDropActiveLocks() { - Mutex = PTHREAD_RWLOCK_INITIALIZER; - } - private: - pthread_rwlock_t Mutex; - }; + bool try_lock_shared() { + const auto Result = pthread_rwlock_tryrdlock(&Mutex); + return Result == 0; + } + // Initialize the internal pthread object to its default initializer state. + // Should only ever be used in the child process when a Linux fork() has occured. + void StealAndDropActiveLocks() { + Mutex = PTHREAD_RWLOCK_INITIALIZER; + } +private: + pthread_rwlock_t Mutex; +}; #else - // Windows doesn't support forking, so these can be standard mutexes. - class ForkableUniqueMutex final : public std::mutex { - public: - void StealAndDropActiveLocks() { - LogMan::Msg::AFmt("{} is unsupported on WIN32 builds!", __func__); - } - }; +// Windows doesn't support forking, so these can be standard mutexes. +class ForkableUniqueMutex final : public std::mutex { +public: + void StealAndDropActiveLocks() { + LogMan::Msg::AFmt("{} is unsupported on WIN32 builds!", __func__); + } +}; - class ForkableSharedMutex final : public std::shared_mutex { - public: - void StealAndDropActiveLocks() { - LogMan::Msg::AFmt("{} is unsupported on WIN32 builds!", __func__); - } - }; +class ForkableSharedMutex final : public std::shared_mutex { +public: + void StealAndDropActiveLocks() { + LogMan::Msg::AFmt("{} is unsupported on WIN32 builds!", __func__); + } +}; #endif - // Helper class to manage deferred signal refcounting within a block scope - class DeferredSignalRefCountGuard final { - public: - explicit DeferredSignalRefCountGuard(FEXCore::Core::InternalThreadState *Thread) : Thread(Thread) { - // Needs to be atomic so that operations can't end up getting reordered around this. - Thread->CurrentFrame->State.DeferredSignalRefCount.Increment(1); - } +// Helper class to manage deferred signal refcounting within a block scope +class DeferredSignalRefCountGuard final { +public: + explicit DeferredSignalRefCountGuard(FEXCore::Core::InternalThreadState* Thread) + : Thread(Thread) { + // Needs to be atomic so that operations can't end up getting reordered around this. + Thread->CurrentFrame->State.DeferredSignalRefCount.Increment(1); + } - // Move-only type - DeferredSignalRefCountGuard(const DeferredSignalRefCountGuard&) = delete; - DeferredSignalRefCountGuard& operator=(DeferredSignalRefCountGuard&) = delete; - DeferredSignalRefCountGuard(DeferredSignalRefCountGuard&& rhs) : Thread(rhs.Thread) { - rhs.Thread = nullptr; - } + // Move-only type + DeferredSignalRefCountGuard(const DeferredSignalRefCountGuard&) = delete; + DeferredSignalRefCountGuard& operator=(DeferredSignalRefCountGuard&) = delete; + DeferredSignalRefCountGuard(DeferredSignalRefCountGuard&& rhs) + : Thread(rhs.Thread) { + rhs.Thread = nullptr; + } - ~DeferredSignalRefCountGuard() { - if (Thread) { + ~DeferredSignalRefCountGuard() { + if (Thread) { #ifdef _M_X86_64 - // Needs to be atomic so that operations can't end up getting reordered around this. - // Without this, the refcount and the signal access could get reordered. - auto Result = Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); + // Needs to be atomic so that operations can't end up getting reordered around this. + // Without this, the refcount and the signal access could get reordered. + auto Result = Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); - // X86-64 must do an additional check around the store. - if ((Result - 1) == 0) { - // Must happen after the refcount store - Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); - } -#else - Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); - Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); -#endif - } + // X86-64 must do an additional check around the store. + if ((Result - 1) == 0) { + // Must happen after the refcount store + Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); } - private: - FEXCore::Core::InternalThreadState *Thread; - }; +#else + Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); + Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); +#endif + } + } +private: + FEXCore::Core::InternalThreadState* Thread; +}; #ifndef _WIN32 - // Helper class to mask POSIX signals within a block scope - class ScopedSignalMasker final { - public: - explicit ScopedSignalMasker(uint64_t Mask) : OriginalMask(0) { - // Mask all signals, storing the original incoming mask - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &*OriginalMask, sizeof(*OriginalMask)); - } - - // Move-only type - ScopedSignalMasker(const ScopedSignalMasker&) = delete; - ScopedSignalMasker& operator=(ScopedSignalMasker&) = delete; - ScopedSignalMasker(ScopedSignalMasker&& rhs) : OriginalMask(rhs.OriginalMask) { - rhs.OriginalMask.reset(); - } - - ~ScopedSignalMasker() { - if (OriginalMask) { - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(*OriginalMask)); - } - } - private: - std::optional OriginalMask{}; - }; -#endif - - /** - * @brief Produces a wrapper object around a scoped lock of the given mutex - * while ensuring POSIX signals are masked while the mutex is locked - * - * Use this to prevent reentrancy issues of C++ mutexes with certain signal handlers. - * Common examples of such issues are: - * - C++ mutexes not unlocking due to a signal handler calling longjmp from within a scope owning the mutex - * - The signal handler itself using a mutex that would be re-locked if the handler gets invoked - * again before unlocking - * - * Ownership of the returned object may be moved, but it is NOT SAFE to move across threads. - */ - template class LockType = std::unique_lock, typename MutexType> - [[nodiscard]] static auto MaskSignalsAndLockMutex(MutexType& mutex, uint64_t Mask = ~0ULL) { -#ifndef _WIN32 - // Signals are masked first, and then the lock is acquired - struct { - ScopedSignalMasker mask; - LockType lock; - } scope_guard { ScopedSignalMasker { Mask }, LockType { mutex } }; - return scope_guard; -#else - // TODO: Doesn't block signals which may or may not cause issues. - return LockType { mutex }; -#endif +// Helper class to mask POSIX signals within a block scope +class ScopedSignalMasker final { +public: + explicit ScopedSignalMasker(uint64_t Mask) + : OriginalMask(0) { + // Mask all signals, storing the original incoming mask + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &*OriginalMask, sizeof(*OriginalMask)); } - /** - * @brief Produces a wrapper object around a scoped lock of the given mutex - * while bumping the Thread's deferred signal refcount while the mutex is - * locked. - */ - template class LockType = std::unique_lock, typename MutexType> - [[nodiscard]] static auto GuardSignalDeferringSection(MutexType& mutex, FEXCore::Core::InternalThreadState *Thread, uint64_t Mask = ~0ULL) { - // Refcount is incremented first, and then the lock is acquired. - struct { - std::optional refcount; - LockType lock; - } scope_guard = { DeferredSignalRefCountGuard { Thread }, LockType { mutex } }; - return scope_guard; + // Move-only type + ScopedSignalMasker(const ScopedSignalMasker&) = delete; + ScopedSignalMasker& operator=(ScopedSignalMasker&) = delete; + ScopedSignalMasker(ScopedSignalMasker&& rhs) + : OriginalMask(rhs.OriginalMask) { + rhs.OriginalMask.reset(); } - // Like GuardSignalDeferringSection but falls back to masking signals when Thread is nullptr - template class LockType = std::unique_lock, typename MutexType> - [[nodiscard]] static auto GuardSignalDeferringSectionWithFallback(MutexType& mutex, FEXCore::Core::InternalThreadState *Thread, uint64_t Mask = ~0ULL) { -#ifndef _WIN32 - using ExtraGuard = std::variant; -#else - using ExtraGuard = std::variant; + ~ScopedSignalMasker() { + if (OriginalMask) { + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(*OriginalMask)); + } + } +private: + std::optional OriginalMask {}; +}; #endif - struct { - ExtraGuard refcount_or_mask; - LockType lock; - } scope_guard { - Thread ? ExtraGuard { DeferredSignalRefCountGuard { Thread } } +/** + * @brief Produces a wrapper object around a scoped lock of the given mutex + * while ensuring POSIX signals are masked while the mutex is locked + * + * Use this to prevent reentrancy issues of C++ mutexes with certain signal handlers. + * Common examples of such issues are: + * - C++ mutexes not unlocking due to a signal handler calling longjmp from within a scope owning the mutex + * - The signal handler itself using a mutex that would be re-locked if the handler gets invoked + * again before unlocking + * + * Ownership of the returned object may be moved, but it is NOT SAFE to move across threads. + */ +template class LockType = std::unique_lock, typename MutexType> +[[nodiscard]] +static auto MaskSignalsAndLockMutex(MutexType& mutex, uint64_t Mask = ~0ULL) { #ifndef _WIN32 - : ExtraGuard { ScopedSignalMasker { Mask } } + // Signals are masked first, and then the lock is acquired + struct { + ScopedSignalMasker mask; + LockType lock; + } scope_guard {ScopedSignalMasker {Mask}, LockType {mutex}}; + return scope_guard; #else - : ExtraGuard { } + // TODO: Doesn't block signals which may or may not cause issues. + return LockType {mutex}; #endif - }; - scope_guard.lock = LockType { mutex }; - return scope_guard; - } } + +/** + * @brief Produces a wrapper object around a scoped lock of the given mutex + * while bumping the Thread's deferred signal refcount while the mutex is + * locked. + */ +template class LockType = std::unique_lock, typename MutexType> +[[nodiscard]] +static auto GuardSignalDeferringSection(MutexType& mutex, FEXCore::Core::InternalThreadState* Thread, uint64_t Mask = ~0ULL) { + // Refcount is incremented first, and then the lock is acquired. + struct { + std::optional refcount; + LockType lock; + } scope_guard = {DeferredSignalRefCountGuard {Thread}, LockType {mutex}}; + return scope_guard; +} + +// Like GuardSignalDeferringSection but falls back to masking signals when Thread is nullptr +template class LockType = std::unique_lock, typename MutexType> +[[nodiscard]] +static auto GuardSignalDeferringSectionWithFallback(MutexType& mutex, FEXCore::Core::InternalThreadState* Thread, uint64_t Mask = ~0ULL) { +#ifndef _WIN32 + using ExtraGuard = std::variant; +#else + using ExtraGuard = std::variant; +#endif + + struct { + ExtraGuard refcount_or_mask; + LockType lock; + } scope_guard {Thread ? ExtraGuard {DeferredSignalRefCountGuard {Thread}} +#ifndef _WIN32 + : + ExtraGuard {ScopedSignalMasker {Mask}} +#else + : + ExtraGuard {} +#endif + }; + scope_guard.lock = LockType {mutex}; + return scope_guard; +} +} // namespace FEXCore diff --git a/FEXCore/include/FEXCore/Utils/StringUtils.h b/FEXCore/include/FEXCore/Utils/StringUtils.h index af135e76a..cad62186d 100644 --- a/FEXCore/include/FEXCore/Utils/StringUtils.h +++ b/FEXCore/include/FEXCore/Utils/StringUtils.h @@ -3,29 +3,32 @@ #include namespace FEXCore::StringUtils { - // Trim the left side of the string of whitespace and new lines - [[maybe_unused]] static fextl::string LeftTrim(fextl::string String, std::string_view TrimTokens = " \t\n\r") { - size_t pos = fextl::string::npos; - if ((pos = String.find_first_not_of(TrimTokens)) != fextl::string::npos) { - String.erase(0, pos); - } - - return String; - } - - // Trim the right side of the string of whitespace and new lines - [[maybe_unused]] static fextl::string RightTrim(fextl::string String, std::string_view TrimTokens = " \t\n\r") { - size_t pos = fextl::string::npos; - if ((pos = String.find_last_not_of(TrimTokens)) != fextl::string::npos) { - String.erase(String.begin() + pos + 1, String.end()); - } - - return String; - } - - // Trim both the left and right of the string of whitespace and new lines - [[maybe_unused]] static fextl::string Trim(fextl::string String, std::string_view TrimTokens = " \t\n\r") { - return RightTrim(LeftTrim(std::move(String), TrimTokens), TrimTokens); +// Trim the left side of the string of whitespace and new lines +[[maybe_unused]] +static fextl::string LeftTrim(fextl::string String, std::string_view TrimTokens = " \t\n\r") { + size_t pos = fextl::string::npos; + if ((pos = String.find_first_not_of(TrimTokens)) != fextl::string::npos) { + String.erase(0, pos); } + return String; } + +// Trim the right side of the string of whitespace and new lines +[[maybe_unused]] +static fextl::string RightTrim(fextl::string String, std::string_view TrimTokens = " \t\n\r") { + size_t pos = fextl::string::npos; + if ((pos = String.find_last_not_of(TrimTokens)) != fextl::string::npos) { + String.erase(String.begin() + pos + 1, String.end()); + } + + return String; +} + +// Trim both the left and right of the string of whitespace and new lines +[[maybe_unused]] +static fextl::string Trim(fextl::string String, std::string_view TrimTokens = " \t\n\r") { + return RightTrim(LeftTrim(std::move(String), TrimTokens), TrimTokens); +} + +} // namespace FEXCore::StringUtils diff --git a/FEXCore/include/FEXCore/Utils/Telemetry.h b/FEXCore/include/FEXCore/Utils/Telemetry.h index 377856058..9fa77325b 100644 --- a/FEXCore/include/FEXCore/Utils/Telemetry.h +++ b/FEXCore/include/FEXCore/Utils/Telemetry.h @@ -10,60 +10,72 @@ #include namespace FEXCore::Telemetry { - enum TelemetryType { - TYPE_HAS_SPLIT_LOCKS, - TYPE_16BYTE_SPLIT, - TYPE_USES_VEX_OPS, - TYPE_USES_EVEX_OPS, - TYPE_CAS_16BIT_TEAR, - TYPE_CAS_32BIT_TEAR, - TYPE_CAS_64BIT_TEAR, - TYPE_CAS_128BIT_TEAR, - TYPE_CRASH_MASK, - // If a 32-bit application is writing a non-zero value to segments. - TYPE_WRITES_32BIT_SEGMENT_ES, - TYPE_WRITES_32BIT_SEGMENT_SS, - TYPE_WRITES_32BIT_SEGMENT_CS, - TYPE_WRITES_32BIT_SEGMENT_DS, - // If a 32-bit application is prefix/using a non-zero segment on memory access. - TYPE_USES_32BIT_SEGMENT_ES, - TYPE_USES_32BIT_SEGMENT_SS, - TYPE_USES_32BIT_SEGMENT_CS, - TYPE_USES_32BIT_SEGMENT_DS, - TYPE_UNHANDLED_NONCANONICAL_ADDRESS, - TYPE_LAST, - }; +enum TelemetryType { + TYPE_HAS_SPLIT_LOCKS, + TYPE_16BYTE_SPLIT, + TYPE_USES_VEX_OPS, + TYPE_USES_EVEX_OPS, + TYPE_CAS_16BIT_TEAR, + TYPE_CAS_32BIT_TEAR, + TYPE_CAS_64BIT_TEAR, + TYPE_CAS_128BIT_TEAR, + TYPE_CRASH_MASK, + // If a 32-bit application is writing a non-zero value to segments. + TYPE_WRITES_32BIT_SEGMENT_ES, + TYPE_WRITES_32BIT_SEGMENT_SS, + TYPE_WRITES_32BIT_SEGMENT_CS, + TYPE_WRITES_32BIT_SEGMENT_DS, + // If a 32-bit application is prefix/using a non-zero segment on memory access. + TYPE_USES_32BIT_SEGMENT_ES, + TYPE_USES_32BIT_SEGMENT_SS, + TYPE_USES_32BIT_SEGMENT_CS, + TYPE_USES_32BIT_SEGMENT_DS, + TYPE_UNHANDLED_NONCANONICAL_ADDRESS, + TYPE_LAST, +}; #ifndef FEX_DISABLE_TELEMETRY - class Value; +class Value; - class Value final { - public: - Value() = default; - Value(uint64_t Default) : Data {Default} {} +class Value final { +public: + Value() = default; + Value(uint64_t Default) + : Data {Default} {} - uint64_t operator*() const { return Data; } - void operator=(uint64_t Value) { Data = Value; } - void operator|=(uint64_t Value) { Data |= Value; } - void operator++(int) { Data++; } + uint64_t operator*() const { + return Data; + } + void operator=(uint64_t Value) { + Data = Value; + } + void operator|=(uint64_t Value) { + Data |= Value; + } + void operator++(int) { + Data++; + } - std::atomic *GetAddr() { return &Data; } + std::atomic* GetAddr() { + return &Data; + } - private: - std::atomic Data; - }; +private: + std::atomic Data; +}; - FEX_DEFAULT_VISIBILITY Value &GetTelemetryValue(TelemetryType Type); +FEX_DEFAULT_VISIBILITY Value& GetTelemetryValue(TelemetryType Type); - FEX_DEFAULT_VISIBILITY void Initialize(); - FEX_DEFAULT_VISIBILITY void Shutdown(fextl::string const &ApplicationName); +FEX_DEFAULT_VISIBILITY void Initialize(); +FEX_DEFAULT_VISIBILITY void Shutdown(const fextl::string& ApplicationName); // Telemetry object declaration // This returns the internal structure to the telemetry data structures // One must be careful with placing these in the hot path of code execution // It can be fairly costly, especially in the static version where it puts barriers in the code -#define FEXCORE_TELEMETRY_STATIC_INIT(Name, Type) static FEXCore::Telemetry::Value &Name = FEXCore::Telemetry::GetTelemetryValue(FEXCore::Telemetry::Type) -#define FEXCORE_TELEMETRY_INIT(Name, Type) FEXCore::Telemetry::Value &Name = FEXCore::Telemetry::GetTelemetryValue(FEXCore::Telemetry::Type) +#define FEXCORE_TELEMETRY_STATIC_INIT(Name, Type) \ + static FEXCore::Telemetry::Value& Name = FEXCore::Telemetry::GetTelemetryValue(FEXCore::Telemetry::Type) +#define FEXCORE_TELEMETRY_INIT(Name, Type) FEXCore::Telemetry::Value& Name = FEXCore::Telemetry::GetTelemetryValue(FEXCore::Telemetry::Type) // Telemetry ALU operations // These are typically 3-4 instructions depending on what you're doing #define FEXCORE_TELEMETRY_SET(Name, Value) Name = Value @@ -74,15 +86,23 @@ namespace FEXCore::Telemetry { // Not recommended to do telemetry inside JIT code in production code #define FEXCORE_TELEMETRY_Addr(Name) Name->GetAddr() #else - static inline void Initialize() {} - static inline void Shutdown(fextl::string const &ApplicationName) {} +static inline void Initialize() {} +static inline void Shutdown(const fextl::string& ApplicationName) {} #define FEXCORE_TELEMETRY_STATIC_INIT(Name, Type) #define FEXCORE_TELEMETRY_INIT(Name, Type) -#define FEXCORE_TELEMETRY(Name, Value) do {} while(0) -#define FEXCORE_TELEMETRY_SET(Name, Value) do {} while(0) -#define FEXCORE_TELEMETRY_OR(Name, Value) do {} while(0) -#define FEXCORE_TELEMETRY_INC(Name) do {} while(0) +#define FEXCORE_TELEMETRY(Name, Value) \ + do { \ + } while (0) +#define FEXCORE_TELEMETRY_SET(Name, Value) \ + do { \ + } while (0) +#define FEXCORE_TELEMETRY_OR(Name, Value) \ + do { \ + } while (0) +#define FEXCORE_TELEMETRY_INC(Name) \ + do { \ + } while (0) #define FEXCORE_TELEMETRY_Addr(Name) reinterpret_cast*>(nullptr) #endif -} +} // namespace FEXCore::Telemetry diff --git a/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h b/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h index 0edf612e5..8a6efb38c 100644 --- a/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h +++ b/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h @@ -11,496 +11,498 @@ #include namespace FEXCore::Utils { - /** - * @brief An intrusive thread pool allocator - * - * Requires coordination between the allocator and its clients to efficiently share memory allocations between threads. - * - * The `Client` in this case referring to the location in code allocating a `MemoryBuffer` from the allocator. - * - The client must `Claim` a buffer to allocate it - * - In claiming a buffer, the allocator is passed a `BufferOwnedFlag` that is updated by both the allocator and client. - * - When the client is done with the buffer it must `Disown` or `Unclaim` the buffer. - * - `Disown` the buffer when it is expected to be used again soon. - * - This is relatively cheap. - * - `Unclaim` when the buffer won't be used again for an extended period. - * - This is expensive and requires a mutex shared between threads - * - `FixedSizePooledAllocation` helper class provided to help with this. - * - * Once the client has disowned a buffer then the allocator is free to reclaim the buffer when another thread is trying to `Claim` a new buffer. - * The buffer getting claimed from a disowned client must have had its last use greater than the defined `DURATION` before it has a chance to get - * reclaimed by the Allocator. - * - * During buffer reclaiming is also when unclaimed buffers get freed. This means active threads are able to clean up idle thread's unused memory. - */ - class IntrusivePooledAllocator { - public: - template - struct AllocationInfo { - T Ptr; - size_t Size; - }; - - struct MemoryBuffer; - /** - * @brief Container for tracking the buffers - * - * We're using fextl::list explicitly because its iterators aren't invalidated when the list is adjusted. - * if we had list types that we can atomically erase and append elements then unclaiming could be made cheaper. - */ - using ContainerType = fextl::list; - /** - * @brief steady_clock to ensure long running applications don't hit any timeskip problems. - */ - using ClockType = std::chrono::steady_clock; - /** - * @brief Atomic flag state for letting the client know if it owns the buffer - */ - enum class ClientFlags : uint32_t { - FLAG_FREE = 0, - FLAG_OWNED = 1, - FLAG_DISOWNED = 3, - }; - - using BufferOwnedFlag = std::atomic; - - struct MemoryBuffer : public FEXCore::Allocator::FEXAllocOperators { - MemoryBuffer(void* Ptr, size_t Size, std::chrono::time_point LastUsed) - : Ptr {Ptr} - , Size {Size} - , LastUsed {LastUsed} {} - - void* Ptr; - size_t Size; - std::atomic> LastUsed; - BufferOwnedFlag *CurrentClientOwnedFlag{}; - }; - // Ensure that the atomic objects of MemoryBuffer are lock free - static_assert(decltype(MemoryBuffer::LastUsed){}.is_always_lock_free, "Oops, needs to be lock free"); - static_assert(std::remove_pointer::type{}.is_always_lock_free, "Oops, needs to be lock free"); - - /** - * @brief Lets the client easily check if they own the buffer or not - * - * @param CurrentClientFlag Client owned flag - * - * @return Is the client buffer owned at the point of checking - */ - static bool IsClientBufferOwned(BufferOwnedFlag &CurrentClientFlag) { - return CurrentClientFlag.load() == ClientFlags::FLAG_OWNED; - } - - /** - * @brief Lets the client easily check if the buffer was freed - * - * @param CurrentClientFlag Client owned flag - * - * @return Is the client buffer owned at the point of checking - */ - static bool IsClientBufferFree(BufferOwnedFlag &CurrentClientFlag) { - return CurrentClientFlag.load() == ClientFlags::FLAG_FREE; - } - - /** - * @brief Allocates and claims a buffer that is tracked from the thread pool - * - * @param Size - * @param CurrentClientFlag - * - * Once a buffer is claimed, the pool allocator can not reclaim this buffer until it is "Disowned" - * - * @return iterator to the internal tracking container - */ - ContainerType::iterator ClaimBuffer(size_t Size, BufferOwnedFlag *CurrentClientFlag) { - std::unique_lock lk {AllocationMutex}; - auto Buffer = ClaimBufferImpl(Size); - (*Buffer)->CurrentClientOwnedFlag = CurrentClientFlag; - CurrentClientFlag->store(ClientFlags::FLAG_OWNED); - return Buffer; - } - - /** - * @brief Immediately release the buffer back to the allocator - * - * @param Buffer - The iterator that was previously given with ClaimBuffer - * - * Once this is called on a buffer then the pool allocator has full ownership of the buffer - */ - void UnclaimBuffer(ContainerType::iterator Buffer) { - std::unique_lock lk {AllocationMutex}; - (*Buffer)->CurrentClientOwnedFlag->store(ClientFlags::FLAG_FREE); - UnclaimBufferImpl(Buffer); - } - - /** - * @brief Set internal flags of buffer claiming that the buffer is relinquished ownership - * - * @param Buffer - The iterator that was previously given with ClaimBuffer - * - * Once the buffer is disowned, the allocator can take back ownership of the buffer at any time - * - * Use ReownOrClaimBuffer if you want to attempt reusing a buffer being held on to. - */ - void DisownBuffer(ContainerType::iterator Buffer) { - // Client still owns the buffer but isn't using it - // Allows us to claim it back if necessary - (*Buffer)->LastUsed.store(ClockType::now(), std::memory_order_relaxed); - (*Buffer)->CurrentClientOwnedFlag->store(ClientFlags::FLAG_DISOWNED); - } - - /** - * @brief Try to reown a buffer that we have previous disowned, failing that, claim a new buffer - * - * @param Buffer - The buffer we previously disowned - * @param Size - The size of the buffer - * @param CurrentClientFlag - The client tracked flag - * - * Once a DisownBuffer has been called, it is unsafe to use the buffer until it has been reowned - * Always Reown a buffer after disowning it before use! - * - * @return Either the original buffer passed in if we managed to reclaim, or a new buffer if we couldn't - */ - ContainerType::iterator ReownOrClaimBuffer(ContainerType::iterator Buffer, size_t Size, BufferOwnedFlag *CurrentClientFlag) { - ClientFlags Expected = ClientFlags::FLAG_DISOWNED; - if (CurrentClientFlag->compare_exchange_strong(Expected, ClientFlags::FLAG_OWNED)) { - // If we managed to change the flag from DISOWNED to OWNED then we have successfully reclaimed - // Finish setting up state - (*Buffer)->LastUsed.store(ClockType::now(), std::memory_order_relaxed); - return Buffer; - } - - // Couldn't reclaim, just get a new buffer - return ClaimBuffer(Size, CurrentClientFlag); - } - - virtual ~IntrusivePooledAllocator() = default; - - // XXX: Is this a good amount? - /** - * @brief Duration before the allocator will reclaim buffers that the client claimed AND disowned - * - * Pool allocator will not attempt to reclaim client owned buffers, would be unsafe to do so. - */ - constexpr static std::chrono::duration DURATION {std::chrono::seconds(5)}; - - protected: - IntrusivePooledAllocator() = default; - - ContainerType::iterator ClaimBufferImpl(size_t Size) { - auto BuffersEnd = UnclaimedBuffers.end(); - ContainerType::iterator BestFit = BuffersEnd; - ContainerType::iterator UnsizedFit = BuffersEnd; - - auto Now = ClockType::now(); - // Move any expired ClaimedBuffers to UnclaimedBuffers - { - // Spin the non-owned buffers and see if we can take ones past the period - for (auto it = ClaimedBuffers.begin(); it != ClaimedBuffers.end();) { - // 1) Can't take anything that the client has still claimed - // 2) Needs to still be last used beyond our time threshold - // 3) Only take the oldest buffer - if ((*it)->CurrentClientOwnedFlag->load() == ClientFlags::FLAG_DISOWNED) { - auto UsedTime = (*it)->LastUsed.load(std::memory_order_relaxed); - if ((Now - UsedTime) >= DURATION) { - ClientFlags Expected = ClientFlags::FLAG_DISOWNED; - if ((*it)->CurrentClientOwnedFlag->compare_exchange_strong(Expected, ClientFlags::FLAG_FREE)) { - // We managed to take away ownership - // Put it back in the regular pool and come back to it - (*it)->CurrentClientOwnedFlag = nullptr; - UnclaimedBuffers.emplace_back(*it); - it = ClaimedBuffers.erase(it); - continue; - } - } - } - - ++it; - } - } - - // Find an unclaimed buffer that is >= Size and Free up to one unclaimed buffer that has expired - { - // Walk all the allocations and find a buffer that fits - for (auto it = UnclaimedBuffers.begin(); it != BuffersEnd; ++it) { - if ((*it)->Size == Size) { - BestFit = it; - break; - } - - if ((*it)->Size > Size) { - UnsizedFit = it; - } - } - - // If we didn't have an exact fit then use an unsized fit - if (BestFit == BuffersEnd) { - BestFit = UnsizedFit; - } - - // Free up to one unclaimed buffer that has expired - { - std::chrono::time_point LRUTime{}; - ContainerType::iterator LastUsed = BuffersEnd; - - // Walk all the allocations and find a buffer to erase - for (auto it = UnclaimedBuffers.begin(); it != UnclaimedBuffers.end(); ++it) { - // Ensure that the LRU value is past our duration threshold and isn't the one we are claiming - // Also only select a single memory region - if (it != BestFit) { - auto UsedTime = (*it)->LastUsed.load(std::memory_order_relaxed); - if ((Now - UsedTime) >= DURATION && - UsedTime > LRUTime) { - LastUsed = it; - LRUTime = UsedTime; - } - } - } - - // If we found a buffer then free it - if (LastUsed != BuffersEnd) { - Free((*LastUsed)->Ptr, (*LastUsed)->Size); - delete *LastUsed; - UnclaimedBuffers.erase(LastUsed); - } - } - - if (BestFit != UnclaimedBuffers.end()) { - MemoryBuffer *Buffer = *BestFit; - UnclaimedBuffers.erase(BestFit); - return ClaimedBuffers.emplace(ClaimedBuffers.end(), Buffer); - } - } - - // Need to allocate a new buffer, couldn't fit - auto Data = Alloc(Size); - return ClaimedBuffers.emplace(ClaimedBuffers.end(), new MemoryBuffer{Data, Size, ClockType::now()}); - } - - void UnclaimBufferImpl(ContainerType::iterator Buffer) { - (*Buffer)->CurrentClientOwnedFlag = nullptr; - UnclaimedBuffers.emplace_back(*Buffer); - ClaimedBuffers.erase(Buffer); - } - - void FreeAllBuffers() { - for (auto it : UnclaimedBuffers) { - Free(it->Ptr, it->Size); - delete it; - } - - for (auto it : ClaimedBuffers) { - Free(it->Ptr, it->Size); - delete it; - } - - UnclaimedBuffers.clear(); - ClaimedBuffers.clear(); - } - - /** - * @brief List of buffers that this pool allocator itself owns - */ - ContainerType UnclaimedBuffers; - - /** - * @brief List of buffers that are client claimed - */ - ContainerType ClaimedBuffers; - - /** - * @brief Mutex to ensure thread safety while shuffling buffers around and allocating - */ - std::mutex AllocationMutex; - - private: - /** - * @brief Allocates the buffer - * - * @param Size of the object to allocate - * - * @return pointer - */ - virtual void *Alloc(size_t Size) = 0; - /** - * @brief Frees the buffer - * - * @param Ptr buffer pointer - * @param Size buffer size - */ - virtual void Free(void* Ptr, size_t Size) = 0; +/** + * @brief An intrusive thread pool allocator + * + * Requires coordination between the allocator and its clients to efficiently share memory allocations between threads. + * + * The `Client` in this case referring to the location in code allocating a `MemoryBuffer` from the allocator. + * - The client must `Claim` a buffer to allocate it + * - In claiming a buffer, the allocator is passed a `BufferOwnedFlag` that is updated by both the allocator and client. + * - When the client is done with the buffer it must `Disown` or `Unclaim` the buffer. + * - `Disown` the buffer when it is expected to be used again soon. + * - This is relatively cheap. + * - `Unclaim` when the buffer won't be used again for an extended period. + * - This is expensive and requires a mutex shared between threads + * - `FixedSizePooledAllocation` helper class provided to help with this. + * + * Once the client has disowned a buffer then the allocator is free to reclaim the buffer when another thread is trying to `Claim` a new buffer. + * The buffer getting claimed from a disowned client must have had its last use greater than the defined `DURATION` before it has a chance to get + * reclaimed by the Allocator. + * + * During buffer reclaiming is also when unclaimed buffers get freed. This means active threads are able to clean up idle thread's unused memory. + */ +class IntrusivePooledAllocator { +public: + template + struct AllocationInfo { + T Ptr; + size_t Size; }; + struct MemoryBuffer; /** - * @brief Thread pool allocator that allocates and frees objects using malloc + * @brief Container for tracking the buffers + * + * We're using fextl::list explicitly because its iterators aren't invalidated when the list is adjusted. + * if we had list types that we can atomically erase and append elements then unclaiming could be made cheaper. */ - class PooledAllocatorMalloc final : public IntrusivePooledAllocator { - public: - PooledAllocatorMalloc() = default; - - virtual ~PooledAllocatorMalloc() { - FreeAllBuffers(); - } - - private: - void *Alloc(size_t Size) override { - return FEXCore::Allocator::malloc(Size); - } - - void Free(void* Ptr, size_t Size) override { - FEXCore::Allocator::free(Ptr); - } + using ContainerType = fextl::list; + /** + * @brief steady_clock to ensure long running applications don't hit any timeskip problems. + */ + using ClockType = std::chrono::steady_clock; + /** + * @brief Atomic flag state for letting the client know if it owns the buffer + */ + enum class ClientFlags : uint32_t { + FLAG_FREE = 0, + FLAG_OWNED = 1, + FLAG_DISOWNED = 3, }; - /** - * @brief Thread pool allocator that allocates and frees objects that uses mmap - */ - class PooledAllocatorVirtual final : public IntrusivePooledAllocator { - public: - PooledAllocatorVirtual() = default; + using BufferOwnedFlag = std::atomic; - virtual ~PooledAllocatorVirtual() { - FreeAllBuffers(); - } + struct MemoryBuffer : public FEXCore::Allocator::FEXAllocOperators { + MemoryBuffer(void* Ptr, size_t Size, std::chrono::time_point LastUsed) + : Ptr {Ptr} + , Size {Size} + , LastUsed {LastUsed} {} - private: - void *Alloc(size_t Size) override { - return FEXCore::Allocator::VirtualAlloc(Size); - } - - void Free(void* Ptr, size_t Size) override { - FEXCore::Allocator::VirtualFree(Ptr, Size); - } + void* Ptr; + size_t Size; + std::atomic> LastUsed; + BufferOwnedFlag* CurrentClientOwnedFlag {}; }; + // Ensure that the atomic objects of MemoryBuffer are lock free + static_assert(decltype(MemoryBuffer::LastUsed) {}.is_always_lock_free, "Oops, needs to be lock free"); + static_assert(std::remove_pointer::type {}.is_always_lock_free, "Oops, needs to be lock " + "free"); /** - * @brief Wrapper around the pool allocator for delayed pool reclaiming + * @brief Lets the client easily check if they own the buffer or not * - * This is expected to be used in high frequency buffer temporary usage. - * Instead of quickly unclaiming and reclaiming the buffer while the the code is hot, - * This instead will do the cheap operation of disowning the buffer until the code path cools down enough. - * Once the code path stops disowning the codepath more times than `PeriodFrequency` during `PeriodMS` then - * it will immediately unclaim. + * @param CurrentClientFlag Client owned flag * - * Implications: - * - The object will always be claimed for at *least* `PeriodFrequency` - * - The object will still *always* be disowned after each temporary use - * - This allows the pool allocator to reclaim a buffer from a sleeping thread - * - * Performance characteristics: - * - Disowning is cheap. - * - Last-used timestamp update - * - atomic_bool clear to signify it is disowned - * - * - Reowning is relatively cheap (When buffer is still owned). - * - atomic_bool load to check if the object is still owned - * - atomic CAS to change the object to `OWNED` state - * - Resolves a race condition where the `Allocator` can be in the process of reclaiming the buffer from the client - * - Last-used timestamp update - * - atomic_bool set to signify owned - * - atomic set to change object to `OWNED` state - * - When object isn't owned, then allocate a new buffer from the pool - * - * - Unclaiming is fairly costly - * - Requires owning a mutex, shared between all threads using the `Allocator` - * - Updating two fextl::list containers to give the ownership back to the `Allocator` - * - * - Claiming is very costly - * - Requires owning a mutex, shared between all threads using the `Allocator` - * - Scans two fextl::list containers to find the best fit buffer - * - Or allocates another buffer when that fails - * - Frees stale buffers opportunistically + * @return Is the client buffer owned at the point of checking */ - template - class FixedSizePooledAllocation final { - // If the delayed object reclaimer is more than the thread pool allocator's duration then the pool allocator would always need to reclaim the - // buffer rather than giving it back. - static_assert(std::chrono::duration(std::chrono::milliseconds(PeriodMS)) <= IntrusivePooledAllocator::DURATION, - "DeplayedObjectReclaimer period needs to be lower or equal to the pool allocator duration"); + static bool IsClientBufferOwned(BufferOwnedFlag& CurrentClientFlag) { + return CurrentClientFlag.load() == ClientFlags::FLAG_OWNED; + } - public: - FixedSizePooledAllocation(IntrusivePooledAllocator &Allocator, size_t Size) - : ThreadAllocator {Allocator} - , Size {Size} { - } + /** + * @brief Lets the client easily check if the buffer was freed + * + * @param CurrentClientFlag Client owned flag + * + * @return Is the client buffer owned at the point of checking + */ + static bool IsClientBufferFree(BufferOwnedFlag& CurrentClientFlag) { + return CurrentClientFlag.load() == ClientFlags::FLAG_FREE; + } - /** - * @brief Return the owned buffer or allocate another one from the `Allocator` - * - * The buffer returned isn't guaranteed to be the exact size of `Size` but it will be at least `Size`. - * The contents of the memory returned isn't guaranteed to be zero initialized or not. - * Not even guaranteed to contain the previous data from the previous reowning if the pointer is the same. - * - * @return object of type `Type` allocated with at least the size of `Size` from the constructor - */ - Type ReownOrClaimBuffer() { - if (!FEXCore::Utils::IntrusivePooledAllocator::IsClientBufferOwned(ClientOwnedFlag)) { - Info = ThreadAllocator.ReownOrClaimBuffer(Info, Size, &ClientOwnedFlag); - } + /** + * @brief Allocates and claims a buffer that is tracked from the thread pool + * + * @param Size + * @param CurrentClientFlag + * + * Once a buffer is claimed, the pool allocator can not reclaim this buffer until it is "Disowned" + * + * @return iterator to the internal tracking container + */ + ContainerType::iterator ClaimBuffer(size_t Size, BufferOwnedFlag* CurrentClientFlag) { + std::unique_lock lk {AllocationMutex}; + auto Buffer = ClaimBufferImpl(Size); + (*Buffer)->CurrentClientOwnedFlag = CurrentClientFlag; + CurrentClientFlag->store(ClientFlags::FLAG_OWNED); + return Buffer; + } - // Putting a memset here is very handy for using thread sanitizer to find buffer usage races - // Leaving this here for future excavation that will definitely occur here - // memset((*Info)->Ptr, 0, Size); + /** + * @brief Immediately release the buffer back to the allocator + * + * @param Buffer - The iterator that was previously given with ClaimBuffer + * + * Once this is called on a buffer then the pool allocator has full ownership of the buffer + */ + void UnclaimBuffer(ContainerType::iterator Buffer) { + std::unique_lock lk {AllocationMutex}; + (*Buffer)->CurrentClientOwnedFlag->store(ClientFlags::FLAG_FREE); + UnclaimBufferImpl(Buffer); + } - return reinterpret_cast((*Info)->Ptr); - } + /** + * @brief Set internal flags of buffer claiming that the buffer is relinquished ownership + * + * @param Buffer - The iterator that was previously given with ClaimBuffer + * + * Once the buffer is disowned, the allocator can take back ownership of the buffer at any time + * + * Use ReownOrClaimBuffer if you want to attempt reusing a buffer being held on to. + */ + void DisownBuffer(ContainerType::iterator Buffer) { + // Client still owns the buffer but isn't using it + // Allows us to claim it back if necessary + (*Buffer)->LastUsed.store(ClockType::now(), std::memory_order_relaxed); + (*Buffer)->CurrentClientOwnedFlag->store(ClientFlags::FLAG_DISOWNED); + } - /** - * @brief Disown or unclaim the buffer, letting the `Allocator` know it can reclaim the buffer - * - * Once the `ReownOrClaimBuffer` function has been used, this must be called to let the `Allocator` know it is safe to reclaim a buffer. - * - * This will first Disown the buffer; which is cheap. - * - * If the frequency of use is below the threshold then immediately `UnclaimBuffer` so that `Allocator` can reuse it. - */ - void DelayedDisownBuffer() { - LOGMAN_THROW_A_FMT(FEXCore::Utils::IntrusivePooledAllocator::IsClientBufferOwned(ClientOwnedFlag), - "Tried to disown buffer when client doesn't own it"); + /** + * @brief Try to reown a buffer that we have previous disowned, failing that, claim a new buffer + * + * @param Buffer - The buffer we previously disowned + * @param Size - The size of the buffer + * @param CurrentClientFlag - The client tracked flag + * + * Once a DisownBuffer has been called, it is unsafe to use the buffer until it has been reowned + * Always Reown a buffer after disowning it before use! + * + * @return Either the original buffer passed in if we managed to reclaim, or a new buffer if we couldn't + */ + ContainerType::iterator ReownOrClaimBuffer(ContainerType::iterator Buffer, size_t Size, BufferOwnedFlag* CurrentClientFlag) { + ClientFlags Expected = ClientFlags::FLAG_DISOWNED; + if (CurrentClientFlag->compare_exchange_strong(Expected, ClientFlags::FLAG_OWNED)) { + // If we managed to change the flag from DISOWNED to OWNED then we have successfully reclaimed + // Finish setting up state + (*Buffer)->LastUsed.store(ClockType::now(), std::memory_order_relaxed); + return Buffer; + } - // Always disown but not always unclaim - // Disowning = cheap, unclaiming = expensive - ThreadAllocator.DisownBuffer(Info); + // Couldn't reclaim, just get a new buffer + return ClaimBuffer(Size, CurrentClientFlag); + } - auto Now = std::chrono::steady_clock::now(); - if ((Now - Previous) >= std::chrono::duration(std::chrono::milliseconds(PeriodMS))) { - if (CountPer < PeriodFrequency) { - // Only unclaim the buffer if our buffer usage isn't excessive in the last period - UnclaimBuffer(); + virtual ~IntrusivePooledAllocator() = default; + + // XXX: Is this a good amount? + /** + * @brief Duration before the allocator will reclaim buffers that the client claimed AND disowned + * + * Pool allocator will not attempt to reclaim client owned buffers, would be unsafe to do so. + */ + constexpr static std::chrono::duration DURATION {std::chrono::seconds(5)}; + +protected: + IntrusivePooledAllocator() = default; + + ContainerType::iterator ClaimBufferImpl(size_t Size) { + auto BuffersEnd = UnclaimedBuffers.end(); + ContainerType::iterator BestFit = BuffersEnd; + ContainerType::iterator UnsizedFit = BuffersEnd; + + auto Now = ClockType::now(); + // Move any expired ClaimedBuffers to UnclaimedBuffers + { + // Spin the non-owned buffers and see if we can take ones past the period + for (auto it = ClaimedBuffers.begin(); it != ClaimedBuffers.end();) { + // 1) Can't take anything that the client has still claimed + // 2) Needs to still be last used beyond our time threshold + // 3) Only take the oldest buffer + if ((*it)->CurrentClientOwnedFlag->load() == ClientFlags::FLAG_DISOWNED) { + auto UsedTime = (*it)->LastUsed.load(std::memory_order_relaxed); + if ((Now - UsedTime) >= DURATION) { + ClientFlags Expected = ClientFlags::FLAG_DISOWNED; + if ((*it)->CurrentClientOwnedFlag->compare_exchange_strong(Expected, ClientFlags::FLAG_FREE)) { + // We managed to take away ownership + // Put it back in the regular pool and come back to it + (*it)->CurrentClientOwnedFlag = nullptr; + UnclaimedBuffers.emplace_back(*it); + it = ClaimedBuffers.erase(it); + continue; + } } - CountPer = 0; - Previous = Now; } - ++CountPer; - } - /** - * @brief Completely unclaim the buffer - * - * Useful if it is known that the buffer won't be used again for a period and can be given back - * to the `Allocator` immediately. - * - * Necessary if an object is going to be freed from memory, so the `Allocator` can't update the `ClientOwnedFlag` - * - * Only use in that edge case! Otherwise use `DelayedDisownBuffer` - */ - void UnclaimBuffer() { - if (!FEXCore::Utils::IntrusivePooledAllocator::IsClientBufferFree(ClientOwnedFlag)) { - ThreadAllocator.UnclaimBuffer(Info); + ++it; + } + } + + // Find an unclaimed buffer that is >= Size and Free up to one unclaimed buffer that has expired + { + // Walk all the allocations and find a buffer that fits + for (auto it = UnclaimedBuffers.begin(); it != BuffersEnd; ++it) { + if ((*it)->Size == Size) { + BestFit = it; + break; + } + + if ((*it)->Size > Size) { + UnsizedFit = it; } } - private: - // Thread allocator - FEXCore::Utils::IntrusivePooledAllocator &ThreadAllocator; + // If we didn't have an exact fit then use an unsized fit + if (BestFit == BuffersEnd) { + BestFit = UnsizedFit; + } - // Buffer size - size_t Size; + // Free up to one unclaimed buffer that has expired + { + std::chrono::time_point LRUTime {}; + ContainerType::iterator LastUsed = BuffersEnd; - // Buffer ownership tracking - FEXCore::Utils::IntrusivePooledAllocator::ContainerType::iterator Info{}; - FEXCore::Utils::IntrusivePooledAllocator::BufferOwnedFlag ClientOwnedFlag { FEXCore::Utils::IntrusivePooledAllocator::ClientFlags::FLAG_FREE }; + // Walk all the allocations and find a buffer to erase + for (auto it = UnclaimedBuffers.begin(); it != UnclaimedBuffers.end(); ++it) { + // Ensure that the LRU value is past our duration threshold and isn't the one we are claiming + // Also only select a single memory region + if (it != BestFit) { + auto UsedTime = (*it)->LastUsed.load(std::memory_order_relaxed); + if ((Now - UsedTime) >= DURATION && UsedTime > LRUTime) { + LastUsed = it; + LRUTime = UsedTime; + } + } + } - // Threshold counting - uint64_t CountPer{}; - std::chrono::steady_clock::time_point Previous; - }; -} + // If we found a buffer then free it + if (LastUsed != BuffersEnd) { + Free((*LastUsed)->Ptr, (*LastUsed)->Size); + delete *LastUsed; + UnclaimedBuffers.erase(LastUsed); + } + } + + if (BestFit != UnclaimedBuffers.end()) { + MemoryBuffer* Buffer = *BestFit; + UnclaimedBuffers.erase(BestFit); + return ClaimedBuffers.emplace(ClaimedBuffers.end(), Buffer); + } + } + + // Need to allocate a new buffer, couldn't fit + auto Data = Alloc(Size); + return ClaimedBuffers.emplace(ClaimedBuffers.end(), new MemoryBuffer {Data, Size, ClockType::now()}); + } + + void UnclaimBufferImpl(ContainerType::iterator Buffer) { + (*Buffer)->CurrentClientOwnedFlag = nullptr; + UnclaimedBuffers.emplace_back(*Buffer); + ClaimedBuffers.erase(Buffer); + } + + void FreeAllBuffers() { + for (auto it : UnclaimedBuffers) { + Free(it->Ptr, it->Size); + delete it; + } + + for (auto it : ClaimedBuffers) { + Free(it->Ptr, it->Size); + delete it; + } + + UnclaimedBuffers.clear(); + ClaimedBuffers.clear(); + } + + /** + * @brief List of buffers that this pool allocator itself owns + */ + ContainerType UnclaimedBuffers; + + /** + * @brief List of buffers that are client claimed + */ + ContainerType ClaimedBuffers; + + /** + * @brief Mutex to ensure thread safety while shuffling buffers around and allocating + */ + std::mutex AllocationMutex; + +private: + /** + * @brief Allocates the buffer + * + * @param Size of the object to allocate + * + * @return pointer + */ + virtual void* Alloc(size_t Size) = 0; + /** + * @brief Frees the buffer + * + * @param Ptr buffer pointer + * @param Size buffer size + */ + virtual void Free(void* Ptr, size_t Size) = 0; +}; + +/** + * @brief Thread pool allocator that allocates and frees objects using malloc + */ +class PooledAllocatorMalloc final : public IntrusivePooledAllocator { +public: + PooledAllocatorMalloc() = default; + + virtual ~PooledAllocatorMalloc() { + FreeAllBuffers(); + } + +private: + void* Alloc(size_t Size) override { + return FEXCore::Allocator::malloc(Size); + } + + void Free(void* Ptr, size_t Size) override { + FEXCore::Allocator::free(Ptr); + } +}; + +/** + * @brief Thread pool allocator that allocates and frees objects that uses mmap + */ +class PooledAllocatorVirtual final : public IntrusivePooledAllocator { +public: + PooledAllocatorVirtual() = default; + + virtual ~PooledAllocatorVirtual() { + FreeAllBuffers(); + } + +private: + void* Alloc(size_t Size) override { + return FEXCore::Allocator::VirtualAlloc(Size); + } + + void Free(void* Ptr, size_t Size) override { + FEXCore::Allocator::VirtualFree(Ptr, Size); + } +}; + +/** + * @brief Wrapper around the pool allocator for delayed pool reclaiming + * + * This is expected to be used in high frequency buffer temporary usage. + * Instead of quickly unclaiming and reclaiming the buffer while the the code is hot, + * This instead will do the cheap operation of disowning the buffer until the code path cools down enough. + * Once the code path stops disowning the codepath more times than `PeriodFrequency` during `PeriodMS` then + * it will immediately unclaim. + * + * Implications: + * - The object will always be claimed for at *least* `PeriodFrequency` + * - The object will still *always* be disowned after each temporary use + * - This allows the pool allocator to reclaim a buffer from a sleeping thread + * + * Performance characteristics: + * - Disowning is cheap. + * - Last-used timestamp update + * - atomic_bool clear to signify it is disowned + * + * - Reowning is relatively cheap (When buffer is still owned). + * - atomic_bool load to check if the object is still owned + * - atomic CAS to change the object to `OWNED` state + * - Resolves a race condition where the `Allocator` can be in the process of reclaiming the buffer from the client + * - Last-used timestamp update + * - atomic_bool set to signify owned + * - atomic set to change object to `OWNED` state + * - When object isn't owned, then allocate a new buffer from the pool + * + * - Unclaiming is fairly costly + * - Requires owning a mutex, shared between all threads using the `Allocator` + * - Updating two fextl::list containers to give the ownership back to the `Allocator` + * + * - Claiming is very costly + * - Requires owning a mutex, shared between all threads using the `Allocator` + * - Scans two fextl::list containers to find the best fit buffer + * - Or allocates another buffer when that fails + * - Frees stale buffers opportunistically + */ +template +class FixedSizePooledAllocation final { + // If the delayed object reclaimer is more than the thread pool allocator's duration then the pool allocator would always need to reclaim + // the buffer rather than giving it back. + static_assert(std::chrono::duration(std::chrono::milliseconds(PeriodMS)) <= IntrusivePooledAllocator::DURATION, "DeplayedObjectReclaimer " + "period needs to be " + "lower or equal to the " + "pool allocator " + "duration"); + +public: + FixedSizePooledAllocation(IntrusivePooledAllocator& Allocator, size_t Size) + : ThreadAllocator {Allocator} + , Size {Size} {} + + /** + * @brief Return the owned buffer or allocate another one from the `Allocator` + * + * The buffer returned isn't guaranteed to be the exact size of `Size` but it will be at least `Size`. + * The contents of the memory returned isn't guaranteed to be zero initialized or not. + * Not even guaranteed to contain the previous data from the previous reowning if the pointer is the same. + * + * @return object of type `Type` allocated with at least the size of `Size` from the constructor + */ + Type ReownOrClaimBuffer() { + if (!FEXCore::Utils::IntrusivePooledAllocator::IsClientBufferOwned(ClientOwnedFlag)) { + Info = ThreadAllocator.ReownOrClaimBuffer(Info, Size, &ClientOwnedFlag); + } + + // Putting a memset here is very handy for using thread sanitizer to find buffer usage races + // Leaving this here for future excavation that will definitely occur here + // memset((*Info)->Ptr, 0, Size); + + return reinterpret_cast((*Info)->Ptr); + } + + /** + * @brief Disown or unclaim the buffer, letting the `Allocator` know it can reclaim the buffer + * + * Once the `ReownOrClaimBuffer` function has been used, this must be called to let the `Allocator` know it is safe to reclaim a buffer. + * + * This will first Disown the buffer; which is cheap. + * + * If the frequency of use is below the threshold then immediately `UnclaimBuffer` so that `Allocator` can reuse it. + */ + void DelayedDisownBuffer() { + LOGMAN_THROW_A_FMT(FEXCore::Utils::IntrusivePooledAllocator::IsClientBufferOwned(ClientOwnedFlag), "Tried to disown buffer when client " + "doesn't own it"); + + // Always disown but not always unclaim + // Disowning = cheap, unclaiming = expensive + ThreadAllocator.DisownBuffer(Info); + + auto Now = std::chrono::steady_clock::now(); + if ((Now - Previous) >= std::chrono::duration(std::chrono::milliseconds(PeriodMS))) { + if (CountPer < PeriodFrequency) { + // Only unclaim the buffer if our buffer usage isn't excessive in the last period + UnclaimBuffer(); + } + CountPer = 0; + Previous = Now; + } + ++CountPer; + } + + /** + * @brief Completely unclaim the buffer + * + * Useful if it is known that the buffer won't be used again for a period and can be given back + * to the `Allocator` immediately. + * + * Necessary if an object is going to be freed from memory, so the `Allocator` can't update the `ClientOwnedFlag` + * + * Only use in that edge case! Otherwise use `DelayedDisownBuffer` + */ + void UnclaimBuffer() { + if (!FEXCore::Utils::IntrusivePooledAllocator::IsClientBufferFree(ClientOwnedFlag)) { + ThreadAllocator.UnclaimBuffer(Info); + } + } + +private: + // Thread allocator + FEXCore::Utils::IntrusivePooledAllocator& ThreadAllocator; + + // Buffer size + size_t Size; + + // Buffer ownership tracking + FEXCore::Utils::IntrusivePooledAllocator::ContainerType::iterator Info {}; + FEXCore::Utils::IntrusivePooledAllocator::BufferOwnedFlag ClientOwnedFlag {FEXCore::Utils::IntrusivePooledAllocator::ClientFlags::FLAG_FREE}; + + // Threshold counting + uint64_t CountPer {}; + std::chrono::steady_clock::time_point Previous; +}; +} // namespace FEXCore::Utils diff --git a/FEXCore/include/FEXCore/Utils/Threads.h b/FEXCore/include/FEXCore/Utils/Threads.h index 514c0ce63..8f153a7cf 100644 --- a/FEXCore/include/FEXCore/Utils/Threads.h +++ b/FEXCore/include/FEXCore/Utils/Threads.h @@ -5,50 +5,48 @@ #include namespace FEXCore::Threads { - using ThreadFunc = void*(*)(void* user_ptr); +using ThreadFunc = void* (*)(void* user_ptr); - class Thread; - using CreateThreadFunc = std::function(ThreadFunc Func, void* Arg)>; - using CleanupAfterForkFunc = std::function; +class Thread; +using CreateThreadFunc = std::function(ThreadFunc Func, void* Arg)>; +using CleanupAfterForkFunc = std::function; - struct Pointers { - CreateThreadFunc CreateThread; - CleanupAfterForkFunc CleanupAfterFork; - }; +struct Pointers { + CreateThreadFunc CreateThread; + CleanupAfterForkFunc CleanupAfterFork; +}; - // API - class Thread { - public: - virtual ~Thread() = default; - virtual bool joinable() = 0; - virtual bool join(void **ret) = 0; - virtual bool detach() = 0; - virtual bool IsSelf() = 0; - - /** - * @name Calls provided API functions - * @{ */ - - static fextl::unique_ptr Create( - ThreadFunc Func, - void* Arg); - - static void CleanupAfterFork(); - - /** @} */ - - // Set API functions - static void SetInternalPointers(Pointers const &_Ptrs); - }; +// API +class Thread { +public: + virtual ~Thread() = default; + virtual bool joinable() = 0; + virtual bool join(void** ret) = 0; + virtual bool detach() = 0; + virtual bool IsSelf() = 0; /** - * @brief Sets the calling thread's signal mask to the one provided - * - * @param Mask The new 64-bit signal mask to set - * - * @return The previous signal mask - */ - uint64_t SetSignalMask(uint64_t Mask); + * @name Calls provided API functions + * @{ */ - void SetThreadName(const char *name); -} + static fextl::unique_ptr Create(ThreadFunc Func, void* Arg); + + static void CleanupAfterFork(); + + /** @} */ + + // Set API functions + static void SetInternalPointers(const Pointers& _Ptrs); +}; + +/** + * @brief Sets the calling thread's signal mask to the one provided + * + * @param Mask The new 64-bit signal mask to set + * + * @return The previous signal mask + */ +uint64_t SetSignalMask(uint64_t Mask); + +void SetThreadName(const char* name); +} // namespace FEXCore::Threads diff --git a/FEXCore/include/FEXCore/Utils/TypeDefines.h b/FEXCore/include/FEXCore/Utils/TypeDefines.h index 43b6049eb..ec03ac6cd 100644 --- a/FEXCore/include/FEXCore/Utils/TypeDefines.h +++ b/FEXCore/include/FEXCore/Utils/TypeDefines.h @@ -3,10 +3,10 @@ #include namespace FEXCore::Utils { - // FEX assumes an operating page size of 4096 - // To work around build systems that build on a 16k/64k page size, define our page size here - // Don't use the system provided PAGE_SIZE define because of this. - constexpr size_t FEX_PAGE_SIZE = 4096; - constexpr size_t FEX_PAGE_SHIFT = 12; - constexpr size_t FEX_PAGE_MASK = ~(FEX_PAGE_SIZE - 1); -} +// FEX assumes an operating page size of 4096 +// To work around build systems that build on a 16k/64k page size, define our page size here +// Don't use the system provided PAGE_SIZE define because of this. +constexpr size_t FEX_PAGE_SIZE = 4096; +constexpr size_t FEX_PAGE_SHIFT = 12; +constexpr size_t FEX_PAGE_MASK = ~(FEX_PAGE_SIZE - 1); +} // namespace FEXCore::Utils diff --git a/FEXCore/include/FEXCore/Utils/refcount_shared_mutex.h b/FEXCore/include/FEXCore/Utils/refcount_shared_mutex.h index 668ea0f05..dd702733f 100644 --- a/FEXCore/include/FEXCore/Utils/refcount_shared_mutex.h +++ b/FEXCore/include/FEXCore/Utils/refcount_shared_mutex.h @@ -9,258 +9,240 @@ #include namespace FEXCore::Utils { - /** - * @brief This class is similar to std::shared_mutex but is safe to shared lock multiple times from the same thread. - * - * Just like std::shared_mutex, this has shared lock priority when a shared lock is already held. - */ - class refcount_shared_mutex final { - public: - void lock() { - auto UniqueResult = TryUniqueLock(); - if (UniqueResult.second) { - // Managed to get the unique lock - return; - } +/** + * @brief This class is similar to std::shared_mutex but is safe to shared lock multiple times from the same thread. + * + * Just like std::shared_mutex, this has shared lock priority when a shared lock is already held. + */ +class refcount_shared_mutex final { +public: + void lock() { + auto UniqueResult = TryUniqueLock(); + if (UniqueResult.second) { + // Managed to get the unique lock + return; + } - int Op = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; + int Op = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; - do { - ::syscall(SYS_futex, - &Futex, - Op, - UniqueResult.first, // Value - nullptr, // Timeout - nullptr, // Addr - 0); + do { + ::syscall(SYS_futex, &Futex, Op, + UniqueResult.first, // Value + nullptr, // Timeout + nullptr, // Addr + 0); - UniqueResult = TryUniqueLock(); - // If Res == 0 then check the unique lock to see if unique is no longer owned - if (UniqueResult.second) { - // Unique lock succeeded - return; - } - } while (true); + UniqueResult = TryUniqueLock(); + // If Res == 0 then check the unique lock to see if unique is no longer owned + if (UniqueResult.second) { + // Unique lock succeeded + return; } + } while (true); + } - bool try_lock() { - auto UniqueResult = TryUniqueLock(); - return UniqueResult.second; - } + bool try_lock() { + auto UniqueResult = TryUniqueLock(); + return UniqueResult.second; + } - void unlock() { - LOGMAN_THROW_A_FMT(Futex.load() == UNIQUE_LOCK_VALUE, "Tried unlocking not locked mutex?"); + void unlock() { + LOGMAN_THROW_A_FMT(Futex.load() == UNIQUE_LOCK_VALUE, "Tried unlocking not locked mutex?"); - auto TryUniqueUnlock = [this]() -> std::pair { - auto LocalFutex = Futex.load(); + auto TryUniqueUnlock = [this]() -> std::pair { + auto LocalFutex = Futex.load(); - if (LocalFutex != UNIQUE_LOCK_VALUE) { - // Refcount must be zero if we are to attempt getting a unique lock - } - else { - // Try locking now in userspace - while (LocalFutex == UNIQUE_LOCK_VALUE) { - auto Desired = LocalFutex; - Desired = 0; - if (Futex.compare_exchange_strong(LocalFutex, Desired)) { - // We have successfully unique locked - return std::make_pair(Desired, true); - } - else { - if (LocalFutex == UNIQUE_LOCK_VALUE) { - // If another thread pulled the unique lock or the ref count incremented - // Then we need to wait, loop will end - } - } + if (LocalFutex != UNIQUE_LOCK_VALUE) { + // Refcount must be zero if we are to attempt getting a unique lock + } else { + // Try locking now in userspace + while (LocalFutex == UNIQUE_LOCK_VALUE) { + auto Desired = LocalFutex; + Desired = 0; + if (Futex.compare_exchange_strong(LocalFutex, Desired)) { + // We have successfully unique locked + return std::make_pair(Desired, true); + } else { + if (LocalFutex == UNIQUE_LOCK_VALUE) { + // If another thread pulled the unique lock or the ref count incremented + // Then we need to wait, loop will end } } - - return std::make_pair(LocalFutex, false); - }; - - [[maybe_unused]] auto UniqueResult = TryUniqueUnlock(); - LOGMAN_THROW_A_FMT(UniqueResult.second, "Couldn't unlock mutex memory?"); - - // We've now unlocked, use the futex to wake up any shared waiters - int Op = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; - ::syscall(SYS_futex, - &Futex, - Op, - INT_MAX, // Could be any number of shared waiters - nullptr, // timeout - nullptr, // addr - 0); - } - - bool try_lock_shared() { - return TryRefIncrement(); - } - - void lock_shared() { - if (TryRefIncrement()) { - return; } - - // Unique lock was held. Wait until it is no longer held using a system futex - int Op = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; - - auto Expected = UNIQUE_LOCK_VALUE; - do { - ::syscall(SYS_futex, - &Futex, - Op, - Expected, // Value - nullptr, // Timeout, - nullptr, // Addr - 0); - - Expected = Futex.load(); - // If Res == 0 then check the unique lock to see if unique is no longer owned - if (Expected != UNIQUE_LOCK_VALUE) { - if (TryRefIncrement()) { - // Ref count succeeded - return; - } - } - } while (true); } - // Returns the number of ref counts remaining once this leaves - uint32_t unlock_shared() { - auto DecrementResult = TryRefDecrement(); + return std::make_pair(LocalFutex, false); + }; - if (DecrementResult.second) { - if (DecrementResult.first == 0) { - // If we were the last shared value out then we need to do a futex to wake up any waiters - int Op = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; - ::syscall(SYS_futex, - &Futex, - Op, - 1, // Wake up only one thread if one is waiting. Which would be the unique waiter + [[maybe_unused]] auto UniqueResult = TryUniqueUnlock(); + LOGMAN_THROW_A_FMT(UniqueResult.second, "Couldn't unlock mutex memory?"); + + // We've now unlocked, use the futex to wake up any shared waiters + int Op = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; + ::syscall(SYS_futex, &Futex, Op, + INT_MAX, // Could be any number of shared waiters nullptr, // timeout nullptr, // addr 0); - } - return DecrementResult.first; + } + + bool try_lock_shared() { + return TryRefIncrement(); + } + + void lock_shared() { + if (TryRefIncrement()) { + return; + } + + // Unique lock was held. Wait until it is no longer held using a system futex + int Op = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; + + auto Expected = UNIQUE_LOCK_VALUE; + do { + ::syscall(SYS_futex, &Futex, Op, + Expected, // Value + nullptr, // Timeout, + nullptr, // Addr + 0); + + Expected = Futex.load(); + // If Res == 0 then check the unique lock to see if unique is no longer owned + if (Expected != UNIQUE_LOCK_VALUE) { + if (TryRefIncrement()) { + // Ref count succeeded + return; } - - LOGMAN_MSG_A_FMT("Managed to squeeze a unique lock between shared locks?"); - return 0; // Error } + } while (true); + } - // Get the raw futex ref count number - uint32_t GetNumRefCounts() const { - return Futex.load(); - } - - // Be careful with this. Only use when you know the mutex is dead - void Reset() { - Futex.store(0); + // Returns the number of ref counts remaining once this leaves + uint32_t unlock_shared() { + auto DecrementResult = TryRefDecrement(); + if (DecrementResult.second) { + if (DecrementResult.first == 0) { + // If we were the last shared value out then we need to do a futex to wake up any waiters int Op = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; - ::syscall(SYS_futex, - &Futex, - Op, - INT_MAX, // Wake up all threads if any waiting - nullptr, // timeout - nullptr, // addr - 0); + ::syscall(SYS_futex, &Futex, Op, + 1, // Wake up only one thread if one is waiting. Which would be the unique waiter + nullptr, // timeout + nullptr, // addr + 0); } + return DecrementResult.first; + } - private: - bool TryRefIncrement() { - auto LocalFutex = Futex.load(); + LOGMAN_MSG_A_FMT("Managed to squeeze a unique lock between shared locks?"); + return 0; // Error + } - if (LocalFutex == UNIQUE_LOCK_VALUE) { - // Unique lock held - } - else { - // Try to increment the counter if unique lock isn't held - while (LocalFutex != UNIQUE_LOCK_VALUE) { - auto Desired = LocalFutex; - Desired++; + // Get the raw futex ref count number + uint32_t GetNumRefCounts() const { + return Futex.load(); + } - // Try to increment the ref count - if (Futex.compare_exchange_strong(LocalFutex, Desired)) { - // We have successfully incremented the ref counting mutex in userspace - return true; - } - else { - if (LocalFutex == UNIQUE_LOCK_VALUE) { - // Unique lock was held - // Nothing to do, loop will end - } + // Be careful with this. Only use when you know the mutex is dead + void Reset() { + Futex.store(0); - // Try again. Can happen in a race to increment the ref count - } + int Op = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; + ::syscall(SYS_futex, &Futex, Op, + INT_MAX, // Wake up all threads if any waiting + nullptr, // timeout + nullptr, // addr + 0); + } + +private: + bool TryRefIncrement() { + auto LocalFutex = Futex.load(); + + if (LocalFutex == UNIQUE_LOCK_VALUE) { + // Unique lock held + } else { + // Try to increment the counter if unique lock isn't held + while (LocalFutex != UNIQUE_LOCK_VALUE) { + auto Desired = LocalFutex; + Desired++; + + // Try to increment the ref count + if (Futex.compare_exchange_strong(LocalFutex, Desired)) { + // We have successfully incremented the ref counting mutex in userspace + return true; + } else { + if (LocalFutex == UNIQUE_LOCK_VALUE) { + // Unique lock was held + // Nothing to do, loop will end } + + // Try again. Can happen in a race to increment the ref count } + } + } - return false; - }; - - std::pair TryRefDecrement() { - auto LocalFutex = Futex.load(); - - if (LocalFutex == UNIQUE_LOCK_VALUE) { - // Unique lock held - } - else { - // Try to increment the counter if unique lock isn't held - while (LocalFutex != UNIQUE_LOCK_VALUE) { - auto Desired = LocalFutex; - Desired--; - - // Try to increment the ref count - if (Futex.compare_exchange_strong(LocalFutex, Desired)) { - // We have successfully incremented the ref counting mutex in userspace - return std::make_pair(Desired, true); - } - else { - if (LocalFutex == UNIQUE_LOCK_VALUE) { - // Unique lock was held - // Nothing to do, loop will end - } - - // Try again. Can happen in a race to increment the ref count - } - } - } - - return std::make_pair(LocalFutex, false); - }; - - std::pair TryUniqueLock() { - auto LocalFutex = Futex.load(); - - if (LocalFutex) { - // Refcount must be zero if we are to attempt getting a unique lock - } - else { - // Try locking now in userspace - while (LocalFutex == 0) { - auto Desired = LocalFutex; - Desired = UNIQUE_LOCK_VALUE; - if (Futex.compare_exchange_strong(LocalFutex, Desired)) { - // We have successfully unique locked - return std::make_pair(Desired, true); - } - else { - if (LocalFutex == 0) { - // If another thread pulled the unique lock or the ref count incremented - // Then we need to wait, loop will end - } - } - } - } - - return std::make_pair(LocalFutex, false); - }; - - constexpr static uint32_t UNIQUE_LOCK_VALUE = -4096U; - // -1 = unique_lock - // 0 = no shared - // >0 = shared waiters - std::atomic Futex{}; + return false; }; -} + + std::pair TryRefDecrement() { + auto LocalFutex = Futex.load(); + + if (LocalFutex == UNIQUE_LOCK_VALUE) { + // Unique lock held + } else { + // Try to increment the counter if unique lock isn't held + while (LocalFutex != UNIQUE_LOCK_VALUE) { + auto Desired = LocalFutex; + Desired--; + + // Try to increment the ref count + if (Futex.compare_exchange_strong(LocalFutex, Desired)) { + // We have successfully incremented the ref counting mutex in userspace + return std::make_pair(Desired, true); + } else { + if (LocalFutex == UNIQUE_LOCK_VALUE) { + // Unique lock was held + // Nothing to do, loop will end + } + + // Try again. Can happen in a race to increment the ref count + } + } + } + + return std::make_pair(LocalFutex, false); + }; + + std::pair TryUniqueLock() { + auto LocalFutex = Futex.load(); + + if (LocalFutex) { + // Refcount must be zero if we are to attempt getting a unique lock + } else { + // Try locking now in userspace + while (LocalFutex == 0) { + auto Desired = LocalFutex; + Desired = UNIQUE_LOCK_VALUE; + if (Futex.compare_exchange_strong(LocalFutex, Desired)) { + // We have successfully unique locked + return std::make_pair(Desired, true); + } else { + if (LocalFutex == 0) { + // If another thread pulled the unique lock or the ref count incremented + // Then we need to wait, loop will end + } + } + } + } + + return std::make_pair(LocalFutex, false); + }; + + constexpr static uint32_t UNIQUE_LOCK_VALUE = -4096U; + // -1 = unique_lock + // 0 = no shared + // >0 = shared waiters + std::atomic Futex {}; +}; +} // namespace FEXCore::Utils diff --git a/FEXCore/include/FEXCore/fextl/allocator.h b/FEXCore/include/FEXCore/fextl/allocator.h index 38f0d2466..d6423e750 100644 --- a/FEXCore/include/FEXCore/fextl/allocator.h +++ b/FEXCore/include/FEXCore/fextl/allocator.h @@ -5,26 +5,29 @@ #include namespace fextl { - /** - * @brief C++ allocator class interface in to FEXCore::Allocator for memory allocations. - */ - template - class FEXAlloc : public std::allocator { - public: - using value_type = T; - using propagate_on_container_move_assignment = std::true_type; +/** + * @brief C++ allocator class interface in to FEXCore::Allocator for memory allocations. + */ +template +class FEXAlloc : public std::allocator { +public: + using value_type = T; + using propagate_on_container_move_assignment = std::true_type; - FEXAlloc() noexcept {} - template FEXAlloc(FEXAlloc const&) noexcept {} + FEXAlloc() noexcept {} + template + FEXAlloc(const FEXAlloc&) noexcept {} - inline value_type *allocate(std::size_t n) { - return reinterpret_cast(::FEXCore::Allocator::aligned_alloc(std::alignment_of_v, n * sizeof(value_type))); - } + inline value_type* allocate(std::size_t n) { + return reinterpret_cast(::FEXCore::Allocator::aligned_alloc(std::alignment_of_v, n * sizeof(value_type))); + } - inline void deallocate(value_type* p, size_t) noexcept { - ::FEXCore::Allocator::aligned_free(p); - } + inline void deallocate(value_type* p, size_t) noexcept { + ::FEXCore::Allocator::aligned_free(p); + } - inline bool operator==(const FEXAlloc&) const { return true; } - }; -} + inline bool operator==(const FEXAlloc&) const { + return true; + } +}; +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/deque.h b/FEXCore/include/FEXCore/fextl/deque.h index db21c72f3..4553f8eff 100644 --- a/FEXCore/include/FEXCore/fextl/deque.h +++ b/FEXCore/include/FEXCore/fextl/deque.h @@ -5,6 +5,6 @@ #include namespace fextl { - template> - using deque = std::deque; +template> +using deque = std::deque; } diff --git a/FEXCore/include/FEXCore/fextl/fmt.h b/FEXCore/include/FEXCore/fextl/fmt.h index 64caf0a65..48e0d3712 100644 --- a/FEXCore/include/FEXCore/fextl/fmt.h +++ b/FEXCore/include/FEXCore/fextl/fmt.h @@ -8,79 +8,70 @@ #include namespace fextl::fmt { - template > - using basic_memory_buffer = ::fmt::basic_memory_buffer; - using memory_buffer = fextl::fmt::basic_memory_buffer; +template> +using basic_memory_buffer = ::fmt::basic_memory_buffer; +using memory_buffer = fextl::fmt::basic_memory_buffer; - template - OutputIt format_to(OutputIt out, ::fmt::format_string fmt, Args&&... args) { - return ::fmt::vformat_to(out, fmt.str, ::fmt::make_format_args(args...)); - } +template +OutputIt format_to(OutputIt out, ::fmt::format_string fmt, Args&&... args) { + return ::fmt::vformat_to(out, fmt.str, ::fmt::make_format_args(args...)); +} - template - FMT_NODISCARD auto to_string(const fextl::fmt::basic_memory_buffer& buf) - -> fextl::basic_string { - auto size = buf.size(); - ::fmt::detail::assume(size < std::basic_string().max_size()); - return fextl::basic_string(buf.data(), size); - } +template +FMT_NODISCARD auto to_string(const fextl::fmt::basic_memory_buffer& buf) -> fextl::basic_string { + auto size = buf.size(); + ::fmt::detail::assume(size < std::basic_string().max_size()); + return fextl::basic_string(buf.data(), size); +} - FMT_FUNC FMT_INLINE fextl::string vformat(::fmt::string_view fmt, ::fmt::format_args args) { - // Don't optimize the "{}" case to keep the binary size small and because it - // can be better optimized in fmt::format anyway. - auto buffer = memory_buffer(); - ::fmt::detail::vformat_to(buffer, fmt, args); - return fextl::fmt::to_string(buffer); - } +FMT_FUNC FMT_INLINE fextl::string vformat(::fmt::string_view fmt, ::fmt::format_args args) { + // Don't optimize the "{}" case to keep the binary size small and because it + // can be better optimized in fmt::format anyway. + auto buffer = memory_buffer(); + ::fmt::detail::vformat_to(buffer, fmt, args); + return fextl::fmt::to_string(buffer); +} - template - FMT_NODISCARD FMT_INLINE auto format(::fmt::format_string fmt, T&&... args) - -> fextl::string { - return fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - } +template +FMT_NODISCARD FMT_INLINE auto format(::fmt::format_string fmt, T&&... args) -> fextl::string { + return fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); +} #ifndef _WIN32 - template - FMT_INLINE auto print(::fmt::format_string fmt, T&&... args) - -> void { - auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - write(STDOUT_FILENO, String.c_str(), String.size()); - } - - template - FMT_INLINE auto print(int FD, ::fmt::format_string fmt, T&&... args) - -> void { - auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - write(FD, String.c_str(), String.size()); - } -#else - template - FMT_INLINE auto print(::fmt::format_string fmt, T&&... args) - -> void { - auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - auto f = FEXCore::File::File::GetStdOUT(); - f.Write(String.c_str(), String.size()); - } - - template - FMT_INLINE auto print(HANDLE File, ::fmt::format_string fmt, T&&... args) - -> void { - auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - WriteFile(File, String.c_str(), String.size(), nullptr, nullptr); - } -#endif - template - FMT_INLINE auto print(FEXCore::File::File& f, ::fmt::format_string fmt, T&&... args) - -> void { - auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - f.Write(String.c_str(), String.size()); - } - - template - FMT_INLINE auto print(std::FILE* f, ::fmt::format_string fmt, T&&... args) - -> void { - auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - write(fileno(f), String.c_str(), String.size()); - } +template +FMT_INLINE auto print(::fmt::format_string fmt, T&&... args) -> void { + auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); + write(STDOUT_FILENO, String.c_str(), String.size()); } + +template +FMT_INLINE auto print(int FD, ::fmt::format_string fmt, T&&... args) -> void { + auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); + write(FD, String.c_str(), String.size()); +} +#else +template +FMT_INLINE auto print(::fmt::format_string fmt, T&&... args) -> void { + auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); + auto f = FEXCore::File::File::GetStdOUT(); + f.Write(String.c_str(), String.size()); +} + +template +FMT_INLINE auto print(HANDLE File, ::fmt::format_string fmt, T&&... args) -> void { + auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); + WriteFile(File, String.c_str(), String.size(), nullptr, nullptr); +} +#endif +template +FMT_INLINE auto print(FEXCore::File::File& f, ::fmt::format_string fmt, T&&... args) -> void { + auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); + f.Write(String.c_str(), String.size()); +} + +template +FMT_INLINE auto print(std::FILE* f, ::fmt::format_string fmt, T&&... args) -> void { + auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); + write(fileno(f), String.c_str(), String.size()); +} +} // namespace fextl::fmt diff --git a/FEXCore/include/FEXCore/fextl/forward_list.h b/FEXCore/include/FEXCore/fextl/forward_list.h index 210212a28..eb3a09ea1 100644 --- a/FEXCore/include/FEXCore/fextl/forward_list.h +++ b/FEXCore/include/FEXCore/fextl/forward_list.h @@ -5,6 +5,6 @@ #include namespace fextl { - template> - using forward_list = std::forward_list; +template> +using forward_list = std::forward_list; } diff --git a/FEXCore/include/FEXCore/fextl/list.h b/FEXCore/include/FEXCore/fextl/list.h index 798d5a687..613981d61 100644 --- a/FEXCore/include/FEXCore/fextl/list.h +++ b/FEXCore/include/FEXCore/fextl/list.h @@ -5,6 +5,6 @@ #include namespace fextl { - template> - using list = std::list; +template> +using list = std::list; } diff --git a/FEXCore/include/FEXCore/fextl/map.h b/FEXCore/include/FEXCore/fextl/map.h index 4a23ab24b..abb37d898 100644 --- a/FEXCore/include/FEXCore/fextl/map.h +++ b/FEXCore/include/FEXCore/fextl/map.h @@ -5,9 +5,9 @@ #include namespace fextl { - template, class Allocator = fextl::FEXAlloc>> - using map = std::map; +template, class Allocator = fextl::FEXAlloc>> +using map = std::map; - template, class Allocator = fextl::FEXAlloc>> - using multimap = std::multimap; -} +template, class Allocator = fextl::FEXAlloc>> +using multimap = std::multimap; +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/memory.h b/FEXCore/include/FEXCore/fextl/memory.h index d40a1fa04..f4d860a30 100644 --- a/FEXCore/include/FEXCore/fextl/memory.h +++ b/FEXCore/include/FEXCore/fextl/memory.h @@ -6,29 +6,28 @@ #include namespace fextl { - template - struct default_delete : public std::default_delete { - void operator()(T* ptr) const { - std::destroy_at(ptr); - FEXCore::Allocator::aligned_free(ptr); - } - - template - requires (std::is_base_of_v) - operator fextl::default_delete() { - return fextl::default_delete(); - } - }; - - template> - using unique_ptr = std::unique_ptr; - - template - requires (!std::is_array_v) - fextl::unique_ptr make_unique(Args&&... args) { - auto ptr = FEXCore::Allocator::aligned_alloc(std::alignment_of_v, sizeof(T)); - auto Result = ::new (ptr) T (std::forward(args)...); - return fextl::unique_ptr(Result); +template +struct default_delete : public std::default_delete { + void operator()(T* ptr) const { + std::destroy_at(ptr); + FEXCore::Allocator::aligned_free(ptr); } -} + template + requires (std::is_base_of_v) + operator fextl::default_delete() { + return fextl::default_delete(); + } +}; + +template> +using unique_ptr = std::unique_ptr; + +template +requires (!std::is_array_v) +fextl::unique_ptr make_unique(Args&&... args) { + auto ptr = FEXCore::Allocator::aligned_alloc(std::alignment_of_v, sizeof(T)); + auto Result = ::new (ptr) T(std::forward(args)...); + return fextl::unique_ptr(Result); +} +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/memory_resource.h b/FEXCore/include/FEXCore/fextl/memory_resource.h index 35e8e8f1c..4b1025eba 100644 --- a/FEXCore/include/FEXCore/fextl/memory_resource.h +++ b/FEXCore/include/FEXCore/fextl/memory_resource.h @@ -8,71 +8,70 @@ #include namespace fextl { - namespace pmr { - class default_resource : public std::pmr::memory_resource { - private: - void* do_allocate( std::size_t bytes, std::size_t alignment ) override { - return FEXCore::Allocator::memalign(alignment, bytes); - } +namespace pmr { + class default_resource : public std::pmr::memory_resource { + private: + void* do_allocate(std::size_t bytes, std::size_t alignment) override { + return FEXCore::Allocator::memalign(alignment, bytes); + } - void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override { - return FEXCore::Allocator::aligned_free(p); - } + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override { + return FEXCore::Allocator::aligned_free(p); + } - bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override { - return this == &other; - } - }; + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { + return this == &other; + } + }; - FEX_DEFAULT_VISIBILITY std::pmr::memory_resource* get_default_resource(); + FEX_DEFAULT_VISIBILITY std::pmr::memory_resource* get_default_resource(); - /** - * @brief This is similar to the std::pmr::monotonic_buffer_resource. - * - * The difference is that class doesn't have ownership of the backing memory and - * it also doesn't have any growth factor. - * - * If the amount of memory allocated is overrun then this will overwrite memory unless assertions are enabled. - * - * Ensure that you know how much memory you're going to use before using this class. - */ - class fixed_size_monotonic_buffer_resource final : public std::pmr::memory_resource { - public: - fixed_size_monotonic_buffer_resource(void* Base, [[maybe_unused]] size_t Size) - : Ptr {reinterpret_cast(Base)} + /** + * @brief This is similar to the std::pmr::monotonic_buffer_resource. + * + * The difference is that class doesn't have ownership of the backing memory and + * it also doesn't have any growth factor. + * + * If the amount of memory allocated is overrun then this will overwrite memory unless assertions are enabled. + * + * Ensure that you know how much memory you're going to use before using this class. + */ + class fixed_size_monotonic_buffer_resource final : public std::pmr::memory_resource { + public: + fixed_size_monotonic_buffer_resource(void* Base, [[maybe_unused]] size_t Size) + : Ptr {reinterpret_cast(Base)} #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - , PtrEnd {reinterpret_cast(Base) + Size} - , Size {Size} + , PtrEnd {reinterpret_cast(Base) + Size} + , Size {Size} #endif - {} - void* do_allocate( std::size_t bytes, std::size_t alignment ) override { - uint64_t NewPtr = FEXCore::AlignUp((uint64_t)Ptr, alignment); - Ptr = NewPtr + bytes; + { + } + void* do_allocate(std::size_t bytes, std::size_t alignment) override { + uint64_t NewPtr = FEXCore::AlignUp((uint64_t)Ptr, alignment); + Ptr = NewPtr + bytes; #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - if (Ptr >= PtrEnd) { - LogMan::Msg::AFmt("Fail: Only allocated: {} ({} this time) bytes. Tried allocating at ptr offset: {}.\n", - Size, - bytes, - (uint64_t)(Ptr - (PtrEnd - Size))); - FEX_TRAP_EXECUTION; - } + if (Ptr >= PtrEnd) { + LogMan::Msg::AFmt("Fail: Only allocated: {} ({} this time) bytes. Tried allocating at ptr offset: {}.\n", Size, bytes, + (uint64_t)(Ptr - (PtrEnd - Size))); + FEX_TRAP_EXECUTION; + } #endif - return reinterpret_cast(NewPtr); - } + return reinterpret_cast(NewPtr); + } - void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override { - // noop - } + void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override { + // noop + } - bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override { - return this == &other; - } - private: - uint64_t Ptr; + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { + return this == &other; + } + private: + uint64_t Ptr; #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - uint64_t PtrEnd; - size_t Size; + uint64_t PtrEnd; + size_t Size; #endif - }; - } -} + }; +} // namespace pmr +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/queue.h b/FEXCore/include/FEXCore/fextl/queue.h index 5ea30e5a0..d215bd786 100644 --- a/FEXCore/include/FEXCore/fextl/queue.h +++ b/FEXCore/include/FEXCore/fextl/queue.h @@ -6,6 +6,6 @@ #include namespace fextl { - template> - using queue = std::queue; +template> +using queue = std::queue; } diff --git a/FEXCore/include/FEXCore/fextl/robin_map.h b/FEXCore/include/FEXCore/fextl/robin_map.h index ad0d2dd72..a82bd3bf2 100644 --- a/FEXCore/include/FEXCore/fextl/robin_map.h +++ b/FEXCore/include/FEXCore/fextl/robin_map.h @@ -5,6 +5,6 @@ #include namespace fextl { - template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> - using robin_map = tsl::robin_map; +template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> +using robin_map = tsl::robin_map; } diff --git a/FEXCore/include/FEXCore/fextl/set.h b/FEXCore/include/FEXCore/fextl/set.h index 7c45780cf..938b40384 100644 --- a/FEXCore/include/FEXCore/fextl/set.h +++ b/FEXCore/include/FEXCore/fextl/set.h @@ -5,9 +5,9 @@ #include namespace fextl { - template, class Allocator = fextl::FEXAlloc> - using set = std::set; +template, class Allocator = fextl::FEXAlloc> +using set = std::set; - template, class Allocator = fextl::FEXAlloc> - using multiset = std::multiset; -} +template, class Allocator = fextl::FEXAlloc> +using multiset = std::multiset; +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/sstream.h b/FEXCore/include/FEXCore/fextl/sstream.h index 48026e119..1fa90a6c5 100644 --- a/FEXCore/include/FEXCore/fextl/sstream.h +++ b/FEXCore/include/FEXCore/fextl/sstream.h @@ -5,20 +5,20 @@ #include namespace fextl { - template, class Allocator = fextl::FEXAlloc> - using basic_stringbuf = std::basic_stringbuf; +template, class Allocator = fextl::FEXAlloc> +using basic_stringbuf = std::basic_stringbuf; - template, class Allocator = fextl::FEXAlloc> - using basic_istringstream = std::basic_istringstream; +template, class Allocator = fextl::FEXAlloc> +using basic_istringstream = std::basic_istringstream; - template, class Allocator = fextl::FEXAlloc> - using basic_ostringstream = std::basic_ostringstream; +template, class Allocator = fextl::FEXAlloc> +using basic_ostringstream = std::basic_ostringstream; - template, class Allocator = fextl::FEXAlloc> - using basic_stringstream = std::basic_stringstream; +template, class Allocator = fextl::FEXAlloc> +using basic_stringstream = std::basic_stringstream; - using stringbuf = fextl::basic_stringbuf; - using istringstream = fextl::basic_istringstream; - using ostringstream = fextl::basic_ostringstream; - using stringstream = fextl::basic_stringstream; -} +using stringbuf = fextl::basic_stringbuf; +using istringstream = fextl::basic_istringstream; +using ostringstream = fextl::basic_ostringstream; +using stringstream = fextl::basic_stringstream; +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/stack.h b/FEXCore/include/FEXCore/fextl/stack.h index ba70c6883..2fe10c2e4 100644 --- a/FEXCore/include/FEXCore/fextl/stack.h +++ b/FEXCore/include/FEXCore/fextl/stack.h @@ -6,6 +6,6 @@ #include namespace fextl { - template> - using stack = std::stack; +template> +using stack = std::stack; } diff --git a/FEXCore/include/FEXCore/fextl/string.h b/FEXCore/include/FEXCore/fextl/string.h index fec45768a..2f7ff4279 100644 --- a/FEXCore/include/FEXCore/fextl/string.h +++ b/FEXCore/include/FEXCore/fextl/string.h @@ -6,15 +6,15 @@ #include namespace fextl { - template, class Allocator = fextl::FEXAlloc> - using basic_string = std::basic_string; +template, class Allocator = fextl::FEXAlloc> +using basic_string = std::basic_string; - using string = fextl::basic_string; -} +using string = fextl::basic_string; +} // namespace fextl template<> - struct std::hash { - std::size_t operator()(fextl::string const& s) const noexcept { - return std::hash{}(s); +struct std::hash { + std::size_t operator()(const fextl::string& s) const noexcept { + return std::hash {}(s); }; }; diff --git a/FEXCore/include/FEXCore/fextl/unordered_map.h b/FEXCore/include/FEXCore/fextl/unordered_map.h index 40711921e..709020736 100644 --- a/FEXCore/include/FEXCore/fextl/unordered_map.h +++ b/FEXCore/include/FEXCore/fextl/unordered_map.h @@ -5,9 +5,9 @@ #include namespace fextl { - template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> - using unordered_map = std::unordered_map; +template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> +using unordered_map = std::unordered_map; - template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> - using unordered_multimap = std::unordered_multimap; -} +template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> +using unordered_multimap = std::unordered_multimap; +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/unordered_set.h b/FEXCore/include/FEXCore/fextl/unordered_set.h index 930e546d4..61c139593 100644 --- a/FEXCore/include/FEXCore/fextl/unordered_set.h +++ b/FEXCore/include/FEXCore/fextl/unordered_set.h @@ -5,9 +5,9 @@ #include namespace fextl { - template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc> - using unordered_set = std::unordered_set; +template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc> +using unordered_set = std::unordered_set; - template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc> - using unordered_multiset = std::unordered_multiset; -} +template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc> +using unordered_multiset = std::unordered_multiset; +} // namespace fextl diff --git a/FEXCore/include/FEXCore/fextl/vector.h b/FEXCore/include/FEXCore/fextl/vector.h index e2d2e0c4b..7246eff08 100644 --- a/FEXCore/include/FEXCore/fextl/vector.h +++ b/FEXCore/include/FEXCore/fextl/vector.h @@ -5,6 +5,6 @@ #include namespace fextl { - template> - using vector = std::vector; +template> +using vector = std::vector; } diff --git a/FEXCore/unittests/APITests/FutexSpinTest.cpp b/FEXCore/unittests/APITests/FutexSpinTest.cpp index 7947cd87c..1b12be304 100644 --- a/FEXCore/unittests/APITests/FutexSpinTest.cpp +++ b/FEXCore/unittests/APITests/FutexSpinTest.cpp @@ -6,7 +6,7 @@ constexpr auto SleepAmount = std::chrono::milliseconds(250); TEST_CASE("FutexSpin-Timed-8bit") { - uint8_t Test{}; + uint8_t Test {}; auto now = std::chrono::high_resolution_clock::now(); FEXCore::Utils::SpinWaitLock::Wait(&Test, 1, SleepAmount); @@ -20,8 +20,8 @@ TEST_CASE("FutexSpin-Timed-8bit") { TEST_CASE("FutexSpin-Sleep-8bit") { constexpr auto SleepAmount = std::chrono::seconds(1); - uint8_t Test{}; - std::atomic ActualSpinLoop{}; + uint8_t Test {}; + std::atomic ActualSpinLoop {}; std::chrono::nanoseconds SleptAmount; std::thread t([&Test, &SleptAmount, &ActualSpinLoop]() { @@ -33,7 +33,8 @@ TEST_CASE("FutexSpin-Sleep-8bit") { }); // Wait until the second thread lets us know to stop waiting sleeping. - while(ActualSpinLoop.load() == 0); + while (ActualSpinLoop.load() == 0) + ; // sleep this thread for the sleep amount. std::this_thread::sleep_for(SleepAmount); @@ -49,7 +50,7 @@ TEST_CASE("FutexSpin-Sleep-8bit") { } TEST_CASE("FutexSpin-Timed-16bit") { - uint16_t Test{}; + uint16_t Test {}; auto now = std::chrono::high_resolution_clock::now(); FEXCore::Utils::SpinWaitLock::Wait(&Test, 1, SleepAmount); @@ -61,7 +62,7 @@ TEST_CASE("FutexSpin-Timed-16bit") { } TEST_CASE("FutexSpin-Timed-32bit") { - uint32_t Test{}; + uint32_t Test {}; auto now = std::chrono::high_resolution_clock::now(); FEXCore::Utils::SpinWaitLock::Wait(&Test, 1, SleepAmount); @@ -73,7 +74,7 @@ TEST_CASE("FutexSpin-Timed-32bit") { } TEST_CASE("FutexSpin-Timed-64bit") { - uint64_t Test{}; + uint64_t Test {}; auto now = std::chrono::high_resolution_clock::now(); FEXCore::Utils::SpinWaitLock::Wait(&Test, 1, SleepAmount); diff --git a/FEXCore/unittests/Emitter/ALU_Tests.cpp b/FEXCore/unittests/Emitter/ALU_Tests.cpp index 37a7d458f..0217a9662 100644 --- a/FEXCore/unittests/Emitter/ALU_Tests.cpp +++ b/FEXCore/unittests/Emitter/ALU_Tests.cpp @@ -226,7 +226,6 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: PC relative") { CHECK(DisassembleEncoding(0) == 0xb000081e); CHECK(DisassembleEncoding(1) == 0x910013de); } - } TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Add/subtract immediate") { TEST_SINGLE(add(Size::i32Bit, Reg::r29, Reg::r28, 0, false), "add w29, w28, #0x0 (0)"); @@ -371,9 +370,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Logical immediate") { TEST_SINGLE(eor(Size::i64Bit, Reg::r29, Reg::r28, 1), "eor x29, x28, #0x1"); TEST_SINGLE(eor(Size::i64Bit, Reg::r29, Reg::r28, -2), "eor x29, x28, #0xfffffffffffffffe"); - TEST_SINGLE(tst(Size::i32Bit, Reg::r28, 1), "tst w28, #0x1"); + TEST_SINGLE(tst(Size::i32Bit, Reg::r28, 1), "tst w28, #0x1"); TEST_SINGLE(tst(Size::i32Bit, Reg::r28, -2), "tst w28, #0xfffffffe"); - TEST_SINGLE(tst(Size::i64Bit, Reg::r28, 1), "tst x28, #0x1"); + TEST_SINGLE(tst(Size::i64Bit, Reg::r28, 1), "tst x28, #0x1"); TEST_SINGLE(tst(Size::i64Bit, Reg::r28, -2), "tst x28, #0xfffffffffffffffe"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Move wide immediate") { @@ -442,28 +441,28 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Bitfield") { TEST_SINGLE(asr(Size::i32Bit, Reg::r29, Reg::r28, 17), "asr w29, w28, #17"); TEST_SINGLE(asr(Size::i64Bit, Reg::r29, Reg::r28, 17), "asr x29, x28, #17"); - TEST_SINGLE(bfc(Size::i32Bit, Reg::r29, 4, 3), "bfc w29, #4, #3"); + TEST_SINGLE(bfc(Size::i32Bit, Reg::r29, 4, 3), "bfc w29, #4, #3"); TEST_SINGLE(bfc(Size::i32Bit, Reg::r29, 27, 3), "bfc w29, #27, #3"); - TEST_SINGLE(bfc(Size::i64Bit, Reg::r29, 4, 3), "bfc x29, #4, #3"); + TEST_SINGLE(bfc(Size::i64Bit, Reg::r29, 4, 3), "bfc x29, #4, #3"); TEST_SINGLE(bfc(Size::i64Bit, Reg::r29, 57, 3), "bfc x29, #57, #3"); - TEST_SINGLE(bfxil(Size::i32Bit, Reg::r29, Reg::r28, 4, 3), "bfxil w29, w28, #4, #3"); + TEST_SINGLE(bfxil(Size::i32Bit, Reg::r29, Reg::r28, 4, 3), "bfxil w29, w28, #4, #3"); TEST_SINGLE(bfxil(Size::i32Bit, Reg::r29, Reg::r28, 27, 3), "bfxil w29, w28, #27, #3"); - TEST_SINGLE(bfxil(Size::i64Bit, Reg::r29, Reg::r28, 4, 3), "bfxil x29, x28, #4, #3"); + TEST_SINGLE(bfxil(Size::i64Bit, Reg::r29, Reg::r28, 4, 3), "bfxil x29, x28, #4, #3"); TEST_SINGLE(bfxil(Size::i64Bit, Reg::r29, Reg::r28, 57, 3), "bfxil x29, x28, #57, #3"); - TEST_SINGLE(sbfiz(Size::i32Bit, Reg::r29, Reg::r28, 5, 3), "sbfiz w29, w28, #5, #3"); + TEST_SINGLE(sbfiz(Size::i32Bit, Reg::r29, Reg::r28, 5, 3), "sbfiz w29, w28, #5, #3"); TEST_SINGLE(sbfiz(Size::i32Bit, Reg::r29, Reg::r28, 27, 3), "sbfiz w29, w28, #27, #3"); - TEST_SINGLE(sbfiz(Size::i64Bit, Reg::r29, Reg::r28, 5, 3), "sbfiz x29, x28, #5, #3"); + TEST_SINGLE(sbfiz(Size::i64Bit, Reg::r29, Reg::r28, 5, 3), "sbfiz x29, x28, #5, #3"); TEST_SINGLE(sbfiz(Size::i64Bit, Reg::r29, Reg::r28, 54, 3), "sbfiz x29, x28, #54, #3"); - TEST_SINGLE(ubfiz(Size::i32Bit, Reg::r29, Reg::r28, 5, 3), "ubfiz w29, w28, #5, #3"); + TEST_SINGLE(ubfiz(Size::i32Bit, Reg::r29, Reg::r28, 5, 3), "ubfiz w29, w28, #5, #3"); TEST_SINGLE(ubfiz(Size::i32Bit, Reg::r29, Reg::r28, 27, 3), "ubfiz w29, w28, #27, #3"); - TEST_SINGLE(ubfiz(Size::i64Bit, Reg::r29, Reg::r28, 5, 3), "ubfiz x29, x28, #5, #3"); + TEST_SINGLE(ubfiz(Size::i64Bit, Reg::r29, Reg::r28, 5, 3), "ubfiz x29, x28, #5, #3"); TEST_SINGLE(ubfiz(Size::i64Bit, Reg::r29, Reg::r28, 54, 3), "ubfiz x29, x28, #54, #3"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Extract") { @@ -1691,8 +1690,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: AddSub - with carry") { TEST_SINGLE(sbcs(Size::i32Bit, Reg::r29, Reg::r28, Reg::r27), "sbcs w29, w28, w27"); TEST_SINGLE(sbcs(Size::i64Bit, Reg::r29, Reg::r28, Reg::r27), "sbcs x29, x28, x27"); - TEST_SINGLE(ngc(Size::i32Bit, Reg::r29, Reg::r27), "ngc w29, w27"); - TEST_SINGLE(ngc(Size::i64Bit, Reg::r29, Reg::r27), "ngc x29, x27"); + TEST_SINGLE(ngc(Size::i32Bit, Reg::r29, Reg::r27), "ngc w29, w27"); + TEST_SINGLE(ngc(Size::i64Bit, Reg::r29, Reg::r27), "ngc x29, x27"); TEST_SINGLE(ngcs(Size::i32Bit, Reg::r29, Reg::r27), "ngcs w29, w27"); TEST_SINGLE(ngcs(Size::i64Bit, Reg::r29, Reg::r27), "ngcs x29, x27"); @@ -1706,7 +1705,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Rotate right into flags") { TEST_SINGLE(rmif(XReg::x30, 63, 0b1111), "rmif x30, #63, #NZCV"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Evaluate into flags") { - TEST_SINGLE(setf8(WReg::w30), "setf8 w30"); + TEST_SINGLE(setf8(WReg::w30), "setf8 w30"); TEST_SINGLE(setf16(WReg::w30), "setf16 w30"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ALU: Carry flag invert") { diff --git a/FEXCore/unittests/Emitter/ASIMD_Tests.cpp b/FEXCore/unittests/Emitter/ASIMD_Tests.cpp index c72850b76..d085b972f 100644 --- a/FEXCore/unittests/Emitter/ASIMD_Tests.cpp +++ b/FEXCore/unittests/Emitter/ASIMD_Tests.cpp @@ -40,35 +40,41 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD table lookup") TEST_SINGLE(tbx(QReg::q30, QReg::q26, QReg::q25), "tbx v30.16b, {v26.16b}, v25.16b"); TEST_SINGLE(tbx(DReg::d30, QReg::q26, DReg::d25), "tbx v30.8b, {v26.16b}, v25.8b"); - TEST_SINGLE(tbl(QReg::q30, QReg::q31, QReg::q0, QReg::q25), "tbl v30.16b, {v31.16b, v0.16b}, v25.16b"); - TEST_SINGLE(tbl(DReg::d30, QReg::q31, QReg::q0, DReg::d25), "tbl v30.8b, {v31.16b, v0.16b}, v25.8b"); + TEST_SINGLE(tbl(QReg::q30, QReg::q31, QReg::q0, QReg::q25), "tbl v30.16b, {v31.16b, v0.16b}, v25.16b"); + TEST_SINGLE(tbl(DReg::d30, QReg::q31, QReg::q0, DReg::d25), "tbl v30.8b, {v31.16b, v0.16b}, v25.8b"); TEST_SINGLE(tbl(QReg::q30, QReg::q26, QReg::q27, QReg::q25), "tbl v30.16b, {v26.16b, v27.16b}, v25.16b"); TEST_SINGLE(tbl(DReg::d30, QReg::q26, QReg::q27, DReg::d25), "tbl v30.8b, {v26.16b, v27.16b}, v25.8b"); - TEST_SINGLE(tbx(QReg::q30, QReg::q31, QReg::q0, QReg::q25), "tbx v30.16b, {v31.16b, v0.16b}, v25.16b"); - TEST_SINGLE(tbx(DReg::d30, QReg::q31, QReg::q0, DReg::d25), "tbx v30.8b, {v31.16b, v0.16b}, v25.8b"); + TEST_SINGLE(tbx(QReg::q30, QReg::q31, QReg::q0, QReg::q25), "tbx v30.16b, {v31.16b, v0.16b}, v25.16b"); + TEST_SINGLE(tbx(DReg::d30, QReg::q31, QReg::q0, DReg::d25), "tbx v30.8b, {v31.16b, v0.16b}, v25.8b"); TEST_SINGLE(tbx(QReg::q30, QReg::q26, QReg::q27, QReg::q25), "tbx v30.16b, {v26.16b, v27.16b}, v25.16b"); TEST_SINGLE(tbx(DReg::d30, QReg::q26, QReg::q27, DReg::d25), "tbx v30.8b, {v26.16b, v27.16b}, v25.8b"); - TEST_SINGLE(tbl(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q25), "tbl v30.16b, {v31.16b, v0.16b, v1.16b}, v25.16b"); - TEST_SINGLE(tbl(DReg::d30, QReg::q31, QReg::q0, QReg::q1, DReg::d25), "tbl v30.8b, {v31.16b, v0.16b, v1.16b}, v25.8b"); + TEST_SINGLE(tbl(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q25), "tbl v30.16b, {v31.16b, v0.16b, v1.16b}, v25.16b"); + TEST_SINGLE(tbl(DReg::d30, QReg::q31, QReg::q0, QReg::q1, DReg::d25), "tbl v30.8b, {v31.16b, v0.16b, v1.16b}, v25.8b"); TEST_SINGLE(tbl(QReg::q30, QReg::q26, QReg::q27, QReg::q28, QReg::q25), "tbl v30.16b, {v26.16b, v27.16b, v28.16b}, v25.16b"); TEST_SINGLE(tbl(DReg::d30, QReg::q26, QReg::q27, QReg::q28, DReg::d25), "tbl v30.8b, {v26.16b, v27.16b, v28.16b}, v25.8b"); - TEST_SINGLE(tbx(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q25), "tbx v30.16b, {v31.16b, v0.16b, v1.16b}, v25.16b"); - TEST_SINGLE(tbx(DReg::d30, QReg::q31, QReg::q0, QReg::q1, DReg::d25), "tbx v30.8b, {v31.16b, v0.16b, v1.16b}, v25.8b"); + TEST_SINGLE(tbx(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q25), "tbx v30.16b, {v31.16b, v0.16b, v1.16b}, v25.16b"); + TEST_SINGLE(tbx(DReg::d30, QReg::q31, QReg::q0, QReg::q1, DReg::d25), "tbx v30.8b, {v31.16b, v0.16b, v1.16b}, v25.8b"); TEST_SINGLE(tbx(QReg::q30, QReg::q26, QReg::q27, QReg::q28, QReg::q25), "tbx v30.16b, {v26.16b, v27.16b, v28.16b}, v25.16b"); TEST_SINGLE(tbx(DReg::d30, QReg::q26, QReg::q27, QReg::q28, DReg::d25), "tbx v30.8b, {v26.16b, v27.16b, v28.16b}, v25.8b"); - TEST_SINGLE(tbl(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, QReg::q25), "tbl v30.16b, {v31.16b, v0.16b, v1.16b, v2.16b}, v25.16b"); - TEST_SINGLE(tbl(DReg::d30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, DReg::d25), "tbl v30.8b, {v31.16b, v0.16b, v1.16b, v2.16b}, v25.8b"); - TEST_SINGLE(tbl(QReg::q30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, QReg::q25), "tbl v30.16b, {v26.16b, v27.16b, v28.16b, v29.16b}, v25.16b"); - TEST_SINGLE(tbl(DReg::d30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, DReg::d25), "tbl v30.8b, {v26.16b, v27.16b, v28.16b, v29.16b}, v25.8b"); + TEST_SINGLE(tbl(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, QReg::q25), "tbl v30.16b, {v31.16b, v0.16b, v1.16b, v2.16b}, " + "v25.16b"); + TEST_SINGLE(tbl(DReg::d30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, DReg::d25), "tbl v30.8b, {v31.16b, v0.16b, v1.16b, v2.16b}, v25.8b"); + TEST_SINGLE(tbl(QReg::q30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, QReg::q25), "tbl v30.16b, {v26.16b, v27.16b, v28.16b, v29.16b}, " + "v25.16b"); + TEST_SINGLE(tbl(DReg::d30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, DReg::d25), "tbl v30.8b, {v26.16b, v27.16b, v28.16b, v29.16b}, " + "v25.8b"); - TEST_SINGLE(tbx(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, QReg::q25), "tbx v30.16b, {v31.16b, v0.16b, v1.16b, v2.16b}, v25.16b"); - TEST_SINGLE(tbx(DReg::d30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, DReg::d25), "tbx v30.8b, {v31.16b, v0.16b, v1.16b, v2.16b}, v25.8b"); - TEST_SINGLE(tbx(QReg::q30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, QReg::q25), "tbx v30.16b, {v26.16b, v27.16b, v28.16b, v29.16b}, v25.16b"); - TEST_SINGLE(tbx(DReg::d30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, DReg::d25), "tbx v30.8b, {v26.16b, v27.16b, v28.16b, v29.16b}, v25.8b"); + TEST_SINGLE(tbx(QReg::q30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, QReg::q25), "tbx v30.16b, {v31.16b, v0.16b, v1.16b, v2.16b}, " + "v25.16b"); + TEST_SINGLE(tbx(DReg::d30, QReg::q31, QReg::q0, QReg::q1, QReg::q2, DReg::d25), "tbx v30.8b, {v31.16b, v0.16b, v1.16b, v2.16b}, v25.8b"); + TEST_SINGLE(tbx(QReg::q30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, QReg::q25), "tbx v30.16b, {v26.16b, v27.16b, v28.16b, v29.16b}, " + "v25.16b"); + TEST_SINGLE(tbx(DReg::d30, QReg::q26, QReg::q27, QReg::q28, QReg::q29, DReg::d25), "tbx v30.8b, {v26.16b, v27.16b, v28.16b, v29.16b}, " + "v25.8b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD permute") { // Commented out lines showcase unallocated encodings. @@ -84,11 +90,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD permute") { TEST_SINGLE(uzp1(DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uzp1(DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uzp1(DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uzp1(DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uzp1(DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(uzp1(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uzp1(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uzp1(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uzp1(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uzp1(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uzp1 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(trn1(QReg::q30, QReg::q29, QReg::q28), "trn1 v30.16b, v29.16b, v28.16b"); TEST_SINGLE(trn1(QReg::q30, QReg::q29, QReg::q28), "trn1 v30.8h, v29.8h, v28.8h"); @@ -102,11 +108,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD permute") { TEST_SINGLE(trn1(DReg::d30, DReg::d29, DReg::d28), "trn1 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(trn1(DReg::d30, DReg::d29, DReg::d28), "trn1 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(trn1(DReg::d30, DReg::d29, DReg::d28), "trn1 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(trn1(DReg::d30, DReg::d29, DReg::d28), "trn1 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(trn1(DReg::d30, DReg::d29, DReg::d28), "trn1 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(trn1(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "trn1 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(trn1(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "trn1 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(trn1(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "trn1 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(trn1(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "trn1 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(trn1(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "trn1 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(zip1(QReg::q30, QReg::q29, QReg::q28), "zip1 v30.16b, v29.16b, v28.16b"); TEST_SINGLE(zip1(QReg::q30, QReg::q29, QReg::q28), "zip1 v30.8h, v29.8h, v28.8h"); @@ -120,11 +126,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD permute") { TEST_SINGLE(zip1(DReg::d30, DReg::d29, DReg::d28), "zip1 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(zip1(DReg::d30, DReg::d29, DReg::d28), "zip1 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(zip1(DReg::d30, DReg::d29, DReg::d28), "zip1 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(zip1(DReg::d30, DReg::d29, DReg::d28), "zip1 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(zip1(DReg::d30, DReg::d29, DReg::d28), "zip1 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(zip1(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "zip1 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(zip1(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "zip1 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(zip1(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "zip1 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(zip1(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "zip1 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(zip1(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "zip1 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(uzp2(QReg::q30, QReg::q29, QReg::q28), "uzp2 v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uzp2(QReg::q30, QReg::q29, QReg::q28), "uzp2 v30.8h, v29.8h, v28.8h"); @@ -138,11 +144,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD permute") { TEST_SINGLE(uzp2(DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uzp2(DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uzp2(DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uzp2(DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uzp2(DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(uzp2(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uzp2(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uzp2(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uzp2(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uzp2(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uzp2 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(trn2(QReg::q30, QReg::q29, QReg::q28), "trn2 v30.16b, v29.16b, v28.16b"); TEST_SINGLE(trn2(QReg::q30, QReg::q29, QReg::q28), "trn2 v30.8h, v29.8h, v28.8h"); @@ -156,11 +162,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD permute") { TEST_SINGLE(trn2(DReg::d30, DReg::d29, DReg::d28), "trn2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(trn2(DReg::d30, DReg::d29, DReg::d28), "trn2 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(trn2(DReg::d30, DReg::d29, DReg::d28), "trn2 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(trn2(DReg::d30, DReg::d29, DReg::d28), "trn2 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(trn2(DReg::d30, DReg::d29, DReg::d28), "trn2 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(trn2(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "trn2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(trn2(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "trn2 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(trn2(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "trn2 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(trn2(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "trn2 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(trn2(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "trn2 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(zip2(QReg::q30, QReg::q29, QReg::q28), "zip2 v30.16b, v29.16b, v28.16b"); TEST_SINGLE(zip2(QReg::q30, QReg::q29, QReg::q28), "zip2 v30.8h, v29.8h, v28.8h"); @@ -174,11 +180,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD permute") { TEST_SINGLE(zip2(DReg::d30, DReg::d29, DReg::d28), "zip2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(zip2(DReg::d30, DReg::d29, DReg::d28), "zip2 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(zip2(DReg::d30, DReg::d29, DReg::d28), "zip2 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(zip2(DReg::d30, DReg::d29, DReg::d28), "zip2 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(zip2(DReg::d30, DReg::d29, DReg::d28), "zip2 v30.1d, v29.1d, v28.1d"); TEST_SINGLE(zip2(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "zip2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(zip2(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "zip2 v30.4h, v29.4h, v28.4h"); TEST_SINGLE(zip2(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "zip2 v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(zip2(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "zip2 v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(zip2(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "zip2 v30.1d, v29.1d, v28.1d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD extract") { TEST_SINGLE(ext(QReg::q30, QReg::q29, QReg::q28, 0), "ext v30.16b, v29.16b, v28.16b, #0"); @@ -200,11 +206,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD copy") { TEST_SINGLE(dup(SubRegSize::i8Bit, DReg::d30, DReg::d29, 0), "dup v30.8b, v29.b[0]"); TEST_SINGLE(dup(SubRegSize::i16Bit, DReg::d30, DReg::d29, 0), "dup v30.4h, v29.h[0]"); TEST_SINGLE(dup(SubRegSize::i32Bit, DReg::d30, DReg::d29, 0), "dup v30.2s, v29.s[0]"); - //TEST_SINGLE(dup(SubRegSize::i64Bit, DReg::d30, DReg::d29, 0), "dup v30.1d, v29.d[0]"); + // TEST_SINGLE(dup(SubRegSize::i64Bit, DReg::d30, DReg::d29, 0), "dup v30.1d, v29.d[0]"); TEST_SINGLE(dup(SubRegSize::i8Bit, DReg::d30, DReg::d29, 15), "dup v30.8b, v29.b[15]"); TEST_SINGLE(dup(SubRegSize::i16Bit, DReg::d30, DReg::d29, 7), "dup v30.4h, v29.h[7]"); TEST_SINGLE(dup(SubRegSize::i32Bit, DReg::d30, DReg::d29, 3), "dup v30.2s, v29.s[3]"); - //TEST_SINGLE(dup(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "dup v30.1d, v29.d[1]"); + // TEST_SINGLE(dup(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "dup v30.1d, v29.d[1]"); TEST_SINGLE(dup(SubRegSize::i8Bit, QReg::q30, Reg::r29), "dup v30.16b, w29"); TEST_SINGLE(dup(SubRegSize::i16Bit, QReg::q30, Reg::r29), "dup v30.8h, w29"); @@ -214,7 +220,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD copy") { TEST_SINGLE(dup(SubRegSize::i8Bit, DReg::d30, Reg::r29), "dup v30.8b, w29"); TEST_SINGLE(dup(SubRegSize::i16Bit, DReg::d30, Reg::r29), "dup v30.4h, w29"); TEST_SINGLE(dup(SubRegSize::i32Bit, DReg::d30, Reg::r29), "dup v30.2s, w29"); - //TEST_SINGLE(dup(SubRegSize::i64Bit, DReg::d30, Reg::r29), "dup v30.1d, x29"); + // TEST_SINGLE(dup(SubRegSize::i64Bit, DReg::d30, Reg::r29), "dup v30.1d, x29"); TEST_SINGLE(smov(XReg::x29, VReg::v30, 0), "smov x29, v30.b[0]"); TEST_SINGLE(smov(XReg::x29, VReg::v30, 15), "smov x29, v30.b[15]"); TEST_SINGLE(smov(XReg::x29, VReg::v30, 0), "smov x29, v30.h[0]"); @@ -236,7 +242,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD copy") { TEST_SINGLE(umov(Reg::r29, VReg::v30, 0), "mov x29, v30.d[0]"); TEST_SINGLE(umov(Reg::r29, VReg::v30, 1), "mov x29, v30.d[1]"); - TEST_SINGLE(ins(VReg::v30, 0, Reg::r29), "mov v30.b[0], w29"); + TEST_SINGLE(ins(VReg::v30, 0, Reg::r29), "mov v30.b[0], w29"); TEST_SINGLE(ins(VReg::v30, 0, Reg::r29), "mov v30.h[0], w29"); TEST_SINGLE(ins(VReg::v30, 0, Reg::r29), "mov v30.s[0], w29"); TEST_SINGLE(ins(VReg::v30, 0, Reg::r29), "mov v30.d[0], x29"); @@ -245,7 +251,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD copy") { TEST_SINGLE(ins(VReg::v30, 3, Reg::r29), "mov v30.s[3], w29"); TEST_SINGLE(ins(VReg::v30, 1, Reg::r29), "mov v30.d[1], x29"); - TEST_SINGLE(ins(SubRegSize::i8Bit, VReg::v30, 0, Reg::r29), "mov v30.b[0], w29"); + TEST_SINGLE(ins(SubRegSize::i8Bit, VReg::v30, 0, Reg::r29), "mov v30.b[0], w29"); TEST_SINGLE(ins(SubRegSize::i16Bit, VReg::v30, 0, Reg::r29), "mov v30.h[0], w29"); TEST_SINGLE(ins(SubRegSize::i32Bit, VReg::v30, 0, Reg::r29), "mov v30.s[0], w29"); TEST_SINGLE(ins(SubRegSize::i64Bit, VReg::v30, 0, Reg::r29), "mov v30.d[0], x29"); @@ -254,7 +260,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD copy") { TEST_SINGLE(ins(SubRegSize::i32Bit, VReg::v30, 3, Reg::r29), "mov v30.s[3], w29"); TEST_SINGLE(ins(SubRegSize::i64Bit, VReg::v30, 1, Reg::r29), "mov v30.d[1], x29"); - TEST_SINGLE(ins(SubRegSize::i8Bit, VReg::v30, 0, VReg::v29, 15), "mov v30.b[0], v29.b[15]"); + TEST_SINGLE(ins(SubRegSize::i8Bit, VReg::v30, 0, VReg::v29, 15), "mov v30.b[0], v29.b[15]"); TEST_SINGLE(ins(SubRegSize::i16Bit, VReg::v30, 0, VReg::v29, 7), "mov v30.h[0], v29.h[7]"); TEST_SINGLE(ins(SubRegSize::i32Bit, VReg::v30, 0, VReg::v29, 3), "mov v30.s[0], v29.s[3]"); TEST_SINGLE(ins(SubRegSize::i64Bit, VReg::v30, 0, VReg::v29, 1), "mov v30.d[0], v29.d[1]"); @@ -328,7 +334,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three-register TEST_SINGLE(sdot(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sdot(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.4h, v29.8b, v28.8b"); TEST_SINGLE(sdot(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.2s, v29.8b, v28.8b"); - //TEST_SINGLE(sdot(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.1d, v29.8b, v28.8b"); + // TEST_SINGLE(sdot(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.1d, v29.8b, v28.8b"); TEST_SINGLE(usdot(QReg::q30, QReg::q29, QReg::q28), "usdot v30.4s, v29.16b, v28.16b"); TEST_SINGLE(usdot(DReg::d30, DReg::d29, DReg::d28), "usdot v30.2s, v29.8b, v28.8b"); @@ -340,7 +346,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three-register TEST_SINGLE(sqrdmlah(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqrdmlah(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqrdmlah(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqrdmlah(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.1d, v29.1d, v28.1d"); TEST_SINGLE(sqrdmlsh(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlsh v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sqrdmlsh(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlsh v30.8h, v29.8h, v28.8h"); @@ -349,7 +355,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three-register TEST_SINGLE(sqrdmlsh(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqrdmlsh(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqrdmlsh(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqrdmlsh(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.1d, v29.1d, v28.1d"); TEST_SINGLE(udot(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "udot v30.16b, v29.16b, v28.16b"); TEST_SINGLE(udot(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "udot v30.8h, v29.16b, v28.16b"); @@ -358,63 +364,63 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three-register TEST_SINGLE(udot(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.8b, v29.8b, v28.8b"); TEST_SINGLE(udot(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.4h, v29.8b, v28.8b"); TEST_SINGLE(udot(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.2s, v29.8b, v28.8b"); - //TEST_SINGLE(udot(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.1d, v29.8b, v28.8b"); + // TEST_SINGLE(udot(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.1d, v29.8b, v28.8b"); - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.16b, v29.16b, v28.16b, #0"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.16b, v29.16b, v28.16b, #0"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.8h, v29.8h, v28.8h, #0"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.4s, v29.4s, v28.4s, #0"); TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.2d, v29.2d, v28.2d, #0"); - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.8b, v29.8b, v28.8b, #0"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.8b, v29.8b, v28.8b, #0"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.4h, v29.4h, v28.4h, #0"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.2s, v29.2s, v28.2s, #0"); - //TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.1d, v29.1d, v28.1d, #0"); + // TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.1d, v29.1d, v28.1d, #0"); - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.16b, v29.16b, v28.16b, #90"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.16b, v29.16b, v28.16b, #90"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.8h, v29.8h, v28.8h, #90"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.4s, v29.4s, v28.4s, #90"); TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.2d, v29.2d, v28.2d, #90"); - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.8b, v29.8b, v28.8b, #90"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.8b, v29.8b, v28.8b, #90"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.4h, v29.4h, v28.4h, #90"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.2s, v29.2s, v28.2s, #90"); - //TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.1d, v29.1d, v28.1d, #90"); + // TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.1d, v29.1d, v28.1d, #90"); // Vixl disassembler has a bug that claims 8-bit fcmla exists - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.16b, v29.16b, v28.16b, #180"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.16b, v29.16b, v28.16b, #180"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.8h, v29.8h, v28.8h, #180"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.4s, v29.4s, v28.4s, #180"); TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.2d, v29.2d, v28.2d, #180"); - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.8b, v29.8b, v28.8b, #180"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.8b, v29.8b, v28.8b, #180"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.4h, v29.4h, v28.4h, #180"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.2s, v29.2s, v28.2s, #180"); - //TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.1d, v29.1d, v28.1d, #180"); + // TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.1d, v29.1d, v28.1d, #180"); - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.16b, v29.16b, v28.16b, #270"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.16b, v29.16b, v28.16b, #270"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.8h, v29.8h, v28.8h, #270"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.4s, v29.4s, v28.4s, #270"); TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.2d, v29.2d, v28.2d, #270"); - //TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.8b, v29.8b, v28.8b, #270"); + // TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.8b, v29.8b, v28.8b, #270"); TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.4h, v29.4h, v28.4h, #270"); TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.2s, v29.2s, v28.2s, #270"); - //TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.1d, v29.1d, v28.1d, #270"); + // TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.1d, v29.1d, v28.1d, #270"); // Vixl disassembler has a bug that claims 8-bit fcadd exists - //TEST_SINGLE(fcadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.16b, v29.16b, v28.16b, #90"); + // TEST_SINGLE(fcadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.16b, v29.16b, v28.16b, #90"); TEST_SINGLE(fcadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.8h, v29.8h, v28.8h, #90"); TEST_SINGLE(fcadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.4s, v29.4s, v28.4s, #90"); TEST_SINGLE(fcadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.2d, v29.2d, v28.2d, #90"); - //TEST_SINGLE(fcadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.8b, v29.8b, v28.8b, #90"); + // TEST_SINGLE(fcadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.8b, v29.8b, v28.8b, #90"); TEST_SINGLE(fcadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.4h, v29.4h, v28.4h, #90"); TEST_SINGLE(fcadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.2s, v29.2s, v28.2s, #90"); - //TEST_SINGLE(fcadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.1d, v29.1d, v28.1d, #90"); + // TEST_SINGLE(fcadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.1d, v29.1d, v28.1d, #90"); - //TEST_SINGLE(fcadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.16b, v29.16b, v28.16b, #270"); + // TEST_SINGLE(fcadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.16b, v29.16b, v28.16b, #270"); TEST_SINGLE(fcadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.8h, v29.8h, v28.8h, #270"); TEST_SINGLE(fcadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.4s, v29.4s, v28.4s, #270"); TEST_SINGLE(fcadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.2d, v29.2d, v28.2d, #270"); - //TEST_SINGLE(fcadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.8b, v29.8b, v28.8b, #270"); + // TEST_SINGLE(fcadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.8b, v29.8b, v28.8b, #270"); TEST_SINGLE(fcadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.4h, v29.4h, v28.4h, #270"); TEST_SINGLE(fcadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.2s, v29.2s, v28.2s, #270"); - //TEST_SINGLE(fcadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.1d, v29.1d, v28.1d, #270"); + // TEST_SINGLE(fcadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.1d, v29.1d, v28.1d, #270"); // TODO: Enable once vixl disassembler supports these instructions // TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q28), "bfdot v30.4s, v29.8h, v28.8h"); @@ -425,7 +431,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three-register TEST_SINGLE(smmla(VReg::v30, VReg::v29, VReg::v28), "smmla v30.4s, v29.16b, v28.16b"); TEST_SINGLE(usmmla(VReg::v30, VReg::v29, VReg::v28), "usmmla v30.4s, v29.16b, v28.16b"); // TODO: Enable once vixl disassembler supports these instructions - //TEST_SINGLE(bfmmla(VReg::v30, VReg::v29, VReg::v28), "bfmmla v30.4s, v29.8h, v28.8h"); + // TEST_SINGLE(bfmmla(VReg::v30, VReg::v29, VReg::v28), "bfmmla v30.4s, v29.8h, v28.8h"); TEST_SINGLE(ummla(VReg::v30, VReg::v29, VReg::v28), "ummla v30.4s, v29.16b, v28.16b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register miscellaneous") { @@ -433,29 +439,29 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(rev64(SubRegSize::i8Bit, QReg::q30, QReg::q29), "rev64 v30.16b, v29.16b"); TEST_SINGLE(rev64(SubRegSize::i16Bit, QReg::q30, QReg::q29), "rev64 v30.8h, v29.8h"); TEST_SINGLE(rev64(SubRegSize::i32Bit, QReg::q30, QReg::q29), "rev64 v30.4s, v29.4s"); - //TEST_SINGLE(rev64(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rev64 v30.2d, v29.2d"); + // TEST_SINGLE(rev64(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rev64 v30.2d, v29.2d"); TEST_SINGLE(rev64(SubRegSize::i8Bit, DReg::d30, DReg::d29), "rev64 v30.8b, v29.8b"); TEST_SINGLE(rev64(SubRegSize::i16Bit, DReg::d30, DReg::d29), "rev64 v30.4h, v29.4h"); TEST_SINGLE(rev64(SubRegSize::i32Bit, DReg::d30, DReg::d29), "rev64 v30.2s, v29.2s"); - //TEST_SINGLE(rev64(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rev64 v30.1d, v29.1d"); + // TEST_SINGLE(rev64(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rev64 v30.1d, v29.1d"); TEST_SINGLE(rev16(SubRegSize::i8Bit, QReg::q30, QReg::q29), "rev16 v30.16b, v29.16b"); - //TEST_SINGLE(rev16(SubRegSize::i16Bit, QReg::q30, QReg::q29), "rev16 v30.8h, v29.8h"); - //TEST_SINGLE(rev16(SubRegSize::i32Bit, QReg::q30, QReg::q29), "rev16 v30.4s, v29.4s"); - //TEST_SINGLE(rev16(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rev16 v30.2d, v29.2d"); + // TEST_SINGLE(rev16(SubRegSize::i16Bit, QReg::q30, QReg::q29), "rev16 v30.8h, v29.8h"); + // TEST_SINGLE(rev16(SubRegSize::i32Bit, QReg::q30, QReg::q29), "rev16 v30.4s, v29.4s"); + // TEST_SINGLE(rev16(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rev16 v30.2d, v29.2d"); TEST_SINGLE(rev16(SubRegSize::i8Bit, DReg::d30, DReg::d29), "rev16 v30.8b, v29.8b"); - //TEST_SINGLE(rev16(SubRegSize::i16Bit, DReg::d30, DReg::d29), "rev16 v30.4h, v29.4h"); - //TEST_SINGLE(rev16(SubRegSize::i32Bit, DReg::d30, DReg::d29), "rev16 v30.2s, v29.2s"); - //TEST_SINGLE(rev16(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rev16 v30.1d, v29.1d"); + // TEST_SINGLE(rev16(SubRegSize::i16Bit, DReg::d30, DReg::d29), "rev16 v30.4h, v29.4h"); + // TEST_SINGLE(rev16(SubRegSize::i32Bit, DReg::d30, DReg::d29), "rev16 v30.2s, v29.2s"); + // TEST_SINGLE(rev16(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rev16 v30.1d, v29.1d"); - //TEST_SINGLE(saddlp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "saddlp v30.16b, v29.16b"); + // TEST_SINGLE(saddlp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "saddlp v30.16b, v29.16b"); TEST_SINGLE(saddlp(SubRegSize::i16Bit, QReg::q30, QReg::q29), "saddlp v30.8h, v29.16b"); TEST_SINGLE(saddlp(SubRegSize::i32Bit, QReg::q30, QReg::q29), "saddlp v30.4s, v29.8h"); TEST_SINGLE(saddlp(SubRegSize::i64Bit, QReg::q30, QReg::q29), "saddlp v30.2d, v29.4s"); - //TEST_SINGLE(saddlp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "saddlp v30.8b, v29.8b"); + // TEST_SINGLE(saddlp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "saddlp v30.8b, v29.8b"); TEST_SINGLE(saddlp(SubRegSize::i16Bit, DReg::d30, DReg::d29), "saddlp v30.4h, v29.8b"); TEST_SINGLE(saddlp(SubRegSize::i32Bit, DReg::d30, DReg::d29), "saddlp v30.2s, v29.4h"); TEST_SINGLE(saddlp(SubRegSize::i64Bit, DReg::d30, DReg::d29), "saddlp v30.1d, v29.2s"); @@ -468,34 +474,34 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(suqadd(SubRegSize::i8Bit, DReg::d30, DReg::d29), "suqadd v30.8b, v29.8b"); TEST_SINGLE(suqadd(SubRegSize::i16Bit, DReg::d30, DReg::d29), "suqadd v30.4h, v29.4h"); TEST_SINGLE(suqadd(SubRegSize::i32Bit, DReg::d30, DReg::d29), "suqadd v30.2s, v29.2s"); - //TEST_SINGLE(suqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29), "suqadd v30.1d, v29.1d"); + // TEST_SINGLE(suqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29), "suqadd v30.1d, v29.1d"); TEST_SINGLE(cls(SubRegSize::i8Bit, QReg::q30, QReg::q29), "cls v30.16b, v29.16b"); TEST_SINGLE(cls(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cls v30.8h, v29.8h"); TEST_SINGLE(cls(SubRegSize::i32Bit, QReg::q30, QReg::q29), "cls v30.4s, v29.4s"); - //TEST_SINGLE(cls(SubRegSize::i64Bit, QReg::q30, QReg::q29), "cls v30.2d, v29.2d"); + // TEST_SINGLE(cls(SubRegSize::i64Bit, QReg::q30, QReg::q29), "cls v30.2d, v29.2d"); TEST_SINGLE(cls(SubRegSize::i8Bit, DReg::d30, DReg::d29), "cls v30.8b, v29.8b"); TEST_SINGLE(cls(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cls v30.4h, v29.4h"); TEST_SINGLE(cls(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cls v30.2s, v29.2s"); - //TEST_SINGLE(cls(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cls v30.1d, v29.1d"); + // TEST_SINGLE(cls(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cls v30.1d, v29.1d"); TEST_SINGLE(cnt(SubRegSize::i8Bit, QReg::q30, QReg::q29), "cnt v30.16b, v29.16b"); - //TEST_SINGLE(cnt(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cnt v30.8h, v29.8h"); - //TEST_SINGLE(cnt(SubRegSize::i32Bit, QReg::q30, QReg::q29), "cnt v30.4s, v29.4s"); - //TEST_SINGLE(cnt(SubRegSize::i64Bit, QReg::q30, QReg::q29), "cnt v30.2d, v29.2d"); + // TEST_SINGLE(cnt(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cnt v30.8h, v29.8h"); + // TEST_SINGLE(cnt(SubRegSize::i32Bit, QReg::q30, QReg::q29), "cnt v30.4s, v29.4s"); + // TEST_SINGLE(cnt(SubRegSize::i64Bit, QReg::q30, QReg::q29), "cnt v30.2d, v29.2d"); TEST_SINGLE(cnt(SubRegSize::i8Bit, DReg::d30, DReg::d29), "cnt v30.8b, v29.8b"); - //TEST_SINGLE(cnt(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cnt v30.4h, v29.4h"); - //TEST_SINGLE(cnt(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cnt v30.2s, v29.2s"); - //TEST_SINGLE(cnt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cnt v30.1d, v29.1d"); + // TEST_SINGLE(cnt(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cnt v30.4h, v29.4h"); + // TEST_SINGLE(cnt(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cnt v30.2s, v29.2s"); + // TEST_SINGLE(cnt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cnt v30.1d, v29.1d"); - //TEST_SINGLE(sadalp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sadalp v30.16b, v29.16b"); + // TEST_SINGLE(sadalp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sadalp v30.16b, v29.16b"); TEST_SINGLE(sadalp(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sadalp v30.8h, v29.16b"); TEST_SINGLE(sadalp(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sadalp v30.4s, v29.8h"); TEST_SINGLE(sadalp(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sadalp v30.2d, v29.4s"); - //TEST_SINGLE(sadalp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sadalp v30.8b, v29.8b"); + // TEST_SINGLE(sadalp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sadalp v30.8b, v29.8b"); TEST_SINGLE(sadalp(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sadalp v30.4h, v29.8b"); TEST_SINGLE(sadalp(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sadalp v30.2s, v29.4h"); TEST_SINGLE(sadalp(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sadalp v30.1d, v29.2s"); @@ -508,7 +514,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(sqabs(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sqabs v30.8b, v29.8b"); TEST_SINGLE(sqabs(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sqabs v30.4h, v29.4h"); TEST_SINGLE(sqabs(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sqabs v30.2s, v29.2s"); - //TEST_SINGLE(sqabs(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqabs v30.1d, v29.1d"); + // TEST_SINGLE(sqabs(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqabs v30.1d, v29.1d"); TEST_SINGLE(cmgt(SubRegSize::i8Bit, QReg::q30, QReg::q29), "cmgt v30.16b, v29.16b, #0"); TEST_SINGLE(cmgt(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cmgt v30.8h, v29.8h, #0"); @@ -518,7 +524,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(cmgt(SubRegSize::i8Bit, DReg::d30, DReg::d29), "cmgt v30.8b, v29.8b, #0"); TEST_SINGLE(cmgt(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cmgt v30.4h, v29.4h, #0"); TEST_SINGLE(cmgt(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cmgt v30.2s, v29.2s, #0"); - //TEST_SINGLE(cmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmgt v30.1d, v29.1d, #0"); + // TEST_SINGLE(cmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmgt v30.1d, v29.1d, #0"); TEST_SINGLE(cmeq(SubRegSize::i8Bit, QReg::q30, QReg::q29), "cmeq v30.16b, v29.16b, #0"); TEST_SINGLE(cmeq(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cmeq v30.8h, v29.8h, #0"); @@ -528,7 +534,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(cmeq(SubRegSize::i8Bit, DReg::d30, DReg::d29), "cmeq v30.8b, v29.8b, #0"); TEST_SINGLE(cmeq(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cmeq v30.4h, v29.4h, #0"); TEST_SINGLE(cmeq(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cmeq v30.2s, v29.2s, #0"); - //TEST_SINGLE(cmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmeq v30.1d, v29.1d, #0"); + // TEST_SINGLE(cmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmeq v30.1d, v29.1d, #0"); TEST_SINGLE(cmlt(SubRegSize::i8Bit, QReg::q30, QReg::q29), "cmlt v30.16b, v29.16b, #0"); TEST_SINGLE(cmlt(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cmlt v30.8h, v29.8h, #0"); @@ -538,7 +544,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(cmlt(SubRegSize::i8Bit, DReg::d30, DReg::d29), "cmlt v30.8b, v29.8b, #0"); TEST_SINGLE(cmlt(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cmlt v30.4h, v29.4h, #0"); TEST_SINGLE(cmlt(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cmlt v30.2s, v29.2s, #0"); - //TEST_SINGLE(cmlt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmlt v30.1d, v29.1d, #0"); + // TEST_SINGLE(cmlt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmlt v30.1d, v29.1d, #0"); TEST_SINGLE(abs(SubRegSize::i8Bit, QReg::q30, QReg::q29), "abs v30.16b, v29.16b"); TEST_SINGLE(abs(SubRegSize::i16Bit, QReg::q30, QReg::q29), "abs v30.8h, v29.8h"); @@ -553,189 +559,189 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(xtn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "xtn v30.8b, v29.8h"); TEST_SINGLE(xtn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "xtn v30.4h, v29.4s"); TEST_SINGLE(xtn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "xtn v30.2s, v29.2d"); - //TEST_SINGLE(xtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "xtn v30.2d, v29.1d"); + // TEST_SINGLE(xtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "xtn v30.2d, v29.1d"); TEST_SINGLE(xtn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "xtn v30.8b, v29.8h"); TEST_SINGLE(xtn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "xtn v30.4h, v29.4s"); TEST_SINGLE(xtn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "xtn v30.2s, v29.2d"); - //TEST_SINGLE(xtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "xtn v30.1d, v29.1d"); + // TEST_SINGLE(xtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "xtn v30.1d, v29.1d"); TEST_SINGLE(xtn2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "xtn2 v30.16b, v29.8h"); TEST_SINGLE(xtn2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "xtn2 v30.8h, v29.4s"); TEST_SINGLE(xtn2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "xtn2 v30.4s, v29.2d"); - //TEST_SINGLE(xtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "xtn2 v30.2d, v29.1d"); + // TEST_SINGLE(xtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "xtn2 v30.2d, v29.1d"); TEST_SINGLE(xtn2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "xtn2 v30.16b, v29.8h"); TEST_SINGLE(xtn2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "xtn2 v30.8h, v29.4s"); TEST_SINGLE(xtn2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "xtn2 v30.4s, v29.2d"); - //TEST_SINGLE(xtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "xtn2 v30.2d, v29.1d"); + // TEST_SINGLE(xtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "xtn2 v30.2d, v29.1d"); TEST_SINGLE(sqxtn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sqxtn v30.8b, v29.8h"); TEST_SINGLE(sqxtn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sqxtn v30.4h, v29.4s"); TEST_SINGLE(sqxtn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sqxtn v30.2s, v29.2d"); - //TEST_SINGLE(sqxtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtn v30.2d, v29.1d"); + // TEST_SINGLE(sqxtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtn v30.2d, v29.1d"); TEST_SINGLE(sqxtn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sqxtn v30.8b, v29.8h"); TEST_SINGLE(sqxtn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sqxtn v30.4h, v29.4s"); TEST_SINGLE(sqxtn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sqxtn v30.2s, v29.2d"); - //TEST_SINGLE(sqxtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtn v30.1d, v29.1d"); + // TEST_SINGLE(sqxtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtn v30.1d, v29.1d"); TEST_SINGLE(sqxtn2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sqxtn2 v30.16b, v29.8h"); TEST_SINGLE(sqxtn2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sqxtn2 v30.8h, v29.4s"); TEST_SINGLE(sqxtn2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sqxtn2 v30.4s, v29.2d"); - //TEST_SINGLE(sqxtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtn2 v30.2d, v29.1d"); + // TEST_SINGLE(sqxtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtn2 v30.2d, v29.1d"); TEST_SINGLE(sqxtn2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sqxtn2 v30.16b, v29.8h"); TEST_SINGLE(sqxtn2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sqxtn2 v30.8h, v29.4s"); TEST_SINGLE(sqxtn2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sqxtn2 v30.4s, v29.2d"); - //TEST_SINGLE(sqxtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtn2 v30.2d, v29.1d"); + // TEST_SINGLE(sqxtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtn2 v30.2d, v29.1d"); - //TEST_SINGLE(fcvtn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtn v30.8b, v29.8h"); + // TEST_SINGLE(fcvtn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtn v30.8b, v29.8h"); TEST_SINGLE(fcvtn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtn v30.4h, v29.4s"); TEST_SINGLE(fcvtn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtn v30.2s, v29.2d"); - //TEST_SINGLE(fcvtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtn v30.2d, v29.1d"); + // TEST_SINGLE(fcvtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtn v30.2d, v29.1d"); - //TEST_SINGLE(fcvtn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtn v30.8b, v29.8h"); + // TEST_SINGLE(fcvtn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtn v30.8b, v29.8h"); TEST_SINGLE(fcvtn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtn v30.4h, v29.4s"); TEST_SINGLE(fcvtn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtn v30.2s, v29.2d"); - //TEST_SINGLE(fcvtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtn v30.1d, v29.1d"); + // TEST_SINGLE(fcvtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtn v30.1d, v29.1d"); - //TEST_SINGLE(fcvtn2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtn2 v30.16b, v29.8h"); + // TEST_SINGLE(fcvtn2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtn2 v30.16b, v29.8h"); TEST_SINGLE(fcvtn2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtn2 v30.8h, v29.4s"); TEST_SINGLE(fcvtn2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtn2 v30.4s, v29.2d"); - //TEST_SINGLE(fcvtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtn2 v30.2d, v29.1d"); + // TEST_SINGLE(fcvtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtn2 v30.2d, v29.1d"); - //TEST_SINGLE(fcvtn2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtn2 v30.16b, v29.8h"); + // TEST_SINGLE(fcvtn2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtn2 v30.16b, v29.8h"); TEST_SINGLE(fcvtn2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtn2 v30.8h, v29.4s"); TEST_SINGLE(fcvtn2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtn2 v30.4s, v29.2d"); - //TEST_SINGLE(fcvtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtn2 v30.2d, v29.1d"); + // TEST_SINGLE(fcvtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtn2 v30.2d, v29.1d"); - //TEST_SINGLE(fcvtl(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtl v30.8b, v29.8h"); - //TEST_SINGLE(fcvtl(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtl v30.4h, v29.4s"); + // TEST_SINGLE(fcvtl(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtl v30.8b, v29.8h"); + // TEST_SINGLE(fcvtl(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtl v30.4h, v29.4s"); TEST_SINGLE(fcvtl(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtl v30.4s, v29.4h"); TEST_SINGLE(fcvtl(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtl v30.2d, v29.2s"); - //TEST_SINGLE(fcvtl(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtl v30.8b, v29.8h"); - //TEST_SINGLE(fcvtl(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtl v30.4h, v29.4s"); + // TEST_SINGLE(fcvtl(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtl v30.8b, v29.8h"); + // TEST_SINGLE(fcvtl(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtl v30.4h, v29.4s"); TEST_SINGLE(fcvtl(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtl v30.4s, v29.4h"); TEST_SINGLE(fcvtl(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtl v30.2d, v29.2s"); - //TEST_SINGLE(fcvtl2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtl2 v30.16b, v29.8h"); - //TEST_SINGLE(fcvtl2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtl2 v30.8h, v29.4s"); + // TEST_SINGLE(fcvtl2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtl2 v30.16b, v29.8h"); + // TEST_SINGLE(fcvtl2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtl2 v30.8h, v29.4s"); TEST_SINGLE(fcvtl2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtl2 v30.4s, v29.8h"); TEST_SINGLE(fcvtl2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtl2 v30.2d, v29.4s"); - //TEST_SINGLE(fcvtl2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtl2 v30.16b, v29.8h"); - //TEST_SINGLE(fcvtl2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtl2 v30.8h, v29.4s"); + // TEST_SINGLE(fcvtl2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtl2 v30.16b, v29.8h"); + // TEST_SINGLE(fcvtl2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtl2 v30.8h, v29.4s"); TEST_SINGLE(fcvtl2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtl2 v30.4s, v29.8h"); TEST_SINGLE(fcvtl2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtl2 v30.2d, v29.4s"); TEST_SINGLE(frintn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frintn v30.4s, v29.4s"); TEST_SINGLE(frintn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frintn v30.2d, v29.2d"); TEST_SINGLE(frintn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frintn v30.2s, v29.2s"); - //TEST_SINGLE(frintn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintn v30.1d, v29.1d"); + // TEST_SINGLE(frintn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintn v30.1d, v29.1d"); TEST_SINGLE(frintm(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frintm v30.4s, v29.4s"); TEST_SINGLE(frintm(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frintm v30.2d, v29.2d"); TEST_SINGLE(frintm(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frintm v30.2s, v29.2s"); - //TEST_SINGLE(frintm(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintm v30.1d, v29.1d"); + // TEST_SINGLE(frintm(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintm v30.1d, v29.1d"); TEST_SINGLE(fcvtns(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtns v30.4s, v29.4s"); TEST_SINGLE(fcvtns(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtns v30.2d, v29.2d"); TEST_SINGLE(fcvtns(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtns v30.2s, v29.2s"); - //TEST_SINGLE(fcvtns(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtns v30.1d, v29.1d"); + // TEST_SINGLE(fcvtns(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtns v30.1d, v29.1d"); TEST_SINGLE(fcvtms(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtms v30.4s, v29.4s"); TEST_SINGLE(fcvtms(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtms v30.2d, v29.2d"); TEST_SINGLE(fcvtms(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtms v30.2s, v29.2s"); - //TEST_SINGLE(fcvtms(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtms v30.1d, v29.1d"); + // TEST_SINGLE(fcvtms(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtms v30.1d, v29.1d"); TEST_SINGLE(fcvtas(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtas v30.4s, v29.4s"); TEST_SINGLE(fcvtas(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtas v30.2d, v29.2d"); TEST_SINGLE(fcvtas(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtas v30.2s, v29.2s"); - //TEST_SINGLE(fcvtas(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtas v30.1d, v29.1d"); + // TEST_SINGLE(fcvtas(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtas v30.1d, v29.1d"); TEST_SINGLE(scvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29), "scvtf v30.4s, v29.4s"); TEST_SINGLE(scvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29), "scvtf v30.2d, v29.2d"); TEST_SINGLE(scvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29), "scvtf v30.2s, v29.2s"); - //TEST_SINGLE(scvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29), "scvtf v30.1d, v29.1d"); + // TEST_SINGLE(scvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29), "scvtf v30.1d, v29.1d"); TEST_SINGLE(frint32z(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frint32z v30.4s, v29.4s"); TEST_SINGLE(frint32z(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frint32z v30.2d, v29.2d"); TEST_SINGLE(frint32z(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frint32z v30.2s, v29.2s"); - //TEST_SINGLE(frint32z(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint32z v30.1d, v29.1d"); + // TEST_SINGLE(frint32z(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint32z v30.1d, v29.1d"); TEST_SINGLE(frint64z(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frint64z v30.4s, v29.4s"); TEST_SINGLE(frint64z(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frint64z v30.2d, v29.2d"); TEST_SINGLE(frint64z(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frint64z v30.2s, v29.2s"); - //TEST_SINGLE(frint64z(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint64z v30.1d, v29.1d"); + // TEST_SINGLE(frint64z(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint64z v30.1d, v29.1d"); TEST_SINGLE(fcmgt(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcmgt v30.4s, v29.4s, #0.0"); TEST_SINGLE(fcmgt(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcmgt v30.2d, v29.2d, #0.0"); TEST_SINGLE(fcmgt(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcmgt v30.2s, v29.2s, #0.0"); - //TEST_SINGLE(fcmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmgt v30.1d, v29.1d, #0.0"); + // TEST_SINGLE(fcmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmgt v30.1d, v29.1d, #0.0"); TEST_SINGLE(fcmeq(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcmeq v30.4s, v29.4s, #0.0"); TEST_SINGLE(fcmeq(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcmeq v30.2d, v29.2d, #0.0"); TEST_SINGLE(fcmeq(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcmeq v30.2s, v29.2s, #0.0"); - //TEST_SINGLE(fcmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmeq v30.1d, v29.1d, #0.0"); + // TEST_SINGLE(fcmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmeq v30.1d, v29.1d, #0.0"); TEST_SINGLE(fcmlt(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcmlt v30.4s, v29.4s, #0.0"); TEST_SINGLE(fcmlt(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcmlt v30.2d, v29.2d, #0.0"); TEST_SINGLE(fcmlt(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcmlt v30.2s, v29.2s, #0.0"); - //TEST_SINGLE(fcmlt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmlt v30.1d, v29.1d, #0.0"); + // TEST_SINGLE(fcmlt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmlt v30.1d, v29.1d, #0.0"); TEST_SINGLE(fabs(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fabs v30.4s, v29.4s"); TEST_SINGLE(fabs(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fabs v30.2d, v29.2d"); TEST_SINGLE(fabs(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fabs v30.2s, v29.2s"); - //TEST_SINGLE(fabs(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fabs v30.1d, v29.1d"); + // TEST_SINGLE(fabs(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fabs v30.1d, v29.1d"); TEST_SINGLE(frintp(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frintp v30.4s, v29.4s"); TEST_SINGLE(frintp(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frintp v30.2d, v29.2d"); TEST_SINGLE(frintp(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frintp v30.2s, v29.2s"); - //TEST_SINGLE(frintp(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintp v30.1d, v29.1d"); + // TEST_SINGLE(frintp(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintp v30.1d, v29.1d"); TEST_SINGLE(frintz(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frintz v30.4s, v29.4s"); TEST_SINGLE(frintz(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frintz v30.2d, v29.2d"); TEST_SINGLE(frintz(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frintz v30.2s, v29.2s"); - //TEST_SINGLE(frintz(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintz v30.1d, v29.1d"); + // TEST_SINGLE(frintz(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintz v30.1d, v29.1d"); TEST_SINGLE(fcvtps(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtps v30.4s, v29.4s"); TEST_SINGLE(fcvtps(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtps v30.2d, v29.2d"); TEST_SINGLE(fcvtps(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtps v30.2s, v29.2s"); - //TEST_SINGLE(fcvtps(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtps v30.1d, v29.1d"); + // TEST_SINGLE(fcvtps(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtps v30.1d, v29.1d"); TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtzs v30.4s, v29.4s"); TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtzs v30.2d, v29.2d"); TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtzs v30.2s, v29.2s"); - //TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtzs v30.1d, v29.1d"); + // TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtzs v30.1d, v29.1d"); TEST_SINGLE(urecpe(SubRegSize::i32Bit, QReg::q30, QReg::q29), "urecpe v30.4s, v29.4s"); - //TEST_SINGLE(urecpe(SubRegSize::i64Bit, QReg::q30, QReg::q29), "urecpe v30.2d, v29.2d"); + // TEST_SINGLE(urecpe(SubRegSize::i64Bit, QReg::q30, QReg::q29), "urecpe v30.2d, v29.2d"); TEST_SINGLE(urecpe(SubRegSize::i32Bit, DReg::d30, DReg::d29), "urecpe v30.2s, v29.2s"); - //TEST_SINGLE(urecpe(SubRegSize::i64Bit, DReg::d30, DReg::d29), "urecpe v30.1d, v29.1d"); + // TEST_SINGLE(urecpe(SubRegSize::i64Bit, DReg::d30, DReg::d29), "urecpe v30.1d, v29.1d"); TEST_SINGLE(frecpe(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frecpe v30.4s, v29.4s"); TEST_SINGLE(frecpe(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frecpe v30.2d, v29.2d"); TEST_SINGLE(frecpe(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frecpe v30.2s, v29.2s"); - //TEST_SINGLE(frecpe(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frecpe v30.1d, v29.1d"); + // TEST_SINGLE(frecpe(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frecpe v30.1d, v29.1d"); TEST_SINGLE(rev32(SubRegSize::i8Bit, QReg::q30, QReg::q29), "rev32 v30.16b, v29.16b"); TEST_SINGLE(rev32(SubRegSize::i16Bit, QReg::q30, QReg::q29), "rev32 v30.8h, v29.8h"); - //TEST_SINGLE(rev32(SubRegSize::i32Bit, QReg::q30, QReg::q29), "rev32 v30.4s, v29.4s"); - //TEST_SINGLE(rev32(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rev32 v30.2d, v29.2d"); + // TEST_SINGLE(rev32(SubRegSize::i32Bit, QReg::q30, QReg::q29), "rev32 v30.4s, v29.4s"); + // TEST_SINGLE(rev32(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rev32 v30.2d, v29.2d"); TEST_SINGLE(rev32(SubRegSize::i8Bit, DReg::d30, DReg::d29), "rev32 v30.8b, v29.8b"); TEST_SINGLE(rev32(SubRegSize::i16Bit, DReg::d30, DReg::d29), "rev32 v30.4h, v29.4h"); - //TEST_SINGLE(rev32(SubRegSize::i32Bit, DReg::d30, DReg::d29), "rev32 v30.2s, v29.2s"); - //TEST_SINGLE(rev32(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rev32 v30.1d, v29.1d"); + // TEST_SINGLE(rev32(SubRegSize::i32Bit, DReg::d30, DReg::d29), "rev32 v30.2s, v29.2s"); + // TEST_SINGLE(rev32(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rev32 v30.1d, v29.1d"); - //TEST_SINGLE(uaddlp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uaddlp v30.16b, v29.16b"); + // TEST_SINGLE(uaddlp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uaddlp v30.16b, v29.16b"); TEST_SINGLE(uaddlp(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uaddlp v30.8h, v29.16b"); TEST_SINGLE(uaddlp(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uaddlp v30.4s, v29.8h"); TEST_SINGLE(uaddlp(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uaddlp v30.2d, v29.4s"); - //TEST_SINGLE(uaddlp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uaddlp v30.8b, v29.8b"); + // TEST_SINGLE(uaddlp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uaddlp v30.8b, v29.8b"); TEST_SINGLE(uaddlp(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uaddlp v30.4h, v29.8b"); TEST_SINGLE(uaddlp(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uaddlp v30.2s, v29.4h"); TEST_SINGLE(uaddlp(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uaddlp v30.1d, v29.2s"); @@ -748,24 +754,24 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(usqadd(SubRegSize::i8Bit, DReg::d30, DReg::d29), "usqadd v30.8b, v29.8b"); TEST_SINGLE(usqadd(SubRegSize::i16Bit, DReg::d30, DReg::d29), "usqadd v30.4h, v29.4h"); TEST_SINGLE(usqadd(SubRegSize::i32Bit, DReg::d30, DReg::d29), "usqadd v30.2s, v29.2s"); - //TEST_SINGLE(usqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29), "usqadd v30.1d, v29.1d"); + // TEST_SINGLE(usqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29), "usqadd v30.1d, v29.1d"); TEST_SINGLE(clz(SubRegSize::i8Bit, QReg::q30, QReg::q29), "clz v30.16b, v29.16b"); TEST_SINGLE(clz(SubRegSize::i16Bit, QReg::q30, QReg::q29), "clz v30.8h, v29.8h"); TEST_SINGLE(clz(SubRegSize::i32Bit, QReg::q30, QReg::q29), "clz v30.4s, v29.4s"); - //TEST_SINGLE(clz(SubRegSize::i64Bit, QReg::q30, QReg::q29), "clz v30.2d, v29.2d"); + // TEST_SINGLE(clz(SubRegSize::i64Bit, QReg::q30, QReg::q29), "clz v30.2d, v29.2d"); TEST_SINGLE(clz(SubRegSize::i8Bit, DReg::d30, DReg::d29), "clz v30.8b, v29.8b"); TEST_SINGLE(clz(SubRegSize::i16Bit, DReg::d30, DReg::d29), "clz v30.4h, v29.4h"); TEST_SINGLE(clz(SubRegSize::i32Bit, DReg::d30, DReg::d29), "clz v30.2s, v29.2s"); - //TEST_SINGLE(clz(SubRegSize::i64Bit, DReg::d30, DReg::d29), "clz v30.1d, v29.1d"); + // TEST_SINGLE(clz(SubRegSize::i64Bit, DReg::d30, DReg::d29), "clz v30.1d, v29.1d"); - //TEST_SINGLE(uadalp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uadalp v30.16b, v29.16b"); + // TEST_SINGLE(uadalp(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uadalp v30.16b, v29.16b"); TEST_SINGLE(uadalp(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uadalp v30.8h, v29.16b"); TEST_SINGLE(uadalp(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uadalp v30.4s, v29.8h"); TEST_SINGLE(uadalp(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uadalp v30.2d, v29.4s"); - //TEST_SINGLE(uadalp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uadalp v30.8b, v29.8b"); + // TEST_SINGLE(uadalp(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uadalp v30.8b, v29.8b"); TEST_SINGLE(uadalp(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uadalp v30.4h, v29.8b"); TEST_SINGLE(uadalp(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uadalp v30.2s, v29.4h"); TEST_SINGLE(uadalp(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uadalp v30.1d, v29.2s"); @@ -778,7 +784,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(sqneg(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sqneg v30.8b, v29.8b"); TEST_SINGLE(sqneg(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sqneg v30.4h, v29.4h"); TEST_SINGLE(sqneg(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sqneg v30.2s, v29.2s"); - //TEST_SINGLE(sqneg(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqneg v30.1d, v29.1d"); + // TEST_SINGLE(sqneg(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqneg v30.1d, v29.1d"); TEST_SINGLE(cmge(SubRegSize::i8Bit, QReg::q30, QReg::q29), "cmge v30.16b, v29.16b, #0"); TEST_SINGLE(cmge(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cmge v30.8h, v29.8h, #0"); @@ -788,7 +794,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(cmge(SubRegSize::i8Bit, DReg::d30, DReg::d29), "cmge v30.8b, v29.8b, #0"); TEST_SINGLE(cmge(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cmge v30.4h, v29.4h, #0"); TEST_SINGLE(cmge(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cmge v30.2s, v29.2s, #0"); - //TEST_SINGLE(cmge(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmge v30.1d, v29.1d, #0"); + // TEST_SINGLE(cmge(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmge v30.1d, v29.1d, #0"); // TEST_SINGLE(cmle(SubRegSize::i8Bit, QReg::q30, QReg::q29), "cmle v30.16b, v29.16b, #0"); TEST_SINGLE(cmle(SubRegSize::i16Bit, QReg::q30, QReg::q29), "cmle v30.8h, v29.8h, #0"); @@ -798,7 +804,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(cmle(SubRegSize::i8Bit, DReg::d30, DReg::d29), "cmle v30.8b, v29.8b, #0"); TEST_SINGLE(cmle(SubRegSize::i16Bit, DReg::d30, DReg::d29), "cmle v30.4h, v29.4h, #0"); TEST_SINGLE(cmle(SubRegSize::i32Bit, DReg::d30, DReg::d29), "cmle v30.2s, v29.2s, #0"); - //TEST_SINGLE(cmle(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmle v30.1d, v29.1d, #0"); + // TEST_SINGLE(cmle(SubRegSize::i64Bit, DReg::d30, DReg::d29), "cmle v30.1d, v29.1d, #0"); TEST_SINGLE(neg(SubRegSize::i8Bit, QReg::q30, QReg::q29), "neg v30.16b, v29.16b"); TEST_SINGLE(neg(SubRegSize::i16Bit, QReg::q30, QReg::q29), "neg v30.8h, v29.8h"); @@ -808,34 +814,34 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(neg(SubRegSize::i8Bit, DReg::d30, DReg::d29), "neg v30.8b, v29.8b"); TEST_SINGLE(neg(SubRegSize::i16Bit, DReg::d30, DReg::d29), "neg v30.4h, v29.4h"); TEST_SINGLE(neg(SubRegSize::i32Bit, DReg::d30, DReg::d29), "neg v30.2s, v29.2s"); - //TEST_SINGLE(neg(SubRegSize::i64Bit, DReg::d30, DReg::d29), "neg v30.1d, v29.1d"); + // TEST_SINGLE(neg(SubRegSize::i64Bit, DReg::d30, DReg::d29), "neg v30.1d, v29.1d"); TEST_SINGLE(sqxtun(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sqxtun v30.8b, v29.8h"); TEST_SINGLE(sqxtun(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sqxtun v30.4h, v29.4s"); TEST_SINGLE(sqxtun(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sqxtun v30.2s, v29.2d"); - //TEST_SINGLE(sqxtun(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtun v30.2d, v29.1d"); + // TEST_SINGLE(sqxtun(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtun v30.2d, v29.1d"); TEST_SINGLE(sqxtun(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sqxtun v30.8b, v29.8h"); TEST_SINGLE(sqxtun(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sqxtun v30.4h, v29.4s"); TEST_SINGLE(sqxtun(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sqxtun v30.2s, v29.2d"); - //TEST_SINGLE(sqxtun(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtun v30.1d, v29.1d"); + // TEST_SINGLE(sqxtun(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtun v30.1d, v29.1d"); TEST_SINGLE(sqxtun2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sqxtun2 v30.16b, v29.8h"); TEST_SINGLE(sqxtun2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sqxtun2 v30.8h, v29.4s"); TEST_SINGLE(sqxtun2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sqxtun2 v30.4s, v29.2d"); - //TEST_SINGLE(sqxtun2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtun2 v30.2d, v29.1d"); + // TEST_SINGLE(sqxtun2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sqxtun2 v30.2d, v29.1d"); TEST_SINGLE(sqxtun2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sqxtun2 v30.16b, v29.8h"); TEST_SINGLE(sqxtun2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sqxtun2 v30.8h, v29.4s"); TEST_SINGLE(sqxtun2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sqxtun2 v30.4s, v29.2d"); - //TEST_SINGLE(sqxtun2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtun2 v30.2d, v29.1d"); + // TEST_SINGLE(sqxtun2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sqxtun2 v30.2d, v29.1d"); - //TEST_SINGLE(shll(SubRegSize::i8Bit, DReg::d30, DReg::d29), "shll v30.8b, v29.8b, #0"); + // TEST_SINGLE(shll(SubRegSize::i8Bit, DReg::d30, DReg::d29), "shll v30.8b, v29.8b, #0"); TEST_SINGLE(shll(SubRegSize::i16Bit, DReg::d30, DReg::d29), "shll v30.8h, v29.8b, #8"); TEST_SINGLE(shll(SubRegSize::i32Bit, DReg::d30, DReg::d29), "shll v30.4s, v29.4h, #16"); TEST_SINGLE(shll(SubRegSize::i64Bit, DReg::d30, DReg::d29), "shll v30.2d, v29.2s, #32"); - //TEST_SINGLE(shll2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "shll2 v30.16b, v29.16b, #0"); + // TEST_SINGLE(shll2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "shll2 v30.16b, v29.16b, #0"); TEST_SINGLE(shll2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "shll2 v30.8h, v29.16b, #8"); TEST_SINGLE(shll2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "shll2 v30.4s, v29.8h, #16"); TEST_SINGLE(shll2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "shll2 v30.2d, v29.4s, #32"); @@ -843,307 +849,307 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register m TEST_SINGLE(uqxtn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uqxtn v30.8b, v29.8h"); TEST_SINGLE(uqxtn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uqxtn v30.4h, v29.4s"); TEST_SINGLE(uqxtn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uqxtn v30.2s, v29.2d"); - //TEST_SINGLE(uqxtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uqxtn v30.2d, v29.1d"); + // TEST_SINGLE(uqxtn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uqxtn v30.2d, v29.1d"); TEST_SINGLE(uqxtn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uqxtn v30.8b, v29.8h"); TEST_SINGLE(uqxtn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uqxtn v30.4h, v29.4s"); TEST_SINGLE(uqxtn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uqxtn v30.2s, v29.2d"); - //TEST_SINGLE(uqxtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uqxtn v30.1d, v29.1d"); + // TEST_SINGLE(uqxtn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uqxtn v30.1d, v29.1d"); TEST_SINGLE(uqxtn2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uqxtn2 v30.16b, v29.8h"); TEST_SINGLE(uqxtn2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uqxtn2 v30.8h, v29.4s"); TEST_SINGLE(uqxtn2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uqxtn2 v30.4s, v29.2d"); - //TEST_SINGLE(uqxtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uqxtn2 v30.2d, v29.1d"); + // TEST_SINGLE(uqxtn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uqxtn2 v30.2d, v29.1d"); TEST_SINGLE(uqxtn2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uqxtn2 v30.16b, v29.8h"); TEST_SINGLE(uqxtn2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uqxtn2 v30.8h, v29.4s"); TEST_SINGLE(uqxtn2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uqxtn2 v30.4s, v29.2d"); - //TEST_SINGLE(uqxtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uqxtn2 v30.2d, v29.1d"); + // TEST_SINGLE(uqxtn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uqxtn2 v30.2d, v29.1d"); // - //TEST_SINGLE(fcvtxn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtxn v30.8b, v29.8h"); - //TEST_SINGLE(fcvtxn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtxn v30.4h, v29.4s"); + // TEST_SINGLE(fcvtxn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtxn v30.8b, v29.8h"); + // TEST_SINGLE(fcvtxn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtxn v30.4h, v29.4s"); TEST_SINGLE(fcvtxn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtxn v30.2s, v29.2d"); - //TEST_SINGLE(fcvtxn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtxn v30.2d, v29.1d"); + // TEST_SINGLE(fcvtxn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtxn v30.2d, v29.1d"); - //TEST_SINGLE(fcvtxn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtxn v30.8b, v29.8h"); - //TEST_SINGLE(fcvtxn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtxn v30.4h, v29.4s"); + // TEST_SINGLE(fcvtxn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtxn v30.8b, v29.8h"); + // TEST_SINGLE(fcvtxn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtxn v30.4h, v29.4s"); TEST_SINGLE(fcvtxn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtxn v30.2s, v29.2d"); - //TEST_SINGLE(fcvtxn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtxn v30.1d, v29.1d"); + // TEST_SINGLE(fcvtxn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtxn v30.1d, v29.1d"); - //TEST_SINGLE(fcvtxn2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtxn2 v30.16b, v29.8h"); - //TEST_SINGLE(fcvtxn2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtxn2 v30.8h, v29.4s"); + // TEST_SINGLE(fcvtxn2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fcvtxn2 v30.16b, v29.8h"); + // TEST_SINGLE(fcvtxn2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fcvtxn2 v30.8h, v29.4s"); TEST_SINGLE(fcvtxn2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtxn2 v30.4s, v29.2d"); - //TEST_SINGLE(fcvtxn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtxn2 v30.2d, v29.1d"); + // TEST_SINGLE(fcvtxn2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtxn2 v30.2d, v29.1d"); - //TEST_SINGLE(fcvtxn2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtxn2 v30.16b, v29.8h"); - //TEST_SINGLE(fcvtxn2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtxn2 v30.8h, v29.4s"); + // TEST_SINGLE(fcvtxn2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fcvtxn2 v30.16b, v29.8h"); + // TEST_SINGLE(fcvtxn2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fcvtxn2 v30.8h, v29.4s"); TEST_SINGLE(fcvtxn2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtxn2 v30.4s, v29.2d"); - //TEST_SINGLE(fcvtxn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtxn2 v30.2d, v29.1d"); + // TEST_SINGLE(fcvtxn2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtxn2 v30.2d, v29.1d"); TEST_SINGLE(frinta(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frinta v30.4s, v29.4s"); TEST_SINGLE(frinta(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frinta v30.2d, v29.2d"); TEST_SINGLE(frinta(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frinta v30.2s, v29.2s"); - //TEST_SINGLE(frinta(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frinta v30.1d, v29.1d"); + // TEST_SINGLE(frinta(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frinta v30.1d, v29.1d"); TEST_SINGLE(frintx(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frintx v30.4s, v29.4s"); TEST_SINGLE(frintx(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frintx v30.2d, v29.2d"); TEST_SINGLE(frintx(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frintx v30.2s, v29.2s"); - //TEST_SINGLE(frintx(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintx v30.1d, v29.1d"); + // TEST_SINGLE(frintx(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frintx v30.1d, v29.1d"); TEST_SINGLE(fcvtnu(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtnu v30.4s, v29.4s"); TEST_SINGLE(fcvtnu(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtnu v30.2d, v29.2d"); TEST_SINGLE(fcvtnu(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtnu v30.2s, v29.2s"); - //TEST_SINGLE(fcvtnu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtnu v30.1d, v29.1d"); + // TEST_SINGLE(fcvtnu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtnu v30.1d, v29.1d"); TEST_SINGLE(fcvtmu(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtmu v30.4s, v29.4s"); TEST_SINGLE(fcvtmu(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtmu v30.2d, v29.2d"); TEST_SINGLE(fcvtmu(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtmu v30.2s, v29.2s"); - //TEST_SINGLE(fcvtmu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtmu v30.1d, v29.1d"); + // TEST_SINGLE(fcvtmu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtmu v30.1d, v29.1d"); TEST_SINGLE(fcvtau(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtau v30.4s, v29.4s"); TEST_SINGLE(fcvtau(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtau v30.2d, v29.2d"); TEST_SINGLE(fcvtau(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtau v30.2s, v29.2s"); - //TEST_SINGLE(fcvtau(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtau v30.1d, v29.1d"); + // TEST_SINGLE(fcvtau(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtau v30.1d, v29.1d"); TEST_SINGLE(ucvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29), "ucvtf v30.4s, v29.4s"); TEST_SINGLE(ucvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29), "ucvtf v30.2d, v29.2d"); TEST_SINGLE(ucvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29), "ucvtf v30.2s, v29.2s"); - //TEST_SINGLE(ucvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29), "ucvtf v30.1d, v29.1d"); + // TEST_SINGLE(ucvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29), "ucvtf v30.1d, v29.1d"); TEST_SINGLE(frint32x(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frint32x v30.4s, v29.4s"); TEST_SINGLE(frint32x(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frint32x v30.2d, v29.2d"); TEST_SINGLE(frint32x(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frint32x v30.2s, v29.2s"); - //TEST_SINGLE(frint32x(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint32x v30.1d, v29.1d"); + // TEST_SINGLE(frint32x(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint32x v30.1d, v29.1d"); TEST_SINGLE(frint64x(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frint64x v30.4s, v29.4s"); TEST_SINGLE(frint64x(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frint64x v30.2d, v29.2d"); TEST_SINGLE(frint64x(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frint64x v30.2s, v29.2s"); - //TEST_SINGLE(frint64x(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint64x v30.1d, v29.1d"); + // TEST_SINGLE(frint64x(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frint64x v30.1d, v29.1d"); TEST_SINGLE(not_(SubRegSize::i8Bit, QReg::q30, QReg::q29), "mvn v30.16b, v29.16b"); - //TEST_SINGLE(not_(SubRegSize::i16Bit, QReg::q30, QReg::q29), "not v30.8h, v29.8h"); - //TEST_SINGLE(not_(SubRegSize::i32Bit, QReg::q30, QReg::q29), "not v30.4s, v29.4s"); - //TEST_SINGLE(not_(SubRegSize::i64Bit, QReg::q30, QReg::q29), "not v30.2d, v29.2d"); + // TEST_SINGLE(not_(SubRegSize::i16Bit, QReg::q30, QReg::q29), "not v30.8h, v29.8h"); + // TEST_SINGLE(not_(SubRegSize::i32Bit, QReg::q30, QReg::q29), "not v30.4s, v29.4s"); + // TEST_SINGLE(not_(SubRegSize::i64Bit, QReg::q30, QReg::q29), "not v30.2d, v29.2d"); TEST_SINGLE(not_(SubRegSize::i8Bit, DReg::d30, DReg::d29), "mvn v30.8b, v29.8b"); - //TEST_SINGLE(not_(SubRegSize::i16Bit, DReg::d30, DReg::d29), "not v30.4h, v29.4h"); - //TEST_SINGLE(not_(SubRegSize::i32Bit, DReg::d30, DReg::d29), "not v30.2s, v29.2s"); - //TEST_SINGLE(not_(SubRegSize::i64Bit, DReg::d30, DReg::d29), "not v30.1d, v29.1d"); + // TEST_SINGLE(not_(SubRegSize::i16Bit, DReg::d30, DReg::d29), "not v30.4h, v29.4h"); + // TEST_SINGLE(not_(SubRegSize::i32Bit, DReg::d30, DReg::d29), "not v30.2s, v29.2s"); + // TEST_SINGLE(not_(SubRegSize::i64Bit, DReg::d30, DReg::d29), "not v30.1d, v29.1d"); TEST_SINGLE(mvn(SubRegSize::i8Bit, QReg::q30, QReg::q29), "mvn v30.16b, v29.16b"); - //TEST_SINGLE(mvn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "mvn v30.8h, v29.8h"); - //TEST_SINGLE(mvn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "mvn v30.4s, v29.4s"); - //TEST_SINGLE(mvn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "mvn v30.2d, v29.2d"); + // TEST_SINGLE(mvn(SubRegSize::i16Bit, QReg::q30, QReg::q29), "mvn v30.8h, v29.8h"); + // TEST_SINGLE(mvn(SubRegSize::i32Bit, QReg::q30, QReg::q29), "mvn v30.4s, v29.4s"); + // TEST_SINGLE(mvn(SubRegSize::i64Bit, QReg::q30, QReg::q29), "mvn v30.2d, v29.2d"); TEST_SINGLE(mvn(SubRegSize::i8Bit, DReg::d30, DReg::d29), "mvn v30.8b, v29.8b"); - //TEST_SINGLE(mvn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "mvn v30.4h, v29.4h"); - //TEST_SINGLE(mvn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "mvn v30.2s, v29.2s"); - //TEST_SINGLE(mvn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "mvn v30.1d, v29.1d"); + // TEST_SINGLE(mvn(SubRegSize::i16Bit, DReg::d30, DReg::d29), "mvn v30.4h, v29.4h"); + // TEST_SINGLE(mvn(SubRegSize::i32Bit, DReg::d30, DReg::d29), "mvn v30.2s, v29.2s"); + // TEST_SINGLE(mvn(SubRegSize::i64Bit, DReg::d30, DReg::d29), "mvn v30.1d, v29.1d"); TEST_SINGLE(rbit(SubRegSize::i8Bit, QReg::q30, QReg::q29), "rbit v30.16b, v29.16b"); - //TEST_SINGLE(rbit(SubRegSize::i16Bit, QReg::q30, QReg::q29), "rbit v30.8h, v29.8h"); - //TEST_SINGLE(rbit(SubRegSize::i32Bit, QReg::q30, QReg::q29), "rbit v30.4s, v29.4s"); - //TEST_SINGLE(rbit(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rbit v30.2d, v29.2d"); + // TEST_SINGLE(rbit(SubRegSize::i16Bit, QReg::q30, QReg::q29), "rbit v30.8h, v29.8h"); + // TEST_SINGLE(rbit(SubRegSize::i32Bit, QReg::q30, QReg::q29), "rbit v30.4s, v29.4s"); + // TEST_SINGLE(rbit(SubRegSize::i64Bit, QReg::q30, QReg::q29), "rbit v30.2d, v29.2d"); TEST_SINGLE(rbit(SubRegSize::i8Bit, DReg::d30, DReg::d29), "rbit v30.8b, v29.8b"); - //TEST_SINGLE(rbit(SubRegSize::i16Bit, DReg::d30, DReg::d29), "rbit v30.4h, v29.4h"); - //TEST_SINGLE(rbit(SubRegSize::i32Bit, DReg::d30, DReg::d29), "rbit v30.2s, v29.2s"); - //TEST_SINGLE(rbit(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rbit v30.1d, v29.1d"); + // TEST_SINGLE(rbit(SubRegSize::i16Bit, DReg::d30, DReg::d29), "rbit v30.4h, v29.4h"); + // TEST_SINGLE(rbit(SubRegSize::i32Bit, DReg::d30, DReg::d29), "rbit v30.2s, v29.2s"); + // TEST_SINGLE(rbit(SubRegSize::i64Bit, DReg::d30, DReg::d29), "rbit v30.1d, v29.1d"); TEST_SINGLE(fcmge(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcmge v30.4s, v29.4s, #0.0"); TEST_SINGLE(fcmge(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcmge v30.2d, v29.2d, #0.0"); TEST_SINGLE(fcmge(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcmge v30.2s, v29.2s, #0.0"); - //TEST_SINGLE(fcmge(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmge v30.1d, v29.1d, #0.0"); + // TEST_SINGLE(fcmge(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmge v30.1d, v29.1d, #0.0"); TEST_SINGLE(fcmle(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcmle v30.4s, v29.4s, #0.0"); TEST_SINGLE(fcmle(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcmle v30.2d, v29.2d, #0.0"); TEST_SINGLE(fcmle(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcmle v30.2s, v29.2s, #0.0"); - //TEST_SINGLE(fcmle(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmle v30.1d, v29.1d, #0.0"); + // TEST_SINGLE(fcmle(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcmle v30.1d, v29.1d, #0.0"); TEST_SINGLE(fneg(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fneg v30.4s, v29.4s"); TEST_SINGLE(fneg(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fneg v30.2d, v29.2d"); TEST_SINGLE(fneg(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fneg v30.2s, v29.2s"); - //TEST_SINGLE(fneg(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fneg v30.1d, v29.1d"); + // TEST_SINGLE(fneg(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fneg v30.1d, v29.1d"); TEST_SINGLE(frinti(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frinti v30.4s, v29.4s"); TEST_SINGLE(frinti(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frinti v30.2d, v29.2d"); TEST_SINGLE(frinti(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frinti v30.2s, v29.2s"); - //TEST_SINGLE(frinti(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frinti v30.1d, v29.1d"); + // TEST_SINGLE(frinti(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frinti v30.1d, v29.1d"); TEST_SINGLE(fcvtpu(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtpu v30.4s, v29.4s"); TEST_SINGLE(fcvtpu(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtpu v30.2d, v29.2d"); TEST_SINGLE(fcvtpu(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtpu v30.2s, v29.2s"); - //TEST_SINGLE(fcvtpu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtpu v30.1d, v29.1d"); + // TEST_SINGLE(fcvtpu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtpu v30.1d, v29.1d"); TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fcvtzu v30.4s, v29.4s"); TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fcvtzu v30.2d, v29.2d"); TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fcvtzu v30.2s, v29.2s"); - //TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtzu v30.1d, v29.1d"); + // TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fcvtzu v30.1d, v29.1d"); TEST_SINGLE(ursqrte(SubRegSize::i32Bit, QReg::q30, QReg::q29), "ursqrte v30.4s, v29.4s"); - //TEST_SINGLE(ursqrte(SubRegSize::i64Bit, QReg::q30, QReg::q29), "ursqrte v30.2d, v29.2d"); + // TEST_SINGLE(ursqrte(SubRegSize::i64Bit, QReg::q30, QReg::q29), "ursqrte v30.2d, v29.2d"); TEST_SINGLE(ursqrte(SubRegSize::i32Bit, DReg::d30, DReg::d29), "ursqrte v30.2s, v29.2s"); - //TEST_SINGLE(ursqrte(SubRegSize::i64Bit, DReg::d30, DReg::d29), "ursqrte v30.1d, v29.1d"); + // TEST_SINGLE(ursqrte(SubRegSize::i64Bit, DReg::d30, DReg::d29), "ursqrte v30.1d, v29.1d"); TEST_SINGLE(frsqrte(SubRegSize::i32Bit, QReg::q30, QReg::q29), "frsqrte v30.4s, v29.4s"); TEST_SINGLE(frsqrte(SubRegSize::i64Bit, QReg::q30, QReg::q29), "frsqrte v30.2d, v29.2d"); TEST_SINGLE(frsqrte(SubRegSize::i32Bit, DReg::d30, DReg::d29), "frsqrte v30.2s, v29.2s"); - //TEST_SINGLE(frsqrte(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frsqrte v30.1d, v29.1d"); + // TEST_SINGLE(frsqrte(SubRegSize::i64Bit, DReg::d30, DReg::d29), "frsqrte v30.1d, v29.1d"); TEST_SINGLE(fsqrt(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fsqrt v30.4s, v29.4s"); TEST_SINGLE(fsqrt(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fsqrt v30.2d, v29.2d"); TEST_SINGLE(fsqrt(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fsqrt v30.2s, v29.2s"); - //TEST_SINGLE(fsqrt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fsqrt v30.1d, v29.1d"); + // TEST_SINGLE(fsqrt(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fsqrt v30.1d, v29.1d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD across lanes") { - //TEST_SINGLE(saddlv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "saddlv v30.16b, v29.16b"); + // TEST_SINGLE(saddlv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "saddlv v30.16b, v29.16b"); TEST_SINGLE(saddlv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "saddlv h30, v29.16b"); TEST_SINGLE(saddlv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "saddlv s30, v29.8h"); TEST_SINGLE(saddlv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "saddlv d30, v29.4s"); - //TEST_SINGLE(saddlv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "saddlv v30.8b, v29.8b"); + // TEST_SINGLE(saddlv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "saddlv v30.8b, v29.8b"); TEST_SINGLE(saddlv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "saddlv h30, v29.8b"); TEST_SINGLE(saddlv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "saddlv s30, v29.4h"); - //TEST_SINGLE(saddlv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "saddlv d30, v29.1d"); + // TEST_SINGLE(saddlv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "saddlv d30, v29.1d"); TEST_SINGLE(smaxv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "smaxv b30, v29.16b"); TEST_SINGLE(smaxv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "smaxv h30, v29.8h"); TEST_SINGLE(smaxv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "smaxv s30, v29.4s"); - //TEST_SINGLE(smaxv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "smaxv d30, v29.4s"); + // TEST_SINGLE(smaxv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "smaxv d30, v29.4s"); TEST_SINGLE(smaxv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "smaxv b30, v29.8b"); TEST_SINGLE(smaxv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "smaxv h30, v29.4h"); - //TEST_SINGLE(smaxv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "smaxv s30, v29.2s"); - //TEST_SINGLE(smaxv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "smaxv d30, v29.1d"); + // TEST_SINGLE(smaxv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "smaxv s30, v29.2s"); + // TEST_SINGLE(smaxv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "smaxv d30, v29.1d"); TEST_SINGLE(sminv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sminv b30, v29.16b"); TEST_SINGLE(sminv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sminv h30, v29.8h"); TEST_SINGLE(sminv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sminv s30, v29.4s"); - //TEST_SINGLE(sminv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sminv d30, v29.4s"); + // TEST_SINGLE(sminv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sminv d30, v29.4s"); TEST_SINGLE(sminv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sminv b30, v29.8b"); TEST_SINGLE(sminv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sminv h30, v29.4h"); - //TEST_SINGLE(sminv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sminv s30, v29.2s"); - //TEST_SINGLE(sminv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sminv d30, v29.1d"); + // TEST_SINGLE(sminv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sminv s30, v29.2s"); + // TEST_SINGLE(sminv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sminv d30, v29.1d"); TEST_SINGLE(addv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "addv b30, v29.16b"); TEST_SINGLE(addv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "addv h30, v29.8h"); TEST_SINGLE(addv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "addv s30, v29.4s"); - //TEST_SINGLE(addv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "addv d30, v29.4s"); + // TEST_SINGLE(addv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "addv d30, v29.4s"); TEST_SINGLE(addv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "addv b30, v29.8b"); TEST_SINGLE(addv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "addv h30, v29.4h"); - //TEST_SINGLE(addv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "addv s30, v29.2s"); - //TEST_SINGLE(addv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "addv d30, v29.1d"); + // TEST_SINGLE(addv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "addv s30, v29.2s"); + // TEST_SINGLE(addv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "addv d30, v29.1d"); - //TEST_SINGLE(uaddlv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uaddlv v30.16b, v29.16b"); + // TEST_SINGLE(uaddlv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uaddlv v30.16b, v29.16b"); TEST_SINGLE(uaddlv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uaddlv h30, v29.16b"); TEST_SINGLE(uaddlv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uaddlv s30, v29.8h"); TEST_SINGLE(uaddlv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uaddlv d30, v29.4s"); - //TEST_SINGLE(uaddlv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uaddlv v30.8b, v29.8b"); + // TEST_SINGLE(uaddlv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uaddlv v30.8b, v29.8b"); TEST_SINGLE(uaddlv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uaddlv h30, v29.8b"); TEST_SINGLE(uaddlv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uaddlv s30, v29.4h"); - //TEST_SINGLE(uaddlv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uaddlv d30, v29.1d"); + // TEST_SINGLE(uaddlv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uaddlv d30, v29.1d"); TEST_SINGLE(umaxv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "umaxv b30, v29.16b"); TEST_SINGLE(umaxv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "umaxv h30, v29.8h"); TEST_SINGLE(umaxv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "umaxv s30, v29.4s"); - //TEST_SINGLE(umaxv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "umaxv d30, v29.4s"); + // TEST_SINGLE(umaxv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "umaxv d30, v29.4s"); TEST_SINGLE(umaxv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "umaxv b30, v29.8b"); TEST_SINGLE(umaxv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "umaxv h30, v29.4h"); - //TEST_SINGLE(umaxv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "umaxv s30, v29.2s"); - //TEST_SINGLE(umaxv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "umaxv d30, v29.1d"); + // TEST_SINGLE(umaxv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "umaxv s30, v29.2s"); + // TEST_SINGLE(umaxv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "umaxv d30, v29.1d"); TEST_SINGLE(uminv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uminv b30, v29.16b"); TEST_SINGLE(uminv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uminv h30, v29.8h"); TEST_SINGLE(uminv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uminv s30, v29.4s"); - //TEST_SINGLE(uminv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uminv d30, v29.4s"); + // TEST_SINGLE(uminv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uminv d30, v29.4s"); TEST_SINGLE(uminv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uminv b30, v29.8b"); TEST_SINGLE(uminv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uminv h30, v29.4h"); - //TEST_SINGLE(uminv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uminv s30, v29.2s"); - //TEST_SINGLE(uminv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uminv d30, v29.1d"); + // TEST_SINGLE(uminv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uminv s30, v29.2s"); + // TEST_SINGLE(uminv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uminv d30, v29.1d"); - //TEST_SINGLE(fmaxnmv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fmaxnmv b30, v29.16b"); + // TEST_SINGLE(fmaxnmv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fmaxnmv b30, v29.16b"); TEST_SINGLE(fmaxnmv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fmaxnmv h30, v29.8h"); TEST_SINGLE(fmaxnmv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fmaxnmv s30, v29.4s"); - //TEST_SINGLE(fmaxnmv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fmaxnmv d30, v29.4s"); + // TEST_SINGLE(fmaxnmv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fmaxnmv d30, v29.4s"); - //TEST_SINGLE(fmaxnmv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fmaxnmv b30, v29.8b"); + // TEST_SINGLE(fmaxnmv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fmaxnmv b30, v29.8b"); TEST_SINGLE(fmaxnmv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fmaxnmv h30, v29.4h"); - //TEST_SINGLE(fmaxnmv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fmaxnmv s30, v29.2s"); - //TEST_SINGLE(fmaxnmv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fmaxnmv d30, v29.1d"); + // TEST_SINGLE(fmaxnmv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fmaxnmv s30, v29.2s"); + // TEST_SINGLE(fmaxnmv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fmaxnmv d30, v29.1d"); - //TEST_SINGLE(fmaxv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fmaxv b30, v29.16b"); + // TEST_SINGLE(fmaxv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fmaxv b30, v29.16b"); TEST_SINGLE(fmaxv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fmaxv h30, v29.8h"); TEST_SINGLE(fmaxv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fmaxv s30, v29.4s"); - //TEST_SINGLE(fmaxv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fmaxv d30, v29.4s"); + // TEST_SINGLE(fmaxv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fmaxv d30, v29.4s"); - //TEST_SINGLE(fmaxv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fmaxv b30, v29.8b"); + // TEST_SINGLE(fmaxv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fmaxv b30, v29.8b"); TEST_SINGLE(fmaxv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fmaxv h30, v29.4h"); - //TEST_SINGLE(fmaxv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fmaxv s30, v29.2s"); - //TEST_SINGLE(fmaxv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fmaxv d30, v29.1d"); + // TEST_SINGLE(fmaxv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fmaxv s30, v29.2s"); + // TEST_SINGLE(fmaxv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fmaxv d30, v29.1d"); - //TEST_SINGLE(fminnmv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fminnmv b30, v29.16b"); + // TEST_SINGLE(fminnmv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fminnmv b30, v29.16b"); TEST_SINGLE(fminnmv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fminnmv h30, v29.8h"); TEST_SINGLE(fminnmv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fminnmv s30, v29.4s"); - //TEST_SINGLE(fminnmv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fminnmv d30, v29.4s"); + // TEST_SINGLE(fminnmv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fminnmv d30, v29.4s"); - //TEST_SINGLE(fminnmv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fminnmv b30, v29.8b"); + // TEST_SINGLE(fminnmv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fminnmv b30, v29.8b"); TEST_SINGLE(fminnmv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fminnmv h30, v29.4h"); - //TEST_SINGLE(fminnmv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fminnmv s30, v29.2s"); - //TEST_SINGLE(fminnmv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fminnmv d30, v29.1d"); + // TEST_SINGLE(fminnmv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fminnmv s30, v29.2s"); + // TEST_SINGLE(fminnmv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fminnmv d30, v29.1d"); - //TEST_SINGLE(fminv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fminv b30, v29.16b"); + // TEST_SINGLE(fminv(SubRegSize::i8Bit, QReg::q30, QReg::q29), "fminv b30, v29.16b"); TEST_SINGLE(fminv(SubRegSize::i16Bit, QReg::q30, QReg::q29), "fminv h30, v29.8h"); TEST_SINGLE(fminv(SubRegSize::i32Bit, QReg::q30, QReg::q29), "fminv s30, v29.4s"); - //TEST_SINGLE(fminv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fminv d30, v29.4s"); + // TEST_SINGLE(fminv(SubRegSize::i64Bit, QReg::q30, QReg::q29), "fminv d30, v29.4s"); - //TEST_SINGLE(fminv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fminv b30, v29.8b"); + // TEST_SINGLE(fminv(SubRegSize::i8Bit, DReg::d30, DReg::d29), "fminv b30, v29.8b"); TEST_SINGLE(fminv(SubRegSize::i16Bit, DReg::d30, DReg::d29), "fminv h30, v29.4h"); - //TEST_SINGLE(fminv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fminv s30, v29.2s"); - //TEST_SINGLE(fminv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fminv d30, v29.1d"); + // TEST_SINGLE(fminv(SubRegSize::i32Bit, DReg::d30, DReg::d29), "fminv s30, v29.2s"); + // TEST_SINGLE(fminv(SubRegSize::i64Bit, DReg::d30, DReg::d29), "fminv d30, v29.1d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three different") { - //TEST_SINGLE(saddl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "saddl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(saddl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "saddl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(saddl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "saddl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(saddl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "saddl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(saddl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "saddl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(saddl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "saddl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(saddl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "saddl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(saddl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "saddl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(saddl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "saddl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(saddl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "saddl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(saddw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "saddw v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(saddw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "saddw v30.8b, v29.8b, v28.8b"); TEST_SINGLE(saddw(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "saddw v30.8h, v29.8h, v28.8b"); TEST_SINGLE(saddw(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "saddw v30.4s, v29.4s, v28.4h"); TEST_SINGLE(saddw(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "saddw v30.2d, v29.2d, v28.2s"); - //TEST_SINGLE(saddw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "saddw2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(saddw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "saddw2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(saddw2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "saddw2 v30.8h, v29.8h, v28.16b"); TEST_SINGLE(saddw2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "saddw2 v30.4s, v29.4s, v28.8h"); TEST_SINGLE(saddw2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "saddw2 v30.2d, v29.2d, v28.4s"); - //TEST_SINGLE(ssubl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "ssubl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(ssubl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "ssubl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(ssubl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "ssubl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(ssubl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "ssubl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(ssubl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "ssubl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(ssubl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "ssubl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(ssubl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "ssubl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(ssubl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "ssubl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(ssubl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "ssubl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(ssubl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "ssubl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(ssubw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "ssubw v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(ssubw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "ssubw v30.8b, v29.8b, v28.8b"); TEST_SINGLE(ssubw(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "ssubw v30.8h, v29.8h, v28.8b"); TEST_SINGLE(ssubw(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "ssubw v30.4s, v29.4s, v28.4h"); TEST_SINGLE(ssubw(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "ssubw v30.2d, v29.2d, v28.2s"); - //TEST_SINGLE(ssubw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "ssubw2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(ssubw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "ssubw2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(ssubw2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "ssubw2 v30.8h, v29.8h, v28.16b"); TEST_SINGLE(ssubw2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "ssubw2 v30.4s, v29.4s, v28.8h"); TEST_SINGLE(ssubw2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "ssubw2 v30.2d, v29.2d, v28.4s"); @@ -1151,19 +1157,19 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three differen TEST_SINGLE(addhn(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "addhn v30.8b, v29.8h, v28.8h"); TEST_SINGLE(addhn(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "addhn v30.4h, v29.4s, v28.4s"); TEST_SINGLE(addhn(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "addhn v30.2s, v29.2d, v28.2d"); - //TEST_SINGLE(addhn(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "addhn v30.2d, v29.2d, v28.2s"); + // TEST_SINGLE(addhn(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "addhn v30.2d, v29.2d, v28.2s"); TEST_SINGLE(addhn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "addhn2 v30.16b, v29.8h, v28.8h"); TEST_SINGLE(addhn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "addhn2 v30.8h, v29.4s, v28.4s"); TEST_SINGLE(addhn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "addhn2 v30.4s, v29.2d, v28.2d"); - //TEST_SINGLE(addhn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "addhn2 v30.2d, v29.2d, v28.4s"); + // TEST_SINGLE(addhn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "addhn2 v30.2d, v29.2d, v28.4s"); - //TEST_SINGLE(sabal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sabal v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sabal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sabal v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sabal(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sabal v30.8h, v29.8b, v28.8b"); TEST_SINGLE(sabal(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sabal v30.4s, v29.4h, v28.4h"); TEST_SINGLE(sabal(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sabal v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(sabal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sabal2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sabal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sabal2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sabal2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sabal2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(sabal2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sabal2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(sabal2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sabal2 v30.2d, v29.4s, v28.4s"); @@ -1171,208 +1177,208 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three differen TEST_SINGLE(subhn(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "subhn v30.8b, v29.8h, v28.8h"); TEST_SINGLE(subhn(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "subhn v30.4h, v29.4s, v28.4s"); TEST_SINGLE(subhn(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "subhn v30.2s, v29.2d, v28.2d"); - //TEST_SINGLE(subhn(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "subhn v30.2d, v29.2d, v28.2s"); + // TEST_SINGLE(subhn(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "subhn v30.2d, v29.2d, v28.2s"); TEST_SINGLE(subhn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "subhn2 v30.16b, v29.8h, v28.8h"); TEST_SINGLE(subhn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "subhn2 v30.8h, v29.4s, v28.4s"); TEST_SINGLE(subhn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "subhn2 v30.4s, v29.2d, v28.2d"); - //TEST_SINGLE(subhn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "subhn2 v30.2d, v29.2d, v28.4s"); + // TEST_SINGLE(subhn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "subhn2 v30.2d, v29.2d, v28.4s"); - //TEST_SINGLE(sabdl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sabdl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sabdl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sabdl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sabdl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sabdl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(sabdl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sabdl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(sabdl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sabdl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(sabdl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sabdl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sabdl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sabdl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sabdl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sabdl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(sabdl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sabdl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(sabdl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sabdl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(smlal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smlal v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(smlal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smlal v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smlal(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "smlal v30.8h, v29.8b, v28.8b"); TEST_SINGLE(smlal(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "smlal v30.4s, v29.4h, v28.4h"); TEST_SINGLE(smlal(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smlal v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(smlal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smlal2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(smlal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smlal2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smlal2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "smlal2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(smlal2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "smlal2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(smlal2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smlal2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(sqdmlal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlal v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(sqdmlal(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlal v30.8h, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmlal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlal v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmlal(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlal v30.8h, v29.8b, v28.8b"); TEST_SINGLE(sqdmlal(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlal v30.4s, v29.4h, v28.4h"); TEST_SINGLE(sqdmlal(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlal v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(sqdmlal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlal2 v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(sqdmlal2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlal2 v30.8h, v29.16b, v28.16b"); + // TEST_SINGLE(sqdmlal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlal2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmlal2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlal2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(sqdmlal2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlal2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(sqdmlal2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlal2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(smlsl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smlsl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(smlsl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smlsl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smlsl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "smlsl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(smlsl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "smlsl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(smlsl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smlsl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(smlsl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smlsl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(smlsl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smlsl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smlsl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "smlsl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(smlsl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "smlsl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(smlsl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smlsl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(sqdmlsl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlsl v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(sqdmlsl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlsl v30.8h, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmlsl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlsl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmlsl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlsl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(sqdmlsl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlsl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(sqdmlsl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmlsl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(sqdmlsl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlsl2 v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(sqdmlsl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlsl2 v30.8h, v29.16b, v28.16b"); + // TEST_SINGLE(sqdmlsl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlsl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmlsl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlsl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(sqdmlsl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlsl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(sqdmlsl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmlsl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(smull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smull v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(smull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smull v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smull(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "smull v30.8h, v29.8b, v28.8b"); TEST_SINGLE(smull(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "smull v30.4s, v29.4h, v28.4h"); TEST_SINGLE(smull(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smull v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(smull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smull2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(smull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smull2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smull2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "smull2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(smull2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "smull2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(smull2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smull2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(sqdmull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmull v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(sqdmull(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmull v30.8h, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmull v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmull(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmull v30.8h, v29.8b, v28.8b"); TEST_SINGLE(sqdmull(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmull v30.4s, v29.4h, v28.4h"); TEST_SINGLE(sqdmull(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmull v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(sqdmull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmull2 v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(sqdmull2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmull2 v30.8h, v29.16b, v28.16b"); + // TEST_SINGLE(sqdmull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmull2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmull2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmull2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(sqdmull2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmull2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(sqdmull2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmull2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(pmull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(pmull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.8b, v29.8b, v28.8b"); TEST_SINGLE(pmull(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.8h, v29.8b, v28.8b"); - //TEST_SINGLE(pmull(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.4s, v29.4h, v28.4h"); - //TEST_SINGLE(pmull(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.2d, v29.2s, v28.2s"); + // TEST_SINGLE(pmull(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.4s, v29.4h, v28.4h"); + // TEST_SINGLE(pmull(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.2d, v29.2s, v28.2s"); if (false) { // Vixl doesn't support this TEST_SINGLE(pmull(SubRegSize::i128Bit, DReg::d30, DReg::d29, DReg::d28), "pmull v30.1q, v29.1d, v28.1d"); } - //TEST_SINGLE(pmull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(pmull2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.8h, v29.16b, v28.16b"); - //TEST_SINGLE(pmull2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.4s, v29.8h, v28.8h"); - //TEST_SINGLE(pmull2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.2d, v29.4s, v28.4s"); + // TEST_SINGLE(pmull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(pmull2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.8h, v29.16b, v28.16b"); + // TEST_SINGLE(pmull2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.4s, v29.8h, v28.8h"); + // TEST_SINGLE(pmull2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.2d, v29.4s, v28.4s"); if (false) { // Vixl doesn't support this TEST_SINGLE(pmull2(SubRegSize::i128Bit, QReg::q30, QReg::q29, QReg::q28), "pmull2 v30.1q, v29.2d, v28.2d"); } - //TEST_SINGLE(uaddl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uaddl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uaddl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uaddl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uaddl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uaddl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(uaddl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uaddl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(uaddl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uaddl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(uaddl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uaddl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uaddl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uaddl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uaddl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uaddl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(uaddl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uaddl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(uaddl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uaddl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(uaddw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uaddw v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uaddw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uaddw v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uaddw(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uaddw v30.8h, v29.8h, v28.8b"); TEST_SINGLE(uaddw(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uaddw v30.4s, v29.4s, v28.4h"); TEST_SINGLE(uaddw(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uaddw v30.2d, v29.2d, v28.2s"); - //TEST_SINGLE(uaddw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uaddw2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uaddw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uaddw2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uaddw2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uaddw2 v30.8h, v29.8h, v28.16b"); TEST_SINGLE(uaddw2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uaddw2 v30.4s, v29.4s, v28.8h"); TEST_SINGLE(uaddw2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uaddw2 v30.2d, v29.2d, v28.4s"); - //TEST_SINGLE(usubl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "usubl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(usubl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "usubl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(usubl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "usubl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(usubl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "usubl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(usubl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "usubl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(usubl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "usubl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(usubl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "usubl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(usubl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "usubl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(usubl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "usubl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(usubl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "usubl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(usubw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "usubw v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(usubw(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "usubw v30.8b, v29.8b, v28.8b"); TEST_SINGLE(usubw(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "usubw v30.8h, v29.8h, v28.8b"); TEST_SINGLE(usubw(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "usubw v30.4s, v29.4s, v28.4h"); TEST_SINGLE(usubw(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "usubw v30.2d, v29.2d, v28.2s"); - //TEST_SINGLE(usubw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "usubw2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(usubw2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "usubw2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(usubw2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "usubw2 v30.8h, v29.8h, v28.16b"); TEST_SINGLE(usubw2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "usubw2 v30.4s, v29.4s, v28.8h"); TEST_SINGLE(usubw2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "usubw2 v30.2d, v29.2d, v28.4s"); //// XXX: RADDHN/2 - //TEST_SINGLE(uabal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uabal v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uabal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uabal v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uabal(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uabal v30.8h, v29.8b, v28.8b"); TEST_SINGLE(uabal(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uabal v30.4s, v29.4h, v28.4h"); TEST_SINGLE(uabal(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uabal v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(uabal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uabal2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uabal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uabal2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uabal2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uabal2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(uabal2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uabal2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(uabal2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uabal2 v30.2d, v29.4s, v28.4s"); //// XXX: RSUBHN/2 - //TEST_SINGLE(uabdl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uabdl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uabdl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uabdl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uabdl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uabdl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(uabdl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uabdl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(uabdl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uabdl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(uabdl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uabdl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(uabdl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uabdl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uabdl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uabdl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(uabdl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uabdl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(uabdl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uabdl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(umlal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umlal v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(umlal(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umlal v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umlal(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "umlal v30.8h, v29.8b, v28.8b"); TEST_SINGLE(umlal(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "umlal v30.4s, v29.4h, v28.4h"); TEST_SINGLE(umlal(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umlal v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(umlal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umlal2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(umlal2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umlal2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umlal2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "umlal2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(umlal2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "umlal2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(umlal2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umlal2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(umlsl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umlsl v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(umlsl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umlsl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umlsl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "umlsl v30.8h, v29.8b, v28.8b"); TEST_SINGLE(umlsl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "umlsl v30.4s, v29.4h, v28.4h"); TEST_SINGLE(umlsl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umlsl v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(umlsl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umlsl2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(umlsl2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umlsl2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umlsl2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "umlsl2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(umlsl2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "umlsl2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(umlsl2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umlsl2 v30.2d, v29.4s, v28.4s"); - //TEST_SINGLE(umull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umull v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(umull(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umull v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umull(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "umull v30.8h, v29.8b, v28.8b"); TEST_SINGLE(umull(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "umull v30.4s, v29.4h, v28.4h"); TEST_SINGLE(umull(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umull v30.2d, v29.2s, v28.2s"); - //TEST_SINGLE(umull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umull2 v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(umull2(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umull2 v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umull2(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "umull2 v30.8h, v29.16b, v28.16b"); TEST_SINGLE(umull2(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "umull2 v30.4s, v29.8h, v28.8h"); TEST_SINGLE(umull2(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umull2 v30.2d, v29.4s, v28.4s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { - TEST_SINGLE(shadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "shadd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(shadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "shadd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(shadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "shadd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(shadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "shadd v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(shadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "shadd v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(shadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "shadd v30.2d, v29.2d, v28.2d"); TEST_SINGLE(shadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "shadd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(shadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "shadd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(shadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "shadd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(shadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "shadd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(shadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "shadd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sqadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqadd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sqadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqadd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sqadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqadd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sqadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqadd v30.4s, v29.4s, v28.4s"); TEST_SINGLE(sqadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqadd v30.2d, v29.2d, v28.2d"); @@ -1380,29 +1386,29 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(sqadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqadd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqadd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqadd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqadd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqadd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(srhadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "srhadd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(srhadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "srhadd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(srhadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "srhadd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(srhadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "srhadd v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(srhadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "srhadd v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(srhadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "srhadd v30.2d, v29.2d, v28.2d"); TEST_SINGLE(srhadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "srhadd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(srhadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "srhadd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(srhadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "srhadd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(srhadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "srhadd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(srhadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "srhadd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(shsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "shsub v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(shsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "shsub v30.16b, v29.16b, v28.16b"); TEST_SINGLE(shsub(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "shsub v30.8h, v29.8h, v28.8h"); TEST_SINGLE(shsub(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "shsub v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(shsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "shsub v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(shsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "shsub v30.2d, v29.2d, v28.2d"); TEST_SINGLE(shsub(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "shsub v30.8b, v29.8b, v28.8b"); TEST_SINGLE(shsub(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "shsub v30.4h, v29.4h, v28.4h"); TEST_SINGLE(shsub(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "shsub v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(shsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "shsub v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(shsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "shsub v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sqsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqsub v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sqsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqsub v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sqsub(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqsub v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sqsub(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqsub v30.4s, v29.4s, v28.4s"); TEST_SINGLE(sqsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqsub v30.2d, v29.2d, v28.2d"); @@ -1410,9 +1416,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(sqsub(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqsub v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqsub(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqsub v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqsub(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqsub v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqsub v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqsub v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(cmgt(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmgt v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(cmgt(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmgt v30.16b, v29.16b, v28.16b"); TEST_SINGLE(cmgt(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "cmgt v30.8h, v29.8h, v28.8h"); TEST_SINGLE(cmgt(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "cmgt v30.4s, v29.4s, v28.4s"); TEST_SINGLE(cmgt(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "cmgt v30.2d, v29.2d, v28.2d"); @@ -1420,9 +1426,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(cmgt(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "cmgt v30.8b, v29.8b, v28.8b"); TEST_SINGLE(cmgt(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "cmgt v30.4h, v29.4h, v28.4h"); TEST_SINGLE(cmgt(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "cmgt v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(cmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmgt v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(cmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmgt v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(cmge(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmge v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(cmge(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmge v30.16b, v29.16b, v28.16b"); TEST_SINGLE(cmge(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "cmge v30.8h, v29.8h, v28.8h"); TEST_SINGLE(cmge(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "cmge v30.4s, v29.4s, v28.4s"); TEST_SINGLE(cmge(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "cmge v30.2d, v29.2d, v28.2d"); @@ -1430,9 +1436,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(cmge(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "cmge v30.8b, v29.8b, v28.8b"); TEST_SINGLE(cmge(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "cmge v30.4h, v29.4h, v28.4h"); TEST_SINGLE(cmge(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "cmge v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(cmge(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmge v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(cmge(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmge v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sshl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sshl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sshl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sshl v30.4s, v29.4s, v28.4s"); TEST_SINGLE(sshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sshl v30.2d, v29.2d, v28.2d"); @@ -1440,9 +1446,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(sshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sshl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sshl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sshl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sshl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sshl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqshl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqshl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqshl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqshl v30.4s, v29.4s, v28.4s"); TEST_SINGLE(sqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqshl v30.2d, v29.2d, v28.2d"); @@ -1450,9 +1456,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(sqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqshl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqshl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqshl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqshl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqshl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(srshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "srshl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(srshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "srshl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(srshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "srshl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(srshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "srshl v30.4s, v29.4s, v28.4s"); TEST_SINGLE(srshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "srshl v30.2d, v29.2d, v28.2d"); @@ -1460,9 +1466,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(srshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "srshl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(srshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "srshl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(srshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "srshl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(srshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "srshl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(srshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "srshl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sqrshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqrshl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sqrshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqrshl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sqrshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqrshl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sqrshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqrshl v30.4s, v29.4s, v28.4s"); TEST_SINGLE(sqrshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqrshl v30.2d, v29.2d, v28.2d"); @@ -1470,49 +1476,49 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(sqrshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqrshl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqrshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqrshl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqrshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqrshl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqrshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrshl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqrshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrshl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(smax(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smax v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(smax(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smax v30.16b, v29.16b, v28.16b"); TEST_SINGLE(smax(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "smax v30.8h, v29.8h, v28.8h"); TEST_SINGLE(smax(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "smax v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(smax(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smax v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(smax(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smax v30.2d, v29.2d, v28.2d"); TEST_SINGLE(smax(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smax v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smax(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "smax v30.4h, v29.4h, v28.4h"); TEST_SINGLE(smax(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "smax v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(smax(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smax v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(smax(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smax v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(smin(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smin v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(smin(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smin v30.16b, v29.16b, v28.16b"); TEST_SINGLE(smin(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "smin v30.8h, v29.8h, v28.8h"); TEST_SINGLE(smin(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "smin v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(smin(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smin v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(smin(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smin v30.2d, v29.2d, v28.2d"); TEST_SINGLE(smin(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smin v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smin(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "smin v30.4h, v29.4h, v28.4h"); TEST_SINGLE(smin(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "smin v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(smin(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smin v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(smin(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smin v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sabd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sabd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sabd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sabd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sabd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sabd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sabd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sabd v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(sabd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sabd v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(sabd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sabd v30.2d, v29.2d, v28.2d"); TEST_SINGLE(sabd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sabd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sabd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sabd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sabd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sabd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sabd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sabd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sabd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sabd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(saba(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "saba v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(saba(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "saba v30.16b, v29.16b, v28.16b"); TEST_SINGLE(saba(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "saba v30.8h, v29.8h, v28.8h"); TEST_SINGLE(saba(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "saba v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(saba(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "saba v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(saba(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "saba v30.2d, v29.2d, v28.2d"); TEST_SINGLE(saba(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "saba v30.8b, v29.8b, v28.8b"); TEST_SINGLE(saba(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "saba v30.4h, v29.4h, v28.4h"); TEST_SINGLE(saba(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "saba v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(saba(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "saba v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(saba(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "saba v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(add(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "add v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(add(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "add v30.16b, v29.16b, v28.16b"); TEST_SINGLE(add(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "add v30.8h, v29.8h, v28.8h"); TEST_SINGLE(add(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "add v30.4s, v29.4s, v28.4s"); TEST_SINGLE(add(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "add v30.2d, v29.2d, v28.2d"); @@ -1520,9 +1526,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(add(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "add v30.8b, v29.8b, v28.8b"); TEST_SINGLE(add(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "add v30.4h, v29.4h, v28.4h"); TEST_SINGLE(add(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "add v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(add(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "add v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(add(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "add v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(cmtst(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmtst v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(cmtst(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmtst v30.16b, v29.16b, v28.16b"); TEST_SINGLE(cmtst(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "cmtst v30.8h, v29.8h, v28.8h"); TEST_SINGLE(cmtst(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "cmtst v30.4s, v29.4s, v28.4s"); TEST_SINGLE(cmtst(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "cmtst v30.2d, v29.2d, v28.2d"); @@ -1530,59 +1536,59 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(cmtst(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "cmtst v30.8b, v29.8b, v28.8b"); TEST_SINGLE(cmtst(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "cmtst v30.4h, v29.4h, v28.4h"); TEST_SINGLE(cmtst(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "cmtst v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(cmtst(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmtst v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(cmtst(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmtst v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(mla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "mla v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(mla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "mla v30.16b, v29.16b, v28.16b"); TEST_SINGLE(mla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "mla v30.8h, v29.8h, v28.8h"); TEST_SINGLE(mla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "mla v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(mla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "mla v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(mla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "mla v30.2d, v29.2d, v28.2d"); TEST_SINGLE(mla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "mla v30.8b, v29.8b, v28.8b"); TEST_SINGLE(mla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "mla v30.4h, v29.4h, v28.4h"); TEST_SINGLE(mla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "mla v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(mla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "mla v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(mla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "mla v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(mul(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "mul v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(mul(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "mul v30.16b, v29.16b, v28.16b"); TEST_SINGLE(mul(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "mul v30.8h, v29.8h, v28.8h"); TEST_SINGLE(mul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "mul v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(mul(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "mul v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(mul(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "mul v30.2d, v29.2d, v28.2d"); TEST_SINGLE(mul(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "mul v30.8b, v29.8b, v28.8b"); TEST_SINGLE(mul(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "mul v30.4h, v29.4h, v28.4h"); TEST_SINGLE(mul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "mul v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(mul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "mul v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(mul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "mul v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(smaxp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smaxp v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(smaxp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "smaxp v30.16b, v29.16b, v28.16b"); TEST_SINGLE(smaxp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "smaxp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(smaxp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "smaxp v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(smaxp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smaxp v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(smaxp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "smaxp v30.2d, v29.2d, v28.2d"); TEST_SINGLE(smaxp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "smaxp v30.8b, v29.8b, v28.8b"); TEST_SINGLE(smaxp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "smaxp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(smaxp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "smaxp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(smaxp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smaxp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(smaxp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "smaxp v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sminp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sminp v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sminp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sminp v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sminp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sminp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sminp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sminp v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(sminp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sminp v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(sminp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sminp v30.2d, v29.2d, v28.2d"); TEST_SINGLE(sminp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sminp v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sminp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sminp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sminp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sminp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sminp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sminp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sminp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sminp v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(sqdmulh(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmulh v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(sqdmulh(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmulh v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sqdmulh(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmulh v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmulh v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(sqdmulh(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmulh v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(sqdmulh(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqdmulh v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(sqdmulh(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmulh v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqdmulh(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmulh v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqdmulh(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmulh v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmulh v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqdmulh(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmulh v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqdmulh(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqdmulh v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(addp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "addp v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(addp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "addp v30.16b, v29.16b, v28.16b"); TEST_SINGLE(addp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "addp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(addp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "addp v30.4s, v29.4s, v28.4s"); TEST_SINGLE(addp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "addp v30.2d, v29.2d, v28.2d"); @@ -1590,77 +1596,77 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(addp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "addp v30.8b, v29.8b, v28.8b"); TEST_SINGLE(addp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "addp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(addp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "addp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(addp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "addp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(addp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "addp v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmaxnm(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnm v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmaxnm(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnm v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmaxnm(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnm v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmaxnm(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnm v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmaxnm(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnm v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmaxnm(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnm v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmaxnm(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnm v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmaxnm(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnm v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmaxnm(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnm v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmaxnm(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnm v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmaxnm(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnm v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmaxnm(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnm v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmaxnm(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnm v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmla v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmla v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmla v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmla v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmla v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmla v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmla v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmla v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmla v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmla v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmla v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmla v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmla v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fadd v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fadd v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fadd v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fadd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fadd v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fadd v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fadd v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fadd v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fadd v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fadd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fadd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fadd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fadd v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmulx(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmulx v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmulx(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmulx v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmulx(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmulx v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmulx(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmulx v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmulx(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmulx v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmulx(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmulx v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmulx(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmulx v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmulx(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmulx v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmulx(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmulx v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmulx(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmulx v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmulx(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmulx v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmulx(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmulx v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmulx(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmulx v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fcmeq(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fcmeq v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fcmeq(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fcmeq v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fcmeq(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fcmeq v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fcmeq(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fcmeq v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fcmeq(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fcmeq v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fcmeq(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fcmeq v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fcmeq(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fcmeq v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fcmeq(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fcmeq v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fcmeq(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fcmeq v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fcmeq(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fcmeq v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fcmeq(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fcmeq v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fcmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fcmeq v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fcmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fcmeq v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmax(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmax v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmax(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmax v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmax(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmax v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmax(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmax v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmax(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmax v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmax(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmax v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmax(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmax v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmax(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmax v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmax(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmax v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmax(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmax v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmax(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmax v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmax(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmax v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmax(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmax v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(frecps(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "frecps v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(frecps(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "frecps v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(frecps(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "frecps v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(frecps(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "frecps v30.8h, v29.8h, v28.8h"); TEST_SINGLE(frecps(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "frecps v30.4s, v29.4s, v28.4s"); TEST_SINGLE(frecps(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "frecps v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(frecps(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "frecps v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(frecps(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "frecps v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(frecps(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "frecps v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(frecps(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "frecps v30.4h, v29.4h, v28.4h"); TEST_SINGLE(frecps(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "frecps v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(frecps(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "frecps v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(frecps(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "frecps v30.1d, v29.1d, v28.1d"); TEST_SINGLE(and_(QReg::q30, QReg::q29, QReg::q28), "and v30.16b, v29.16b, v28.16b"); TEST_SINGLE(and_(DReg::d30, DReg::d29, DReg::d28), "and v30.8b, v29.8b, v28.8b"); @@ -1674,55 +1680,55 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(bic(QReg::q30, QReg::q29, QReg::q28), "bic v30.16b, v29.16b, v28.16b"); TEST_SINGLE(bic(DReg::d30, DReg::d29, DReg::d28), "bic v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fminnm(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fminnm v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fminnm(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fminnm v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fminnm(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fminnm v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fminnm(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fminnm v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fminnm(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fminnm v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fminnm(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fminnm v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fminnm(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fminnm v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fminnm(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fminnm v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fminnm(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fminnm v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fminnm(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fminnm v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fminnm(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fminnm v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fminnm(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fminnm v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fminnm(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fminnm v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmls(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmls v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmls(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmls v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmls(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmls v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmls(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmls v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmls v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmls(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmls v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmls(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmls v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmls(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmls v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmls(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmls v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmls(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmls v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmls v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmls v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmls v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fsub v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fsub(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fsub v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fsub v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fsub(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fsub v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fsub(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fsub v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fsub v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fsub(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fsub v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fsub(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fsub v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fsub(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fsub v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fsub(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fsub v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fsub(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fsub v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fsub v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fsub v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmin(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmin v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmin(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmin v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmin(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmin v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmin(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmin v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmin(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmin v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmin(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmin v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmin(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmin v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmin(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmin v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmin(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmin v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmin(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmin v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmin(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmin v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmin(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmin v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmin(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmin v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(frsqrts(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "frsqrts v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(frsqrts(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "frsqrts v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(frsqrts(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "frsqrts v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(frsqrts(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "frsqrts v30.8h, v29.8h, v28.8h"); TEST_SINGLE(frsqrts(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "frsqrts v30.4s, v29.4s, v28.4s"); TEST_SINGLE(frsqrts(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "frsqrts v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(frsqrts(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "frsqrts v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(frsqrts(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "frsqrts v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(frsqrts(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "frsqrts v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(frsqrts(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "frsqrts v30.4h, v29.4h, v28.4h"); TEST_SINGLE(frsqrts(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "frsqrts v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(frsqrts(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "frsqrts v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(frsqrts(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "frsqrts v30.1d, v29.1d, v28.1d"); TEST_SINGLE(orr(QReg::q30, QReg::q29, QReg::q28), "orr v30.16b, v29.16b, v28.16b"); TEST_SINGLE(orr(DReg::d30, DReg::d29, DReg::d28), "orr v30.8b, v29.8b, v28.8b"); @@ -1739,17 +1745,17 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(orn(QReg::q30, QReg::q29, QReg::q28), "orn v30.16b, v29.16b, v28.16b"); TEST_SINGLE(orn(DReg::d30, DReg::d29, DReg::d28), "orn v30.8b, v29.8b, v28.8b"); - TEST_SINGLE(uhadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uhadd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uhadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uhadd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uhadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uhadd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uhadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uhadd v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uhadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uhadd v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uhadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uhadd v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uhadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uhadd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uhadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uhadd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uhadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uhadd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uhadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uhadd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uhadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uhadd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uqadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqadd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uqadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqadd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uqadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uqadd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uqadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uqadd v30.4s, v29.4s, v28.4s"); TEST_SINGLE(uqadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uqadd v30.2d, v29.2d, v28.2d"); @@ -1757,39 +1763,39 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(uqadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uqadd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uqadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uqadd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uqadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uqadd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqadd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uqadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqadd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(urhadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "urhadd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(urhadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "urhadd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(urhadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "urhadd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(urhadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "urhadd v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(urhadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "urhadd v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(urhadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "urhadd v30.2d, v29.2d, v28.2d"); TEST_SINGLE(urhadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "urhadd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(urhadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "urhadd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(urhadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "urhadd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(urhadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "urhadd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(urhadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "urhadd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uhsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uhsub v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uhsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uhsub v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uhsub(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uhsub v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uhsub(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uhsub v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uhsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uhsub v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uhsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uhsub v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uhsub(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uhsub v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uhsub(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uhsub v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uhsub(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uhsub v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uhsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uhsub v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uhsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uhsub v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uqsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqsub v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uqsub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqsub v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uqsub(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uqsub v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uqsub(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uqsub v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uqsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uqsub v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uqsub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uqsub v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uqsub(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uqsub v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uqsub(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uqsub v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uqsub(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uqsub v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uqsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqsub v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uqsub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqsub v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(cmhi(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmhi v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(cmhi(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmhi v30.16b, v29.16b, v28.16b"); TEST_SINGLE(cmhi(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "cmhi v30.8h, v29.8h, v28.8h"); TEST_SINGLE(cmhi(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "cmhi v30.4s, v29.4s, v28.4s"); TEST_SINGLE(cmhi(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "cmhi v30.2d, v29.2d, v28.2d"); @@ -1797,9 +1803,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(cmhi(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "cmhi v30.8b, v29.8b, v28.8b"); TEST_SINGLE(cmhi(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "cmhi v30.4h, v29.4h, v28.4h"); TEST_SINGLE(cmhi(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "cmhi v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(cmhi(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmhi v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(cmhi(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmhi v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(cmhs(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmhs v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(cmhs(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmhs v30.16b, v29.16b, v28.16b"); TEST_SINGLE(cmhs(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "cmhs v30.8h, v29.8h, v28.8h"); TEST_SINGLE(cmhs(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "cmhs v30.4s, v29.4s, v28.4s"); TEST_SINGLE(cmhs(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "cmhs v30.2d, v29.2d, v28.2d"); @@ -1807,9 +1813,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(cmhs(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "cmhs v30.8b, v29.8b, v28.8b"); TEST_SINGLE(cmhs(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "cmhs v30.4h, v29.4h, v28.4h"); TEST_SINGLE(cmhs(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "cmhs v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(cmhs(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmhs v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(cmhs(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmhs v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(ushl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "ushl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(ushl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "ushl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(ushl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "ushl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(ushl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "ushl v30.4s, v29.4s, v28.4s"); TEST_SINGLE(ushl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "ushl v30.2d, v29.2d, v28.2d"); @@ -1817,19 +1823,19 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(ushl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "ushl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(ushl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "ushl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(ushl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "ushl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(ushl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "ushl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(ushl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "ushl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqshl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqshl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uqshl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uqshl v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uqshl v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uqshl v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uqshl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uqshl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uqshl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqshl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqshl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(urshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "urshl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(urshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "urshl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(urshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "urshl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(urshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "urshl v30.4s, v29.4s, v28.4s"); TEST_SINGLE(urshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "urshl v30.2d, v29.2d, v28.2d"); @@ -1837,59 +1843,59 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(urshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "urshl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(urshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "urshl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(urshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "urshl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(urshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "urshl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(urshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "urshl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uqrshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqrshl v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uqrshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uqrshl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uqrshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uqrshl v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uqrshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uqrshl v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uqrshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uqrshl v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uqrshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uqrshl v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uqrshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uqrshl v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uqrshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uqrshl v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uqrshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uqrshl v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uqrshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqrshl v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uqrshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uqrshl v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(umax(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umax v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(umax(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umax v30.16b, v29.16b, v28.16b"); TEST_SINGLE(umax(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "umax v30.8h, v29.8h, v28.8h"); TEST_SINGLE(umax(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "umax v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(umax(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umax v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(umax(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umax v30.2d, v29.2d, v28.2d"); TEST_SINGLE(umax(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umax v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umax(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "umax v30.4h, v29.4h, v28.4h"); TEST_SINGLE(umax(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "umax v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(umax(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umax v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(umax(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umax v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(umin(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umin v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(umin(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umin v30.16b, v29.16b, v28.16b"); TEST_SINGLE(umin(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "umin v30.8h, v29.8h, v28.8h"); TEST_SINGLE(umin(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "umin v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(umin(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umin v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(umin(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umin v30.2d, v29.2d, v28.2d"); TEST_SINGLE(umin(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umin v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umin(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "umin v30.4h, v29.4h, v28.4h"); TEST_SINGLE(umin(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "umin v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(umin(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umin v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(umin(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umin v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uabd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uabd v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uabd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uabd v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uabd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uabd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uabd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uabd v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uabd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uabd v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uabd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uabd v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uabd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uabd v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uabd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uabd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uabd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uabd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uabd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uabd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uabd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uabd v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uaba(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uaba v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uaba(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uaba v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uaba(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uaba v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uaba(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uaba v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uaba(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uaba v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uaba(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uaba v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uaba(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uaba v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uaba(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uaba v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uaba(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uaba v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uaba(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uaba v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uaba(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uaba v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(sub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sub v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(sub(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sub v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sub(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sub v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sub(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sub v30.4s, v29.4s, v28.4s"); TEST_SINGLE(sub(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sub v30.2d, v29.2d, v28.2d"); @@ -1897,9 +1903,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(sub(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sub v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sub(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sub v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sub(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sub v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sub v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sub(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sub v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(cmeq(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmeq v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(cmeq(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "cmeq v30.16b, v29.16b, v28.16b"); TEST_SINGLE(cmeq(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "cmeq v30.8h, v29.8h, v28.8h"); TEST_SINGLE(cmeq(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "cmeq v30.4s, v29.4s, v28.4s"); TEST_SINGLE(cmeq(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "cmeq v30.2d, v29.2d, v28.2d"); @@ -1907,120 +1913,120 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(cmeq(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "cmeq v30.8b, v29.8b, v28.8b"); TEST_SINGLE(cmeq(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "cmeq v30.4h, v29.4h, v28.4h"); TEST_SINGLE(cmeq(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "cmeq v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(cmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmeq v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(cmeq(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "cmeq v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(mls(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "mls v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(mls(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "mls v30.16b, v29.16b, v28.16b"); TEST_SINGLE(mls(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "mls v30.8h, v29.8h, v28.8h"); TEST_SINGLE(mls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "mls v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(mls(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "mls v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(mls(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "mls v30.2d, v29.2d, v28.2d"); TEST_SINGLE(mls(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "mls v30.8b, v29.8b, v28.8b"); TEST_SINGLE(mls(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "mls v30.4h, v29.4h, v28.4h"); TEST_SINGLE(mls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "mls v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(mls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "mls v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(mls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "mls v30.1d, v29.1d, v28.1d"); TEST_SINGLE(pmul(QReg::q30, QReg::q29, QReg::q28), "pmul v30.16b, v29.16b, v28.16b"); TEST_SINGLE(pmul(DReg::d30, DReg::d29, DReg::d28), "pmul v30.8b, v29.8b, v28.8b"); - TEST_SINGLE(umaxp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umaxp v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(umaxp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "umaxp v30.16b, v29.16b, v28.16b"); TEST_SINGLE(umaxp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "umaxp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(umaxp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "umaxp v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(umaxp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umaxp v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(umaxp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "umaxp v30.2d, v29.2d, v28.2d"); TEST_SINGLE(umaxp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "umaxp v30.8b, v29.8b, v28.8b"); TEST_SINGLE(umaxp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "umaxp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(umaxp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "umaxp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(umaxp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umaxp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(umaxp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "umaxp v30.1d, v29.1d, v28.1d"); - TEST_SINGLE(uminp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uminp v30.16b, v29.16b, v28.16b"); + TEST_SINGLE(uminp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "uminp v30.16b, v29.16b, v28.16b"); TEST_SINGLE(uminp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "uminp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(uminp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "uminp v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(uminp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uminp v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(uminp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "uminp v30.2d, v29.2d, v28.2d"); TEST_SINGLE(uminp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "uminp v30.8b, v29.8b, v28.8b"); TEST_SINGLE(uminp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "uminp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(uminp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "uminp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(uminp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uminp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(uminp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "uminp v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(sqrdmulh(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmulh v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmulh v30.16b, v29.16b, v28.16b"); TEST_SINGLE(sqrdmulh(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmulh v30.8h, v29.8h, v28.8h"); TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmulh v30.4s, v29.4s, v28.4s"); - //TEST_SINGLE(sqrdmulh(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmulh v30.2d, v29.2d, v28.2d"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmulh v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(sqrdmulh(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmulh v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmulh v30.8b, v29.8b, v28.8b"); TEST_SINGLE(sqrdmulh(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmulh v30.4h, v29.4h, v28.4h"); TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmulh v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(sqrdmulh(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmulh v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmulh v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmaxnmp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnmp v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmaxnmp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnmp v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmaxnmp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnmp v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmaxnmp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnmp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmaxnmp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnmp v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmaxnmp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxnmp v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmaxnmp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnmp v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmaxnmp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnmp v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmaxnmp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnmp v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmaxnmp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnmp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmaxnmp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnmp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmaxnmp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnmp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmaxnmp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxnmp v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(faddp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "faddp v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(faddp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "faddp v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(faddp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "faddp v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(faddp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "faddp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(faddp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "faddp v30.4s, v29.4s, v28.4s"); TEST_SINGLE(faddp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "faddp v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(faddp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "faddp v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(faddp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "faddp v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(faddp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "faddp v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(faddp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "faddp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(faddp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "faddp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(faddp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "faddp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(faddp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "faddp v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmul(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmul v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmul(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmul v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmul(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmul v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmul(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmul v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmul v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmul(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmul v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmul(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmul v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmul(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmul v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmul(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmul v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmul(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmul v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmul v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmul v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmul v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fcmge(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fcmge v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fcmge(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fcmge v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fcmge(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fcmge v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fcmge(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fcmge v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fcmge(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fcmge v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fcmge(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fcmge v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fcmge(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fcmge v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fcmge(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fcmge v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fcmge(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fcmge v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fcmge(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fcmge v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fcmge(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fcmge v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fcmge(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fcmge v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fcmge(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fcmge v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(facge(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "facge v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(facge(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "facge v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(facge(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "facge v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(facge(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "facge v30.8h, v29.8h, v28.8h"); TEST_SINGLE(facge(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "facge v30.4s, v29.4s, v28.4s"); TEST_SINGLE(facge(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "facge v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(facge(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "facge v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(facge(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "facge v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(facge(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "facge v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(facge(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "facge v30.4h, v29.4h, v28.4h"); TEST_SINGLE(facge(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "facge v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(facge(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "facge v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(facge(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "facge v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fmaxp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxp v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fmaxp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxp v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fmaxp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxp v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fmaxp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fmaxp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxp v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fmaxp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fmaxp v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fmaxp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxp v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fmaxp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxp v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fmaxp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxp v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fmaxp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fmaxp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fmaxp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fmaxp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fmaxp v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fdiv(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fdiv v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fdiv(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fdiv v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fdiv(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fdiv v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fdiv(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fdiv v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fdiv(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fdiv v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fdiv(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fdiv v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fdiv(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fdiv v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fdiv(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fdiv v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fdiv(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fdiv v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fdiv(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fdiv v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fdiv(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fdiv v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fdiv(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fdiv v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fdiv(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fdiv v30.1d, v29.1d, v28.1d"); TEST_SINGLE(eor(QReg::q30, QReg::q29, QReg::q28), "eor v30.16b, v29.16b, v28.16b"); TEST_SINGLE(eor(DReg::d30, DReg::d29, DReg::d28), "eor v30.8b, v29.8b, v28.8b"); @@ -2028,55 +2034,55 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same") { TEST_SINGLE(bsl(QReg::q30, QReg::q29, QReg::q28), "bsl v30.16b, v29.16b, v28.16b"); TEST_SINGLE(bsl(DReg::d30, DReg::d29, DReg::d28), "bsl v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fminnmp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fminnmp v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fminnmp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fminnmp v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fminnmp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fminnmp v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fminnmp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fminnmp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fminnmp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fminnmp v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fminnmp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fminnmp v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fminnmp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fminnmp v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fminnmp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fminnmp v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fminnmp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fminnmp v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fminnmp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fminnmp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fminnmp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fminnmp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fminnmp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fminnmp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fminnmp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fminnmp v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fabd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fabd v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fabd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fabd v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fabd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fabd v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fabd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fabd v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fabd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fabd v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fabd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fabd v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fabd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fabd v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fabd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fabd v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fabd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fabd v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fabd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fabd v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fabd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fabd v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fabd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fabd v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fabd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fabd v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fcmgt(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fcmgt v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fcmgt(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fcmgt v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fcmgt(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fcmgt v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fcmgt(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fcmgt v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fcmgt(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fcmgt v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fcmgt(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fcmgt v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fcmgt(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fcmgt v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fcmgt(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fcmgt v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fcmgt(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fcmgt v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fcmgt(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fcmgt v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fcmgt(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fcmgt v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fcmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fcmgt v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fcmgt(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fcmgt v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(facgt(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "facgt v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(facgt(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "facgt v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(facgt(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "facgt v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(facgt(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "facgt v30.8h, v29.8h, v28.8h"); TEST_SINGLE(facgt(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "facgt v30.4s, v29.4s, v28.4s"); TEST_SINGLE(facgt(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "facgt v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(facgt(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "facgt v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(facgt(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "facgt v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(facgt(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "facgt v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(facgt(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "facgt v30.4h, v29.4h, v28.4h"); TEST_SINGLE(facgt(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "facgt v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(facgt(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "facgt v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(facgt(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "facgt v30.1d, v29.1d, v28.1d"); - //TEST_SINGLE(fminp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fminp v30.16b, v29.16b, v28.16b"); - //TEST_SINGLE(fminp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fminp v30.8h, v29.8h, v28.8h"); + // TEST_SINGLE(fminp(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "fminp v30.16b, v29.16b, v28.16b"); + // TEST_SINGLE(fminp(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "fminp v30.8h, v29.8h, v28.8h"); TEST_SINGLE(fminp(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "fminp v30.4s, v29.4s, v28.4s"); TEST_SINGLE(fminp(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "fminp v30.2d, v29.2d, v28.2d"); - //TEST_SINGLE(fminp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fminp v30.8b, v29.8b, v28.8b"); - //TEST_SINGLE(fminp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fminp v30.4h, v29.4h, v28.4h"); + // TEST_SINGLE(fminp(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "fminp v30.8b, v29.8b, v28.8b"); + // TEST_SINGLE(fminp(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "fminp v30.4h, v29.4h, v28.4h"); TEST_SINGLE(fminp(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "fminp v30.2s, v29.2s, v28.2s"); - //TEST_SINGLE(fminp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fminp v30.1d, v29.1d, v28.1d"); + // TEST_SINGLE(fminp(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "fminp v30.1d, v29.1d, v28.1d"); TEST_SINGLE(bit(QReg::q30, QReg::q29, QReg::q28), "bit v30.16b, v29.16b, v28.16b"); TEST_SINGLE(bit(DReg::d30, DReg::d29, DReg::d28), "bit v30.8b, v29.8b, v28.8b"); @@ -2094,7 +2100,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD modified immed TEST_SINGLE(fmov(SubRegSize::i16Bit, DReg::d30, 1.0), "fmov v30.4h, #0x70 (1.0000)"); TEST_SINGLE(fmov(SubRegSize::i32Bit, DReg::d30, 1.0), "fmov v30.2s, #0x70 (1.0000)"); - //TEST_SINGLE(fmov(SubRegSize::i64Bit, DReg::d30, 1.0), "fmov v30.1d, #0x70 (1.0000)"); + // TEST_SINGLE(fmov(SubRegSize::i64Bit, DReg::d30, 1.0), "fmov v30.1d, #0x70 (1.0000)"); // XXX: MVNI - Shifted immediate // XXX: BIC @@ -2118,539 +2124,539 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD modified immed } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD shift by immediate") { - TEST_SINGLE(sshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sshr v30.16b, v29.16b, #1"); - TEST_SINGLE(sshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sshr v30.16b, v29.16b, #7"); - TEST_SINGLE(sshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sshr v30.8h, v29.8h, #1"); + TEST_SINGLE(sshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sshr v30.16b, v29.16b, #1"); + TEST_SINGLE(sshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sshr v30.16b, v29.16b, #7"); + TEST_SINGLE(sshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sshr v30.8h, v29.8h, #1"); TEST_SINGLE(sshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sshr v30.8h, v29.8h, #15"); - TEST_SINGLE(sshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sshr v30.4s, v29.4s, #1"); + TEST_SINGLE(sshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sshr v30.4s, v29.4s, #1"); TEST_SINGLE(sshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sshr v30.4s, v29.4s, #31"); - TEST_SINGLE(sshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sshr v30.2d, v29.2d, #1"); + TEST_SINGLE(sshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sshr v30.2d, v29.2d, #1"); TEST_SINGLE(sshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sshr v30.2d, v29.2d, #63"); - TEST_SINGLE(sshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sshr v30.8b, v29.8b, #1"); - TEST_SINGLE(sshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sshr v30.8b, v29.8b, #7"); - TEST_SINGLE(sshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sshr v30.4h, v29.4h, #1"); + TEST_SINGLE(sshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sshr v30.8b, v29.8b, #1"); + TEST_SINGLE(sshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sshr v30.8b, v29.8b, #7"); + TEST_SINGLE(sshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sshr v30.4h, v29.4h, #1"); TEST_SINGLE(sshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sshr v30.4h, v29.4h, #15"); - TEST_SINGLE(sshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sshr v30.2s, v29.2s, #1"); + TEST_SINGLE(sshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sshr v30.2s, v29.2s, #1"); TEST_SINGLE(sshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sshr v30.2s, v29.2s, #31"); - //TEST_SINGLE(sshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sshr v30.1d, v29.1d, #1"); - //TEST_SINGLE(sshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sshr v30.1d, v29.1d, #63"); + // TEST_SINGLE(sshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sshr v30.1d, v29.1d, #1"); + // TEST_SINGLE(sshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sshr v30.1d, v29.1d, #63"); - TEST_SINGLE(ssra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ssra v30.16b, v29.16b, #1"); - TEST_SINGLE(ssra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ssra v30.16b, v29.16b, #7"); - TEST_SINGLE(ssra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ssra v30.8h, v29.8h, #1"); + TEST_SINGLE(ssra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ssra v30.16b, v29.16b, #1"); + TEST_SINGLE(ssra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ssra v30.16b, v29.16b, #7"); + TEST_SINGLE(ssra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ssra v30.8h, v29.8h, #1"); TEST_SINGLE(ssra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "ssra v30.8h, v29.8h, #15"); - TEST_SINGLE(ssra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ssra v30.4s, v29.4s, #1"); + TEST_SINGLE(ssra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ssra v30.4s, v29.4s, #1"); TEST_SINGLE(ssra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "ssra v30.4s, v29.4s, #31"); - TEST_SINGLE(ssra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ssra v30.2d, v29.2d, #1"); + TEST_SINGLE(ssra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ssra v30.2d, v29.2d, #1"); TEST_SINGLE(ssra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "ssra v30.2d, v29.2d, #63"); - TEST_SINGLE(ssra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ssra v30.8b, v29.8b, #1"); - TEST_SINGLE(ssra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ssra v30.8b, v29.8b, #7"); - TEST_SINGLE(ssra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ssra v30.4h, v29.4h, #1"); + TEST_SINGLE(ssra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ssra v30.8b, v29.8b, #1"); + TEST_SINGLE(ssra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ssra v30.8b, v29.8b, #7"); + TEST_SINGLE(ssra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ssra v30.4h, v29.4h, #1"); TEST_SINGLE(ssra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "ssra v30.4h, v29.4h, #15"); - TEST_SINGLE(ssra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ssra v30.2s, v29.2s, #1"); + TEST_SINGLE(ssra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ssra v30.2s, v29.2s, #1"); TEST_SINGLE(ssra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "ssra v30.2s, v29.2s, #31"); - //TEST_SINGLE(ssra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ssra v30.1d, v29.1d, #1"); - //TEST_SINGLE(ssra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ssra v30.1d, v29.1d, #63"); + // TEST_SINGLE(ssra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ssra v30.1d, v29.1d, #1"); + // TEST_SINGLE(ssra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ssra v30.1d, v29.1d, #63"); - TEST_SINGLE(srshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "srshr v30.16b, v29.16b, #1"); - TEST_SINGLE(srshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "srshr v30.16b, v29.16b, #7"); - TEST_SINGLE(srshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "srshr v30.8h, v29.8h, #1"); + TEST_SINGLE(srshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "srshr v30.16b, v29.16b, #1"); + TEST_SINGLE(srshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "srshr v30.16b, v29.16b, #7"); + TEST_SINGLE(srshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "srshr v30.8h, v29.8h, #1"); TEST_SINGLE(srshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "srshr v30.8h, v29.8h, #15"); - TEST_SINGLE(srshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "srshr v30.4s, v29.4s, #1"); + TEST_SINGLE(srshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "srshr v30.4s, v29.4s, #1"); TEST_SINGLE(srshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "srshr v30.4s, v29.4s, #31"); - TEST_SINGLE(srshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "srshr v30.2d, v29.2d, #1"); + TEST_SINGLE(srshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "srshr v30.2d, v29.2d, #1"); TEST_SINGLE(srshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "srshr v30.2d, v29.2d, #63"); - TEST_SINGLE(srshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "srshr v30.8b, v29.8b, #1"); - TEST_SINGLE(srshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "srshr v30.8b, v29.8b, #7"); - TEST_SINGLE(srshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "srshr v30.4h, v29.4h, #1"); + TEST_SINGLE(srshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "srshr v30.8b, v29.8b, #1"); + TEST_SINGLE(srshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "srshr v30.8b, v29.8b, #7"); + TEST_SINGLE(srshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "srshr v30.4h, v29.4h, #1"); TEST_SINGLE(srshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "srshr v30.4h, v29.4h, #15"); - TEST_SINGLE(srshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "srshr v30.2s, v29.2s, #1"); + TEST_SINGLE(srshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "srshr v30.2s, v29.2s, #1"); TEST_SINGLE(srshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "srshr v30.2s, v29.2s, #31"); - //TEST_SINGLE(srshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "srshr v30.1d, v29.1d, #1"); - //TEST_SINGLE(srshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "srshr v30.1d, v29.1d, #63"); + // TEST_SINGLE(srshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "srshr v30.1d, v29.1d, #1"); + // TEST_SINGLE(srshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "srshr v30.1d, v29.1d, #63"); - TEST_SINGLE(srsra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "srsra v30.16b, v29.16b, #1"); - TEST_SINGLE(srsra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "srsra v30.16b, v29.16b, #7"); - TEST_SINGLE(srsra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "srsra v30.8h, v29.8h, #1"); + TEST_SINGLE(srsra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "srsra v30.16b, v29.16b, #1"); + TEST_SINGLE(srsra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "srsra v30.16b, v29.16b, #7"); + TEST_SINGLE(srsra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "srsra v30.8h, v29.8h, #1"); TEST_SINGLE(srsra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "srsra v30.8h, v29.8h, #15"); - TEST_SINGLE(srsra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "srsra v30.4s, v29.4s, #1"); + TEST_SINGLE(srsra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "srsra v30.4s, v29.4s, #1"); TEST_SINGLE(srsra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "srsra v30.4s, v29.4s, #31"); - TEST_SINGLE(srsra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "srsra v30.2d, v29.2d, #1"); + TEST_SINGLE(srsra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "srsra v30.2d, v29.2d, #1"); TEST_SINGLE(srsra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "srsra v30.2d, v29.2d, #63"); - TEST_SINGLE(srsra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "srsra v30.8b, v29.8b, #1"); - TEST_SINGLE(srsra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "srsra v30.8b, v29.8b, #7"); - TEST_SINGLE(srsra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "srsra v30.4h, v29.4h, #1"); + TEST_SINGLE(srsra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "srsra v30.8b, v29.8b, #1"); + TEST_SINGLE(srsra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "srsra v30.8b, v29.8b, #7"); + TEST_SINGLE(srsra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "srsra v30.4h, v29.4h, #1"); TEST_SINGLE(srsra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "srsra v30.4h, v29.4h, #15"); - TEST_SINGLE(srsra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "srsra v30.2s, v29.2s, #1"); + TEST_SINGLE(srsra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "srsra v30.2s, v29.2s, #1"); TEST_SINGLE(srsra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "srsra v30.2s, v29.2s, #31"); - //TEST_SINGLE(srsra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "srsra v30.1d, v29.1d, #1"); - //TEST_SINGLE(srsra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "srsra v30.1d, v29.1d, #63"); + // TEST_SINGLE(srsra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "srsra v30.1d, v29.1d, #1"); + // TEST_SINGLE(srsra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "srsra v30.1d, v29.1d, #63"); - TEST_SINGLE(shl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "shl v30.16b, v29.16b, #1"); - TEST_SINGLE(shl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "shl v30.16b, v29.16b, #7"); - TEST_SINGLE(shl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "shl v30.8h, v29.8h, #1"); + TEST_SINGLE(shl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "shl v30.16b, v29.16b, #1"); + TEST_SINGLE(shl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "shl v30.16b, v29.16b, #7"); + TEST_SINGLE(shl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "shl v30.8h, v29.8h, #1"); TEST_SINGLE(shl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "shl v30.8h, v29.8h, #15"); - TEST_SINGLE(shl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "shl v30.4s, v29.4s, #1"); + TEST_SINGLE(shl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "shl v30.4s, v29.4s, #1"); TEST_SINGLE(shl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "shl v30.4s, v29.4s, #31"); - TEST_SINGLE(shl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "shl v30.2d, v29.2d, #1"); + TEST_SINGLE(shl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "shl v30.2d, v29.2d, #1"); TEST_SINGLE(shl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "shl v30.2d, v29.2d, #63"); - TEST_SINGLE(shl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "shl v30.8b, v29.8b, #1"); - TEST_SINGLE(shl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "shl v30.8b, v29.8b, #7"); - TEST_SINGLE(shl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "shl v30.4h, v29.4h, #1"); + TEST_SINGLE(shl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "shl v30.8b, v29.8b, #1"); + TEST_SINGLE(shl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "shl v30.8b, v29.8b, #7"); + TEST_SINGLE(shl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "shl v30.4h, v29.4h, #1"); TEST_SINGLE(shl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "shl v30.4h, v29.4h, #15"); - TEST_SINGLE(shl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "shl v30.2s, v29.2s, #1"); + TEST_SINGLE(shl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "shl v30.2s, v29.2s, #1"); TEST_SINGLE(shl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "shl v30.2s, v29.2s, #31"); - //TEST_SINGLE(shl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "shl v30.1d, v29.1d, #1"); - //TEST_SINGLE(shl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "shl v30.1d, v29.1d, #63"); + // TEST_SINGLE(shl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "shl v30.1d, v29.1d, #1"); + // TEST_SINGLE(shl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "shl v30.1d, v29.1d, #63"); - TEST_SINGLE(sqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshl v30.16b, v29.16b, #1"); - TEST_SINGLE(sqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshl v30.16b, v29.16b, #7"); - TEST_SINGLE(sqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshl v30.8h, v29.8h, #1"); + TEST_SINGLE(sqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshl v30.16b, v29.16b, #1"); + TEST_SINGLE(sqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshl v30.16b, v29.16b, #7"); + TEST_SINGLE(sqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshl v30.8h, v29.8h, #1"); TEST_SINGLE(sqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sqshl v30.8h, v29.8h, #15"); - TEST_SINGLE(sqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshl v30.4s, v29.4s, #1"); + TEST_SINGLE(sqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshl v30.4s, v29.4s, #1"); TEST_SINGLE(sqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sqshl v30.4s, v29.4s, #31"); - TEST_SINGLE(sqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshl v30.2d, v29.2d, #1"); + TEST_SINGLE(sqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshl v30.2d, v29.2d, #1"); TEST_SINGLE(sqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqshl v30.2d, v29.2d, #63"); - TEST_SINGLE(sqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshl v30.8b, v29.8b, #1"); - TEST_SINGLE(sqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshl v30.8b, v29.8b, #7"); - TEST_SINGLE(sqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshl v30.4h, v29.4h, #1"); + TEST_SINGLE(sqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshl v30.8b, v29.8b, #1"); + TEST_SINGLE(sqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshl v30.8b, v29.8b, #7"); + TEST_SINGLE(sqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshl v30.4h, v29.4h, #1"); TEST_SINGLE(sqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sqshl v30.4h, v29.4h, #15"); - TEST_SINGLE(sqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshl v30.2s, v29.2s, #1"); + TEST_SINGLE(sqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshl v30.2s, v29.2s, #1"); TEST_SINGLE(sqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sqshl v30.2s, v29.2s, #31"); - //TEST_SINGLE(sqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshl v30.1d, v29.1d, #1"); - //TEST_SINGLE(sqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshl v30.1d, v29.1d, #63"); + // TEST_SINGLE(sqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshl v30.1d, v29.1d, #1"); + // TEST_SINGLE(sqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshl v30.1d, v29.1d, #63"); - TEST_SINGLE(shrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "shrn v30.8b, v29.8h, #1"); - TEST_SINGLE(shrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "shrn v30.8b, v29.8h, #7"); - TEST_SINGLE(shrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "shrn v30.4h, v29.4s, #1"); + TEST_SINGLE(shrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "shrn v30.8b, v29.8h, #1"); + TEST_SINGLE(shrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "shrn v30.8b, v29.8h, #7"); + TEST_SINGLE(shrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "shrn v30.4h, v29.4s, #1"); TEST_SINGLE(shrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "shrn v30.4h, v29.4s, #15"); - TEST_SINGLE(shrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "shrn v30.2s, v29.2d, #1"); + TEST_SINGLE(shrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "shrn v30.2s, v29.2d, #1"); TEST_SINGLE(shrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "shrn v30.2s, v29.2d, #31"); - //TEST_SINGLE(shrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "shrn v30.1d, v29.1d, #1"); - //TEST_SINGLE(shrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "shrn v30.1d, v29.1d, #63"); + // TEST_SINGLE(shrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "shrn v30.1d, v29.1d, #1"); + // TEST_SINGLE(shrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "shrn v30.1d, v29.1d, #63"); - TEST_SINGLE(shrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.16b, v29.8h, #1"); - TEST_SINGLE(shrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "shrn2 v30.16b, v29.8h, #7"); - TEST_SINGLE(shrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.8h, v29.4s, #1"); + TEST_SINGLE(shrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.16b, v29.8h, #1"); + TEST_SINGLE(shrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "shrn2 v30.16b, v29.8h, #7"); + TEST_SINGLE(shrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.8h, v29.4s, #1"); TEST_SINGLE(shrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "shrn2 v30.8h, v29.4s, #15"); - TEST_SINGLE(shrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.4s, v29.2d, #1"); + TEST_SINGLE(shrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.4s, v29.2d, #1"); TEST_SINGLE(shrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "shrn2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(shrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(shrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "shrn2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(shrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "shrn2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(shrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "shrn2 v30.2d, v29.2d, #63"); - TEST_SINGLE(rshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "rshrn v30.8b, v29.8h, #1"); - TEST_SINGLE(rshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "rshrn v30.8b, v29.8h, #7"); - TEST_SINGLE(rshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "rshrn v30.4h, v29.4s, #1"); + TEST_SINGLE(rshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "rshrn v30.8b, v29.8h, #1"); + TEST_SINGLE(rshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "rshrn v30.8b, v29.8h, #7"); + TEST_SINGLE(rshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "rshrn v30.4h, v29.4s, #1"); TEST_SINGLE(rshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "rshrn v30.4h, v29.4s, #15"); - TEST_SINGLE(rshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "rshrn v30.2s, v29.2d, #1"); + TEST_SINGLE(rshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "rshrn v30.2s, v29.2d, #1"); TEST_SINGLE(rshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "rshrn v30.2s, v29.2d, #31"); - //TEST_SINGLE(rshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "rshrn v30.1d, v29.1d, #1"); - //TEST_SINGLE(rshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "rshrn v30.1d, v29.1d, #63"); + // TEST_SINGLE(rshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "rshrn v30.1d, v29.1d, #1"); + // TEST_SINGLE(rshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "rshrn v30.1d, v29.1d, #63"); - TEST_SINGLE(rshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.16b, v29.8h, #1"); - TEST_SINGLE(rshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "rshrn2 v30.16b, v29.8h, #7"); - TEST_SINGLE(rshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.8h, v29.4s, #1"); + TEST_SINGLE(rshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.16b, v29.8h, #1"); + TEST_SINGLE(rshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "rshrn2 v30.16b, v29.8h, #7"); + TEST_SINGLE(rshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.8h, v29.4s, #1"); TEST_SINGLE(rshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "rshrn2 v30.8h, v29.4s, #15"); - TEST_SINGLE(rshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.4s, v29.2d, #1"); + TEST_SINGLE(rshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.4s, v29.2d, #1"); TEST_SINGLE(rshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "rshrn2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(rshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(rshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "rshrn2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(rshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "rshrn2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(rshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "rshrn2 v30.2d, v29.2d, #63"); - TEST_SINGLE(sqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.8b, v29.8h, #1"); - TEST_SINGLE(sqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshrn v30.8b, v29.8h, #7"); - TEST_SINGLE(sqshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.4h, v29.4s, #1"); + TEST_SINGLE(sqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.8b, v29.8h, #1"); + TEST_SINGLE(sqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshrn v30.8b, v29.8h, #7"); + TEST_SINGLE(sqshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.4h, v29.4s, #1"); TEST_SINGLE(sqshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sqshrn v30.4h, v29.4s, #15"); - TEST_SINGLE(sqshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.2s, v29.2d, #1"); + TEST_SINGLE(sqshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.2s, v29.2d, #1"); TEST_SINGLE(sqshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sqshrn v30.2s, v29.2d, #31"); - //TEST_SINGLE(sqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.1d, v29.1d, #1"); - //TEST_SINGLE(sqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshrn v30.1d, v29.1d, #63"); + // TEST_SINGLE(sqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshrn v30.1d, v29.1d, #1"); + // TEST_SINGLE(sqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshrn v30.1d, v29.1d, #63"); - TEST_SINGLE(sqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.16b, v29.8h, #1"); - TEST_SINGLE(sqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshrn2 v30.16b, v29.8h, #7"); - TEST_SINGLE(sqshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.8h, v29.4s, #1"); + TEST_SINGLE(sqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.16b, v29.8h, #1"); + TEST_SINGLE(sqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshrn2 v30.16b, v29.8h, #7"); + TEST_SINGLE(sqshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.8h, v29.4s, #1"); TEST_SINGLE(sqshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sqshrn2 v30.8h, v29.4s, #15"); - TEST_SINGLE(sqshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.4s, v29.2d, #1"); + TEST_SINGLE(sqshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.4s, v29.2d, #1"); TEST_SINGLE(sqshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sqshrn2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(sqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(sqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqshrn2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(sqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshrn2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(sqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqshrn2 v30.2d, v29.2d, #63"); - TEST_SINGLE(sqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.8b, v29.8h, #1"); - TEST_SINGLE(sqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqrshrn v30.8b, v29.8h, #7"); - TEST_SINGLE(sqrshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.4h, v29.4s, #1"); + TEST_SINGLE(sqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.8b, v29.8h, #1"); + TEST_SINGLE(sqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqrshrn v30.8b, v29.8h, #7"); + TEST_SINGLE(sqrshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.4h, v29.4s, #1"); TEST_SINGLE(sqrshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sqrshrn v30.4h, v29.4s, #15"); - TEST_SINGLE(sqrshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.2s, v29.2d, #1"); + TEST_SINGLE(sqrshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.2s, v29.2d, #1"); TEST_SINGLE(sqrshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sqrshrn v30.2s, v29.2d, #31"); - //TEST_SINGLE(sqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.1d, v29.1d, #1"); - //TEST_SINGLE(sqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqrshrn v30.1d, v29.1d, #63"); + // TEST_SINGLE(sqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqrshrn v30.1d, v29.1d, #1"); + // TEST_SINGLE(sqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqrshrn v30.1d, v29.1d, #63"); - TEST_SINGLE(sqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.16b, v29.8h, #1"); - TEST_SINGLE(sqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqrshrn2 v30.16b, v29.8h, #7"); - TEST_SINGLE(sqrshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.8h, v29.4s, #1"); + TEST_SINGLE(sqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.16b, v29.8h, #1"); + TEST_SINGLE(sqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqrshrn2 v30.16b, v29.8h, #7"); + TEST_SINGLE(sqrshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.8h, v29.4s, #1"); TEST_SINGLE(sqrshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sqrshrn2 v30.8h, v29.4s, #15"); - TEST_SINGLE(sqrshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.4s, v29.2d, #1"); + TEST_SINGLE(sqrshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.4s, v29.2d, #1"); TEST_SINGLE(sqrshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sqrshrn2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(sqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(sqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqrshrn2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(sqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqrshrn2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(sqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqrshrn2 v30.2d, v29.2d, #63"); - //TEST_SINGLE(sshll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sshll v30.8b, v29.8h, #1"); - //TEST_SINGLE(sshll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sshll v30.8b, v29.8h, #7"); - TEST_SINGLE(sshll(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sshll v30.8h, v29.8b, #1"); + // TEST_SINGLE(sshll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sshll v30.8b, v29.8h, #1"); + // TEST_SINGLE(sshll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sshll v30.8b, v29.8h, #7"); + TEST_SINGLE(sshll(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sshll v30.8h, v29.8b, #1"); TEST_SINGLE(sshll(SubRegSize::i16Bit, DReg::d30, DReg::d29, 7), "sshll v30.8h, v29.8b, #7"); - TEST_SINGLE(sshll(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sshll v30.4s, v29.4h, #1"); + TEST_SINGLE(sshll(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sshll v30.4s, v29.4h, #1"); TEST_SINGLE(sshll(SubRegSize::i32Bit, DReg::d30, DReg::d29, 15), "sshll v30.4s, v29.4h, #15"); - TEST_SINGLE(sshll(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sshll v30.2d, v29.2s, #1"); + TEST_SINGLE(sshll(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sshll v30.2d, v29.2s, #1"); TEST_SINGLE(sshll(SubRegSize::i64Bit, DReg::d30, DReg::d29, 31), "sshll v30.2d, v29.2s, #31"); - //TEST_SINGLE(sshll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.16b, v29.8h, #1"); - //TEST_SINGLE(sshll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sshll2 v30.16b, v29.8h, #7"); - TEST_SINGLE(sshll2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.8h, v29.16b, #1"); + // TEST_SINGLE(sshll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.16b, v29.8h, #1"); + // TEST_SINGLE(sshll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sshll2 v30.16b, v29.8h, #7"); + TEST_SINGLE(sshll2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.8h, v29.16b, #1"); TEST_SINGLE(sshll2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 7), "sshll2 v30.8h, v29.16b, #7"); - TEST_SINGLE(sshll2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.4s, v29.8h, #1"); + TEST_SINGLE(sshll2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.4s, v29.8h, #1"); TEST_SINGLE(sshll2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 15), "sshll2 v30.4s, v29.8h, #15"); - TEST_SINGLE(sshll2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.2d, v29.4s, #1"); + TEST_SINGLE(sshll2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sshll2 v30.2d, v29.4s, #1"); TEST_SINGLE(sshll2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 31), "sshll2 v30.2d, v29.4s, #31"); - //TEST_SINGLE(sxtl(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sxtl v30.8b, v29.8h"); - TEST_SINGLE(sxtl(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sxtl v30.8h, v29.8b"); - TEST_SINGLE(sxtl(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sxtl v30.4s, v29.4h"); - TEST_SINGLE(sxtl(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sxtl v30.2d, v29.2s"); + // TEST_SINGLE(sxtl(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sxtl v30.8b, v29.8h"); + TEST_SINGLE(sxtl(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sxtl v30.8h, v29.8b"); + TEST_SINGLE(sxtl(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sxtl v30.4s, v29.4h"); + TEST_SINGLE(sxtl(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sxtl v30.2d, v29.2s"); - //TEST_SINGLE(sxtl(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sxtl v30.8b, v29.8h"); - TEST_SINGLE(sxtl(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sxtl v30.8h, v29.8b"); - TEST_SINGLE(sxtl(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sxtl v30.4s, v29.4h"); - TEST_SINGLE(sxtl(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sxtl v30.2d, v29.2s"); + // TEST_SINGLE(sxtl(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sxtl v30.8b, v29.8h"); + TEST_SINGLE(sxtl(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sxtl v30.8h, v29.8b"); + TEST_SINGLE(sxtl(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sxtl v30.4s, v29.4h"); + TEST_SINGLE(sxtl(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sxtl v30.2d, v29.2s"); - //TEST_SINGLE(sxtl2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sxtl2 v30.16b, v29.8h"); - TEST_SINGLE(sxtl2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sxtl2 v30.8h, v29.16b"); - TEST_SINGLE(sxtl2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sxtl2 v30.4s, v29.8h"); - TEST_SINGLE(sxtl2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sxtl2 v30.2d, v29.4s"); + // TEST_SINGLE(sxtl2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "sxtl2 v30.16b, v29.8h"); + TEST_SINGLE(sxtl2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "sxtl2 v30.8h, v29.16b"); + TEST_SINGLE(sxtl2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "sxtl2 v30.4s, v29.8h"); + TEST_SINGLE(sxtl2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "sxtl2 v30.2d, v29.4s"); - //TEST_SINGLE(sxtl2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sxtl2 v30.16b, v29.8h"); - TEST_SINGLE(sxtl2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sxtl2 v30.8h, v29.16b"); - TEST_SINGLE(sxtl2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sxtl2 v30.4s, v29.8h"); - TEST_SINGLE(sxtl2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sxtl2 v30.2d, v29.4s"); + // TEST_SINGLE(sxtl2(SubRegSize::i8Bit, DReg::d30, DReg::d29), "sxtl2 v30.16b, v29.8h"); + TEST_SINGLE(sxtl2(SubRegSize::i16Bit, DReg::d30, DReg::d29), "sxtl2 v30.8h, v29.16b"); + TEST_SINGLE(sxtl2(SubRegSize::i32Bit, DReg::d30, DReg::d29), "sxtl2 v30.4s, v29.8h"); + TEST_SINGLE(sxtl2(SubRegSize::i64Bit, DReg::d30, DReg::d29), "sxtl2 v30.2d, v29.4s"); - //TEST_SINGLE(scvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "scvtf v30.16b, v29.16b, #1"); - //TEST_SINGLE(scvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "scvtf v30.16b, v29.16b, #7"); - TEST_SINGLE(scvtf(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "scvtf v30.8h, v29.8h, #1"); + // TEST_SINGLE(scvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "scvtf v30.16b, v29.16b, #1"); + // TEST_SINGLE(scvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "scvtf v30.16b, v29.16b, #7"); + TEST_SINGLE(scvtf(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "scvtf v30.8h, v29.8h, #1"); TEST_SINGLE(scvtf(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "scvtf v30.8h, v29.8h, #15"); - TEST_SINGLE(scvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "scvtf v30.4s, v29.4s, #1"); + TEST_SINGLE(scvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "scvtf v30.4s, v29.4s, #1"); TEST_SINGLE(scvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "scvtf v30.4s, v29.4s, #31"); - TEST_SINGLE(scvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "scvtf v30.2d, v29.2d, #1"); + TEST_SINGLE(scvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "scvtf v30.2d, v29.2d, #1"); TEST_SINGLE(scvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "scvtf v30.2d, v29.2d, #63"); - //TEST_SINGLE(scvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "scvtf v30.8b, v29.8b, #1"); - //TEST_SINGLE(scvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "scvtf v30.8b, v29.8b, #7"); - TEST_SINGLE(scvtf(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "scvtf v30.4h, v29.4h, #1"); + // TEST_SINGLE(scvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "scvtf v30.8b, v29.8b, #1"); + // TEST_SINGLE(scvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "scvtf v30.8b, v29.8b, #7"); + TEST_SINGLE(scvtf(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "scvtf v30.4h, v29.4h, #1"); TEST_SINGLE(scvtf(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "scvtf v30.4h, v29.4h, #15"); - TEST_SINGLE(scvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "scvtf v30.2s, v29.2s, #1"); + TEST_SINGLE(scvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "scvtf v30.2s, v29.2s, #1"); TEST_SINGLE(scvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "scvtf v30.2s, v29.2s, #31"); - //TEST_SINGLE(scvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "scvtf v30.1d, v29.1d, #1"); - //TEST_SINGLE(scvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "scvtf v30.1d, v29.1d, #63"); + // TEST_SINGLE(scvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "scvtf v30.1d, v29.1d, #1"); + // TEST_SINGLE(scvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "scvtf v30.1d, v29.1d, #63"); - //TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.16b, v29.16b, #1"); - //TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "fcvtzs v30.16b, v29.16b, #7"); - TEST_SINGLE(fcvtzs(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.8h, v29.8h, #1"); + // TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.16b, v29.16b, #1"); + // TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "fcvtzs v30.16b, v29.16b, #7"); + TEST_SINGLE(fcvtzs(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.8h, v29.8h, #1"); TEST_SINGLE(fcvtzs(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "fcvtzs v30.8h, v29.8h, #15"); - TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.4s, v29.4s, #1"); + TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.4s, v29.4s, #1"); TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "fcvtzs v30.4s, v29.4s, #31"); - TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.2d, v29.2d, #1"); + TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "fcvtzs v30.2d, v29.2d, #1"); TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "fcvtzs v30.2d, v29.2d, #63"); - //TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.8b, v29.8b, #1"); - //TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "fcvtzs v30.8b, v29.8b, #7"); - TEST_SINGLE(fcvtzs(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.4h, v29.4h, #1"); + // TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.8b, v29.8b, #1"); + // TEST_SINGLE(fcvtzs(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "fcvtzs v30.8b, v29.8b, #7"); + TEST_SINGLE(fcvtzs(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.4h, v29.4h, #1"); TEST_SINGLE(fcvtzs(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "fcvtzs v30.4h, v29.4h, #15"); - TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.2s, v29.2s, #1"); + TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.2s, v29.2s, #1"); TEST_SINGLE(fcvtzs(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "fcvtzs v30.2s, v29.2s, #31"); - //TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.1d, v29.1d, #1"); - //TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "fcvtzs v30.1d, v29.1d, #63"); + // TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "fcvtzs v30.1d, v29.1d, #1"); + // TEST_SINGLE(fcvtzs(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "fcvtzs v30.1d, v29.1d, #63"); - TEST_SINGLE(ushr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ushr v30.16b, v29.16b, #1"); - TEST_SINGLE(ushr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ushr v30.16b, v29.16b, #7"); - TEST_SINGLE(ushr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ushr v30.8h, v29.8h, #1"); + TEST_SINGLE(ushr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ushr v30.16b, v29.16b, #1"); + TEST_SINGLE(ushr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ushr v30.16b, v29.16b, #7"); + TEST_SINGLE(ushr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ushr v30.8h, v29.8h, #1"); TEST_SINGLE(ushr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "ushr v30.8h, v29.8h, #15"); - TEST_SINGLE(ushr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ushr v30.4s, v29.4s, #1"); + TEST_SINGLE(ushr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ushr v30.4s, v29.4s, #1"); TEST_SINGLE(ushr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "ushr v30.4s, v29.4s, #31"); - TEST_SINGLE(ushr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ushr v30.2d, v29.2d, #1"); + TEST_SINGLE(ushr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ushr v30.2d, v29.2d, #1"); TEST_SINGLE(ushr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "ushr v30.2d, v29.2d, #63"); - TEST_SINGLE(ushr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ushr v30.8b, v29.8b, #1"); - TEST_SINGLE(ushr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ushr v30.8b, v29.8b, #7"); - TEST_SINGLE(ushr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ushr v30.4h, v29.4h, #1"); + TEST_SINGLE(ushr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ushr v30.8b, v29.8b, #1"); + TEST_SINGLE(ushr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ushr v30.8b, v29.8b, #7"); + TEST_SINGLE(ushr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ushr v30.4h, v29.4h, #1"); TEST_SINGLE(ushr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "ushr v30.4h, v29.4h, #15"); - TEST_SINGLE(ushr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ushr v30.2s, v29.2s, #1"); + TEST_SINGLE(ushr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ushr v30.2s, v29.2s, #1"); TEST_SINGLE(ushr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "ushr v30.2s, v29.2s, #31"); - //TEST_SINGLE(ushr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ushr v30.1d, v29.1d, #1"); - //TEST_SINGLE(ushr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ushr v30.1d, v29.1d, #63"); + // TEST_SINGLE(ushr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ushr v30.1d, v29.1d, #1"); + // TEST_SINGLE(ushr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ushr v30.1d, v29.1d, #63"); - TEST_SINGLE(usra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "usra v30.16b, v29.16b, #1"); - TEST_SINGLE(usra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "usra v30.16b, v29.16b, #7"); - TEST_SINGLE(usra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "usra v30.8h, v29.8h, #1"); + TEST_SINGLE(usra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "usra v30.16b, v29.16b, #1"); + TEST_SINGLE(usra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "usra v30.16b, v29.16b, #7"); + TEST_SINGLE(usra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "usra v30.8h, v29.8h, #1"); TEST_SINGLE(usra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "usra v30.8h, v29.8h, #15"); - TEST_SINGLE(usra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "usra v30.4s, v29.4s, #1"); + TEST_SINGLE(usra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "usra v30.4s, v29.4s, #1"); TEST_SINGLE(usra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "usra v30.4s, v29.4s, #31"); - TEST_SINGLE(usra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "usra v30.2d, v29.2d, #1"); + TEST_SINGLE(usra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "usra v30.2d, v29.2d, #1"); TEST_SINGLE(usra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "usra v30.2d, v29.2d, #63"); - TEST_SINGLE(usra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "usra v30.8b, v29.8b, #1"); - TEST_SINGLE(usra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "usra v30.8b, v29.8b, #7"); - TEST_SINGLE(usra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "usra v30.4h, v29.4h, #1"); + TEST_SINGLE(usra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "usra v30.8b, v29.8b, #1"); + TEST_SINGLE(usra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "usra v30.8b, v29.8b, #7"); + TEST_SINGLE(usra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "usra v30.4h, v29.4h, #1"); TEST_SINGLE(usra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "usra v30.4h, v29.4h, #15"); - TEST_SINGLE(usra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "usra v30.2s, v29.2s, #1"); + TEST_SINGLE(usra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "usra v30.2s, v29.2s, #1"); TEST_SINGLE(usra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "usra v30.2s, v29.2s, #31"); - //TEST_SINGLE(usra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "usra v30.1d, v29.1d, #1"); - //TEST_SINGLE(usra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "usra v30.1d, v29.1d, #63"); + // TEST_SINGLE(usra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "usra v30.1d, v29.1d, #1"); + // TEST_SINGLE(usra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "usra v30.1d, v29.1d, #63"); - TEST_SINGLE(urshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "urshr v30.16b, v29.16b, #1"); - TEST_SINGLE(urshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "urshr v30.16b, v29.16b, #7"); - TEST_SINGLE(urshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "urshr v30.8h, v29.8h, #1"); + TEST_SINGLE(urshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "urshr v30.16b, v29.16b, #1"); + TEST_SINGLE(urshr(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "urshr v30.16b, v29.16b, #7"); + TEST_SINGLE(urshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "urshr v30.8h, v29.8h, #1"); TEST_SINGLE(urshr(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "urshr v30.8h, v29.8h, #15"); - TEST_SINGLE(urshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "urshr v30.4s, v29.4s, #1"); + TEST_SINGLE(urshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "urshr v30.4s, v29.4s, #1"); TEST_SINGLE(urshr(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "urshr v30.4s, v29.4s, #31"); - TEST_SINGLE(urshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "urshr v30.2d, v29.2d, #1"); + TEST_SINGLE(urshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "urshr v30.2d, v29.2d, #1"); TEST_SINGLE(urshr(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "urshr v30.2d, v29.2d, #63"); - TEST_SINGLE(urshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "urshr v30.8b, v29.8b, #1"); - TEST_SINGLE(urshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "urshr v30.8b, v29.8b, #7"); - TEST_SINGLE(urshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "urshr v30.4h, v29.4h, #1"); + TEST_SINGLE(urshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "urshr v30.8b, v29.8b, #1"); + TEST_SINGLE(urshr(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "urshr v30.8b, v29.8b, #7"); + TEST_SINGLE(urshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "urshr v30.4h, v29.4h, #1"); TEST_SINGLE(urshr(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "urshr v30.4h, v29.4h, #15"); - TEST_SINGLE(urshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "urshr v30.2s, v29.2s, #1"); + TEST_SINGLE(urshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "urshr v30.2s, v29.2s, #1"); TEST_SINGLE(urshr(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "urshr v30.2s, v29.2s, #31"); - //TEST_SINGLE(urshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "urshr v30.1d, v29.1d, #1"); - //TEST_SINGLE(urshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "urshr v30.1d, v29.1d, #63"); + // TEST_SINGLE(urshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "urshr v30.1d, v29.1d, #1"); + // TEST_SINGLE(urshr(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "urshr v30.1d, v29.1d, #63"); - TEST_SINGLE(ursra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ursra v30.16b, v29.16b, #1"); - TEST_SINGLE(ursra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ursra v30.16b, v29.16b, #7"); - TEST_SINGLE(ursra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ursra v30.8h, v29.8h, #1"); + TEST_SINGLE(ursra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ursra v30.16b, v29.16b, #1"); + TEST_SINGLE(ursra(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ursra v30.16b, v29.16b, #7"); + TEST_SINGLE(ursra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ursra v30.8h, v29.8h, #1"); TEST_SINGLE(ursra(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "ursra v30.8h, v29.8h, #15"); - TEST_SINGLE(ursra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ursra v30.4s, v29.4s, #1"); + TEST_SINGLE(ursra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ursra v30.4s, v29.4s, #1"); TEST_SINGLE(ursra(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "ursra v30.4s, v29.4s, #31"); - TEST_SINGLE(ursra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ursra v30.2d, v29.2d, #1"); + TEST_SINGLE(ursra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ursra v30.2d, v29.2d, #1"); TEST_SINGLE(ursra(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "ursra v30.2d, v29.2d, #63"); - TEST_SINGLE(ursra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ursra v30.8b, v29.8b, #1"); - TEST_SINGLE(ursra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ursra v30.8b, v29.8b, #7"); - TEST_SINGLE(ursra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ursra v30.4h, v29.4h, #1"); + TEST_SINGLE(ursra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ursra v30.8b, v29.8b, #1"); + TEST_SINGLE(ursra(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ursra v30.8b, v29.8b, #7"); + TEST_SINGLE(ursra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ursra v30.4h, v29.4h, #1"); TEST_SINGLE(ursra(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "ursra v30.4h, v29.4h, #15"); - TEST_SINGLE(ursra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ursra v30.2s, v29.2s, #1"); + TEST_SINGLE(ursra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ursra v30.2s, v29.2s, #1"); TEST_SINGLE(ursra(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "ursra v30.2s, v29.2s, #31"); - //TEST_SINGLE(ursra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ursra v30.1d, v29.1d, #1"); - //TEST_SINGLE(ursra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ursra v30.1d, v29.1d, #63"); + // TEST_SINGLE(ursra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ursra v30.1d, v29.1d, #1"); + // TEST_SINGLE(ursra(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ursra v30.1d, v29.1d, #63"); - TEST_SINGLE(sri(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sri v30.16b, v29.16b, #1"); - TEST_SINGLE(sri(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sri v30.16b, v29.16b, #7"); - TEST_SINGLE(sri(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sri v30.8h, v29.8h, #1"); + TEST_SINGLE(sri(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sri v30.16b, v29.16b, #1"); + TEST_SINGLE(sri(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sri v30.16b, v29.16b, #7"); + TEST_SINGLE(sri(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sri v30.8h, v29.8h, #1"); TEST_SINGLE(sri(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sri v30.8h, v29.8h, #15"); - TEST_SINGLE(sri(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sri v30.4s, v29.4s, #1"); + TEST_SINGLE(sri(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sri v30.4s, v29.4s, #1"); TEST_SINGLE(sri(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sri v30.4s, v29.4s, #31"); - TEST_SINGLE(sri(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sri v30.2d, v29.2d, #1"); + TEST_SINGLE(sri(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sri v30.2d, v29.2d, #1"); TEST_SINGLE(sri(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sri v30.2d, v29.2d, #63"); - TEST_SINGLE(sri(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sri v30.8b, v29.8b, #1"); - TEST_SINGLE(sri(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sri v30.8b, v29.8b, #7"); - TEST_SINGLE(sri(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sri v30.4h, v29.4h, #1"); + TEST_SINGLE(sri(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sri v30.8b, v29.8b, #1"); + TEST_SINGLE(sri(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sri v30.8b, v29.8b, #7"); + TEST_SINGLE(sri(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sri v30.4h, v29.4h, #1"); TEST_SINGLE(sri(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sri v30.4h, v29.4h, #15"); - TEST_SINGLE(sri(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sri v30.2s, v29.2s, #1"); + TEST_SINGLE(sri(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sri v30.2s, v29.2s, #1"); TEST_SINGLE(sri(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sri v30.2s, v29.2s, #31"); - //TEST_SINGLE(sri(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sri v30.1d, v29.1d, #1"); - //TEST_SINGLE(sri(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sri v30.1d, v29.1d, #63"); + // TEST_SINGLE(sri(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sri v30.1d, v29.1d, #1"); + // TEST_SINGLE(sri(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sri v30.1d, v29.1d, #63"); - TEST_SINGLE(sli(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sli v30.16b, v29.16b, #1"); - TEST_SINGLE(sli(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sli v30.16b, v29.16b, #7"); - TEST_SINGLE(sli(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sli v30.8h, v29.8h, #1"); + TEST_SINGLE(sli(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sli v30.16b, v29.16b, #1"); + TEST_SINGLE(sli(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sli v30.16b, v29.16b, #7"); + TEST_SINGLE(sli(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sli v30.8h, v29.8h, #1"); TEST_SINGLE(sli(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sli v30.8h, v29.8h, #15"); - TEST_SINGLE(sli(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sli v30.4s, v29.4s, #1"); + TEST_SINGLE(sli(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sli v30.4s, v29.4s, #1"); TEST_SINGLE(sli(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sli v30.4s, v29.4s, #31"); - TEST_SINGLE(sli(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sli v30.2d, v29.2d, #1"); + TEST_SINGLE(sli(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sli v30.2d, v29.2d, #1"); TEST_SINGLE(sli(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sli v30.2d, v29.2d, #63"); - TEST_SINGLE(sli(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sli v30.8b, v29.8b, #1"); - TEST_SINGLE(sli(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sli v30.8b, v29.8b, #7"); - TEST_SINGLE(sli(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sli v30.4h, v29.4h, #1"); + TEST_SINGLE(sli(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sli v30.8b, v29.8b, #1"); + TEST_SINGLE(sli(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sli v30.8b, v29.8b, #7"); + TEST_SINGLE(sli(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sli v30.4h, v29.4h, #1"); TEST_SINGLE(sli(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sli v30.4h, v29.4h, #15"); - TEST_SINGLE(sli(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sli v30.2s, v29.2s, #1"); + TEST_SINGLE(sli(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sli v30.2s, v29.2s, #1"); TEST_SINGLE(sli(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sli v30.2s, v29.2s, #31"); - //TEST_SINGLE(sli(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sli v30.1d, v29.1d, #1"); - //TEST_SINGLE(sli(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sli v30.1d, v29.1d, #63"); + // TEST_SINGLE(sli(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sli v30.1d, v29.1d, #1"); + // TEST_SINGLE(sli(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sli v30.1d, v29.1d, #63"); - TEST_SINGLE(sqshlu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.16b, v29.16b, #1"); - TEST_SINGLE(sqshlu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshlu v30.16b, v29.16b, #7"); - TEST_SINGLE(sqshlu(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.8h, v29.8h, #1"); + TEST_SINGLE(sqshlu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.16b, v29.16b, #1"); + TEST_SINGLE(sqshlu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshlu v30.16b, v29.16b, #7"); + TEST_SINGLE(sqshlu(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.8h, v29.8h, #1"); TEST_SINGLE(sqshlu(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sqshlu v30.8h, v29.8h, #15"); - TEST_SINGLE(sqshlu(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.4s, v29.4s, #1"); + TEST_SINGLE(sqshlu(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.4s, v29.4s, #1"); TEST_SINGLE(sqshlu(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sqshlu v30.4s, v29.4s, #31"); - TEST_SINGLE(sqshlu(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.2d, v29.2d, #1"); + TEST_SINGLE(sqshlu(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshlu v30.2d, v29.2d, #1"); TEST_SINGLE(sqshlu(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqshlu v30.2d, v29.2d, #63"); - TEST_SINGLE(sqshlu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.8b, v29.8b, #1"); - TEST_SINGLE(sqshlu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshlu v30.8b, v29.8b, #7"); - TEST_SINGLE(sqshlu(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.4h, v29.4h, #1"); + TEST_SINGLE(sqshlu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.8b, v29.8b, #1"); + TEST_SINGLE(sqshlu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshlu v30.8b, v29.8b, #7"); + TEST_SINGLE(sqshlu(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.4h, v29.4h, #1"); TEST_SINGLE(sqshlu(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sqshlu v30.4h, v29.4h, #15"); - TEST_SINGLE(sqshlu(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.2s, v29.2s, #1"); + TEST_SINGLE(sqshlu(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.2s, v29.2s, #1"); TEST_SINGLE(sqshlu(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sqshlu v30.2s, v29.2s, #31"); - //TEST_SINGLE(sqshlu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.1d, v29.1d, #1"); - //TEST_SINGLE(sqshlu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshlu v30.1d, v29.1d, #63"); + // TEST_SINGLE(sqshlu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshlu v30.1d, v29.1d, #1"); + // TEST_SINGLE(sqshlu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshlu v30.1d, v29.1d, #63"); - TEST_SINGLE(uqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "uqshl v30.16b, v29.16b, #1"); - TEST_SINGLE(uqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "uqshl v30.16b, v29.16b, #7"); - TEST_SINGLE(uqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "uqshl v30.8h, v29.8h, #1"); + TEST_SINGLE(uqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "uqshl v30.16b, v29.16b, #1"); + TEST_SINGLE(uqshl(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "uqshl v30.16b, v29.16b, #7"); + TEST_SINGLE(uqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "uqshl v30.8h, v29.8h, #1"); TEST_SINGLE(uqshl(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "uqshl v30.8h, v29.8h, #15"); - TEST_SINGLE(uqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "uqshl v30.4s, v29.4s, #1"); + TEST_SINGLE(uqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "uqshl v30.4s, v29.4s, #1"); TEST_SINGLE(uqshl(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "uqshl v30.4s, v29.4s, #31"); - TEST_SINGLE(uqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "uqshl v30.2d, v29.2d, #1"); + TEST_SINGLE(uqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "uqshl v30.2d, v29.2d, #1"); TEST_SINGLE(uqshl(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "uqshl v30.2d, v29.2d, #63"); - TEST_SINGLE(uqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "uqshl v30.8b, v29.8b, #1"); - TEST_SINGLE(uqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "uqshl v30.8b, v29.8b, #7"); - TEST_SINGLE(uqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "uqshl v30.4h, v29.4h, #1"); + TEST_SINGLE(uqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "uqshl v30.8b, v29.8b, #1"); + TEST_SINGLE(uqshl(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "uqshl v30.8b, v29.8b, #7"); + TEST_SINGLE(uqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "uqshl v30.4h, v29.4h, #1"); TEST_SINGLE(uqshl(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "uqshl v30.4h, v29.4h, #15"); - TEST_SINGLE(uqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "uqshl v30.2s, v29.2s, #1"); + TEST_SINGLE(uqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "uqshl v30.2s, v29.2s, #1"); TEST_SINGLE(uqshl(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "uqshl v30.2s, v29.2s, #31"); - //TEST_SINGLE(uqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "uqshl v30.1d, v29.1d, #1"); - //TEST_SINGLE(uqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "uqshl v30.1d, v29.1d, #63"); + // TEST_SINGLE(uqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "uqshl v30.1d, v29.1d, #1"); + // TEST_SINGLE(uqshl(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "uqshl v30.1d, v29.1d, #63"); - TEST_SINGLE(sqshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.8b, v29.8h, #1"); - TEST_SINGLE(sqshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshrun v30.8b, v29.8h, #7"); - TEST_SINGLE(sqshrun(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.4h, v29.4s, #1"); + TEST_SINGLE(sqshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.8b, v29.8h, #1"); + TEST_SINGLE(sqshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqshrun v30.8b, v29.8h, #7"); + TEST_SINGLE(sqshrun(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.4h, v29.4s, #1"); TEST_SINGLE(sqshrun(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sqshrun v30.4h, v29.4s, #15"); - TEST_SINGLE(sqshrun(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.2s, v29.2d, #1"); + TEST_SINGLE(sqshrun(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.2s, v29.2d, #1"); TEST_SINGLE(sqshrun(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sqshrun v30.2s, v29.2d, #31"); - //TEST_SINGLE(sqshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.1d, v29.1d, #1"); - //TEST_SINGLE(sqshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshrun v30.1d, v29.1d, #63"); + // TEST_SINGLE(sqshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqshrun v30.1d, v29.1d, #1"); + // TEST_SINGLE(sqshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqshrun v30.1d, v29.1d, #63"); - TEST_SINGLE(sqshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.16b, v29.8h, #1"); - TEST_SINGLE(sqshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshrun2 v30.16b, v29.8h, #7"); - TEST_SINGLE(sqshrun2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.8h, v29.4s, #1"); + TEST_SINGLE(sqshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.16b, v29.8h, #1"); + TEST_SINGLE(sqshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqshrun2 v30.16b, v29.8h, #7"); + TEST_SINGLE(sqshrun2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.8h, v29.4s, #1"); TEST_SINGLE(sqshrun2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sqshrun2 v30.8h, v29.4s, #15"); - TEST_SINGLE(sqshrun2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.4s, v29.2d, #1"); + TEST_SINGLE(sqshrun2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.4s, v29.2d, #1"); TEST_SINGLE(sqshrun2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sqshrun2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(sqshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(sqshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqshrun2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(sqshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqshrun2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(sqshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqshrun2 v30.2d, v29.2d, #63"); - TEST_SINGLE(sqrshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.8b, v29.8h, #1"); - TEST_SINGLE(sqrshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqrshrun v30.8b, v29.8h, #7"); - TEST_SINGLE(sqrshrun(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.4h, v29.4s, #1"); + TEST_SINGLE(sqrshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.8b, v29.8h, #1"); + TEST_SINGLE(sqrshrun(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "sqrshrun v30.8b, v29.8h, #7"); + TEST_SINGLE(sqrshrun(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.4h, v29.4s, #1"); TEST_SINGLE(sqrshrun(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "sqrshrun v30.4h, v29.4s, #15"); - TEST_SINGLE(sqrshrun(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.2s, v29.2d, #1"); + TEST_SINGLE(sqrshrun(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.2s, v29.2d, #1"); TEST_SINGLE(sqrshrun(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "sqrshrun v30.2s, v29.2d, #31"); - //TEST_SINGLE(sqrshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.1d, v29.1d, #1"); - //TEST_SINGLE(sqrshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqrshrun v30.1d, v29.1d, #63"); + // TEST_SINGLE(sqrshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "sqrshrun v30.1d, v29.1d, #1"); + // TEST_SINGLE(sqrshrun(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "sqrshrun v30.1d, v29.1d, #63"); - TEST_SINGLE(sqrshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.16b, v29.8h, #1"); - TEST_SINGLE(sqrshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqrshrun2 v30.16b, v29.8h, #7"); - TEST_SINGLE(sqrshrun2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.8h, v29.4s, #1"); + TEST_SINGLE(sqrshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.16b, v29.8h, #1"); + TEST_SINGLE(sqrshrun2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "sqrshrun2 v30.16b, v29.8h, #7"); + TEST_SINGLE(sqrshrun2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.8h, v29.4s, #1"); TEST_SINGLE(sqrshrun2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "sqrshrun2 v30.8h, v29.4s, #15"); - TEST_SINGLE(sqrshrun2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.4s, v29.2d, #1"); + TEST_SINGLE(sqrshrun2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.4s, v29.2d, #1"); TEST_SINGLE(sqrshrun2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "sqrshrun2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(sqrshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(sqrshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqrshrun2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(sqrshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "sqrshrun2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(sqrshrun2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "sqrshrun2 v30.2d, v29.2d, #63"); - TEST_SINGLE(uqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.8b, v29.8h, #1"); - TEST_SINGLE(uqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "uqshrn v30.8b, v29.8h, #7"); - TEST_SINGLE(uqshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.4h, v29.4s, #1"); + TEST_SINGLE(uqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.8b, v29.8h, #1"); + TEST_SINGLE(uqshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "uqshrn v30.8b, v29.8h, #7"); + TEST_SINGLE(uqshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.4h, v29.4s, #1"); TEST_SINGLE(uqshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "uqshrn v30.4h, v29.4s, #15"); - TEST_SINGLE(uqshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.2s, v29.2d, #1"); + TEST_SINGLE(uqshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.2s, v29.2d, #1"); TEST_SINGLE(uqshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "uqshrn v30.2s, v29.2d, #31"); - //TEST_SINGLE(uqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.1d, v29.1d, #1"); - //TEST_SINGLE(uqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "uqshrn v30.1d, v29.1d, #63"); + // TEST_SINGLE(uqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "uqshrn v30.1d, v29.1d, #1"); + // TEST_SINGLE(uqshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "uqshrn v30.1d, v29.1d, #63"); - TEST_SINGLE(uqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.16b, v29.8h, #1"); - TEST_SINGLE(uqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "uqshrn2 v30.16b, v29.8h, #7"); - TEST_SINGLE(uqshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.8h, v29.4s, #1"); + TEST_SINGLE(uqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.16b, v29.8h, #1"); + TEST_SINGLE(uqshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "uqshrn2 v30.16b, v29.8h, #7"); + TEST_SINGLE(uqshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.8h, v29.4s, #1"); TEST_SINGLE(uqshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "uqshrn2 v30.8h, v29.4s, #15"); - TEST_SINGLE(uqshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.4s, v29.2d, #1"); + TEST_SINGLE(uqshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.4s, v29.2d, #1"); TEST_SINGLE(uqshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "uqshrn2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(uqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(uqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "uqshrn2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(uqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "uqshrn2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(uqshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "uqshrn2 v30.2d, v29.2d, #63"); - TEST_SINGLE(uqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.8b, v29.8h, #1"); - TEST_SINGLE(uqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "uqrshrn v30.8b, v29.8h, #7"); - TEST_SINGLE(uqrshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.4h, v29.4s, #1"); + TEST_SINGLE(uqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.8b, v29.8h, #1"); + TEST_SINGLE(uqrshrn(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "uqrshrn v30.8b, v29.8h, #7"); + TEST_SINGLE(uqrshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.4h, v29.4s, #1"); TEST_SINGLE(uqrshrn(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "uqrshrn v30.4h, v29.4s, #15"); - TEST_SINGLE(uqrshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.2s, v29.2d, #1"); + TEST_SINGLE(uqrshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.2s, v29.2d, #1"); TEST_SINGLE(uqrshrn(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "uqrshrn v30.2s, v29.2d, #31"); - //TEST_SINGLE(uqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.1d, v29.1d, #1"); - //TEST_SINGLE(uqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "uqrshrn v30.1d, v29.1d, #63"); + // TEST_SINGLE(uqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "uqrshrn v30.1d, v29.1d, #1"); + // TEST_SINGLE(uqrshrn(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "uqrshrn v30.1d, v29.1d, #63"); - TEST_SINGLE(uqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.16b, v29.8h, #1"); - TEST_SINGLE(uqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "uqrshrn2 v30.16b, v29.8h, #7"); - TEST_SINGLE(uqrshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.8h, v29.4s, #1"); + TEST_SINGLE(uqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.16b, v29.8h, #1"); + TEST_SINGLE(uqrshrn2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "uqrshrn2 v30.16b, v29.8h, #7"); + TEST_SINGLE(uqrshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.8h, v29.4s, #1"); TEST_SINGLE(uqrshrn2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "uqrshrn2 v30.8h, v29.4s, #15"); - TEST_SINGLE(uqrshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.4s, v29.2d, #1"); + TEST_SINGLE(uqrshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.4s, v29.2d, #1"); TEST_SINGLE(uqrshrn2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "uqrshrn2 v30.4s, v29.2d, #31"); - //TEST_SINGLE(uqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.2d, v29.2d, #1"); - //TEST_SINGLE(uqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "uqrshrn2 v30.2d, v29.2d, #63"); + // TEST_SINGLE(uqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "uqrshrn2 v30.2d, v29.2d, #1"); + // TEST_SINGLE(uqrshrn2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "uqrshrn2 v30.2d, v29.2d, #63"); - //TEST_SINGLE(ushll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ushll v30.8b, v29.8h, #1"); - //TEST_SINGLE(ushll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ushll v30.8b, v29.8h, #7"); - TEST_SINGLE(ushll(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ushll v30.8h, v29.8b, #1"); + // TEST_SINGLE(ushll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ushll v30.8b, v29.8h, #1"); + // TEST_SINGLE(ushll(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ushll v30.8b, v29.8h, #7"); + TEST_SINGLE(ushll(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ushll v30.8h, v29.8b, #1"); TEST_SINGLE(ushll(SubRegSize::i16Bit, DReg::d30, DReg::d29, 7), "ushll v30.8h, v29.8b, #7"); - TEST_SINGLE(ushll(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ushll v30.4s, v29.4h, #1"); + TEST_SINGLE(ushll(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ushll v30.4s, v29.4h, #1"); TEST_SINGLE(ushll(SubRegSize::i32Bit, DReg::d30, DReg::d29, 15), "ushll v30.4s, v29.4h, #15"); - TEST_SINGLE(ushll(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ushll v30.2d, v29.2s, #1"); + TEST_SINGLE(ushll(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ushll v30.2d, v29.2s, #1"); TEST_SINGLE(ushll(SubRegSize::i64Bit, DReg::d30, DReg::d29, 31), "ushll v30.2d, v29.2s, #31"); - //TEST_SINGLE(ushll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.16b, v29.8h, #1"); - //TEST_SINGLE(ushll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ushll2 v30.16b, v29.8h, #7"); - TEST_SINGLE(ushll2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.8h, v29.16b, #1"); + // TEST_SINGLE(ushll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.16b, v29.8h, #1"); + // TEST_SINGLE(ushll2(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ushll2 v30.16b, v29.8h, #7"); + TEST_SINGLE(ushll2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.8h, v29.16b, #1"); TEST_SINGLE(ushll2(SubRegSize::i16Bit, QReg::q30, QReg::q29, 7), "ushll2 v30.8h, v29.16b, #7"); - TEST_SINGLE(ushll2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.4s, v29.8h, #1"); + TEST_SINGLE(ushll2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.4s, v29.8h, #1"); TEST_SINGLE(ushll2(SubRegSize::i32Bit, QReg::q30, QReg::q29, 15), "ushll2 v30.4s, v29.8h, #15"); - TEST_SINGLE(ushll2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.2d, v29.4s, #1"); + TEST_SINGLE(ushll2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ushll2 v30.2d, v29.4s, #1"); TEST_SINGLE(ushll2(SubRegSize::i64Bit, QReg::q30, QReg::q29, 31), "ushll2 v30.2d, v29.4s, #31"); - //TEST_SINGLE(uxtl(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uxtl v30.8b, v29.8h"); - TEST_SINGLE(uxtl(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uxtl v30.8h, v29.8b"); - TEST_SINGLE(uxtl(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uxtl v30.4s, v29.4h"); - TEST_SINGLE(uxtl(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uxtl v30.2d, v29.2s"); + // TEST_SINGLE(uxtl(SubRegSize::i8Bit, DReg::d30, DReg::d29), "uxtl v30.8b, v29.8h"); + TEST_SINGLE(uxtl(SubRegSize::i16Bit, DReg::d30, DReg::d29), "uxtl v30.8h, v29.8b"); + TEST_SINGLE(uxtl(SubRegSize::i32Bit, DReg::d30, DReg::d29), "uxtl v30.4s, v29.4h"); + TEST_SINGLE(uxtl(SubRegSize::i64Bit, DReg::d30, DReg::d29), "uxtl v30.2d, v29.2s"); - //TEST_SINGLE(uxtl2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uxtl2 v30.16b, v29.8h"); - TEST_SINGLE(uxtl2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uxtl2 v30.8h, v29.16b"); - TEST_SINGLE(uxtl2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uxtl2 v30.4s, v29.8h"); - TEST_SINGLE(uxtl2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uxtl2 v30.2d, v29.4s"); + // TEST_SINGLE(uxtl2(SubRegSize::i8Bit, QReg::q30, QReg::q29), "uxtl2 v30.16b, v29.8h"); + TEST_SINGLE(uxtl2(SubRegSize::i16Bit, QReg::q30, QReg::q29), "uxtl2 v30.8h, v29.16b"); + TEST_SINGLE(uxtl2(SubRegSize::i32Bit, QReg::q30, QReg::q29), "uxtl2 v30.4s, v29.8h"); + TEST_SINGLE(uxtl2(SubRegSize::i64Bit, QReg::q30, QReg::q29), "uxtl2 v30.2d, v29.4s"); - //TEST_SINGLE(ucvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.16b, v29.16b, #1"); - //TEST_SINGLE(ucvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ucvtf v30.16b, v29.16b, #7"); - TEST_SINGLE(ucvtf(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.8h, v29.8h, #1"); + // TEST_SINGLE(ucvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.16b, v29.16b, #1"); + // TEST_SINGLE(ucvtf(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "ucvtf v30.16b, v29.16b, #7"); + TEST_SINGLE(ucvtf(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.8h, v29.8h, #1"); TEST_SINGLE(ucvtf(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "ucvtf v30.8h, v29.8h, #15"); - TEST_SINGLE(ucvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.4s, v29.4s, #1"); + TEST_SINGLE(ucvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.4s, v29.4s, #1"); TEST_SINGLE(ucvtf(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "ucvtf v30.4s, v29.4s, #31"); - TEST_SINGLE(ucvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.2d, v29.2d, #1"); + TEST_SINGLE(ucvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "ucvtf v30.2d, v29.2d, #1"); TEST_SINGLE(ucvtf(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "ucvtf v30.2d, v29.2d, #63"); - //TEST_SINGLE(ucvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.8b, v29.8b, #1"); - //TEST_SINGLE(ucvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ucvtf v30.8b, v29.8b, #7"); - TEST_SINGLE(ucvtf(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.4h, v29.4h, #1"); + // TEST_SINGLE(ucvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.8b, v29.8b, #1"); + // TEST_SINGLE(ucvtf(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "ucvtf v30.8b, v29.8b, #7"); + TEST_SINGLE(ucvtf(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.4h, v29.4h, #1"); TEST_SINGLE(ucvtf(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "ucvtf v30.4h, v29.4h, #15"); - TEST_SINGLE(ucvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.2s, v29.2s, #1"); + TEST_SINGLE(ucvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.2s, v29.2s, #1"); TEST_SINGLE(ucvtf(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "ucvtf v30.2s, v29.2s, #31"); - //TEST_SINGLE(ucvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.1d, v29.1d, #1"); - //TEST_SINGLE(ucvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ucvtf v30.1d, v29.1d, #63"); + // TEST_SINGLE(ucvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "ucvtf v30.1d, v29.1d, #1"); + // TEST_SINGLE(ucvtf(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "ucvtf v30.1d, v29.1d, #63"); - //TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.16b, v29.16b, #1"); - //TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "fcvtzu v30.16b, v29.16b, #7"); - TEST_SINGLE(fcvtzu(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.8h, v29.8h, #1"); + // TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.16b, v29.16b, #1"); + // TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, QReg::q30, QReg::q29, 7), "fcvtzu v30.16b, v29.16b, #7"); + TEST_SINGLE(fcvtzu(SubRegSize::i16Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.8h, v29.8h, #1"); TEST_SINGLE(fcvtzu(SubRegSize::i16Bit, QReg::q30, QReg::q29, 15), "fcvtzu v30.8h, v29.8h, #15"); - TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.4s, v29.4s, #1"); + TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.4s, v29.4s, #1"); TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, QReg::q30, QReg::q29, 31), "fcvtzu v30.4s, v29.4s, #31"); - TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.2d, v29.2d, #1"); + TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, QReg::q30, QReg::q29, 1), "fcvtzu v30.2d, v29.2d, #1"); TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, QReg::q30, QReg::q29, 63), "fcvtzu v30.2d, v29.2d, #63"); - //TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.8b, v29.8b, #1"); - //TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "fcvtzu v30.8b, v29.8b, #7"); - TEST_SINGLE(fcvtzu(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.4h, v29.4h, #1"); + // TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.8b, v29.8b, #1"); + // TEST_SINGLE(fcvtzu(SubRegSize::i8Bit, DReg::d30, DReg::d29, 7), "fcvtzu v30.8b, v29.8b, #7"); + TEST_SINGLE(fcvtzu(SubRegSize::i16Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.4h, v29.4h, #1"); TEST_SINGLE(fcvtzu(SubRegSize::i16Bit, DReg::d30, DReg::d29, 15), "fcvtzu v30.4h, v29.4h, #15"); - TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.2s, v29.2s, #1"); + TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.2s, v29.2s, #1"); TEST_SINGLE(fcvtzu(SubRegSize::i32Bit, DReg::d30, DReg::d29, 31), "fcvtzu v30.2s, v29.2s, #31"); - //TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.1d, v29.1d, #1"); - //TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "fcvtzu v30.1d, v29.1d, #63"); + // TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 1), "fcvtzu v30.1d, v29.1d, #1"); + // TEST_SINGLE(fcvtzu(SubRegSize::i64Bit, DReg::d30, DReg::d29, 63), "fcvtzu v30.1d, v29.1d, #63"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x indexed element") { @@ -2658,8 +2664,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(smlal(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "smlal v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(smlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlal v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(smlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlal v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(smlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlal v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(smlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlal v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(smlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "smlal v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(smlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "smlal v30.2d, v29.2s, v15.s[3]"); @@ -2668,8 +2674,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(smlal2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "smlal2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(smlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlal2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(smlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlal2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(smlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlal2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(smlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlal2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(smlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "smlal2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(smlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "smlal2 v30.2d, v29.4s, v15.s[3]"); @@ -2678,8 +2684,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmlal(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "sqdmlal v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlal v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(sqdmlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlal v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(sqdmlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlal v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(sqdmlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlal v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(sqdmlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "sqdmlal v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(sqdmlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "sqdmlal v30.2d, v29.2s, v15.s[3]"); @@ -2688,8 +2694,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmlal2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "sqdmlal2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlal2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(sqdmlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlal2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(sqdmlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlal2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(sqdmlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlal2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(sqdmlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "sqdmlal2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(sqdmlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "sqdmlal2 v30.2d, v29.4s, v15.s[3]"); @@ -2698,8 +2704,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(smlsl(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "smlsl v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(smlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlsl v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(smlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlsl v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(smlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlsl v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(smlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlsl v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(smlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "smlsl v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(smlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "smlsl v30.2d, v29.2s, v15.s[3]"); @@ -2708,8 +2714,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(smlsl2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "smlsl2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(smlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlsl2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(smlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlsl2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(smlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smlsl2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(smlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smlsl2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(smlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "smlsl2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(smlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "smlsl2 v30.2d, v29.4s, v15.s[3]"); @@ -2718,8 +2724,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmlsl(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "sqdmlsl v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlsl v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(sqdmlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlsl v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(sqdmlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlsl v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(sqdmlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlsl v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(sqdmlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "sqdmlsl v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(sqdmlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "sqdmlsl v30.2d, v29.2s, v15.s[3]"); @@ -2728,8 +2734,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmlsl2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "sqdmlsl2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlsl2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(sqdmlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlsl2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(sqdmlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmlsl2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(sqdmlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmlsl2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(sqdmlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "sqdmlsl2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(sqdmlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "sqdmlsl2 v30.2d, v29.4s, v15.s[3]"); @@ -2738,8 +2744,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(mul(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 7), "mul v30.8h, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(mul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "mul v30.4s, v29.4s, v28.s[0]"); - //TEST_SINGLE(mul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "mul v30.4s, v29.4s, v28.s[3]"); + // TEST_SINGLE(mul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "mul v30.4s, v29.4s, v28.s[0]"); + // TEST_SINGLE(mul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "mul v30.4s, v29.4s, v28.s[3]"); TEST_SINGLE(mul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "mul v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(mul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "mul v30.4s, v29.4s, v15.s[3]"); @@ -2748,8 +2754,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(mul(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d15, 7), "mul v30.4h, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(mul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "mul v30.2s, v29.2s, v28.s[0]"); - //TEST_SINGLE(mul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "mul v30.2s, v29.2s, v28.s[3]"); + // TEST_SINGLE(mul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "mul v30.2s, v29.2s, v28.s[0]"); + // TEST_SINGLE(mul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "mul v30.2s, v29.2s, v28.s[3]"); TEST_SINGLE(mul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 0), "mul v30.2s, v29.2s, v15.s[0]"); TEST_SINGLE(mul(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 3), "mul v30.2s, v29.2s, v15.s[3]"); @@ -2758,8 +2764,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(smull(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "smull v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(smull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smull v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(smull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smull v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(smull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smull v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(smull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smull v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(smull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "smull v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(smull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "smull v30.2d, v29.2s, v15.s[3]"); @@ -2768,8 +2774,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(smull2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "smull2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(smull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smull2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(smull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smull2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(smull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "smull2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(smull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "smull2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(smull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "smull2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(smull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "smull2 v30.2d, v29.4s, v15.s[3]"); @@ -2778,8 +2784,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmull(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "sqdmull v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmull v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(sqdmull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmull v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(sqdmull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmull v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(sqdmull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmull v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(sqdmull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "sqdmull v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(sqdmull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "sqdmull v30.2d, v29.2s, v15.s[3]"); @@ -2788,8 +2794,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmull2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "sqdmull2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmull2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(sqdmull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmull2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(sqdmull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "sqdmull2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(sqdmull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "sqdmull2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(sqdmull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "sqdmull2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(sqdmull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "sqdmull2 v30.2d, v29.4s, v15.s[3]"); @@ -2798,8 +2804,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmulh(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 7), "sqdmulh v30.8h, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqdmulh v30.4s, v29.4s, v28.s[0]"); - //TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqdmulh v30.4s, v29.4s, v28.s[3]"); + // TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqdmulh v30.4s, v29.4s, v28.s[0]"); + // TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqdmulh v30.4s, v29.4s, v28.s[3]"); TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "sqdmulh v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "sqdmulh v30.4s, v29.4s, v15.s[3]"); @@ -2808,8 +2814,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqdmulh(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d15, 7), "sqdmulh v30.4h, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqdmulh v30.2s, v29.2s, v28.s[0]"); - //TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqdmulh v30.2s, v29.2s, v28.s[3]"); + // TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqdmulh v30.2s, v29.2s, v28.s[0]"); + // TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqdmulh v30.2s, v29.2s, v28.s[3]"); TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 0), "sqdmulh v30.2s, v29.2s, v15.s[0]"); TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 3), "sqdmulh v30.2s, v29.2s, v15.s[3]"); @@ -2818,8 +2824,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqrdmulh(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 7), "sqrdmulh v30.8h, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqrdmulh v30.4s, v29.4s, v28.s[0]"); - //TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqrdmulh v30.4s, v29.4s, v28.s[3]"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqrdmulh v30.4s, v29.4s, v28.s[0]"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqrdmulh v30.4s, v29.4s, v28.s[3]"); TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "sqrdmulh v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "sqrdmulh v30.4s, v29.4s, v15.s[3]"); @@ -2828,8 +2834,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqrdmulh(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d15, 7), "sqrdmulh v30.4h, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqrdmulh v30.2s, v29.2s, v28.s[0]"); - //TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqrdmulh v30.2s, v29.2s, v28.s[3]"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqrdmulh v30.2s, v29.2s, v28.s[0]"); + // TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqrdmulh v30.2s, v29.2s, v28.s[3]"); TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 0), "sqrdmulh v30.2s, v29.2s, v15.s[0]"); TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 3), "sqrdmulh v30.2s, v29.2s, v15.s[3]"); @@ -2877,17 +2883,17 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sudot(DReg::d30, DReg::d29, DReg::d15, 3), "sudot v30.2s, v29.8b, v15.4b[3]"); // Unimplemented in vixl disassembler - //TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q28, 0), "bfdot v30.4s, v29.8h, v28.2h[0]"); - //TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q28, 3), "bfdot v30.4s, v29.8h, v28.2h[3]"); + // TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q28, 0), "bfdot v30.4s, v29.8h, v28.2h[0]"); + // TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q28, 3), "bfdot v30.4s, v29.8h, v28.2h[3]"); - //TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q15, 0), "bfdot v30.4s, v29.8h, v15.2h[0]"); - //TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q15, 3), "bfdot v30.4s, v29.8h, v15.2h[3]"); + // TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q15, 0), "bfdot v30.4s, v29.8h, v15.2h[0]"); + // TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q15, 3), "bfdot v30.4s, v29.8h, v15.2h[3]"); - //TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d28, 0), "bfdot v30.2s, v29.4h, v28.2h[0]"); - //TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d28, 3), "bfdot v30.2s, v29.4h, v28.2h[3]"); + // TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d28, 0), "bfdot v30.2s, v29.4h, v28.2h[0]"); + // TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d28, 3), "bfdot v30.2s, v29.4h, v28.2h[3]"); - //TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d15, 0), "bfdot v30.2s, v29.4h, v15.2h[0]"); - //TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d15, 3), "bfdot v30.2s, v29.4h, v15.2h[3]"); + // TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d15, 0), "bfdot v30.2s, v29.4h, v15.2h[0]"); + // TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d15, 3), "bfdot v30.2s, v29.4h, v15.2h[3]"); TEST_SINGLE(fmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "fmla v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(fmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "fmla v30.4s, v29.4s, v15.s[3]"); @@ -2898,8 +2904,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(fmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q15, 0), "fmla v30.2d, v29.2d, v15.d[0]"); TEST_SINGLE(fmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q15, 1), "fmla v30.2d, v29.2d, v15.d[1]"); - //TEST_SINGLE(fmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 0), "fmla v30.1d, v29.1d, v15.d[0]"); - //TEST_SINGLE(fmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 1), "fmla v30.1d, v29.1d, v15.d[1]"); + // TEST_SINGLE(fmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 0), "fmla v30.1d, v29.1d, v15.d[0]"); + // TEST_SINGLE(fmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 1), "fmla v30.1d, v29.1d, v15.d[1]"); TEST_SINGLE(fmls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "fmls v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(fmls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "fmls v30.4s, v29.4s, v15.s[3]"); @@ -2910,8 +2916,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(fmls(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q15, 0), "fmls v30.2d, v29.2d, v15.d[0]"); TEST_SINGLE(fmls(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q15, 1), "fmls v30.2d, v29.2d, v15.d[1]"); - //TEST_SINGLE(fmls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 0), "fmls v30.1d, v29.1d, v15.d[0]"); - //TEST_SINGLE(fmls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 1), "fmls v30.1d, v29.1d, v15.d[1]"); + // TEST_SINGLE(fmls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 0), "fmls v30.1d, v29.1d, v15.d[0]"); + // TEST_SINGLE(fmls(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 1), "fmls v30.1d, v29.1d, v15.d[1]"); TEST_SINGLE(fmul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "fmul v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(fmul(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "fmul v30.4s, v29.4s, v15.s[3]"); @@ -2922,8 +2928,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(fmul(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q15, 0), "fmul v30.2d, v29.2d, v15.d[0]"); TEST_SINGLE(fmul(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q15, 1), "fmul v30.2d, v29.2d, v15.d[1]"); - //TEST_SINGLE(fmul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 0), "fmul v30.1d, v29.1d, v15.d[0]"); - //TEST_SINGLE(fmul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 1), "fmul v30.1d, v29.1d, v15.d[1]"); + // TEST_SINGLE(fmul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 0), "fmul v30.1d, v29.1d, v15.d[0]"); + // TEST_SINGLE(fmul(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d15, 1), "fmul v30.1d, v29.1d, v15.d[1]"); TEST_SINGLE(fmlal(QReg::q30, QReg::q29, QReg::q15, 0), "fmlal v30.4s, v29.4h, v15.h[0]"); TEST_SINGLE(fmlal(QReg::q30, QReg::q29, QReg::q15, 7), "fmlal v30.4s, v29.4h, v15.h[7]"); @@ -2962,18 +2968,18 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(usdot(DReg::d30, DReg::d29, DReg::d15, 3), "usdot v30.2s, v29.8b, v15.4b[3]"); // Unimplemented in vixl disassembler - //TEST_SINGLE(bfmlalb(VReg::v30, VReg::v29, VReg::v15, 0), "bfmlalb v30.4s, v29.8h, v15.h[0]"); - //TEST_SINGLE(bfmlalb(VReg::v30, VReg::v29, VReg::v15, 7), "bfmlalb v30.4s, v29.8h, v15.h[7]"); + // TEST_SINGLE(bfmlalb(VReg::v30, VReg::v29, VReg::v15, 0), "bfmlalb v30.4s, v29.8h, v15.h[0]"); + // TEST_SINGLE(bfmlalb(VReg::v30, VReg::v29, VReg::v15, 7), "bfmlalb v30.4s, v29.8h, v15.h[7]"); - //TEST_SINGLE(bfmlalt(VReg::v30, VReg::v29, VReg::v15, 0), "bfmlalt v30.4s, v29.8h, v15.h[0]"); - //TEST_SINGLE(bfmlalt(VReg::v30, VReg::v29, VReg::v15, 7), "bfmlalt v30.4s, v29.8h, v15.h[7]"); + // TEST_SINGLE(bfmlalt(VReg::v30, VReg::v29, VReg::v15, 0), "bfmlalt v30.4s, v29.8h, v15.h[0]"); + // TEST_SINGLE(bfmlalt(VReg::v30, VReg::v29, VReg::v15, 7), "bfmlalt v30.4s, v29.8h, v15.h[7]"); TEST_SINGLE(mla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 0), "mla v30.8h, v29.8h, v15.h[0]"); TEST_SINGLE(mla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 7), "mla v30.8h, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(mla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "mla v30.4s, v29.4s, v28.s[0]"); - //TEST_SINGLE(mla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "mla v30.4s, v29.4s, v28.s[3]"); + // TEST_SINGLE(mla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "mla v30.4s, v29.4s, v28.s[0]"); + // TEST_SINGLE(mla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "mla v30.4s, v29.4s, v28.s[3]"); TEST_SINGLE(mla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "mla v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(mla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "mla v30.4s, v29.4s, v15.s[3]"); @@ -2982,8 +2988,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(mla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d15, 7), "mla v30.4h, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(mla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "mla v30.2s, v29.2s, v28.s[0]"); - //TEST_SINGLE(mla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "mla v30.2s, v29.2s, v28.s[3]"); + // TEST_SINGLE(mla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "mla v30.2s, v29.2s, v28.s[0]"); + // TEST_SINGLE(mla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "mla v30.2s, v29.2s, v28.s[3]"); TEST_SINGLE(mla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 0), "mla v30.2s, v29.2s, v15.s[0]"); TEST_SINGLE(mla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 3), "mla v30.2s, v29.2s, v15.s[3]"); @@ -2992,8 +2998,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(umlal(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "umlal v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(umlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlal v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(umlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlal v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(umlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlal v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(umlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlal v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(umlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "umlal v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(umlal(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "umlal v30.2d, v29.2s, v15.s[3]"); @@ -3002,8 +3008,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(umlal2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "umlal2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(umlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlal2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(umlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlal2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(umlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlal2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(umlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlal2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(umlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "umlal2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(umlal2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "umlal2 v30.2d, v29.4s, v15.s[3]"); @@ -3012,8 +3018,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(mls(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 7), "mls v30.8h, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(mls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "mls v30.4s, v29.4s, v28.s[0]"); - //TEST_SINGLE(mls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "mls v30.4s, v29.4s, v28.s[3]"); + // TEST_SINGLE(mls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "mls v30.4s, v29.4s, v28.s[0]"); + // TEST_SINGLE(mls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "mls v30.4s, v29.4s, v28.s[3]"); TEST_SINGLE(mls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "mls v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(mls(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "mls v30.4s, v29.4s, v15.s[3]"); @@ -3022,8 +3028,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(mls(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d15, 7), "mls v30.4h, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(mls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "mls v30.2s, v29.2s, v28.s[0]"); - //TEST_SINGLE(mls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "mls v30.2s, v29.2s, v28.s[3]"); + // TEST_SINGLE(mls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "mls v30.2s, v29.2s, v28.s[0]"); + // TEST_SINGLE(mls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "mls v30.2s, v29.2s, v28.s[3]"); TEST_SINGLE(mls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 0), "mls v30.2s, v29.2s, v15.s[0]"); TEST_SINGLE(mls(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 3), "mls v30.2s, v29.2s, v15.s[3]"); @@ -3032,8 +3038,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(umlsl(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "umlsl v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(umlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlsl v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(umlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlsl v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(umlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlsl v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(umlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlsl v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(umlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "umlsl v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(umlsl(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "umlsl v30.2d, v29.2s, v15.s[3]"); @@ -3042,8 +3048,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(umlsl2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "umlsl2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(umlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlsl2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(umlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlsl2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(umlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umlsl2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(umlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umlsl2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(umlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "umlsl2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(umlsl2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "umlsl2 v30.2d, v29.4s, v15.s[3]"); @@ -3052,8 +3058,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(umull(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "umull v30.4s, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(umull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umull v30.2d, v29.2s, v28.s[0]"); - //TEST_SINGLE(umull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umull v30.2d, v29.2s, v28.s[3]"); + // TEST_SINGLE(umull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umull v30.2d, v29.2s, v28.s[0]"); + // TEST_SINGLE(umull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umull v30.2d, v29.2s, v28.s[3]"); TEST_SINGLE(umull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "umull v30.2d, v29.2s, v15.s[0]"); TEST_SINGLE(umull(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "umull v30.2d, v29.2s, v15.s[3]"); @@ -3062,8 +3068,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(umull2(SubRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v15, 7), "umull2 v30.4s, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(umull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umull2 v30.2d, v29.4s, v28.s[0]"); - //TEST_SINGLE(umull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umull2 v30.2d, v29.4s, v28.s[3]"); + // TEST_SINGLE(umull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 0), "umull2 v30.2d, v29.4s, v28.s[0]"); + // TEST_SINGLE(umull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28, 3), "umull2 v30.2d, v29.4s, v28.s[3]"); TEST_SINGLE(umull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 0), "umull2 v30.2d, v29.4s, v15.s[0]"); TEST_SINGLE(umull2(SubRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v15, 3), "umull2 v30.2d, v29.4s, v15.s[3]"); @@ -3072,8 +3078,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqrdmlah(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 7), "sqrdmlah v30.8h, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqrdmlah v30.4s, v29.4s, v28.s[0]"); - //TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqrdmlah v30.4s, v29.4s, v28.s[3]"); + // TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqrdmlah v30.4s, v29.4s, v28.s[0]"); + // TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqrdmlah v30.4s, v29.4s, v28.s[3]"); TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "sqrdmlah v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "sqrdmlah v30.4s, v29.4s, v15.s[3]"); @@ -3082,8 +3088,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqrdmlah(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d15, 7), "sqrdmlah v30.4h, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqrdmlah v30.2s, v29.2s, v28.s[0]"); - //TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqrdmlah v30.2s, v29.2s, v28.s[3]"); + // TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqrdmlah v30.2s, v29.2s, v28.s[0]"); + // TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqrdmlah v30.2s, v29.2s, v28.s[3]"); TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 0), "sqrdmlah v30.2s, v29.2s, v15.s[0]"); TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 3), "sqrdmlah v30.2s, v29.2s, v15.s[3]"); @@ -3104,8 +3110,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqrdmlsh(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q15, 7), "sqrdmlsh v30.8h, v29.8h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqrdmlsh v30.4s, v29.4s, v28.s[0]"); - //TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqrdmlsh v30.4s, v29.4s, v28.s[3]"); + // TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 0), "sqrdmlsh v30.4s, v29.4s, v28.s[0]"); + // TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, 3), "sqrdmlsh v30.4s, v29.4s, v28.s[3]"); TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 0), "sqrdmlsh v30.4s, v29.4s, v15.s[0]"); TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q15, 3), "sqrdmlsh v30.4s, v29.4s, v15.s[3]"); @@ -3114,8 +3120,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD vector x index TEST_SINGLE(sqrdmlsh(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d15, 7), "sqrdmlsh v30.4h, v29.4h, v15.h[7]"); // vixl has a disassembler bug where it doesn't decode rm correctly for registers >= 16 - //TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqrdmlsh v30.2s, v29.2s, v28.s[0]"); - //TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqrdmlsh v30.2s, v29.2s, v28.s[3]"); + // TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 0), "sqrdmlsh v30.2s, v29.2s, v28.s[0]"); + // TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, 3), "sqrdmlsh v30.2s, v29.2s, v28.s[3]"); TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 0), "sqrdmlsh v30.2s, v29.2s, v15.s[0]"); TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d15, 3), "sqrdmlsh v30.2s, v29.2s, v15.s[3]"); @@ -3133,60 +3139,60 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Cryptographic two-register S // TODO: Implement in emitter. } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Conversion between floating-point and fixed-point") { - TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "scvtf h29, w30, #1"); + TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "scvtf h29, w30, #1"); TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i32Bit, Reg::r30, 32), "scvtf h29, w30, #32"); - TEST_SINGLE(scvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "scvtf s29, w30, #1"); + TEST_SINGLE(scvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "scvtf s29, w30, #1"); TEST_SINGLE(scvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i32Bit, Reg::r30, 32), "scvtf s29, w30, #32"); - TEST_SINGLE(scvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "scvtf d29, w30, #1"); + TEST_SINGLE(scvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "scvtf d29, w30, #1"); TEST_SINGLE(scvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i32Bit, Reg::r30, 32), "scvtf d29, w30, #32"); - TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "scvtf h29, x30, #1"); + TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "scvtf h29, x30, #1"); TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i64Bit, Reg::r30, 64), "scvtf h29, x30, #64"); - TEST_SINGLE(scvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "scvtf s29, x30, #1"); + TEST_SINGLE(scvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "scvtf s29, x30, #1"); TEST_SINGLE(scvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i64Bit, Reg::r30, 64), "scvtf s29, x30, #64"); - TEST_SINGLE(scvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "scvtf d29, x30, #1"); + TEST_SINGLE(scvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "scvtf d29, x30, #1"); TEST_SINGLE(scvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i64Bit, Reg::r30, 64), "scvtf d29, x30, #64"); - TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "ucvtf h29, w30, #1"); + TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "ucvtf h29, w30, #1"); TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i32Bit, Reg::r30, 32), "ucvtf h29, w30, #32"); - TEST_SINGLE(ucvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "ucvtf s29, w30, #1"); + TEST_SINGLE(ucvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "ucvtf s29, w30, #1"); TEST_SINGLE(ucvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i32Bit, Reg::r30, 32), "ucvtf s29, w30, #32"); - TEST_SINGLE(ucvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "ucvtf d29, w30, #1"); + TEST_SINGLE(ucvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i32Bit, Reg::r30, 1), "ucvtf d29, w30, #1"); TEST_SINGLE(ucvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i32Bit, Reg::r30, 32), "ucvtf d29, w30, #32"); - TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "ucvtf h29, x30, #1"); + TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "ucvtf h29, x30, #1"); TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v29, Size::i64Bit, Reg::r30, 64), "ucvtf h29, x30, #64"); - TEST_SINGLE(ucvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "ucvtf s29, x30, #1"); + TEST_SINGLE(ucvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "ucvtf s29, x30, #1"); TEST_SINGLE(ucvtf(ScalarRegSize::i32Bit, VReg::v29, Size::i64Bit, Reg::r30, 64), "ucvtf s29, x30, #64"); - TEST_SINGLE(ucvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "ucvtf d29, x30, #1"); + TEST_SINGLE(ucvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i64Bit, Reg::r30, 1), "ucvtf d29, x30, #1"); TEST_SINGLE(ucvtf(ScalarRegSize::i64Bit, VReg::v29, Size::i64Bit, Reg::r30, 64), "ucvtf d29, x30, #64"); - TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzs w30, h29, #1"); + TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzs w30, h29, #1"); TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 32), "fcvtzs w30, h29, #32"); - TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzs w30, s29, #1"); + TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzs w30, s29, #1"); TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 32), "fcvtzs w30, s29, #32"); - TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzs w30, d29, #1"); + TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzs w30, d29, #1"); TEST_SINGLE(fcvtzs(Size::i32Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 32), "fcvtzs w30, d29, #32"); - TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzs x30, h29, #1"); + TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzs x30, h29, #1"); TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 64), "fcvtzs x30, h29, #64"); - TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzs x30, s29, #1"); + TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzs x30, s29, #1"); TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 64), "fcvtzs x30, s29, #64"); - TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzs x30, d29, #1"); + TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzs x30, d29, #1"); TEST_SINGLE(fcvtzs(Size::i64Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 64), "fcvtzs x30, d29, #64"); - TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzu w30, h29, #1"); + TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzu w30, h29, #1"); TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 32), "fcvtzu w30, h29, #32"); - TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzu w30, s29, #1"); + TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzu w30, s29, #1"); TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 32), "fcvtzu w30, s29, #32"); - TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzu w30, d29, #1"); + TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzu w30, d29, #1"); TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 32), "fcvtzu w30, d29, #32"); - TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzu x30, h29, #1"); + TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 1), "fcvtzu x30, h29, #1"); TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i16Bit, VReg::v29, 64), "fcvtzu x30, h29, #64"); - TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzu x30, s29, #1"); + TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 1), "fcvtzu x30, s29, #1"); TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i32Bit, VReg::v29, 64), "fcvtzu x30, s29, #64"); - TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzu x30, d29, #1"); + TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 1), "fcvtzu x30, d29, #1"); TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r30, ScalarRegSize::i64Bit, VReg::v29, 64), "fcvtzu x30, d29, #64"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Conversion between floating-point and integer") { @@ -3235,27 +3241,27 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Conversion between floating- TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, HReg::h30), "fmov w29, h30"); TEST_SINGLE(fmov(Size::i64Bit, Reg::r29, HReg::h30), "fmov x29, h30"); TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, SReg::s30), "fmov w29, s30"); - //TEST_SINGLE(fmov(Size::i64Bit, Reg::r29, SReg::s30), "fmov x29, s30"); - //TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, DReg::d30), "fmov w29, d30"); + // TEST_SINGLE(fmov(Size::i64Bit, Reg::r29, SReg::s30), "fmov x29, s30"); + // TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, DReg::d30), "fmov w29, d30"); TEST_SINGLE(fmov(Size::i64Bit, Reg::r29, DReg::d30), "fmov x29, d30"); - //TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, VReg::v30, false), "fmov w29, s30"); + // TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, VReg::v30, false), "fmov w29, s30"); TEST_SINGLE(fmov(Size::i64Bit, Reg::r29, VReg::v30, false), "fmov x29, d30"); - //TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, VReg::v30, true), "fmov w29, s30"); + // TEST_SINGLE(fmov(Size::i32Bit, Reg::r29, VReg::v30, true), "fmov w29, s30"); TEST_SINGLE(fmov(Size::i64Bit, Reg::r29, VReg::v30, true), "fmov x29, v30.D[1]"); TEST_SINGLE(fmov(Size::i32Bit, HReg::h30, Reg::r29), "fmov h30, w29"); TEST_SINGLE(fmov(Size::i64Bit, HReg::h30, Reg::r29), "fmov h30, x29"); TEST_SINGLE(fmov(Size::i32Bit, SReg::s30, Reg::r29), "fmov s30, w29"); - //TEST_SINGLE(fmov(Size::i64Bit, SReg::s30, Reg::r29), "fmov s30, x29"); - //TEST_SINGLE(fmov(Size::i32Bit, DReg::d30, Reg::r29), "fmov d30, w29"); + // TEST_SINGLE(fmov(Size::i64Bit, SReg::s30, Reg::r29), "fmov s30, x29"); + // TEST_SINGLE(fmov(Size::i32Bit, DReg::d30, Reg::r29), "fmov d30, w29"); TEST_SINGLE(fmov(Size::i64Bit, DReg::d30, Reg::r29), "fmov d30, x29"); - //TEST_SINGLE(fmov(Size::i32Bit, VReg::v30, Reg::r29, false), "fmov s30, w29"); + // TEST_SINGLE(fmov(Size::i32Bit, VReg::v30, Reg::r29, false), "fmov s30, w29"); TEST_SINGLE(fmov(Size::i64Bit, VReg::v30, Reg::r29, false), "fmov d30, x29"); - //TEST_SINGLE(fmov(Size::i32Bit, VReg::v30, Reg::r29, true), "fmov d30, x29"); + // TEST_SINGLE(fmov(Size::i32Bit, VReg::v30, Reg::r29, true), "fmov d30, x29"); TEST_SINGLE(fmov(Size::i64Bit, VReg::v30, Reg::r29, true), "fmov v30.D[1], x29"); TEST_SINGLE(fcvtps(Size::i32Bit, Reg::r29, HReg::h30), "fcvtps w29, h30"); @@ -3300,5 +3306,3 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Conversion between floating- TEST_SINGLE(fcvtzu(Size::i32Bit, Reg::r29, DReg::d30), "fcvtzu w29, d30"); TEST_SINGLE(fcvtzu(Size::i64Bit, Reg::r29, DReg::d30), "fcvtzu x29, d30"); } - - diff --git a/FEXCore/unittests/Emitter/Loadstore_Tests.cpp b/FEXCore/unittests/Emitter/Loadstore_Tests.cpp index ee45a1f89..2244c9dc6 100644 --- a/FEXCore/unittests/Emitter/Loadstore_Tests.cpp +++ b/FEXCore/unittests/Emitter/Loadstore_Tests.cpp @@ -31,8 +31,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, Reg::r30), "ld1 {v26.2d}, [x30]"); TEST_SINGLE(ld1(DReg::d26, Reg::r30), "ld1 {v26.1d}, [x30]"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, Reg::r30), "ld1 {v31.16b, v0.16b}, [x30]"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, Reg::r30), "ld1 {v31.8b, v0.8b}, [x30]"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, Reg::r30), "ld1 {v31.16b, v0.16b}, [x30]"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, Reg::r30), "ld1 {v31.8b, v0.8b}, [x30]"); TEST_SINGLE(ld1(QReg::q26, QReg::q27, Reg::r30), "ld1 {v26.16b, v27.16b}, [x30]"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, Reg::r30), "ld1 {v26.8b, v27.8b}, [x30]"); @@ -45,8 +45,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, QReg::q27, Reg::r30), "ld1 {v26.2d, v27.2d}, [x30]"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, Reg::r30), "ld1 {v26.1d, v27.1d}, [x30]"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "ld1 {v31.16b, v0.16b, v1.16b}, [x30]"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "ld1 {v31.8b, v0.8b, v1.8b}, [x30]"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "ld1 {v31.16b, v0.16b, v1.16b}, [x30]"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "ld1 {v31.8b, v0.8b, v1.8b}, [x30]"); TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld1 {v26.16b, v27.16b, v28.16b}, [x30]"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld1 {v26.8b, v27.8b, v28.8b}, [x30]"); @@ -59,9 +59,10 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld1 {v26.2d, v27.2d, v28.2d}, [x30]"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld1 {v26.1d, v27.1d, v28.1d}, [x30]"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "ld1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "ld1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld1 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30]"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "ld1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "ld1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld1 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30]"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld1 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30]"); TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld1 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30]"); @@ -85,8 +86,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, Reg::r30), "st1 {v26.2d}, [x30]"); TEST_SINGLE(st1(DReg::d26, Reg::r30), "st1 {v26.1d}, [x30]"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, Reg::r30), "st1 {v31.16b, v0.16b}, [x30]"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, Reg::r30), "st1 {v31.8b, v0.8b}, [x30]"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, Reg::r30), "st1 {v31.16b, v0.16b}, [x30]"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, Reg::r30), "st1 {v31.8b, v0.8b}, [x30]"); TEST_SINGLE(st1(QReg::q26, QReg::q27, Reg::r30), "st1 {v26.16b, v27.16b}, [x30]"); TEST_SINGLE(st1(DReg::d26, DReg::d27, Reg::r30), "st1 {v26.8b, v27.8b}, [x30]"); @@ -99,8 +100,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, QReg::q27, Reg::r30), "st1 {v26.2d, v27.2d}, [x30]"); TEST_SINGLE(st1(DReg::d26, DReg::d27, Reg::r30), "st1 {v26.1d, v27.1d}, [x30]"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "st1 {v31.16b, v0.16b, v1.16b}, [x30]"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "st1 {v31.8b, v0.8b, v1.8b}, [x30]"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "st1 {v31.16b, v0.16b, v1.16b}, [x30]"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "st1 {v31.8b, v0.8b, v1.8b}, [x30]"); TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "st1 {v26.16b, v27.16b, v28.16b}, [x30]"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "st1 {v26.8b, v27.8b, v28.8b}, [x30]"); @@ -113,9 +114,10 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "st1 {v26.2d, v27.2d, v28.2d}, [x30]"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "st1 {v26.1d, v27.1d, v28.1d}, [x30]"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "st1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "st1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "st1 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30]"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "st1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "st1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "st1 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30]"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "st1 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30]"); TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "st1 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30]"); @@ -127,8 +129,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "st1 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30]"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "st1 {v26.1d, v27.1d, v28.1d, v29.1d}, [x30]"); - TEST_SINGLE(ld2(QReg::q31, QReg::q0, Reg::r30), "ld2 {v31.16b, v0.16b}, [x30]"); - TEST_SINGLE(ld2(DReg::d31, DReg::d0, Reg::r30), "ld2 {v31.8b, v0.8b}, [x30]"); + TEST_SINGLE(ld2(QReg::q31, QReg::q0, Reg::r30), "ld2 {v31.16b, v0.16b}, [x30]"); + TEST_SINGLE(ld2(DReg::d31, DReg::d0, Reg::r30), "ld2 {v31.8b, v0.8b}, [x30]"); TEST_SINGLE(ld2(QReg::q26, QReg::q27, Reg::r30), "ld2 {v26.16b, v27.16b}, [x30]"); TEST_SINGLE(ld2(DReg::d26, DReg::d27, Reg::r30), "ld2 {v26.8b, v27.8b}, [x30]"); @@ -141,8 +143,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld2(QReg::q26, QReg::q27, Reg::r30), "ld2 {v26.2d, v27.2d}, [x30]"); TEST_SINGLE(ld2(DReg::d26, DReg::d27, Reg::r30), "unallocated (NEONLoadStoreMultiStruct)"); - TEST_SINGLE(st2(QReg::q31, QReg::q0, Reg::r30), "st2 {v31.16b, v0.16b}, [x30]"); - TEST_SINGLE(st2(DReg::d31, DReg::d0, Reg::r30), "st2 {v31.8b, v0.8b}, [x30]"); + TEST_SINGLE(st2(QReg::q31, QReg::q0, Reg::r30), "st2 {v31.16b, v0.16b}, [x30]"); + TEST_SINGLE(st2(DReg::d31, DReg::d0, Reg::r30), "st2 {v31.8b, v0.8b}, [x30]"); TEST_SINGLE(st2(QReg::q26, QReg::q27, Reg::r30), "st2 {v26.16b, v27.16b}, [x30]"); TEST_SINGLE(st2(DReg::d26, DReg::d27, Reg::r30), "st2 {v26.8b, v27.8b}, [x30]"); @@ -155,8 +157,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st2(QReg::q26, QReg::q27, Reg::r30), "st2 {v26.2d, v27.2d}, [x30]"); TEST_SINGLE(st2(DReg::d26, DReg::d27, Reg::r30), "unallocated (NEONLoadStoreMultiStruct)"); - TEST_SINGLE(ld3(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "ld3 {v31.16b, v0.16b, v1.16b}, [x30]"); - TEST_SINGLE(ld3(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "ld3 {v31.8b, v0.8b, v1.8b}, [x30]"); + TEST_SINGLE(ld3(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "ld3 {v31.16b, v0.16b, v1.16b}, [x30]"); + TEST_SINGLE(ld3(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "ld3 {v31.8b, v0.8b, v1.8b}, [x30]"); TEST_SINGLE(ld3(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld3 {v26.16b, v27.16b, v28.16b}, [x30]"); TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld3 {v26.8b, v27.8b, v28.8b}, [x30]"); @@ -169,8 +171,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld3(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld3 {v26.2d, v27.2d, v28.2d}, [x30]"); TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "unallocated (NEONLoadStoreMultiStruct)"); - TEST_SINGLE(st3(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "st3 {v31.16b, v0.16b, v1.16b}, [x30]"); - TEST_SINGLE(st3(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "st3 {v31.8b, v0.8b, v1.8b}, [x30]"); + TEST_SINGLE(st3(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "st3 {v31.16b, v0.16b, v1.16b}, [x30]"); + TEST_SINGLE(st3(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "st3 {v31.8b, v0.8b, v1.8b}, [x30]"); TEST_SINGLE(st3(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "st3 {v26.16b, v27.16b, v28.16b}, [x30]"); TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "st3 {v26.8b, v27.8b, v28.8b}, [x30]"); @@ -183,9 +185,10 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st3(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "st3 {v26.2d, v27.2d, v28.2d}, [x30]"); TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "unallocated (NEONLoadStoreMultiStruct)"); - TEST_SINGLE(ld4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "ld4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); - TEST_SINGLE(ld4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "ld4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30]"); + TEST_SINGLE(ld4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "ld4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); + TEST_SINGLE(ld4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "ld4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30]"); TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30]"); TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30]"); @@ -197,9 +200,10 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30]"); TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "unallocated (NEONLoadStoreMultiStruct)"); - TEST_SINGLE(st4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "st4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); - TEST_SINGLE(st4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "st4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "st4 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30]"); + TEST_SINGLE(st4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "st4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); + TEST_SINGLE(st4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "st4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "st4 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30]"); TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "st4 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30]"); TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "st4 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30]"); @@ -237,8 +241,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, Reg::r30, 16), "ld1 {v26.2d}, [x30], #16"); TEST_SINGLE(ld1(DReg::d26, Reg::r30, 8), "ld1 {v26.1d}, [x30], #8"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "ld1 {v31.16b, v0.16b}, [x30], x29"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "ld1 {v31.8b, v0.8b}, [x30], x29"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "ld1 {v31.16b, v0.16b}, [x30], x29"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "ld1 {v31.8b, v0.8b}, [x30], x29"); TEST_SINGLE(ld1(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld1 {v26.16b, v27.16b}, [x30], x29"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld1 {v26.8b, v27.8b}, [x30], x29"); @@ -251,8 +255,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld1 {v26.2d, v27.2d}, [x30], x29"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld1 {v26.1d, v27.1d}, [x30], x29"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, Reg::r30, 32), "ld1 {v31.16b, v0.16b}, [x30], #32"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, Reg::r30, 16), "ld1 {v31.8b, v0.8b}, [x30], #16"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, Reg::r30, 32), "ld1 {v31.16b, v0.16b}, [x30], #32"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, Reg::r30, 16), "ld1 {v31.8b, v0.8b}, [x30], #16"); TEST_SINGLE(ld1(QReg::q26, QReg::q27, Reg::r30, 32), "ld1 {v26.16b, v27.16b}, [x30], #32"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, Reg::r30, 16), "ld1 {v26.8b, v27.8b}, [x30], #16"); @@ -265,8 +269,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, QReg::q27, Reg::r30, 32), "ld1 {v26.2d, v27.2d}, [x30], #32"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, Reg::r30, 16), "ld1 {v26.1d, v27.1d}, [x30], #16"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "ld1 {v31.16b, v0.16b, v1.16b}, [x30], x29"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "ld1 {v31.8b, v0.8b, v1.8b}, [x30], x29"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "ld1 {v31.16b, v0.16b, v1.16b}, [x30], x29"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "ld1 {v31.8b, v0.8b, v1.8b}, [x30], x29"); TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld1 {v26.16b, v27.16b, v28.16b}, [x30], x29"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld1 {v26.8b, v27.8b, v28.8b}, [x30], x29"); @@ -279,8 +283,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld1 {v26.2d, v27.2d, v28.2d}, [x30], x29"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld1 {v26.1d, v27.1d, v28.1d}, [x30], x29"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "ld1 {v31.16b, v0.16b, v1.16b}, [x30], #48"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "ld1 {v31.8b, v0.8b, v1.8b}, [x30], #24"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "ld1 {v31.16b, v0.16b, v1.16b}, [x30], #48"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "ld1 {v31.8b, v0.8b, v1.8b}, [x30], #24"); TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "ld1 {v26.16b, v27.16b, v28.16b}, [x30], #48"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "ld1 {v26.8b, v27.8b, v28.8b}, [x30], #24"); @@ -293,33 +297,53 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "ld1 {v26.2d, v27.2d, v28.2d}, [x30], #48"); TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "ld1 {v26.1d, v27.1d, v28.1d}, [x30], #24"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "ld1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], x29"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "ld1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], x29"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], x29"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], x29"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "ld1 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], x29"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "ld1 {v31.8b, v0.8b, v1.8b, v2.8b}, " + "[x30], x29"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.16b, v27.16b, v28.16b, " + "v29.16b}, [x30], x29"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.8b, v27.8b, v28.8b, " + "v29.8b}, [x30], x29"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], x29"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], x29"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.8h, v27.8h, v28.8h, " + "v29.8h}, [x30], x29"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.4h, v27.4h, v28.4h, " + "v29.4h}, [x30], x29"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], x29"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], x29"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.4s, v27.4s, v28.4s, " + "v29.4s}, [x30], x29"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.2s, v27.2s, v28.2s, " + "v29.2s}, [x30], x29"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], x29"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.1d, v27.1d, v28.1d, v29.1d}, [x30], x29"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld1 {v26.2d, v27.2d, v28.2d, " + "v29.2d}, [x30], x29"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld1 {v26.1d, v27.1d, v28.1d, " + "v29.1d}, [x30], x29"); - TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "ld1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], #64"); - TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "ld1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], #32"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], #64"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], #32"); + TEST_SINGLE(ld1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "ld1 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], #64"); + TEST_SINGLE(ld1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "ld1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], " + "#32"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30], #64"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.8b, v27.8b, v28.8b, v29.8b}, " + "[x30], #32"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], #64"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], #32"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.8h, v27.8h, v28.8h, v29.8h}, " + "[x30], #64"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.4h, v27.4h, v28.4h, v29.4h}, " + "[x30], #32"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], #64"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], #32"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.4s, v27.4s, v28.4s, v29.4s}, " + "[x30], #64"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.2s, v27.2s, v28.2s, v29.2s}, " + "[x30], #32"); - TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], #64"); - TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.1d, v27.1d, v28.1d, v29.1d}, [x30], #32"); + TEST_SINGLE(ld1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld1 {v26.2d, v27.2d, v28.2d, v29.2d}, " + "[x30], #64"); + TEST_SINGLE(ld1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld1 {v26.1d, v27.1d, v28.1d, v29.1d}, " + "[x30], #32"); TEST_SINGLE(st1(QReg::q26, Reg::r30, Reg::r29), "st1 {v26.16b}, [x30], x29"); TEST_SINGLE(st1(DReg::d26, Reg::r30, Reg::r29), "st1 {v26.8b}, [x30], x29"); @@ -345,8 +369,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, Reg::r30, 16), "st1 {v26.2d}, [x30], #16"); TEST_SINGLE(st1(DReg::d26, Reg::r30, 8), "st1 {v26.1d}, [x30], #8"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "st1 {v31.16b, v0.16b}, [x30], x29"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "st1 {v31.8b, v0.8b}, [x30], x29"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "st1 {v31.16b, v0.16b}, [x30], x29"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "st1 {v31.8b, v0.8b}, [x30], x29"); TEST_SINGLE(st1(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "st1 {v26.16b, v27.16b}, [x30], x29"); TEST_SINGLE(st1(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "st1 {v26.8b, v27.8b}, [x30], x29"); @@ -359,8 +383,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "st1 {v26.2d, v27.2d}, [x30], x29"); TEST_SINGLE(st1(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "st1 {v26.1d, v27.1d}, [x30], x29"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, Reg::r30, 32), "st1 {v31.16b, v0.16b}, [x30], #32"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, Reg::r30, 16), "st1 {v31.8b, v0.8b}, [x30], #16"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, Reg::r30, 32), "st1 {v31.16b, v0.16b}, [x30], #32"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, Reg::r30, 16), "st1 {v31.8b, v0.8b}, [x30], #16"); TEST_SINGLE(st1(QReg::q26, QReg::q27, Reg::r30, 32), "st1 {v26.16b, v27.16b}, [x30], #32"); TEST_SINGLE(st1(DReg::d26, DReg::d27, Reg::r30, 16), "st1 {v26.8b, v27.8b}, [x30], #16"); @@ -373,8 +397,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, QReg::q27, Reg::r30, 32), "st1 {v26.2d, v27.2d}, [x30], #32"); TEST_SINGLE(st1(DReg::d26, DReg::d27, Reg::r30, 16), "st1 {v26.1d, v27.1d}, [x30], #16"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "st1 {v31.16b, v0.16b, v1.16b}, [x30], x29"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "st1 {v31.8b, v0.8b, v1.8b}, [x30], x29"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "st1 {v31.16b, v0.16b, v1.16b}, [x30], x29"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "st1 {v31.8b, v0.8b, v1.8b}, [x30], x29"); TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "st1 {v26.16b, v27.16b, v28.16b}, [x30], x29"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "st1 {v26.8b, v27.8b, v28.8b}, [x30], x29"); @@ -387,8 +411,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "st1 {v26.2d, v27.2d, v28.2d}, [x30], x29"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "st1 {v26.1d, v27.1d, v28.1d}, [x30], x29"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "st1 {v31.16b, v0.16b, v1.16b}, [x30], #48"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "st1 {v31.8b, v0.8b, v1.8b}, [x30], #24"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "st1 {v31.16b, v0.16b, v1.16b}, [x30], #48"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "st1 {v31.8b, v0.8b, v1.8b}, [x30], #24"); TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "st1 {v26.16b, v27.16b, v28.16b}, [x30], #48"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "st1 {v26.8b, v27.8b, v28.8b}, [x30], #24"); @@ -401,36 +425,56 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "st1 {v26.2d, v27.2d, v28.2d}, [x30], #48"); TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "st1 {v26.1d, v27.1d, v28.1d}, [x30], #24"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "st1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], x29"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "st1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], x29"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], x29"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], x29"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "st1 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], x29"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "st1 {v31.8b, v0.8b, v1.8b, v2.8b}, " + "[x30], x29"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.16b, v27.16b, v28.16b, " + "v29.16b}, [x30], x29"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.8b, v27.8b, v28.8b, " + "v29.8b}, [x30], x29"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], x29"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], x29"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.8h, v27.8h, v28.8h, " + "v29.8h}, [x30], x29"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.4h, v27.4h, v28.4h, " + "v29.4h}, [x30], x29"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], x29"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], x29"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.4s, v27.4s, v28.4s, " + "v29.4s}, [x30], x29"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.2s, v27.2s, v28.2s, " + "v29.2s}, [x30], x29"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], x29"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.1d, v27.1d, v28.1d, v29.1d}, [x30], x29"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st1 {v26.2d, v27.2d, v28.2d, " + "v29.2d}, [x30], x29"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st1 {v26.1d, v27.1d, v28.1d, " + "v29.1d}, [x30], x29"); - TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "st1 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], #64"); - TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "st1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], #32"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], #64"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], #32"); + TEST_SINGLE(st1(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "st1 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], #64"); + TEST_SINGLE(st1(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "st1 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], " + "#32"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30], #64"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.8b, v27.8b, v28.8b, v29.8b}, " + "[x30], #32"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], #64"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], #32"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.8h, v27.8h, v28.8h, v29.8h}, " + "[x30], #64"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.4h, v27.4h, v28.4h, v29.4h}, " + "[x30], #32"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], #64"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], #32"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.4s, v27.4s, v28.4s, v29.4s}, " + "[x30], #64"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.2s, v27.2s, v28.2s, v29.2s}, " + "[x30], #32"); - TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], #64"); - TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.1d, v27.1d, v28.1d, v29.1d}, [x30], #32"); + TEST_SINGLE(st1(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st1 {v26.2d, v27.2d, v28.2d, v29.2d}, " + "[x30], #64"); + TEST_SINGLE(st1(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st1 {v26.1d, v27.1d, v28.1d, v29.1d}, " + "[x30], #32"); - TEST_SINGLE(ld2(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "ld2 {v31.16b, v0.16b}, [x30], x29"); - TEST_SINGLE(ld2(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "ld2 {v31.8b, v0.8b}, [x30], x29"); + TEST_SINGLE(ld2(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "ld2 {v31.16b, v0.16b}, [x30], x29"); + TEST_SINGLE(ld2(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "ld2 {v31.8b, v0.8b}, [x30], x29"); TEST_SINGLE(ld2(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld2 {v26.16b, v27.16b}, [x30], x29"); TEST_SINGLE(ld2(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld2 {v26.8b, v27.8b}, [x30], x29"); @@ -443,8 +487,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld2(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld2 {v26.2d, v27.2d}, [x30], x29"); TEST_SINGLE(ld2(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "unallocated (NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(ld2(QReg::q31, QReg::q0, Reg::r30, 32), "ld2 {v31.16b, v0.16b}, [x30], #32"); - TEST_SINGLE(ld2(DReg::d31, DReg::d0, Reg::r30, 16), "ld2 {v31.8b, v0.8b}, [x30], #16"); + TEST_SINGLE(ld2(QReg::q31, QReg::q0, Reg::r30, 32), "ld2 {v31.16b, v0.16b}, [x30], #32"); + TEST_SINGLE(ld2(DReg::d31, DReg::d0, Reg::r30, 16), "ld2 {v31.8b, v0.8b}, [x30], #16"); TEST_SINGLE(ld2(QReg::q26, QReg::q27, Reg::r30, 32), "ld2 {v26.16b, v27.16b}, [x30], #32"); TEST_SINGLE(ld2(DReg::d26, DReg::d27, Reg::r30, 16), "ld2 {v26.8b, v27.8b}, [x30], #16"); @@ -457,8 +501,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld2(QReg::q26, QReg::q27, Reg::r30, 32), "ld2 {v26.2d, v27.2d}, [x30], #32"); TEST_SINGLE(ld2(DReg::d26, DReg::d27, Reg::r30, 16), "unallocated (NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(st2(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "st2 {v31.16b, v0.16b}, [x30], x29"); - TEST_SINGLE(st2(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "st2 {v31.8b, v0.8b}, [x30], x29"); + TEST_SINGLE(st2(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "st2 {v31.16b, v0.16b}, [x30], x29"); + TEST_SINGLE(st2(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "st2 {v31.8b, v0.8b}, [x30], x29"); TEST_SINGLE(st2(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "st2 {v26.16b, v27.16b}, [x30], x29"); TEST_SINGLE(st2(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "st2 {v26.8b, v27.8b}, [x30], x29"); @@ -471,8 +515,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st2(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "st2 {v26.2d, v27.2d}, [x30], x29"); TEST_SINGLE(st2(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "unallocated (NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(st2(QReg::q31, QReg::q0, Reg::r30, 32), "st2 {v31.16b, v0.16b}, [x30], #32"); - TEST_SINGLE(st2(DReg::d31, DReg::d0, Reg::r30, 16), "st2 {v31.8b, v0.8b}, [x30], #16"); + TEST_SINGLE(st2(QReg::q31, QReg::q0, Reg::r30, 32), "st2 {v31.16b, v0.16b}, [x30], #32"); + TEST_SINGLE(st2(DReg::d31, DReg::d0, Reg::r30, 16), "st2 {v31.8b, v0.8b}, [x30], #16"); TEST_SINGLE(st2(QReg::q26, QReg::q27, Reg::r30, 32), "st2 {v26.16b, v27.16b}, [x30], #32"); TEST_SINGLE(st2(DReg::d26, DReg::d27, Reg::r30, 16), "st2 {v26.8b, v27.8b}, [x30], #16"); @@ -485,8 +529,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st2(QReg::q26, QReg::q27, Reg::r30, 32), "st2 {v26.2d, v27.2d}, [x30], #32"); TEST_SINGLE(st2(DReg::d26, DReg::d27, Reg::r30, 16), "unallocated (NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(ld3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "ld3 {v31.16b, v0.16b, v1.16b}, [x30], x29"); - TEST_SINGLE(ld3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "ld3 {v31.8b, v0.8b, v1.8b}, [x30], x29"); + TEST_SINGLE(ld3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "ld3 {v31.16b, v0.16b, v1.16b}, [x30], x29"); + TEST_SINGLE(ld3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "ld3 {v31.8b, v0.8b, v1.8b}, [x30], x29"); TEST_SINGLE(ld3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld3 {v26.16b, v27.16b, v28.16b}, [x30], x29"); TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld3 {v26.8b, v27.8b, v28.8b}, [x30], x29"); @@ -497,10 +541,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld3 {v26.2s, v27.2s, v28.2s}, [x30], x29"); TEST_SINGLE(ld3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld3 {v26.2d, v27.2d, v28.2d}, [x30], x29"); - TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "unallocated (NEONLoadStoreMultiStructPostIndex)"); + TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "unallocated " + "(NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(ld3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "ld3 {v31.16b, v0.16b, v1.16b}, [x30], #48"); - TEST_SINGLE(ld3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "ld3 {v31.8b, v0.8b, v1.8b}, [x30], #24"); + TEST_SINGLE(ld3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "ld3 {v31.16b, v0.16b, v1.16b}, [x30], #48"); + TEST_SINGLE(ld3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "ld3 {v31.8b, v0.8b, v1.8b}, [x30], #24"); TEST_SINGLE(ld3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "ld3 {v26.16b, v27.16b, v28.16b}, [x30], #48"); TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "ld3 {v26.8b, v27.8b, v28.8b}, [x30], #24"); @@ -513,8 +558,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "ld3 {v26.2d, v27.2d, v28.2d}, [x30], #48"); TEST_SINGLE(ld3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "unallocated (NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(st3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "st3 {v31.16b, v0.16b, v1.16b}, [x30], x29"); - TEST_SINGLE(st3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "st3 {v31.8b, v0.8b, v1.8b}, [x30], x29"); + TEST_SINGLE(st3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "st3 {v31.16b, v0.16b, v1.16b}, [x30], x29"); + TEST_SINGLE(st3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "st3 {v31.8b, v0.8b, v1.8b}, [x30], x29"); TEST_SINGLE(st3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "st3 {v26.16b, v27.16b, v28.16b}, [x30], x29"); TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "st3 {v26.8b, v27.8b, v28.8b}, [x30], x29"); @@ -525,10 +570,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "st3 {v26.2s, v27.2s, v28.2s}, [x30], x29"); TEST_SINGLE(st3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "st3 {v26.2d, v27.2d, v28.2d}, [x30], x29"); - TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "unallocated (NEONLoadStoreMultiStructPostIndex)"); + TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "unallocated " + "(NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(st3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "st3 {v31.16b, v0.16b, v1.16b}, [x30], #48"); - TEST_SINGLE(st3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "st3 {v31.8b, v0.8b, v1.8b}, [x30], #24"); + TEST_SINGLE(st3(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 48), "st3 {v31.16b, v0.16b, v1.16b}, [x30], #48"); + TEST_SINGLE(st3(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 24), "st3 {v31.8b, v0.8b, v1.8b}, [x30], #24"); TEST_SINGLE(st3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "st3 {v26.16b, v27.16b, v28.16b}, [x30], #48"); TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "st3 {v26.8b, v27.8b, v28.8b}, [x30], #24"); @@ -541,64 +587,106 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st3(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 48), "st3 {v26.2d, v27.2d, v28.2d}, [x30], #48"); TEST_SINGLE(st3(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "unallocated (NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(ld4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "ld4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], x29"); - TEST_SINGLE(ld4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "ld4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], x29"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], x29"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], x29"); + TEST_SINGLE(ld4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "ld4 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], x29"); + TEST_SINGLE(ld4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "ld4 {v31.8b, v0.8b, v1.8b, v2.8b}, " + "[x30], x29"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.16b, v27.16b, v28.16b, " + "v29.16b}, [x30], x29"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4 {v26.8b, v27.8b, v28.8b, " + "v29.8b}, [x30], x29"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], x29"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], x29"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.8h, v27.8h, v28.8h, " + "v29.8h}, [x30], x29"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4 {v26.4h, v27.4h, v28.4h, " + "v29.4h}, [x30], x29"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], x29"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], x29"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.4s, v27.4s, v28.4s, " + "v29.4s}, [x30], x29"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4 {v26.2s, v27.2s, v28.2s, " + "v29.2s}, [x30], x29"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], x29"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "unallocated (NEONLoadStoreMultiStructPostIndex)"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4 {v26.2d, v27.2d, v28.2d, " + "v29.2d}, [x30], x29"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "unallocated " + "(NEONLoadStoreMultiStructPostIndex" + ")"); - TEST_SINGLE(ld4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "ld4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], #64"); - TEST_SINGLE(ld4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "ld4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], #32"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], #64"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], #32"); + TEST_SINGLE(ld4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "ld4 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], #64"); + TEST_SINGLE(ld4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "ld4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], " + "#32"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30], #64"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4 {v26.8b, v27.8b, v28.8b, v29.8b}, " + "[x30], #32"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], #64"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], #32"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.8h, v27.8h, v28.8h, v29.8h}, " + "[x30], #64"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4 {v26.4h, v27.4h, v28.4h, v29.4h}, " + "[x30], #32"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], #64"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], #32"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.4s, v27.4s, v28.4s, v29.4s}, " + "[x30], #64"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4 {v26.2s, v27.2s, v28.2s, v29.2s}, " + "[x30], #32"); - TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], #64"); - TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "unallocated (NEONLoadStoreMultiStructPostIndex)"); + TEST_SINGLE(ld4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "ld4 {v26.2d, v27.2d, v28.2d, v29.2d}, " + "[x30], #64"); + TEST_SINGLE(ld4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "unallocated " + "(NEONLoadStoreMultiStructPostIndex)"); - TEST_SINGLE(st4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "st4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], x29"); - TEST_SINGLE(st4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "st4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], x29"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], x29"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st4 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], x29"); + TEST_SINGLE(st4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "st4 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], x29"); + TEST_SINGLE(st4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "st4 {v31.8b, v0.8b, v1.8b, v2.8b}, " + "[x30], x29"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.16b, v27.16b, v28.16b, " + "v29.16b}, [x30], x29"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st4 {v26.8b, v27.8b, v28.8b, " + "v29.8b}, [x30], x29"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], x29"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st4 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], x29"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.8h, v27.8h, v28.8h, " + "v29.8h}, [x30], x29"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st4 {v26.4h, v27.4h, v28.4h, " + "v29.4h}, [x30], x29"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], x29"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st4 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], x29"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.4s, v27.4s, v28.4s, " + "v29.4s}, [x30], x29"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "st4 {v26.2s, v27.2s, v28.2s, " + "v29.2s}, [x30], x29"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], x29"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "unallocated (NEONLoadStoreMultiStructPostIndex)"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "st4 {v26.2d, v27.2d, v28.2d, " + "v29.2d}, [x30], x29"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "unallocated " + "(NEONLoadStoreMultiStructPostIndex" + ")"); - TEST_SINGLE(st4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "st4 {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], #64"); - TEST_SINGLE(st4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "st4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], #32"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], #64"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st4 {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], #32"); + TEST_SINGLE(st4(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 64), "st4 {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], #64"); + TEST_SINGLE(st4(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 32), "st4 {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], " + "#32"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30], #64"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st4 {v26.8b, v27.8b, v28.8b, v29.8b}, " + "[x30], #32"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], #64"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st4 {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], #32"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.8h, v27.8h, v28.8h, v29.8h}, " + "[x30], #64"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st4 {v26.4h, v27.4h, v28.4h, v29.4h}, " + "[x30], #32"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], #64"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st4 {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], #32"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.4s, v27.4s, v28.4s, v29.4s}, " + "[x30], #64"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "st4 {v26.2s, v27.2s, v28.2s, v29.2s}, " + "[x30], #32"); - TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], #64"); - TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "unallocated (NEONLoadStoreMultiStructPostIndex)"); + TEST_SINGLE(st4(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 64), "st4 {v26.2d, v27.2d, v28.2d, v29.2d}, " + "[x30], #64"); + TEST_SINGLE(st4(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "unallocated " + "(NEONLoadStoreMultiStructPostIndex)"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: ASIMD loadstore single") { - TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30), "ld1 {v26.b}[0], [x30]"); + TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30), "ld1 {v26.b}[0], [x30]"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30), "ld1 {v26.h}[0], [x30]"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30), "ld1 {v26.s}[0], [x30]"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30), "ld1 {v26.d}[0], [x30]"); @@ -608,17 +696,17 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: ASIMD loadstore single") TEST_SINGLE(ld1(VReg::v26, 3, Reg::r30), "ld1 {v26.s}[3], [x30]"); TEST_SINGLE(ld1(VReg::v26, 1, Reg::r30), "ld1 {v26.d}[1], [x30]"); - TEST_SINGLE(ld1r(DReg::d26, Reg::r30), "ld1r {v26.8b}, [x30]"); + TEST_SINGLE(ld1r(DReg::d26, Reg::r30), "ld1r {v26.8b}, [x30]"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30), "ld1r {v26.4h}, [x30]"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30), "ld1r {v26.2s}, [x30]"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30), "ld1r {v26.1d}, [x30]"); - TEST_SINGLE(ld1r(QReg::q26, Reg::r30), "ld1r {v26.16b}, [x30]"); + TEST_SINGLE(ld1r(QReg::q26, Reg::r30), "ld1r {v26.16b}, [x30]"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30), "ld1r {v26.8h}, [x30]"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30), "ld1r {v26.4s}, [x30]"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30), "ld1r {v26.2d}, [x30]"); - TEST_SINGLE(st1(VReg::v26, 0, Reg::r30), "st1 {v26.b}[0], [x30]"); + TEST_SINGLE(st1(VReg::v26, 0, Reg::r30), "st1 {v26.b}[0], [x30]"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30), "st1 {v26.h}[0], [x30]"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30), "st1 {v26.s}[0], [x30]"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30), "st1 {v26.d}[0], [x30]"); @@ -628,8 +716,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: ASIMD loadstore single") TEST_SINGLE(st1(VReg::v26, 3, Reg::r30), "st1 {v26.s}[3], [x30]"); TEST_SINGLE(st1(VReg::v26, 1, Reg::r30), "st1 {v26.d}[1], [x30]"); - TEST_SINGLE(ld2(VReg::v31, VReg::v0, 0, Reg::r30), "ld2 {v31.b, v0.b}[0], [x30]"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30), "ld2 {v26.b, v27.b}[0], [x30]"); + TEST_SINGLE(ld2(VReg::v31, VReg::v0, 0, Reg::r30), "ld2 {v31.b, v0.b}[0], [x30]"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30), "ld2 {v26.b, v27.b}[0], [x30]"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30), "ld2 {v26.h, v27.h}[0], [x30]"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30), "ld2 {v26.s, v27.s}[0], [x30]"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30), "ld2 {v26.d, v27.d}[0], [x30]"); @@ -639,20 +727,20 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: ASIMD loadstore single") TEST_SINGLE(ld2(VReg::v26, VReg::v27, 3, Reg::r30), "ld2 {v26.s, v27.s}[3], [x30]"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 1, Reg::r30), "ld2 {v26.d, v27.d}[1], [x30]"); - TEST_SINGLE(ld2r(DReg::d31, DReg::d0, Reg::r30), "ld2r {v31.8b, v0.8b}, [x30]"); - TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30), "ld2r {v26.8b, v27.8b}, [x30]"); + TEST_SINGLE(ld2r(DReg::d31, DReg::d0, Reg::r30), "ld2r {v31.8b, v0.8b}, [x30]"); + TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30), "ld2r {v26.8b, v27.8b}, [x30]"); TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30), "ld2r {v26.4h, v27.4h}, [x30]"); TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30), "ld2r {v26.2s, v27.2s}, [x30]"); TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30), "ld2r {v26.1d, v27.1d}, [x30]"); - TEST_SINGLE(ld2r(QReg::q31, QReg::q0, Reg::r30), "ld2r {v31.16b, v0.16b}, [x30]"); - TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30), "ld2r {v26.16b, v27.16b}, [x30]"); + TEST_SINGLE(ld2r(QReg::q31, QReg::q0, Reg::r30), "ld2r {v31.16b, v0.16b}, [x30]"); + TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30), "ld2r {v26.16b, v27.16b}, [x30]"); TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30), "ld2r {v26.8h, v27.8h}, [x30]"); TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30), "ld2r {v26.4s, v27.4s}, [x30]"); TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30), "ld2r {v26.2d, v27.2d}, [x30]"); - TEST_SINGLE(st2(VReg::v31, VReg::v0, 0, Reg::r30), "st2 {v31.b, v0.b}[0], [x30]"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30), "st2 {v26.b, v27.b}[0], [x30]"); + TEST_SINGLE(st2(VReg::v31, VReg::v0, 0, Reg::r30), "st2 {v31.b, v0.b}[0], [x30]"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30), "st2 {v26.b, v27.b}[0], [x30]"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30), "st2 {v26.h, v27.h}[0], [x30]"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30), "st2 {v26.s, v27.s}[0], [x30]"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30), "st2 {v26.d, v27.d}[0], [x30]"); @@ -662,8 +750,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: ASIMD loadstore single") TEST_SINGLE(st2(VReg::v26, VReg::v27, 3, Reg::r30), "st2 {v26.s, v27.s}[3], [x30]"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 1, Reg::r30), "st2 {v26.d, v27.d}[1], [x30]"); - TEST_SINGLE(ld3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30), "ld3 {v31.b, v0.b, v1.b}[0], [x30]"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "ld3 {v26.b, v27.b, v28.b}[0], [x30]"); + TEST_SINGLE(ld3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30), "ld3 {v31.b, v0.b, v1.b}[0], [x30]"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "ld3 {v26.b, v27.b, v28.b}[0], [x30]"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "ld3 {v26.h, v27.h, v28.h}[0], [x30]"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "ld3 {v26.s, v27.s, v28.s}[0], [x30]"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "ld3 {v26.d, v27.d, v28.d}[0], [x30]"); @@ -673,20 +761,20 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: ASIMD loadstore single") TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30), "ld3 {v26.s, v27.s, v28.s}[3], [x30]"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30), "ld3 {v26.d, v27.d, v28.d}[1], [x30]"); - TEST_SINGLE(ld3r(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "ld3r {v31.8b, v0.8b, v1.8b}, [x30]"); - TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld3r {v26.8b, v27.8b, v28.8b}, [x30]"); + TEST_SINGLE(ld3r(DReg::d31, DReg::d0, DReg::d1, Reg::r30), "ld3r {v31.8b, v0.8b, v1.8b}, [x30]"); + TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld3r {v26.8b, v27.8b, v28.8b}, [x30]"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld3r {v26.4h, v27.4h, v28.4h}, [x30]"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld3r {v26.2s, v27.2s, v28.2s}, [x30]"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30), "ld3r {v26.1d, v27.1d, v28.1d}, [x30]"); - TEST_SINGLE(ld3r(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "ld3r {v31.16b, v0.16b, v1.16b}, [x30]"); - TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld3r {v26.16b, v27.16b, v28.16b}, [x30]"); + TEST_SINGLE(ld3r(QReg::q31, QReg::q0, QReg::q1, Reg::r30), "ld3r {v31.16b, v0.16b, v1.16b}, [x30]"); + TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld3r {v26.16b, v27.16b, v28.16b}, [x30]"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld3r {v26.8h, v27.8h, v28.8h}, [x30]"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld3r {v26.4s, v27.4s, v28.4s}, [x30]"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30), "ld3r {v26.2d, v27.2d, v28.2d}, [x30]"); - TEST_SINGLE(st3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30), "st3 {v31.b, v0.b, v1.b}[0], [x30]"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "st3 {v26.b, v27.b, v28.b}[0], [x30]"); + TEST_SINGLE(st3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30), "st3 {v31.b, v0.b, v1.b}[0], [x30]"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "st3 {v26.b, v27.b, v28.b}[0], [x30]"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "st3 {v26.h, v27.h, v28.h}[0], [x30]"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "st3 {v26.s, v27.s, v28.s}[0], [x30]"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30), "st3 {v26.d, v27.d, v28.d}[0], [x30]"); @@ -696,42 +784,66 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: ASIMD loadstore single") TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30), "st3 {v26.s, v27.s, v28.s}[3], [x30]"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30), "st3 {v26.d, v27.d, v28.d}[1], [x30]"); - TEST_SINGLE(ld4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30), "ld4 {v31.b, v0.b, v1.b, v2.b}[0], [x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.b, v27.b, v28.b, v29.b}[0], [x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.h, v27.h, v28.h, v29.h}[0], [x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.s, v27.s, v28.s, v29.s}[0], [x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.d, v27.d, v28.d, v29.d}[0], [x30]"); + TEST_SINGLE(ld4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30), "ld4 {v31.b, v0.b, v1.b, v2.b}[0], [x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.b, v27.b, v28.b, v29.b}[0], " + "[x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.h, v27.h, v28.h, v29.h}[0], " + "[x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.s, v27.s, v28.s, v29.s}[0], " + "[x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "ld4 {v26.d, v27.d, v28.d, v29.d}[0], " + "[x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30), "ld4 {v26.b, v27.b, v28.b, v29.b}[15], [x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30), "ld4 {v26.h, v27.h, v28.h, v29.h}[7], [x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30), "ld4 {v26.s, v27.s, v28.s, v29.s}[3], [x30]"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30), "ld4 {v26.d, v27.d, v28.d, v29.d}[1], [x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30), "ld4 {v26.b, v27.b, v28.b, v29.b}[15], " + "[x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30), "ld4 {v26.h, v27.h, v28.h, v29.h}[7], " + "[x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30), "ld4 {v26.s, v27.s, v28.s, v29.s}[3], " + "[x30]"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30), "ld4 {v26.d, v27.d, v28.d, v29.d}[1], " + "[x30]"); - TEST_SINGLE(ld4r(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "ld4r {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.8b, v27.8b, v28.8b, v29.8b}, [x30]"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.4h, v27.4h, v28.4h, v29.4h}, [x30]"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.2s, v27.2s, v28.2s, v29.2s}, [x30]"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.1d, v27.1d, v28.1d, v29.1d}, [x30]"); + TEST_SINGLE(ld4r(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30), "ld4r {v31.8b, v0.8b, v1.8b, v2.8b}, [x30]"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.8b, v27.8b, v28.8b, v29.8b}, " + "[x30]"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.4h, v27.4h, v28.4h, v29.4h}, " + "[x30]"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.2s, v27.2s, v28.2s, v29.2s}, " + "[x30]"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30), "ld4r {v26.1d, v27.1d, v28.1d, v29.1d}, " + "[x30]"); - TEST_SINGLE(ld4r(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "ld4r {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.16b, v27.16b, v28.16b, v29.16b}, [x30]"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.8h, v27.8h, v28.8h, v29.8h}, [x30]"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.4s, v27.4s, v28.4s, v29.4s}, [x30]"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.2d, v27.2d, v28.2d, v29.2d}, [x30]"); + TEST_SINGLE(ld4r(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30), "ld4r {v31.16b, v0.16b, v1.16b, v2.16b}, [x30]"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.16b, v27.16b, v28.16b, v29.16b}, " + "[x30]"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.8h, v27.8h, v28.8h, v29.8h}, " + "[x30]"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.4s, v27.4s, v28.4s, v29.4s}, " + "[x30]"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30), "ld4r {v26.2d, v27.2d, v28.2d, v29.2d}, " + "[x30]"); - TEST_SINGLE(st4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30), "st4 {v31.b, v0.b, v1.b, v2.b}[0], [x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.b, v27.b, v28.b, v29.b}[0], [x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.h, v27.h, v28.h, v29.h}[0], [x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.s, v27.s, v28.s, v29.s}[0], [x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.d, v27.d, v28.d, v29.d}[0], [x30]"); + TEST_SINGLE(st4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30), "st4 {v31.b, v0.b, v1.b, v2.b}[0], [x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.b, v27.b, v28.b, v29.b}[0], " + "[x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.h, v27.h, v28.h, v29.h}[0], " + "[x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.s, v27.s, v28.s, v29.s}[0], " + "[x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30), "st4 {v26.d, v27.d, v28.d, v29.d}[0], " + "[x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30), "st4 {v26.b, v27.b, v28.b, v29.b}[15], [x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30), "st4 {v26.h, v27.h, v28.h, v29.h}[7], [x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30), "st4 {v26.s, v27.s, v28.s, v29.s}[3], [x30]"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30), "st4 {v26.d, v27.d, v28.d, v29.d}[1], [x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30), "st4 {v26.b, v27.b, v28.b, v29.b}[15], " + "[x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30), "st4 {v26.h, v27.h, v28.h, v29.h}[7], " + "[x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30), "st4 {v26.s, v27.s, v28.s, v29.s}[3], " + "[x30]"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30), "st4 {v26.d, v27.d, v28.d, v29.d}[1], " + "[x30]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store single structure (post-indexed)") { - TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, 1), "ld1 {v26.b}[0], [x30], #1"); + TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, 1), "ld1 {v26.b}[0], [x30], #1"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, 2), "ld1 {v26.h}[0], [x30], #2"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, 4), "ld1 {v26.s}[0], [x30], #4"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, 8), "ld1 {v26.d}[0], [x30], #8"); @@ -741,17 +853,17 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(ld1(VReg::v26, 3, Reg::r30, 4), "ld1 {v26.s}[3], [x30], #4"); TEST_SINGLE(ld1(VReg::v26, 1, Reg::r30, 8), "ld1 {v26.d}[1], [x30], #8"); - TEST_SINGLE(ld1r(DReg::d26, Reg::r30, 1), "ld1r {v26.8b}, [x30], #1"); + TEST_SINGLE(ld1r(DReg::d26, Reg::r30, 1), "ld1r {v26.8b}, [x30], #1"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30, 2), "ld1r {v26.4h}, [x30], #2"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30, 4), "ld1r {v26.2s}, [x30], #4"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30, 8), "ld1r {v26.1d}, [x30], #8"); - TEST_SINGLE(ld1r(QReg::q26, Reg::r30, 1), "ld1r {v26.16b}, [x30], #1"); + TEST_SINGLE(ld1r(QReg::q26, Reg::r30, 1), "ld1r {v26.16b}, [x30], #1"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30, 2), "ld1r {v26.8h}, [x30], #2"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30, 4), "ld1r {v26.4s}, [x30], #4"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30, 8), "ld1r {v26.2d}, [x30], #8"); - TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, 1), "st1 {v26.b}[0], [x30], #1"); + TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, 1), "st1 {v26.b}[0], [x30], #1"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, 2), "st1 {v26.h}[0], [x30], #2"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, 4), "st1 {v26.s}[0], [x30], #4"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, 8), "st1 {v26.d}[0], [x30], #8"); @@ -761,239 +873,295 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Advanced SIMD load/store TEST_SINGLE(st1(VReg::v26, 3, Reg::r30, 4), "st1 {v26.s}[3], [x30], #4"); TEST_SINGLE(st1(VReg::v26, 1, Reg::r30, 8), "st1 {v26.d}[1], [x30], #8"); - TEST_SINGLE(ld2(VReg::v31, VReg::v0, 0, Reg::r30, 2), "ld2 {v31.b, v0.b}[0], [x30], #2"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, 2), "ld2 {v26.b, v27.b}[0], [x30], #2"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, 4), "ld2 {v26.h, v27.h}[0], [x30], #4"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, 8), "ld2 {v26.s, v27.s}[0], [x30], #8"); + TEST_SINGLE(ld2(VReg::v31, VReg::v0, 0, Reg::r30, 2), "ld2 {v31.b, v0.b}[0], [x30], #2"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, 2), "ld2 {v26.b, v27.b}[0], [x30], #2"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, 4), "ld2 {v26.h, v27.h}[0], [x30], #4"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, 8), "ld2 {v26.s, v27.s}[0], [x30], #8"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, 16), "ld2 {v26.d, v27.d}[0], [x30], #16"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 15, Reg::r30, 2), "ld2 {v26.b, v27.b}[15], [x30], #2"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 7, Reg::r30, 4), "ld2 {v26.h, v27.h}[7], [x30], #4"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 3, Reg::r30, 8), "ld2 {v26.s, v27.s}[3], [x30], #8"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 15, Reg::r30, 2), "ld2 {v26.b, v27.b}[15], [x30], #2"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 7, Reg::r30, 4), "ld2 {v26.h, v27.h}[7], [x30], #4"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 3, Reg::r30, 8), "ld2 {v26.s, v27.s}[3], [x30], #8"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 1, Reg::r30, 16), "ld2 {v26.d, v27.d}[1], [x30], #16"); - TEST_SINGLE(ld2r(DReg::d31, DReg::d0, Reg::r30, 2), "ld2r {v31.8b, v0.8b}, [x30], #2"); - TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, 2), "ld2r {v26.8b, v27.8b}, [x30], #2"); - TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, 4), "ld2r {v26.4h, v27.4h}, [x30], #4"); - TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, 8), "ld2r {v26.2s, v27.2s}, [x30], #8"); + TEST_SINGLE(ld2r(DReg::d31, DReg::d0, Reg::r30, 2), "ld2r {v31.8b, v0.8b}, [x30], #2"); + TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, 2), "ld2r {v26.8b, v27.8b}, [x30], #2"); + TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, 4), "ld2r {v26.4h, v27.4h}, [x30], #4"); + TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, 8), "ld2r {v26.2s, v27.2s}, [x30], #8"); TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, 16), "ld2r {v26.1d, v27.1d}, [x30], #16"); - TEST_SINGLE(ld2r(QReg::q31, QReg::q0, Reg::r30, 2), "ld2r {v31.16b, v0.16b}, [x30], #2"); - TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, 2), "ld2r {v26.16b, v27.16b}, [x30], #2"); - TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, 4), "ld2r {v26.8h, v27.8h}, [x30], #4"); - TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, 8), "ld2r {v26.4s, v27.4s}, [x30], #8"); + TEST_SINGLE(ld2r(QReg::q31, QReg::q0, Reg::r30, 2), "ld2r {v31.16b, v0.16b}, [x30], #2"); + TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, 2), "ld2r {v26.16b, v27.16b}, [x30], #2"); + TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, 4), "ld2r {v26.8h, v27.8h}, [x30], #4"); + TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, 8), "ld2r {v26.4s, v27.4s}, [x30], #8"); TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, 16), "ld2r {v26.2d, v27.2d}, [x30], #16"); - TEST_SINGLE(st2(VReg::v31, VReg::v0, 0, Reg::r30, 2), "st2 {v31.b, v0.b}[0], [x30], #2"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, 2), "st2 {v26.b, v27.b}[0], [x30], #2"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, 4), "st2 {v26.h, v27.h}[0], [x30], #4"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, 8), "st2 {v26.s, v27.s}[0], [x30], #8"); + TEST_SINGLE(st2(VReg::v31, VReg::v0, 0, Reg::r30, 2), "st2 {v31.b, v0.b}[0], [x30], #2"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, 2), "st2 {v26.b, v27.b}[0], [x30], #2"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, 4), "st2 {v26.h, v27.h}[0], [x30], #4"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, 8), "st2 {v26.s, v27.s}[0], [x30], #8"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, 16), "st2 {v26.d, v27.d}[0], [x30], #16"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 15, Reg::r30, 2), "st2 {v26.b, v27.b}[15], [x30], #2"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 7, Reg::r30, 4), "st2 {v26.h, v27.h}[7], [x30], #4"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 3, Reg::r30, 8), "st2 {v26.s, v27.s}[3], [x30], #8"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 1, Reg::r30, 16), "st2 {v26.d, v27.d}[1], [x30], #16"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 15, Reg::r30, 2), "st2 {v26.b, v27.b}[15], [x30], #2"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 7, Reg::r30, 4), "st2 {v26.h, v27.h}[7], [x30], #4"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 3, Reg::r30, 8), "st2 {v26.s, v27.s}[3], [x30], #8"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 1, Reg::r30, 16), "st2 {v26.d, v27.d}[1], [x30], #16"); - TEST_SINGLE(ld3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, 3), "ld3 {v31.b, v0.b, v1.b}[0], [x30], #3"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 3), "ld3 {v26.b, v27.b, v28.b}[0], [x30], #3"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 6), "ld3 {v26.h, v27.h, v28.h}[0], [x30], #6"); + TEST_SINGLE(ld3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, 3), "ld3 {v31.b, v0.b, v1.b}[0], [x30], #3"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 3), "ld3 {v26.b, v27.b, v28.b}[0], [x30], #3"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 6), "ld3 {v26.h, v27.h, v28.h}[0], [x30], #6"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 12), "ld3 {v26.s, v27.s, v28.s}[0], [x30], #12"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 24), "ld3 {v26.d, v27.d, v28.d}[0], [x30], #24"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, 1), "ld3 {v26.b, v27.b, v28.b}[15], [x30], #3"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, 2), "ld3 {v26.h, v27.h, v28.h}[7], [x30], #6"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, 4), "ld3 {v26.s, v27.s, v28.s}[3], [x30], #12"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, 8), "ld3 {v26.d, v27.d, v28.d}[1], [x30], #24"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, 1), "ld3 {v26.b, v27.b, v28.b}[15], [x30], #3"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, 2), "ld3 {v26.h, v27.h, v28.h}[7], [x30], #6"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, 4), "ld3 {v26.s, v27.s, v28.s}[3], [x30], #12"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, 8), "ld3 {v26.d, v27.d, v28.d}[1], [x30], #24"); - TEST_SINGLE(ld3r(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 3), "ld3r {v31.8b, v0.8b, v1.8b}, [x30], #3"); - TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 3), "ld3r {v26.8b, v27.8b, v28.8b}, [x30], #3"); - TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 6), "ld3r {v26.4h, v27.4h, v28.4h}, [x30], #6"); + TEST_SINGLE(ld3r(DReg::d31, DReg::d0, DReg::d1, Reg::r30, 3), "ld3r {v31.8b, v0.8b, v1.8b}, [x30], #3"); + TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 3), "ld3r {v26.8b, v27.8b, v28.8b}, [x30], #3"); + TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 6), "ld3r {v26.4h, v27.4h, v28.4h}, [x30], #6"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 12), "ld3r {v26.2s, v27.2s, v28.2s}, [x30], #12"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, 24), "ld3r {v26.1d, v27.1d, v28.1d}, [x30], #24"); - TEST_SINGLE(ld3r(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 3), "ld3r {v31.16b, v0.16b, v1.16b}, [x30], #3"); - TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 3), "ld3r {v26.16b, v27.16b, v28.16b}, [x30], #3"); - TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 6), "ld3r {v26.8h, v27.8h, v28.8h}, [x30], #6"); + TEST_SINGLE(ld3r(QReg::q31, QReg::q0, QReg::q1, Reg::r30, 3), "ld3r {v31.16b, v0.16b, v1.16b}, [x30], #3"); + TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 3), "ld3r {v26.16b, v27.16b, v28.16b}, [x30], #3"); + TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 6), "ld3r {v26.8h, v27.8h, v28.8h}, [x30], #6"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 12), "ld3r {v26.4s, v27.4s, v28.4s}, [x30], #12"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, 24), "ld3r {v26.2d, v27.2d, v28.2d}, [x30], #24"); - TEST_SINGLE(st3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, 3), "st3 {v31.b, v0.b, v1.b}[0], [x30], #3"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 3), "st3 {v26.b, v27.b, v28.b}[0], [x30], #3"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 6), "st3 {v26.h, v27.h, v28.h}[0], [x30], #6"); + TEST_SINGLE(st3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, 3), "st3 {v31.b, v0.b, v1.b}[0], [x30], #3"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 3), "st3 {v26.b, v27.b, v28.b}[0], [x30], #3"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 6), "st3 {v26.h, v27.h, v28.h}[0], [x30], #6"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 12), "st3 {v26.s, v27.s, v28.s}[0], [x30], #12"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, 24), "st3 {v26.d, v27.d, v28.d}[0], [x30], #24"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, 3), "st3 {v26.b, v27.b, v28.b}[15], [x30], #3"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, 6), "st3 {v26.h, v27.h, v28.h}[7], [x30], #6"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, 12), "st3 {v26.s, v27.s, v28.s}[3], [x30], #12"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, 24), "st3 {v26.d, v27.d, v28.d}[1], [x30], #24"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, 3), "st3 {v26.b, v27.b, v28.b}[15], [x30], #3"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, 6), "st3 {v26.h, v27.h, v28.h}[7], [x30], #6"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, 12), "st3 {v26.s, v27.s, v28.s}[3], [x30], #12"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, 24), "st3 {v26.d, v27.d, v28.d}[1], [x30], #24"); - TEST_SINGLE(ld4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, 4), "ld4 {v31.b, v0.b, v1.b, v2.b}[0], [x30], #4"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 4), "ld4 {v26.b, v27.b, v28.b, v29.b}[0], [x30], #4"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 8), "ld4 {v26.h, v27.h, v28.h, v29.h}[0], [x30], #8"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 16), "ld4 {v26.s, v27.s, v28.s, v29.s}[0], [x30], #16"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 32), "ld4 {v26.d, v27.d, v28.d, v29.d}[0], [x30], #32"); + TEST_SINGLE(ld4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, 4), "ld4 {v31.b, v0.b, v1.b, v2.b}[0], [x30], " + "#4"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 4), "ld4 {v26.b, v27.b, v28.b, v29.b}[0], " + "[x30], #4"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 8), "ld4 {v26.h, v27.h, v28.h, v29.h}[0], " + "[x30], #8"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 16), "ld4 {v26.s, v27.s, v28.s, v29.s}[0], " + "[x30], #16"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 32), "ld4 {v26.d, v27.d, v28.d, v29.d}[0], " + "[x30], #32"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, 4), "ld4 {v26.b, v27.b, v28.b, v29.b}[15], [x30], #4"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, 8), "ld4 {v26.h, v27.h, v28.h, v29.h}[7], [x30], #8"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, 16), "ld4 {v26.s, v27.s, v28.s, v29.s}[3], [x30], #16"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, 32), "ld4 {v26.d, v27.d, v28.d, v29.d}[1], [x30], #32"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, 4), "ld4 {v26.b, v27.b, v28.b, v29.b}[15], " + "[x30], #4"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, 8), "ld4 {v26.h, v27.h, v28.h, v29.h}[7], " + "[x30], #8"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, 16), "ld4 {v26.s, v27.s, v28.s, v29.s}[3], " + "[x30], #16"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, 32), "ld4 {v26.d, v27.d, v28.d, v29.d}[1], " + "[x30], #32"); - TEST_SINGLE(ld4r(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 4), "ld4r {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], #4"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 4), "ld4r {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], #4"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 8), "ld4r {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], #8"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 16), "ld4r {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], #16"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4r {v26.1d, v27.1d, v28.1d, v29.1d}, [x30], #32"); + TEST_SINGLE(ld4r(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, 4), "ld4r {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], " + "#4"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 4), "ld4r {v26.8b, v27.8b, v28.8b, v29.8b}, " + "[x30], #4"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 8), "ld4r {v26.4h, v27.4h, v28.4h, v29.4h}, " + "[x30], #8"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 16), "ld4r {v26.2s, v27.2s, v28.2s, v29.2s}, " + "[x30], #16"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, 32), "ld4r {v26.1d, v27.1d, v28.1d, v29.1d}, " + "[x30], #32"); - TEST_SINGLE(ld4r(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 4), "ld4r {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], #4"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 4), "ld4r {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], #4"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 8), "ld4r {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], #8"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 16), "ld4r {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], #16"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 32), "ld4r {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], #32"); + TEST_SINGLE(ld4r(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, 4), "ld4r {v31.16b, v0.16b, v1.16b, v2.16b}, " + "[x30], #4"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 4), "ld4r {v26.16b, v27.16b, v28.16b, " + "v29.16b}, [x30], #4"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 8), "ld4r {v26.8h, v27.8h, v28.8h, v29.8h}, " + "[x30], #8"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 16), "ld4r {v26.4s, v27.4s, v28.4s, v29.4s}, " + "[x30], #16"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, 32), "ld4r {v26.2d, v27.2d, v28.2d, v29.2d}, " + "[x30], #32"); - TEST_SINGLE(st4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, 4), "st4 {v31.b, v0.b, v1.b, v2.b}[0], [x30], #4"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 4), "st4 {v26.b, v27.b, v28.b, v29.b}[0], [x30], #4"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 8), "st4 {v26.h, v27.h, v28.h, v29.h}[0], [x30], #8"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 16), "st4 {v26.s, v27.s, v28.s, v29.s}[0], [x30], #16"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 32), "st4 {v26.d, v27.d, v28.d, v29.d}[0], [x30], #32"); + TEST_SINGLE(st4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, 4), "st4 {v31.b, v0.b, v1.b, v2.b}[0], [x30], " + "#4"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 4), "st4 {v26.b, v27.b, v28.b, v29.b}[0], " + "[x30], #4"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 8), "st4 {v26.h, v27.h, v28.h, v29.h}[0], " + "[x30], #8"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 16), "st4 {v26.s, v27.s, v28.s, v29.s}[0], " + "[x30], #16"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, 32), "st4 {v26.d, v27.d, v28.d, v29.d}[0], " + "[x30], #32"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, 4), "st4 {v26.b, v27.b, v28.b, v29.b}[15], [x30], #4"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, 8), "st4 {v26.h, v27.h, v28.h, v29.h}[7], [x30], #8"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, 16), "st4 {v26.s, v27.s, v28.s, v29.s}[3], [x30], #16"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, 32), "st4 {v26.d, v27.d, v28.d, v29.d}[1], [x30], #32"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, 4), "st4 {v26.b, v27.b, v28.b, v29.b}[15], " + "[x30], #4"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, 8), "st4 {v26.h, v27.h, v28.h, v29.h}[7], " + "[x30], #8"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, 16), "st4 {v26.s, v27.s, v28.s, v29.s}[3], " + "[x30], #16"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, 32), "st4 {v26.d, v27.d, v28.d, v29.d}[1], " + "[x30], #32"); - TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, Reg::r29), "ld1 {v26.b}[0], [x30], x29"); + TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, Reg::r29), "ld1 {v26.b}[0], [x30], x29"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, Reg::r29), "ld1 {v26.h}[0], [x30], x29"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, Reg::r29), "ld1 {v26.s}[0], [x30], x29"); TEST_SINGLE(ld1(VReg::v26, 0, Reg::r30, Reg::r29), "ld1 {v26.d}[0], [x30], x29"); - TEST_SINGLE(ld1(VReg::v26, 15, Reg::r30, Reg::r29), "ld1 {v26.b}[15], [x30], x29"); + TEST_SINGLE(ld1(VReg::v26, 15, Reg::r30, Reg::r29), "ld1 {v26.b}[15], [x30], x29"); TEST_SINGLE(ld1(VReg::v26, 7, Reg::r30, Reg::r29), "ld1 {v26.h}[7], [x30], x29"); TEST_SINGLE(ld1(VReg::v26, 3, Reg::r30, Reg::r29), "ld1 {v26.s}[3], [x30], x29"); TEST_SINGLE(ld1(VReg::v26, 1, Reg::r30, Reg::r29), "ld1 {v26.d}[1], [x30], x29"); - TEST_SINGLE(ld1r(DReg::d26, Reg::r30, Reg::r29), "ld1r {v26.8b}, [x30], x29"); + TEST_SINGLE(ld1r(DReg::d26, Reg::r30, Reg::r29), "ld1r {v26.8b}, [x30], x29"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30, Reg::r29), "ld1r {v26.4h}, [x30], x29"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30, Reg::r29), "ld1r {v26.2s}, [x30], x29"); TEST_SINGLE(ld1r(DReg::d26, Reg::r30, Reg::r29), "ld1r {v26.1d}, [x30], x29"); - TEST_SINGLE(ld1r(QReg::q26, Reg::r30, Reg::r29), "ld1r {v26.16b}, [x30], x29"); + TEST_SINGLE(ld1r(QReg::q26, Reg::r30, Reg::r29), "ld1r {v26.16b}, [x30], x29"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30, Reg::r29), "ld1r {v26.8h}, [x30], x29"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30, Reg::r29), "ld1r {v26.4s}, [x30], x29"); TEST_SINGLE(ld1r(QReg::q26, Reg::r30, Reg::r29), "ld1r {v26.2d}, [x30], x29"); - TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, Reg::r29), "st1 {v26.b}[0], [x30], x29"); + TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, Reg::r29), "st1 {v26.b}[0], [x30], x29"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, Reg::r29), "st1 {v26.h}[0], [x30], x29"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, Reg::r29), "st1 {v26.s}[0], [x30], x29"); TEST_SINGLE(st1(VReg::v26, 0, Reg::r30, Reg::r29), "st1 {v26.d}[0], [x30], x29"); - TEST_SINGLE(st1(VReg::v26, 15, Reg::r30, Reg::r29), "st1 {v26.b}[15], [x30], x29"); + TEST_SINGLE(st1(VReg::v26, 15, Reg::r30, Reg::r29), "st1 {v26.b}[15], [x30], x29"); TEST_SINGLE(st1(VReg::v26, 7, Reg::r30, Reg::r29), "st1 {v26.h}[7], [x30], x29"); TEST_SINGLE(st1(VReg::v26, 3, Reg::r30, Reg::r29), "st1 {v26.s}[3], [x30], x29"); TEST_SINGLE(st1(VReg::v26, 1, Reg::r30, Reg::r29), "st1 {v26.d}[1], [x30], x29"); - TEST_SINGLE(ld2(VReg::v31, VReg::v0, 0, Reg::r30, Reg::r29), "ld2 {v31.b, v0.b}[0], [x30], x29"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "ld2 {v26.b, v27.b}[0], [x30], x29"); + TEST_SINGLE(ld2(VReg::v31, VReg::v0, 0, Reg::r30, Reg::r29), "ld2 {v31.b, v0.b}[0], [x30], x29"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "ld2 {v26.b, v27.b}[0], [x30], x29"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "ld2 {v26.h, v27.h}[0], [x30], x29"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "ld2 {v26.s, v27.s}[0], [x30], x29"); TEST_SINGLE(ld2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "ld2 {v26.d, v27.d}[0], [x30], x29"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 15, Reg::r30, Reg::r29), "ld2 {v26.b, v27.b}[15], [x30], x29"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 7, Reg::r30, Reg::r29), "ld2 {v26.h, v27.h}[7], [x30], x29"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 3, Reg::r30, Reg::r29), "ld2 {v26.s, v27.s}[3], [x30], x29"); - TEST_SINGLE(ld2(VReg::v26, VReg::v27, 1, Reg::r30, Reg::r29), "ld2 {v26.d, v27.d}[1], [x30], x29"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 15, Reg::r30, Reg::r29), "ld2 {v26.b, v27.b}[15], [x30], x29"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 7, Reg::r30, Reg::r29), "ld2 {v26.h, v27.h}[7], [x30], x29"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 3, Reg::r30, Reg::r29), "ld2 {v26.s, v27.s}[3], [x30], x29"); + TEST_SINGLE(ld2(VReg::v26, VReg::v27, 1, Reg::r30, Reg::r29), "ld2 {v26.d, v27.d}[1], [x30], x29"); - TEST_SINGLE(ld2r(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "ld2r {v31.8b, v0.8b}, [x30], x29"); - TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld2r {v26.8b, v27.8b}, [x30], x29"); + TEST_SINGLE(ld2r(DReg::d31, DReg::d0, Reg::r30, Reg::r29), "ld2r {v31.8b, v0.8b}, [x30], x29"); + TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld2r {v26.8b, v27.8b}, [x30], x29"); TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld2r {v26.4h, v27.4h}, [x30], x29"); TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld2r {v26.2s, v27.2s}, [x30], x29"); TEST_SINGLE(ld2r(DReg::d26, DReg::d27, Reg::r30, Reg::r29), "ld2r {v26.1d, v27.1d}, [x30], x29"); - TEST_SINGLE(ld2r(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "ld2r {v31.16b, v0.16b}, [x30], x29"); - TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld2r {v26.16b, v27.16b}, [x30], x29"); + TEST_SINGLE(ld2r(QReg::q31, QReg::q0, Reg::r30, Reg::r29), "ld2r {v31.16b, v0.16b}, [x30], x29"); + TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld2r {v26.16b, v27.16b}, [x30], x29"); TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld2r {v26.8h, v27.8h}, [x30], x29"); TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld2r {v26.4s, v27.4s}, [x30], x29"); TEST_SINGLE(ld2r(QReg::q26, QReg::q27, Reg::r30, Reg::r29), "ld2r {v26.2d, v27.2d}, [x30], x29"); - TEST_SINGLE(st2(VReg::v31, VReg::v0, 0, Reg::r30, Reg::r29), "st2 {v31.b, v0.b}[0], [x30], x29"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "st2 {v26.b, v27.b}[0], [x30], x29"); + TEST_SINGLE(st2(VReg::v31, VReg::v0, 0, Reg::r30, Reg::r29), "st2 {v31.b, v0.b}[0], [x30], x29"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "st2 {v26.b, v27.b}[0], [x30], x29"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "st2 {v26.h, v27.h}[0], [x30], x29"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "st2 {v26.s, v27.s}[0], [x30], x29"); TEST_SINGLE(st2(VReg::v26, VReg::v27, 0, Reg::r30, Reg::r29), "st2 {v26.d, v27.d}[0], [x30], x29"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 15, Reg::r30, Reg::r29), "st2 {v26.b, v27.b}[15], [x30], x29"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 7, Reg::r30, Reg::r29), "st2 {v26.h, v27.h}[7], [x30], x29"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 3, Reg::r30, Reg::r29), "st2 {v26.s, v27.s}[3], [x30], x29"); - TEST_SINGLE(st2(VReg::v26, VReg::v27, 1, Reg::r30, Reg::r29), "st2 {v26.d, v27.d}[1], [x30], x29"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 15, Reg::r30, Reg::r29), "st2 {v26.b, v27.b}[15], [x30], x29"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 7, Reg::r30, Reg::r29), "st2 {v26.h, v27.h}[7], [x30], x29"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 3, Reg::r30, Reg::r29), "st2 {v26.s, v27.s}[3], [x30], x29"); + TEST_SINGLE(st2(VReg::v26, VReg::v27, 1, Reg::r30, Reg::r29), "st2 {v26.d, v27.d}[1], [x30], x29"); - TEST_SINGLE(ld3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, Reg::r29), "ld3 {v31.b, v0.b, v1.b}[0], [x30], x29"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "ld3 {v26.b, v27.b, v28.b}[0], [x30], x29"); + TEST_SINGLE(ld3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, Reg::r29), "ld3 {v31.b, v0.b, v1.b}[0], [x30], x29"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "ld3 {v26.b, v27.b, v28.b}[0], [x30], x29"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "ld3 {v26.h, v27.h, v28.h}[0], [x30], x29"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "ld3 {v26.s, v27.s, v28.s}[0], [x30], x29"); TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "ld3 {v26.d, v27.d, v28.d}[0], [x30], x29"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, Reg::r29), "ld3 {v26.b, v27.b, v28.b}[15], [x30], x29"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, Reg::r29), "ld3 {v26.h, v27.h, v28.h}[7], [x30], x29"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, Reg::r29), "ld3 {v26.s, v27.s, v28.s}[3], [x30], x29"); - TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, Reg::r29), "ld3 {v26.d, v27.d, v28.d}[1], [x30], x29"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, Reg::r29), "ld3 {v26.b, v27.b, v28.b}[15], [x30], x29"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, Reg::r29), "ld3 {v26.h, v27.h, v28.h}[7], [x30], x29"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, Reg::r29), "ld3 {v26.s, v27.s, v28.s}[3], [x30], x29"); + TEST_SINGLE(ld3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, Reg::r29), "ld3 {v26.d, v27.d, v28.d}[1], [x30], x29"); - TEST_SINGLE(ld3r(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "ld3r {v31.8b, v0.8b, v1.8b}, [x30], x29"); - TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld3r {v26.8b, v27.8b, v28.8b}, [x30], x29"); + TEST_SINGLE(ld3r(DReg::d31, DReg::d0, DReg::d1, Reg::r30, Reg::r29), "ld3r {v31.8b, v0.8b, v1.8b}, [x30], x29"); + TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld3r {v26.8b, v27.8b, v28.8b}, [x30], x29"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld3r {v26.4h, v27.4h, v28.4h}, [x30], x29"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld3r {v26.2s, v27.2s, v28.2s}, [x30], x29"); TEST_SINGLE(ld3r(DReg::d26, DReg::d27, DReg::d28, Reg::r30, Reg::r29), "ld3r {v26.1d, v27.1d, v28.1d}, [x30], x29"); - TEST_SINGLE(ld3r(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "ld3r {v31.16b, v0.16b, v1.16b}, [x30], x29"); - TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld3r {v26.16b, v27.16b, v28.16b}, [x30], x29"); + TEST_SINGLE(ld3r(QReg::q31, QReg::q0, QReg::q1, Reg::r30, Reg::r29), "ld3r {v31.16b, v0.16b, v1.16b}, [x30], x29"); + TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld3r {v26.16b, v27.16b, v28.16b}, [x30], x29"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld3r {v26.8h, v27.8h, v28.8h}, [x30], x29"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld3r {v26.4s, v27.4s, v28.4s}, [x30], x29"); TEST_SINGLE(ld3r(QReg::q26, QReg::q27, QReg::q28, Reg::r30, Reg::r29), "ld3r {v26.2d, v27.2d, v28.2d}, [x30], x29"); - TEST_SINGLE(st3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, Reg::r29), "st3 {v31.b, v0.b, v1.b}[0], [x30], x29"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "st3 {v26.b, v27.b, v28.b}[0], [x30], x29"); + TEST_SINGLE(st3(VReg::v31, VReg::v0, VReg::v1, 0, Reg::r30, Reg::r29), "st3 {v31.b, v0.b, v1.b}[0], [x30], x29"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "st3 {v26.b, v27.b, v28.b}[0], [x30], x29"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "st3 {v26.h, v27.h, v28.h}[0], [x30], x29"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "st3 {v26.s, v27.s, v28.s}[0], [x30], x29"); TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 0, Reg::r30, Reg::r29), "st3 {v26.d, v27.d, v28.d}[0], [x30], x29"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, Reg::r29), "st3 {v26.b, v27.b, v28.b}[15], [x30], x29"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, Reg::r29), "st3 {v26.h, v27.h, v28.h}[7], [x30], x29"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, Reg::r29), "st3 {v26.s, v27.s, v28.s}[3], [x30], x29"); - TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, Reg::r29), "st3 {v26.d, v27.d, v28.d}[1], [x30], x29"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 15, Reg::r30, Reg::r29), "st3 {v26.b, v27.b, v28.b}[15], [x30], x29"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 7, Reg::r30, Reg::r29), "st3 {v26.h, v27.h, v28.h}[7], [x30], x29"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 3, Reg::r30, Reg::r29), "st3 {v26.s, v27.s, v28.s}[3], [x30], x29"); + TEST_SINGLE(st3(VReg::v26, VReg::v27, VReg::v28, 1, Reg::r30, Reg::r29), "st3 {v26.d, v27.d, v28.d}[1], [x30], x29"); - TEST_SINGLE(ld4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, Reg::r29), "ld4 {v31.b, v0.b, v1.b, v2.b}[0], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.b, v27.b, v28.b, v29.b}[0], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.h, v27.h, v28.h, v29.h}[0], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.s, v27.s, v28.s, v29.s}[0], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.d, v27.d, v28.d, v29.d}[0], [x30], x29"); + TEST_SINGLE(ld4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, Reg::r29), "ld4 {v31.b, v0.b, v1.b, v2.b}[0], " + "[x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.b, v27.b, v28.b, " + "v29.b}[0], [x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.h, v27.h, v28.h, " + "v29.h}[0], [x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.s, v27.s, v28.s, " + "v29.s}[0], [x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "ld4 {v26.d, v27.d, v28.d, " + "v29.d}[0], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, Reg::r29), "ld4 {v26.b, v27.b, v28.b, v29.b}[15], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, Reg::r29), "ld4 {v26.h, v27.h, v28.h, v29.h}[7], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, Reg::r29), "ld4 {v26.s, v27.s, v28.s, v29.s}[3], [x30], x29"); - TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, Reg::r29), "ld4 {v26.d, v27.d, v28.d, v29.d}[1], [x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, Reg::r29), "ld4 {v26.b, v27.b, v28.b, " + "v29.b}[15], [x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, Reg::r29), "ld4 {v26.h, v27.h, v28.h, " + "v29.h}[7], [x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, Reg::r29), "ld4 {v26.s, v27.s, v28.s, " + "v29.s}[3], [x30], x29"); + TEST_SINGLE(ld4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, Reg::r29), "ld4 {v26.d, v27.d, v28.d, " + "v29.d}[1], [x30], x29"); - TEST_SINGLE(ld4r(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "ld4r {v31.8b, v0.8b, v1.8b, v2.8b}, [x30], x29"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.8b, v27.8b, v28.8b, v29.8b}, [x30], x29"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.4h, v27.4h, v28.4h, v29.4h}, [x30], x29"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.2s, v27.2s, v28.2s, v29.2s}, [x30], x29"); - TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.1d, v27.1d, v28.1d, v29.1d}, [x30], x29"); + TEST_SINGLE(ld4r(DReg::d31, DReg::d0, DReg::d1, DReg::d2, Reg::r30, Reg::r29), "ld4r {v31.8b, v0.8b, v1.8b, v2.8b}, " + "[x30], x29"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.8b, v27.8b, v28.8b, " + "v29.8b}, [x30], x29"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.4h, v27.4h, v28.4h, " + "v29.4h}, [x30], x29"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.2s, v27.2s, v28.2s, " + "v29.2s}, [x30], x29"); + TEST_SINGLE(ld4r(DReg::d26, DReg::d27, DReg::d28, DReg::d29, Reg::r30, Reg::r29), "ld4r {v26.1d, v27.1d, v28.1d, " + "v29.1d}, [x30], x29"); - TEST_SINGLE(ld4r(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "ld4r {v31.16b, v0.16b, v1.16b, v2.16b}, [x30], x29"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.16b, v27.16b, v28.16b, v29.16b}, [x30], x29"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.8h, v27.8h, v28.8h, v29.8h}, [x30], x29"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.4s, v27.4s, v28.4s, v29.4s}, [x30], x29"); - TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.2d, v27.2d, v28.2d, v29.2d}, [x30], x29"); + TEST_SINGLE(ld4r(QReg::q31, QReg::q0, QReg::q1, QReg::q2, Reg::r30, Reg::r29), "ld4r {v31.16b, v0.16b, v1.16b, " + "v2.16b}, [x30], x29"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.16b, v27.16b, v28.16b, " + "v29.16b}, [x30], x29"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.8h, v27.8h, v28.8h, " + "v29.8h}, [x30], x29"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.4s, v27.4s, v28.4s, " + "v29.4s}, [x30], x29"); + TEST_SINGLE(ld4r(QReg::q26, QReg::q27, QReg::q28, QReg::q29, Reg::r30, Reg::r29), "ld4r {v26.2d, v27.2d, v28.2d, " + "v29.2d}, [x30], x29"); - TEST_SINGLE(st4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, Reg::r29), "st4 {v31.b, v0.b, v1.b, v2.b}[0], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.b, v27.b, v28.b, v29.b}[0], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.h, v27.h, v28.h, v29.h}[0], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.s, v27.s, v28.s, v29.s}[0], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.d, v27.d, v28.d, v29.d}[0], [x30], x29"); + TEST_SINGLE(st4(VReg::v31, VReg::v0, VReg::v1, VReg::v2, 0, Reg::r30, Reg::r29), "st4 {v31.b, v0.b, v1.b, v2.b}[0], " + "[x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.b, v27.b, v28.b, " + "v29.b}[0], [x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.h, v27.h, v28.h, " + "v29.h}[0], [x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.s, v27.s, v28.s, " + "v29.s}[0], [x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 0, Reg::r30, Reg::r29), "st4 {v26.d, v27.d, v28.d, " + "v29.d}[0], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, Reg::r29), "st4 {v26.b, v27.b, v28.b, v29.b}[15], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, Reg::r29), "st4 {v26.h, v27.h, v28.h, v29.h}[7], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, Reg::r29), "st4 {v26.s, v27.s, v28.s, v29.s}[3], [x30], x29"); - TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, Reg::r29), "st4 {v26.d, v27.d, v28.d, v29.d}[1], [x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 15, Reg::r30, Reg::r29), "st4 {v26.b, v27.b, v28.b, " + "v29.b}[15], [x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 7, Reg::r30, Reg::r29), "st4 {v26.h, v27.h, v28.h, " + "v29.h}[7], [x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 3, Reg::r30, Reg::r29), "st4 {v26.s, v27.s, v28.s, " + "v29.s}[3], [x30], x29"); + TEST_SINGLE(st4(VReg::v26, VReg::v27, VReg::v28, VReg::v29, 1, Reg::r30, Reg::r29), "st4 {v26.d, v27.d, v28.d, " + "v29.d}[1], [x30], x29"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Loadstore exclusive pair") { TEST_SINGLE(stxp(Size::i32Bit, Reg::r28, Reg::r29, Reg::r30, Reg::r28), "stxp w28, w29, w30, [x28]"); @@ -1115,41 +1283,41 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Compare and swap") { } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: LDAPR/STLR unscaled immediate") { TEST_SINGLE(stlurb(Reg::r30, Reg::r29, -256), "stlurb w30, [x29, #-256]"); - TEST_SINGLE(stlurb(Reg::r30, Reg::r29, 255), "stlurb w30, [x29, #255]"); + TEST_SINGLE(stlurb(Reg::r30, Reg::r29, 255), "stlurb w30, [x29, #255]"); TEST_SINGLE(ldapurb(Reg::r30, Reg::r29, -256), "ldapurb w30, [x29, #-256]"); - TEST_SINGLE(ldapurb(Reg::r30, Reg::r29, 255), "ldapurb w30, [x29, #255]"); + TEST_SINGLE(ldapurb(Reg::r30, Reg::r29, 255), "ldapurb w30, [x29, #255]"); TEST_SINGLE(ldapursb(WReg::w30, Reg::r29, -256), "ldapursb w30, [x29, #-256]"); - TEST_SINGLE(ldapursb(WReg::w30, Reg::r29, 255), "ldapursb w30, [x29, #255]"); + TEST_SINGLE(ldapursb(WReg::w30, Reg::r29, 255), "ldapursb w30, [x29, #255]"); TEST_SINGLE(ldapursb(XReg::x30, Reg::r29, -256), "ldapursb x30, [x29, #-256]"); - TEST_SINGLE(ldapursb(XReg::x30, Reg::r29, 255), "ldapursb x30, [x29, #255]"); + TEST_SINGLE(ldapursb(XReg::x30, Reg::r29, 255), "ldapursb x30, [x29, #255]"); TEST_SINGLE(stlurh(Reg::r30, Reg::r29, -256), "stlurh w30, [x29, #-256]"); - TEST_SINGLE(stlurh(Reg::r30, Reg::r29, 255), "stlurh w30, [x29, #255]"); + TEST_SINGLE(stlurh(Reg::r30, Reg::r29, 255), "stlurh w30, [x29, #255]"); TEST_SINGLE(ldapurh(Reg::r30, Reg::r29, -256), "ldapurh w30, [x29, #-256]"); - TEST_SINGLE(ldapurh(Reg::r30, Reg::r29, 255), "ldapurh w30, [x29, #255]"); + TEST_SINGLE(ldapurh(Reg::r30, Reg::r29, 255), "ldapurh w30, [x29, #255]"); TEST_SINGLE(ldapursh(WReg::w30, Reg::r29, -256), "ldapursh w30, [x29, #-256]"); - TEST_SINGLE(ldapursh(WReg::w30, Reg::r29, 255), "ldapursh w30, [x29, #255]"); + TEST_SINGLE(ldapursh(WReg::w30, Reg::r29, 255), "ldapursh w30, [x29, #255]"); TEST_SINGLE(ldapursh(XReg::x30, Reg::r29, -256), "ldapursh x30, [x29, #-256]"); - TEST_SINGLE(ldapursh(XReg::x30, Reg::r29, 255), "ldapursh x30, [x29, #255]"); + TEST_SINGLE(ldapursh(XReg::x30, Reg::r29, 255), "ldapursh x30, [x29, #255]"); TEST_SINGLE(stlur(WReg::w30, Reg::r29, -256), "stlur w30, [x29, #-256]"); - TEST_SINGLE(stlur(WReg::w30, Reg::r29, 255), "stlur w30, [x29, #255]"); + TEST_SINGLE(stlur(WReg::w30, Reg::r29, 255), "stlur w30, [x29, #255]"); TEST_SINGLE(ldapur(WReg::w30, Reg::r29, -256), "ldapur w30, [x29, #-256]"); - TEST_SINGLE(ldapur(WReg::w30, Reg::r29, 255), "ldapur w30, [x29, #255]"); + TEST_SINGLE(ldapur(WReg::w30, Reg::r29, 255), "ldapur w30, [x29, #255]"); TEST_SINGLE(ldapursw(XReg::x30, Reg::r29, -256), "ldapursw x30, [x29, #-256]"); - TEST_SINGLE(ldapursw(XReg::x30, Reg::r29, 255), "ldapursw x30, [x29, #255]"); + TEST_SINGLE(ldapursw(XReg::x30, Reg::r29, 255), "ldapursw x30, [x29, #255]"); TEST_SINGLE(stlur(XReg::x30, Reg::r29, -256), "stlur x30, [x29, #-256]"); - TEST_SINGLE(stlur(XReg::x30, Reg::r29, 255), "stlur x30, [x29, #255]"); + TEST_SINGLE(stlur(XReg::x30, Reg::r29, 255), "stlur x30, [x29, #255]"); TEST_SINGLE(ldapur(XReg::x30, Reg::r29, -256), "ldapur x30, [x29, #-256]"); - TEST_SINGLE(ldapur(XReg::x30, Reg::r29, 255), "ldapur x30, [x29, #255]"); + TEST_SINGLE(ldapur(XReg::x30, Reg::r29, 255), "ldapur x30, [x29, #255]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Load register literal") { { @@ -1283,34 +1451,34 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Memory copy/set") { } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Loadstore no-allocate pair") { TEST_SINGLE(stnp(WReg::w30, WReg::w28, Reg::r29, -256), "stnp w30, w28, [x29, #-256]"); - TEST_SINGLE(stnp(WReg::w30, WReg::w28, Reg::r29, 252), "stnp w30, w28, [x29, #252]"); + TEST_SINGLE(stnp(WReg::w30, WReg::w28, Reg::r29, 252), "stnp w30, w28, [x29, #252]"); TEST_SINGLE(ldnp(WReg::w30, WReg::w28, Reg::r29, -256), "ldnp w30, w28, [x29, #-256]"); - TEST_SINGLE(ldnp(WReg::w30, WReg::w28, Reg::r29, 252), "ldnp w30, w28, [x29, #252]"); + TEST_SINGLE(ldnp(WReg::w30, WReg::w28, Reg::r29, 252), "ldnp w30, w28, [x29, #252]"); TEST_SINGLE(stnp(SReg::s30, SReg::s28, Reg::r29, -256), "stnp s30, s28, [x29, #-256]"); - TEST_SINGLE(stnp(SReg::s30, SReg::s28, Reg::r29, 252), "stnp s30, s28, [x29, #252]"); + TEST_SINGLE(stnp(SReg::s30, SReg::s28, Reg::r29, 252), "stnp s30, s28, [x29, #252]"); TEST_SINGLE(ldnp(SReg::s30, SReg::s28, Reg::r29, -256), "ldnp s30, s28, [x29, #-256]"); - TEST_SINGLE(ldnp(SReg::s30, SReg::s28, Reg::r29, 252), "ldnp s30, s28, [x29, #252]"); + TEST_SINGLE(ldnp(SReg::s30, SReg::s28, Reg::r29, 252), "ldnp s30, s28, [x29, #252]"); TEST_SINGLE(stnp(XReg::x30, XReg::x28, Reg::r29, -512), "stnp x30, x28, [x29, #-512]"); - TEST_SINGLE(stnp(XReg::x30, XReg::x28, Reg::r29, 504), "stnp x30, x28, [x29, #504]"); + TEST_SINGLE(stnp(XReg::x30, XReg::x28, Reg::r29, 504), "stnp x30, x28, [x29, #504]"); TEST_SINGLE(ldnp(XReg::x30, XReg::x28, Reg::r29, -512), "ldnp x30, x28, [x29, #-512]"); - TEST_SINGLE(ldnp(XReg::x30, XReg::x28, Reg::r29, 504), "ldnp x30, x28, [x29, #504]"); + TEST_SINGLE(ldnp(XReg::x30, XReg::x28, Reg::r29, 504), "ldnp x30, x28, [x29, #504]"); TEST_SINGLE(stnp(DReg::d30, DReg::d28, Reg::r29, -512), "stnp d30, d28, [x29, #-512]"); - TEST_SINGLE(stnp(DReg::d30, DReg::d28, Reg::r29, 504), "stnp d30, d28, [x29, #504]"); + TEST_SINGLE(stnp(DReg::d30, DReg::d28, Reg::r29, 504), "stnp d30, d28, [x29, #504]"); TEST_SINGLE(ldnp(DReg::d30, DReg::d28, Reg::r29, -512), "ldnp d30, d28, [x29, #-512]"); - TEST_SINGLE(ldnp(DReg::d30, DReg::d28, Reg::r29, 504), "ldnp d30, d28, [x29, #504]"); + TEST_SINGLE(ldnp(DReg::d30, DReg::d28, Reg::r29, 504), "ldnp d30, d28, [x29, #504]"); TEST_SINGLE(stnp(QReg::q30, QReg::q28, Reg::r29, -1024), "stnp q30, q28, [x29, #-1024]"); - TEST_SINGLE(stnp(QReg::q30, QReg::q28, Reg::r29, 1008), "stnp q30, q28, [x29, #1008]"); + TEST_SINGLE(stnp(QReg::q30, QReg::q28, Reg::r29, 1008), "stnp q30, q28, [x29, #1008]"); TEST_SINGLE(ldnp(QReg::q30, QReg::q28, Reg::r29, -1024), "ldnp q30, q28, [x29, #-1024]"); - TEST_SINGLE(ldnp(QReg::q30, QReg::q28, Reg::r29, 1008), "ldnp q30, q28, [x29, #1008]"); + TEST_SINGLE(ldnp(QReg::q30, QReg::q28, Reg::r29, 1008), "ldnp q30, q28, [x29, #1008]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Loadstore register pair post-indexed") { TEST_SINGLE(stp(WReg::w30, WReg::w28, Reg::r29, -256), "stp w30, w28, [x29], #-256"); @@ -1574,162 +1742,162 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Loadstore register unpri } } TEST_CASE_METHOD(TestDisassembler, "Emitter: Loadstore: Atomic memory operations") { - TEST_SINGLE(stadd(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddb w30, [x29]"); + TEST_SINGLE(stadd(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddb w30, [x29]"); TEST_SINGLE(stadd(SubRegSize::i16Bit, Reg::r30, Reg::r29), "staddh w30, [x29]"); TEST_SINGLE(stadd(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stadd w30, [x29]"); TEST_SINGLE(stadd(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stadd x30, [x29]"); - TEST_SINGLE(staddl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddlb w30, [x29]"); + TEST_SINGLE(staddl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddlb w30, [x29]"); TEST_SINGLE(staddl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "staddlh w30, [x29]"); TEST_SINGLE(staddl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "staddl w30, [x29]"); TEST_SINGLE(staddl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "staddl x30, [x29]"); - TEST_SINGLE(stadda(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddab w30, [x29]"); + TEST_SINGLE(stadda(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddab w30, [x29]"); TEST_SINGLE(stadda(SubRegSize::i16Bit, Reg::r30, Reg::r29), "staddah w30, [x29]"); TEST_SINGLE(stadda(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stadda w30, [x29]"); TEST_SINGLE(stadda(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stadda x30, [x29]"); - TEST_SINGLE(staddal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddalb w30, [x29]"); + TEST_SINGLE(staddal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "staddalb w30, [x29]"); TEST_SINGLE(staddal(SubRegSize::i16Bit, Reg::r30, Reg::r29), "staddalh w30, [x29]"); TEST_SINGLE(staddal(SubRegSize::i32Bit, Reg::r30, Reg::r29), "staddal w30, [x29]"); TEST_SINGLE(staddal(SubRegSize::i64Bit, Reg::r30, Reg::r29), "staddal x30, [x29]"); - TEST_SINGLE(stclr(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclrb w30, [x29]"); + TEST_SINGLE(stclr(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclrb w30, [x29]"); TEST_SINGLE(stclr(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stclrh w30, [x29]"); TEST_SINGLE(stclr(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stclr w30, [x29]"); TEST_SINGLE(stclr(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stclr x30, [x29]"); - TEST_SINGLE(stclrl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclrlb w30, [x29]"); + TEST_SINGLE(stclrl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclrlb w30, [x29]"); TEST_SINGLE(stclrl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stclrlh w30, [x29]"); TEST_SINGLE(stclrl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stclrl w30, [x29]"); TEST_SINGLE(stclrl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stclrl x30, [x29]"); - TEST_SINGLE(stclra(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclrab w30, [x29]"); + TEST_SINGLE(stclra(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclrab w30, [x29]"); TEST_SINGLE(stclra(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stclrah w30, [x29]"); TEST_SINGLE(stclra(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stclra w30, [x29]"); TEST_SINGLE(stclra(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stclra x30, [x29]"); - TEST_SINGLE(stclral(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclralb w30, [x29]"); + TEST_SINGLE(stclral(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stclralb w30, [x29]"); TEST_SINGLE(stclral(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stclralh w30, [x29]"); TEST_SINGLE(stclral(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stclral w30, [x29]"); TEST_SINGLE(stclral(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stclral x30, [x29]"); - TEST_SINGLE(stset(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetb w30, [x29]"); + TEST_SINGLE(stset(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetb w30, [x29]"); TEST_SINGLE(stset(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stseth w30, [x29]"); TEST_SINGLE(stset(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stset w30, [x29]"); TEST_SINGLE(stset(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stset x30, [x29]"); - TEST_SINGLE(stsetl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetlb w30, [x29]"); + TEST_SINGLE(stsetl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetlb w30, [x29]"); TEST_SINGLE(stsetl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsetlh w30, [x29]"); TEST_SINGLE(stsetl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsetl w30, [x29]"); TEST_SINGLE(stsetl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsetl x30, [x29]"); - TEST_SINGLE(stseta(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetab w30, [x29]"); + TEST_SINGLE(stseta(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetab w30, [x29]"); TEST_SINGLE(stseta(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsetah w30, [x29]"); TEST_SINGLE(stseta(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stseta w30, [x29]"); TEST_SINGLE(stseta(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stseta x30, [x29]"); - TEST_SINGLE(stsetal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetalb w30, [x29]"); + TEST_SINGLE(stsetal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsetalb w30, [x29]"); TEST_SINGLE(stsetal(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsetalh w30, [x29]"); TEST_SINGLE(stsetal(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsetal w30, [x29]"); TEST_SINGLE(stsetal(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsetal x30, [x29]"); - TEST_SINGLE(steor(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steorb w30, [x29]"); + TEST_SINGLE(steor(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steorb w30, [x29]"); TEST_SINGLE(steor(SubRegSize::i16Bit, Reg::r30, Reg::r29), "steorh w30, [x29]"); TEST_SINGLE(steor(SubRegSize::i32Bit, Reg::r30, Reg::r29), "steor w30, [x29]"); TEST_SINGLE(steor(SubRegSize::i64Bit, Reg::r30, Reg::r29), "steor x30, [x29]"); - TEST_SINGLE(steorl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steorlb w30, [x29]"); + TEST_SINGLE(steorl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steorlb w30, [x29]"); TEST_SINGLE(steorl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "steorlh w30, [x29]"); TEST_SINGLE(steorl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "steorl w30, [x29]"); TEST_SINGLE(steorl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "steorl x30, [x29]"); - TEST_SINGLE(steora(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steorab w30, [x29]"); + TEST_SINGLE(steora(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steorab w30, [x29]"); TEST_SINGLE(steora(SubRegSize::i16Bit, Reg::r30, Reg::r29), "steorah w30, [x29]"); TEST_SINGLE(steora(SubRegSize::i32Bit, Reg::r30, Reg::r29), "steora w30, [x29]"); TEST_SINGLE(steora(SubRegSize::i64Bit, Reg::r30, Reg::r29), "steora x30, [x29]"); - TEST_SINGLE(steoral(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steoralb w30, [x29]"); + TEST_SINGLE(steoral(SubRegSize::i8Bit, Reg::r30, Reg::r29), "steoralb w30, [x29]"); TEST_SINGLE(steoral(SubRegSize::i16Bit, Reg::r30, Reg::r29), "steoralh w30, [x29]"); TEST_SINGLE(steoral(SubRegSize::i32Bit, Reg::r30, Reg::r29), "steoral w30, [x29]"); TEST_SINGLE(steoral(SubRegSize::i64Bit, Reg::r30, Reg::r29), "steoral x30, [x29]"); - TEST_SINGLE(stsmax(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxb w30, [x29]"); + TEST_SINGLE(stsmax(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxb w30, [x29]"); TEST_SINGLE(stsmax(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsmaxh w30, [x29]"); TEST_SINGLE(stsmax(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsmax w30, [x29]"); TEST_SINGLE(stsmax(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsmax x30, [x29]"); - TEST_SINGLE(stsmaxl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxlb w30, [x29]"); + TEST_SINGLE(stsmaxl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxlb w30, [x29]"); TEST_SINGLE(stsmaxl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsmaxlh w30, [x29]"); TEST_SINGLE(stsmaxl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsmaxl w30, [x29]"); TEST_SINGLE(stsmaxl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsmaxl x30, [x29]"); - TEST_SINGLE(stsmaxa(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxab w30, [x29]"); + TEST_SINGLE(stsmaxa(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxab w30, [x29]"); TEST_SINGLE(stsmaxa(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsmaxah w30, [x29]"); TEST_SINGLE(stsmaxa(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsmaxa w30, [x29]"); TEST_SINGLE(stsmaxa(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsmaxa x30, [x29]"); - TEST_SINGLE(stsmaxal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxalb w30, [x29]"); + TEST_SINGLE(stsmaxal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsmaxalb w30, [x29]"); TEST_SINGLE(stsmaxal(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsmaxalh w30, [x29]"); TEST_SINGLE(stsmaxal(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsmaxal w30, [x29]"); TEST_SINGLE(stsmaxal(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsmaxal x30, [x29]"); - TEST_SINGLE(stsmin(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminb w30, [x29]"); + TEST_SINGLE(stsmin(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminb w30, [x29]"); TEST_SINGLE(stsmin(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsminh w30, [x29]"); TEST_SINGLE(stsmin(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsmin w30, [x29]"); TEST_SINGLE(stsmin(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsmin x30, [x29]"); - TEST_SINGLE(stsminl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminlb w30, [x29]"); + TEST_SINGLE(stsminl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminlb w30, [x29]"); TEST_SINGLE(stsminl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsminlh w30, [x29]"); TEST_SINGLE(stsminl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsminl w30, [x29]"); TEST_SINGLE(stsminl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsminl x30, [x29]"); - TEST_SINGLE(stsmina(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminab w30, [x29]"); + TEST_SINGLE(stsmina(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminab w30, [x29]"); TEST_SINGLE(stsmina(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsminah w30, [x29]"); TEST_SINGLE(stsmina(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsmina w30, [x29]"); TEST_SINGLE(stsmina(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsmina x30, [x29]"); - TEST_SINGLE(stsminal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminalb w30, [x29]"); + TEST_SINGLE(stsminal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stsminalb w30, [x29]"); TEST_SINGLE(stsminal(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stsminalh w30, [x29]"); TEST_SINGLE(stsminal(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stsminal w30, [x29]"); TEST_SINGLE(stsminal(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stsminal x30, [x29]"); - TEST_SINGLE(stumax(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxb w30, [x29]"); + TEST_SINGLE(stumax(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxb w30, [x29]"); TEST_SINGLE(stumax(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stumaxh w30, [x29]"); TEST_SINGLE(stumax(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stumax w30, [x29]"); TEST_SINGLE(stumax(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stumax x30, [x29]"); - TEST_SINGLE(stumaxl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxlb w30, [x29]"); + TEST_SINGLE(stumaxl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxlb w30, [x29]"); TEST_SINGLE(stumaxl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stumaxlh w30, [x29]"); TEST_SINGLE(stumaxl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stumaxl w30, [x29]"); TEST_SINGLE(stumaxl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stumaxl x30, [x29]"); - TEST_SINGLE(stumaxa(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxab w30, [x29]"); + TEST_SINGLE(stumaxa(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxab w30, [x29]"); TEST_SINGLE(stumaxa(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stumaxah w30, [x29]"); TEST_SINGLE(stumaxa(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stumaxa w30, [x29]"); TEST_SINGLE(stumaxa(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stumaxa x30, [x29]"); - TEST_SINGLE(stumaxal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxalb w30, [x29]"); + TEST_SINGLE(stumaxal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stumaxalb w30, [x29]"); TEST_SINGLE(stumaxal(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stumaxalh w30, [x29]"); TEST_SINGLE(stumaxal(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stumaxal w30, [x29]"); TEST_SINGLE(stumaxal(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stumaxal x30, [x29]"); - TEST_SINGLE(stumin(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminb w30, [x29]"); + TEST_SINGLE(stumin(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminb w30, [x29]"); TEST_SINGLE(stumin(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stuminh w30, [x29]"); TEST_SINGLE(stumin(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stumin w30, [x29]"); TEST_SINGLE(stumin(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stumin x30, [x29]"); - TEST_SINGLE(stuminl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminlb w30, [x29]"); + TEST_SINGLE(stuminl(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminlb w30, [x29]"); TEST_SINGLE(stuminl(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stuminlh w30, [x29]"); TEST_SINGLE(stuminl(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stuminl w30, [x29]"); TEST_SINGLE(stuminl(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stuminl x30, [x29]"); - TEST_SINGLE(stumina(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminab w30, [x29]"); + TEST_SINGLE(stumina(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminab w30, [x29]"); TEST_SINGLE(stumina(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stuminah w30, [x29]"); TEST_SINGLE(stumina(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stumina w30, [x29]"); TEST_SINGLE(stumina(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stumina x30, [x29]"); - TEST_SINGLE(stuminal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminalb w30, [x29]"); + TEST_SINGLE(stuminal(SubRegSize::i8Bit, Reg::r30, Reg::r29), "stuminalb w30, [x29]"); TEST_SINGLE(stuminal(SubRegSize::i16Bit, Reg::r30, Reg::r29), "stuminalh w30, [x29]"); TEST_SINGLE(stuminal(SubRegSize::i32Bit, Reg::r30, Reg::r29), "stuminal w30, [x29]"); TEST_SINGLE(stuminal(SubRegSize::i64Bit, Reg::r30, Reg::r29), "stuminal x30, [x29]"); diff --git a/FEXCore/unittests/Emitter/SVE_Tests.cpp b/FEXCore/unittests/Emitter/SVE_Tests.cpp index b707fdfa8..f45de0d6b 100644 --- a/FEXCore/unittests/Emitter/SVE_Tests.cpp +++ b/FEXCore/unittests/Emitter/SVE_Tests.cpp @@ -26,54 +26,54 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: Base Encodings") { TEST_SINGLE(dup(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, 1), "mov z30.q, z29.q[1]"); TEST_SINGLE(dup(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, 3), "mov z30.q, z29.q[3]"); - TEST_SINGLE(sel(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.b, p6, z29.b, z28.b"); - TEST_SINGLE(sel(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.h, p6, z29.h, z28.h"); - TEST_SINGLE(sel(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.s, p6, z29.s, z28.s"); - TEST_SINGLE(sel(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.d, p6, z29.d, z28.d"); - //TEST_SINGLE(sel(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.q, p6, z29.q, z28.q"); + TEST_SINGLE(sel(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.b, p6, z29.b, z28.b"); + TEST_SINGLE(sel(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.h, p6, z29.h, z28.h"); + TEST_SINGLE(sel(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.s, p6, z29.s, z28.s"); + TEST_SINGLE(sel(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.d, p6, z29.d, z28.d"); + // TEST_SINGLE(sel(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z29, ZReg::z28), "sel z30.q, p6, z29.q, z28.q"); - TEST_SINGLE(mov(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.b, p6/m, z29.b"); - TEST_SINGLE(mov(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.h, p6/m, z29.h"); - TEST_SINGLE(mov(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.s, p6/m, z29.s"); - TEST_SINGLE(mov(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.d, p6/m, z29.d"); - //TEST_SINGLE(mov(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.q, p6/m, z29.q"); + TEST_SINGLE(mov(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.b, p6/m, z29.b"); + TEST_SINGLE(mov(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.h, p6/m, z29.h"); + TEST_SINGLE(mov(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.s, p6/m, z29.s"); + TEST_SINGLE(mov(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.d, p6/m, z29.d"); + // TEST_SINGLE(mov(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "mov z30.q, p6/m, z29.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer add/subtract vectors (unpredicated)") { - TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.b, z29.b, z28.b"); - TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.h, z29.h, z28.h"); - TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.s, z29.s, z28.s"); - TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.d, z29.d, z28.d"); - //TEST_SINGLE(add(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.q, z29.q, z28.q"); + TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.b, z29.b, z28.b"); + TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.h, z29.h, z28.h"); + TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.s, z29.s, z28.s"); + TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.d, z29.d, z28.d"); + // TEST_SINGLE(add(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "add z30.q, z29.q, z28.q"); - TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.b, z29.b, z28.b"); - TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.h, z29.h, z28.h"); - TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.s, z29.s, z28.s"); - TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.d, z29.d, z28.d"); - //TEST_SINGLE(sub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.q, z29.q, z28.q"); + TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.b, z29.b, z28.b"); + TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.h, z29.h, z28.h"); + TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.s, z29.s, z28.s"); + TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.d, z29.d, z28.d"); + // TEST_SINGLE(sub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sub z30.q, z29.q, z28.q"); - TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.b, z29.b, z28.b"); - TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.h, z29.h, z28.h"); - TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.s, z29.s, z28.s"); - TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.d, z29.d, z28.d"); - //TEST_SINGLE(sqadd(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.q, z29.q, z28.q"); + TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.b, z29.b, z28.b"); + TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.h, z29.h, z28.h"); + TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.s, z29.s, z28.s"); + TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.d, z29.d, z28.d"); + // TEST_SINGLE(sqadd(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqadd z30.q, z29.q, z28.q"); - TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.b, z29.b, z28.b"); - TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.h, z29.h, z28.h"); - TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.s, z29.s, z28.s"); - TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.d, z29.d, z28.d"); - //TEST_SINGLE(uqadd(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.q, z29.q, z28.q"); + TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.b, z29.b, z28.b"); + TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.h, z29.h, z28.h"); + TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.s, z29.s, z28.s"); + TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.d, z29.d, z28.d"); + // TEST_SINGLE(uqadd(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqadd z30.q, z29.q, z28.q"); - TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.b, z29.b, z28.b"); - TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.h, z29.h, z28.h"); - TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.s, z29.s, z28.s"); - TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.d, z29.d, z28.d"); - //TEST_SINGLE(sqsub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.q, z29.q, z28.q"); + TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.b, z29.b, z28.b"); + TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.h, z29.h, z28.h"); + TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.s, z29.s, z28.s"); + TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.d, z29.d, z28.d"); + // TEST_SINGLE(sqsub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqsub z30.q, z29.q, z28.q"); - TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.b, z29.b, z28.b"); - TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.h, z29.h, z28.h"); - TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.s, z29.s, z28.s"); - TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.d, z29.d, z28.d"); - //TEST_SINGLE(uqsub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.q, z29.q, z28.q"); + TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.b, z29.b, z28.b"); + TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.h, z29.h, z28.h"); + TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.s, z29.s, z28.s"); + TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.d, z29.d, z28.d"); + // TEST_SINGLE(uqsub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uqsub z30.q, z29.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE address generation") { TEST_SINGLE(adr(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z31), "adr z30.s, [z29.s, z31.s]"); @@ -97,146 +97,145 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE address generation") { TEST_SINGLE(adr(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z31, SVEModType::MOD_SXTW, 3), "adr z30.d, [z29.d, z31.d, sxtw #3]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE table lookup (three sources)") { - TEST_SINGLE(tbl(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.b, {z29.b}, z28.b"); - TEST_SINGLE(tbl(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.h, {z29.h}, z28.h"); - TEST_SINGLE(tbl(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.s, {z29.s}, z28.s"); - TEST_SINGLE(tbl(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.d, {z29.d}, z28.d"); - //TEST_SINGLE(tbl(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.q, {z29.q}, z28.q"); + TEST_SINGLE(tbl(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.b, {z29.b}, z28.b"); + TEST_SINGLE(tbl(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.h, {z29.h}, z28.h"); + TEST_SINGLE(tbl(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.s, {z29.s}, z28.s"); + TEST_SINGLE(tbl(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.d, {z29.d}, z28.d"); + // TEST_SINGLE(tbl(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbl z30.q, {z29.q}, z28.q"); - TEST_SINGLE(tbl(SubRegSize::i8Bit, ZReg::z31, ZReg::z29, ZReg::z30, ZReg::z28), "tbl z31.b, {z29.b, z30.b}, z28.b"); + TEST_SINGLE(tbl(SubRegSize::i8Bit, ZReg::z31, ZReg::z29, ZReg::z30, ZReg::z28), "tbl z31.b, {z29.b, z30.b}, z28.b"); TEST_SINGLE(tbl(SubRegSize::i16Bit, ZReg::z31, ZReg::z29, ZReg::z30, ZReg::z28), "tbl z31.h, {z29.h, z30.h}, z28.h"); TEST_SINGLE(tbl(SubRegSize::i32Bit, ZReg::z31, ZReg::z29, ZReg::z30, ZReg::z28), "tbl z31.s, {z29.s, z30.s}, z28.s"); TEST_SINGLE(tbl(SubRegSize::i64Bit, ZReg::z31, ZReg::z29, ZReg::z30, ZReg::z28), "tbl z31.d, {z29.d, z30.d}, z28.d"); - TEST_SINGLE(tbx(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.b, z29.b, z28.b"); - TEST_SINGLE(tbx(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.h, z29.h, z28.h"); - TEST_SINGLE(tbx(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.s, z29.s, z28.s"); - TEST_SINGLE(tbx(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.d, z29.d, z28.d"); - //TEST_SINGLE(tbx(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.q, z29.q, z28.q"); - + TEST_SINGLE(tbx(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.b, z29.b, z28.b"); + TEST_SINGLE(tbx(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.h, z29.h, z28.h"); + TEST_SINGLE(tbx(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.s, z29.s, z28.s"); + TEST_SINGLE(tbx(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.d, z29.d, z28.d"); + // TEST_SINGLE(tbx(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "tbx z30.q, z29.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE permute vector elements") { - TEST_SINGLE(zip1(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip1 z30.b, z29.b, z28.b"); + TEST_SINGLE(zip1(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip1 z30.b, z29.b, z28.b"); TEST_SINGLE(zip1(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip1 z30.h, z29.h, z28.h"); TEST_SINGLE(zip1(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip1 z30.s, z29.s, z28.s"); TEST_SINGLE(zip1(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip1 z30.d, z29.d, z28.d"); - TEST_SINGLE(zip2(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip2 z30.b, z29.b, z28.b"); + TEST_SINGLE(zip2(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip2 z30.b, z29.b, z28.b"); TEST_SINGLE(zip2(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip2 z30.h, z29.h, z28.h"); TEST_SINGLE(zip2(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip2 z30.s, z29.s, z28.s"); TEST_SINGLE(zip2(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "zip2 z30.d, z29.d, z28.d"); - TEST_SINGLE(uzp1(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp1 z30.b, z29.b, z28.b"); + TEST_SINGLE(uzp1(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp1 z30.b, z29.b, z28.b"); TEST_SINGLE(uzp1(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp1 z30.h, z29.h, z28.h"); TEST_SINGLE(uzp1(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp1 z30.s, z29.s, z28.s"); TEST_SINGLE(uzp1(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp1 z30.d, z29.d, z28.d"); - TEST_SINGLE(uzp2(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp2 z30.b, z29.b, z28.b"); + TEST_SINGLE(uzp2(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp2 z30.b, z29.b, z28.b"); TEST_SINGLE(uzp2(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp2 z30.h, z29.h, z28.h"); TEST_SINGLE(uzp2(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp2 z30.s, z29.s, z28.s"); TEST_SINGLE(uzp2(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uzp2 z30.d, z29.d, z28.d"); - TEST_SINGLE(trn1(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn1 z30.b, z29.b, z28.b"); + TEST_SINGLE(trn1(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn1 z30.b, z29.b, z28.b"); TEST_SINGLE(trn1(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn1 z30.h, z29.h, z28.h"); TEST_SINGLE(trn1(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn1 z30.s, z29.s, z28.s"); TEST_SINGLE(trn1(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn1 z30.d, z29.d, z28.d"); - TEST_SINGLE(trn2(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn2 z30.b, z29.b, z28.b"); + TEST_SINGLE(trn2(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn2 z30.b, z29.b, z28.b"); TEST_SINGLE(trn2(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn2 z30.h, z29.h, z28.h"); TEST_SINGLE(trn2(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn2 z30.s, z29.s, z28.s"); TEST_SINGLE(trn2(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "trn2 z30.d, z29.d, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer compare with unsigned immediate") { - TEST_SINGLE(cmphi(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphi p6.b, p5/z, z30.b, #0"); + TEST_SINGLE(cmphi(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphi p6.b, p5/z, z30.b, #0"); TEST_SINGLE(cmphi(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphi p6.h, p5/z, z30.h, #0"); TEST_SINGLE(cmphi(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphi p6.s, p5/z, z30.s, #0"); TEST_SINGLE(cmphi(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphi p6.d, p5/z, z30.d, #0"); - TEST_SINGLE(cmphi(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphi p6.b, p5/z, z30.b, #127"); + TEST_SINGLE(cmphi(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphi p6.b, p5/z, z30.b, #127"); TEST_SINGLE(cmphi(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphi p6.h, p5/z, z30.h, #127"); TEST_SINGLE(cmphi(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphi p6.s, p5/z, z30.s, #127"); TEST_SINGLE(cmphi(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphi p6.d, p5/z, z30.d, #127"); - TEST_SINGLE(cmphs(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphs p6.b, p5/z, z30.b, #0"); + TEST_SINGLE(cmphs(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphs p6.b, p5/z, z30.b, #0"); TEST_SINGLE(cmphs(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphs p6.h, p5/z, z30.h, #0"); TEST_SINGLE(cmphs(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphs p6.s, p5/z, z30.s, #0"); TEST_SINGLE(cmphs(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmphs p6.d, p5/z, z30.d, #0"); - TEST_SINGLE(cmphs(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphs p6.b, p5/z, z30.b, #127"); + TEST_SINGLE(cmphs(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphs p6.b, p5/z, z30.b, #127"); TEST_SINGLE(cmphs(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphs p6.h, p5/z, z30.h, #127"); TEST_SINGLE(cmphs(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphs p6.s, p5/z, z30.s, #127"); TEST_SINGLE(cmphs(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmphs p6.d, p5/z, z30.d, #127"); - TEST_SINGLE(cmplo(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmplo p6.b, p5/z, z30.b, #0"); + TEST_SINGLE(cmplo(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmplo p6.b, p5/z, z30.b, #0"); TEST_SINGLE(cmplo(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmplo p6.h, p5/z, z30.h, #0"); TEST_SINGLE(cmplo(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmplo p6.s, p5/z, z30.s, #0"); TEST_SINGLE(cmplo(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmplo p6.d, p5/z, z30.d, #0"); - TEST_SINGLE(cmplo(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmplo p6.b, p5/z, z30.b, #127"); + TEST_SINGLE(cmplo(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmplo p6.b, p5/z, z30.b, #127"); TEST_SINGLE(cmplo(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmplo p6.h, p5/z, z30.h, #127"); TEST_SINGLE(cmplo(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmplo p6.s, p5/z, z30.s, #127"); TEST_SINGLE(cmplo(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmplo p6.d, p5/z, z30.d, #127"); - TEST_SINGLE(cmpls(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmpls p6.b, p5/z, z30.b, #0"); + TEST_SINGLE(cmpls(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmpls p6.b, p5/z, z30.b, #0"); TEST_SINGLE(cmpls(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmpls p6.h, p5/z, z30.h, #0"); TEST_SINGLE(cmpls(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmpls p6.s, p5/z, z30.s, #0"); TEST_SINGLE(cmpls(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 0), "cmpls p6.d, p5/z, z30.d, #0"); - TEST_SINGLE(cmpls(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmpls p6.b, p5/z, z30.b, #127"); + TEST_SINGLE(cmpls(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmpls p6.b, p5/z, z30.b, #127"); TEST_SINGLE(cmpls(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmpls p6.h, p5/z, z30.h, #127"); TEST_SINGLE(cmpls(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmpls p6.s, p5/z, z30.s, #127"); TEST_SINGLE(cmpls(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 127), "cmpls p6.d, p5/z, z30.d, #127"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer compare with signed immediate") { - TEST_SINGLE(cmpeq(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpeq p6.b, p5/z, z30.b, #-16"); + TEST_SINGLE(cmpeq(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpeq p6.b, p5/z, z30.b, #-16"); TEST_SINGLE(cmpeq(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpeq p6.h, p5/z, z30.h, #-16"); TEST_SINGLE(cmpeq(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpeq p6.s, p5/z, z30.s, #-16"); TEST_SINGLE(cmpeq(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpeq p6.d, p5/z, z30.d, #-16"); - TEST_SINGLE(cmpeq(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.b, p5/z, z30.b, #15"); - TEST_SINGLE(cmpeq(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.h, p5/z, z30.h, #15"); - TEST_SINGLE(cmpeq(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.s, p5/z, z30.s, #15"); - TEST_SINGLE(cmpeq(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.d, p5/z, z30.d, #15"); + TEST_SINGLE(cmpeq(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.b, p5/z, z30.b, #15"); + TEST_SINGLE(cmpeq(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.h, p5/z, z30.h, #15"); + TEST_SINGLE(cmpeq(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.s, p5/z, z30.s, #15"); + TEST_SINGLE(cmpeq(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpeq p6.d, p5/z, z30.d, #15"); - TEST_SINGLE(cmpgt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpgt p6.b, p5/z, z30.b, #-16"); + TEST_SINGLE(cmpgt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpgt p6.b, p5/z, z30.b, #-16"); TEST_SINGLE(cmpgt(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpgt p6.h, p5/z, z30.h, #-16"); TEST_SINGLE(cmpgt(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpgt p6.s, p5/z, z30.s, #-16"); TEST_SINGLE(cmpgt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpgt p6.d, p5/z, z30.d, #-16"); - TEST_SINGLE(cmpgt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.b, p5/z, z30.b, #15"); - TEST_SINGLE(cmpgt(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.h, p5/z, z30.h, #15"); - TEST_SINGLE(cmpgt(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.s, p5/z, z30.s, #15"); - TEST_SINGLE(cmpgt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.d, p5/z, z30.d, #15"); + TEST_SINGLE(cmpgt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.b, p5/z, z30.b, #15"); + TEST_SINGLE(cmpgt(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.h, p5/z, z30.h, #15"); + TEST_SINGLE(cmpgt(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.s, p5/z, z30.s, #15"); + TEST_SINGLE(cmpgt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpgt p6.d, p5/z, z30.d, #15"); - TEST_SINGLE(cmpge(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpge p6.b, p5/z, z30.b, #-16"); + TEST_SINGLE(cmpge(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpge p6.b, p5/z, z30.b, #-16"); TEST_SINGLE(cmpge(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpge p6.h, p5/z, z30.h, #-16"); TEST_SINGLE(cmpge(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpge p6.s, p5/z, z30.s, #-16"); TEST_SINGLE(cmpge(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpge p6.d, p5/z, z30.d, #-16"); - TEST_SINGLE(cmpge(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.b, p5/z, z30.b, #15"); - TEST_SINGLE(cmpge(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.h, p5/z, z30.h, #15"); - TEST_SINGLE(cmpge(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.s, p5/z, z30.s, #15"); - TEST_SINGLE(cmpge(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.d, p5/z, z30.d, #15"); + TEST_SINGLE(cmpge(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.b, p5/z, z30.b, #15"); + TEST_SINGLE(cmpge(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.h, p5/z, z30.h, #15"); + TEST_SINGLE(cmpge(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.s, p5/z, z30.s, #15"); + TEST_SINGLE(cmpge(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpge p6.d, p5/z, z30.d, #15"); - TEST_SINGLE(cmplt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmplt p6.b, p5/z, z30.b, #-16"); + TEST_SINGLE(cmplt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmplt p6.b, p5/z, z30.b, #-16"); TEST_SINGLE(cmplt(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmplt p6.h, p5/z, z30.h, #-16"); TEST_SINGLE(cmplt(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmplt p6.s, p5/z, z30.s, #-16"); TEST_SINGLE(cmplt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmplt p6.d, p5/z, z30.d, #-16"); - TEST_SINGLE(cmplt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.b, p5/z, z30.b, #15"); - TEST_SINGLE(cmplt(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.h, p5/z, z30.h, #15"); - TEST_SINGLE(cmplt(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.s, p5/z, z30.s, #15"); - TEST_SINGLE(cmplt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.d, p5/z, z30.d, #15"); + TEST_SINGLE(cmplt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.b, p5/z, z30.b, #15"); + TEST_SINGLE(cmplt(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.h, p5/z, z30.h, #15"); + TEST_SINGLE(cmplt(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.s, p5/z, z30.s, #15"); + TEST_SINGLE(cmplt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmplt p6.d, p5/z, z30.d, #15"); - TEST_SINGLE(cmple(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmple p6.b, p5/z, z30.b, #-16"); + TEST_SINGLE(cmple(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmple p6.b, p5/z, z30.b, #-16"); TEST_SINGLE(cmple(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmple p6.h, p5/z, z30.h, #-16"); TEST_SINGLE(cmple(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmple p6.s, p5/z, z30.s, #-16"); TEST_SINGLE(cmple(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmple p6.d, p5/z, z30.d, #-16"); - TEST_SINGLE(cmple(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.b, p5/z, z30.b, #15"); - TEST_SINGLE(cmple(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.h, p5/z, z30.h, #15"); - TEST_SINGLE(cmple(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.s, p5/z, z30.s, #15"); - TEST_SINGLE(cmple(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.d, p5/z, z30.d, #15"); + TEST_SINGLE(cmple(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.b, p5/z, z30.b, #15"); + TEST_SINGLE(cmple(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.h, p5/z, z30.h, #15"); + TEST_SINGLE(cmple(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.s, p5/z, z30.s, #15"); + TEST_SINGLE(cmple(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmple p6.d, p5/z, z30.d, #15"); - TEST_SINGLE(cmpne(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpne p6.b, p5/z, z30.b, #-16"); + TEST_SINGLE(cmpne(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpne p6.b, p5/z, z30.b, #-16"); TEST_SINGLE(cmpne(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpne p6.h, p5/z, z30.h, #-16"); TEST_SINGLE(cmpne(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpne p6.s, p5/z, z30.s, #-16"); TEST_SINGLE(cmpne(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, -16), "cmpne p6.d, p5/z, z30.d, #-16"); - TEST_SINGLE(cmpne(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.b, p5/z, z30.b, #15"); - TEST_SINGLE(cmpne(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.h, p5/z, z30.h, #15"); - TEST_SINGLE(cmpne(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.s, p5/z, z30.s, #15"); - TEST_SINGLE(cmpne(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.d, p5/z, z30.d, #15"); + TEST_SINGLE(cmpne(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.b, p5/z, z30.b, #15"); + TEST_SINGLE(cmpne(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.h, p5/z, z30.h, #15"); + TEST_SINGLE(cmpne(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.s, p5/z, z30.s, #15"); + TEST_SINGLE(cmpne(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, 15), "cmpne p6.d, p5/z, z30.d, #15"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate logical operations") { TEST_SINGLE(and_(PReg::p6, PReg::p5.Zeroing(), PReg::p4, PReg::p3), "and p6.b, p5/z, p4.b, p3.b"); @@ -271,142 +270,130 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer clamp") { // TODO: Implement in emitter. } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 character match") { - TEST_SINGLE(match(SubRegSize::i8Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), - "match p8.b, p6/z, z30.b, z29.b"); - TEST_SINGLE(match(SubRegSize::i16Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), - "match p8.h, p6/z, z30.h, z29.h"); + TEST_SINGLE(match(SubRegSize::i8Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), "match p8.b, p6/z, z30.b, z29.b"); + TEST_SINGLE(match(SubRegSize::i16Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), "match p8.h, p6/z, z30.h, z29.h"); - TEST_SINGLE(nmatch(SubRegSize::i8Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), - "nmatch p8.b, p6/z, z30.b, z29.b"); - TEST_SINGLE(nmatch(SubRegSize::i16Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), - "nmatch p8.h, p6/z, z30.h, z29.h"); + TEST_SINGLE(nmatch(SubRegSize::i8Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), "nmatch p8.b, p6/z, z30.b, z29.b"); + TEST_SINGLE(nmatch(SubRegSize::i16Bit, PReg::p8, PReg::p6.Zeroing(), ZReg::z30, ZReg::z29), "nmatch p8.h, p6/z, z30.h, z29.h"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point convert precision odd elements") { TEST_SINGLE(fcvtxnt(ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtxnt z30.s, p6/m, z29.d"); TEST_SINGLE(fcvtnt(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtnt z30.h, p6/m, z29.s"); TEST_SINGLE(fcvtnt(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtnt z30.s, p6/m, z29.d"); - //TEST_SINGLE(fcvtnt(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtnt z30.d, p6/m, z29.d"); + // TEST_SINGLE(fcvtnt(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtnt z30.d, p6/m, z29.d"); - //TEST_SINGLE(fcvtlt(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtlt z30.h, p6/m, z29.b"); + // TEST_SINGLE(fcvtlt(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtlt z30.h, p6/m, z29.b"); TEST_SINGLE(fcvtlt(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtlt z30.s, p6/m, z29.h"); TEST_SINGLE(fcvtlt(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtlt z30.d, p6/m, z29.s"); - //void fcvtxnt(FEXCore::ARMEmitter::ZRegister zd, FEXCore::ARMEmitter::PRegister pg, FEXCore::ARMEmitter::ZRegister zn) { + // void fcvtxnt(FEXCore::ARMEmitter::ZRegister zd, FEXCore::ARMEmitter::PRegister pg, FEXCore::ARMEmitter::ZRegister zn) { /////< Size is destination size - //void fcvtnt(FEXCore::ARMEmitter::SubRegSize size, FEXCore::ARMEmitter::ZRegister zd, FEXCore::ARMEmitter::PRegister pg, FEXCore::ARMEmitter::ZRegister zn) { + // void fcvtnt(FEXCore::ARMEmitter::SubRegSize size, FEXCore::ARMEmitter::ZRegister zd, FEXCore::ARMEmitter::PRegister pg, FEXCore::ARMEmitter::ZRegister zn) { /////< Size is destination size - //void fcvtlt(FEXCore::ARMEmitter::SubRegSize size, FEXCore::ARMEmitter::ZRegister zd, FEXCore::ARMEmitter::PRegister pg, FEXCore::ARMEmitter::ZRegister zn) { + // void fcvtlt(FEXCore::ARMEmitter::SubRegSize size, FEXCore::ARMEmitter::ZRegister zd, FEXCore::ARMEmitter::PRegister pg, FEXCore::ARMEmitter::ZRegister zn) { // XXX: BFCVTNT } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 floating-point pairwise operations") { - //TEST_SINGLE(faddp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(faddp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(faddp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(faddp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(faddp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(faddp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(faddp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(faddp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(faddp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(faddp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "faddp z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmaxnmp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmaxnmp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmaxnmp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmaxnmp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmaxnmp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmaxnmp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmaxnmp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmaxnmp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmaxnmp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmaxnmp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnmp z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fminnmp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fminnmp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fminnmp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fminnmp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fminnmp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fminnmp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fminnmp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fminnmp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fminnmp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fminnmp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnmp z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmax(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmax(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmax(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmax(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmin(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmin(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmin(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmin(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.q, p6/m, z30.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point complex add") { - TEST_SINGLE(fcadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_90), - "fcadd z30.h, p6/m, z30.h, z28.h, #90"); - TEST_SINGLE(fcadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_90), - "fcadd z30.s, p6/m, z30.s, z28.s, #90"); - TEST_SINGLE(fcadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_90), - "fcadd z30.d, p6/m, z30.d, z28.d, #90"); + TEST_SINGLE(fcadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_90), "fcadd z30.h, p6/m, " + "z30.h, z28.h, #90"); + TEST_SINGLE(fcadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_90), "fcadd z30.s, p6/m, " + "z30.s, z28.s, #90"); + TEST_SINGLE(fcadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_90), "fcadd z30.d, p6/m, " + "z30.d, z28.d, #90"); - TEST_SINGLE(fcadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_270), - "fcadd z30.h, p6/m, z30.h, z28.h, #270"); - TEST_SINGLE(fcadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_270), - "fcadd z30.s, p6/m, z30.s, z28.s, #270"); - TEST_SINGLE(fcadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_270), - "fcadd z30.d, p6/m, z30.d, z28.d, #270"); + TEST_SINGLE(fcadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_270), "fcadd z30.h, p6/m, " + "z30.h, z28.h, #270"); + TEST_SINGLE(fcadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_270), "fcadd z30.s, p6/m, " + "z30.s, z28.s, #270"); + TEST_SINGLE(fcadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28, Rotation::ROTATE_270), "fcadd z30.d, p6/m, " + "z30.d, z28.d, #270"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point multiply-add (vector)") { - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_0), - "fcmla z30.h, p6/m, z10.h, z28.h, #0"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_0), - "fcmla z30.s, p6/m, z10.s, z28.s, #0"); - TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_0), - "fcmla z30.d, p6/m, z10.d, z28.d, #0"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_0), "fcmla z30.h, p6/m, " + "z10.h, z28.h, #0"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_0), "fcmla z30.s, p6/m, " + "z10.s, z28.s, #0"); + TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_0), "fcmla z30.d, p6/m, " + "z10.d, z28.d, #0"); - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_90), - "fcmla z30.h, p6/m, z10.h, z28.h, #90"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_90), - "fcmla z30.s, p6/m, z10.s, z28.s, #90"); - TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_90), - "fcmla z30.d, p6/m, z10.d, z28.d, #90"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_90), "fcmla z30.h, p6/m, " + "z10.h, z28.h, #90"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_90), "fcmla z30.s, p6/m, " + "z10.s, z28.s, #90"); + TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_90), "fcmla z30.d, p6/m, " + "z10.d, z28.d, #90"); - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_180), - "fcmla z30.h, p6/m, z10.h, z28.h, #180"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_180), - "fcmla z30.s, p6/m, z10.s, z28.s, #180"); - TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_180), - "fcmla z30.d, p6/m, z10.d, z28.d, #180"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_180), "fcmla z30.h, p6/m, " + "z10.h, z28.h, #180"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_180), "fcmla z30.s, p6/m, " + "z10.s, z28.s, #180"); + TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_180), "fcmla z30.d, p6/m, " + "z10.d, z28.d, #180"); - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_270), - "fcmla z30.h, p6/m, z10.h, z28.h, #270"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_270), - "fcmla z30.s, p6/m, z10.s, z28.s, #270"); - TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_270), - "fcmla z30.d, p6/m, z10.d, z28.d, #270"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_270), "fcmla z30.h, p6/m, " + "z10.h, z28.h, #270"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_270), "fcmla z30.s, p6/m, " + "z10.s, z28.s, #270"); + TEST_SINGLE(fcmla(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z10, ZReg::z28, Rotation::ROTATE_270), "fcmla z30.d, p6/m, " + "z10.d, z28.d, #270"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point multiply-add (indexed)") { - TEST_SINGLE(fmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z7, 7), "fmla z30.h, z29.h, z7.h[7]"); - TEST_SINGLE(fmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z7, 3), "fmla z30.s, z29.s, z7.s[3]"); + TEST_SINGLE(fmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z7, 7), "fmla z30.h, z29.h, z7.h[7]"); + TEST_SINGLE(fmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z7, 3), "fmla z30.s, z29.s, z7.s[3]"); TEST_SINGLE(fmla(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z15, 1), "fmla z30.d, z29.d, z15.d[1]"); - TEST_SINGLE(fmls(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z7, 7), "fmls z30.h, z29.h, z7.h[7]"); - TEST_SINGLE(fmls(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z7, 3), "fmls z30.s, z29.s, z7.s[3]"); + TEST_SINGLE(fmls(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z7, 7), "fmls z30.h, z29.h, z7.h[7]"); + TEST_SINGLE(fmls(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z7, 3), "fmls z30.s, z29.s, z7.s[3]"); TEST_SINGLE(fmls(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z15, 1), "fmls z30.d, z29.d, z15.d[1]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point complex multiply-add (indexed)") { - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 0, Rotation::ROTATE_0), - "fcmla z30.h, z10.h, z7.h[0], #0"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 0, Rotation::ROTATE_0), - "fcmla z30.s, z10.s, z15.s[0], #0"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 0, Rotation::ROTATE_0), "fcmla z30.h, z10.h, z7.h[0], #0"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 0, Rotation::ROTATE_0), "fcmla z30.s, z10.s, z15.s[0], #0"); - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 1, Rotation::ROTATE_90), - "fcmla z30.h, z10.h, z7.h[1], #90"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 1, Rotation::ROTATE_90), - "fcmla z30.s, z10.s, z15.s[1], #90"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 1, Rotation::ROTATE_180), - "fcmla z30.s, z10.s, z15.s[1], #180"); - TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 1, Rotation::ROTATE_270), - "fcmla z30.s, z10.s, z15.s[1], #270"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 1, Rotation::ROTATE_90), "fcmla z30.h, z10.h, z7.h[1], #90"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 1, Rotation::ROTATE_90), "fcmla z30.s, z10.s, z15.s[1], #90"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 1, Rotation::ROTATE_180), "fcmla z30.s, z10.s, z15.s[1], #180"); + TEST_SINGLE(fcmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z10, ZReg::z15, 1, Rotation::ROTATE_270), "fcmla z30.s, z10.s, z15.s[1], #270"); - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 2, Rotation::ROTATE_180), - "fcmla z30.h, z10.h, z7.h[2], #180"); - TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 3, Rotation::ROTATE_270), - "fcmla z30.h, z10.h, z7.h[3], #270"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 2, Rotation::ROTATE_180), "fcmla z30.h, z10.h, z7.h[2], #180"); + TEST_SINGLE(fcmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z10, ZReg::z7, 3, Rotation::ROTATE_270), "fcmla z30.h, z10.h, z7.h[3], #270"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point multiply (indexed)") { - TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z7, 7), "fmul z30.h, z29.h, z7.h[7]"); - TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z7, 3), "fmul z30.s, z29.s, z7.s[3]"); + TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z7, 7), "fmul z30.h, z29.h, z7.h[7]"); + TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z7, 3), "fmul z30.s, z29.s, z7.s[3]"); TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z15, 1), "fmul z30.d, z29.d, z15.d[1]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating point matrix multiply accumulate") { @@ -451,41 +438,41 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point compare vec TEST_SINGLE(faclt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "facgt p6.d, p5/z, z29.d, z30.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point arithmetic (unpredicated)") { - //TEST_SINGLE(fadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.b, z29.b, z28.b"); - TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.h, z29.h, z28.h"); - TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.s, z29.s, z28.s"); - TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.d, z29.d, z28.d"); - //TEST_SINGLE(fadd(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.q, z29.q, z28.q"); + // TEST_SINGLE(fadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.b, z29.b, z28.b"); + TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.h, z29.h, z28.h"); + TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.s, z29.s, z28.s"); + TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.d, z29.d, z28.d"); + // TEST_SINGLE(fadd(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fadd z30.q, z29.q, z28.q"); - //TEST_SINGLE(fsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.b, z29.b, z28.b"); - TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.h, z29.h, z28.h"); - TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.s, z29.s, z28.s"); - TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.d, z29.d, z28.d"); - //TEST_SINGLE(fsub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.q, z29.q, z28.q"); + // TEST_SINGLE(fsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.b, z29.b, z28.b"); + TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.h, z29.h, z28.h"); + TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.s, z29.s, z28.s"); + TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.d, z29.d, z28.d"); + // TEST_SINGLE(fsub(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fsub z30.q, z29.q, z28.q"); - //TEST_SINGLE(fmul(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.b, z29.b, z28.b"); - TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.h, z29.h, z28.h"); - TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.s, z29.s, z28.s"); - TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.d, z29.d, z28.d"); - //TEST_SINGLE(fmul(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.q, z29.q, z28.q"); + // TEST_SINGLE(fmul(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.b, z29.b, z28.b"); + TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.h, z29.h, z28.h"); + TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.s, z29.s, z28.s"); + TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.d, z29.d, z28.d"); + // TEST_SINGLE(fmul(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "fmul z30.q, z29.q, z28.q"); - //TEST_SINGLE(ftsmul(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.b, z29.b, z28.b"); - TEST_SINGLE(ftsmul(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.h, z29.h, z28.h"); - TEST_SINGLE(ftsmul(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.s, z29.s, z28.s"); - TEST_SINGLE(ftsmul(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.d, z29.d, z28.d"); - //TEST_SINGLE(ftsmul(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.q, z29.q, z28.q"); + // TEST_SINGLE(ftsmul(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.b, z29.b, z28.b"); + TEST_SINGLE(ftsmul(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.h, z29.h, z28.h"); + TEST_SINGLE(ftsmul(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.s, z29.s, z28.s"); + TEST_SINGLE(ftsmul(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.d, z29.d, z28.d"); + // TEST_SINGLE(ftsmul(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ftsmul z30.q, z29.q, z28.q"); - //TEST_SINGLE(frecps(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.b, z29.b, z28.b"); - TEST_SINGLE(frecps(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.h, z29.h, z28.h"); - TEST_SINGLE(frecps(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.s, z29.s, z28.s"); - TEST_SINGLE(frecps(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.d, z29.d, z28.d"); - //TEST_SINGLE(frecps(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.q, z29.q, z28.q"); + // TEST_SINGLE(frecps(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.b, z29.b, z28.b"); + TEST_SINGLE(frecps(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.h, z29.h, z28.h"); + TEST_SINGLE(frecps(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.s, z29.s, z28.s"); + TEST_SINGLE(frecps(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.d, z29.d, z28.d"); + // TEST_SINGLE(frecps(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frecps z30.q, z29.q, z28.q"); - //TEST_SINGLE(frsqrts(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.b, z29.b, z28.b"); - TEST_SINGLE(frsqrts(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.h, z29.h, z28.h"); - TEST_SINGLE(frsqrts(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.s, z29.s, z28.s"); - TEST_SINGLE(frsqrts(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.d, z29.d, z28.d"); - //TEST_SINGLE(frsqrts(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.q, z29.q, z28.q"); + // TEST_SINGLE(frsqrts(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.b, z29.b, z28.b"); + TEST_SINGLE(frsqrts(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.h, z29.h, z28.h"); + TEST_SINGLE(frsqrts(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.s, z29.s, z28.s"); + TEST_SINGLE(frsqrts(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.d, z29.d, z28.d"); + // TEST_SINGLE(frsqrts(SubRegSize::i128Bit, ZReg::z30, ZReg::z29, ZReg::z28), "frsqrts z30.q, z29.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point recursive reduction") { TEST_SINGLE(faddv(SubRegSize::i16Bit, VReg::v30, PReg::p7, ZReg::z28), "faddv h30, p7, z28.h"); @@ -510,41 +497,41 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point recursive r } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer multiply-accumulate writing addend (predicated)") { - TEST_SINGLE(mla(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mla z30.b, p7/m, z28.b, z29.b"); + TEST_SINGLE(mla(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mla z30.b, p7/m, z28.b, z29.b"); TEST_SINGLE(mla(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mla z30.h, p7/m, z28.h, z29.h"); TEST_SINGLE(mla(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mla z30.s, p7/m, z28.s, z29.s"); TEST_SINGLE(mla(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mla z30.d, p7/m, z28.d, z29.d"); - TEST_SINGLE(mls(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mls z30.b, p7/m, z28.b, z29.b"); + TEST_SINGLE(mls(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mls z30.b, p7/m, z28.b, z29.b"); TEST_SINGLE(mls(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mls z30.h, p7/m, z28.h, z29.h"); TEST_SINGLE(mls(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mls z30.s, p7/m, z28.s, z29.s"); TEST_SINGLE(mls(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mls z30.d, p7/m, z28.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer multiply-add writing multiplicand (predicated)") { - TEST_SINGLE(mad(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mad z30.b, p7/m, z28.b, z29.b"); + TEST_SINGLE(mad(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mad z30.b, p7/m, z28.b, z29.b"); TEST_SINGLE(mad(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mad z30.h, p7/m, z28.h, z29.h"); TEST_SINGLE(mad(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mad z30.s, p7/m, z28.s, z29.s"); TEST_SINGLE(mad(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "mad z30.d, p7/m, z28.d, z29.d"); - TEST_SINGLE(msb(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "msb z30.b, p7/m, z28.b, z29.b"); + TEST_SINGLE(msb(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "msb z30.b, p7/m, z28.b, z29.b"); TEST_SINGLE(msb(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "msb z30.h, p7/m, z28.h, z29.h"); TEST_SINGLE(msb(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "msb z30.s, p7/m, z28.s, z29.s"); TEST_SINGLE(msb(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z28, ZReg::z29), "msb z30.d, p7/m, z28.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer add/subtract vectors (predicated)") { - TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "add z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "add z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "add z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "add z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "add z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sub z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sub z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sub z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sub z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sub z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "subr z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "subr z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "subr z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "subr z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "subr z30.d, p7/m, z30.d, z28.d"); @@ -583,136 +570,116 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer min/max/difference } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer multiply vectors (predicated)") { - TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "mul z30.b, p7/m, z30.b, z29.b"); - TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "mul z30.h, p7/m, z30.h, z29.h"); - TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "mul z30.s, p7/m, z30.s, z29.s"); - TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "mul z30.d, p7/m, z30.d, z29.d"); + TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "mul z30.b, p7/m, z30.b, z29.b"); + TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "mul z30.h, p7/m, z30.h, z29.h"); + TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "mul z30.s, p7/m, z30.s, z29.s"); + TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "mul z30.d, p7/m, z30.d, z29.d"); - TEST_SINGLE(smulh(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "smulh z30.b, p7/m, z30.b, z29.b"); - TEST_SINGLE(smulh(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "smulh z30.h, p7/m, z30.h, z29.h"); - TEST_SINGLE(smulh(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "smulh z30.s, p7/m, z30.s, z29.s"); - TEST_SINGLE(smulh(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "smulh z30.d, p7/m, z30.d, z29.d"); + TEST_SINGLE(smulh(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "smulh z30.b, p7/m, z30.b, z29.b"); + TEST_SINGLE(smulh(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "smulh z30.h, p7/m, z30.h, z29.h"); + TEST_SINGLE(smulh(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "smulh z30.s, p7/m, z30.s, z29.s"); + TEST_SINGLE(smulh(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "smulh z30.d, p7/m, z30.d, z29.d"); - TEST_SINGLE(umulh(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "umulh z30.b, p7/m, z30.b, z29.b"); - TEST_SINGLE(umulh(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "umulh z30.h, p7/m, z30.h, z29.h"); - TEST_SINGLE(umulh(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "umulh z30.s, p7/m, z30.s, z29.s"); - TEST_SINGLE(umulh(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "umulh z30.d, p7/m, z30.d, z29.d"); + TEST_SINGLE(umulh(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "umulh z30.b, p7/m, z30.b, z29.b"); + TEST_SINGLE(umulh(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "umulh z30.h, p7/m, z30.h, z29.h"); + TEST_SINGLE(umulh(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "umulh z30.s, p7/m, z30.s, z29.s"); + TEST_SINGLE(umulh(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "umulh z30.d, p7/m, z30.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer divide vectors (predicated)") { - TEST_SINGLE(sdiv(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "sdiv z30.s, p7/m, z30.s, z29.s"); - TEST_SINGLE(sdiv(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "sdiv z30.d, p7/m, z30.d, z29.d"); + TEST_SINGLE(sdiv(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "sdiv z30.s, p7/m, z30.s, z29.s"); + TEST_SINGLE(sdiv(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "sdiv z30.d, p7/m, z30.d, z29.d"); - TEST_SINGLE(udiv(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "udiv z30.s, p7/m, z30.s, z29.s"); - TEST_SINGLE(udiv(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "udiv z30.d, p7/m, z30.d, z29.d"); + TEST_SINGLE(udiv(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "udiv z30.s, p7/m, z30.s, z29.s"); + TEST_SINGLE(udiv(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "udiv z30.d, p7/m, z30.d, z29.d"); - TEST_SINGLE(sdivr(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "sdivr z30.s, p7/m, z30.s, z29.s"); - TEST_SINGLE(sdivr(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "sdivr z30.d, p7/m, z30.d, z29.d"); + TEST_SINGLE(sdivr(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "sdivr z30.s, p7/m, z30.s, z29.s"); + TEST_SINGLE(sdivr(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "sdivr z30.d, p7/m, z30.d, z29.d"); - TEST_SINGLE(udivr(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "udivr z30.s, p7/m, z30.s, z29.s"); - TEST_SINGLE(udivr(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), - "udivr z30.d, p7/m, z30.d, z29.d"); + TEST_SINGLE(udivr(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "udivr z30.s, p7/m, z30.s, z29.s"); + TEST_SINGLE(udivr(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "udivr z30.d, p7/m, z30.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise logical operations (predicated)") { - TEST_SINGLE(orr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(orr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(orr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(orr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.d, p6/m, z30.d, z29.d"); - //TEST_SINGLE(orr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.q, p6/m, z30.q, z29.q"); + TEST_SINGLE(orr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(orr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(orr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(orr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.d, p6/m, z30.d, z29.d"); + // TEST_SINGLE(orr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "orr z30.q, p6/m, z30.q, z29.q"); - TEST_SINGLE(eor(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(eor(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(eor(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(eor(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.d, p6/m, z30.d, z29.d"); - //TEST_SINGLE(eor(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.q, p6/m, z30.q, z29.q"); + TEST_SINGLE(eor(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(eor(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(eor(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(eor(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.d, p6/m, z30.d, z29.d"); + // TEST_SINGLE(eor(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "eor z30.q, p6/m, z30.q, z29.q"); - TEST_SINGLE(and_(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(and_(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(and_(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(and_(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.d, p6/m, z30.d, z29.d"); - //TEST_SINGLE(and_(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.q, p6/m, z30.q, z29.q"); + TEST_SINGLE(and_(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(and_(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(and_(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(and_(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.d, p6/m, z30.d, z29.d"); + // TEST_SINGLE(and_(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "and z30.q, p6/m, z30.q, z29.q"); - TEST_SINGLE(bic(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(bic(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(bic(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(bic(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.d, p6/m, z30.d, z29.d"); - //TEST_SINGLE(bic(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.q, p6/m, z30.q, z29.q"); + TEST_SINGLE(bic(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(bic(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(bic(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(bic(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.d, p6/m, z30.d, z29.d"); + // TEST_SINGLE(bic(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "bic z30.q, p6/m, z30.q, z29.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer add reduction (predicated)") { - TEST_SINGLE(saddv(SubRegSize::i8Bit, DReg::d30, PReg::p7, ZReg::z29), "saddv d30, p7, z29.b"); + TEST_SINGLE(saddv(SubRegSize::i8Bit, DReg::d30, PReg::p7, ZReg::z29), "saddv d30, p7, z29.b"); TEST_SINGLE(saddv(SubRegSize::i16Bit, DReg::d30, PReg::p7, ZReg::z29), "saddv d30, p7, z29.h"); TEST_SINGLE(saddv(SubRegSize::i32Bit, DReg::d30, PReg::p7, ZReg::z29), "saddv d30, p7, z29.s"); - TEST_SINGLE(uaddv(SubRegSize::i8Bit, DReg::d30, PReg::p7, ZReg::z29), "uaddv d30, p7, z29.b"); + TEST_SINGLE(uaddv(SubRegSize::i8Bit, DReg::d30, PReg::p7, ZReg::z29), "uaddv d30, p7, z29.b"); TEST_SINGLE(uaddv(SubRegSize::i16Bit, DReg::d30, PReg::p7, ZReg::z29), "uaddv d30, p7, z29.h"); TEST_SINGLE(uaddv(SubRegSize::i32Bit, DReg::d30, PReg::p7, ZReg::z29), "uaddv d30, p7, z29.s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer min/max reduction (predicated)") { - TEST_SINGLE(smaxv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv b30, p6, z29.b"); - TEST_SINGLE(smaxv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv h30, p6, z29.h"); - TEST_SINGLE(smaxv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv s30, p6, z29.s"); - TEST_SINGLE(smaxv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv d30, p6, z29.d"); + TEST_SINGLE(smaxv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv b30, p6, z29.b"); + TEST_SINGLE(smaxv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv h30, p6, z29.h"); + TEST_SINGLE(smaxv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv s30, p6, z29.s"); + TEST_SINGLE(smaxv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "smaxv d30, p6, z29.d"); - TEST_SINGLE(umaxv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv b30, p6, z29.b"); - TEST_SINGLE(umaxv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv h30, p6, z29.h"); - TEST_SINGLE(umaxv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv s30, p6, z29.s"); - TEST_SINGLE(umaxv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv d30, p6, z29.d"); + TEST_SINGLE(umaxv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv b30, p6, z29.b"); + TEST_SINGLE(umaxv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv h30, p6, z29.h"); + TEST_SINGLE(umaxv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv s30, p6, z29.s"); + TEST_SINGLE(umaxv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "umaxv d30, p6, z29.d"); - TEST_SINGLE(sminv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv b30, p6, z29.b"); - TEST_SINGLE(sminv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv h30, p6, z29.h"); - TEST_SINGLE(sminv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv s30, p6, z29.s"); - TEST_SINGLE(sminv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv d30, p6, z29.d"); + TEST_SINGLE(sminv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv b30, p6, z29.b"); + TEST_SINGLE(sminv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv h30, p6, z29.h"); + TEST_SINGLE(sminv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv s30, p6, z29.s"); + TEST_SINGLE(sminv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "sminv d30, p6, z29.d"); - TEST_SINGLE(uminv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv b30, p6, z29.b"); - TEST_SINGLE(uminv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv h30, p6, z29.h"); - TEST_SINGLE(uminv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv s30, p6, z29.s"); - TEST_SINGLE(uminv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv d30, p6, z29.d"); + TEST_SINGLE(uminv(SubRegSize::i8Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv b30, p6, z29.b"); + TEST_SINGLE(uminv(SubRegSize::i16Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv h30, p6, z29.h"); + TEST_SINGLE(uminv(SubRegSize::i32Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv s30, p6, z29.s"); + TEST_SINGLE(uminv(SubRegSize::i64Bit, VReg::v30, PReg::p6, ZReg::z29), "uminv d30, p6, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE constructive prefix (predicated)") { - TEST_SINGLE(movprfx(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.b, p6/m, z29.b"); - TEST_SINGLE(movprfx(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.h, p6/m, z29.h"); - TEST_SINGLE(movprfx(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.s, p6/m, z29.s"); - TEST_SINGLE(movprfx(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.d, p6/m, z29.d"); - //TEST_SINGLE(movprfx(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.q, p6/m, z29.q"); - TEST_SINGLE(movprfx(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.b, p6/z, z29.b"); - TEST_SINGLE(movprfx(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.h, p6/z, z29.h"); - TEST_SINGLE(movprfx(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.s, p6/z, z29.s"); - TEST_SINGLE(movprfx(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.d, p6/z, z29.d"); - //TEST_SINGLE(movprfx(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.q, p6/z, z29.q"); + TEST_SINGLE(movprfx(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.b, p6/m, z29.b"); + TEST_SINGLE(movprfx(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.h, p6/m, z29.h"); + TEST_SINGLE(movprfx(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.s, p6/m, z29.s"); + TEST_SINGLE(movprfx(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.d, p6/m, z29.d"); + // TEST_SINGLE(movprfx(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "movprfx z30.q, p6/m, z29.q"); + TEST_SINGLE(movprfx(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.b, p6/z, z29.b"); + TEST_SINGLE(movprfx(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.h, p6/z, z29.h"); + TEST_SINGLE(movprfx(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.s, p6/z, z29.s"); + TEST_SINGLE(movprfx(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.d, p6/z, z29.d"); + // TEST_SINGLE(movprfx(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29), "movprfx z30.q, p6/z, z29.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise logical reduction (predicated)") { - TEST_SINGLE(orv(SubRegSize::i8Bit, VReg::v30, PReg::p7, ZReg::z29), "orv b30, p7, z29.b"); + TEST_SINGLE(orv(SubRegSize::i8Bit, VReg::v30, PReg::p7, ZReg::z29), "orv b30, p7, z29.b"); TEST_SINGLE(orv(SubRegSize::i16Bit, VReg::v30, PReg::p7, ZReg::z29), "orv h30, p7, z29.h"); TEST_SINGLE(orv(SubRegSize::i32Bit, VReg::v30, PReg::p7, ZReg::z29), "orv s30, p7, z29.s"); TEST_SINGLE(orv(SubRegSize::i64Bit, VReg::v30, PReg::p7, ZReg::z29), "orv d30, p7, z29.d"); - TEST_SINGLE(eorv(SubRegSize::i8Bit, VReg::v30, PReg::p7, ZReg::z29), "eorv b30, p7, z29.b"); + TEST_SINGLE(eorv(SubRegSize::i8Bit, VReg::v30, PReg::p7, ZReg::z29), "eorv b30, p7, z29.b"); TEST_SINGLE(eorv(SubRegSize::i16Bit, VReg::v30, PReg::p7, ZReg::z29), "eorv h30, p7, z29.h"); TEST_SINGLE(eorv(SubRegSize::i32Bit, VReg::v30, PReg::p7, ZReg::z29), "eorv s30, p7, z29.s"); TEST_SINGLE(eorv(SubRegSize::i64Bit, VReg::v30, PReg::p7, ZReg::z29), "eorv d30, p7, z29.d"); - TEST_SINGLE(andv(SubRegSize::i8Bit, VReg::v30, PReg::p7, ZReg::z29), "andv b30, p7, z29.b"); + TEST_SINGLE(andv(SubRegSize::i8Bit, VReg::v30, PReg::p7, ZReg::z29), "andv b30, p7, z29.b"); TEST_SINGLE(andv(SubRegSize::i16Bit, VReg::v30, PReg::p7, ZReg::z29), "andv h30, p7, z29.h"); TEST_SINGLE(andv(SubRegSize::i32Bit, VReg::v30, PReg::p7, ZReg::z29), "andv s30, p7, z29.s"); TEST_SINGLE(andv(SubRegSize::i64Bit, VReg::v30, PReg::p7, ZReg::z29), "andv d30, p7, z29.d"); @@ -800,140 +767,140 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise shift by immediate TEST_SINGLE(sqshlu(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, 63), "sqshlu z30.d, p6/m, z30.d, #63"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise shift by vector (predicated)") { - TEST_SINGLE(asr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(asr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asr z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(asr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asr z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(asr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asr z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(asr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(lsr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(lsr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsr z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(lsr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsr z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(lsr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsr z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(lsr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(lsl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsl z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(lsl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsl z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(lsl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsl z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(lsl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsl z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(lsl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsl z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(asrr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asrr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(asrr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asrr z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(asrr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asrr z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(asrr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asrr z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(asrr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "asrr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(lsrr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsrr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(lsrr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsrr z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(lsrr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsrr z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(lsrr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsrr z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(lsrr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lsrr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(lslr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lslr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(lslr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lslr z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(lslr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lslr z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(lslr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lslr z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(lslr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "lslr z30.d, p6/m, z30.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise shift by wide elements (predicated)") { - TEST_SINGLE(asr_wide(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "asr z30.b, p7/m, z30.b, z29.d"); + TEST_SINGLE(asr_wide(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "asr z30.b, p7/m, z30.b, z29.d"); TEST_SINGLE(asr_wide(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "asr z30.h, p7/m, z30.h, z29.d"); TEST_SINGLE(asr_wide(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "asr z30.s, p7/m, z30.s, z29.d"); - TEST_SINGLE(lsr_wide(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsr z30.b, p7/m, z30.b, z29.d"); + TEST_SINGLE(lsr_wide(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsr z30.b, p7/m, z30.b, z29.d"); TEST_SINGLE(lsr_wide(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsr z30.h, p7/m, z30.h, z29.d"); TEST_SINGLE(lsr_wide(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsr z30.s, p7/m, z30.s, z29.d"); - TEST_SINGLE(lsl_wide(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsl z30.b, p7/m, z30.b, z29.d"); + TEST_SINGLE(lsl_wide(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsl z30.b, p7/m, z30.b, z29.d"); TEST_SINGLE(lsl_wide(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsl z30.h, p7/m, z30.h, z29.d"); TEST_SINGLE(lsl_wide(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z29), "lsl z30.s, p7/m, z30.s, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer unary operations (predicated)") { - //TEST_SINGLE(sxtb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.b, p6/m, z29.b"); - TEST_SINGLE(sxtb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.h, p6/m, z29.h"); - TEST_SINGLE(sxtb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.s, p6/m, z29.s"); - TEST_SINGLE(sxtb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.d, p6/m, z29.d"); - //TEST_SINGLE(sxtb(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.q, p6/m, z29.q"); + // TEST_SINGLE(sxtb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.b, p6/m, z29.b"); + TEST_SINGLE(sxtb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.h, p6/m, z29.h"); + TEST_SINGLE(sxtb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.s, p6/m, z29.s"); + TEST_SINGLE(sxtb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.d, p6/m, z29.d"); + // TEST_SINGLE(sxtb(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtb z30.q, p6/m, z29.q"); - //TEST_SINGLE(uxtb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.b, p6/m, z29.b"); - TEST_SINGLE(uxtb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.h, p6/m, z29.h"); - TEST_SINGLE(uxtb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.s, p6/m, z29.s"); - TEST_SINGLE(uxtb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.d, p6/m, z29.d"); - //TEST_SINGLE(uxtb(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.q, p6/m, z29.q"); + // TEST_SINGLE(uxtb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.b, p6/m, z29.b"); + TEST_SINGLE(uxtb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.h, p6/m, z29.h"); + TEST_SINGLE(uxtb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.s, p6/m, z29.s"); + TEST_SINGLE(uxtb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.d, p6/m, z29.d"); + // TEST_SINGLE(uxtb(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtb z30.q, p6/m, z29.q"); - //TEST_SINGLE(sxth(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.b, p6/m, z29.b"); - //TEST_SINGLE(sxth(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.h, p6/m, z29.h"); - TEST_SINGLE(sxth(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.s, p6/m, z29.s"); - TEST_SINGLE(sxth(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.d, p6/m, z29.d"); - //TEST_SINGLE(sxth(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.q, p6/m, z29.q"); + // TEST_SINGLE(sxth(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.b, p6/m, z29.b"); + // TEST_SINGLE(sxth(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.h, p6/m, z29.h"); + TEST_SINGLE(sxth(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.s, p6/m, z29.s"); + TEST_SINGLE(sxth(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.d, p6/m, z29.d"); + // TEST_SINGLE(sxth(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxth z30.q, p6/m, z29.q"); - //TEST_SINGLE(uxth(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.b, p6/m, z29.b"); - //TEST_SINGLE(uxth(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.h, p6/m, z29.h"); - TEST_SINGLE(uxth(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.s, p6/m, z29.s"); - TEST_SINGLE(uxth(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.d, p6/m, z29.d"); - //TEST_SINGLE(uxth(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.q, p6/m, z29.q"); + // TEST_SINGLE(uxth(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.b, p6/m, z29.b"); + // TEST_SINGLE(uxth(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.h, p6/m, z29.h"); + TEST_SINGLE(uxth(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.s, p6/m, z29.s"); + TEST_SINGLE(uxth(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.d, p6/m, z29.d"); + // TEST_SINGLE(uxth(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxth z30.q, p6/m, z29.q"); - //TEST_SINGLE(sxtw(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.b, p6/m, z29.b"); - //TEST_SINGLE(sxtw(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.h, p6/m, z29.h"); - //TEST_SINGLE(sxtw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.s, p6/m, z29.s"); - TEST_SINGLE(sxtw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.d, p6/m, z29.d"); - //TEST_SINGLE(sxtw(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.q, p6/m, z29.q"); + // TEST_SINGLE(sxtw(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.b, p6/m, z29.b"); + // TEST_SINGLE(sxtw(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.h, p6/m, z29.h"); + // TEST_SINGLE(sxtw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.s, p6/m, z29.s"); + TEST_SINGLE(sxtw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.d, p6/m, z29.d"); + // TEST_SINGLE(sxtw(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sxtw z30.q, p6/m, z29.q"); - //TEST_SINGLE(uxtw(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.b, p6/m, z29.b"); - //TEST_SINGLE(uxtw(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.h, p6/m, z29.h"); - //TEST_SINGLE(uxtw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.s, p6/m, z29.s"); - TEST_SINGLE(uxtw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.d, p6/m, z29.d"); - //TEST_SINGLE(uxtw(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.q, p6/m, z29.q"); + // TEST_SINGLE(uxtw(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.b, p6/m, z29.b"); + // TEST_SINGLE(uxtw(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.h, p6/m, z29.h"); + // TEST_SINGLE(uxtw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.s, p6/m, z29.s"); + TEST_SINGLE(uxtw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.d, p6/m, z29.d"); + // TEST_SINGLE(uxtw(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uxtw z30.q, p6/m, z29.q"); - TEST_SINGLE(abs(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.b, p6/m, z29.b"); - TEST_SINGLE(abs(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.h, p6/m, z29.h"); - TEST_SINGLE(abs(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.s, p6/m, z29.s"); - TEST_SINGLE(abs(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.d, p6/m, z29.d"); - //TEST_SINGLE(abs(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.q, p6/m, z29.q"); + TEST_SINGLE(abs(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.b, p6/m, z29.b"); + TEST_SINGLE(abs(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.h, p6/m, z29.h"); + TEST_SINGLE(abs(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.s, p6/m, z29.s"); + TEST_SINGLE(abs(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.d, p6/m, z29.d"); + // TEST_SINGLE(abs(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "abs z30.q, p6/m, z29.q"); - TEST_SINGLE(neg(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.b, p6/m, z29.b"); - TEST_SINGLE(neg(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.h, p6/m, z29.h"); - TEST_SINGLE(neg(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.s, p6/m, z29.s"); - TEST_SINGLE(neg(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.d, p6/m, z29.d"); - //TEST_SINGLE(neg(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.q, p6/m, z29.q"); + TEST_SINGLE(neg(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.b, p6/m, z29.b"); + TEST_SINGLE(neg(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.h, p6/m, z29.h"); + TEST_SINGLE(neg(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.s, p6/m, z29.s"); + TEST_SINGLE(neg(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.d, p6/m, z29.d"); + // TEST_SINGLE(neg(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "neg z30.q, p6/m, z29.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise unary operations (predicated)") { - TEST_SINGLE(cls(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.b, p6/m, z29.b"); - TEST_SINGLE(cls(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.h, p6/m, z29.h"); - TEST_SINGLE(cls(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.s, p6/m, z29.s"); - TEST_SINGLE(cls(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.d, p6/m, z29.d"); - //TEST_SINGLE(cls(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.q, p6/m, z29.q"); + TEST_SINGLE(cls(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.b, p6/m, z29.b"); + TEST_SINGLE(cls(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.h, p6/m, z29.h"); + TEST_SINGLE(cls(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.s, p6/m, z29.s"); + TEST_SINGLE(cls(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.d, p6/m, z29.d"); + // TEST_SINGLE(cls(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cls z30.q, p6/m, z29.q"); - TEST_SINGLE(clz(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.b, p6/m, z29.b"); - TEST_SINGLE(clz(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.h, p6/m, z29.h"); - TEST_SINGLE(clz(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.s, p6/m, z29.s"); - TEST_SINGLE(clz(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.d, p6/m, z29.d"); - //TEST_SINGLE(clz(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.q, p6/m, z29.q"); + TEST_SINGLE(clz(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.b, p6/m, z29.b"); + TEST_SINGLE(clz(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.h, p6/m, z29.h"); + TEST_SINGLE(clz(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.s, p6/m, z29.s"); + TEST_SINGLE(clz(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.d, p6/m, z29.d"); + // TEST_SINGLE(clz(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "clz z30.q, p6/m, z29.q"); - TEST_SINGLE(cnt(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.b, p6/m, z29.b"); - TEST_SINGLE(cnt(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.h, p6/m, z29.h"); - TEST_SINGLE(cnt(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.s, p6/m, z29.s"); - TEST_SINGLE(cnt(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.d, p6/m, z29.d"); - //TEST_SINGLE(cnt(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.q, p6/m, z29.q"); + TEST_SINGLE(cnt(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.b, p6/m, z29.b"); + TEST_SINGLE(cnt(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.h, p6/m, z29.h"); + TEST_SINGLE(cnt(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.s, p6/m, z29.s"); + TEST_SINGLE(cnt(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.d, p6/m, z29.d"); + // TEST_SINGLE(cnt(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnt z30.q, p6/m, z29.q"); - TEST_SINGLE(cnot(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.b, p6/m, z29.b"); - TEST_SINGLE(cnot(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.h, p6/m, z29.h"); - TEST_SINGLE(cnot(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.s, p6/m, z29.s"); - TEST_SINGLE(cnot(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.d, p6/m, z29.d"); - //TEST_SINGLE(cnot(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.q, p6/m, z29.q"); + TEST_SINGLE(cnot(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.b, p6/m, z29.b"); + TEST_SINGLE(cnot(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.h, p6/m, z29.h"); + TEST_SINGLE(cnot(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.s, p6/m, z29.s"); + TEST_SINGLE(cnot(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.d, p6/m, z29.d"); + // TEST_SINGLE(cnot(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "cnot z30.q, p6/m, z29.q"); - //TEST_SINGLE(fabs(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.b, p6/m, z29.b"); - TEST_SINGLE(fabs(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.h, p6/m, z29.h"); - TEST_SINGLE(fabs(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.s, p6/m, z29.s"); - TEST_SINGLE(fabs(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.d, p6/m, z29.d"); - //TEST_SINGLE(fabs(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.q, p6/m, z29.q"); + // TEST_SINGLE(fabs(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.b, p6/m, z29.b"); + TEST_SINGLE(fabs(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.h, p6/m, z29.h"); + TEST_SINGLE(fabs(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.s, p6/m, z29.s"); + TEST_SINGLE(fabs(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.d, p6/m, z29.d"); + // TEST_SINGLE(fabs(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fabs z30.q, p6/m, z29.q"); - //TEST_SINGLE(fneg(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.b, p6/m, z29.b"); - TEST_SINGLE(fneg(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.h, p6/m, z29.h"); - TEST_SINGLE(fneg(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.s, p6/m, z29.s"); - TEST_SINGLE(fneg(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.d, p6/m, z29.d"); - //TEST_SINGLE(fneg(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.q, p6/m, z29.q"); + // TEST_SINGLE(fneg(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.b, p6/m, z29.b"); + TEST_SINGLE(fneg(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.h, p6/m, z29.h"); + TEST_SINGLE(fneg(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.s, p6/m, z29.s"); + TEST_SINGLE(fneg(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.d, p6/m, z29.d"); + // TEST_SINGLE(fneg(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fneg z30.q, p6/m, z29.q"); - TEST_SINGLE(not_(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.b, p6/m, z29.b"); - TEST_SINGLE(not_(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.h, p6/m, z29.h"); - TEST_SINGLE(not_(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.s, p6/m, z29.s"); - TEST_SINGLE(not_(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.d, p6/m, z29.d"); - //TEST_SINGLE(not_(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.q, p6/m, z29.q"); + TEST_SINGLE(not_(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.b, p6/m, z29.b"); + TEST_SINGLE(not_(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.h, p6/m, z29.h"); + TEST_SINGLE(not_(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.s, p6/m, z29.s"); + TEST_SINGLE(not_(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.d, p6/m, z29.d"); + // TEST_SINGLE(not_(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "not z30.q, p6/m, z29.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise logical operations (unpredicated)") { TEST_SINGLE(and_(ZReg::z30, ZReg::z29, ZReg::z28), "and z30.d, z29.d, z28.d"); @@ -942,13 +909,13 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise logical operations TEST_SINGLE(eor(ZReg::z30, ZReg::z29, ZReg::z28), "eor z30.d, z29.d, z28.d"); TEST_SINGLE(bic(ZReg::z30, ZReg::z29, ZReg::z28), "bic z30.d, z29.d, z28.d"); - TEST_SINGLE(xar(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "xar z30.b, z30.b, z29.b, #1"); - TEST_SINGLE(xar(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "xar z30.b, z30.b, z29.b, #8"); - TEST_SINGLE(xar(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "xar z30.h, z30.h, z29.h, #1"); + TEST_SINGLE(xar(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "xar z30.b, z30.b, z29.b, #1"); + TEST_SINGLE(xar(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "xar z30.b, z30.b, z29.b, #8"); + TEST_SINGLE(xar(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "xar z30.h, z30.h, z29.h, #1"); TEST_SINGLE(xar(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "xar z30.h, z30.h, z29.h, #16"); - TEST_SINGLE(xar(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "xar z30.s, z30.s, z29.s, #1"); + TEST_SINGLE(xar(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "xar z30.s, z30.s, z29.s, #1"); TEST_SINGLE(xar(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "xar z30.s, z30.s, z29.s, #32"); - TEST_SINGLE(xar(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "xar z30.d, z30.d, z29.d, #1"); + TEST_SINGLE(xar(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "xar z30.d, z30.d, z29.d, #1"); TEST_SINGLE(xar(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "xar z30.d, z30.d, z29.d, #64"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise ternary operations") { @@ -960,35 +927,35 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise ternary operation TEST_SINGLE(nbsl(ZReg::z30, ZReg::z30, ZReg::z28, ZReg::z29), "nbsl z30.d, z30.d, z28.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Index Generation") { - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, -16, -16), "index z30.b, #-16, #-16"); - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, -16, 15), "index z30.b, #-16, #15"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, -16, -16), "index z30.b, #-16, #-16"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, -16, 15), "index z30.b, #-16, #15"); TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, -16, -16), "index z30.h, #-16, #-16"); - TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, -16, 15), "index z30.h, #-16, #15"); + TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, -16, 15), "index z30.h, #-16, #15"); TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, -16, -16), "index z30.s, #-16, #-16"); - TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, -16, 15), "index z30.s, #-16, #15"); + TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, -16, 15), "index z30.s, #-16, #15"); TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, -16, -16), "index z30.d, #-16, #-16"); - TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, -16, 15), "index z30.d, #-16, #15"); + TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, -16, 15), "index z30.d, #-16, #15"); - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, -16), "index z30.b, w29, #-16"); - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, 15), "index z30.b, w29, #15"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, -16), "index z30.b, w29, #-16"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, 15), "index z30.b, w29, #15"); TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, WReg::w29, -16), "index z30.h, w29, #-16"); - TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, WReg::w29, 15), "index z30.h, w29, #15"); + TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, WReg::w29, 15), "index z30.h, w29, #15"); TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, WReg::w29, -16), "index z30.s, w29, #-16"); - TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, WReg::w29, 15), "index z30.s, w29, #15"); + TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, WReg::w29, 15), "index z30.s, w29, #15"); TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, XReg::x29, -16), "index z30.d, x29, #-16"); - TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, XReg::x29, 15), "index z30.d, x29, #15"); + TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, XReg::x29, 15), "index z30.d, x29, #15"); - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, -16, WReg::w29), "index z30.b, #-16, w29"); - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, 15, WReg::w29), "index z30.b, #15, w29"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, -16, WReg::w29), "index z30.b, #-16, w29"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, 15, WReg::w29), "index z30.b, #15, w29"); TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, -16, WReg::w29), "index z30.h, #-16, w29"); - TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, 15, WReg::w29), "index z30.h, #15, w29"); + TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, 15, WReg::w29), "index z30.h, #15, w29"); TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, -16, WReg::w29), "index z30.s, #-16, w29"); - TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, 15, WReg::w29), "index z30.s, #15, w29"); + TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, 15, WReg::w29), "index z30.s, #15, w29"); TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, -16, XReg::x29), "index z30.d, #-16, x29"); - TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, 15, XReg::x29), "index z30.d, #15, x29"); + TEST_SINGLE(index(SubRegSize::i64Bit, ZReg::z30, 15, XReg::x29), "index z30.d, #15, x29"); - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, WReg::w28), "index z30.b, w29, w28"); - TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, WReg::w28), "index z30.b, w29, w28"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, WReg::w28), "index z30.b, w29, w28"); + TEST_SINGLE(index(SubRegSize::i8Bit, ZReg::z30, WReg::w29, WReg::w28), "index z30.b, w29, w28"); TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, WReg::w29, WReg::w28), "index z30.h, w29, w28"); TEST_SINGLE(index(SubRegSize::i16Bit, ZReg::z30, WReg::w29, WReg::w28), "index z30.h, w29, w28"); TEST_SINGLE(index(SubRegSize::i32Bit, ZReg::z30, WReg::w29, WReg::w28), "index z30.s, w29, w28"); @@ -998,20 +965,20 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Index Generation") { } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE stack frame adjustment") { TEST_SINGLE(addvl(XReg::rsp, XReg::rsp, -32), "addvl sp, sp, #-32"); - TEST_SINGLE(addvl(XReg::rsp, XReg::rsp, 31), "addvl sp, sp, #31"); - TEST_SINGLE(addvl(XReg::x30, XReg::x29, 15), "addvl x30, x29, #15"); + TEST_SINGLE(addvl(XReg::rsp, XReg::rsp, 31), "addvl sp, sp, #31"); + TEST_SINGLE(addvl(XReg::x30, XReg::x29, 15), "addvl x30, x29, #15"); TEST_SINGLE(addpl(XReg::rsp, XReg::rsp, -32), "addpl sp, sp, #-32"); - TEST_SINGLE(addpl(XReg::rsp, XReg::rsp, 31), "addpl sp, sp, #31"); - TEST_SINGLE(addpl(XReg::x30, XReg::x29, 15), "addpl x30, x29, #15"); + TEST_SINGLE(addpl(XReg::rsp, XReg::rsp, 31), "addpl sp, sp, #31"); + TEST_SINGLE(addpl(XReg::x30, XReg::x29, 15), "addpl x30, x29, #15"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: Streaming SVE stack frame adjustment") { // TODO: Implement in emitter. } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE stack frame size") { TEST_SINGLE(rdvl(XReg::x30, -32), "rdvl x30, #-32"); - TEST_SINGLE(rdvl(XReg::x30, 31), "rdvl x30, #31"); - TEST_SINGLE(rdvl(XReg::x30, 15), "rdvl x30, #15"); + TEST_SINGLE(rdvl(XReg::x30, 31), "rdvl x30, #31"); + TEST_SINGLE(rdvl(XReg::x30, 15), "rdvl x30, #15"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: Streaming SVE stack frame size") { // TODO: Implement in emitter. @@ -1034,60 +1001,60 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer multiply vectors TEST_SINGLE(umulh(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umulh z30.d, z29.d, z28.d"); TEST_SINGLE(pmul(ZReg::z30, ZReg::z29, ZReg::z28), "pmul z30.b, z29.b, z28.b"); - } +} TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 signed saturating doubling multiply high (unpredicated)") { - TEST_SINGLE(sqdmulh(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmulh z30.b, z29.b, z28.b"); + TEST_SINGLE(sqdmulh(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmulh z30.b, z29.b, z28.b"); TEST_SINGLE(sqdmulh(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmulh z30.h, z29.h, z28.h"); TEST_SINGLE(sqdmulh(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmulh z30.s, z29.s, z28.s"); TEST_SINGLE(sqdmulh(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmulh z30.d, z29.d, z28.d"); - TEST_SINGLE(sqrdmulh(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmulh z30.b, z29.b, z28.b"); + TEST_SINGLE(sqrdmulh(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmulh z30.b, z29.b, z28.b"); TEST_SINGLE(sqrdmulh(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmulh z30.h, z29.h, z28.h"); TEST_SINGLE(sqrdmulh(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmulh z30.s, z29.s, z28.s"); TEST_SINGLE(sqrdmulh(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmulh z30.d, z29.d, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise shift by wide elements (unpredicated)") { - TEST_SINGLE(asr_wide(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "asr z30.b, z29.b, z28.d"); + TEST_SINGLE(asr_wide(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "asr z30.b, z29.b, z28.d"); TEST_SINGLE(asr_wide(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "asr z30.h, z29.h, z28.d"); TEST_SINGLE(asr_wide(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "asr z30.s, z29.s, z28.d"); - TEST_SINGLE(lsr_wide(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsr z30.b, z29.b, z28.d"); + TEST_SINGLE(lsr_wide(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsr z30.b, z29.b, z28.d"); TEST_SINGLE(lsr_wide(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsr z30.h, z29.h, z28.d"); TEST_SINGLE(lsr_wide(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsr z30.s, z29.s, z28.d"); - TEST_SINGLE(lsl_wide(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsl z30.b, z29.b, z28.d"); + TEST_SINGLE(lsl_wide(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsl z30.b, z29.b, z28.d"); TEST_SINGLE(lsl_wide(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsl z30.h, z29.h, z28.d"); TEST_SINGLE(lsl_wide(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "lsl z30.s, z29.s, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE bitwise shift by immediate (unpredicated)") { - TEST_SINGLE(asr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "asr z30.b, z29.b, #1"); - TEST_SINGLE(asr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "asr z30.b, z29.b, #8"); - TEST_SINGLE(asr(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "asr z30.h, z29.h, #1"); + TEST_SINGLE(asr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "asr z30.b, z29.b, #1"); + TEST_SINGLE(asr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "asr z30.b, z29.b, #8"); + TEST_SINGLE(asr(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "asr z30.h, z29.h, #1"); TEST_SINGLE(asr(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "asr z30.h, z29.h, #16"); - TEST_SINGLE(asr(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "asr z30.s, z29.s, #1"); + TEST_SINGLE(asr(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "asr z30.s, z29.s, #1"); TEST_SINGLE(asr(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "asr z30.s, z29.s, #32"); - TEST_SINGLE(asr(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "asr z30.d, z29.d, #1"); + TEST_SINGLE(asr(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "asr z30.d, z29.d, #1"); TEST_SINGLE(asr(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "asr z30.d, z29.d, #64"); - TEST_SINGLE(lsr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.b, z29.b, #1"); - TEST_SINGLE(lsr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "lsr z30.b, z29.b, #8"); - TEST_SINGLE(lsr(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.h, z29.h, #1"); + TEST_SINGLE(lsr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.b, z29.b, #1"); + TEST_SINGLE(lsr(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "lsr z30.b, z29.b, #8"); + TEST_SINGLE(lsr(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.h, z29.h, #1"); TEST_SINGLE(lsr(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "lsr z30.h, z29.h, #16"); - TEST_SINGLE(lsr(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.s, z29.s, #1"); + TEST_SINGLE(lsr(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.s, z29.s, #1"); TEST_SINGLE(lsr(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "lsr z30.s, z29.s, #32"); - TEST_SINGLE(lsr(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.d, z29.d, #1"); + TEST_SINGLE(lsr(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "lsr z30.d, z29.d, #1"); TEST_SINGLE(lsr(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "lsr z30.d, z29.d, #64"); - TEST_SINGLE(lsl(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.b, z29.b, #0"); - TEST_SINGLE(lsl(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 7), "lsl z30.b, z29.b, #7"); - TEST_SINGLE(lsl(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.h, z29.h, #0"); + TEST_SINGLE(lsl(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.b, z29.b, #0"); + TEST_SINGLE(lsl(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 7), "lsl z30.b, z29.b, #7"); + TEST_SINGLE(lsl(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.h, z29.h, #0"); TEST_SINGLE(lsl(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 15), "lsl z30.h, z29.h, #15"); - TEST_SINGLE(lsl(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.s, z29.s, #0"); + TEST_SINGLE(lsl(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.s, z29.s, #0"); TEST_SINGLE(lsl(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 31), "lsl z30.s, z29.s, #31"); - TEST_SINGLE(lsl(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.d, z29.d, #0"); + TEST_SINGLE(lsl(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "lsl z30.d, z29.d, #0"); TEST_SINGLE(lsl(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 63), "lsl z30.d, z29.d, #63"); } @@ -1106,261 +1073,261 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE constructive prefix (unpre } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE saturating inc/dec vector by element count") { - TEST_SINGLE(sqinch(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "sqinch z30.h, pow2"); - TEST_SINGLE(sqinch(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqinch z30.h, vl256, mul #7"); - TEST_SINGLE(sqinch(ZReg::z30, PredicatePattern::SVE_ALL , 16), "sqinch z30.h, all, mul #16"); + TEST_SINGLE(sqinch(ZReg::z30, PredicatePattern::SVE_POW2, 1), "sqinch z30.h, pow2"); + TEST_SINGLE(sqinch(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqinch z30.h, vl256, mul #7"); + TEST_SINGLE(sqinch(ZReg::z30, PredicatePattern::SVE_ALL, 16), "sqinch z30.h, all, mul #16"); - TEST_SINGLE(uqinch(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "uqinch z30.h, pow2"); - TEST_SINGLE(uqinch(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqinch z30.h, vl256, mul #7"); - TEST_SINGLE(uqinch(ZReg::z30, PredicatePattern::SVE_ALL , 16), "uqinch z30.h, all, mul #16"); + TEST_SINGLE(uqinch(ZReg::z30, PredicatePattern::SVE_POW2, 1), "uqinch z30.h, pow2"); + TEST_SINGLE(uqinch(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqinch z30.h, vl256, mul #7"); + TEST_SINGLE(uqinch(ZReg::z30, PredicatePattern::SVE_ALL, 16), "uqinch z30.h, all, mul #16"); - TEST_SINGLE(sqdech(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "sqdech z30.h, pow2"); - TEST_SINGLE(sqdech(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqdech z30.h, vl256, mul #7"); - TEST_SINGLE(sqdech(ZReg::z30, PredicatePattern::SVE_ALL , 16), "sqdech z30.h, all, mul #16"); + TEST_SINGLE(sqdech(ZReg::z30, PredicatePattern::SVE_POW2, 1), "sqdech z30.h, pow2"); + TEST_SINGLE(sqdech(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqdech z30.h, vl256, mul #7"); + TEST_SINGLE(sqdech(ZReg::z30, PredicatePattern::SVE_ALL, 16), "sqdech z30.h, all, mul #16"); - TEST_SINGLE(uqdech(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "uqdech z30.h, pow2"); - TEST_SINGLE(uqdech(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqdech z30.h, vl256, mul #7"); - TEST_SINGLE(uqdech(ZReg::z30, PredicatePattern::SVE_ALL , 16), "uqdech z30.h, all, mul #16"); + TEST_SINGLE(uqdech(ZReg::z30, PredicatePattern::SVE_POW2, 1), "uqdech z30.h, pow2"); + TEST_SINGLE(uqdech(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqdech z30.h, vl256, mul #7"); + TEST_SINGLE(uqdech(ZReg::z30, PredicatePattern::SVE_ALL, 16), "uqdech z30.h, all, mul #16"); - TEST_SINGLE(sqincw(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "sqincw z30.s, pow2"); - TEST_SINGLE(sqincw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqincw z30.s, vl256, mul #7"); - TEST_SINGLE(sqincw(ZReg::z30, PredicatePattern::SVE_ALL , 16), "sqincw z30.s, all, mul #16"); + TEST_SINGLE(sqincw(ZReg::z30, PredicatePattern::SVE_POW2, 1), "sqincw z30.s, pow2"); + TEST_SINGLE(sqincw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqincw z30.s, vl256, mul #7"); + TEST_SINGLE(sqincw(ZReg::z30, PredicatePattern::SVE_ALL, 16), "sqincw z30.s, all, mul #16"); - TEST_SINGLE(uqincw(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "uqincw z30.s, pow2"); - TEST_SINGLE(uqincw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqincw z30.s, vl256, mul #7"); - TEST_SINGLE(uqincw(ZReg::z30, PredicatePattern::SVE_ALL , 16), "uqincw z30.s, all, mul #16"); + TEST_SINGLE(uqincw(ZReg::z30, PredicatePattern::SVE_POW2, 1), "uqincw z30.s, pow2"); + TEST_SINGLE(uqincw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqincw z30.s, vl256, mul #7"); + TEST_SINGLE(uqincw(ZReg::z30, PredicatePattern::SVE_ALL, 16), "uqincw z30.s, all, mul #16"); - TEST_SINGLE(sqdecw(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "sqdecw z30.s, pow2"); - TEST_SINGLE(sqdecw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqdecw z30.s, vl256, mul #7"); - TEST_SINGLE(sqdecw(ZReg::z30, PredicatePattern::SVE_ALL , 16), "sqdecw z30.s, all, mul #16"); + TEST_SINGLE(sqdecw(ZReg::z30, PredicatePattern::SVE_POW2, 1), "sqdecw z30.s, pow2"); + TEST_SINGLE(sqdecw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqdecw z30.s, vl256, mul #7"); + TEST_SINGLE(sqdecw(ZReg::z30, PredicatePattern::SVE_ALL, 16), "sqdecw z30.s, all, mul #16"); - TEST_SINGLE(uqdecw(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "uqdecw z30.s, pow2"); - TEST_SINGLE(uqdecw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqdecw z30.s, vl256, mul #7"); - TEST_SINGLE(uqdecw(ZReg::z30, PredicatePattern::SVE_ALL , 16), "uqdecw z30.s, all, mul #16"); + TEST_SINGLE(uqdecw(ZReg::z30, PredicatePattern::SVE_POW2, 1), "uqdecw z30.s, pow2"); + TEST_SINGLE(uqdecw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqdecw z30.s, vl256, mul #7"); + TEST_SINGLE(uqdecw(ZReg::z30, PredicatePattern::SVE_ALL, 16), "uqdecw z30.s, all, mul #16"); - TEST_SINGLE(sqincd(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "sqincd z30.d, pow2"); - TEST_SINGLE(sqincd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqincd z30.d, vl256, mul #7"); - TEST_SINGLE(sqincd(ZReg::z30, PredicatePattern::SVE_ALL , 16), "sqincd z30.d, all, mul #16"); + TEST_SINGLE(sqincd(ZReg::z30, PredicatePattern::SVE_POW2, 1), "sqincd z30.d, pow2"); + TEST_SINGLE(sqincd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqincd z30.d, vl256, mul #7"); + TEST_SINGLE(sqincd(ZReg::z30, PredicatePattern::SVE_ALL, 16), "sqincd z30.d, all, mul #16"); - TEST_SINGLE(uqincd(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "uqincd z30.d, pow2"); - TEST_SINGLE(uqincd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqincd z30.d, vl256, mul #7"); - TEST_SINGLE(uqincd(ZReg::z30, PredicatePattern::SVE_ALL , 16), "uqincd z30.d, all, mul #16"); + TEST_SINGLE(uqincd(ZReg::z30, PredicatePattern::SVE_POW2, 1), "uqincd z30.d, pow2"); + TEST_SINGLE(uqincd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqincd z30.d, vl256, mul #7"); + TEST_SINGLE(uqincd(ZReg::z30, PredicatePattern::SVE_ALL, 16), "uqincd z30.d, all, mul #16"); - TEST_SINGLE(sqdecd(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "sqdecd z30.d, pow2"); - TEST_SINGLE(sqdecd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqdecd z30.d, vl256, mul #7"); - TEST_SINGLE(sqdecd(ZReg::z30, PredicatePattern::SVE_ALL , 16), "sqdecd z30.d, all, mul #16"); + TEST_SINGLE(sqdecd(ZReg::z30, PredicatePattern::SVE_POW2, 1), "sqdecd z30.d, pow2"); + TEST_SINGLE(sqdecd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "sqdecd z30.d, vl256, mul #7"); + TEST_SINGLE(sqdecd(ZReg::z30, PredicatePattern::SVE_ALL, 16), "sqdecd z30.d, all, mul #16"); - TEST_SINGLE(uqdecd(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "uqdecd z30.d, pow2"); - TEST_SINGLE(uqdecd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqdecd z30.d, vl256, mul #7"); - TEST_SINGLE(uqdecd(ZReg::z30, PredicatePattern::SVE_ALL , 16), "uqdecd z30.d, all, mul #16"); + TEST_SINGLE(uqdecd(ZReg::z30, PredicatePattern::SVE_POW2, 1), "uqdecd z30.d, pow2"); + TEST_SINGLE(uqdecd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "uqdecd z30.d, vl256, mul #7"); + TEST_SINGLE(uqdecd(ZReg::z30, PredicatePattern::SVE_ALL, 16), "uqdecd z30.d, all, mul #16"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE element count") { - TEST_SINGLE(cntb(XReg::x30, PredicatePattern::SVE_POW2 , 1), "cntb x30, pow2"); - TEST_SINGLE(cntb(XReg::x30, PredicatePattern::SVE_VL256, 7), "cntb x30, vl256, mul #7"); - TEST_SINGLE(cntb(XReg::x30, PredicatePattern::SVE_ALL , 16), "cntb x30, all, mul #16"); + TEST_SINGLE(cntb(XReg::x30, PredicatePattern::SVE_POW2, 1), "cntb x30, pow2"); + TEST_SINGLE(cntb(XReg::x30, PredicatePattern::SVE_VL256, 7), "cntb x30, vl256, mul #7"); + TEST_SINGLE(cntb(XReg::x30, PredicatePattern::SVE_ALL, 16), "cntb x30, all, mul #16"); - TEST_SINGLE(cnth(XReg::x30, PredicatePattern::SVE_POW2 , 1), "cnth x30, pow2"); - TEST_SINGLE(cnth(XReg::x30, PredicatePattern::SVE_VL256, 7), "cnth x30, vl256, mul #7"); - TEST_SINGLE(cnth(XReg::x30, PredicatePattern::SVE_ALL , 16), "cnth x30, all, mul #16"); + TEST_SINGLE(cnth(XReg::x30, PredicatePattern::SVE_POW2, 1), "cnth x30, pow2"); + TEST_SINGLE(cnth(XReg::x30, PredicatePattern::SVE_VL256, 7), "cnth x30, vl256, mul #7"); + TEST_SINGLE(cnth(XReg::x30, PredicatePattern::SVE_ALL, 16), "cnth x30, all, mul #16"); - TEST_SINGLE(cntw(XReg::x30, PredicatePattern::SVE_POW2 , 1), "cntw x30, pow2"); - TEST_SINGLE(cntw(XReg::x30, PredicatePattern::SVE_VL256, 7), "cntw x30, vl256, mul #7"); - TEST_SINGLE(cntw(XReg::x30, PredicatePattern::SVE_ALL , 16), "cntw x30, all, mul #16"); + TEST_SINGLE(cntw(XReg::x30, PredicatePattern::SVE_POW2, 1), "cntw x30, pow2"); + TEST_SINGLE(cntw(XReg::x30, PredicatePattern::SVE_VL256, 7), "cntw x30, vl256, mul #7"); + TEST_SINGLE(cntw(XReg::x30, PredicatePattern::SVE_ALL, 16), "cntw x30, all, mul #16"); - TEST_SINGLE(cntd(XReg::x30, PredicatePattern::SVE_POW2 , 1), "cntd x30, pow2"); - TEST_SINGLE(cntd(XReg::x30, PredicatePattern::SVE_VL256, 7), "cntd x30, vl256, mul #7"); - TEST_SINGLE(cntd(XReg::x30, PredicatePattern::SVE_ALL , 16), "cntd x30, all, mul #16"); + TEST_SINGLE(cntd(XReg::x30, PredicatePattern::SVE_POW2, 1), "cntd x30, pow2"); + TEST_SINGLE(cntd(XReg::x30, PredicatePattern::SVE_VL256, 7), "cntd x30, vl256, mul #7"); + TEST_SINGLE(cntd(XReg::x30, PredicatePattern::SVE_ALL, 16), "cntd x30, all, mul #16"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE inc/dec vector by element count") { - TEST_SINGLE(inch(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "inch z30.h, pow2"); - TEST_SINGLE(inch(ZReg::z30, PredicatePattern::SVE_VL256, 7), "inch z30.h, vl256, mul #7"); - TEST_SINGLE(inch(ZReg::z30, PredicatePattern::SVE_ALL , 16), "inch z30.h, all, mul #16"); + TEST_SINGLE(inch(ZReg::z30, PredicatePattern::SVE_POW2, 1), "inch z30.h, pow2"); + TEST_SINGLE(inch(ZReg::z30, PredicatePattern::SVE_VL256, 7), "inch z30.h, vl256, mul #7"); + TEST_SINGLE(inch(ZReg::z30, PredicatePattern::SVE_ALL, 16), "inch z30.h, all, mul #16"); - TEST_SINGLE(dech(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "dech z30.h, pow2"); - TEST_SINGLE(dech(ZReg::z30, PredicatePattern::SVE_VL256, 7), "dech z30.h, vl256, mul #7"); - TEST_SINGLE(dech(ZReg::z30, PredicatePattern::SVE_ALL , 16), "dech z30.h, all, mul #16"); + TEST_SINGLE(dech(ZReg::z30, PredicatePattern::SVE_POW2, 1), "dech z30.h, pow2"); + TEST_SINGLE(dech(ZReg::z30, PredicatePattern::SVE_VL256, 7), "dech z30.h, vl256, mul #7"); + TEST_SINGLE(dech(ZReg::z30, PredicatePattern::SVE_ALL, 16), "dech z30.h, all, mul #16"); - TEST_SINGLE(incw(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "incw z30.s, pow2"); - TEST_SINGLE(incw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "incw z30.s, vl256, mul #7"); - TEST_SINGLE(incw(ZReg::z30, PredicatePattern::SVE_ALL , 16), "incw z30.s, all, mul #16"); + TEST_SINGLE(incw(ZReg::z30, PredicatePattern::SVE_POW2, 1), "incw z30.s, pow2"); + TEST_SINGLE(incw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "incw z30.s, vl256, mul #7"); + TEST_SINGLE(incw(ZReg::z30, PredicatePattern::SVE_ALL, 16), "incw z30.s, all, mul #16"); - TEST_SINGLE(decw(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "decw z30.s, pow2"); - TEST_SINGLE(decw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "decw z30.s, vl256, mul #7"); - TEST_SINGLE(decw(ZReg::z30, PredicatePattern::SVE_ALL , 16), "decw z30.s, all, mul #16"); + TEST_SINGLE(decw(ZReg::z30, PredicatePattern::SVE_POW2, 1), "decw z30.s, pow2"); + TEST_SINGLE(decw(ZReg::z30, PredicatePattern::SVE_VL256, 7), "decw z30.s, vl256, mul #7"); + TEST_SINGLE(decw(ZReg::z30, PredicatePattern::SVE_ALL, 16), "decw z30.s, all, mul #16"); - TEST_SINGLE(incd(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "incd z30.d, pow2"); - TEST_SINGLE(incd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "incd z30.d, vl256, mul #7"); - TEST_SINGLE(incd(ZReg::z30, PredicatePattern::SVE_ALL , 16), "incd z30.d, all, mul #16"); + TEST_SINGLE(incd(ZReg::z30, PredicatePattern::SVE_POW2, 1), "incd z30.d, pow2"); + TEST_SINGLE(incd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "incd z30.d, vl256, mul #7"); + TEST_SINGLE(incd(ZReg::z30, PredicatePattern::SVE_ALL, 16), "incd z30.d, all, mul #16"); - TEST_SINGLE(decd(ZReg::z30, PredicatePattern::SVE_POW2 , 1), "decd z30.d, pow2"); - TEST_SINGLE(decd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "decd z30.d, vl256, mul #7"); - TEST_SINGLE(decd(ZReg::z30, PredicatePattern::SVE_ALL , 16), "decd z30.d, all, mul #16"); + TEST_SINGLE(decd(ZReg::z30, PredicatePattern::SVE_POW2, 1), "decd z30.d, pow2"); + TEST_SINGLE(decd(ZReg::z30, PredicatePattern::SVE_VL256, 7), "decd z30.d, vl256, mul #7"); + TEST_SINGLE(decd(ZReg::z30, PredicatePattern::SVE_ALL, 16), "decd z30.d, all, mul #16"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE inc/dec register by element count") { - TEST_SINGLE(incb(XReg::x30, PredicatePattern::SVE_POW2 , 1), "incb x30, pow2"); - TEST_SINGLE(incb(XReg::x30, PredicatePattern::SVE_VL256, 7), "incb x30, vl256, mul #7"); - TEST_SINGLE(incb(XReg::x30, PredicatePattern::SVE_ALL , 16), "incb x30, all, mul #16"); + TEST_SINGLE(incb(XReg::x30, PredicatePattern::SVE_POW2, 1), "incb x30, pow2"); + TEST_SINGLE(incb(XReg::x30, PredicatePattern::SVE_VL256, 7), "incb x30, vl256, mul #7"); + TEST_SINGLE(incb(XReg::x30, PredicatePattern::SVE_ALL, 16), "incb x30, all, mul #16"); - TEST_SINGLE(decb(XReg::x30, PredicatePattern::SVE_POW2 , 1), "decb x30, pow2"); - TEST_SINGLE(decb(XReg::x30, PredicatePattern::SVE_VL256, 7), "decb x30, vl256, mul #7"); - TEST_SINGLE(decb(XReg::x30, PredicatePattern::SVE_ALL , 16), "decb x30, all, mul #16"); + TEST_SINGLE(decb(XReg::x30, PredicatePattern::SVE_POW2, 1), "decb x30, pow2"); + TEST_SINGLE(decb(XReg::x30, PredicatePattern::SVE_VL256, 7), "decb x30, vl256, mul #7"); + TEST_SINGLE(decb(XReg::x30, PredicatePattern::SVE_ALL, 16), "decb x30, all, mul #16"); - TEST_SINGLE(inch(XReg::x30, PredicatePattern::SVE_POW2 , 1), "inch x30, pow2"); - TEST_SINGLE(inch(XReg::x30, PredicatePattern::SVE_VL256, 7), "inch x30, vl256, mul #7"); - TEST_SINGLE(inch(XReg::x30, PredicatePattern::SVE_ALL , 16), "inch x30, all, mul #16"); + TEST_SINGLE(inch(XReg::x30, PredicatePattern::SVE_POW2, 1), "inch x30, pow2"); + TEST_SINGLE(inch(XReg::x30, PredicatePattern::SVE_VL256, 7), "inch x30, vl256, mul #7"); + TEST_SINGLE(inch(XReg::x30, PredicatePattern::SVE_ALL, 16), "inch x30, all, mul #16"); - TEST_SINGLE(dech(XReg::x30, PredicatePattern::SVE_POW2 , 1), "dech x30, pow2"); - TEST_SINGLE(dech(XReg::x30, PredicatePattern::SVE_VL256, 7), "dech x30, vl256, mul #7"); - TEST_SINGLE(dech(XReg::x30, PredicatePattern::SVE_ALL , 16), "dech x30, all, mul #16"); + TEST_SINGLE(dech(XReg::x30, PredicatePattern::SVE_POW2, 1), "dech x30, pow2"); + TEST_SINGLE(dech(XReg::x30, PredicatePattern::SVE_VL256, 7), "dech x30, vl256, mul #7"); + TEST_SINGLE(dech(XReg::x30, PredicatePattern::SVE_ALL, 16), "dech x30, all, mul #16"); - TEST_SINGLE(incw(XReg::x30, PredicatePattern::SVE_POW2 , 1), "incw x30, pow2"); - TEST_SINGLE(incw(XReg::x30, PredicatePattern::SVE_VL256, 7), "incw x30, vl256, mul #7"); - TEST_SINGLE(incw(XReg::x30, PredicatePattern::SVE_ALL , 16), "incw x30, all, mul #16"); + TEST_SINGLE(incw(XReg::x30, PredicatePattern::SVE_POW2, 1), "incw x30, pow2"); + TEST_SINGLE(incw(XReg::x30, PredicatePattern::SVE_VL256, 7), "incw x30, vl256, mul #7"); + TEST_SINGLE(incw(XReg::x30, PredicatePattern::SVE_ALL, 16), "incw x30, all, mul #16"); - TEST_SINGLE(decw(XReg::x30, PredicatePattern::SVE_POW2 , 1), "decw x30, pow2"); - TEST_SINGLE(decw(XReg::x30, PredicatePattern::SVE_VL256, 7), "decw x30, vl256, mul #7"); - TEST_SINGLE(decw(XReg::x30, PredicatePattern::SVE_ALL , 16), "decw x30, all, mul #16"); + TEST_SINGLE(decw(XReg::x30, PredicatePattern::SVE_POW2, 1), "decw x30, pow2"); + TEST_SINGLE(decw(XReg::x30, PredicatePattern::SVE_VL256, 7), "decw x30, vl256, mul #7"); + TEST_SINGLE(decw(XReg::x30, PredicatePattern::SVE_ALL, 16), "decw x30, all, mul #16"); - TEST_SINGLE(incd(XReg::x30, PredicatePattern::SVE_POW2 , 1), "incd x30, pow2"); - TEST_SINGLE(incd(XReg::x30, PredicatePattern::SVE_VL256, 7), "incd x30, vl256, mul #7"); - TEST_SINGLE(incd(XReg::x30, PredicatePattern::SVE_ALL , 16), "incd x30, all, mul #16"); + TEST_SINGLE(incd(XReg::x30, PredicatePattern::SVE_POW2, 1), "incd x30, pow2"); + TEST_SINGLE(incd(XReg::x30, PredicatePattern::SVE_VL256, 7), "incd x30, vl256, mul #7"); + TEST_SINGLE(incd(XReg::x30, PredicatePattern::SVE_ALL, 16), "incd x30, all, mul #16"); - TEST_SINGLE(decd(XReg::x30, PredicatePattern::SVE_POW2 , 1), "decd x30, pow2"); - TEST_SINGLE(decd(XReg::x30, PredicatePattern::SVE_VL256, 7), "decd x30, vl256, mul #7"); - TEST_SINGLE(decd(XReg::x30, PredicatePattern::SVE_ALL , 16), "decd x30, all, mul #16"); + TEST_SINGLE(decd(XReg::x30, PredicatePattern::SVE_POW2, 1), "decd x30, pow2"); + TEST_SINGLE(decd(XReg::x30, PredicatePattern::SVE_VL256, 7), "decd x30, vl256, mul #7"); + TEST_SINGLE(decd(XReg::x30, PredicatePattern::SVE_ALL, 16), "decd x30, all, mul #16"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE saturating inc/dec register by element count") { - TEST_SINGLE(sqincb(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqincb x30, pow2"); - TEST_SINGLE(sqincb(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqincb x30, vl256, mul #7"); - TEST_SINGLE(sqincb(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqincb x30, all, mul #16"); + TEST_SINGLE(sqincb(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqincb x30, pow2"); + TEST_SINGLE(sqincb(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqincb x30, vl256, mul #7"); + TEST_SINGLE(sqincb(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqincb x30, all, mul #16"); - TEST_SINGLE(sqincb(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqincb x30, w30, pow2"); - TEST_SINGLE(sqincb(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqincb x30, w30, vl256, mul #7"); - TEST_SINGLE(sqincb(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqincb x30, w30, all, mul #16"); + TEST_SINGLE(sqincb(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqincb x30, w30, pow2"); + TEST_SINGLE(sqincb(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqincb x30, w30, vl256, mul #7"); + TEST_SINGLE(sqincb(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqincb x30, w30, all, mul #16"); - TEST_SINGLE(uqincb(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqincb x30, pow2"); - TEST_SINGLE(uqincb(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqincb x30, vl256, mul #7"); - TEST_SINGLE(uqincb(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqincb x30, all, mul #16"); + TEST_SINGLE(uqincb(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqincb x30, pow2"); + TEST_SINGLE(uqincb(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqincb x30, vl256, mul #7"); + TEST_SINGLE(uqincb(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqincb x30, all, mul #16"); - TEST_SINGLE(uqincb(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqincb w30, pow2"); - TEST_SINGLE(uqincb(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqincb w30, vl256, mul #7"); - TEST_SINGLE(uqincb(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqincb w30, all, mul #16"); + TEST_SINGLE(uqincb(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqincb w30, pow2"); + TEST_SINGLE(uqincb(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqincb w30, vl256, mul #7"); + TEST_SINGLE(uqincb(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqincb w30, all, mul #16"); - TEST_SINGLE(sqdecb(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqdecb x30, pow2"); - TEST_SINGLE(sqdecb(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdecb x30, vl256, mul #7"); - TEST_SINGLE(sqdecb(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqdecb x30, all, mul #16"); + TEST_SINGLE(sqdecb(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqdecb x30, pow2"); + TEST_SINGLE(sqdecb(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdecb x30, vl256, mul #7"); + TEST_SINGLE(sqdecb(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqdecb x30, all, mul #16"); - TEST_SINGLE(sqdecb(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqdecb x30, w30, pow2"); - TEST_SINGLE(sqdecb(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdecb x30, w30, vl256, mul #7"); - TEST_SINGLE(sqdecb(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqdecb x30, w30, all, mul #16"); + TEST_SINGLE(sqdecb(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqdecb x30, w30, pow2"); + TEST_SINGLE(sqdecb(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdecb x30, w30, vl256, mul #7"); + TEST_SINGLE(sqdecb(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqdecb x30, w30, all, mul #16"); - TEST_SINGLE(uqdecb(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqdecb x30, pow2"); - TEST_SINGLE(uqdecb(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdecb x30, vl256, mul #7"); - TEST_SINGLE(uqdecb(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqdecb x30, all, mul #16"); + TEST_SINGLE(uqdecb(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqdecb x30, pow2"); + TEST_SINGLE(uqdecb(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdecb x30, vl256, mul #7"); + TEST_SINGLE(uqdecb(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqdecb x30, all, mul #16"); - TEST_SINGLE(uqdecb(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqdecb w30, pow2"); - TEST_SINGLE(uqdecb(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdecb w30, vl256, mul #7"); - TEST_SINGLE(uqdecb(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqdecb w30, all, mul #16"); + TEST_SINGLE(uqdecb(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqdecb w30, pow2"); + TEST_SINGLE(uqdecb(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdecb w30, vl256, mul #7"); + TEST_SINGLE(uqdecb(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqdecb w30, all, mul #16"); - TEST_SINGLE(sqinch(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqinch x30, pow2"); - TEST_SINGLE(sqinch(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqinch x30, vl256, mul #7"); - TEST_SINGLE(sqinch(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqinch x30, all, mul #16"); + TEST_SINGLE(sqinch(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqinch x30, pow2"); + TEST_SINGLE(sqinch(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqinch x30, vl256, mul #7"); + TEST_SINGLE(sqinch(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqinch x30, all, mul #16"); - TEST_SINGLE(sqinch(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqinch x30, w30, pow2"); - TEST_SINGLE(sqinch(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqinch x30, w30, vl256, mul #7"); - TEST_SINGLE(sqinch(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqinch x30, w30, all, mul #16"); + TEST_SINGLE(sqinch(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqinch x30, w30, pow2"); + TEST_SINGLE(sqinch(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqinch x30, w30, vl256, mul #7"); + TEST_SINGLE(sqinch(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqinch x30, w30, all, mul #16"); - TEST_SINGLE(uqinch(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqinch x30, pow2"); - TEST_SINGLE(uqinch(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqinch x30, vl256, mul #7"); - TEST_SINGLE(uqinch(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqinch x30, all, mul #16"); + TEST_SINGLE(uqinch(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqinch x30, pow2"); + TEST_SINGLE(uqinch(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqinch x30, vl256, mul #7"); + TEST_SINGLE(uqinch(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqinch x30, all, mul #16"); - TEST_SINGLE(uqinch(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqinch w30, pow2"); - TEST_SINGLE(uqinch(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqinch w30, vl256, mul #7"); - TEST_SINGLE(uqinch(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqinch w30, all, mul #16"); + TEST_SINGLE(uqinch(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqinch w30, pow2"); + TEST_SINGLE(uqinch(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqinch w30, vl256, mul #7"); + TEST_SINGLE(uqinch(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqinch w30, all, mul #16"); - TEST_SINGLE(sqdech(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqdech x30, pow2"); - TEST_SINGLE(sqdech(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdech x30, vl256, mul #7"); - TEST_SINGLE(sqdech(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqdech x30, all, mul #16"); + TEST_SINGLE(sqdech(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqdech x30, pow2"); + TEST_SINGLE(sqdech(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdech x30, vl256, mul #7"); + TEST_SINGLE(sqdech(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqdech x30, all, mul #16"); - TEST_SINGLE(sqdech(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqdech x30, w30, pow2"); - TEST_SINGLE(sqdech(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdech x30, w30, vl256, mul #7"); - TEST_SINGLE(sqdech(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqdech x30, w30, all, mul #16"); + TEST_SINGLE(sqdech(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqdech x30, w30, pow2"); + TEST_SINGLE(sqdech(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdech x30, w30, vl256, mul #7"); + TEST_SINGLE(sqdech(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqdech x30, w30, all, mul #16"); - TEST_SINGLE(uqdech(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqdech x30, pow2"); - TEST_SINGLE(uqdech(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdech x30, vl256, mul #7"); - TEST_SINGLE(uqdech(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqdech x30, all, mul #16"); + TEST_SINGLE(uqdech(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqdech x30, pow2"); + TEST_SINGLE(uqdech(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdech x30, vl256, mul #7"); + TEST_SINGLE(uqdech(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqdech x30, all, mul #16"); - TEST_SINGLE(uqdech(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqdech w30, pow2"); - TEST_SINGLE(uqdech(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdech w30, vl256, mul #7"); - TEST_SINGLE(uqdech(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqdech w30, all, mul #16"); + TEST_SINGLE(uqdech(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqdech w30, pow2"); + TEST_SINGLE(uqdech(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdech w30, vl256, mul #7"); + TEST_SINGLE(uqdech(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqdech w30, all, mul #16"); - TEST_SINGLE(sqincw(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqincw x30, pow2"); - TEST_SINGLE(sqincw(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqincw x30, vl256, mul #7"); - TEST_SINGLE(sqincw(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqincw x30, all, mul #16"); + TEST_SINGLE(sqincw(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqincw x30, pow2"); + TEST_SINGLE(sqincw(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqincw x30, vl256, mul #7"); + TEST_SINGLE(sqincw(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqincw x30, all, mul #16"); - TEST_SINGLE(sqincw(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqincw x30, w30, pow2"); - TEST_SINGLE(sqincw(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqincw x30, w30, vl256, mul #7"); - TEST_SINGLE(sqincw(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqincw x30, w30, all, mul #16"); + TEST_SINGLE(sqincw(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqincw x30, w30, pow2"); + TEST_SINGLE(sqincw(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqincw x30, w30, vl256, mul #7"); + TEST_SINGLE(sqincw(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqincw x30, w30, all, mul #16"); - TEST_SINGLE(uqincw(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqincw x30, pow2"); - TEST_SINGLE(uqincw(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqincw x30, vl256, mul #7"); - TEST_SINGLE(uqincw(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqincw x30, all, mul #16"); + TEST_SINGLE(uqincw(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqincw x30, pow2"); + TEST_SINGLE(uqincw(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqincw x30, vl256, mul #7"); + TEST_SINGLE(uqincw(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqincw x30, all, mul #16"); - TEST_SINGLE(uqincw(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqincw w30, pow2"); - TEST_SINGLE(uqincw(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqincw w30, vl256, mul #7"); - TEST_SINGLE(uqincw(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqincw w30, all, mul #16"); + TEST_SINGLE(uqincw(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqincw w30, pow2"); + TEST_SINGLE(uqincw(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqincw w30, vl256, mul #7"); + TEST_SINGLE(uqincw(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqincw w30, all, mul #16"); - TEST_SINGLE(sqdecw(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqdecw x30, pow2"); - TEST_SINGLE(sqdecw(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdecw x30, vl256, mul #7"); - TEST_SINGLE(sqdecw(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqdecw x30, all, mul #16"); + TEST_SINGLE(sqdecw(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqdecw x30, pow2"); + TEST_SINGLE(sqdecw(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdecw x30, vl256, mul #7"); + TEST_SINGLE(sqdecw(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqdecw x30, all, mul #16"); - TEST_SINGLE(sqdecw(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqdecw x30, w30, pow2"); - TEST_SINGLE(sqdecw(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdecw x30, w30, vl256, mul #7"); - TEST_SINGLE(sqdecw(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqdecw x30, w30, all, mul #16"); + TEST_SINGLE(sqdecw(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqdecw x30, w30, pow2"); + TEST_SINGLE(sqdecw(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdecw x30, w30, vl256, mul #7"); + TEST_SINGLE(sqdecw(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqdecw x30, w30, all, mul #16"); - TEST_SINGLE(uqdecw(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqdecw x30, pow2"); - TEST_SINGLE(uqdecw(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdecw x30, vl256, mul #7"); - TEST_SINGLE(uqdecw(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqdecw x30, all, mul #16"); + TEST_SINGLE(uqdecw(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqdecw x30, pow2"); + TEST_SINGLE(uqdecw(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdecw x30, vl256, mul #7"); + TEST_SINGLE(uqdecw(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqdecw x30, all, mul #16"); - TEST_SINGLE(uqdecw(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqdecw w30, pow2"); - TEST_SINGLE(uqdecw(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdecw w30, vl256, mul #7"); - TEST_SINGLE(uqdecw(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqdecw w30, all, mul #16"); + TEST_SINGLE(uqdecw(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqdecw w30, pow2"); + TEST_SINGLE(uqdecw(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdecw w30, vl256, mul #7"); + TEST_SINGLE(uqdecw(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqdecw w30, all, mul #16"); - TEST_SINGLE(sqincd(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqincd x30, pow2"); - TEST_SINGLE(sqincd(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqincd x30, vl256, mul #7"); - TEST_SINGLE(sqincd(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqincd x30, all, mul #16"); + TEST_SINGLE(sqincd(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqincd x30, pow2"); + TEST_SINGLE(sqincd(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqincd x30, vl256, mul #7"); + TEST_SINGLE(sqincd(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqincd x30, all, mul #16"); - TEST_SINGLE(sqincd(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqincd x30, w30, pow2"); - TEST_SINGLE(sqincd(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqincd x30, w30, vl256, mul #7"); - TEST_SINGLE(sqincd(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqincd x30, w30, all, mul #16"); + TEST_SINGLE(sqincd(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqincd x30, w30, pow2"); + TEST_SINGLE(sqincd(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqincd x30, w30, vl256, mul #7"); + TEST_SINGLE(sqincd(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqincd x30, w30, all, mul #16"); - TEST_SINGLE(uqincd(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqincd x30, pow2"); - TEST_SINGLE(uqincd(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqincd x30, vl256, mul #7"); - TEST_SINGLE(uqincd(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqincd x30, all, mul #16"); + TEST_SINGLE(uqincd(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqincd x30, pow2"); + TEST_SINGLE(uqincd(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqincd x30, vl256, mul #7"); + TEST_SINGLE(uqincd(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqincd x30, all, mul #16"); - TEST_SINGLE(uqincd(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqincd w30, pow2"); - TEST_SINGLE(uqincd(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqincd w30, vl256, mul #7"); - TEST_SINGLE(uqincd(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqincd w30, all, mul #16"); + TEST_SINGLE(uqincd(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqincd w30, pow2"); + TEST_SINGLE(uqincd(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqincd w30, vl256, mul #7"); + TEST_SINGLE(uqincd(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqincd w30, all, mul #16"); - TEST_SINGLE(sqdecd(XReg::x30, PredicatePattern::SVE_POW2 , 1), "sqdecd x30, pow2"); - TEST_SINGLE(sqdecd(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdecd x30, vl256, mul #7"); - TEST_SINGLE(sqdecd(XReg::x30, PredicatePattern::SVE_ALL , 16), "sqdecd x30, all, mul #16"); + TEST_SINGLE(sqdecd(XReg::x30, PredicatePattern::SVE_POW2, 1), "sqdecd x30, pow2"); + TEST_SINGLE(sqdecd(XReg::x30, PredicatePattern::SVE_VL256, 7), "sqdecd x30, vl256, mul #7"); + TEST_SINGLE(sqdecd(XReg::x30, PredicatePattern::SVE_ALL, 16), "sqdecd x30, all, mul #16"); - TEST_SINGLE(sqdecd(WReg::w30, PredicatePattern::SVE_POW2 , 1), "sqdecd x30, w30, pow2"); - TEST_SINGLE(sqdecd(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdecd x30, w30, vl256, mul #7"); - TEST_SINGLE(sqdecd(WReg::w30, PredicatePattern::SVE_ALL , 16), "sqdecd x30, w30, all, mul #16"); + TEST_SINGLE(sqdecd(WReg::w30, PredicatePattern::SVE_POW2, 1), "sqdecd x30, w30, pow2"); + TEST_SINGLE(sqdecd(WReg::w30, PredicatePattern::SVE_VL256, 7), "sqdecd x30, w30, vl256, mul #7"); + TEST_SINGLE(sqdecd(WReg::w30, PredicatePattern::SVE_ALL, 16), "sqdecd x30, w30, all, mul #16"); - TEST_SINGLE(uqdecd(XReg::x30, PredicatePattern::SVE_POW2 , 1), "uqdecd x30, pow2"); - TEST_SINGLE(uqdecd(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdecd x30, vl256, mul #7"); - TEST_SINGLE(uqdecd(XReg::x30, PredicatePattern::SVE_ALL , 16), "uqdecd x30, all, mul #16"); + TEST_SINGLE(uqdecd(XReg::x30, PredicatePattern::SVE_POW2, 1), "uqdecd x30, pow2"); + TEST_SINGLE(uqdecd(XReg::x30, PredicatePattern::SVE_VL256, 7), "uqdecd x30, vl256, mul #7"); + TEST_SINGLE(uqdecd(XReg::x30, PredicatePattern::SVE_ALL, 16), "uqdecd x30, all, mul #16"); - TEST_SINGLE(uqdecd(WReg::w30, PredicatePattern::SVE_POW2 , 1), "uqdecd w30, pow2"); - TEST_SINGLE(uqdecd(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdecd w30, vl256, mul #7"); - TEST_SINGLE(uqdecd(WReg::w30, PredicatePattern::SVE_ALL , 16), "uqdecd w30, all, mul #16"); + TEST_SINGLE(uqdecd(WReg::w30, PredicatePattern::SVE_POW2, 1), "uqdecd w30, pow2"); + TEST_SINGLE(uqdecd(WReg::w30, PredicatePattern::SVE_VL256, 7), "uqdecd w30, vl256, mul #7"); + TEST_SINGLE(uqdecd(WReg::w30, PredicatePattern::SVE_ALL, 16), "uqdecd w30, all, mul #16"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Bitwise Immediate") { @@ -1376,12 +1343,12 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Integer Wide Immediate - P } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE copy integer immediate (predicated)") { - TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.b, p6/m, #-128") + TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.b, p6/m, #-128") TEST_SINGLE(cpy(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.h, p6/m, #-128"); TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.s, p6/m, #-128"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.d, p6/m, #-128"); - TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.b, p6/m, #127"); + TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.b, p6/m, #127"); TEST_SINGLE(cpy(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.h, p6/m, #127"); TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.s, p6/m, #127"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.d, p6/m, #127"); @@ -1394,12 +1361,12 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE copy integer immediate (pr TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), 32512), "mov z30.s, p6/m, #127, lsl #8"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), 32512), "mov z30.d, p6/m, #127, lsl #8"); - TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.b, p6/m, #-128") + TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.b, p6/m, #-128") TEST_SINGLE(mov_imm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.h, p6/m, #-128"); TEST_SINGLE(mov_imm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.s, p6/m, #-128"); TEST_SINGLE(mov_imm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), -128), "mov z30.d, p6/m, #-128"); - TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.b, p6/m, #127"); + TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.b, p6/m, #127"); TEST_SINGLE(mov_imm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.h, p6/m, #127"); TEST_SINGLE(mov_imm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.s, p6/m, #127"); TEST_SINGLE(mov_imm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), 127), "mov z30.d, p6/m, #127"); @@ -1412,12 +1379,12 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE copy integer immediate (pr TEST_SINGLE(mov_imm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), 32512), "mov z30.s, p6/m, #127, lsl #8"); TEST_SINGLE(mov_imm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), 32512), "mov z30.d, p6/m, #127, lsl #8"); - TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.b, p6/z, #-128") + TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.b, p6/z, #-128") TEST_SINGLE(cpy(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.h, p6/z, #-128"); TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.s, p6/z, #-128"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.d, p6/z, #-128"); - TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.b, p6/z, #127"); + TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.b, p6/z, #127"); TEST_SINGLE(cpy(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.h, p6/z, #127"); TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.s, p6/z, #127"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.d, p6/z, #127"); @@ -1430,12 +1397,12 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE copy integer immediate (pr TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), 32512), "mov z30.s, p6/z, #127, lsl #8"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), 32512), "mov z30.d, p6/z, #127, lsl #8"); - TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.b, p6/z, #-128") + TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.b, p6/z, #-128") TEST_SINGLE(mov_imm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.h, p6/z, #-128"); TEST_SINGLE(mov_imm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.s, p6/z, #-128"); TEST_SINGLE(mov_imm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), -128), "mov z30.d, p6/z, #-128"); - TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.b, p6/z, #127"); + TEST_SINGLE(mov_imm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.b, p6/z, #127"); TEST_SINGLE(mov_imm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.h, p6/z, #127"); TEST_SINGLE(mov_imm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.s, p6/z, #127"); TEST_SINGLE(mov_imm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), 127), "mov z30.d, p6/z, #127"); @@ -1450,60 +1417,60 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE copy integer immediate (pr } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Permute Vector - Unpredicated") { - TEST_SINGLE(dup(SubRegSize::i8Bit, ZReg::z30, Reg::r29), "mov z30.b, w29"); - TEST_SINGLE(dup(SubRegSize::i16Bit, ZReg::z30, Reg::r29), "mov z30.h, w29"); - TEST_SINGLE(dup(SubRegSize::i32Bit, ZReg::z30, Reg::r29), "mov z30.s, w29"); - TEST_SINGLE(dup(SubRegSize::i64Bit, ZReg::z30, Reg::r29), "mov z30.d, x29"); + TEST_SINGLE(dup(SubRegSize::i8Bit, ZReg::z30, Reg::r29), "mov z30.b, w29"); + TEST_SINGLE(dup(SubRegSize::i16Bit, ZReg::z30, Reg::r29), "mov z30.h, w29"); + TEST_SINGLE(dup(SubRegSize::i32Bit, ZReg::z30, Reg::r29), "mov z30.s, w29"); + TEST_SINGLE(dup(SubRegSize::i64Bit, ZReg::z30, Reg::r29), "mov z30.d, x29"); - TEST_SINGLE(mov(SubRegSize::i8Bit, ZReg::z30, Reg::r29), "mov z30.b, w29"); - TEST_SINGLE(mov(SubRegSize::i16Bit, ZReg::z30, Reg::r29), "mov z30.h, w29"); - TEST_SINGLE(mov(SubRegSize::i32Bit, ZReg::z30, Reg::r29), "mov z30.s, w29"); - TEST_SINGLE(mov(SubRegSize::i64Bit, ZReg::z30, Reg::r29), "mov z30.d, x29"); + TEST_SINGLE(mov(SubRegSize::i8Bit, ZReg::z30, Reg::r29), "mov z30.b, w29"); + TEST_SINGLE(mov(SubRegSize::i16Bit, ZReg::z30, Reg::r29), "mov z30.h, w29"); + TEST_SINGLE(mov(SubRegSize::i32Bit, ZReg::z30, Reg::r29), "mov z30.s, w29"); + TEST_SINGLE(mov(SubRegSize::i64Bit, ZReg::z30, Reg::r29), "mov z30.d, x29"); - TEST_SINGLE(insr(SubRegSize::i8Bit, ZReg::z30, Reg::r29), "insr z30.b, w29"); + TEST_SINGLE(insr(SubRegSize::i8Bit, ZReg::z30, Reg::r29), "insr z30.b, w29"); TEST_SINGLE(insr(SubRegSize::i16Bit, ZReg::z30, Reg::r29), "insr z30.h, w29"); TEST_SINGLE(insr(SubRegSize::i32Bit, ZReg::z30, Reg::r29), "insr z30.s, w29"); TEST_SINGLE(insr(SubRegSize::i64Bit, ZReg::z30, Reg::r29), "insr z30.d, x29"); - TEST_SINGLE(insr(SubRegSize::i8Bit, ZReg::z30, VReg::v29), "insr z30.b, b29"); + TEST_SINGLE(insr(SubRegSize::i8Bit, ZReg::z30, VReg::v29), "insr z30.b, b29"); TEST_SINGLE(insr(SubRegSize::i16Bit, ZReg::z30, VReg::v29), "insr z30.h, h29"); TEST_SINGLE(insr(SubRegSize::i32Bit, ZReg::z30, VReg::v29), "insr z30.s, s29"); TEST_SINGLE(insr(SubRegSize::i64Bit, ZReg::z30, VReg::v29), "insr z30.d, d29"); - TEST_SINGLE(rev(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "rev z30.b, z29.b"); + TEST_SINGLE(rev(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "rev z30.b, z29.b"); TEST_SINGLE(rev(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "rev z30.h, z29.h"); TEST_SINGLE(rev(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "rev z30.s, z29.s"); TEST_SINGLE(rev(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "rev z30.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE unpack vector elements") { - //TEST_SINGLE(sunpklo(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sunpklo z30.b, z29.b"); - TEST_SINGLE(sunpklo(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sunpklo z30.h, z29.b"); - TEST_SINGLE(sunpklo(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sunpklo z30.s, z29.h"); - TEST_SINGLE(sunpklo(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sunpklo z30.d, z29.s"); - //TEST_SINGLE(sunpklo(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "sunpklo z30.q, z29.q"); + // TEST_SINGLE(sunpklo(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sunpklo z30.b, z29.b"); + TEST_SINGLE(sunpklo(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sunpklo z30.h, z29.b"); + TEST_SINGLE(sunpklo(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sunpklo z30.s, z29.h"); + TEST_SINGLE(sunpklo(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sunpklo z30.d, z29.s"); + // TEST_SINGLE(sunpklo(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "sunpklo z30.q, z29.q"); - //TEST_SINGLE(sunpkhi(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.b, z29.b"); - TEST_SINGLE(sunpkhi(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.h, z29.b"); - TEST_SINGLE(sunpkhi(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.s, z29.h"); - TEST_SINGLE(sunpkhi(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.d, z29.s"); - //TEST_SINGLE(sunpkhi(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.q, z29.q"); + // TEST_SINGLE(sunpkhi(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.b, z29.b"); + TEST_SINGLE(sunpkhi(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.h, z29.b"); + TEST_SINGLE(sunpkhi(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.s, z29.h"); + TEST_SINGLE(sunpkhi(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.d, z29.s"); + // TEST_SINGLE(sunpkhi(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "sunpkhi z30.q, z29.q"); - //TEST_SINGLE(uunpklo(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "uunpklo z30.b, z29.b"); - TEST_SINGLE(uunpklo(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "uunpklo z30.h, z29.b"); - TEST_SINGLE(uunpklo(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "uunpklo z30.s, z29.h"); - TEST_SINGLE(uunpklo(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uunpklo z30.d, z29.s"); - //TEST_SINGLE(uunpklo(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "uunpklo z30.q, z29.q"); + // TEST_SINGLE(uunpklo(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "uunpklo z30.b, z29.b"); + TEST_SINGLE(uunpklo(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "uunpklo z30.h, z29.b"); + TEST_SINGLE(uunpklo(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "uunpklo z30.s, z29.h"); + TEST_SINGLE(uunpklo(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uunpklo z30.d, z29.s"); + // TEST_SINGLE(uunpklo(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "uunpklo z30.q, z29.q"); - //TEST_SINGLE(uunpkhi(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.b, z29.b"); - TEST_SINGLE(uunpkhi(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.h, z29.b"); - TEST_SINGLE(uunpkhi(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.s, z29.h"); - TEST_SINGLE(uunpkhi(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.d, z29.s"); - //TEST_SINGLE(uunpkhi(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.q, z29.q"); + // TEST_SINGLE(uunpkhi(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.b, z29.b"); + TEST_SINGLE(uunpkhi(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.h, z29.b"); + TEST_SINGLE(uunpkhi(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.s, z29.h"); + TEST_SINGLE(uunpkhi(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.d, z29.s"); + // TEST_SINGLE(uunpkhi(SubRegSize::i128Bit, ZReg::z30, ZReg::z29), "uunpkhi z30.q, z29.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Permute Predicate") { - TEST_SINGLE(rev(SubRegSize::i8Bit, PReg::p15, PReg::p14), "rev p15.b, p14.b"); + TEST_SINGLE(rev(SubRegSize::i8Bit, PReg::p15, PReg::p14), "rev p15.b, p14.b"); TEST_SINGLE(rev(SubRegSize::i16Bit, PReg::p15, PReg::p14), "rev p15.h, p14.h"); TEST_SINGLE(rev(SubRegSize::i32Bit, PReg::p15, PReg::p14), "rev p15.s, p14.s"); TEST_SINGLE(rev(SubRegSize::i64Bit, PReg::p15, PReg::p14), "rev p15.d, p14.d"); @@ -1511,32 +1478,32 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Permute Predicate") { TEST_SINGLE(punpklo(PReg::p15, PReg::p14), "punpklo p15.h, p14.b"); TEST_SINGLE(punpkhi(PReg::p15, PReg::p14), "punpkhi p15.h, p14.b"); - TEST_SINGLE(zip1(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "zip1 p15.b, p14.b, p13.b"); + TEST_SINGLE(zip1(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "zip1 p15.b, p14.b, p13.b"); TEST_SINGLE(zip1(SubRegSize::i16Bit, PReg::p15, PReg::p14, PReg::p13), "zip1 p15.h, p14.h, p13.h"); TEST_SINGLE(zip1(SubRegSize::i32Bit, PReg::p15, PReg::p14, PReg::p13), "zip1 p15.s, p14.s, p13.s"); TEST_SINGLE(zip1(SubRegSize::i64Bit, PReg::p15, PReg::p14, PReg::p13), "zip1 p15.d, p14.d, p13.d"); - TEST_SINGLE(zip2(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "zip2 p15.b, p14.b, p13.b"); + TEST_SINGLE(zip2(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "zip2 p15.b, p14.b, p13.b"); TEST_SINGLE(zip2(SubRegSize::i16Bit, PReg::p15, PReg::p14, PReg::p13), "zip2 p15.h, p14.h, p13.h"); TEST_SINGLE(zip2(SubRegSize::i32Bit, PReg::p15, PReg::p14, PReg::p13), "zip2 p15.s, p14.s, p13.s"); TEST_SINGLE(zip2(SubRegSize::i64Bit, PReg::p15, PReg::p14, PReg::p13), "zip2 p15.d, p14.d, p13.d"); - TEST_SINGLE(uzp1(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "uzp1 p15.b, p14.b, p13.b"); + TEST_SINGLE(uzp1(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "uzp1 p15.b, p14.b, p13.b"); TEST_SINGLE(uzp1(SubRegSize::i16Bit, PReg::p15, PReg::p14, PReg::p13), "uzp1 p15.h, p14.h, p13.h"); TEST_SINGLE(uzp1(SubRegSize::i32Bit, PReg::p15, PReg::p14, PReg::p13), "uzp1 p15.s, p14.s, p13.s"); TEST_SINGLE(uzp1(SubRegSize::i64Bit, PReg::p15, PReg::p14, PReg::p13), "uzp1 p15.d, p14.d, p13.d"); - TEST_SINGLE(uzp2(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "uzp2 p15.b, p14.b, p13.b"); + TEST_SINGLE(uzp2(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "uzp2 p15.b, p14.b, p13.b"); TEST_SINGLE(uzp2(SubRegSize::i16Bit, PReg::p15, PReg::p14, PReg::p13), "uzp2 p15.h, p14.h, p13.h"); TEST_SINGLE(uzp2(SubRegSize::i32Bit, PReg::p15, PReg::p14, PReg::p13), "uzp2 p15.s, p14.s, p13.s"); TEST_SINGLE(uzp2(SubRegSize::i64Bit, PReg::p15, PReg::p14, PReg::p13), "uzp2 p15.d, p14.d, p13.d"); - TEST_SINGLE(trn1(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "trn1 p15.b, p14.b, p13.b"); + TEST_SINGLE(trn1(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "trn1 p15.b, p14.b, p13.b"); TEST_SINGLE(trn1(SubRegSize::i16Bit, PReg::p15, PReg::p14, PReg::p13), "trn1 p15.h, p14.h, p13.h"); TEST_SINGLE(trn1(SubRegSize::i32Bit, PReg::p15, PReg::p14, PReg::p13), "trn1 p15.s, p14.s, p13.s"); TEST_SINGLE(trn1(SubRegSize::i64Bit, PReg::p15, PReg::p14, PReg::p13), "trn1 p15.d, p14.d, p13.d"); - TEST_SINGLE(trn2(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "trn2 p15.b, p14.b, p13.b"); + TEST_SINGLE(trn2(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p13), "trn2 p15.b, p14.b, p13.b"); TEST_SINGLE(trn2(SubRegSize::i16Bit, PReg::p15, PReg::p14, PReg::p13), "trn2 p15.h, p14.h, p13.h"); TEST_SINGLE(trn2(SubRegSize::i32Bit, PReg::p15, PReg::p14, PReg::p13), "trn2 p15.s, p14.s, p13.s"); TEST_SINGLE(trn2(SubRegSize::i64Bit, PReg::p15, PReg::p14, PReg::p13), "trn2 p15.d, p14.d, p13.d"); @@ -1544,75 +1511,80 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Permute Predicate") { TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Permute Vector - Predicated - Base") { // CPY (SIMD&FP scalar) - TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), VReg::v30), "mov z30.b, p7/m, b30"); + TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), VReg::v30), "mov z30.b, p7/m, b30"); TEST_SINGLE(cpy(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), VReg::v30), "mov z30.h, p7/m, h30"); TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), VReg::v30), "mov z30.s, p7/m, s30"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), VReg::v30), "mov z30.d, p7/m, d30"); - //TEST_SINGLE(compact(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.b, p6, z29.b"); - //TEST_SINGLE(compact(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.h, p6, z29.h"); - TEST_SINGLE(compact(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.s, p6, z29.s"); - TEST_SINGLE(compact(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.d, p6, z29.d"); - //TEST_SINGLE(compact(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.q, p6, z29.q"); + // TEST_SINGLE(compact(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.b, p6, z29.b"); + // TEST_SINGLE(compact(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.h, p6, z29.h"); + TEST_SINGLE(compact(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.s, p6, z29.s"); + TEST_SINGLE(compact(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.d, p6, z29.d"); + // TEST_SINGLE(compact(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z29), "compact z30.q, p6, z29.q"); // CPY (scalar) - TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), WReg::rsp), "mov z30.b, p7/m, wsp"); + TEST_SINGLE(cpy(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), WReg::rsp), "mov z30.b, p7/m, wsp"); TEST_SINGLE(cpy(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), WReg::rsp), "mov z30.h, p7/m, wsp"); TEST_SINGLE(cpy(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), WReg::rsp), "mov z30.s, p7/m, wsp"); TEST_SINGLE(cpy(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), XReg::rsp), "mov z30.d, p7/m, sp"); - TEST_SINGLE(splice(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.b, p6, {z28.b, z29.b}"); - TEST_SINGLE(splice(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.h, p6, {z28.h, z29.h}"); - TEST_SINGLE(splice(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.s, p6, {z28.s, z29.s}"); - TEST_SINGLE(splice(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.d, p6, {z28.d, z29.d}"); - TEST_SINGLE(splice(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z31, ZReg::z0), "splice z30.d, p6, {z31.d, z0.d}"); - //TEST_SINGLE(splice(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.q, p6, {z28.q, z29.q}"); + TEST_SINGLE(splice(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.b, p6, {z28.b, " + "z29.b}"); + TEST_SINGLE(splice(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.h, p6, {z28.h, " + "z29.h}"); + TEST_SINGLE(splice(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.s, p6, {z28.s, " + "z29.s}"); + TEST_SINGLE(splice(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.d, p6, {z28.d, " + "z29.d}"); + TEST_SINGLE(splice(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z31, ZReg::z0), "splice z30.d, p6, {z31.d, " + "z0.d}"); + // TEST_SINGLE(splice(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z28, ZReg::z29), "splice z30.q, p6, {z28.q, z29.q}"); - TEST_SINGLE(splice(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.b, p6, z30.b, z28.b"); - TEST_SINGLE(splice(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.h, p6, z30.h, z28.h"); - TEST_SINGLE(splice(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.s, p6, z30.s, z28.s"); - TEST_SINGLE(splice(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.d, p6, z30.d, z28.d"); - //TEST_SINGLE(splice(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.q, p6, z30.q, z28.q"); + TEST_SINGLE(splice(SubRegSize::i8Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.b, p6, z30.b, z28.b"); + TEST_SINGLE(splice(SubRegSize::i16Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.h, p6, z30.h, z28.h"); + TEST_SINGLE(splice(SubRegSize::i32Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.s, p6, z30.s, z28.s"); + TEST_SINGLE(splice(SubRegSize::i64Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.d, p6, z30.d, z28.d"); + // TEST_SINGLE(splice(SubRegSize::i128Bit, ZReg::z30, PReg::p6, ZReg::z30, ZReg::z28), "splice z30.q, p6, z30.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE extract element to general register") { - TEST_SINGLE(lasta(SubRegSize::i8Bit, WReg::w30, PReg::p7, ZReg::z30), "lasta w30, p7, z30.b"); + TEST_SINGLE(lasta(SubRegSize::i8Bit, WReg::w30, PReg::p7, ZReg::z30), "lasta w30, p7, z30.b"); TEST_SINGLE(lasta(SubRegSize::i16Bit, WReg::w30, PReg::p7, ZReg::z30), "lasta w30, p7, z30.h"); TEST_SINGLE(lasta(SubRegSize::i32Bit, WReg::w30, PReg::p7, ZReg::z30), "lasta w30, p7, z30.s"); TEST_SINGLE(lasta(SubRegSize::i64Bit, XReg::x30, PReg::p7, ZReg::z30), "lasta x30, p7, z30.d"); - TEST_SINGLE(lastb(SubRegSize::i8Bit, WReg::w30, PReg::p7, ZReg::z30), "lastb w30, p7, z30.b"); + TEST_SINGLE(lastb(SubRegSize::i8Bit, WReg::w30, PReg::p7, ZReg::z30), "lastb w30, p7, z30.b"); TEST_SINGLE(lastb(SubRegSize::i16Bit, WReg::w30, PReg::p7, ZReg::z30), "lastb w30, p7, z30.h"); TEST_SINGLE(lastb(SubRegSize::i32Bit, WReg::w30, PReg::p7, ZReg::z30), "lastb w30, p7, z30.s"); TEST_SINGLE(lastb(SubRegSize::i64Bit, XReg::x30, PReg::p7, ZReg::z30), "lastb x30, p7, z30.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE extract element to SIMD&FP scalar register") { - TEST_SINGLE(lasta(SubRegSize::i8Bit, BReg::b30, PReg::p7, ZReg::z29), "lasta b30, p7, z29.b"); + TEST_SINGLE(lasta(SubRegSize::i8Bit, BReg::b30, PReg::p7, ZReg::z29), "lasta b30, p7, z29.b"); TEST_SINGLE(lasta(SubRegSize::i16Bit, HReg::h30, PReg::p7, ZReg::z29), "lasta h30, p7, z29.h"); TEST_SINGLE(lasta(SubRegSize::i32Bit, SReg::s30, PReg::p7, ZReg::z29), "lasta s30, p7, z29.s"); TEST_SINGLE(lasta(SubRegSize::i64Bit, DReg::d30, PReg::p7, ZReg::z29), "lasta d30, p7, z29.d"); - TEST_SINGLE(lastb(SubRegSize::i8Bit, BReg::b30, PReg::p7, ZReg::z29), "lastb b30, p7, z29.b"); + TEST_SINGLE(lastb(SubRegSize::i8Bit, BReg::b30, PReg::p7, ZReg::z29), "lastb b30, p7, z29.b"); TEST_SINGLE(lastb(SubRegSize::i16Bit, HReg::h30, PReg::p7, ZReg::z29), "lastb h30, p7, z29.h"); TEST_SINGLE(lastb(SubRegSize::i32Bit, SReg::s30, PReg::p7, ZReg::z29), "lastb s30, p7, z29.s"); TEST_SINGLE(lastb(SubRegSize::i64Bit, DReg::d30, PReg::p7, ZReg::z29), "lastb d30, p7, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE reverse within elements") { - //TEST_SINGLE(revb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revb z30.b, p6/m, z29.b"); + // TEST_SINGLE(revb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revb z30.b, p6/m, z29.b"); TEST_SINGLE(revb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revb z30.h, p6/m, z29.h"); TEST_SINGLE(revb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revb z30.s, p6/m, z29.s"); TEST_SINGLE(revb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revb z30.d, p6/m, z29.d"); - //TEST_SINGLE(revh(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revh z30.b, p6/m, z29.b"); - //TEST_SINGLE(revh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revh z30.h, p6/m, z29.h"); + // TEST_SINGLE(revh(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revh z30.b, p6/m, z29.b"); + // TEST_SINGLE(revh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revh z30.h, p6/m, z29.h"); TEST_SINGLE(revh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revh z30.s, p6/m, z29.s"); TEST_SINGLE(revh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revh z30.d, p6/m, z29.d"); - //TEST_SINGLE(revw(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revw z30.b, p6/m, z29.b"); - //TEST_SINGLE(revw(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revw z30.h, p6/m, z29.h"); - //TEST_SINGLE(revw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revw z30.s, p6/m, z29.s"); + // TEST_SINGLE(revw(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revw z30.b, p6/m, z29.b"); + // TEST_SINGLE(revw(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revw z30.h, p6/m, z29.h"); + // TEST_SINGLE(revw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revw z30.s, p6/m, z29.s"); TEST_SINGLE(revw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "revw z30.d, p6/m, z29.d"); TEST_SINGLE(rbit(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "rbit z30.b, p6/m, z29.b"); @@ -1622,24 +1594,24 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE reverse within elements") } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE conditionally broadcast element to vector") { - TEST_SINGLE(clasta(SubRegSize::i8Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clasta z30.b, p7, z30.b, z29.b"); + TEST_SINGLE(clasta(SubRegSize::i8Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clasta z30.b, p7, z30.b, z29.b"); TEST_SINGLE(clasta(SubRegSize::i16Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clasta z30.h, p7, z30.h, z29.h"); TEST_SINGLE(clasta(SubRegSize::i32Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clasta z30.s, p7, z30.s, z29.s"); TEST_SINGLE(clasta(SubRegSize::i64Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clasta z30.d, p7, z30.d, z29.d"); - TEST_SINGLE(clastb(SubRegSize::i8Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clastb z30.b, p7, z30.b, z29.b"); + TEST_SINGLE(clastb(SubRegSize::i8Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clastb z30.b, p7, z30.b, z29.b"); TEST_SINGLE(clastb(SubRegSize::i16Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clastb z30.h, p7, z30.h, z29.h"); TEST_SINGLE(clastb(SubRegSize::i32Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clastb z30.s, p7, z30.s, z29.s"); TEST_SINGLE(clastb(SubRegSize::i64Bit, ZReg::z30, PReg::p7, ZReg::z30, ZReg::z29), "clastb z30.d, p7, z30.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE conditionally extract element to SIMD&FP scalar") { - TEST_SINGLE(clasta(SubRegSize::i8Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clasta b30, p7, b30, z29.b"); + TEST_SINGLE(clasta(SubRegSize::i8Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clasta b30, p7, b30, z29.b"); TEST_SINGLE(clasta(SubRegSize::i16Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clasta h30, p7, h30, z29.h"); TEST_SINGLE(clasta(SubRegSize::i32Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clasta s30, p7, s30, z29.s"); TEST_SINGLE(clasta(SubRegSize::i64Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clasta d30, p7, d30, z29.d"); - TEST_SINGLE(clastb(SubRegSize::i8Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clastb b30, p7, b30, z29.b"); + TEST_SINGLE(clastb(SubRegSize::i8Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clastb b30, p7, b30, z29.b"); TEST_SINGLE(clastb(SubRegSize::i16Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clastb h30, p7, h30, z29.h"); TEST_SINGLE(clastb(SubRegSize::i32Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clastb s30, p7, s30, z29.s"); TEST_SINGLE(clastb(SubRegSize::i64Bit, VReg::v30, PReg::p7, VReg::v30, ZReg::z29), "clastb d30, p7, d30, z29.d"); @@ -1650,24 +1622,24 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE reverse doublewords") { } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE conditionally extract element to general register") { - TEST_SINGLE(clasta(SubRegSize::i8Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clasta w30, p7, w30, z29.b"); + TEST_SINGLE(clasta(SubRegSize::i8Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clasta w30, p7, w30, z29.b"); TEST_SINGLE(clasta(SubRegSize::i16Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clasta w30, p7, w30, z29.h"); TEST_SINGLE(clasta(SubRegSize::i32Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clasta w30, p7, w30, z29.s"); TEST_SINGLE(clasta(SubRegSize::i64Bit, XReg::x30, PReg::p7, XReg::x30, ZReg::z29), "clasta x30, p7, x30, z29.d"); - TEST_SINGLE(clastb(SubRegSize::i8Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clastb w30, p7, w30, z29.b"); + TEST_SINGLE(clastb(SubRegSize::i8Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clastb w30, p7, w30, z29.b"); TEST_SINGLE(clastb(SubRegSize::i16Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clastb w30, p7, w30, z29.h"); TEST_SINGLE(clastb(SubRegSize::i32Bit, WReg::w30, PReg::p7, WReg::w30, ZReg::z29), "clastb w30, p7, w30, z29.s"); TEST_SINGLE(clastb(SubRegSize::i64Bit, XReg::x30, PReg::p7, XReg::x30, ZReg::z29), "clastb x30, p7, x30, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Permute Vector - Extract") { - TEST_SINGLE(ext(ZReg::z30, ZReg::z30, ZReg::z29, 0), "ext z30.b, z30.b, z29.b, #0"); + TEST_SINGLE(ext(ZReg::z30, ZReg::z30, ZReg::z29, 0), "ext z30.b, z30.b, z29.b, #0"); TEST_SINGLE(ext(ZReg::z30, ZReg::z30, ZReg::z29, 255), "ext z30.b, z30.b, z29.b, #255"); - TEST_SINGLE(ext(ZReg::z30, ZReg::z28, ZReg::z29, 0), "ext z30.b, {z28.b, z29.b}, #0"); + TEST_SINGLE(ext(ZReg::z30, ZReg::z28, ZReg::z29, 0), "ext z30.b, {z28.b, z29.b}, #0"); TEST_SINGLE(ext(ZReg::z30, ZReg::z28, ZReg::z29, 255), "ext z30.b, {z28.b, z29.b}, #255"); - TEST_SINGLE(ext(ZReg::z30, ZReg::z31, ZReg::z0, 255), "ext z30.b, {z31.b, z0.b}, #255"); + TEST_SINGLE(ext(ZReg::z30, ZReg::z31, ZReg::z0, 255), "ext z30.b, {z31.b, z0.b}, #255"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE permute vector segments") { @@ -1675,132 +1647,132 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE permute vector segments") } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer compare vectors") { - TEST_SINGLE(cmpeq(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.b, p5/z, z30.b, z29.b"); + TEST_SINGLE(cmpeq(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.b, p5/z, z30.b, z29.b"); TEST_SINGLE(cmpeq(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.h, p5/z, z30.h, z29.h"); TEST_SINGLE(cmpeq(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.s, p5/z, z30.s, z29.s"); TEST_SINGLE(cmpeq(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.d, p5/z, z30.d, z29.d"); - TEST_SINGLE(cmpge(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.b, p5/z, z30.b, z29.b"); + TEST_SINGLE(cmpge(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.b, p5/z, z30.b, z29.b"); TEST_SINGLE(cmpge(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.h, p5/z, z30.h, z29.h"); TEST_SINGLE(cmpge(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.s, p5/z, z30.s, z29.s"); TEST_SINGLE(cmpge(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.d, p5/z, z30.d, z29.d"); - TEST_SINGLE(cmpgt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.b, p5/z, z30.b, z29.b"); + TEST_SINGLE(cmpgt(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.b, p5/z, z30.b, z29.b"); TEST_SINGLE(cmpgt(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.h, p5/z, z30.h, z29.h"); TEST_SINGLE(cmpgt(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.s, p5/z, z30.s, z29.s"); TEST_SINGLE(cmpgt(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.d, p5/z, z30.d, z29.d"); - TEST_SINGLE(cmphi(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.b, p5/z, z30.b, z29.b"); + TEST_SINGLE(cmphi(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.b, p5/z, z30.b, z29.b"); TEST_SINGLE(cmphi(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.h, p5/z, z30.h, z29.h"); TEST_SINGLE(cmphi(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.s, p5/z, z30.s, z29.s"); TEST_SINGLE(cmphi(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.d, p5/z, z30.d, z29.d"); - TEST_SINGLE(cmphs(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.b, p5/z, z30.b, z29.b"); + TEST_SINGLE(cmphs(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.b, p5/z, z30.b, z29.b"); TEST_SINGLE(cmphs(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.h, p5/z, z30.h, z29.h"); TEST_SINGLE(cmphs(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.s, p5/z, z30.s, z29.s"); TEST_SINGLE(cmphs(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.d, p5/z, z30.d, z29.d"); - TEST_SINGLE(cmpne(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.b, p5/z, z30.b, z29.b"); + TEST_SINGLE(cmpne(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.b, p5/z, z30.b, z29.b"); TEST_SINGLE(cmpne(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.h, p5/z, z30.h, z29.h"); TEST_SINGLE(cmpne(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.s, p5/z, z30.s, z29.s"); TEST_SINGLE(cmpne(SubRegSize::i64Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.d, p5/z, z30.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer compare with wide elements") { - TEST_SINGLE(cmpeq_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmpeq_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmpeq_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmpeq_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpeq p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmpgt_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmpgt_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmpgt_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmpgt_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpgt p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmpge_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmpge_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmpge_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmpge_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpge p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmphi_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmphi_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmphi_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmphi_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphi p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmphs_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmphs_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmphs_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmphs_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmphs p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmplt_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplt p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmplt_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplt p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmplt_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplt p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmplt_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplt p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmple_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmple p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmple_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmple p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmple_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmple p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmple_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmple p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmplo_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplo p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmplo_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplo p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmplo_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplo p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmplo_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmplo p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmpls_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpls p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmpls_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpls p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmpls_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpls p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmpls_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpls p6.s, p5/z, z30.s, z29.d"); - TEST_SINGLE(cmpne_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.b, p5/z, z30.b, z29.d"); + TEST_SINGLE(cmpne_wide(SubRegSize::i8Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.b, p5/z, z30.b, z29.d"); TEST_SINGLE(cmpne_wide(SubRegSize::i16Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.h, p5/z, z30.h, z29.d"); TEST_SINGLE(cmpne_wide(SubRegSize::i32Bit, PReg::p6, PReg::p5.Zeroing(), ZReg::z30, ZReg::z29), "cmpne p6.s, p5/z, z30.s, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE propagate break from previous partition") { - TEST_SINGLE(brkpa(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpa p15.b, p14/z, p13.b, p12.b"); - TEST_SINGLE(brkpas(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpas p15.b, p14/z, p13.b, p12.b"); - TEST_SINGLE(brkpb(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpb p15.b, p14/z, p13.b, p12.b"); - TEST_SINGLE(brkpbs(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpbs p15.b, p14/z, p13.b, p12.b"); + TEST_SINGLE(brkpa(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpa p15.b, p14/z, p13.b, p12.b"); + TEST_SINGLE(brkpas(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpas p15.b, p14/z, p13.b, p12.b"); + TEST_SINGLE(brkpb(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpb p15.b, p14/z, p13.b, p12.b"); + TEST_SINGLE(brkpbs(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p12), "brkpbs p15.b, p14/z, p13.b, p12.b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE propagate break to next partition") { - TEST_SINGLE(brkn(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p15), "brkn p15.b, p14/z, p13.b, p15.b"); - TEST_SINGLE(brkns(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p15), "brkns p15.b, p14/z, p13.b, p15.b"); + TEST_SINGLE(brkn(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p15), "brkn p15.b, p14/z, p13.b, p15.b"); + TEST_SINGLE(brkns(PReg::p15, PReg::p14.Zeroing(), PReg::p13, PReg::p15), "brkns p15.b, p14/z, p13.b, p15.b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE partition break condition") { - TEST_SINGLE(brka(PReg::p15, PReg::p14.Zeroing(), PReg::p13), "brka p15.b, p14/z, p13.b"); - TEST_SINGLE(brka(PReg::p15, PReg::p14.Merging(), PReg::p13), "brka p15.b, p14/m, p13.b"); + TEST_SINGLE(brka(PReg::p15, PReg::p14.Zeroing(), PReg::p13), "brka p15.b, p14/z, p13.b"); + TEST_SINGLE(brka(PReg::p15, PReg::p14.Merging(), PReg::p13), "brka p15.b, p14/m, p13.b"); TEST_SINGLE(brkas(PReg::p15, PReg::p14.Zeroing(), PReg::p13), "brkas p15.b, p14/z, p13.b"); - TEST_SINGLE(brkb(PReg::p15, PReg::p14.Zeroing(), PReg::p13), "brkb p15.b, p14/z, p13.b"); - TEST_SINGLE(brkb(PReg::p15, PReg::p14.Merging(), PReg::p13), "brkb p15.b, p14/m, p13.b"); + TEST_SINGLE(brkb(PReg::p15, PReg::p14.Zeroing(), PReg::p13), "brkb p15.b, p14/z, p13.b"); + TEST_SINGLE(brkb(PReg::p15, PReg::p14.Merging(), PReg::p13), "brkb p15.b, p14/m, p13.b"); TEST_SINGLE(brkbs(PReg::p15, PReg::p14.Zeroing(), PReg::p13), "brkbs p15.b, p14/z, p13.b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Predicate Misc") { - TEST_SINGLE(pnext(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p15), "pnext p15.b, p14, p15.b"); + TEST_SINGLE(pnext(SubRegSize::i8Bit, PReg::p15, PReg::p14, PReg::p15), "pnext p15.b, p14, p15.b"); TEST_SINGLE(pnext(SubRegSize::i16Bit, PReg::p15, PReg::p14, PReg::p15), "pnext p15.h, p14, p15.h"); TEST_SINGLE(pnext(SubRegSize::i32Bit, PReg::p15, PReg::p14, PReg::p15), "pnext p15.s, p14, p15.s"); TEST_SINGLE(pnext(SubRegSize::i64Bit, PReg::p15, PReg::p14, PReg::p15), "pnext p15.d, p14, p15.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate test") { - TEST_SINGLE(ptest(PReg::p6, PReg::p5), "ptest p6, p5.b"); + TEST_SINGLE(ptest(PReg::p6, PReg::p5), "ptest p6, p5.b"); TEST_SINGLE(ptest(PReg::p15, PReg::p14), "ptest p15, p14.b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate first active") { - TEST_SINGLE(pfirst(PReg::p6, PReg::p5, PReg::p6), "pfirst p6.b, p5, p6.b"); + TEST_SINGLE(pfirst(PReg::p6, PReg::p5, PReg::p6), "pfirst p6.b, p5, p6.b"); TEST_SINGLE(pfirst(PReg::p15, PReg::p14, PReg::p15), "pfirst p15.b, p14, p15.b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate zero") { - TEST_SINGLE(pfalse(PReg::p6), "pfalse p6.b"); + TEST_SINGLE(pfalse(PReg::p6), "pfalse p6.b"); TEST_SINGLE(pfalse(PReg::p15), "pfalse p15.b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate read from FFR (predicated)") { - TEST_SINGLE(rdffr(PReg::p6, PReg::p5.Zeroing()), "rdffr p6.b, p5/z"); - TEST_SINGLE(rdffr(PReg::p15, PReg::p14.Zeroing()), "rdffr p15.b, p14/z"); - TEST_SINGLE(rdffrs(PReg::p6, PReg::p5.Zeroing()), "rdffrs p6.b, p5/z"); + TEST_SINGLE(rdffr(PReg::p6, PReg::p5.Zeroing()), "rdffr p6.b, p5/z"); + TEST_SINGLE(rdffr(PReg::p15, PReg::p14.Zeroing()), "rdffr p15.b, p14/z"); + TEST_SINGLE(rdffrs(PReg::p6, PReg::p5.Zeroing()), "rdffrs p6.b, p5/z"); TEST_SINGLE(rdffrs(PReg::p15, PReg::p14.Zeroing()), "rdffrs p15.b, p14/z"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate read from FFR (unpredicated)") { - TEST_SINGLE(rdffr(PReg::p6), "rdffr p6.b"); + TEST_SINGLE(rdffr(PReg::p6), "rdffr p6.b"); TEST_SINGLE(rdffr(PReg::p15), "rdffr p15.b"); } @@ -1977,74 +1949,74 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate initialize") { } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer compare scalar count and limit") { - TEST_SINGLE(whilege(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.b, x30, x29"); + TEST_SINGLE(whilege(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.b, x30, x29"); TEST_SINGLE(whilege(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.h, x30, x29"); TEST_SINGLE(whilege(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.s, x30, x29"); TEST_SINGLE(whilege(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.d, x30, x29"); - TEST_SINGLE(whilege(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.b, w30, w29"); + TEST_SINGLE(whilege(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.b, w30, w29"); TEST_SINGLE(whilege(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.h, w30, w29"); TEST_SINGLE(whilege(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.s, w30, w29"); TEST_SINGLE(whilege(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.d, w30, w29"); - TEST_SINGLE(whilegt(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.b, x30, x29"); + TEST_SINGLE(whilegt(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.b, x30, x29"); TEST_SINGLE(whilegt(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.h, x30, x29"); TEST_SINGLE(whilegt(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.s, x30, x29"); TEST_SINGLE(whilegt(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.d, x30, x29"); - TEST_SINGLE(whilegt(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.b, w30, w29"); + TEST_SINGLE(whilegt(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.b, w30, w29"); TEST_SINGLE(whilegt(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.h, w30, w29"); TEST_SINGLE(whilegt(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.s, w30, w29"); TEST_SINGLE(whilegt(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.d, w30, w29"); - TEST_SINGLE(whilelt(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.b, x30, x29"); + TEST_SINGLE(whilelt(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.b, x30, x29"); TEST_SINGLE(whilelt(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.h, x30, x29"); TEST_SINGLE(whilelt(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.s, x30, x29"); TEST_SINGLE(whilelt(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.d, x30, x29"); - TEST_SINGLE(whilelt(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.b, w30, w29"); + TEST_SINGLE(whilelt(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.b, w30, w29"); TEST_SINGLE(whilelt(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.h, w30, w29"); TEST_SINGLE(whilelt(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.s, w30, w29"); TEST_SINGLE(whilelt(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.d, w30, w29"); - TEST_SINGLE(whilele(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.b, x30, x29"); + TEST_SINGLE(whilele(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.b, x30, x29"); TEST_SINGLE(whilele(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.h, x30, x29"); TEST_SINGLE(whilele(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.s, x30, x29"); TEST_SINGLE(whilele(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.d, x30, x29"); - TEST_SINGLE(whilele(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.b, w30, w29"); + TEST_SINGLE(whilele(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.b, w30, w29"); TEST_SINGLE(whilele(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.h, w30, w29"); TEST_SINGLE(whilele(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.s, w30, w29"); TEST_SINGLE(whilele(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.d, w30, w29"); - TEST_SINGLE(whilehs(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.b, x30, x29"); + TEST_SINGLE(whilehs(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.b, x30, x29"); TEST_SINGLE(whilehs(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.h, x30, x29"); TEST_SINGLE(whilehs(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.s, x30, x29"); TEST_SINGLE(whilehs(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.d, x30, x29"); - TEST_SINGLE(whilehs(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.b, w30, w29"); + TEST_SINGLE(whilehs(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.b, w30, w29"); TEST_SINGLE(whilehs(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.h, w30, w29"); TEST_SINGLE(whilehs(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.s, w30, w29"); TEST_SINGLE(whilehs(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.d, w30, w29"); - TEST_SINGLE(whilehi(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.b, x30, x29"); + TEST_SINGLE(whilehi(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.b, x30, x29"); TEST_SINGLE(whilehi(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.h, x30, x29"); TEST_SINGLE(whilehi(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.s, x30, x29"); TEST_SINGLE(whilehi(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.d, x30, x29"); - TEST_SINGLE(whilehi(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.b, w30, w29"); + TEST_SINGLE(whilehi(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.b, w30, w29"); TEST_SINGLE(whilehi(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.h, w30, w29"); TEST_SINGLE(whilehi(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.s, w30, w29"); TEST_SINGLE(whilehi(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.d, w30, w29"); - TEST_SINGLE(whilelo(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.b, x30, x29"); + TEST_SINGLE(whilelo(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.b, x30, x29"); TEST_SINGLE(whilelo(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.h, x30, x29"); TEST_SINGLE(whilelo(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.s, x30, x29"); TEST_SINGLE(whilelo(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.d, x30, x29"); - TEST_SINGLE(whilelo(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.b, w30, w29"); + TEST_SINGLE(whilelo(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.b, w30, w29"); TEST_SINGLE(whilelo(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.h, w30, w29"); TEST_SINGLE(whilelo(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.s, w30, w29"); TEST_SINGLE(whilelo(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.d, w30, w29"); - TEST_SINGLE(whilels(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.b, x30, x29"); + TEST_SINGLE(whilels(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.b, x30, x29"); TEST_SINGLE(whilels(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.h, x30, x29"); TEST_SINGLE(whilels(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.s, x30, x29"); TEST_SINGLE(whilels(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.d, x30, x29"); - TEST_SINGLE(whilels(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.b, w30, w29"); + TEST_SINGLE(whilels(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.b, w30, w29"); TEST_SINGLE(whilels(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.h, w30, w29"); TEST_SINGLE(whilels(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.s, w30, w29"); TEST_SINGLE(whilels(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.d, w30, w29"); @@ -2059,276 +2031,276 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE conditionally terminate sc } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE pointer conflict compare") { - TEST_SINGLE(whilewr(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilewr p15.b, x30, x29"); + TEST_SINGLE(whilewr(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilewr p15.b, x30, x29"); TEST_SINGLE(whilewr(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilewr p15.h, x30, x29"); TEST_SINGLE(whilewr(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilewr p15.s, x30, x29"); TEST_SINGLE(whilewr(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilewr p15.d, x30, x29"); - TEST_SINGLE(whilerw(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilerw p15.b, x30, x29"); + TEST_SINGLE(whilerw(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilerw p15.b, x30, x29"); TEST_SINGLE(whilerw(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilerw p15.h, x30, x29"); TEST_SINGLE(whilerw(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilerw p15.s, x30, x29"); TEST_SINGLE(whilerw(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilerw p15.d, x30, x29"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer add/subtract immediate (unpredicated)") { - TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "add z30.b, z30.b, #0"); - TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "add z30.b, z30.b, #127"); - TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "add z30.b, z30.b, #255"); + TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "add z30.b, z30.b, #0"); + TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "add z30.b, z30.b, #127"); + TEST_SINGLE(add(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "add z30.b, z30.b, #255"); - TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "add z30.h, z30.h, #0"); - TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "add z30.h, z30.h, #127"); - TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "add z30.h, z30.h, #255"); - TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "add z30.h, z30.h, #1, lsl #8"); + TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "add z30.h, z30.h, #0"); + TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "add z30.h, z30.h, #127"); + TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "add z30.h, z30.h, #255"); + TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "add z30.h, z30.h, #1, lsl #8"); TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 32512), "add z30.h, z30.h, #127, lsl #8"); TEST_SINGLE(add(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 65280), "add z30.h, z30.h, #255, lsl #8"); - TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "add z30.s, z30.s, #0"); - TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "add z30.s, z30.s, #127"); - TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "add z30.s, z30.s, #255"); - TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "add z30.s, z30.s, #1, lsl #8"); + TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "add z30.s, z30.s, #0"); + TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "add z30.s, z30.s, #127"); + TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "add z30.s, z30.s, #255"); + TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "add z30.s, z30.s, #1, lsl #8"); TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 32512), "add z30.s, z30.s, #127, lsl #8"); TEST_SINGLE(add(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 65280), "add z30.s, z30.s, #255, lsl #8"); - TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "add z30.d, z30.d, #0"); - TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "add z30.d, z30.d, #127"); - TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "add z30.d, z30.d, #255"); - TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "add z30.d, z30.d, #1, lsl #8"); + TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "add z30.d, z30.d, #0"); + TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "add z30.d, z30.d, #127"); + TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "add z30.d, z30.d, #255"); + TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "add z30.d, z30.d, #1, lsl #8"); TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 32512), "add z30.d, z30.d, #127, lsl #8"); TEST_SINGLE(add(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 65280), "add z30.d, z30.d, #255, lsl #8"); - TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "sub z30.b, z30.b, #0"); - TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "sub z30.b, z30.b, #127"); - TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "sub z30.b, z30.b, #255"); + TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "sub z30.b, z30.b, #0"); + TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "sub z30.b, z30.b, #127"); + TEST_SINGLE(sub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "sub z30.b, z30.b, #255"); - TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "sub z30.h, z30.h, #0"); - TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "sub z30.h, z30.h, #127"); - TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "sub z30.h, z30.h, #255"); - TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "sub z30.h, z30.h, #1, lsl #8"); + TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "sub z30.h, z30.h, #0"); + TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "sub z30.h, z30.h, #127"); + TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "sub z30.h, z30.h, #255"); + TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "sub z30.h, z30.h, #1, lsl #8"); TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 32512), "sub z30.h, z30.h, #127, lsl #8"); TEST_SINGLE(sub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 65280), "sub z30.h, z30.h, #255, lsl #8"); - TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "sub z30.s, z30.s, #0"); - TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "sub z30.s, z30.s, #127"); - TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "sub z30.s, z30.s, #255"); - TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "sub z30.s, z30.s, #1, lsl #8"); + TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "sub z30.s, z30.s, #0"); + TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "sub z30.s, z30.s, #127"); + TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "sub z30.s, z30.s, #255"); + TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "sub z30.s, z30.s, #1, lsl #8"); TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 32512), "sub z30.s, z30.s, #127, lsl #8"); TEST_SINGLE(sub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 65280), "sub z30.s, z30.s, #255, lsl #8"); - TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "sub z30.d, z30.d, #0"); - TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "sub z30.d, z30.d, #127"); - TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "sub z30.d, z30.d, #255"); - TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "sub z30.d, z30.d, #1, lsl #8"); + TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "sub z30.d, z30.d, #0"); + TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "sub z30.d, z30.d, #127"); + TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "sub z30.d, z30.d, #255"); + TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "sub z30.d, z30.d, #1, lsl #8"); TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 32512), "sub z30.d, z30.d, #127, lsl #8"); TEST_SINGLE(sub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 65280), "sub z30.d, z30.d, #255, lsl #8"); - TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "subr z30.b, z30.b, #0"); - TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "subr z30.b, z30.b, #127"); - TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "subr z30.b, z30.b, #255"); + TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "subr z30.b, z30.b, #0"); + TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "subr z30.b, z30.b, #127"); + TEST_SINGLE(subr(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "subr z30.b, z30.b, #255"); - TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "subr z30.h, z30.h, #0"); - TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "subr z30.h, z30.h, #127"); - TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "subr z30.h, z30.h, #255"); - TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "subr z30.h, z30.h, #1, lsl #8"); + TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "subr z30.h, z30.h, #0"); + TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "subr z30.h, z30.h, #127"); + TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "subr z30.h, z30.h, #255"); + TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "subr z30.h, z30.h, #1, lsl #8"); TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 32512), "subr z30.h, z30.h, #127, lsl #8"); TEST_SINGLE(subr(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 65280), "subr z30.h, z30.h, #255, lsl #8"); - TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "subr z30.s, z30.s, #0"); - TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "subr z30.s, z30.s, #127"); - TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "subr z30.s, z30.s, #255"); - TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "subr z30.s, z30.s, #1, lsl #8"); + TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "subr z30.s, z30.s, #0"); + TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "subr z30.s, z30.s, #127"); + TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "subr z30.s, z30.s, #255"); + TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "subr z30.s, z30.s, #1, lsl #8"); TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 32512), "subr z30.s, z30.s, #127, lsl #8"); TEST_SINGLE(subr(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 65280), "subr z30.s, z30.s, #255, lsl #8"); - TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "subr z30.d, z30.d, #0"); - TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "subr z30.d, z30.d, #127"); - TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "subr z30.d, z30.d, #255"); - TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "subr z30.d, z30.d, #1, lsl #8"); + TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "subr z30.d, z30.d, #0"); + TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "subr z30.d, z30.d, #127"); + TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "subr z30.d, z30.d, #255"); + TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "subr z30.d, z30.d, #1, lsl #8"); TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 32512), "subr z30.d, z30.d, #127, lsl #8"); TEST_SINGLE(subr(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 65280), "subr z30.d, z30.d, #255, lsl #8"); - TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.b, z30.b, #0"); - TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.b, z30.b, #127"); - TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.b, z30.b, #255"); + TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.b, z30.b, #0"); + TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.b, z30.b, #127"); + TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.b, z30.b, #255"); - TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.h, z30.h, #0"); - TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.h, z30.h, #127"); - TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.h, z30.h, #255"); - TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "sqadd z30.h, z30.h, #1, lsl #8"); + TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.h, z30.h, #0"); + TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.h, z30.h, #127"); + TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.h, z30.h, #255"); + TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "sqadd z30.h, z30.h, #1, lsl #8"); TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 32512), "sqadd z30.h, z30.h, #127, lsl #8"); TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 65280), "sqadd z30.h, z30.h, #255, lsl #8"); - TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.s, z30.s, #0"); - TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.s, z30.s, #127"); - TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.s, z30.s, #255"); - TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "sqadd z30.s, z30.s, #1, lsl #8"); + TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.s, z30.s, #0"); + TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.s, z30.s, #127"); + TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.s, z30.s, #255"); + TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "sqadd z30.s, z30.s, #1, lsl #8"); TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 32512), "sqadd z30.s, z30.s, #127, lsl #8"); TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 65280), "sqadd z30.s, z30.s, #255, lsl #8"); - TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.d, z30.d, #0"); - TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.d, z30.d, #127"); - TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.d, z30.d, #255"); - TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "sqadd z30.d, z30.d, #1, lsl #8"); + TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "sqadd z30.d, z30.d, #0"); + TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "sqadd z30.d, z30.d, #127"); + TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "sqadd z30.d, z30.d, #255"); + TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "sqadd z30.d, z30.d, #1, lsl #8"); TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 32512), "sqadd z30.d, z30.d, #127, lsl #8"); TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 65280), "sqadd z30.d, z30.d, #255, lsl #8"); - TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.b, z30.b, #0"); - TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.b, z30.b, #127"); - TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.b, z30.b, #255"); + TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.b, z30.b, #0"); + TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.b, z30.b, #127"); + TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.b, z30.b, #255"); - TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.h, z30.h, #0"); - TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.h, z30.h, #127"); - TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.h, z30.h, #255"); - TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "uqadd z30.h, z30.h, #1, lsl #8"); + TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.h, z30.h, #0"); + TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.h, z30.h, #127"); + TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.h, z30.h, #255"); + TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "uqadd z30.h, z30.h, #1, lsl #8"); TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 32512), "uqadd z30.h, z30.h, #127, lsl #8"); TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 65280), "uqadd z30.h, z30.h, #255, lsl #8"); - TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.s, z30.s, #0"); - TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.s, z30.s, #127"); - TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.s, z30.s, #255"); - TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "uqadd z30.s, z30.s, #1, lsl #8"); + TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.s, z30.s, #0"); + TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.s, z30.s, #127"); + TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.s, z30.s, #255"); + TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "uqadd z30.s, z30.s, #1, lsl #8"); TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 32512), "uqadd z30.s, z30.s, #127, lsl #8"); TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 65280), "uqadd z30.s, z30.s, #255, lsl #8"); - TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.d, z30.d, #0"); - TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.d, z30.d, #127"); - TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.d, z30.d, #255"); - TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "uqadd z30.d, z30.d, #1, lsl #8"); + TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "uqadd z30.d, z30.d, #0"); + TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "uqadd z30.d, z30.d, #127"); + TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "uqadd z30.d, z30.d, #255"); + TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "uqadd z30.d, z30.d, #1, lsl #8"); TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 32512), "uqadd z30.d, z30.d, #127, lsl #8"); TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 65280), "uqadd z30.d, z30.d, #255, lsl #8"); - TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.b, z30.b, #0"); - TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.b, z30.b, #127"); - TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.b, z30.b, #255"); + TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.b, z30.b, #0"); + TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.b, z30.b, #127"); + TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.b, z30.b, #255"); - TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.h, z30.h, #0"); - TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.h, z30.h, #127"); - TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.h, z30.h, #255"); - TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "sqsub z30.h, z30.h, #1, lsl #8"); + TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.h, z30.h, #0"); + TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.h, z30.h, #127"); + TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.h, z30.h, #255"); + TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "sqsub z30.h, z30.h, #1, lsl #8"); TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 32512), "sqsub z30.h, z30.h, #127, lsl #8"); TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 65280), "sqsub z30.h, z30.h, #255, lsl #8"); - TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.s, z30.s, #0"); - TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.s, z30.s, #127"); - TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.s, z30.s, #255"); - TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "sqsub z30.s, z30.s, #1, lsl #8"); + TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.s, z30.s, #0"); + TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.s, z30.s, #127"); + TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.s, z30.s, #255"); + TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "sqsub z30.s, z30.s, #1, lsl #8"); TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 32512), "sqsub z30.s, z30.s, #127, lsl #8"); TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 65280), "sqsub z30.s, z30.s, #255, lsl #8"); - TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.d, z30.d, #0"); - TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.d, z30.d, #127"); - TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.d, z30.d, #255"); - TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "sqsub z30.d, z30.d, #1, lsl #8"); + TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "sqsub z30.d, z30.d, #0"); + TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "sqsub z30.d, z30.d, #127"); + TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "sqsub z30.d, z30.d, #255"); + TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "sqsub z30.d, z30.d, #1, lsl #8"); TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 32512), "sqsub z30.d, z30.d, #127, lsl #8"); TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 65280), "sqsub z30.d, z30.d, #255, lsl #8"); - TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.b, z30.b, #0"); - TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.b, z30.b, #127"); - TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.b, z30.b, #255"); + TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.b, z30.b, #0"); + TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.b, z30.b, #127"); + TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.b, z30.b, #255"); - TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.h, z30.h, #0"); - TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.h, z30.h, #127"); - TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.h, z30.h, #255"); - TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "uqsub z30.h, z30.h, #1, lsl #8"); + TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.h, z30.h, #0"); + TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.h, z30.h, #127"); + TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.h, z30.h, #255"); + TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 256), "uqsub z30.h, z30.h, #1, lsl #8"); TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 32512), "uqsub z30.h, z30.h, #127, lsl #8"); TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 65280), "uqsub z30.h, z30.h, #255, lsl #8"); - TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.s, z30.s, #0"); - TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.s, z30.s, #127"); - TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.s, z30.s, #255"); - TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "uqsub z30.s, z30.s, #1, lsl #8"); + TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.s, z30.s, #0"); + TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.s, z30.s, #127"); + TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.s, z30.s, #255"); + TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 256), "uqsub z30.s, z30.s, #1, lsl #8"); TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 32512), "uqsub z30.s, z30.s, #127, lsl #8"); TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 65280), "uqsub z30.s, z30.s, #255, lsl #8"); - TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.d, z30.d, #0"); - TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.d, z30.d, #127"); - TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.d, z30.d, #255"); - TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "uqsub z30.d, z30.d, #1, lsl #8"); + TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "uqsub z30.d, z30.d, #0"); + TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "uqsub z30.d, z30.d, #127"); + TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "uqsub z30.d, z30.d, #255"); + TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 256), "uqsub z30.d, z30.d, #1, lsl #8"); TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 32512), "uqsub z30.d, z30.d, #127, lsl #8"); TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 65280), "uqsub z30.d, z30.d, #255, lsl #8"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer min/max immediate (unpredicated)") { - TEST_SINGLE(smax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "smax z30.b, z30.b, #0"); - TEST_SINGLE(smax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, -128), "smax z30.b, z30.b, #-128"); - TEST_SINGLE(smax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "smax z30.b, z30.b, #127"); + TEST_SINGLE(smax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "smax z30.b, z30.b, #0"); + TEST_SINGLE(smax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, -128), "smax z30.b, z30.b, #-128"); + TEST_SINGLE(smax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "smax z30.b, z30.b, #127"); - TEST_SINGLE(smax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "smax z30.h, z30.h, #0"); - TEST_SINGLE(smax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, -128), "smax z30.h, z30.h, #-128"); - TEST_SINGLE(smax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "smax z30.h, z30.h, #127"); + TEST_SINGLE(smax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "smax z30.h, z30.h, #0"); + TEST_SINGLE(smax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, -128), "smax z30.h, z30.h, #-128"); + TEST_SINGLE(smax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "smax z30.h, z30.h, #127"); - TEST_SINGLE(smax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "smax z30.s, z30.s, #0"); - TEST_SINGLE(smax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, -128), "smax z30.s, z30.s, #-128"); - TEST_SINGLE(smax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "smax z30.s, z30.s, #127"); + TEST_SINGLE(smax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "smax z30.s, z30.s, #0"); + TEST_SINGLE(smax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, -128), "smax z30.s, z30.s, #-128"); + TEST_SINGLE(smax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "smax z30.s, z30.s, #127"); - TEST_SINGLE(smax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "smax z30.d, z30.d, #0"); - TEST_SINGLE(smax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, -128), "smax z30.d, z30.d, #-128"); - TEST_SINGLE(smax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "smax z30.d, z30.d, #127"); + TEST_SINGLE(smax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "smax z30.d, z30.d, #0"); + TEST_SINGLE(smax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, -128), "smax z30.d, z30.d, #-128"); + TEST_SINGLE(smax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "smax z30.d, z30.d, #127"); - TEST_SINGLE(smin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "smin z30.b, z30.b, #0"); - TEST_SINGLE(smin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, -128), "smin z30.b, z30.b, #-128"); - TEST_SINGLE(smin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "smin z30.b, z30.b, #127"); + TEST_SINGLE(smin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "smin z30.b, z30.b, #0"); + TEST_SINGLE(smin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, -128), "smin z30.b, z30.b, #-128"); + TEST_SINGLE(smin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "smin z30.b, z30.b, #127"); - TEST_SINGLE(smin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "smin z30.h, z30.h, #0"); - TEST_SINGLE(smin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, -128), "smin z30.h, z30.h, #-128"); - TEST_SINGLE(smin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "smin z30.h, z30.h, #127"); + TEST_SINGLE(smin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "smin z30.h, z30.h, #0"); + TEST_SINGLE(smin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, -128), "smin z30.h, z30.h, #-128"); + TEST_SINGLE(smin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "smin z30.h, z30.h, #127"); - TEST_SINGLE(smin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "smin z30.s, z30.s, #0"); - TEST_SINGLE(smin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, -128), "smin z30.s, z30.s, #-128"); - TEST_SINGLE(smin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "smin z30.s, z30.s, #127"); + TEST_SINGLE(smin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "smin z30.s, z30.s, #0"); + TEST_SINGLE(smin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, -128), "smin z30.s, z30.s, #-128"); + TEST_SINGLE(smin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "smin z30.s, z30.s, #127"); - TEST_SINGLE(smin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "smin z30.d, z30.d, #0"); - TEST_SINGLE(smin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, -128), "smin z30.d, z30.d, #-128"); - TEST_SINGLE(smin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "smin z30.d, z30.d, #127"); + TEST_SINGLE(smin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "smin z30.d, z30.d, #0"); + TEST_SINGLE(smin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, -128), "smin z30.d, z30.d, #-128"); + TEST_SINGLE(smin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "smin z30.d, z30.d, #127"); - TEST_SINGLE(umax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "umax z30.b, z30.b, #0"); - TEST_SINGLE(umax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "umax z30.b, z30.b, #127"); - TEST_SINGLE(umax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "umax z30.b, z30.b, #255"); + TEST_SINGLE(umax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "umax z30.b, z30.b, #0"); + TEST_SINGLE(umax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "umax z30.b, z30.b, #127"); + TEST_SINGLE(umax(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "umax z30.b, z30.b, #255"); - TEST_SINGLE(umax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "umax z30.h, z30.h, #0"); - TEST_SINGLE(umax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "umax z30.h, z30.h, #127"); - TEST_SINGLE(umax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "umax z30.h, z30.h, #255"); + TEST_SINGLE(umax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "umax z30.h, z30.h, #0"); + TEST_SINGLE(umax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "umax z30.h, z30.h, #127"); + TEST_SINGLE(umax(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "umax z30.h, z30.h, #255"); - TEST_SINGLE(umax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "umax z30.s, z30.s, #0"); - TEST_SINGLE(umax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "umax z30.s, z30.s, #127"); - TEST_SINGLE(umax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "umax z30.s, z30.s, #255"); + TEST_SINGLE(umax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "umax z30.s, z30.s, #0"); + TEST_SINGLE(umax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "umax z30.s, z30.s, #127"); + TEST_SINGLE(umax(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "umax z30.s, z30.s, #255"); - TEST_SINGLE(umax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "umax z30.d, z30.d, #0"); - TEST_SINGLE(umax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "umax z30.d, z30.d, #127"); - TEST_SINGLE(umax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "umax z30.d, z30.d, #255"); + TEST_SINGLE(umax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "umax z30.d, z30.d, #0"); + TEST_SINGLE(umax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "umax z30.d, z30.d, #127"); + TEST_SINGLE(umax(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "umax z30.d, z30.d, #255"); - TEST_SINGLE(umin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "umin z30.b, z30.b, #0"); - TEST_SINGLE(umin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "umin z30.b, z30.b, #127"); - TEST_SINGLE(umin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "umin z30.b, z30.b, #255"); + TEST_SINGLE(umin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "umin z30.b, z30.b, #0"); + TEST_SINGLE(umin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "umin z30.b, z30.b, #127"); + TEST_SINGLE(umin(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 255), "umin z30.b, z30.b, #255"); - TEST_SINGLE(umin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "umin z30.h, z30.h, #0"); - TEST_SINGLE(umin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "umin z30.h, z30.h, #127"); - TEST_SINGLE(umin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "umin z30.h, z30.h, #255"); + TEST_SINGLE(umin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "umin z30.h, z30.h, #0"); + TEST_SINGLE(umin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "umin z30.h, z30.h, #127"); + TEST_SINGLE(umin(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 255), "umin z30.h, z30.h, #255"); - TEST_SINGLE(umin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "umin z30.s, z30.s, #0"); - TEST_SINGLE(umin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "umin z30.s, z30.s, #127"); - TEST_SINGLE(umin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "umin z30.s, z30.s, #255"); + TEST_SINGLE(umin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "umin z30.s, z30.s, #0"); + TEST_SINGLE(umin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "umin z30.s, z30.s, #127"); + TEST_SINGLE(umin(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 255), "umin z30.s, z30.s, #255"); - TEST_SINGLE(umin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "umin z30.d, z30.d, #0"); - TEST_SINGLE(umin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "umin z30.d, z30.d, #127"); - TEST_SINGLE(umin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "umin z30.d, z30.d, #255"); + TEST_SINGLE(umin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "umin z30.d, z30.d, #0"); + TEST_SINGLE(umin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "umin z30.d, z30.d, #127"); + TEST_SINGLE(umin(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 255), "umin z30.d, z30.d, #255"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer multiply immediate (unpredicated)") { - TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "mul z30.b, z30.b, #0"); - TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, -128), "mul z30.b, z30.b, #-128"); - TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "mul z30.b, z30.b, #127"); + TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 0), "mul z30.b, z30.b, #0"); + TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, -128), "mul z30.b, z30.b, #-128"); + TEST_SINGLE(mul(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, 127), "mul z30.b, z30.b, #127"); - TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "mul z30.h, z30.h, #0"); - TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, -128), "mul z30.h, z30.h, #-128"); - TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "mul z30.h, z30.h, #127"); + TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 0), "mul z30.h, z30.h, #0"); + TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, -128), "mul z30.h, z30.h, #-128"); + TEST_SINGLE(mul(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, 127), "mul z30.h, z30.h, #127"); - TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "mul z30.s, z30.s, #0"); - TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, -128), "mul z30.s, z30.s, #-128"); - TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "mul z30.s, z30.s, #127"); + TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 0), "mul z30.s, z30.s, #0"); + TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, -128), "mul z30.s, z30.s, #-128"); + TEST_SINGLE(mul(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, 127), "mul z30.s, z30.s, #127"); - TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "mul z30.d, z30.d, #0"); - TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, -128), "mul z30.d, z30.d, #-128"); - TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "mul z30.d, z30.d, #127"); + TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 0), "mul z30.d, z30.d, #0"); + TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, -128), "mul z30.d, z30.d, #-128"); + TEST_SINGLE(mul(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, 127), "mul z30.d, z30.d, #127"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE broadcast integer immediate (unpredicated)") { @@ -2342,12 +2314,12 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE broadcast integer immediat TEST_SINGLE(dup_imm(SubRegSize::i32Bit, ZReg::z30, 127), "mov z30.s, #127"); TEST_SINGLE(dup_imm(SubRegSize::i64Bit, ZReg::z30, 127), "mov z30.d, #127"); - //TEST_SINGLE(dup_imm(SubRegSize::i8Bit, ZReg::z30, -32768), "mov z30.b, #-128"); + // TEST_SINGLE(dup_imm(SubRegSize::i8Bit, ZReg::z30, -32768), "mov z30.b, #-128"); TEST_SINGLE(dup_imm(SubRegSize::i16Bit, ZReg::z30, -32768), "mov z30.h, #-128, lsl #8"); TEST_SINGLE(dup_imm(SubRegSize::i32Bit, ZReg::z30, -32768), "mov z30.s, #-128, lsl #8"); TEST_SINGLE(dup_imm(SubRegSize::i64Bit, ZReg::z30, -32768), "mov z30.d, #-128, lsl #8"); - //TEST_SINGLE(dup_imm(SubRegSize::i8Bit, ZReg::z30, 32512), "mov z30.b, #127"); + // TEST_SINGLE(dup_imm(SubRegSize::i8Bit, ZReg::z30, 32512), "mov z30.b, #127"); TEST_SINGLE(dup_imm(SubRegSize::i16Bit, ZReg::z30, 32512), "mov z30.h, #127, lsl #8"); TEST_SINGLE(dup_imm(SubRegSize::i32Bit, ZReg::z30, 32512), "mov z30.s, #127, lsl #8"); TEST_SINGLE(dup_imm(SubRegSize::i64Bit, ZReg::z30, 32512), "mov z30.d, #127, lsl #8"); @@ -2432,7 +2404,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE broadcast floating-point i } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate count") { - TEST_SINGLE(cntp(SubRegSize::i8Bit, XReg::x30, PReg::p15, PReg::p7), "cntp x30, p15, p7.b"); + TEST_SINGLE(cntp(SubRegSize::i8Bit, XReg::x30, PReg::p15, PReg::p7), "cntp x30, p15, p7.b"); TEST_SINGLE(cntp(SubRegSize::i16Bit, XReg::x30, PReg::p15, PReg::p7), "cntp x30, p15, p7.h"); TEST_SINGLE(cntp(SubRegSize::i32Bit, XReg::x30, PReg::p15, PReg::p7), "cntp x30, p15, p7.s"); TEST_SINGLE(cntp(SubRegSize::i64Bit, XReg::x30, PReg::p15, PReg::p7), "cntp x30, p15, p7.d"); @@ -2457,42 +2429,42 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE saturating inc/dec vector } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE saturating inc/dec register by predicate count") { - TEST_SINGLE(sqincp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "sqincp x30, p15.b"); + TEST_SINGLE(sqincp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "sqincp x30, p15.b"); TEST_SINGLE(sqincp(SubRegSize::i16Bit, XReg::x30, PReg::p15), "sqincp x30, p15.h"); TEST_SINGLE(sqincp(SubRegSize::i32Bit, XReg::x30, PReg::p15), "sqincp x30, p15.s"); TEST_SINGLE(sqincp(SubRegSize::i64Bit, XReg::x30, PReg::p15), "sqincp x30, p15.d"); - TEST_SINGLE(sqincp(SubRegSize::i8Bit, XReg::x30, PReg::p15, WReg::w30), "sqincp x30, p15.b, w30"); + TEST_SINGLE(sqincp(SubRegSize::i8Bit, XReg::x30, PReg::p15, WReg::w30), "sqincp x30, p15.b, w30"); TEST_SINGLE(sqincp(SubRegSize::i16Bit, XReg::x30, PReg::p15, WReg::w30), "sqincp x30, p15.h, w30"); TEST_SINGLE(sqincp(SubRegSize::i32Bit, XReg::x30, PReg::p15, WReg::w30), "sqincp x30, p15.s, w30"); TEST_SINGLE(sqincp(SubRegSize::i64Bit, XReg::x30, PReg::p15, WReg::w30), "sqincp x30, p15.d, w30"); - TEST_SINGLE(uqincp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "uqincp x30, p15.b"); + TEST_SINGLE(uqincp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "uqincp x30, p15.b"); TEST_SINGLE(uqincp(SubRegSize::i16Bit, XReg::x30, PReg::p15), "uqincp x30, p15.h"); TEST_SINGLE(uqincp(SubRegSize::i32Bit, XReg::x30, PReg::p15), "uqincp x30, p15.s"); TEST_SINGLE(uqincp(SubRegSize::i64Bit, XReg::x30, PReg::p15), "uqincp x30, p15.d"); - TEST_SINGLE(uqincp(SubRegSize::i8Bit, WReg::w30, PReg::p15), "uqincp w30, p15.b"); + TEST_SINGLE(uqincp(SubRegSize::i8Bit, WReg::w30, PReg::p15), "uqincp w30, p15.b"); TEST_SINGLE(uqincp(SubRegSize::i16Bit, WReg::w30, PReg::p15), "uqincp w30, p15.h"); TEST_SINGLE(uqincp(SubRegSize::i32Bit, WReg::w30, PReg::p15), "uqincp w30, p15.s"); TEST_SINGLE(uqincp(SubRegSize::i64Bit, WReg::w30, PReg::p15), "uqincp w30, p15.d"); - TEST_SINGLE(sqdecp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "sqdecp x30, p15.b"); + TEST_SINGLE(sqdecp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "sqdecp x30, p15.b"); TEST_SINGLE(sqdecp(SubRegSize::i16Bit, XReg::x30, PReg::p15), "sqdecp x30, p15.h"); TEST_SINGLE(sqdecp(SubRegSize::i32Bit, XReg::x30, PReg::p15), "sqdecp x30, p15.s"); TEST_SINGLE(sqdecp(SubRegSize::i64Bit, XReg::x30, PReg::p15), "sqdecp x30, p15.d"); - TEST_SINGLE(sqdecp(SubRegSize::i8Bit, XReg::x30, PReg::p15, WReg::w30), "sqdecp x30, p15.b, w30"); + TEST_SINGLE(sqdecp(SubRegSize::i8Bit, XReg::x30, PReg::p15, WReg::w30), "sqdecp x30, p15.b, w30"); TEST_SINGLE(sqdecp(SubRegSize::i16Bit, XReg::x30, PReg::p15, WReg::w30), "sqdecp x30, p15.h, w30"); TEST_SINGLE(sqdecp(SubRegSize::i32Bit, XReg::x30, PReg::p15, WReg::w30), "sqdecp x30, p15.s, w30"); TEST_SINGLE(sqdecp(SubRegSize::i64Bit, XReg::x30, PReg::p15, WReg::w30), "sqdecp x30, p15.d, w30"); - TEST_SINGLE(uqdecp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "uqdecp x30, p15.b"); + TEST_SINGLE(uqdecp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "uqdecp x30, p15.b"); TEST_SINGLE(uqdecp(SubRegSize::i16Bit, XReg::x30, PReg::p15), "uqdecp x30, p15.h"); TEST_SINGLE(uqdecp(SubRegSize::i32Bit, XReg::x30, PReg::p15), "uqdecp x30, p15.s"); TEST_SINGLE(uqdecp(SubRegSize::i64Bit, XReg::x30, PReg::p15), "uqdecp x30, p15.d"); - TEST_SINGLE(uqdecp(SubRegSize::i8Bit, WReg::w30, PReg::p15), "uqdecp w30, p15.b"); + TEST_SINGLE(uqdecp(SubRegSize::i8Bit, WReg::w30, PReg::p15), "uqdecp w30, p15.b"); TEST_SINGLE(uqdecp(SubRegSize::i16Bit, WReg::w30, PReg::p15), "uqdecp w30, p15.h"); TEST_SINGLE(uqdecp(SubRegSize::i32Bit, WReg::w30, PReg::p15), "uqdecp w30, p15.s"); TEST_SINGLE(uqdecp(SubRegSize::i64Bit, WReg::w30, PReg::p15), "uqdecp w30, p15.d"); @@ -2509,19 +2481,19 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE inc/dec vector by predicat } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE inc/dec register by predicate count") { - TEST_SINGLE(incp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "incp x30, p15.b"); + TEST_SINGLE(incp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "incp x30, p15.b"); TEST_SINGLE(incp(SubRegSize::i16Bit, XReg::x30, PReg::p15), "incp x30, p15.h"); TEST_SINGLE(incp(SubRegSize::i32Bit, XReg::x30, PReg::p15), "incp x30, p15.s"); TEST_SINGLE(incp(SubRegSize::i64Bit, XReg::x30, PReg::p15), "incp x30, p15.d"); - TEST_SINGLE(decp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "decp x30, p15.b"); + TEST_SINGLE(decp(SubRegSize::i8Bit, XReg::x30, PReg::p15), "decp x30, p15.b"); TEST_SINGLE(decp(SubRegSize::i16Bit, XReg::x30, PReg::p15), "decp x30, p15.h"); TEST_SINGLE(decp(SubRegSize::i32Bit, XReg::x30, PReg::p15), "decp x30, p15.s"); TEST_SINGLE(decp(SubRegSize::i64Bit, XReg::x30, PReg::p15), "decp x30, p15.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE FFR write from predicate") { - TEST_SINGLE(wrffr(PReg::p7), "wrffr p7.b"); + TEST_SINGLE(wrffr(PReg::p7), "wrffr p7.b"); TEST_SINGLE(wrffr(PReg::p15), "wrffr p15.b"); } @@ -2530,13 +2502,13 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE FFR initialise") { } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Integer Multiply-Add - Unpredicated") { - TEST_SINGLE(cdot(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cdot z30.s, z29.b, z28.b, #0"); - TEST_SINGLE(cdot(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cdot z30.s, z29.b, z28.b, #90"); + TEST_SINGLE(cdot(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cdot z30.s, z29.b, z28.b, #0"); + TEST_SINGLE(cdot(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cdot z30.s, z29.b, z28.b, #90"); TEST_SINGLE(cdot(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "cdot z30.s, z29.b, z28.b, #180"); TEST_SINGLE(cdot(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "cdot z30.s, z29.b, z28.b, #270"); - TEST_SINGLE(cdot(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cdot z30.d, z29.h, z28.h, #0"); - TEST_SINGLE(cdot(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cdot z30.d, z29.h, z28.h, #90"); + TEST_SINGLE(cdot(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cdot z30.d, z29.h, z28.h, #0"); + TEST_SINGLE(cdot(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cdot z30.d, z29.h, z28.h, #90"); TEST_SINGLE(cdot(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "cdot z30.d, z29.h, z28.h, #180"); TEST_SINGLE(cdot(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "cdot z30.d, z29.h, z28.h, #270"); } @@ -2560,43 +2532,43 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 saturating multiply-add i } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 complex integer multiply-add") { - TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.b, z29.b, z28.b, #0"); - TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.b, z29.b, z28.b, #90"); - TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "cmla z30.b, z29.b, z28.b, #180"); - TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "cmla z30.b, z29.b, z28.b, #270"); + TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.b, z29.b, z28.b, #0"); + TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.b, z29.b, z28.b, #90"); + TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "cmla z30.b, z29.b, z28.b, #180"); + TEST_SINGLE(cmla(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "cmla z30.b, z29.b, z28.b, #270"); - TEST_SINGLE(cmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.h, z29.h, z28.h, #0"); - TEST_SINGLE(cmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.h, z29.h, z28.h, #90"); + TEST_SINGLE(cmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.h, z29.h, z28.h, #0"); + TEST_SINGLE(cmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.h, z29.h, z28.h, #90"); TEST_SINGLE(cmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "cmla z30.h, z29.h, z28.h, #180"); TEST_SINGLE(cmla(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "cmla z30.h, z29.h, z28.h, #270"); - TEST_SINGLE(cmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.s, z29.s, z28.s, #0"); - TEST_SINGLE(cmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.s, z29.s, z28.s, #90"); + TEST_SINGLE(cmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.s, z29.s, z28.s, #0"); + TEST_SINGLE(cmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.s, z29.s, z28.s, #90"); TEST_SINGLE(cmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "cmla z30.s, z29.s, z28.s, #180"); TEST_SINGLE(cmla(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "cmla z30.s, z29.s, z28.s, #270"); - TEST_SINGLE(cmla(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.d, z29.d, z28.d, #0"); - TEST_SINGLE(cmla(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.d, z29.d, z28.d, #90"); + TEST_SINGLE(cmla(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "cmla z30.d, z29.d, z28.d, #0"); + TEST_SINGLE(cmla(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "cmla z30.d, z29.d, z28.d, #90"); TEST_SINGLE(cmla(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "cmla z30.d, z29.d, z28.d, #180"); TEST_SINGLE(cmla(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "cmla z30.d, z29.d, z28.d, #270"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.b, z29.b, z28.b, #0"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.b, z29.b, z28.b, #90"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "sqrdcmlah z30.b, z29.b, z28.b, #180"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "sqrdcmlah z30.b, z29.b, z28.b, #270"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.b, z29.b, z28.b, #0"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.b, z29.b, z28.b, #90"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "sqrdcmlah z30.b, z29.b, z28.b, #180"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "sqrdcmlah z30.b, z29.b, z28.b, #270"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.h, z29.h, z28.h, #0"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.h, z29.h, z28.h, #90"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.h, z29.h, z28.h, #0"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.h, z29.h, z28.h, #90"); TEST_SINGLE(sqrdcmlah(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "sqrdcmlah z30.h, z29.h, z28.h, #180"); TEST_SINGLE(sqrdcmlah(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "sqrdcmlah z30.h, z29.h, z28.h, #270"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.s, z29.s, z28.s, #0"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.s, z29.s, z28.s, #90"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.s, z29.s, z28.s, #0"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.s, z29.s, z28.s, #90"); TEST_SINGLE(sqrdcmlah(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "sqrdcmlah z30.s, z29.s, z28.s, #180"); TEST_SINGLE(sqrdcmlah(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "sqrdcmlah z30.s, z29.s, z28.s, #270"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.d, z29.d, z28.d, #0"); - TEST_SINGLE(sqrdcmlah(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.d, z29.d, z28.d, #90"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_0), "sqrdcmlah z30.d, z29.d, z28.d, #0"); + TEST_SINGLE(sqrdcmlah(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_90), "sqrdcmlah z30.d, z29.d, z28.d, #90"); TEST_SINGLE(sqrdcmlah(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_180), "sqrdcmlah z30.d, z29.d, z28.d, #180"); TEST_SINGLE(sqrdcmlah(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28, Rotation::ROTATE_270), "sqrdcmlah z30.d, z29.d, z28.d, #270"); } @@ -2654,12 +2626,12 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 saturating multiply-add l } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 saturating multiply-add high") { - TEST_SINGLE(sqrdmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlah z30.b, z29.b, z28.b"); + TEST_SINGLE(sqrdmlah(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlah z30.b, z29.b, z28.b"); TEST_SINGLE(sqrdmlah(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlah z30.h, z29.h, z28.h"); TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlah z30.s, z29.s, z28.s"); TEST_SINGLE(sqrdmlah(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlah z30.d, z29.d, z28.d"); - TEST_SINGLE(sqrdmlsh(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlsh z30.b, z29.b, z28.b"); + TEST_SINGLE(sqrdmlsh(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlsh z30.b, z29.b, z28.b"); TEST_SINGLE(sqrdmlsh(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlsh z30.h, z29.h, z28.h"); TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlsh z30.s, z29.s, z28.s"); TEST_SINGLE(sqrdmlsh(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqrdmlsh z30.d, z29.d, z28.d"); @@ -2679,260 +2651,260 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer pairwise add and TEST_SINGLE(uadalp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "uadalp z30.d, p6/m, z29.s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer unary operations (predicated)") { - TEST_SINGLE(urecpe(ZReg::z30, PReg::p6.Merging(), ZReg::z29), "urecpe z30.s, p6/m, z29.s"); + TEST_SINGLE(urecpe(ZReg::z30, PReg::p6.Merging(), ZReg::z29), "urecpe z30.s, p6/m, z29.s"); TEST_SINGLE(ursqrte(ZReg::z30, PReg::p6.Merging(), ZReg::z29), "ursqrte z30.s, p6/m, z29.s"); - TEST_SINGLE(sqabs(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqabs z30.b, p6/m, z29.b"); + TEST_SINGLE(sqabs(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqabs z30.b, p6/m, z29.b"); TEST_SINGLE(sqabs(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqabs z30.h, p6/m, z29.h"); TEST_SINGLE(sqabs(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqabs z30.s, p6/m, z29.s"); TEST_SINGLE(sqabs(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqabs z30.d, p6/m, z29.d"); - TEST_SINGLE(sqneg(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqneg z30.b, p6/m, z29.b"); + TEST_SINGLE(sqneg(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqneg z30.b, p6/m, z29.b"); TEST_SINGLE(sqneg(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqneg z30.h, p6/m, z29.h"); TEST_SINGLE(sqneg(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqneg z30.s, p6/m, z29.s"); TEST_SINGLE(sqneg(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "sqneg z30.d, p6/m, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 saturating/rounding bitwise shift left (predicated)") { - TEST_SINGLE(srshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(srshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(srshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(srshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(srshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(srshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(srshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(srshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshl z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(urshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(urshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(urshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(urshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(urshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(urshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(urshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(urshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshl z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(srshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(srshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(srshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(srshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(srshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(srshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(srshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(srshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "srshlr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(urshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(urshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(urshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(urshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(urshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(urshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(urshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(urshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "urshlr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(sqshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(sqshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(sqshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(sqshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(sqshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(sqshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(sqshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(sqshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshl z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(uqshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(uqshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(uqshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(uqshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(uqshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(uqshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(uqshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(uqshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshl z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(sqrshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(sqrshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(sqrshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(sqrshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(sqrshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(sqrshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(sqrshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(sqrshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshl z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(uqrshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(uqrshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(uqrshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(uqrshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(uqrshl(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(uqrshl(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(uqrshl(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(uqrshl(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshl z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(sqshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(sqshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(sqshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(sqshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(sqshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(sqshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(sqshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(sqshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqshlr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(uqshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.b, p6/m, z30.b, z29.b"); - TEST_SINGLE(uqshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.h, p6/m, z30.h, z29.h"); - TEST_SINGLE(uqshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.s, p6/m, z30.s, z29.s"); - TEST_SINGLE(uqshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.d, p6/m, z30.d, z29.d"); + TEST_SINGLE(uqshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(uqshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.h, p6/m, z30.h, z29.h"); + TEST_SINGLE(uqshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.s, p6/m, z30.s, z29.s"); + TEST_SINGLE(uqshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqshlr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(sqrshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshlr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(sqrshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshlr z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(sqrshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshlr z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(sqrshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshlr z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(sqrshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "sqrshlr z30.d, p6/m, z30.d, z29.d"); - TEST_SINGLE(uqrshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshlr z30.b, p6/m, z30.b, z29.b"); + TEST_SINGLE(uqrshlr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshlr z30.b, p6/m, z30.b, z29.b"); TEST_SINGLE(uqrshlr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshlr z30.h, p6/m, z30.h, z29.h"); TEST_SINGLE(uqrshlr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshlr z30.s, p6/m, z30.s, z29.s"); TEST_SINGLE(uqrshlr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z29), "uqrshlr z30.d, p6/m, z30.d, z29.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer halving add/subtract (predicated)") { - TEST_SINGLE(shadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(shadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(shadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(shadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(shadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(shadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(shadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(shadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(shadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(shadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shadd z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(uhadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(uhadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(uhadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(uhadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(uhadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(shsub(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(shsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(shsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(shsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(shsub(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(uhadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(uhadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(uhadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(uhadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(uhadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhadd z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(shsub(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(shsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(shsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(shsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(shsub(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsub z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(uhsub(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(uhsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(uhsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(uhsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(uhsub(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(uhsub(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(uhsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(uhsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(uhsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(uhsub(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsub z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(srhadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(srhadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(srhadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(srhadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(srhadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(srhadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(srhadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(srhadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(srhadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(srhadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "srhadd z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(urhadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(urhadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(urhadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(urhadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(urhadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(urhadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(urhadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(urhadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(urhadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(urhadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "urhadd z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(shsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(shsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(shsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(shsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(shsubr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(shsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(shsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(shsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(shsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(shsubr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "shsubr z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(uhsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(uhsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(uhsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(uhsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(uhsubr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(uhsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(uhsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(uhsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(uhsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(uhsubr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uhsubr z30.q, p6/m, z30.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer pairwise arithmetic") { - TEST_SINGLE(addp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(addp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(addp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(addp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(addp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(addp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(addp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(addp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(addp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(addp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "addp z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(smaxp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(smaxp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(smaxp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(smaxp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(smaxp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(smaxp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(smaxp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(smaxp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(smaxp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(smaxp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "smaxp z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(umaxp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(umaxp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(umaxp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(umaxp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(umaxp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(umaxp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(umaxp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(umaxp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(umaxp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(umaxp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "umaxp z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(sminp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(sminp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(sminp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(sminp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(sminp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(sminp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(sminp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(sminp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(sminp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(sminp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "sminp z30.q, p6/m, z30.q, z28.q"); - TEST_SINGLE(uminp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(uminp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(uminp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(uminp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(uminp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.q, p6/m, z30.q, z28.q"); + TEST_SINGLE(uminp(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(uminp(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(uminp(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(uminp(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(uminp(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "uminp z30.q, p6/m, z30.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 saturating add/subtract") { - TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqadd z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(sqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqadd z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(sqadd(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqadd z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(sqadd(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqadd z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(sqadd(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqadd z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqadd z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(uqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqadd z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(uqadd(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqadd z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(uqadd(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqadd z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(uqadd(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqadd z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsub z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(sqsub(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsub z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(sqsub(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsub z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(sqsub(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsub z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(sqsub(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsub z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsub z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(uqsub(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsub z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(uqsub(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsub z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(uqsub(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsub z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(uqsub(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsub z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(suqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "suqadd z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(suqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "suqadd z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(suqadd(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "suqadd z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(suqadd(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "suqadd z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(suqadd(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "suqadd z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(usqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "usqadd z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(usqadd(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "usqadd z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(usqadd(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "usqadd z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(usqadd(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "usqadd z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(usqadd(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "usqadd z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(sqsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsubr z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(sqsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsubr z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(sqsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsubr z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(sqsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsubr z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(sqsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "sqsubr z30.d, p7/m, z30.d, z28.d"); - TEST_SINGLE(uqsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsubr z30.b, p7/m, z30.b, z28.b"); + TEST_SINGLE(uqsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsubr z30.b, p7/m, z30.b, z28.b"); TEST_SINGLE(uqsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsubr z30.h, p7/m, z30.h, z28.h"); TEST_SINGLE(uqsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsubr z30.s, p7/m, z30.s, z28.s"); TEST_SINGLE(uqsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p7.Merging(), ZReg::z30, ZReg::z28), "uqsubr z30.d, p7/m, z30.d, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer add/subtract long") { - //TEST_SINGLE(saddlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlb z30.b, z29.b, z28.b"); + // TEST_SINGLE(saddlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlb z30.b, z29.b, z28.b"); TEST_SINGLE(saddlb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlb z30.h, z29.b, z28.b"); TEST_SINGLE(saddlb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlb z30.s, z29.h, z28.h"); TEST_SINGLE(saddlb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlb z30.d, z29.s, z28.s"); - //TEST_SINGLE(saddlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlt z30.b, z29.b, z28.b"); + // TEST_SINGLE(saddlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlt z30.b, z29.b, z28.b"); TEST_SINGLE(saddlt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlt z30.h, z29.b, z28.b"); TEST_SINGLE(saddlt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlt z30.s, z29.h, z28.h"); TEST_SINGLE(saddlt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "saddlt z30.d, z29.s, z28.s"); - //TEST_SINGLE(uaddlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlb z30.b, z29.b, z28.b"); + // TEST_SINGLE(uaddlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlb z30.b, z29.b, z28.b"); TEST_SINGLE(uaddlb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlb z30.h, z29.b, z28.b"); TEST_SINGLE(uaddlb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlb z30.s, z29.h, z28.h"); TEST_SINGLE(uaddlb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlb z30.d, z29.s, z28.s"); - //TEST_SINGLE(uaddlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlt z30.b, z29.b, z28.b"); + // TEST_SINGLE(uaddlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlt z30.b, z29.b, z28.b"); TEST_SINGLE(uaddlt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlt z30.h, z29.b, z28.b"); TEST_SINGLE(uaddlt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlt z30.s, z29.h, z28.h"); TEST_SINGLE(uaddlt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uaddlt z30.d, z29.s, z28.s"); - //TEST_SINGLE(ssublb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublb z30.b, z29.b, z28.b"); + // TEST_SINGLE(ssublb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublb z30.b, z29.b, z28.b"); TEST_SINGLE(ssublb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublb z30.h, z29.b, z28.b"); TEST_SINGLE(ssublb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublb z30.s, z29.h, z28.h"); TEST_SINGLE(ssublb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublb z30.d, z29.s, z28.s"); - //TEST_SINGLE(ssublt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublt z30.b, z29.b, z28.b"); + // TEST_SINGLE(ssublt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublt z30.b, z29.b, z28.b"); TEST_SINGLE(ssublt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublt z30.h, z29.b, z28.b"); TEST_SINGLE(ssublt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublt z30.s, z29.h, z28.h"); TEST_SINGLE(ssublt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssublt z30.d, z29.s, z28.s"); - //TEST_SINGLE(usublb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublb z30.b, z29.b, z28.b"); + // TEST_SINGLE(usublb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublb z30.b, z29.b, z28.b"); TEST_SINGLE(usublb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublb z30.h, z29.b, z28.b"); TEST_SINGLE(usublb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublb z30.s, z29.h, z28.h"); TEST_SINGLE(usublb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublb z30.d, z29.s, z28.s"); - //TEST_SINGLE(usublt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublt z30.b, z29.b, z28.b"); + // TEST_SINGLE(usublt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublt z30.b, z29.b, z28.b"); TEST_SINGLE(usublt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublt z30.h, z29.b, z28.b"); TEST_SINGLE(usublt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublt z30.s, z29.h, z28.h"); TEST_SINGLE(usublt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usublt z30.d, z29.s, z28.s"); - //TEST_SINGLE(sabdlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlb z30.b, z29.b, z28.b"); + // TEST_SINGLE(sabdlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlb z30.b, z29.b, z28.b"); TEST_SINGLE(sabdlb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlb z30.h, z29.b, z28.b"); TEST_SINGLE(sabdlb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlb z30.s, z29.h, z28.h"); TEST_SINGLE(sabdlb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlb z30.d, z29.s, z28.s"); - //TEST_SINGLE(sabdlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlt z30.b, z29.b, z28.b"); + // TEST_SINGLE(sabdlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlt z30.b, z29.b, z28.b"); TEST_SINGLE(sabdlt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlt z30.h, z29.b, z28.b"); TEST_SINGLE(sabdlt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlt z30.s, z29.h, z28.h"); TEST_SINGLE(sabdlt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sabdlt z30.d, z29.s, z28.s"); - //TEST_SINGLE(uabdlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlb z30.b, z29.b, z28.b"); + // TEST_SINGLE(uabdlb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlb z30.b, z29.b, z28.b"); TEST_SINGLE(uabdlb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlb z30.h, z29.b, z28.b"); TEST_SINGLE(uabdlb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlb z30.s, z29.h, z28.h"); TEST_SINGLE(uabdlb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlb z30.d, z29.s, z28.s"); - //TEST_SINGLE(uabdlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlt z30.b, z29.b, z28.b"); + // TEST_SINGLE(uabdlt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlt z30.b, z29.b, z28.b"); TEST_SINGLE(uabdlt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlt z30.h, z29.b, z28.b"); TEST_SINGLE(uabdlt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlt z30.s, z29.h, z28.h"); TEST_SINGLE(uabdlt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "uabdlt z30.d, z29.s, z28.s"); @@ -2971,73 +2943,73 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer add/subtract wide TEST_SINGLE(usubwt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "usubwt z30.d, z29.d, z28.s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer multiply long") { - //TEST_SINGLE(sqdmullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullb z30.b, z29.b, z28.b"); + // TEST_SINGLE(sqdmullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullb z30.b, z29.b, z28.b"); TEST_SINGLE(sqdmullb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullb z30.h, z29.b, z28.b"); TEST_SINGLE(sqdmullb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullb z30.s, z29.h, z28.h"); TEST_SINGLE(sqdmullb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullb z30.d, z29.s, z28.s"); - //TEST_SINGLE(sqdmullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullt z30.b, z29.b, z28.b"); + // TEST_SINGLE(sqdmullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullt z30.b, z29.b, z28.b"); TEST_SINGLE(sqdmullt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullt z30.h, z29.b, z28.b"); TEST_SINGLE(sqdmullt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullt z30.s, z29.h, z28.h"); TEST_SINGLE(sqdmullt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "sqdmullt z30.d, z29.s, z28.s"); - //TEST_SINGLE(pmullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullb z30.b, z29.b, z28.b"); + // TEST_SINGLE(pmullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullb z30.b, z29.b, z28.b"); TEST_SINGLE(pmullb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullb z30.h, z29.b, z28.b"); TEST_SINGLE(pmullb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullb z30.s, z29.h, z28.h"); TEST_SINGLE(pmullb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullb z30.d, z29.s, z28.s"); - //TEST_SINGLE(pmullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullt z30.b, z29.b, z28.b"); + // TEST_SINGLE(pmullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullt z30.b, z29.b, z28.b"); TEST_SINGLE(pmullt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullt z30.h, z29.b, z28.b"); TEST_SINGLE(pmullt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullt z30.s, z29.h, z28.h"); TEST_SINGLE(pmullt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "pmullt z30.d, z29.s, z28.s"); - //TEST_SINGLE(smullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullb z30.b, z29.b, z28.b"); + // TEST_SINGLE(smullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullb z30.b, z29.b, z28.b"); TEST_SINGLE(smullb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullb z30.h, z29.b, z28.b"); TEST_SINGLE(smullb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullb z30.s, z29.h, z28.h"); TEST_SINGLE(smullb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullb z30.d, z29.s, z28.s"); - //TEST_SINGLE(smullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullt z30.b, z29.b, z28.b"); + // TEST_SINGLE(smullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullt z30.b, z29.b, z28.b"); TEST_SINGLE(smullt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullt z30.h, z29.b, z28.b"); TEST_SINGLE(smullt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullt z30.s, z29.h, z28.h"); TEST_SINGLE(smullt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "smullt z30.d, z29.s, z28.s"); - //TEST_SINGLE(umullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullb z30.b, z29.b, z28.b"); + // TEST_SINGLE(umullb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullb z30.b, z29.b, z28.b"); TEST_SINGLE(umullb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullb z30.h, z29.b, z28.b"); TEST_SINGLE(umullb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullb z30.s, z29.h, z28.h"); TEST_SINGLE(umullb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullb z30.d, z29.s, z28.s"); - //TEST_SINGLE(umullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullt z30.b, z29.b, z28.b"); + // TEST_SINGLE(umullt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullt z30.b, z29.b, z28.b"); TEST_SINGLE(umullt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullt z30.h, z29.b, z28.b"); TEST_SINGLE(umullt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullt z30.s, z29.h, z28.h"); TEST_SINGLE(umullt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "umullt z30.d, z29.s, z28.s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise shift left long") { - TEST_SINGLE(sshllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "sshllb z30.h, z29.b, #0"); - TEST_SINGLE(sshllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "sshllb z30.h, z29.b, #7"); - TEST_SINGLE(sshllb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "sshllb z30.s, z29.h, #0"); + TEST_SINGLE(sshllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "sshllb z30.h, z29.b, #0"); + TEST_SINGLE(sshllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "sshllb z30.h, z29.b, #7"); + TEST_SINGLE(sshllb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "sshllb z30.s, z29.h, #0"); TEST_SINGLE(sshllb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 15), "sshllb z30.s, z29.h, #15"); - TEST_SINGLE(sshllb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "sshllb z30.d, z29.s, #0"); + TEST_SINGLE(sshllb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "sshllb z30.d, z29.s, #0"); TEST_SINGLE(sshllb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 31), "sshllb z30.d, z29.s, #31"); - TEST_SINGLE(sshllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "sshllt z30.h, z29.b, #0"); - TEST_SINGLE(sshllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "sshllt z30.h, z29.b, #7"); - TEST_SINGLE(sshllt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "sshllt z30.s, z29.h, #0"); + TEST_SINGLE(sshllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "sshllt z30.h, z29.b, #0"); + TEST_SINGLE(sshllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "sshllt z30.h, z29.b, #7"); + TEST_SINGLE(sshllt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "sshllt z30.s, z29.h, #0"); TEST_SINGLE(sshllt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 15), "sshllt z30.s, z29.h, #15"); - TEST_SINGLE(sshllt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "sshllt z30.d, z29.s, #0"); + TEST_SINGLE(sshllt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "sshllt z30.d, z29.s, #0"); TEST_SINGLE(sshllt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 31), "sshllt z30.d, z29.s, #31"); - TEST_SINGLE(ushllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "ushllb z30.h, z29.b, #0"); - TEST_SINGLE(ushllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "ushllb z30.h, z29.b, #7"); - TEST_SINGLE(ushllb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "ushllb z30.s, z29.h, #0"); + TEST_SINGLE(ushllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "ushllb z30.h, z29.b, #0"); + TEST_SINGLE(ushllb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "ushllb z30.h, z29.b, #7"); + TEST_SINGLE(ushllb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "ushllb z30.s, z29.h, #0"); TEST_SINGLE(ushllb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 15), "ushllb z30.s, z29.h, #15"); - TEST_SINGLE(ushllb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "ushllb z30.d, z29.s, #0"); + TEST_SINGLE(ushllb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "ushllb z30.d, z29.s, #0"); TEST_SINGLE(ushllb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 31), "ushllb z30.d, z29.s, #31"); - TEST_SINGLE(ushllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "ushllt z30.h, z29.b, #0"); - TEST_SINGLE(ushllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "ushllt z30.h, z29.b, #7"); - TEST_SINGLE(ushllt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "ushllt z30.s, z29.h, #0"); + TEST_SINGLE(ushllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "ushllt z30.h, z29.b, #0"); + TEST_SINGLE(ushllt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "ushllt z30.h, z29.b, #7"); + TEST_SINGLE(ushllt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "ushllt z30.s, z29.h, #0"); TEST_SINGLE(ushllt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 15), "ushllt z30.s, z29.h, #15"); - TEST_SINGLE(ushllt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "ushllt z30.d, z29.s, #0"); + TEST_SINGLE(ushllt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "ushllt z30.d, z29.s, #0"); TEST_SINGLE(ushllt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 31), "ushllt z30.d, z29.s, #31"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer add/subtract interleaved long") { @@ -3054,74 +3026,74 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer add/subtract inte TEST_SINGLE(ssubltb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "ssubltb z30.d, z29.s, z28.s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise exclusive-or interleaved") { - TEST_SINGLE(eorbt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eorbt z30.b, z29.b, z28.b"); + TEST_SINGLE(eorbt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eorbt z30.b, z29.b, z28.b"); TEST_SINGLE(eorbt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eorbt z30.h, z29.h, z28.h"); TEST_SINGLE(eorbt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eorbt z30.s, z29.s, z28.s"); TEST_SINGLE(eorbt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eorbt z30.d, z29.d, z28.d"); - TEST_SINGLE(eortb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eortb z30.b, z29.b, z28.b"); + TEST_SINGLE(eortb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eortb z30.b, z29.b, z28.b"); TEST_SINGLE(eortb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eortb z30.h, z29.h, z28.h"); TEST_SINGLE(eortb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eortb z30.s, z29.s, z28.s"); TEST_SINGLE(eortb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "eortb z30.d, z29.d, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer matrix multiply accumulate") { - TEST_SINGLE(smmla(ZReg::z30, ZReg::z29, ZReg::z28), "smmla z30.s, z29.b, z28.b"); + TEST_SINGLE(smmla(ZReg::z30, ZReg::z29, ZReg::z28), "smmla z30.s, z29.b, z28.b"); TEST_SINGLE(usmmla(ZReg::z30, ZReg::z29, ZReg::z28), "usmmla z30.s, z29.b, z28.b"); - TEST_SINGLE(ummla(ZReg::z30, ZReg::z29, ZReg::z28), "ummla z30.s, z29.b, z28.b"); + TEST_SINGLE(ummla(ZReg::z30, ZReg::z29, ZReg::z28), "ummla z30.s, z29.b, z28.b"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise permute") { - TEST_SINGLE(bext(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bext z30.b, z29.b, z28.b"); + TEST_SINGLE(bext(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bext z30.b, z29.b, z28.b"); TEST_SINGLE(bext(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bext z30.h, z29.h, z28.h"); TEST_SINGLE(bext(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bext z30.s, z29.s, z28.s"); TEST_SINGLE(bext(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bext z30.d, z29.d, z28.d"); - TEST_SINGLE(bdep(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bdep z30.b, z29.b, z28.b"); + TEST_SINGLE(bdep(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bdep z30.b, z29.b, z28.b"); TEST_SINGLE(bdep(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bdep z30.h, z29.h, z28.h"); TEST_SINGLE(bdep(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bdep z30.s, z29.s, z28.s"); TEST_SINGLE(bdep(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bdep z30.d, z29.d, z28.d"); - TEST_SINGLE(bgrp(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bgrp z30.b, z29.b, z28.b"); + TEST_SINGLE(bgrp(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bgrp z30.b, z29.b, z28.b"); TEST_SINGLE(bgrp(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bgrp z30.h, z29.h, z28.h"); TEST_SINGLE(bgrp(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bgrp z30.s, z29.s, z28.s"); TEST_SINGLE(bgrp(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, ZReg::z28), "bgrp z30.d, z29.d, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 complex integer add") { - TEST_SINGLE(cadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.b, z30.b, z29.b, #90"); - TEST_SINGLE(cadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.h, z30.h, z29.h, #90"); - TEST_SINGLE(cadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.s, z30.s, z29.s, #90"); - TEST_SINGLE(cadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.d, z30.d, z29.d, #90"); + TEST_SINGLE(cadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.b, z30.b, z29.b, #90"); + TEST_SINGLE(cadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.h, z30.h, z29.h, #90"); + TEST_SINGLE(cadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.s, z30.s, z29.s, #90"); + TEST_SINGLE(cadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "cadd z30.d, z30.d, z29.d, #90"); - TEST_SINGLE(cadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.b, z30.b, z29.b, #270"); - TEST_SINGLE(cadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.h, z30.h, z29.h, #270"); - TEST_SINGLE(cadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.s, z30.s, z29.s, #270"); - TEST_SINGLE(cadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.d, z30.d, z29.d, #270"); + TEST_SINGLE(cadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.b, z30.b, z29.b, #270"); + TEST_SINGLE(cadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.h, z30.h, z29.h, #270"); + TEST_SINGLE(cadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.s, z30.s, z29.s, #270"); + TEST_SINGLE(cadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "cadd z30.d, z30.d, z29.d, #270"); - TEST_SINGLE(sqcadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.b, z30.b, z29.b, #90"); - TEST_SINGLE(sqcadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.h, z30.h, z29.h, #90"); - TEST_SINGLE(sqcadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.s, z30.s, z29.s, #90"); - TEST_SINGLE(sqcadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.d, z30.d, z29.d, #90"); + TEST_SINGLE(sqcadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.b, z30.b, z29.b, #90"); + TEST_SINGLE(sqcadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.h, z30.h, z29.h, #90"); + TEST_SINGLE(sqcadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.s, z30.s, z29.s, #90"); + TEST_SINGLE(sqcadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_90), "sqcadd z30.d, z30.d, z29.d, #90"); - TEST_SINGLE(sqcadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "sqcadd z30.b, z30.b, z29.b, #270"); + TEST_SINGLE(sqcadd(SubRegSize::i8Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "sqcadd z30.b, z30.b, z29.b, #270"); TEST_SINGLE(sqcadd(SubRegSize::i16Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "sqcadd z30.h, z30.h, z29.h, #270"); TEST_SINGLE(sqcadd(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "sqcadd z30.s, z30.s, z29.s, #270"); TEST_SINGLE(sqcadd(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z29, Rotation::ROTATE_270), "sqcadd z30.d, z30.d, z29.d, #270"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer absolute difference and accumulate long") { - TEST_SINGLE(sabalb(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalb z28.h, z29.b, z30.b"); - TEST_SINGLE(sabalb(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalb z28.s, z29.h, z30.h"); - TEST_SINGLE(sabalb(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalb z28.d, z29.s, z30.s"); + TEST_SINGLE(sabalb(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalb z28.h, z29.b, z30.b"); + TEST_SINGLE(sabalb(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalb z28.s, z29.h, z30.h"); + TEST_SINGLE(sabalb(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalb z28.d, z29.s, z30.s"); - TEST_SINGLE(sabalt(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalt z28.h, z29.b, z30.b"); - TEST_SINGLE(sabalt(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalt z28.s, z29.h, z30.h"); - TEST_SINGLE(sabalt(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalt z28.d, z29.s, z30.s"); + TEST_SINGLE(sabalt(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalt z28.h, z29.b, z30.b"); + TEST_SINGLE(sabalt(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalt z28.s, z29.h, z30.h"); + TEST_SINGLE(sabalt(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sabalt z28.d, z29.s, z30.s"); - TEST_SINGLE(uabalb(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalb z28.h, z29.b, z30.b"); - TEST_SINGLE(uabalb(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalb z28.s, z29.h, z30.h"); - TEST_SINGLE(uabalb(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalb z28.d, z29.s, z30.s"); + TEST_SINGLE(uabalb(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalb z28.h, z29.b, z30.b"); + TEST_SINGLE(uabalb(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalb z28.s, z29.h, z30.h"); + TEST_SINGLE(uabalb(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalb z28.d, z29.s, z30.s"); - TEST_SINGLE(uabalt(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalt z28.h, z29.b, z30.b"); - TEST_SINGLE(uabalt(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalt z28.s, z29.h, z30.h"); - TEST_SINGLE(uabalt(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalt z28.d, z29.s, z30.s"); + TEST_SINGLE(uabalt(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalt z28.h, z29.b, z30.b"); + TEST_SINGLE(uabalt(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalt z28.s, z29.h, z30.h"); + TEST_SINGLE(uabalt(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uabalt z28.d, z29.s, z30.s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer add/subtract long with carry") { TEST_SINGLE(adclb(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "adclb z28.s, z29.s, z30.s"); @@ -3137,76 +3109,76 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer add/subtract long TEST_SINGLE(sbclt(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "sbclt z28.d, z29.d, z30.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise shift right and accumulate") { - TEST_SINGLE(ssra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.b, z29.b, #1"); - TEST_SINGLE(ssra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "ssra z30.b, z29.b, #8"); - TEST_SINGLE(ssra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.h, z29.h, #1"); - TEST_SINGLE(ssra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "ssra z30.h, z29.h, #16"); - TEST_SINGLE(ssra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.s, z29.s, #1"); - TEST_SINGLE(ssra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "ssra z30.s, z29.s, #32"); - TEST_SINGLE(ssra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.d, z29.d, #1"); - TEST_SINGLE(ssra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "ssra z30.d, z29.d, #64"); + TEST_SINGLE(ssra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.b, z29.b, #1"); + TEST_SINGLE(ssra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "ssra z30.b, z29.b, #8"); + TEST_SINGLE(ssra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.h, z29.h, #1"); + TEST_SINGLE(ssra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "ssra z30.h, z29.h, #16"); + TEST_SINGLE(ssra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.s, z29.s, #1"); + TEST_SINGLE(ssra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "ssra z30.s, z29.s, #32"); + TEST_SINGLE(ssra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "ssra z30.d, z29.d, #1"); + TEST_SINGLE(ssra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "ssra z30.d, z29.d, #64"); - TEST_SINGLE(usra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "usra z30.b, z29.b, #1"); - TEST_SINGLE(usra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "usra z30.b, z29.b, #8"); - TEST_SINGLE(usra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "usra z30.h, z29.h, #1"); - TEST_SINGLE(usra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "usra z30.h, z29.h, #16"); - TEST_SINGLE(usra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "usra z30.s, z29.s, #1"); - TEST_SINGLE(usra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "usra z30.s, z29.s, #32"); - TEST_SINGLE(usra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "usra z30.d, z29.d, #1"); - TEST_SINGLE(usra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "usra z30.d, z29.d, #64"); + TEST_SINGLE(usra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "usra z30.b, z29.b, #1"); + TEST_SINGLE(usra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "usra z30.b, z29.b, #8"); + TEST_SINGLE(usra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "usra z30.h, z29.h, #1"); + TEST_SINGLE(usra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "usra z30.h, z29.h, #16"); + TEST_SINGLE(usra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "usra z30.s, z29.s, #1"); + TEST_SINGLE(usra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "usra z30.s, z29.s, #32"); + TEST_SINGLE(usra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "usra z30.d, z29.d, #1"); + TEST_SINGLE(usra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "usra z30.d, z29.d, #64"); - TEST_SINGLE(srsra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.b, z29.b, #1"); - TEST_SINGLE(srsra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "srsra z30.b, z29.b, #8"); - TEST_SINGLE(srsra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.h, z29.h, #1"); + TEST_SINGLE(srsra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.b, z29.b, #1"); + TEST_SINGLE(srsra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "srsra z30.b, z29.b, #8"); + TEST_SINGLE(srsra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.h, z29.h, #1"); TEST_SINGLE(srsra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "srsra z30.h, z29.h, #16"); - TEST_SINGLE(srsra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.s, z29.s, #1"); + TEST_SINGLE(srsra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.s, z29.s, #1"); TEST_SINGLE(srsra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "srsra z30.s, z29.s, #32"); - TEST_SINGLE(srsra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.d, z29.d, #1"); + TEST_SINGLE(srsra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "srsra z30.d, z29.d, #1"); TEST_SINGLE(srsra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "srsra z30.d, z29.d, #64"); - TEST_SINGLE(ursra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.b, z29.b, #1"); - TEST_SINGLE(ursra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "ursra z30.b, z29.b, #8"); - TEST_SINGLE(ursra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.h, z29.h, #1"); + TEST_SINGLE(ursra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.b, z29.b, #1"); + TEST_SINGLE(ursra(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "ursra z30.b, z29.b, #8"); + TEST_SINGLE(ursra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.h, z29.h, #1"); TEST_SINGLE(ursra(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "ursra z30.h, z29.h, #16"); - TEST_SINGLE(ursra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.s, z29.s, #1"); + TEST_SINGLE(ursra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.s, z29.s, #1"); TEST_SINGLE(ursra(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "ursra z30.s, z29.s, #32"); - TEST_SINGLE(ursra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.d, z29.d, #1"); + TEST_SINGLE(ursra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "ursra z30.d, z29.d, #1"); TEST_SINGLE(ursra(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "ursra z30.d, z29.d, #64"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise shift and insert") { - TEST_SINGLE(sri(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "sri z30.b, z29.b, #1");\ - TEST_SINGLE(sri(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 4), "sri z30.b, z29.b, #4"); - TEST_SINGLE(sri(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "sri z30.b, z29.b, #8"); - TEST_SINGLE(sri(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "sri z30.h, z29.h, #1"); + TEST_SINGLE(sri(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "sri z30.b, z29.b, #1"); + TEST_SINGLE(sri(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 4), "sri z30.b, z29.b, #4"); + TEST_SINGLE(sri(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 8), "sri z30.b, z29.b, #8"); + TEST_SINGLE(sri(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 1), "sri z30.h, z29.h, #1"); TEST_SINGLE(sri(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 15), "sri z30.h, z29.h, #15"); TEST_SINGLE(sri(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 16), "sri z30.h, z29.h, #16"); - TEST_SINGLE(sri(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "sri z30.s, z29.s, #1"); + TEST_SINGLE(sri(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 1), "sri z30.s, z29.s, #1"); TEST_SINGLE(sri(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 15), "sri z30.s, z29.s, #15"); TEST_SINGLE(sri(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "sri z30.s, z29.s, #32"); - TEST_SINGLE(sri(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "sri z30.d, z29.d, #1"); + TEST_SINGLE(sri(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 1), "sri z30.d, z29.d, #1"); TEST_SINGLE(sri(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 31), "sri z30.d, z29.d, #31"); TEST_SINGLE(sri(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 64), "sri z30.d, z29.d, #64"); - TEST_SINGLE(sli(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 0), "sli z30.b, z29.b, #0"); - TEST_SINGLE(sli(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 4), "sli z30.b, z29.b, #4"); - TEST_SINGLE(sli(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 7), "sli z30.b, z29.b, #7"); - TEST_SINGLE(sli(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "sli z30.h, z29.h, #0"); - TEST_SINGLE(sli(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "sli z30.h, z29.h, #7"); + TEST_SINGLE(sli(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 0), "sli z30.b, z29.b, #0"); + TEST_SINGLE(sli(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 4), "sli z30.b, z29.b, #4"); + TEST_SINGLE(sli(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 7), "sli z30.b, z29.b, #7"); + TEST_SINGLE(sli(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 0), "sli z30.h, z29.h, #0"); + TEST_SINGLE(sli(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 7), "sli z30.h, z29.h, #7"); TEST_SINGLE(sli(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, 15), "sli z30.h, z29.h, #15"); - TEST_SINGLE(sli(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "sli z30.s, z29.s, #0"); + TEST_SINGLE(sli(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 0), "sli z30.s, z29.s, #0"); TEST_SINGLE(sli(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 15), "sli z30.s, z29.s, #15"); TEST_SINGLE(sli(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 31), "sli z30.s, z29.s, #31"); - TEST_SINGLE(sli(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "sli z30.d, z29.d, #0"); + TEST_SINGLE(sli(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 0), "sli z30.d, z29.d, #0"); TEST_SINGLE(sli(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 31), "sli z30.d, z29.d, #31"); TEST_SINGLE(sli(SubRegSize::i64Bit, ZReg::z30, ZReg::z29, 63), "sli z30.d, z29.d, #63"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer absolute difference and accumulate") { - TEST_SINGLE(saba(SubRegSize::i8Bit, ZReg::z28, ZReg::z29, ZReg::z30), "saba z28.b, z29.b, z30.b"); + TEST_SINGLE(saba(SubRegSize::i8Bit, ZReg::z28, ZReg::z29, ZReg::z30), "saba z28.b, z29.b, z30.b"); TEST_SINGLE(saba(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "saba z28.h, z29.h, z30.h"); TEST_SINGLE(saba(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "saba z28.s, z29.s, z30.s"); TEST_SINGLE(saba(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "saba z28.d, z29.d, z30.d"); - TEST_SINGLE(uaba(SubRegSize::i8Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uaba z28.b, z29.b, z30.b"); + TEST_SINGLE(uaba(SubRegSize::i8Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uaba z28.b, z29.b, z30.b"); TEST_SINGLE(uaba(SubRegSize::i16Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uaba z28.h, z29.h, z30.h"); TEST_SINGLE(uaba(SubRegSize::i32Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uaba z28.s, z29.s, z30.s"); TEST_SINGLE(uaba(SubRegSize::i64Bit, ZReg::z28, ZReg::z29, ZReg::z30), "uaba z28.d, z29.d, z30.d"); @@ -3215,32 +3187,32 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 saturating extract narrow TEST_SINGLE(sqxtnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sqxtnb z30.b, z29.h"); TEST_SINGLE(sqxtnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sqxtnb z30.h, z29.s"); TEST_SINGLE(sqxtnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sqxtnb z30.s, z29.d"); - //TEST_SINGLE(sqxtnb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtnb z30.d, z29.q"); + // TEST_SINGLE(sqxtnb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtnb z30.d, z29.q"); TEST_SINGLE(sqxtnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sqxtnt z30.b, z29.h"); TEST_SINGLE(sqxtnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sqxtnt z30.h, z29.s"); TEST_SINGLE(sqxtnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sqxtnt z30.s, z29.d"); - //TEST_SINGLE(sqxtnt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtnt z30.d, z29.q"); + // TEST_SINGLE(sqxtnt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtnt z30.d, z29.q"); TEST_SINGLE(uqxtnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "uqxtnb z30.b, z29.h"); TEST_SINGLE(uqxtnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "uqxtnb z30.h, z29.s"); TEST_SINGLE(uqxtnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "uqxtnb z30.s, z29.d"); - //TEST_SINGLE(uqxtnb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uqxtnb z30.d, z29.q"); + // TEST_SINGLE(uqxtnb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uqxtnb z30.d, z29.q"); TEST_SINGLE(uqxtnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "uqxtnt z30.b, z29.h"); TEST_SINGLE(uqxtnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "uqxtnt z30.h, z29.s"); TEST_SINGLE(uqxtnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "uqxtnt z30.s, z29.d"); - //TEST_SINGLE(uqxtnt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uqxtnt z30.d, z29.q"); + // TEST_SINGLE(uqxtnt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "uqxtnt z30.d, z29.q"); TEST_SINGLE(sqxtunb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sqxtunb z30.b, z29.h"); TEST_SINGLE(sqxtunb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sqxtunb z30.h, z29.s"); TEST_SINGLE(sqxtunb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sqxtunb z30.s, z29.d"); - //TEST_SINGLE(sqxtunb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtunb z30.d, z29.q"); + // TEST_SINGLE(sqxtunb(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtunb z30.d, z29.q"); TEST_SINGLE(sqxtunt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29), "sqxtunt z30.b, z29.h"); TEST_SINGLE(sqxtunt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29), "sqxtunt z30.h, z29.s"); TEST_SINGLE(sqxtunt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29), "sqxtunt z30.s, z29.d"); - //TEST_SINGLE(sqxtunt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtunt z30.d, z29.q"); + // TEST_SINGLE(sqxtunt(SubRegSize::i64Bit, ZReg::z30, ZReg::z29), "sqxtunt z30.d, z29.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise shift right narrow") { TEST_SINGLE(sqshrunb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, 1), "sqshrunb z30.b, z29.h, #1"); @@ -3356,41 +3328,41 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 bitwise shift right narro TEST_SINGLE(uqrshrnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, 32), "uqrshrnt z30.s, z29.d, #32"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 integer add/subtract narrow high part") { - TEST_SINGLE(addhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnb z30.b, z29.h, z28.h"); - TEST_SINGLE(addhnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnb z30.h, z29.s, z28.s"); - TEST_SINGLE(addhnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnb z30.s, z29.d, z28.d"); + TEST_SINGLE(addhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnb z30.b, z29.h, z28.h"); + TEST_SINGLE(addhnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnb z30.h, z29.s, z28.s"); + TEST_SINGLE(addhnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnb z30.s, z29.d, z28.d"); - TEST_SINGLE(addhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnt z30.b, z29.h, z28.h"); - TEST_SINGLE(addhnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnt z30.h, z29.s, z28.s"); - TEST_SINGLE(addhnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnt z30.s, z29.d, z28.d"); + TEST_SINGLE(addhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnt z30.b, z29.h, z28.h"); + TEST_SINGLE(addhnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnt z30.h, z29.s, z28.s"); + TEST_SINGLE(addhnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "addhnt z30.s, z29.d, z28.d"); - TEST_SINGLE(raddhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnb z30.b, z29.h, z28.h"); + TEST_SINGLE(raddhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnb z30.b, z29.h, z28.h"); TEST_SINGLE(raddhnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnb z30.h, z29.s, z28.s"); TEST_SINGLE(raddhnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnb z30.s, z29.d, z28.d"); - TEST_SINGLE(raddhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnt z30.b, z29.h, z28.h"); + TEST_SINGLE(raddhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnt z30.b, z29.h, z28.h"); TEST_SINGLE(raddhnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnt z30.h, z29.s, z28.s"); TEST_SINGLE(raddhnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "raddhnt z30.s, z29.d, z28.d"); - TEST_SINGLE(subhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnb z30.b, z29.h, z28.h"); - TEST_SINGLE(subhnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnb z30.h, z29.s, z28.s"); - TEST_SINGLE(subhnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnb z30.s, z29.d, z28.d"); + TEST_SINGLE(subhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnb z30.b, z29.h, z28.h"); + TEST_SINGLE(subhnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnb z30.h, z29.s, z28.s"); + TEST_SINGLE(subhnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnb z30.s, z29.d, z28.d"); - TEST_SINGLE(subhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnt z30.b, z29.h, z28.h"); - TEST_SINGLE(subhnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnt z30.h, z29.s, z28.s"); - TEST_SINGLE(subhnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnt z30.s, z29.d, z28.d"); + TEST_SINGLE(subhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnt z30.b, z29.h, z28.h"); + TEST_SINGLE(subhnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnt z30.h, z29.s, z28.s"); + TEST_SINGLE(subhnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "subhnt z30.s, z29.d, z28.d"); - TEST_SINGLE(rsubhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnb z30.b, z29.h, z28.h"); + TEST_SINGLE(rsubhnb(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnb z30.b, z29.h, z28.h"); TEST_SINGLE(rsubhnb(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnb z30.h, z29.s, z28.s"); TEST_SINGLE(rsubhnb(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnb z30.s, z29.d, z28.d"); - TEST_SINGLE(rsubhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnt z30.b, z29.h, z28.h"); + TEST_SINGLE(rsubhnt(SubRegSize::i8Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnt z30.b, z29.h, z28.h"); TEST_SINGLE(rsubhnt(SubRegSize::i16Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnt z30.h, z29.s, z28.s"); TEST_SINGLE(rsubhnt(SubRegSize::i32Bit, ZReg::z30, ZReg::z29, ZReg::z28), "rsubhnt z30.s, z29.d, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 Histogram Computation") { - TEST_SINGLE(histcnt(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29, ZReg::z28), "histcnt z30.s, p6/z, z29.s, z28.s"); - TEST_SINGLE(histcnt(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29, ZReg::z28), "histcnt z30.d, p6/z, z29.d, z28.d"); + TEST_SINGLE(histcnt(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29, ZReg::z28), "histcnt z30.s, p6/z, z29.s, z28.s"); + TEST_SINGLE(histcnt(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), ZReg::z29, ZReg::z28), "histcnt z30.d, p6/z, z29.d, z28.d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE2 Histogram Computation - Segment") { TEST_SINGLE(histseg(ZReg::z30, ZReg::z29, ZReg::z28), "histseg z30.b, z29.b, z28.b"); @@ -3487,112 +3459,112 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point arithmetic TEST_SINGLE(ftmad(SubRegSize::i32Bit, ZReg::z30, ZReg::z30, ZReg::z28, 7), "ftmad z30.s, z30.s, z28.s, #7"); TEST_SINGLE(ftmad(SubRegSize::i64Bit, ZReg::z30, ZReg::z30, ZReg::z28, 7), "ftmad z30.d, z30.d, z28.d, #7"); - //TEST_SINGLE(fadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fadd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fadd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fadd z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fsub(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fsub(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fsub(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fsub(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsub z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmul(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmul(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmul(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmul(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmul z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fsubr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fsubr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fsubr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fsubr z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmaxnm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmaxnm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmaxnm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmaxnm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmaxnm(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmaxnm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmaxnm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmaxnm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmaxnm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmaxnm(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmaxnm z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fminnm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fminnm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fminnm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fminnm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fminnm(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fminnm(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fminnm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fminnm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fminnm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fminnm(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fminnm z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmax(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmax(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmax(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmax(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmax z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmin(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmin(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmin(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmin(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmin z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fabd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fabd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fabd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fabd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fabd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fabd(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fabd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fabd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fabd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fabd(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fabd z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fscale(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fscale(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fscale(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fscale(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fscale(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fscale(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fscale(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fscale(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fscale(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fscale(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fscale z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fmulx(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fmulx(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fmulx(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fmulx(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fmulx(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fmulx(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fmulx(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fmulx(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fmulx(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fmulx(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fmulx z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fdiv(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fdiv(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fdiv(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fdiv(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fdiv(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fdiv(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fdiv(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fdiv(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fdiv(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fdiv(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdiv z30.q, p6/m, z30.q, z28.q"); - //TEST_SINGLE(fdivr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.b, p6/m, z30.b, z28.b"); - TEST_SINGLE(fdivr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.h, p6/m, z30.h, z28.h"); - TEST_SINGLE(fdivr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.s, p6/m, z30.s, z28.s"); - TEST_SINGLE(fdivr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.d, p6/m, z30.d, z28.d"); - //TEST_SINGLE(fdivr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.q, p6/m, z30.q, z28.q"); + // TEST_SINGLE(fdivr(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.b, p6/m, z30.b, z28.b"); + TEST_SINGLE(fdivr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.h, p6/m, z30.h, z28.h"); + TEST_SINGLE(fdivr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.s, p6/m, z30.s, z28.s"); + TEST_SINGLE(fdivr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.d, p6/m, z30.d, z28.d"); + // TEST_SINGLE(fdivr(SubRegSize::i128Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z30, ZReg::z28), "fdivr z30.q, p6/m, z30.q, z28.q"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point arithmetic with immediate (predicated)") { - TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fadd z30.h, p6/m, z30.h, #0.5"); - TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fadd z30.s, p6/m, z30.s, #0.5"); - TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fadd z30.d, p6/m, z30.d, #0.5"); - TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fadd z30.h, p6/m, z30.h, #1.0"); - TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fadd z30.s, p6/m, z30.s, #1.0"); - TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fadd z30.d, p6/m, z30.d, #1.0"); + TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fadd z30.h, p6/m, z30.h, #0.5"); + TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fadd z30.s, p6/m, z30.s, #0.5"); + TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fadd z30.d, p6/m, z30.d, #0.5"); + TEST_SINGLE(fadd(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fadd z30.h, p6/m, z30.h, #1.0"); + TEST_SINGLE(fadd(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fadd z30.s, p6/m, z30.s, #1.0"); + TEST_SINGLE(fadd(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fadd z30.d, p6/m, z30.d, #1.0"); - TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsub z30.h, p6/m, z30.h, #0.5"); - TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsub z30.s, p6/m, z30.s, #0.5"); - TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsub z30.d, p6/m, z30.d, #0.5"); - TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsub z30.h, p6/m, z30.h, #1.0"); - TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsub z30.s, p6/m, z30.s, #1.0"); - TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsub z30.d, p6/m, z30.d, #1.0"); + TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsub z30.h, p6/m, z30.h, #0.5"); + TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsub z30.s, p6/m, z30.s, #0.5"); + TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsub z30.d, p6/m, z30.d, #0.5"); + TEST_SINGLE(fsub(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsub z30.h, p6/m, z30.h, #1.0"); + TEST_SINGLE(fsub(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsub z30.s, p6/m, z30.s, #1.0"); + TEST_SINGLE(fsub(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsub z30.d, p6/m, z30.d, #1.0"); - TEST_SINGLE(fsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsubr z30.h, p6/m, z30.h, #0.5"); - TEST_SINGLE(fsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsubr z30.s, p6/m, z30.s, #0.5"); - TEST_SINGLE(fsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsubr z30.d, p6/m, z30.d, #0.5"); - TEST_SINGLE(fsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsubr z30.h, p6/m, z30.h, #1.0"); - TEST_SINGLE(fsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsubr z30.s, p6/m, z30.s, #1.0"); - TEST_SINGLE(fsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsubr z30.d, p6/m, z30.d, #1.0"); + TEST_SINGLE(fsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsubr z30.h, p6/m, z30.h, #0.5"); + TEST_SINGLE(fsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsubr z30.s, p6/m, z30.s, #0.5"); + TEST_SINGLE(fsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_0_5), "fsubr z30.d, p6/m, z30.d, #0.5"); + TEST_SINGLE(fsubr(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsubr z30.h, p6/m, z30.h, #1.0"); + TEST_SINGLE(fsubr(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsubr z30.s, p6/m, z30.s, #1.0"); + TEST_SINGLE(fsubr(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFAddSubImm::_1_0), "fsubr z30.d, p6/m, z30.d, #1.0"); - TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_0_5), "fmul z30.h, p6/m, z30.h, #0.5"); - TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_0_5), "fmul z30.s, p6/m, z30.s, #0.5"); - TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_0_5), "fmul z30.d, p6/m, z30.d, #0.5"); - TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_2_0), "fmul z30.h, p6/m, z30.h, #2.0"); - TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_2_0), "fmul z30.s, p6/m, z30.s, #2.0"); - TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_2_0), "fmul z30.d, p6/m, z30.d, #2.0"); + TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_0_5), "fmul z30.h, p6/m, z30.h, #0.5"); + TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_0_5), "fmul z30.s, p6/m, z30.s, #0.5"); + TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_0_5), "fmul z30.d, p6/m, z30.d, #0.5"); + TEST_SINGLE(fmul(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_2_0), "fmul z30.h, p6/m, z30.h, #2.0"); + TEST_SINGLE(fmul(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_2_0), "fmul z30.s, p6/m, z30.s, #2.0"); + TEST_SINGLE(fmul(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMulImm::_2_0), "fmul z30.d, p6/m, z30.d, #2.0"); TEST_SINGLE(fmaxnm(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmaxnm z30.h, p6/m, z30.h, #0.0"); TEST_SINGLE(fmaxnm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmaxnm z30.s, p6/m, z30.s, #0.0"); @@ -3608,462 +3580,324 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point arithmetic TEST_SINGLE(fminnm(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fminnm z30.s, p6/m, z30.s, #1.0"); TEST_SINGLE(fminnm(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fminnm z30.d, p6/m, z30.d, #1.0"); - TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmax z30.h, p6/m, z30.h, #0.0"); - TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmax z30.s, p6/m, z30.s, #0.0"); - TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmax z30.d, p6/m, z30.d, #0.0"); - TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmax z30.h, p6/m, z30.h, #1.0"); - TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmax z30.s, p6/m, z30.s, #1.0"); - TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmax z30.d, p6/m, z30.d, #1.0"); + TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmax z30.h, p6/m, z30.h, #0.0"); + TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmax z30.s, p6/m, z30.s, #0.0"); + TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmax z30.d, p6/m, z30.d, #0.0"); + TEST_SINGLE(fmax(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmax z30.h, p6/m, z30.h, #1.0"); + TEST_SINGLE(fmax(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmax z30.s, p6/m, z30.s, #1.0"); + TEST_SINGLE(fmax(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmax z30.d, p6/m, z30.d, #1.0"); - TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmin z30.h, p6/m, z30.h, #0.0"); - TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmin z30.s, p6/m, z30.s, #0.0"); - TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmin z30.d, p6/m, z30.d, #0.0"); - TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmin z30.h, p6/m, z30.h, #1.0"); - TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmin z30.s, p6/m, z30.s, #1.0"); - TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmin z30.d, p6/m, z30.d, #1.0"); + TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmin z30.h, p6/m, z30.h, #0.0"); + TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmin z30.s, p6/m, z30.s, #0.0"); + TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_0_0), "fmin z30.d, p6/m, z30.d, #0.0"); + TEST_SINGLE(fmin(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmin z30.h, p6/m, z30.h, #1.0"); + TEST_SINGLE(fmin(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmin z30.s, p6/m, z30.s, #1.0"); + TEST_SINGLE(fmin(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), SVEFMaxMinImm::_1_0), "fmin z30.d, p6/m, z30.d, #1.0"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Memory - 32-bit Gather and Unsized Contiguous") { - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1b {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1b {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1b {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1b {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ld1b {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1b {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1b {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1b {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1b {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ld1b {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1b {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ld1b {z30.s}, p6/z, [z31.s, #31]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1b {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ld1b {z30.d}, p6/z, [z31.d, #31]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1b {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ld1b {z30.s}, p6/z, [z31.s, #31]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1b {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ld1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ld1b {z30.d}, p6/z, [z31.d, #31]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1sb {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1sb {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1sb {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1sb {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ld1sb {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1sb {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1sb {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1sb {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1sb {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ld1sb {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1sb {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ld1sb {z30.s}, p6/z, [z31.s, #31]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1sb {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ld1sb {z30.d}, p6/z, [z31.d, #31]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1sb {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ld1sb {z30.s}, p6/z, [z31.s, #31]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1sb {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ld1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ld1sb {z30.d}, p6/z, [z31.d, #31]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1d {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1d {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 3)), - "ld1d {z30.d}, p6/z, [x30, z31.d, uxtw #3]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 3)), - "ld1d {z30.d}, p6/z, [x30, z31.d, sxtw #3]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 3)), - "ld1d {z30.d}, p6/z, [x30, z31.d, lsl #3]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ld1d {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "ld1d {z30.d}, p6/z, " + "[x30, z31.d, uxtw]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "ld1d {z30.d}, p6/z, " + "[x30, z31.d, sxtw]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 3)), "ld1d {z30.d}, p6/z, " + "[x30, z31.d, uxtw #3]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 3)), "ld1d {z30.d}, p6/z, " + "[x30, z31.d, sxtw #3]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 3)), "ld1d {z30.d}, p6/z, [x30, " + "z31.d, lsl #3]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "ld1d {z30.d}, p6/z, " + "[x30, z31.d]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1d {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 248)), - "ld1d {z30.d}, p6/z, [z31.d, #248]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1d {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ld1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 248)), "ld1d {z30.d}, p6/z, [z31.d, #248]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ld1h {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ld1h {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ld1h {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ld1h {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), - "ld1h {z30.d}, p6/z, [x30, z31.d, lsl #1]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ld1h {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ld1h {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ld1h {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ld1h {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ld1h {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), + "ld1h {z30.d}, p6/z, [x30, z31.d, lsl #1]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ld1h {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1h {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1h {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1h {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1h {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1h {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1h {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1h {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1h {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1h {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ld1h {z30.s}, p6/z, [z31.s, #62]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1h {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ld1h {z30.d}, p6/z, [z31.d, #62]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1h {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ld1h {z30.s}, p6/z, [z31.s, #62]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1h {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ld1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ld1h {z30.d}, p6/z, [z31.d, #62]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ld1sh {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ld1sh {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ld1sh {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ld1sh {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), - "ld1sh {z30.d}, p6/z, [x30, z31.d, lsl #1]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ld1sh {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ld1sh {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ld1sh {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ld1sh {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ld1sh {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), + "ld1sh {z30.d}, p6/z, [x30, z31.d, lsl #1]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ld1sh {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1sh {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1sh {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1sh {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1sh {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1sh {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1sh {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1sh {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1sh {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1sh {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ld1sh {z30.s}, p6/z, [z31.s, #62]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1sh {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ld1sh {z30.d}, p6/z, [z31.d, #62]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1sh {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ld1sh {z30.s}, p6/z, [z31.s, #62]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1sh {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ld1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ld1sh {z30.d}, p6/z, [z31.d, #62]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "ld1w {z30.s}, p6/z, [x30, z31.s, uxtw #2]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "ld1w {z30.s}, p6/z, [x30, z31.s, sxtw #2]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "ld1w {z30.d}, p6/z, [x30, z31.d, uxtw #2]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "ld1w {z30.d}, p6/z, [x30, z31.d, sxtw #2]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), - "ld1w {z30.d}, p6/z, [x30, z31.d, lsl #2]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), + "ld1w {z30.s}, p6/z, [x30, z31.s, uxtw #2]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), + "ld1w {z30.s}, p6/z, [x30, z31.s, sxtw #2]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), + "ld1w {z30.d}, p6/z, [x30, z31.d, uxtw #2]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), + "ld1w {z30.d}, p6/z, [x30, z31.d, sxtw #2]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), + "ld1w {z30.d}, p6/z, [x30, z31.d, lsl #2]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1w {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1w {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1w {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1w {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ld1w {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1w {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1w {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ld1w {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ld1w {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ld1w {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1w {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), - "ld1w {z30.s}, p6/z, [z31.s, #124]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1w {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), - "ld1w {z30.d}, p6/z, [z31.d, #124]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1w {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), "ld1w {z30.s}, p6/z, [z31.s, #124]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1w {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ld1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), "ld1w {z30.d}, p6/z, [z31.d, #124]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ld1sw {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ld1sw {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "ld1sw {z30.d}, p6/z, [x30, z31.d, uxtw #2]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "ld1sw {z30.d}, p6/z, [x30, z31.d, sxtw #2]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), - "ld1sw {z30.d}, p6/z, [x30, z31.d, lsl #2]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ld1sw {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "ld1sw {z30.d}, p6/z, " + "[x30, z31.d, uxtw]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "ld1sw {z30.d}, p6/z, " + "[x30, z31.d, sxtw]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), "ld1sw {z30.d}, p6/z, " + "[x30, z31.d, uxtw #2]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), "ld1sw {z30.d}, p6/z, " + "[x30, z31.d, sxtw #2]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), "ld1sw {z30.d}, p6/z, " + "[x30, z31.d, lsl #2]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "ld1sw {z30.d}, p6/z, " + "[x30, z31.d]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ld1sw {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), - "ld1sw {z30.d}, p6/z, [z31.d, #124]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ld1sw {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ld1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), "ld1sw {z30.d}, p6/z, [z31.d, #124]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1b {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1b {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1b {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1b {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ldff1b {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1b {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1b {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1b {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1b {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ldff1b {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1b {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ldff1b {z30.s}, p6/z, [z31.s, #31]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1b {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ldff1b {z30.d}, p6/z, [z31.d, #31]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1b {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ldff1b {z30.s}, p6/z, [z31.s, " + "#31]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1b {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ldff1b(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ldff1b {z30.d}, p6/z, [z31.d, " + "#31]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1sb {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1sb {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1sb {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1sb {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ldff1sb {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1sb {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1sb {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1sb {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1sb {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ldff1sb {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1sb {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ldff1sb {z30.s}, p6/z, [z31.s, #31]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1sb {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), - "ldff1sb {z30.d}, p6/z, [z31.d, #31]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1sb {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ldff1sb {z30.s}, p6/z, [z31.s, " + "#31]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1sb {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ldff1sb(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 31)), "ldff1sb {z30.d}, p6/z, [z31.d, " + "#31]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1d {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1d {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 3)), - "ldff1d {z30.d}, p6/z, [x30, z31.d, uxtw #3]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 3)), - "ldff1d {z30.d}, p6/z, [x30, z31.d, sxtw #3]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 3)), - "ldff1d {z30.d}, p6/z, [x30, z31.d, lsl #3]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ldff1d {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "ldff1d {z30.d}, p6/z, " + "[x30, z31.d, uxtw]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "ldff1d {z30.d}, p6/z, " + "[x30, z31.d, sxtw]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 3)), "ldff1d {z30.d}, p6/z, " + "[x30, z31.d, uxtw #3]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 3)), "ldff1d {z30.d}, p6/z, " + "[x30, z31.d, sxtw #3]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 3)), "ldff1d {z30.d}, p6/z, " + "[x30, z31.d, lsl #3]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "ldff1d {z30.d}, p6/z, " + "[x30, z31.d]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1d {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 248)), - "ldff1d {z30.d}, p6/z, [z31.d, #248]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1d {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ldff1d(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 248)), "ldff1d {z30.d}, p6/z, [z31.d, #248]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ldff1h {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ldff1h {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ldff1h {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ldff1h {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), - "ldff1h {z30.d}, p6/z, [x30, z31.d, lsl #1]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ldff1h {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ldff1h {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ldff1h {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ldff1h {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ldff1h {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), + "ldff1h {z30.d}, p6/z, [x30, z31.d, lsl #1]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ldff1h {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1h {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1h {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1h {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1h {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1h {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1h {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1h {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1h {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1h {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ldff1h {z30.s}, p6/z, [z31.s, #62]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1h {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ldff1h {z30.d}, p6/z, [z31.d, #62]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1h {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ldff1h {z30.s}, p6/z, [z31.s, " + "#62]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1h {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ldff1h(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ldff1h {z30.d}, p6/z, [z31.d, " + "#62]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ldff1sh {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ldff1sh {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "ldff1sh {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "ldff1sh {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), - "ldff1sh {z30.d}, p6/z, [x30, z31.d, lsl #1]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ldff1sh {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ldff1sh {z30.s}, p6/z, [x30, z31.s, uxtw #1]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ldff1sh {z30.s}, p6/z, [x30, z31.s, sxtw #1]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), + "ldff1sh {z30.d}, p6/z, [x30, z31.d, uxtw #1]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), + "ldff1sh {z30.d}, p6/z, [x30, z31.d, sxtw #1]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), + "ldff1sh {z30.d}, p6/z, [x30, z31.d, lsl #1]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ldff1sh {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1sh {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1sh {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1sh {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1sh {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1sh {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1sh {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1sh {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1sh {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1sh {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ldff1sh {z30.s}, p6/z, [z31.s, #62]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1sh {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), - "ldff1sh {z30.d}, p6/z, [z31.d, #62]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1sh {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ldff1sh {z30.s}, p6/z, [z31.s, " + "#62]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1sh {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ldff1sh(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 62)), "ldff1sh {z30.d}, p6/z, [z31.d, " + "#62]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "ldff1w {z30.s}, p6/z, [x30, z31.s, uxtw #2]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "ldff1w {z30.s}, p6/z, [x30, z31.s, sxtw #2]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "ldff1w {z30.d}, p6/z, [x30, z31.d, uxtw #2]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "ldff1w {z30.d}, p6/z, [x30, z31.d, sxtw #2]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), - "ldff1w {z30.d}, p6/z, [x30, z31.d, lsl #2]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), + "ldff1w {z30.s}, p6/z, [x30, z31.s, uxtw #2]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), + "ldff1w {z30.s}, p6/z, [x30, z31.s, sxtw #2]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), + "ldff1w {z30.d}, p6/z, [x30, z31.d, uxtw #2]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), + "ldff1w {z30.d}, p6/z, [x30, z31.d, sxtw #2]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), + "ldff1w {z30.d}, p6/z, [x30, z31.d, lsl #2]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1w {z30.s}, p6/z, [x30, z31.s, uxtw]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1w {z30.s}, p6/z, [x30, z31.s, sxtw]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1w {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1w {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ldff1w {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1w {z30.s}, p6/z, [x30, z31.s, uxtw]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1w {z30.s}, p6/z, [x30, z31.s, sxtw]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), + "ldff1w {z30.d}, p6/z, [x30, z31.d, uxtw]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), + "ldff1w {z30.d}, p6/z, [x30, z31.d, sxtw]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), + "ldff1w {z30.d}, p6/z, [x30, z31.d]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1w {z30.s}, p6/z, [z31.s]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), - "ldff1w {z30.s}, p6/z, [z31.s, #124]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1w {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), - "ldff1w {z30.d}, p6/z, [z31.d, #124]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1w {z30.s}, p6/z, [z31.s]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), "ldff1w {z30.s}, p6/z, [z31.s, " + "#124]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1w {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ldff1w(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), "ldff1w {z30.d}, p6/z, [z31.d, " + "#124]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "ldff1sw {z30.d}, p6/z, [x30, z31.d, uxtw]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "ldff1sw {z30.d}, p6/z, [x30, z31.d, sxtw]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "ldff1sw {z30.d}, p6/z, [x30, z31.d, uxtw #2]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "ldff1sw {z30.d}, p6/z, [x30, z31.d, sxtw #2]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), - "ldff1sw {z30.d}, p6/z, [x30, z31.d, lsl #2]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "ldff1sw {z30.d}, p6/z, [x30, z31.d]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "ldff1sw {z30.d}, " + "p6/z, [x30, z31.d, " + "uxtw]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "ldff1sw {z30.d}, " + "p6/z, [x30, z31.d, " + "sxtw]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), "ldff1sw {z30.d}, " + "p6/z, [x30, z31.d, " + "uxtw #2]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), "ldff1sw {z30.d}, " + "p6/z, [x30, z31.d, " + "sxtw #2]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), "ldff1sw {z30.d}, p6/z, " + "[x30, z31.d, lsl #2]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "ldff1sw {z30.d}, " + "p6/z, [x30, z31.d]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), - "ldff1sw {z30.d}, p6/z, [z31.d]"); - TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), - "ldff1sw {z30.d}, p6/z, [z31.d, #124]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 0)), "ldff1sw {z30.d}, p6/z, [z31.d]"); + TEST_SINGLE(ldff1sw(ZReg::z30, PReg::p6.Zeroing(), SVEMemOperand(ZReg::z31, 124)), "ldff1sw {z30.d}, p6/z, [z31.d, #124]"); TEST_SINGLE(ldr(PReg::p6, XReg::x29, 0), "ldr p6, [x29]"); TEST_SINGLE(ldr(PReg::p6, XReg::x29, -256), "ldr p6, [x29, #-256, mul vl]"); @@ -4075,133 +3909,148 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Memory - 32-bit Gather and } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE load and broadcast element") { - TEST_SINGLE(ld1rb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.b}, p6/z, [x29]"); - TEST_SINGLE(ld1rb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.b}, p6/z, [x29, #31]"); - TEST_SINGLE(ld1rb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.b}, p6/z, [x29, #63]"); + TEST_SINGLE(ld1rb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.b}, p6/z, [x29]"); + TEST_SINGLE(ld1rb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.b}, p6/z, [x29, #31]"); + TEST_SINGLE(ld1rb(SubRegSize::i8Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.b}, p6/z, [x29, #63]"); - TEST_SINGLE(ld1rb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.h}, p6/z, [x29]"); - TEST_SINGLE(ld1rb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.h}, p6/z, [x29, #31]"); - TEST_SINGLE(ld1rb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.h}, p6/z, [x29, #63]"); + TEST_SINGLE(ld1rb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.h}, p6/z, [x29]"); + TEST_SINGLE(ld1rb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.h}, p6/z, [x29, #31]"); + TEST_SINGLE(ld1rb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.h}, p6/z, [x29, #63]"); - TEST_SINGLE(ld1rb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.s}, p6/z, [x29]"); - TEST_SINGLE(ld1rb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.s}, p6/z, [x29, #31]"); - TEST_SINGLE(ld1rb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.s}, p6/z, [x29, #63]"); + TEST_SINGLE(ld1rb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.s}, p6/z, [x29]"); + TEST_SINGLE(ld1rb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.s}, p6/z, [x29, #31]"); + TEST_SINGLE(ld1rb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.s}, p6/z, [x29, #63]"); - TEST_SINGLE(ld1rb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.d}, p6/z, [x29]"); - TEST_SINGLE(ld1rb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.d}, p6/z, [x29, #31]"); - TEST_SINGLE(ld1rb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.d}, p6/z, [x29, #63]"); + TEST_SINGLE(ld1rb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rb {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rb {z30.d}, p6/z, [x29, #31]"); + TEST_SINGLE(ld1rb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rb {z30.d}, p6/z, [x29, #63]"); - TEST_SINGLE(ld1rsb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsb {z30.h}, p6/z, [x29]"); + TEST_SINGLE(ld1rsb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsb {z30.h}, p6/z, [x29]"); TEST_SINGLE(ld1rsb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rsb {z30.h}, p6/z, [x29, #31]"); TEST_SINGLE(ld1rsb(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rsb {z30.h}, p6/z, [x29, #63]"); - TEST_SINGLE(ld1rsb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsb {z30.s}, p6/z, [x29]"); + TEST_SINGLE(ld1rsb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsb {z30.s}, p6/z, [x29]"); TEST_SINGLE(ld1rsb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rsb {z30.s}, p6/z, [x29, #31]"); TEST_SINGLE(ld1rsb(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rsb {z30.s}, p6/z, [x29, #63]"); - TEST_SINGLE(ld1rsb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsb {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rsb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsb {z30.d}, p6/z, [x29]"); TEST_SINGLE(ld1rsb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 31), "ld1rsb {z30.d}, p6/z, [x29, #31]"); TEST_SINGLE(ld1rsb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 63), "ld1rsb {z30.d}, p6/z, [x29, #63]"); - TEST_SINGLE(ld1rh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rh {z30.h}, p6/z, [x29]"); - TEST_SINGLE(ld1rh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rh {z30.h}, p6/z, [x29, #64]"); - TEST_SINGLE(ld1rh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rh {z30.h}, p6/z, [x29, #126]"); + TEST_SINGLE(ld1rh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rh {z30.h}, p6/z, [x29]"); + TEST_SINGLE(ld1rh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rh {z30.h}, p6/z, [x29, #64]"); + TEST_SINGLE(ld1rh(SubRegSize::i16Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rh {z30.h}, p6/z, [x29, #126]"); - TEST_SINGLE(ld1rh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rh {z30.s}, p6/z, [x29]"); - TEST_SINGLE(ld1rh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rh {z30.s}, p6/z, [x29, #64]"); - TEST_SINGLE(ld1rh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rh {z30.s}, p6/z, [x29, #126]"); + TEST_SINGLE(ld1rh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rh {z30.s}, p6/z, [x29]"); + TEST_SINGLE(ld1rh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rh {z30.s}, p6/z, [x29, #64]"); + TEST_SINGLE(ld1rh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rh {z30.s}, p6/z, [x29, #126]"); - TEST_SINGLE(ld1rh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rh {z30.d}, p6/z, [x29]"); - TEST_SINGLE(ld1rh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rh {z30.d}, p6/z, [x29, #64]"); - TEST_SINGLE(ld1rh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rh {z30.d}, p6/z, [x29, #126]"); + TEST_SINGLE(ld1rh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rh {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rh {z30.d}, p6/z, [x29, #64]"); + TEST_SINGLE(ld1rh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rh {z30.d}, p6/z, [x29, #126]"); - TEST_SINGLE(ld1rsh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsh {z30.s}, p6/z, [x29]"); - TEST_SINGLE(ld1rsh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rsh {z30.s}, p6/z, [x29, #64]"); + TEST_SINGLE(ld1rsh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsh {z30.s}, p6/z, [x29]"); + TEST_SINGLE(ld1rsh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rsh {z30.s}, p6/z, [x29, #64]"); TEST_SINGLE(ld1rsh(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rsh {z30.s}, p6/z, [x29, #126]"); - TEST_SINGLE(ld1rsh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsh {z30.d}, p6/z, [x29]"); - TEST_SINGLE(ld1rsh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rsh {z30.d}, p6/z, [x29, #64]"); + TEST_SINGLE(ld1rsh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsh {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rsh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 64), "ld1rsh {z30.d}, p6/z, [x29, #64]"); TEST_SINGLE(ld1rsh(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 126), "ld1rsh {z30.d}, p6/z, [x29, #126]"); - TEST_SINGLE(ld1rw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rw {z30.s}, p6/z, [x29]"); - TEST_SINGLE(ld1rw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 128), "ld1rw {z30.s}, p6/z, [x29, #128]"); - TEST_SINGLE(ld1rw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 252), "ld1rw {z30.s}, p6/z, [x29, #252]"); + TEST_SINGLE(ld1rw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rw {z30.s}, p6/z, [x29]"); + TEST_SINGLE(ld1rw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 128), "ld1rw {z30.s}, p6/z, [x29, #128]"); + TEST_SINGLE(ld1rw(SubRegSize::i32Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 252), "ld1rw {z30.s}, p6/z, [x29, #252]"); - TEST_SINGLE(ld1rw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rw {z30.d}, p6/z, [x29]"); - TEST_SINGLE(ld1rw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 128), "ld1rw {z30.d}, p6/z, [x29, #128]"); - TEST_SINGLE(ld1rw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 252), "ld1rw {z30.d}, p6/z, [x29, #252]"); + TEST_SINGLE(ld1rw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rw {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 128), "ld1rw {z30.d}, p6/z, [x29, #128]"); + TEST_SINGLE(ld1rw(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 252), "ld1rw {z30.d}, p6/z, [x29, #252]"); - TEST_SINGLE(ld1rsw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsw {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rsw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rsw {z30.d}, p6/z, [x29]"); TEST_SINGLE(ld1rsw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 128), "ld1rsw {z30.d}, p6/z, [x29, #128]"); TEST_SINGLE(ld1rsw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 252), "ld1rsw {z30.d}, p6/z, [x29, #252]"); - TEST_SINGLE(ld1rd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rd {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rd {z30.d}, p6/z, [x29]"); TEST_SINGLE(ld1rd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 256), "ld1rd {z30.d}, p6/z, [x29, #256]"); TEST_SINGLE(ld1rd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 504), "ld1rd {z30.d}, p6/z, [x29, #504]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE load multiple structures (scalar plus scalar)") { - TEST_SINGLE(ld2b(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2b {z31.b, z0.b}, p6/z, [x29, x30]"); + TEST_SINGLE(ld2b(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2b {z31.b, z0.b}, p6/z, [x29, x30]"); TEST_SINGLE(ld2b(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2b {z26.b, z27.b}, p6/z, [x29, x30]"); - TEST_SINGLE(ld3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3b {z31.b, z0.b, z1.b}, p6/z, [x29, x30]"); - TEST_SINGLE(ld3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3b {z26.b, z27.b, z28.b}, p6/z, [x29, x30]"); - TEST_SINGLE(ld4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4b {z31.b, z0.b, z1.b, z2.b}, p6/z, [x29, x30]"); - TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4b {z26.b, z27.b, z28.b, z29.b}, p6/z, [x29, x30]"); + TEST_SINGLE(ld3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3b {z31.b, z0.b, z1.b}, p6/z, [x29, x30]"); + TEST_SINGLE(ld3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3b {z26.b, z27.b, z28.b}, p6/z, [x29, " + "x30]"); + TEST_SINGLE(ld4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4b {z31.b, z0.b, z1.b, z2.b}, " + "p6/z, [x29, x30]"); + TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4b {z26.b, z27.b, z28.b, " + "z29.b}, p6/z, [x29, x30]"); - TEST_SINGLE(ld2h(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2h {z31.h, z0.h}, p6/z, [x29, x30, lsl #1]"); + TEST_SINGLE(ld2h(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2h {z31.h, z0.h}, p6/z, [x29, x30, lsl #1]"); TEST_SINGLE(ld2h(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2h {z26.h, z27.h}, p6/z, [x29, x30, lsl #1]"); - TEST_SINGLE(ld3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3h {z31.h, z0.h, z1.h}, p6/z, [x29, x30, lsl #1]"); - TEST_SINGLE(ld3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3h {z26.h, z27.h, z28.h}, p6/z, [x29, x30, lsl #1]"); - TEST_SINGLE(ld4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4h {z31.h, z0.h, z1.h, z2.h}, p6/z, [x29, x30, lsl #1]"); - TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4h {z26.h, z27.h, z28.h, z29.h}, p6/z, [x29, x30, lsl #1]"); + TEST_SINGLE(ld3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3h {z31.h, z0.h, z1.h}, p6/z, [x29, x30, lsl " + "#1]"); + TEST_SINGLE(ld3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3h {z26.h, z27.h, z28.h}, p6/z, [x29, x30, " + "lsl #1]"); + TEST_SINGLE(ld4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4h {z31.h, z0.h, z1.h, z2.h}, " + "p6/z, [x29, x30, lsl #1]"); + TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4h {z26.h, z27.h, z28.h, " + "z29.h}, p6/z, [x29, x30, lsl #1]"); - TEST_SINGLE(ld2w(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2w {z31.s, z0.s}, p6/z, [x29, x30, lsl #2]"); + TEST_SINGLE(ld2w(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2w {z31.s, z0.s}, p6/z, [x29, x30, lsl #2]"); TEST_SINGLE(ld2w(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2w {z26.s, z27.s}, p6/z, [x29, x30, lsl #2]"); - TEST_SINGLE(ld3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3w {z31.s, z0.s, z1.s}, p6/z, [x29, x30, lsl #2]"); - TEST_SINGLE(ld3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3w {z26.s, z27.s, z28.s}, p6/z, [x29, x30, lsl #2]"); - TEST_SINGLE(ld4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4w {z31.s, z0.s, z1.s, z2.s}, p6/z, [x29, x30, lsl #2]"); - TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4w {z26.s, z27.s, z28.s, z29.s}, p6/z, [x29, x30, lsl #2]"); + TEST_SINGLE(ld3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3w {z31.s, z0.s, z1.s}, p6/z, [x29, x30, lsl " + "#2]"); + TEST_SINGLE(ld3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3w {z26.s, z27.s, z28.s}, p6/z, [x29, x30, " + "lsl #2]"); + TEST_SINGLE(ld4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4w {z31.s, z0.s, z1.s, z2.s}, " + "p6/z, [x29, x30, lsl #2]"); + TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4w {z26.s, z27.s, z28.s, " + "z29.s}, p6/z, [x29, x30, lsl #2]"); - TEST_SINGLE(ld2d(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2d {z31.d, z0.d}, p6/z, [x29, x30, lsl #3]"); + TEST_SINGLE(ld2d(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2d {z31.d, z0.d}, p6/z, [x29, x30, lsl #3]"); TEST_SINGLE(ld2d(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld2d {z26.d, z27.d}, p6/z, [x29, x30, lsl #3]"); - TEST_SINGLE(ld3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3d {z31.d, z0.d, z1.d}, p6/z, [x29, x30, lsl #3]"); - TEST_SINGLE(ld3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3d {z26.d, z27.d, z28.d}, p6/z, [x29, x30, lsl #3]"); - TEST_SINGLE(ld4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4d {z31.d, z0.d, z1.d, z2.d}, p6/z, [x29, x30, lsl #3]"); - TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4d {z26.d, z27.d, z28.d, z29.d}, p6/z, [x29, x30, lsl #3]"); + TEST_SINGLE(ld3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3d {z31.d, z0.d, z1.d}, p6/z, [x29, x30, lsl " + "#3]"); + TEST_SINGLE(ld3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld3d {z26.d, z27.d, z28.d}, p6/z, [x29, x30, " + "lsl #3]"); + TEST_SINGLE(ld4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4d {z31.d, z0.d, z1.d, z2.d}, " + "p6/z, [x29, x30, lsl #3]"); + TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld4d {z26.d, z27.d, z28.d, " + "z29.d}, p6/z, [x29, x30, lsl #3]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE load and broadcast quadword (scalar plus immediate)") { - TEST_SINGLE(ld1rqb(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqb {z30.b}, p6/z, [x29]"); + TEST_SINGLE(ld1rqb(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqb {z30.b}, p6/z, [x29]"); TEST_SINGLE(ld1rqb(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -128), "ld1rqb {z30.b}, p6/z, [x29, #-128]"); - TEST_SINGLE(ld1rqb(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqb {z30.b}, p6/z, [x29, #112]"); + TEST_SINGLE(ld1rqb(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqb {z30.b}, p6/z, [x29, #112]"); - TEST_SINGLE(ld1rob(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rob {z30.b}, p6/z, [x29]"); + TEST_SINGLE(ld1rob(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rob {z30.b}, p6/z, [x29]"); TEST_SINGLE(ld1rob(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -256), "ld1rob {z30.b}, p6/z, [x29, #-256]"); - TEST_SINGLE(ld1rob(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1rob {z30.b}, p6/z, [x29, #224]"); + TEST_SINGLE(ld1rob(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1rob {z30.b}, p6/z, [x29, #224]"); - TEST_SINGLE(ld1rqh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqh {z30.h}, p6/z, [x29]"); + TEST_SINGLE(ld1rqh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqh {z30.h}, p6/z, [x29]"); TEST_SINGLE(ld1rqh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -128), "ld1rqh {z30.h}, p6/z, [x29, #-128]"); - TEST_SINGLE(ld1rqh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqh {z30.h}, p6/z, [x29, #112]"); + TEST_SINGLE(ld1rqh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqh {z30.h}, p6/z, [x29, #112]"); - TEST_SINGLE(ld1roh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1roh {z30.h}, p6/z, [x29]"); + TEST_SINGLE(ld1roh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1roh {z30.h}, p6/z, [x29]"); TEST_SINGLE(ld1roh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -256), "ld1roh {z30.h}, p6/z, [x29, #-256]"); - TEST_SINGLE(ld1roh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1roh {z30.h}, p6/z, [x29, #224]"); + TEST_SINGLE(ld1roh(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1roh {z30.h}, p6/z, [x29, #224]"); - TEST_SINGLE(ld1rqw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqw {z30.s}, p6/z, [x29]"); + TEST_SINGLE(ld1rqw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqw {z30.s}, p6/z, [x29]"); TEST_SINGLE(ld1rqw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -128), "ld1rqw {z30.s}, p6/z, [x29, #-128]"); - TEST_SINGLE(ld1rqw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqw {z30.s}, p6/z, [x29, #112]"); + TEST_SINGLE(ld1rqw(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqw {z30.s}, p6/z, [x29, #112]"); - TEST_SINGLE(ld1row(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1row {z30.s}, p6/z, [x29]"); + TEST_SINGLE(ld1row(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1row {z30.s}, p6/z, [x29]"); TEST_SINGLE(ld1row(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -256), "ld1row {z30.s}, p6/z, [x29, #-256]"); - TEST_SINGLE(ld1row(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1row {z30.s}, p6/z, [x29, #224]"); + TEST_SINGLE(ld1row(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1row {z30.s}, p6/z, [x29, #224]"); - TEST_SINGLE(ld1rqd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqd {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rqd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rqd {z30.d}, p6/z, [x29]"); TEST_SINGLE(ld1rqd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -128), "ld1rqd {z30.d}, p6/z, [x29, #-128]"); - TEST_SINGLE(ld1rqd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqd {z30.d}, p6/z, [x29, #112]"); + TEST_SINGLE(ld1rqd(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 112), "ld1rqd {z30.d}, p6/z, [x29, #112]"); - TEST_SINGLE(ld1rod(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rod {z30.d}, p6/z, [x29]"); + TEST_SINGLE(ld1rod(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 0), "ld1rod {z30.d}, p6/z, [x29]"); TEST_SINGLE(ld1rod(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, -256), "ld1rod {z30.d}, p6/z, [x29, #-256]"); - TEST_SINGLE(ld1rod(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1rod {z30.d}, p6/z, [x29, #224]"); + TEST_SINGLE(ld1rod(ZReg::z30, PReg::p6.Zeroing(), Reg::r29, 224), "ld1rod {z30.d}, p6/z, [x29, #224]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE load and broadcast quadword (scalar plus scalar)") { @@ -4231,65 +4080,89 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE load and broadcast quadwor } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE load multiple structures (scalar plus immediate)") { - TEST_SINGLE(ld2b(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2b {z31.b, z0.b}, p6/z, [x29]"); + TEST_SINGLE(ld2b(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2b {z31.b, z0.b}, p6/z, [x29]"); TEST_SINGLE(ld2b(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 0), "ld2b {z26.b, z27.b}, p6/z, [x29]"); TEST_SINGLE(ld2b(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, -16), "ld2b {z26.b, z27.b}, p6/z, [x29, #-16, mul vl]"); TEST_SINGLE(ld2b(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 14), "ld2b {z26.b, z27.b}, p6/z, [x29, #14, mul vl]"); - TEST_SINGLE(ld2h(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2h {z31.h, z0.h}, p6/z, [x29]"); + TEST_SINGLE(ld2h(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2h {z31.h, z0.h}, p6/z, [x29]"); TEST_SINGLE(ld2h(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 0), "ld2h {z26.h, z27.h}, p6/z, [x29]"); TEST_SINGLE(ld2h(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, -16), "ld2h {z26.h, z27.h}, p6/z, [x29, #-16, mul vl]"); TEST_SINGLE(ld2h(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 14), "ld2h {z26.h, z27.h}, p6/z, [x29, #14, mul vl]"); - TEST_SINGLE(ld2w(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2w {z31.s, z0.s}, p6/z, [x29]"); + TEST_SINGLE(ld2w(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2w {z31.s, z0.s}, p6/z, [x29]"); TEST_SINGLE(ld2w(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 0), "ld2w {z26.s, z27.s}, p6/z, [x29]"); TEST_SINGLE(ld2w(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, -16), "ld2w {z26.s, z27.s}, p6/z, [x29, #-16, mul vl]"); TEST_SINGLE(ld2w(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 14), "ld2w {z26.s, z27.s}, p6/z, [x29, #14, mul vl]"); - TEST_SINGLE(ld2d(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2d {z31.d, z0.d}, p6/z, [x29]"); + TEST_SINGLE(ld2d(ZReg::z31, ZReg::z0, PReg::p6.Zeroing(), Reg::r29, 0), "ld2d {z31.d, z0.d}, p6/z, [x29]"); TEST_SINGLE(ld2d(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 0), "ld2d {z26.d, z27.d}, p6/z, [x29]"); TEST_SINGLE(ld2d(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, -16), "ld2d {z26.d, z27.d}, p6/z, [x29, #-16, mul vl]"); TEST_SINGLE(ld2d(ZReg::z26, ZReg::z27, PReg::p6.Zeroing(), Reg::r29, 14), "ld2d {z26.d, z27.d}, p6/z, [x29, #14, mul vl]"); - TEST_SINGLE(ld3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3b {z31.b, z0.b, z1.b}, p6/z, [x29]"); + TEST_SINGLE(ld3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3b {z31.b, z0.b, z1.b}, p6/z, [x29]"); TEST_SINGLE(ld3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 0), "ld3b {z26.b, z27.b, z28.b}, p6/z, [x29]"); - TEST_SINGLE(ld3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3b {z26.b, z27.b, z28.b}, p6/z, [x29, #-24, mul vl]"); - TEST_SINGLE(ld3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3b {z26.b, z27.b, z28.b}, p6/z, [x29, #21, mul vl]"); + TEST_SINGLE(ld3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3b {z26.b, z27.b, z28.b}, p6/z, [x29, #-24, mul " + "vl]"); + TEST_SINGLE(ld3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3b {z26.b, z27.b, z28.b}, p6/z, [x29, #21, mul " + "vl]"); - TEST_SINGLE(ld3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3h {z31.h, z0.h, z1.h}, p6/z, [x29]"); + TEST_SINGLE(ld3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3h {z31.h, z0.h, z1.h}, p6/z, [x29]"); TEST_SINGLE(ld3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 0), "ld3h {z26.h, z27.h, z28.h}, p6/z, [x29]"); - TEST_SINGLE(ld3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3h {z26.h, z27.h, z28.h}, p6/z, [x29, #-24, mul vl]"); - TEST_SINGLE(ld3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3h {z26.h, z27.h, z28.h}, p6/z, [x29, #21, mul vl]"); + TEST_SINGLE(ld3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3h {z26.h, z27.h, z28.h}, p6/z, [x29, #-24, mul " + "vl]"); + TEST_SINGLE(ld3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3h {z26.h, z27.h, z28.h}, p6/z, [x29, #21, mul " + "vl]"); - TEST_SINGLE(ld3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3w {z31.s, z0.s, z1.s}, p6/z, [x29]"); + TEST_SINGLE(ld3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3w {z31.s, z0.s, z1.s}, p6/z, [x29]"); TEST_SINGLE(ld3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 0), "ld3w {z26.s, z27.s, z28.s}, p6/z, [x29]"); - TEST_SINGLE(ld3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3w {z26.s, z27.s, z28.s}, p6/z, [x29, #-24, mul vl]"); - TEST_SINGLE(ld3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3w {z26.s, z27.s, z28.s}, p6/z, [x29, #21, mul vl]"); + TEST_SINGLE(ld3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3w {z26.s, z27.s, z28.s}, p6/z, [x29, #-24, mul " + "vl]"); + TEST_SINGLE(ld3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3w {z26.s, z27.s, z28.s}, p6/z, [x29, #21, mul " + "vl]"); - TEST_SINGLE(ld3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3d {z31.d, z0.d, z1.d}, p6/z, [x29]"); + TEST_SINGLE(ld3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6.Zeroing(), Reg::r29, 0), "ld3d {z31.d, z0.d, z1.d}, p6/z, [x29]"); TEST_SINGLE(ld3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 0), "ld3d {z26.d, z27.d, z28.d}, p6/z, [x29]"); - TEST_SINGLE(ld3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3d {z26.d, z27.d, z28.d}, p6/z, [x29, #-24, mul vl]"); - TEST_SINGLE(ld3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3d {z26.d, z27.d, z28.d}, p6/z, [x29, #21, mul vl]"); + TEST_SINGLE(ld3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, -24), "ld3d {z26.d, z27.d, z28.d}, p6/z, [x29, #-24, mul " + "vl]"); + TEST_SINGLE(ld3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6.Zeroing(), Reg::r29, 21), "ld3d {z26.d, z27.d, z28.d}, p6/z, [x29, #21, mul " + "vl]"); - TEST_SINGLE(ld4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4b {z31.b, z0.b, z1.b, z2.b}, p6/z, [x29]"); - TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4b {z26.b, z27.b, z28.b, z29.b}, p6/z, [x29]"); - TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4b {z26.b, z27.b, z28.b, z29.b}, p6/z, [x29, #-32, mul vl]"); - TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4b {z26.b, z27.b, z28.b, z29.b}, p6/z, [x29, #28, mul vl]"); + TEST_SINGLE(ld4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4b {z31.b, z0.b, z1.b, z2.b}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4b {z26.b, z27.b, z28.b, z29.b}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4b {z26.b, z27.b, z28.b, z29.b}, " + "p6/z, [x29, #-32, mul vl]"); + TEST_SINGLE(ld4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4b {z26.b, z27.b, z28.b, z29.b}, " + "p6/z, [x29, #28, mul vl]"); - TEST_SINGLE(ld4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4h {z31.h, z0.h, z1.h, z2.h}, p6/z, [x29]"); - TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4h {z26.h, z27.h, z28.h, z29.h}, p6/z, [x29]"); - TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4h {z26.h, z27.h, z28.h, z29.h}, p6/z, [x29, #-32, mul vl]"); - TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4h {z26.h, z27.h, z28.h, z29.h}, p6/z, [x29, #28, mul vl]"); + TEST_SINGLE(ld4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4h {z31.h, z0.h, z1.h, z2.h}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4h {z26.h, z27.h, z28.h, z29.h}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4h {z26.h, z27.h, z28.h, z29.h}, " + "p6/z, [x29, #-32, mul vl]"); + TEST_SINGLE(ld4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4h {z26.h, z27.h, z28.h, z29.h}, " + "p6/z, [x29, #28, mul vl]"); - TEST_SINGLE(ld4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4w {z31.s, z0.s, z1.s, z2.s}, p6/z, [x29]"); - TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4w {z26.s, z27.s, z28.s, z29.s}, p6/z, [x29]"); - TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4w {z26.s, z27.s, z28.s, z29.s}, p6/z, [x29, #-32, mul vl]"); - TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4w {z26.s, z27.s, z28.s, z29.s}, p6/z, [x29, #28, mul vl]"); + TEST_SINGLE(ld4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4w {z31.s, z0.s, z1.s, z2.s}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4w {z26.s, z27.s, z28.s, z29.s}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4w {z26.s, z27.s, z28.s, z29.s}, " + "p6/z, [x29, #-32, mul vl]"); + TEST_SINGLE(ld4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4w {z26.s, z27.s, z28.s, z29.s}, " + "p6/z, [x29, #28, mul vl]"); - TEST_SINGLE(ld4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4d {z31.d, z0.d, z1.d, z2.d}, p6/z, [x29]"); - TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4d {z26.d, z27.d, z28.d, z29.d}, p6/z, [x29]"); - TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4d {z26.d, z27.d, z28.d, z29.d}, p6/z, [x29, #-32, mul vl]"); - TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4d {z26.d, z27.d, z28.d, z29.d}, p6/z, [x29, #28, mul vl]"); + TEST_SINGLE(ld4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6.Zeroing(), Reg::r29, 0), "ld4d {z31.d, z0.d, z1.d, z2.d}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 0), "ld4d {z26.d, z27.d, z28.d, z29.d}, p6/z, " + "[x29]"); + TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, -32), "ld4d {z26.d, z27.d, z28.d, z29.d}, " + "p6/z, [x29, #-32, mul vl]"); + TEST_SINGLE(ld4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6.Zeroing(), Reg::r29, 28), "ld4d {z26.d, z27.d, z28.d, z29.d}, " + "p6/z, [x29, #28, mul vl]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous load (scalar plus immediate)") { TEST_SINGLE(ld1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1b {z26.b}, p6/z, [x29]"); @@ -4311,38 +4184,38 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous load (scalar pl TEST_SINGLE(ld1sw(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sw {z26.d}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1sw(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sw {z26.d}, p6/z, [x29, #7, mul vl]"); - TEST_SINGLE(ld1w(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1w {z26.s}, p6/z, [x29]"); - TEST_SINGLE(ld1w(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1w {z26.d}, p6/z, [x29]"); + TEST_SINGLE(ld1w(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1w {z26.s}, p6/z, [x29]"); + TEST_SINGLE(ld1w(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1w {z26.d}, p6/z, [x29]"); TEST_SINGLE(ld1w(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1w {z26.s}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1w(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1w {z26.d}, p6/z, [x29, #-8, mul vl]"); - //TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1h {z26.b}, p6/z, [x29]"); + // TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1h {z26.b}, p6/z, [x29]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1h {z26.h}, p6/z, [x29]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1h {z26.s}, p6/z, [x29]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1h {z26.d}, p6/z, [x29]"); - //TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1h {z26.b}, p6/z, [x29, #-8, mul vl]"); + // TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1h {z26.b}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1h {z26.h}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1h {z26.s}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1h {z26.d}, p6/z, [x29, #-8, mul vl]"); - //TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1h {z26.b}, p6/z, [x29, #7, mul vl]"); + // TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1h {z26.b}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1h {z26.h}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1h {z26.s}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1h {z26.d}, p6/z, [x29, #7, mul vl]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sh {z26.b}, p6/z, [x29]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sh {z26.h}, p6/z, [x29]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sh {z26.b}, p6/z, [x29]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sh {z26.h}, p6/z, [x29]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sh {z26.s}, p6/z, [x29]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sh {z26.d}, p6/z, [x29]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sh {z26.b}, p6/z, [x29, #-8, mul vl]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sh {z26.h}, p6/z, [x29, #-8, mul vl]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sh {z26.b}, p6/z, [x29, #-8, mul vl]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sh {z26.h}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sh {z26.s}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sh {z26.d}, p6/z, [x29, #-8, mul vl]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sh {z26.b}, p6/z, [x29, #7, mul vl]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sh {z26.h}, p6/z, [x29, #7, mul vl]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sh {z26.b}, p6/z, [x29, #7, mul vl]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sh {z26.h}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sh {z26.s}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sh {z26.d}, p6/z, [x29, #7, mul vl]"); @@ -4350,17 +4223,17 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous load (scalar pl TEST_SINGLE(ld1sw(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sw {z26.d}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1sw(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sw {z26.d}, p6/z, [x29, #7, mul vl]"); - //TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sb {z26.b}, p6/z, [x29]"); + // TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sb {z26.b}, p6/z, [x29]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sb {z26.h}, p6/z, [x29]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sb {z26.s}, p6/z, [x29]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 0), "ld1sb {z26.d}, p6/z, [x29]"); - //TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sb {z26.b}, p6/z, [x29, #-8, mul vl]"); + // TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sb {z26.b}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sb {z26.h}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sb {z26.s}, p6/z, [x29, #-8, mul vl]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, -8), "ld1sb {z26.d}, p6/z, [x29, #-8, mul vl]"); - //TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sb {z26.b}, p6/z, [x29, #7, mul vl]"); + // TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sb {z26.b}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sb {z26.h}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sb {z26.s}, p6/z, [x29, #7, mul vl]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, 7), "ld1sb {z26.d}, p6/z, [x29, #7, mul vl]"); @@ -4375,13 +4248,13 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous store (scalar p TEST_SINGLE(st1b(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1b {z26.s}, p6, [x29, x28]"); TEST_SINGLE(st1b(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1b {z26.d}, p6, [x29, x28]"); - //TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1h {z26.b}, p6, [x29, x28, lsl #1]"); + // TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1h {z26.b}, p6, [x29, x28, lsl #1]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1h {z26.h}, p6, [x29, x28, lsl #1]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1h {z26.s}, p6, [x29, x28, lsl #1]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1h {z26.d}, p6, [x29, x28, lsl #1]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1w {z26.b}, p6, [x29, x28, lsl #2]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1w {z26.h}, p6, [x29, x28, lsl #2]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1w {z26.b}, p6, [x29, x28, lsl #2]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1w {z26.h}, p6, [x29, x28, lsl #2]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1w {z26.s}, p6, [x29, x28, lsl #2]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, Reg::r28), "st1w {z26.d}, p6, [x29, x28, lsl #2]"); @@ -4393,18 +4266,18 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous load (scalar pl TEST_SINGLE(ld1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1b {z26.s}, p6/z, [x29, x30]"); TEST_SINGLE(ld1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1b {z26.d}, p6/z, [x29, x30]"); - //TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sb {z26.b}, p6/z, [x29, x30]"); + // TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sb {z26.b}, p6/z, [x29, x30]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sb {z26.h}, p6/z, [x29, x30]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sb {z26.s}, p6/z, [x29, x30]"); TEST_SINGLE(ld1sb(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sb {z26.d}, p6/z, [x29, x30]"); - //TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1h {z26.b}, p6/z, [x29, x30, lsl #1]"); + // TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1h {z26.b}, p6/z, [x29, x30, lsl #1]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1h {z26.h}, p6/z, [x29, x30, lsl #1]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1h {z26.s}, p6/z, [x29, x30, lsl #1]"); TEST_SINGLE(ld1h(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1h {z26.d}, p6/z, [x29, x30, lsl #1]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sh {z26.b}, p6/z, [x29, x30, lsl #1]"); - //TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sh {z26.h}, p6/z, [x29, x30, lsl #1]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sh {z26.b}, p6/z, [x29, x30, lsl #1]"); + // TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sh {z26.h}, p6/z, [x29, x30, lsl #1]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sh {z26.s}, p6/z, [x29, x30, lsl #1]"); TEST_SINGLE(ld1sh(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1sh {z26.d}, p6/z, [x29, x30, lsl #1]"); @@ -4416,7 +4289,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous load (scalar pl TEST_SINGLE(ld1d(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ld1d {z26.d}, p6/z, [x29, x30, lsl #3]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous first-fault load (scalar plus scalar)") { - TEST_SINGLE(ldff1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ldff1b {z26.b}, p6/z, [x29, x30]"); + TEST_SINGLE(ldff1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ldff1b {z26.b}, p6/z, [x29, x30]"); TEST_SINGLE(ldff1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ldff1b {z26.h}, p6/z, [x29, x30]"); TEST_SINGLE(ldff1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ldff1b {z26.s}, p6/z, [x29, x30]"); TEST_SINGLE(ldff1b(ZReg::z26, PReg::p6.Zeroing(), Reg::r29, Reg::r30), "ldff1b {z26.d}, p6/z, [x29, x30]"); @@ -4491,11 +4364,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer convert to floatin TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "scvtf z30.h, p6/m, z29.s"); TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "scvtf z30.h, p6/m, z29.d"); - //TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "scvtf z30.s, p6/m, z29.h"); + // TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "scvtf z30.s, p6/m, z29.h"); TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "scvtf z30.s, p6/m, z29.s"); TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "scvtf z30.s, p6/m, z29.d"); - //TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "scvtf z30.d, p6/m, z29.h"); + // TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "scvtf z30.d, p6/m, z29.h"); TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "scvtf z30.d, p6/m, z29.s"); TEST_SINGLE(scvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "scvtf z30.d, p6/m, z29.d"); @@ -4503,11 +4376,11 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer convert to floatin TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "ucvtf z30.h, p6/m, z29.s"); TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "ucvtf z30.h, p6/m, z29.d"); - //TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "ucvtf z30.s, p6/m, z29.h"); + // TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "ucvtf z30.s, p6/m, z29.h"); TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "ucvtf z30.s, p6/m, z29.s"); TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "ucvtf z30.s, p6/m, z29.d"); - //TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "ucvtf z30.d, p6/m, z29.h"); + // TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "ucvtf z30.d, p6/m, z29.h"); TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "ucvtf z30.d, p6/m, z29.s"); TEST_SINGLE(ucvtf(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "ucvtf z30.d, p6/m, z29.d"); } @@ -4518,8 +4391,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point convert to TEST_SINGLE(flogb(SubRegSize::i64Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "flogb z30.d, p6/m, z29.d"); TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "fcvtzs z30.h, p6/m, z29.h"); - //TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "fcvtzs z30.h, p6/m, z29.s"); - //TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "fcvtzs z30.h, p6/m, z29.d"); + // TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "fcvtzs z30.h, p6/m, z29.s"); + // TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "fcvtzs z30.h, p6/m, z29.d"); TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "fcvtzs z30.s, p6/m, z29.h"); TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "fcvtzs z30.s, p6/m, z29.s"); @@ -4530,8 +4403,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point convert to TEST_SINGLE(fcvtzs(ZReg::z30, SubRegSize::i64Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "fcvtzs z30.d, p6/m, z29.d"); TEST_SINGLE(fcvtzu(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "fcvtzu z30.h, p6/m, z29.h"); - //TEST_SINGLE(fcvtzu(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "fcvtzu z30.h, p6/m, z29.s"); - //TEST_SINGLE(fcvtzu(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "fcvtzu z30.h, p6/m, z29.d"); + // TEST_SINGLE(fcvtzu(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "fcvtzu z30.h, p6/m, z29.s"); + // TEST_SINGLE(fcvtzu(ZReg::z30, SubRegSize::i16Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i64Bit), "fcvtzu z30.h, p6/m, z29.d"); TEST_SINGLE(fcvtzu(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i16Bit), "fcvtzu z30.s, p6/m, z29.h"); TEST_SINGLE(fcvtzu(ZReg::z30, SubRegSize::i32Bit, PReg::p6.Merging(), ZReg::z29, SubRegSize::i32Bit), "fcvtzu z30.s, p6/m, z29.s"); @@ -4621,95 +4494,111 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point multiply-ac } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE store multiple structures (scalar plus scalar)") { - TEST_SINGLE(st2b(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2b {z31.b, z0.b}, p6, [x29, x30]"); - TEST_SINGLE(st2b(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2b {z26.b, z27.b}, p6, [x29, x30]"); - TEST_SINGLE(st3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3b {z31.b, z0.b, z1.b}, p6, [x29, x30]"); - TEST_SINGLE(st3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3b {z26.b, z27.b, z28.b}, p6, [x29, x30]"); - TEST_SINGLE(st4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4b {z31.b, z0.b, z1.b, z2.b}, p6, [x29, x30]"); - TEST_SINGLE(st4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4b {z26.b, z27.b, z28.b, z29.b}, p6, [x29, x30]"); + TEST_SINGLE(st2b(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2b {z31.b, z0.b}, p6, [x29, x30]"); + TEST_SINGLE(st2b(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2b {z26.b, z27.b}, p6, [x29, x30]"); + TEST_SINGLE(st3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3b {z31.b, z0.b, z1.b}, p6, [x29, x30]"); + TEST_SINGLE(st3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3b {z26.b, z27.b, z28.b}, p6, [x29, x30]"); + TEST_SINGLE(st4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4b {z31.b, z0.b, z1.b, z2.b}, p6, [x29, " + "x30]"); + TEST_SINGLE(st4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4b {z26.b, z27.b, z28.b, z29.b}, p6, " + "[x29, x30]"); - TEST_SINGLE(st2h(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2h {z31.h, z0.h}, p6, [x29, x30, lsl #1]"); - TEST_SINGLE(st2h(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2h {z26.h, z27.h}, p6, [x29, x30, lsl #1]"); - TEST_SINGLE(st3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3h {z31.h, z0.h, z1.h}, p6, [x29, x30, lsl #1]"); - TEST_SINGLE(st3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3h {z26.h, z27.h, z28.h}, p6, [x29, x30, lsl #1]"); - TEST_SINGLE(st4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4h {z31.h, z0.h, z1.h, z2.h}, p6, [x29, x30, lsl #1]"); - TEST_SINGLE(st4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4h {z26.h, z27.h, z28.h, z29.h}, p6, [x29, x30, lsl #1]"); + TEST_SINGLE(st2h(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2h {z31.h, z0.h}, p6, [x29, x30, lsl #1]"); + TEST_SINGLE(st2h(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2h {z26.h, z27.h}, p6, [x29, x30, lsl #1]"); + TEST_SINGLE(st3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3h {z31.h, z0.h, z1.h}, p6, [x29, x30, lsl #1]"); + TEST_SINGLE(st3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3h {z26.h, z27.h, z28.h}, p6, [x29, x30, lsl #1]"); + TEST_SINGLE(st4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4h {z31.h, z0.h, z1.h, z2.h}, p6, [x29, x30, " + "lsl #1]"); + TEST_SINGLE(st4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4h {z26.h, z27.h, z28.h, z29.h}, p6, " + "[x29, x30, lsl #1]"); - TEST_SINGLE(st2w(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2w {z31.s, z0.s}, p6, [x29, x30, lsl #2]"); - TEST_SINGLE(st2w(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2w {z26.s, z27.s}, p6, [x29, x30, lsl #2]"); - TEST_SINGLE(st3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3w {z31.s, z0.s, z1.s}, p6, [x29, x30, lsl #2]"); - TEST_SINGLE(st3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3w {z26.s, z27.s, z28.s}, p6, [x29, x30, lsl #2]"); - TEST_SINGLE(st4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4w {z31.s, z0.s, z1.s, z2.s}, p6, [x29, x30, lsl #2]"); - TEST_SINGLE(st4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4w {z26.s, z27.s, z28.s, z29.s}, p6, [x29, x30, lsl #2]"); + TEST_SINGLE(st2w(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2w {z31.s, z0.s}, p6, [x29, x30, lsl #2]"); + TEST_SINGLE(st2w(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2w {z26.s, z27.s}, p6, [x29, x30, lsl #2]"); + TEST_SINGLE(st3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3w {z31.s, z0.s, z1.s}, p6, [x29, x30, lsl #2]"); + TEST_SINGLE(st3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3w {z26.s, z27.s, z28.s}, p6, [x29, x30, lsl #2]"); + TEST_SINGLE(st4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4w {z31.s, z0.s, z1.s, z2.s}, p6, [x29, x30, " + "lsl #2]"); + TEST_SINGLE(st4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4w {z26.s, z27.s, z28.s, z29.s}, p6, " + "[x29, x30, lsl #2]"); - TEST_SINGLE(st2d(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2d {z31.d, z0.d}, p6, [x29, x30, lsl #3]"); - TEST_SINGLE(st2d(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2d {z26.d, z27.d}, p6, [x29, x30, lsl #3]"); - TEST_SINGLE(st3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3d {z31.d, z0.d, z1.d}, p6, [x29, x30, lsl #3]"); - TEST_SINGLE(st3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3d {z26.d, z27.d, z28.d}, p6, [x29, x30, lsl #3]"); - TEST_SINGLE(st4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4d {z31.d, z0.d, z1.d, z2.d}, p6, [x29, x30, lsl #3]"); - TEST_SINGLE(st4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4d {z26.d, z27.d, z28.d, z29.d}, p6, [x29, x30, lsl #3]"); + TEST_SINGLE(st2d(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, Reg::r30), "st2d {z31.d, z0.d}, p6, [x29, x30, lsl #3]"); + TEST_SINGLE(st2d(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, Reg::r30), "st2d {z26.d, z27.d}, p6, [x29, x30, lsl #3]"); + TEST_SINGLE(st3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, Reg::r30), "st3d {z31.d, z0.d, z1.d}, p6, [x29, x30, lsl #3]"); + TEST_SINGLE(st3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, Reg::r30), "st3d {z26.d, z27.d, z28.d}, p6, [x29, x30, lsl #3]"); + TEST_SINGLE(st4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, Reg::r30), "st4d {z31.d, z0.d, z1.d, z2.d}, p6, [x29, x30, " + "lsl #3]"); + TEST_SINGLE(st4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, Reg::r30), "st4d {z26.d, z27.d, z28.d, z29.d}, p6, " + "[x29, x30, lsl #3]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE store multiple structures (scalar plus immediate)") { - TEST_SINGLE(st2b(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2b {z31.b, z0.b}, p6, [x29]"); + TEST_SINGLE(st2b(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2b {z31.b, z0.b}, p6, [x29]"); TEST_SINGLE(st2b(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 0), "st2b {z26.b, z27.b}, p6, [x29]"); TEST_SINGLE(st2b(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, -16), "st2b {z26.b, z27.b}, p6, [x29, #-16, mul vl]"); TEST_SINGLE(st2b(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 14), "st2b {z26.b, z27.b}, p6, [x29, #14, mul vl]"); - TEST_SINGLE(st2h(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2h {z31.h, z0.h}, p6, [x29]"); + TEST_SINGLE(st2h(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2h {z31.h, z0.h}, p6, [x29]"); TEST_SINGLE(st2h(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 0), "st2h {z26.h, z27.h}, p6, [x29]"); TEST_SINGLE(st2h(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, -16), "st2h {z26.h, z27.h}, p6, [x29, #-16, mul vl]"); TEST_SINGLE(st2h(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 14), "st2h {z26.h, z27.h}, p6, [x29, #14, mul vl]"); - TEST_SINGLE(st2w(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2w {z31.s, z0.s}, p6, [x29]"); + TEST_SINGLE(st2w(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2w {z31.s, z0.s}, p6, [x29]"); TEST_SINGLE(st2w(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 0), "st2w {z26.s, z27.s}, p6, [x29]"); TEST_SINGLE(st2w(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, -16), "st2w {z26.s, z27.s}, p6, [x29, #-16, mul vl]"); TEST_SINGLE(st2w(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 14), "st2w {z26.s, z27.s}, p6, [x29, #14, mul vl]"); - TEST_SINGLE(st2d(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2d {z31.d, z0.d}, p6, [x29]"); + TEST_SINGLE(st2d(ZReg::z31, ZReg::z0, PReg::p6, Reg::r29, 0), "st2d {z31.d, z0.d}, p6, [x29]"); TEST_SINGLE(st2d(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 0), "st2d {z26.d, z27.d}, p6, [x29]"); TEST_SINGLE(st2d(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, -16), "st2d {z26.d, z27.d}, p6, [x29, #-16, mul vl]"); TEST_SINGLE(st2d(ZReg::z26, ZReg::z27, PReg::p6, Reg::r29, 14), "st2d {z26.d, z27.d}, p6, [x29, #14, mul vl]"); - TEST_SINGLE(st3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3b {z31.b, z0.b, z1.b}, p6, [x29]"); + TEST_SINGLE(st3b(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3b {z31.b, z0.b, z1.b}, p6, [x29]"); TEST_SINGLE(st3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 0), "st3b {z26.b, z27.b, z28.b}, p6, [x29]"); TEST_SINGLE(st3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, -24), "st3b {z26.b, z27.b, z28.b}, p6, [x29, #-24, mul vl]"); TEST_SINGLE(st3b(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 21), "st3b {z26.b, z27.b, z28.b}, p6, [x29, #21, mul vl]"); - TEST_SINGLE(st3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3h {z31.h, z0.h, z1.h}, p6, [x29]"); + TEST_SINGLE(st3h(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3h {z31.h, z0.h, z1.h}, p6, [x29]"); TEST_SINGLE(st3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 0), "st3h {z26.h, z27.h, z28.h}, p6, [x29]"); TEST_SINGLE(st3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, -24), "st3h {z26.h, z27.h, z28.h}, p6, [x29, #-24, mul vl]"); TEST_SINGLE(st3h(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 21), "st3h {z26.h, z27.h, z28.h}, p6, [x29, #21, mul vl]"); - TEST_SINGLE(st3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3w {z31.s, z0.s, z1.s}, p6, [x29]"); + TEST_SINGLE(st3w(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3w {z31.s, z0.s, z1.s}, p6, [x29]"); TEST_SINGLE(st3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 0), "st3w {z26.s, z27.s, z28.s}, p6, [x29]"); TEST_SINGLE(st3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, -24), "st3w {z26.s, z27.s, z28.s}, p6, [x29, #-24, mul vl]"); TEST_SINGLE(st3w(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 21), "st3w {z26.s, z27.s, z28.s}, p6, [x29, #21, mul vl]"); - TEST_SINGLE(st3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3d {z31.d, z0.d, z1.d}, p6, [x29]"); + TEST_SINGLE(st3d(ZReg::z31, ZReg::z0, ZReg::z1, PReg::p6, Reg::r29, 0), "st3d {z31.d, z0.d, z1.d}, p6, [x29]"); TEST_SINGLE(st3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 0), "st3d {z26.d, z27.d, z28.d}, p6, [x29]"); TEST_SINGLE(st3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, -24), "st3d {z26.d, z27.d, z28.d}, p6, [x29, #-24, mul vl]"); TEST_SINGLE(st3d(ZReg::z26, ZReg::z27, ZReg::z28, PReg::p6, Reg::r29, 21), "st3d {z26.d, z27.d, z28.d}, p6, [x29, #21, mul vl]"); - TEST_SINGLE(st4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4b {z31.b, z0.b, z1.b, z2.b}, p6, [x29]"); + TEST_SINGLE(st4b(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4b {z31.b, z0.b, z1.b, z2.b}, p6, [x29]"); TEST_SINGLE(st4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 0), "st4b {z26.b, z27.b, z28.b, z29.b}, p6, [x29]"); - TEST_SINGLE(st4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4b {z26.b, z27.b, z28.b, z29.b}, p6, [x29, #-32, mul vl]"); - TEST_SINGLE(st4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4b {z26.b, z27.b, z28.b, z29.b}, p6, [x29, #28, mul vl]"); + TEST_SINGLE(st4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4b {z26.b, z27.b, z28.b, z29.b}, p6, [x29, " + "#-32, mul vl]"); + TEST_SINGLE(st4b(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4b {z26.b, z27.b, z28.b, z29.b}, p6, [x29, #28, " + "mul vl]"); - TEST_SINGLE(st4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4h {z31.h, z0.h, z1.h, z2.h}, p6, [x29]"); + TEST_SINGLE(st4h(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4h {z31.h, z0.h, z1.h, z2.h}, p6, [x29]"); TEST_SINGLE(st4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 0), "st4h {z26.h, z27.h, z28.h, z29.h}, p6, [x29]"); - TEST_SINGLE(st4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4h {z26.h, z27.h, z28.h, z29.h}, p6, [x29, #-32, mul vl]"); - TEST_SINGLE(st4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4h {z26.h, z27.h, z28.h, z29.h}, p6, [x29, #28, mul vl]"); + TEST_SINGLE(st4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4h {z26.h, z27.h, z28.h, z29.h}, p6, [x29, " + "#-32, mul vl]"); + TEST_SINGLE(st4h(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4h {z26.h, z27.h, z28.h, z29.h}, p6, [x29, #28, " + "mul vl]"); - TEST_SINGLE(st4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4w {z31.s, z0.s, z1.s, z2.s}, p6, [x29]"); + TEST_SINGLE(st4w(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4w {z31.s, z0.s, z1.s, z2.s}, p6, [x29]"); TEST_SINGLE(st4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 0), "st4w {z26.s, z27.s, z28.s, z29.s}, p6, [x29]"); - TEST_SINGLE(st4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4w {z26.s, z27.s, z28.s, z29.s}, p6, [x29, #-32, mul vl]"); - TEST_SINGLE(st4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4w {z26.s, z27.s, z28.s, z29.s}, p6, [x29, #28, mul vl]"); + TEST_SINGLE(st4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4w {z26.s, z27.s, z28.s, z29.s}, p6, [x29, " + "#-32, mul vl]"); + TEST_SINGLE(st4w(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4w {z26.s, z27.s, z28.s, z29.s}, p6, [x29, #28, " + "mul vl]"); - TEST_SINGLE(st4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4d {z31.d, z0.d, z1.d, z2.d}, p6, [x29]"); + TEST_SINGLE(st4d(ZReg::z31, ZReg::z0, ZReg::z1, ZReg::z2, PReg::p6, Reg::r29, 0), "st4d {z31.d, z0.d, z1.d, z2.d}, p6, [x29]"); TEST_SINGLE(st4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 0), "st4d {z26.d, z27.d, z28.d, z29.d}, p6, [x29]"); - TEST_SINGLE(st4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4d {z26.d, z27.d, z28.d, z29.d}, p6, [x29, #-32, mul vl]"); - TEST_SINGLE(st4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4d {z26.d, z27.d, z28.d, z29.d}, p6, [x29, #28, mul vl]"); + TEST_SINGLE(st4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, -32), "st4d {z26.d, z27.d, z28.d, z29.d}, p6, [x29, " + "#-32, mul vl]"); + TEST_SINGLE(st4d(ZReg::z26, ZReg::z27, ZReg::z28, ZReg::z29, PReg::p6, Reg::r29, 28), "st4d {z26.d, z27.d, z28.d, z29.d}, p6, [x29, #28, " + "mul vl]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous store (scalar plus immediate)") { TEST_SINGLE(st1b(ZReg::z26, PReg::p6, Reg::r29, 0), "st1b {z26.b}, p6, [x29]"); @@ -4727,33 +4616,33 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous store (scalar p TEST_SINGLE(st1b(ZReg::z26, PReg::p6, Reg::r29, 7), "st1b {z26.s}, p6, [x29, #7, mul vl]"); TEST_SINGLE(st1b(ZReg::z26, PReg::p6, Reg::r29, 7), "st1b {z26.d}, p6, [x29, #7, mul vl]"); - //TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 0), "st1h {z26.b}, p6, [x29]"); + // TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 0), "st1h {z26.b}, p6, [x29]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 0), "st1h {z26.h}, p6, [x29]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 0), "st1h {z26.s}, p6, [x29]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 0), "st1h {z26.d}, p6, [x29]"); - //TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, -8), "st1h {z26.b}, p6, [x29, #-8, mul vl]"); + // TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, -8), "st1h {z26.b}, p6, [x29, #-8, mul vl]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, -8), "st1h {z26.h}, p6, [x29, #-8, mul vl]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, -8), "st1h {z26.s}, p6, [x29, #-8, mul vl]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, -8), "st1h {z26.d}, p6, [x29, #-8, mul vl]"); - //TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 7), "st1h {z26.b}, p6, [x29, #7, mul vl]"); + // TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 7), "st1h {z26.b}, p6, [x29, #7, mul vl]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 7), "st1h {z26.h}, p6, [x29, #7, mul vl]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 7), "st1h {z26.s}, p6, [x29, #7, mul vl]"); TEST_SINGLE(st1h(ZReg::z26, PReg::p6, Reg::r29, 7), "st1h {z26.d}, p6, [x29, #7, mul vl]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 0), "st1w {z26.b}, p6, [x29]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 0), "st1w {z26.h}, p6, [x29]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 0), "st1w {z26.b}, p6, [x29]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 0), "st1w {z26.h}, p6, [x29]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 0), "st1w {z26.s}, p6, [x29]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 0), "st1w {z26.d}, p6, [x29]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, -8), "st1w {z26.b}, p6, [x29, #-8, mul vl]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, -8), "st1w {z26.h}, p6, [x29, #-8, mul vl]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, -8), "st1w {z26.b}, p6, [x29, #-8, mul vl]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, -8), "st1w {z26.h}, p6, [x29, #-8, mul vl]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, -8), "st1w {z26.s}, p6, [x29, #-8, mul vl]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, -8), "st1w {z26.d}, p6, [x29, #-8, mul vl]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 7), "st1w {z26.b}, p6, [x29, #7, mul vl]"); - //TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 7), "st1w {z26.h}, p6, [x29, #7, mul vl]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 7), "st1w {z26.b}, p6, [x29, #7, mul vl]"); + // TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 7), "st1w {z26.h}, p6, [x29, #7, mul vl]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 7), "st1w {z26.s}, p6, [x29, #7, mul vl]"); TEST_SINGLE(st1w(ZReg::z26, PReg::p6, Reg::r29, 7), "st1w {z26.d}, p6, [x29, #7, mul vl]"); @@ -4763,137 +4652,124 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE contiguous store (scalar p } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Scatters") { - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "st1b {z30.s}, p6, [x30, z31.s, uxtw]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "st1b {z30.s}, p6, [x30, z31.s, sxtw]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "st1b {z30.d}, p6, [x30, z31.d, uxtw]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "st1b {z30.d}, p6, [x30, z31.d, sxtw]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "st1b {z30.d}, p6, [x30, z31.d]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "st1b {z30.s}, " + "p6, [x30, " + "z31.s, uxtw]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "st1b {z30.s}, " + "p6, [x30, " + "z31.s, sxtw]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "st1b {z30.d}, " + "p6, [x30, " + "z31.d, uxtw]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "st1b {z30.d}, " + "p6, [x30, " + "z31.d, sxtw]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "st1b {z30.d}, " + "p6, [x30, " + "z31.d]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), - "st1b {z30.s}, p6, [z31.s]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 31)), - "st1b {z30.s}, p6, [z31.s, #31]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), - "st1b {z30.d}, p6, [z31.d]"); - TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 31)), - "st1b {z30.d}, p6, [z31.d, #31]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), "st1b {z30.s}, p6, [z31.s]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 31)), "st1b {z30.s}, p6, [z31.s, #31]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), "st1b {z30.d}, p6, [z31.d]"); + TEST_SINGLE(st1b(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 31)), "st1b {z30.d}, p6, [z31.d, #31]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "st1h {z30.s}, p6, [x30, z31.s, uxtw #1]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "st1h {z30.s}, p6, [x30, z31.s, sxtw #1]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), - "st1h {z30.d}, p6, [x30, z31.d, uxtw #1]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), - "st1h {z30.d}, p6, [x30, z31.d, sxtw #1]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), - "st1h {z30.d}, p6, [x30, z31.d, lsl #1]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), "st1h {z30.s}, " + "p6, [x30, " + "z31.s, uxtw " + "#1]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), "st1h {z30.s}, " + "p6, [x30, " + "z31.s, sxtw " + "#1]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 1)), "st1h {z30.d}, " + "p6, [x30, " + "z31.d, uxtw " + "#1]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 1)), "st1h {z30.d}, " + "p6, [x30, " + "z31.d, sxtw " + "#1]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 1)), "st1h {z30.d}, " + "p6, [x30, " + "z31.d, lsl #1]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "st1h {z30.s}, p6, [x30, z31.s, uxtw]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "st1h {z30.s}, p6, [x30, z31.s, sxtw]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "st1h {z30.d}, p6, [x30, z31.d, uxtw]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "st1h {z30.d}, p6, [x30, z31.d, sxtw]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "st1h {z30.d}, p6, [x30, z31.d]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "st1h {z30.s}, " + "p6, [x30, " + "z31.s, uxtw]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "st1h {z30.s}, " + "p6, [x30, " + "z31.s, sxtw]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "st1h {z30.d}, " + "p6, [x30, " + "z31.d, uxtw]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "st1h {z30.d}, " + "p6, [x30, " + "z31.d, sxtw]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "st1h {z30.d}, " + "p6, [x30, " + "z31.d]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), - "st1h {z30.s}, p6, [z31.s]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 62)), - "st1h {z30.s}, p6, [z31.s, #62]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), - "st1h {z30.d}, p6, [z31.d]"); - TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 62)), - "st1h {z30.d}, p6, [z31.d, #62]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), "st1h {z30.s}, p6, [z31.s]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 62)), "st1h {z30.s}, p6, [z31.s, #62]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), "st1h {z30.d}, p6, [z31.d]"); + TEST_SINGLE(st1h(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 62)), "st1h {z30.d}, p6, [z31.d, #62]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "st1w {z30.s}, p6, [x30, z31.s, uxtw #2]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "st1w {z30.s}, p6, [x30, z31.s, sxtw #2]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), - "st1w {z30.d}, p6, [x30, z31.d, uxtw #2]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), - "st1w {z30.d}, p6, [x30, z31.d, sxtw #2]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), - "st1w {z30.d}, p6, [x30, z31.d, lsl #2]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), "st1w {z30.s}, " + "p6, [x30, " + "z31.s, uxtw " + "#2]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), "st1w {z30.s}, " + "p6, [x30, " + "z31.s, sxtw " + "#2]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 2)), "st1w {z30.d}, " + "p6, [x30, " + "z31.d, uxtw " + "#2]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 2)), "st1w {z30.d}, " + "p6, [x30, " + "z31.d, sxtw " + "#2]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 2)), "st1w {z30.d}, " + "p6, [x30, " + "z31.d, lsl #2]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "st1w {z30.s}, p6, [x30, z31.s, uxtw]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "st1w {z30.s}, p6, [x30, z31.s, sxtw]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "st1w {z30.d}, p6, [x30, z31.d, uxtw]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "st1w {z30.d}, p6, [x30, z31.d, sxtw]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "st1w {z30.d}, p6, [x30, z31.d]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "st1w {z30.s}, " + "p6, [x30, " + "z31.s, uxtw]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "st1w {z30.s}, " + "p6, [x30, " + "z31.s, sxtw]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "st1w {z30.d}, " + "p6, [x30, " + "z31.d, uxtw]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "st1w {z30.d}, " + "p6, [x30, " + "z31.d, sxtw]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "st1w {z30.d}, " + "p6, [x30, " + "z31.d]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), - "st1w {z30.s}, p6, [z31.s]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 124)), - "st1w {z30.s}, p6, [z31.s, #124]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), - "st1w {z30.d}, p6, [z31.d]"); - TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 124)), - "st1w {z30.d}, p6, [z31.d, #124]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), "st1w {z30.s}, p6, [z31.s]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 124)), "st1w {z30.s}, p6, [z31.s, #124]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), "st1w {z30.d}, p6, [z31.d]"); + TEST_SINGLE(st1w(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 124)), "st1w {z30.d}, p6, [z31.d, #124]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 3)), - "st1d {z30.d}, p6, [x30, z31.d, uxtw #3]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 3)), - "st1d {z30.d}, p6, [x30, z31.d, sxtw #3]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 3)), - "st1d {z30.d}, p6, [x30, z31.d, lsl #3]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 3)), "st1d {z30.d}, p6, [x30, z31.d, " + "uxtw #3]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 3)), "st1d {z30.d}, p6, [x30, z31.d, " + "sxtw #3]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_LSL, 3)), "st1d {z30.d}, p6, [x30, z31.d, lsl " + "#3]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), - "st1d {z30.d}, p6, [x30, z31.d, uxtw]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), - "st1d {z30.d}, p6, [x30, z31.d, sxtw]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, - SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), - "st1d {z30.d}, p6, [x30, z31.d]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_UXTW, 0)), "st1d {z30.d}, p6, [x30, z31.d, " + "uxtw]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_SXTW, 0)), "st1d {z30.d}, p6, [x30, z31.d, " + "sxtw]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(XReg::x30, ZReg::z31, SVEModType::MOD_NONE, 0)), "st1d {z30.d}, p6, [x30, z31.d]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), - "st1d {z30.d}, p6, [z31.d]"); - TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 248)), - "st1d {z30.d}, p6, [z31.d, #248]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 0)), "st1d {z30.d}, p6, [z31.d]"); + TEST_SINGLE(st1d(ZReg::z30, PReg::p6, SVEMemOperand(ZReg::z31, 248)), "st1d {z30.d}, p6, [z31.d, #248]"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE Unsized Stores") { diff --git a/FEXCore/unittests/Emitter/Scalar_Tests.cpp b/FEXCore/unittests/Emitter/Scalar_Tests.cpp index 2d27bb97d..2fe862872 100644 --- a/FEXCore/unittests/Emitter/Scalar_Tests.cpp +++ b/FEXCore/unittests/Emitter/Scalar_Tests.cpp @@ -64,227 +64,227 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three } TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar two-register miscellaneous") { // Commented out lines showcase unallocated encodings. - TEST_SINGLE(suqadd(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "suqadd b30, b29"); + TEST_SINGLE(suqadd(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "suqadd b30, b29"); TEST_SINGLE(suqadd(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "suqadd h30, h29"); TEST_SINGLE(suqadd(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "suqadd s30, s29"); TEST_SINGLE(suqadd(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "suqadd d30, d29"); - TEST_SINGLE(sqabs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqabs b30, b29"); + TEST_SINGLE(sqabs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqabs b30, b29"); TEST_SINGLE(sqabs(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "sqabs h30, h29"); TEST_SINGLE(sqabs(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "sqabs s30, s29"); TEST_SINGLE(sqabs(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "sqabs d30, d29"); - //TEST_SINGLE(cmgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmgt b30, b29, #0"); - //TEST_SINGLE(cmgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmgt h30, h29, #0"); - //TEST_SINGLE(cmgt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmgt s30, s29, #0"); + // TEST_SINGLE(cmgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmgt b30, b29, #0"); + // TEST_SINGLE(cmgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmgt h30, h29, #0"); + // TEST_SINGLE(cmgt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmgt s30, s29, #0"); TEST_SINGLE(cmgt(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "cmgt d30, d29, #0"); - //TEST_SINGLE(cmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmeq b30, b29, #0"); - //TEST_SINGLE(cmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmeq h30, h29, #0"); - //TEST_SINGLE(cmeq(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmeq s30, s29, #0"); + // TEST_SINGLE(cmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmeq b30, b29, #0"); + // TEST_SINGLE(cmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmeq h30, h29, #0"); + // TEST_SINGLE(cmeq(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmeq s30, s29, #0"); TEST_SINGLE(cmeq(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "cmeq d30, d29, #0"); - //TEST_SINGLE(cmlt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmlt b30, b29, #0"); - //TEST_SINGLE(cmlt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmlt h30, h29, #0"); - //TEST_SINGLE(cmlt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmlt s30, s29, #0"); + // TEST_SINGLE(cmlt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmlt b30, b29, #0"); + // TEST_SINGLE(cmlt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmlt h30, h29, #0"); + // TEST_SINGLE(cmlt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmlt s30, s29, #0"); TEST_SINGLE(cmlt(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "cmlt d30, d29, #0"); - //TEST_SINGLE(abs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "abs b30, b29"); - //TEST_SINGLE(abs(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "abs h30, h29"); - //TEST_SINGLE(abs(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "abs s30, s29"); + // TEST_SINGLE(abs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "abs b30, b29"); + // TEST_SINGLE(abs(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "abs h30, h29"); + // TEST_SINGLE(abs(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "abs s30, s29"); TEST_SINGLE(abs(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "abs d30, d29"); - TEST_SINGLE(sqxtn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqxtn b30, h29"); + TEST_SINGLE(sqxtn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqxtn b30, h29"); TEST_SINGLE(sqxtn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "sqxtn h30, s29"); TEST_SINGLE(sqxtn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "sqxtn s30, d29"); - //TEST_SINGLE(sqxtn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "sqxtn d30, d29"); + // TEST_SINGLE(sqxtn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "sqxtn d30, d29"); - //TEST_SINGLE(fcvtns(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtns b30, b29"); - //TEST_SINGLE(fcvtns(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtns h30, h29"); + // TEST_SINGLE(fcvtns(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtns b30, b29"); + // TEST_SINGLE(fcvtns(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtns h30, h29"); TEST_SINGLE(fcvtns(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtns s30, s29"); TEST_SINGLE(fcvtns(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtns d30, d29"); - //TEST_SINGLE(fcvtms(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtms b30, b29"); - //TEST_SINGLE(fcvtms(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtms h30, h29"); + // TEST_SINGLE(fcvtms(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtms b30, b29"); + // TEST_SINGLE(fcvtms(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtms h30, h29"); TEST_SINGLE(fcvtms(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtms s30, s29"); TEST_SINGLE(fcvtms(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtms d30, d29"); - //TEST_SINGLE(fcvtas(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtas b30, b29"); - //TEST_SINGLE(fcvtas(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtas h30, h29"); + // TEST_SINGLE(fcvtas(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtas b30, b29"); + // TEST_SINGLE(fcvtas(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtas h30, h29"); TEST_SINGLE(fcvtas(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtas s30, s29"); TEST_SINGLE(fcvtas(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtas d30, d29"); - //TEST_SINGLE(scvtf(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "scvtf b30, b29"); - //TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "scvtf h30, h29"); + // TEST_SINGLE(scvtf(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "scvtf b30, b29"); + // TEST_SINGLE(scvtf(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "scvtf h30, h29"); TEST_SINGLE(scvtf(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "scvtf s30, s29"); TEST_SINGLE(scvtf(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "scvtf d30, d29"); - //TEST_SINGLE(fcmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmeq b30, b29"); - //TEST_SINGLE(fcmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmeq h30, h29"); + // TEST_SINGLE(fcmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmeq b30, b29"); + // TEST_SINGLE(fcmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmeq h30, h29"); TEST_SINGLE(fcmeq(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcmeq s30, s29, #0.0"); TEST_SINGLE(fcmeq(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcmeq d30, d29, #0.0"); - //TEST_SINGLE(fcmlt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmlt b30, b29"); - //TEST_SINGLE(fcmlt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmlt h30, h29"); + // TEST_SINGLE(fcmlt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmlt b30, b29"); + // TEST_SINGLE(fcmlt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmlt h30, h29"); TEST_SINGLE(fcmlt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcmlt s30, s29, #0.0"); TEST_SINGLE(fcmlt(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcmlt d30, d29, #0.0"); - //TEST_SINGLE(fcvtps(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtps b30, b29"); - //TEST_SINGLE(fcvtps(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtps h30, h29"); + // TEST_SINGLE(fcvtps(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtps b30, b29"); + // TEST_SINGLE(fcvtps(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtps h30, h29"); TEST_SINGLE(fcvtps(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtps s30, s29"); TEST_SINGLE(fcvtps(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtps d30, d29"); - //TEST_SINGLE(fcvtzs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtzs b30, b29"); - //TEST_SINGLE(fcvtzs(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtzs h30, h29"); + // TEST_SINGLE(fcvtzs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtzs b30, b29"); + // TEST_SINGLE(fcvtzs(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtzs h30, h29"); TEST_SINGLE(fcvtzs(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtzs s30, s29"); TEST_SINGLE(fcvtzs(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtzs d30, d29"); - //TEST_SINGLE(frecpe(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "frecpe b30, b29"); - //TEST_SINGLE(frecpe(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "frecpe h30, h29"); + // TEST_SINGLE(frecpe(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "frecpe b30, b29"); + // TEST_SINGLE(frecpe(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "frecpe h30, h29"); TEST_SINGLE(frecpe(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "frecpe s30, s29"); TEST_SINGLE(frecpe(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "frecpe d30, d29"); - //TEST_SINGLE(frecpx(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "frecpx b30, b29"); - //TEST_SINGLE(frecpx(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "frecpx h30, h29"); + // TEST_SINGLE(frecpx(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "frecpx b30, b29"); + // TEST_SINGLE(frecpx(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "frecpx h30, h29"); TEST_SINGLE(frecpx(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "frecpx s30, s29"); TEST_SINGLE(frecpx(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "frecpx d30, d29"); - TEST_SINGLE(usqadd(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "usqadd b30, b29"); + TEST_SINGLE(usqadd(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "usqadd b30, b29"); TEST_SINGLE(usqadd(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "usqadd h30, h29"); TEST_SINGLE(usqadd(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "usqadd s30, s29"); TEST_SINGLE(usqadd(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "usqadd d30, d29"); - TEST_SINGLE(sqneg(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqneg b30, b29"); + TEST_SINGLE(sqneg(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqneg b30, b29"); TEST_SINGLE(sqneg(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "sqneg h30, h29"); TEST_SINGLE(sqneg(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "sqneg s30, s29"); TEST_SINGLE(sqneg(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "sqneg d30, d29"); - //TEST_SINGLE(cmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmge b30, b29"); - //TEST_SINGLE(cmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmge h30, h29"); - //TEST_SINGLE(cmge(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmge s30, s29"); + // TEST_SINGLE(cmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmge b30, b29"); + // TEST_SINGLE(cmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmge h30, h29"); + // TEST_SINGLE(cmge(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmge s30, s29"); TEST_SINGLE(cmge(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "cmge d30, d29, #0"); - //TEST_SINGLE(cmle(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmle b30, b29"); - //TEST_SINGLE(cmle(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmle h30, h29"); - //TEST_SINGLE(cmle(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmle s30, s29"); + // TEST_SINGLE(cmle(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "cmle b30, b29"); + // TEST_SINGLE(cmle(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "cmle h30, h29"); + // TEST_SINGLE(cmle(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "cmle s30, s29"); TEST_SINGLE(cmle(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "cmle d30, d29, #0"); - //TEST_SINGLE(neg(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "neg b30, b29"); - //TEST_SINGLE(neg(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "neg h30, h29"); - //TEST_SINGLE(neg(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "neg s30, s29"); + // TEST_SINGLE(neg(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "neg b30, b29"); + // TEST_SINGLE(neg(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "neg h30, h29"); + // TEST_SINGLE(neg(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "neg s30, s29"); TEST_SINGLE(neg(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "neg d30, d29"); - TEST_SINGLE(sqxtun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqxtun b30, h29"); + TEST_SINGLE(sqxtun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "sqxtun b30, h29"); TEST_SINGLE(sqxtun(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "sqxtun h30, s29"); TEST_SINGLE(sqxtun(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "sqxtun s30, d29"); - //TEST_SINGLE(sqxtun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "sqxtun d30, d29"); + // TEST_SINGLE(sqxtun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "sqxtun d30, d29"); - TEST_SINGLE(uqxtn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "uqxtn b30, h29"); + TEST_SINGLE(uqxtn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "uqxtn b30, h29"); TEST_SINGLE(uqxtn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "uqxtn h30, s29"); TEST_SINGLE(uqxtn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "uqxtn s30, d29"); - //TEST_SINGLE(uqxtn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "uqxtn d30, d29"); + // TEST_SINGLE(uqxtn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "uqxtn d30, d29"); - //TEST_SINGLE(fcvtxn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtxn b30, b29"); - //TEST_SINGLE(fcvtxn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtxn h30, h29"); + // TEST_SINGLE(fcvtxn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtxn b30, b29"); + // TEST_SINGLE(fcvtxn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtxn h30, h29"); TEST_SINGLE(fcvtxn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtxn s30, d29"); - //TEST_SINGLE(fcvtxn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtxn d30, d29"); + // TEST_SINGLE(fcvtxn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtxn d30, d29"); - //TEST_SINGLE(fcvtnu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtnu b30, b29"); - //TEST_SINGLE(fcvtnu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtnu h30, h29"); + // TEST_SINGLE(fcvtnu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtnu b30, b29"); + // TEST_SINGLE(fcvtnu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtnu h30, h29"); TEST_SINGLE(fcvtnu(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtnu s30, s29"); TEST_SINGLE(fcvtnu(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtnu d30, d29"); - //TEST_SINGLE(fcvtmu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtmu b30, b29"); - //TEST_SINGLE(fcvtmu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtmu h30, h29"); + // TEST_SINGLE(fcvtmu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtmu b30, b29"); + // TEST_SINGLE(fcvtmu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtmu h30, h29"); TEST_SINGLE(fcvtmu(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtmu s30, s29"); TEST_SINGLE(fcvtmu(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtmu d30, d29"); - //TEST_SINGLE(fcvtau(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtau b30, b29"); - //TEST_SINGLE(fcvtau(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtau h30, h29"); + // TEST_SINGLE(fcvtau(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtau b30, b29"); + // TEST_SINGLE(fcvtau(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtau h30, h29"); TEST_SINGLE(fcvtau(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtau s30, s29"); TEST_SINGLE(fcvtau(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtau d30, d29"); - //TEST_SINGLE(ucvtf(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "ucvtf b30, b29"); - //TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "ucvtf h30, h29"); + // TEST_SINGLE(ucvtf(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "ucvtf b30, b29"); + // TEST_SINGLE(ucvtf(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "ucvtf h30, h29"); TEST_SINGLE(ucvtf(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "ucvtf s30, s29"); TEST_SINGLE(ucvtf(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "ucvtf d30, d29"); - //TEST_SINGLE(fcmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmge b30, b29"); - //TEST_SINGLE(fcmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmge h30, h29"); + // TEST_SINGLE(fcmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmge b30, b29"); + // TEST_SINGLE(fcmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmge h30, h29"); TEST_SINGLE(fcmge(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcmge s30, s29, #0.0"); TEST_SINGLE(fcmge(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcmge d30, d29, #0.0"); - //TEST_SINGLE(fcmle(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmle b30, b29"); - //TEST_SINGLE(fcmle(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmle h30, h29"); + // TEST_SINGLE(fcmle(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmle b30, b29"); + // TEST_SINGLE(fcmle(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmle h30, h29"); TEST_SINGLE(fcmle(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcmle s30, s29, #0.0"); TEST_SINGLE(fcmle(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcmle d30, d29, #0.0"); - //TEST_SINGLE(fcvtpu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtpu b30, b29"); - //TEST_SINGLE(fcvtpu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtpu h30, h29"); + // TEST_SINGLE(fcvtpu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtpu b30, b29"); + // TEST_SINGLE(fcvtpu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtpu h30, h29"); TEST_SINGLE(fcvtpu(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtpu s30, s29"); TEST_SINGLE(fcvtpu(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtpu d30, d29"); - //TEST_SINGLE(fcvtzu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtzu b30, b29"); - //TEST_SINGLE(fcvtzu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtzu h30, h29"); + // TEST_SINGLE(fcvtzu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcvtzu b30, b29"); + // TEST_SINGLE(fcvtzu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcvtzu h30, h29"); TEST_SINGLE(fcvtzu(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcvtzu s30, s29"); TEST_SINGLE(fcvtzu(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcvtzu d30, d29"); - //TEST_SINGLE(frsqrte(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "frsqrte b30, b29"); - //TEST_SINGLE(frsqrte(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "frsqrte h30, h29"); + // TEST_SINGLE(frsqrte(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "frsqrte b30, b29"); + // TEST_SINGLE(frsqrte(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "frsqrte h30, h29"); TEST_SINGLE(frsqrte(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "frsqrte s30, s29"); TEST_SINGLE(frsqrte(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "frsqrte d30, d29"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar pairwise") { // Commented out lines showcase unallocated encodings. - //TEST_SINGLE(addp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "addp b30, b29"); - //TEST_SINGLE(addp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "addp h30, h29"); - //TEST_SINGLE(addp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "addp s30, s29"); + // TEST_SINGLE(addp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "addp b30, b29"); + // TEST_SINGLE(addp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "addp h30, h29"); + // TEST_SINGLE(addp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "addp s30, s29"); TEST_SINGLE(addp(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "addp d30, v29.2d"); - TEST_SINGLE(fmaxnmp(HReg::h30, HReg::h29), "fmaxnmp h30, v29.2h"); - //TEST_SINGLE(fmaxnmp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fmaxnmp b30, b29"); - //TEST_SINGLE(fmaxnmp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fmaxnmp h30, h29"); + TEST_SINGLE(fmaxnmp(HReg::h30, HReg::h29), "fmaxnmp h30, v29.2h"); + // TEST_SINGLE(fmaxnmp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fmaxnmp b30, b29"); + // TEST_SINGLE(fmaxnmp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fmaxnmp h30, h29"); TEST_SINGLE(fmaxnmp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fmaxnmp s30, v29.2s"); TEST_SINGLE(fmaxnmp(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fmaxnmp d30, v29.2d"); - TEST_SINGLE(faddp(HReg::h30, HReg::h29), "faddp h30, v29.2h"); - //TEST_SINGLE(faddp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "faddp b30, b29"); - //TEST_SINGLE(faddp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "faddp h30, h29"); + TEST_SINGLE(faddp(HReg::h30, HReg::h29), "faddp h30, v29.2h"); + // TEST_SINGLE(faddp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "faddp b30, b29"); + // TEST_SINGLE(faddp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "faddp h30, h29"); TEST_SINGLE(faddp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "faddp s30, v29.2s"); TEST_SINGLE(faddp(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "faddp d30, v29.2d"); - TEST_SINGLE(fmaxp(HReg::h30, HReg::h29), "fmaxp h30, v29.2h"); - //TEST_SINGLE(fmaxp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fmaxp b30, b29"); - //TEST_SINGLE(fmaxp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fmaxp h30, h29"); + TEST_SINGLE(fmaxp(HReg::h30, HReg::h29), "fmaxp h30, v29.2h"); + // TEST_SINGLE(fmaxp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fmaxp b30, b29"); + // TEST_SINGLE(fmaxp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fmaxp h30, h29"); TEST_SINGLE(fmaxp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fmaxp s30, v29.2s"); TEST_SINGLE(fmaxp(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fmaxp d30, v29.2d"); - TEST_SINGLE(fminnmp(HReg::h30, HReg::h29), "fminnmp h30, v29.2h"); - //TEST_SINGLE(fminnmp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fminnmp b30, b29"); - //TEST_SINGLE(fminnmp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fminnmp h30, h29"); + TEST_SINGLE(fminnmp(HReg::h30, HReg::h29), "fminnmp h30, v29.2h"); + // TEST_SINGLE(fminnmp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fminnmp b30, b29"); + // TEST_SINGLE(fminnmp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fminnmp h30, h29"); TEST_SINGLE(fminnmp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fminnmp s30, v29.2s"); TEST_SINGLE(fminnmp(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fminnmp d30, v29.2d"); - TEST_SINGLE(fminp(HReg::h30, HReg::h29), "fminp h30, v29.2h"); - //TEST_SINGLE(fminp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fminp b30, b29"); - //TEST_SINGLE(fminp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fminp h30, h29"); + TEST_SINGLE(fminp(HReg::h30, HReg::h29), "fminp h30, v29.2h"); + // TEST_SINGLE(fminp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fminp b30, b29"); + // TEST_SINGLE(fminp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fminp h30, h29"); TEST_SINGLE(fminp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fminp s30, v29.2s"); TEST_SINGLE(fminp(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fminp d30, v29.2d"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three different") { // Commented out lines showcase unallocated encodings. - //TEST_SINGLE(sqdmlal(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlal v30.16b, v29.16b, v28.v16b"); - //TEST_SINGLE(sqdmlal(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlal v30.16b, v29.16b, v28.v16b"); + // TEST_SINGLE(sqdmlal(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlal v30.16b, v29.16b, v28.v16b"); + // TEST_SINGLE(sqdmlal(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlal v30.16b, v29.16b, v28.v16b"); TEST_SINGLE(sqdmlal(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlal s30, h29, h28"); TEST_SINGLE(sqdmlal(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlal d30, s29, s28"); - //TEST_SINGLE(sqdmlsl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlsl v30.16b, v29.16b, v28.v16b"); - //TEST_SINGLE(sqdmlsl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlsl v30.16b, v29.16b, v28.v16b"); + // TEST_SINGLE(sqdmlsl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlsl v30.16b, v29.16b, v28.v16b"); + // TEST_SINGLE(sqdmlsl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlsl v30.16b, v29.16b, v28.v16b"); TEST_SINGLE(sqdmlsl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlsl s30, h29, h28"); TEST_SINGLE(sqdmlsl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmlsl d30, s29, s28"); - //TEST_SINGLE(sqdmull(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmull v30.16b, v29.16b, v28.v16b"); - //TEST_SINGLE(sqdmull(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmull v30.16b, v29.16b, v28.v16b"); + // TEST_SINGLE(sqdmull(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmull v30.16b, v29.16b, v28.v16b"); + // TEST_SINGLE(sqdmull(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmull v30.16b, v29.16b, v28.v16b"); TEST_SINGLE(sqdmull(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmull s30, h29, h28"); TEST_SINGLE(sqdmull(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmull d30, s29, s28"); } @@ -299,19 +299,19 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three TEST_SINGLE(sqsub(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqsub s30, s29, s28"); TEST_SINGLE(sqsub(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqsub d30, d29, d28"); - //TEST_SINGLE(cmgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmgt b30, b29, b28"); - //TEST_SINGLE(cmgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmgt h30, h29, h28"); - //TEST_SINGLE(cmgt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmgt s30, s29, s28"); + // TEST_SINGLE(cmgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmgt b30, b29, b28"); + // TEST_SINGLE(cmgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmgt h30, h29, h28"); + // TEST_SINGLE(cmgt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmgt s30, s29, s28"); TEST_SINGLE(cmgt(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "cmgt d30, d29, d28"); - //TEST_SINGLE(cmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmge b30, b29, b28"); - //TEST_SINGLE(cmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmge h30, h29, h28"); - //TEST_SINGLE(cmge(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmge s30, s29, s28"); + // TEST_SINGLE(cmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmge b30, b29, b28"); + // TEST_SINGLE(cmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmge h30, h29, h28"); + // TEST_SINGLE(cmge(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmge s30, s29, s28"); TEST_SINGLE(cmge(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "cmge d30, d29, d28"); - //TEST_SINGLE(sshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sshl b30, b29, b28"); - //TEST_SINGLE(sshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sshl h30, h29, h28"); - //TEST_SINGLE(sshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sshl s30, s29, s28"); + // TEST_SINGLE(sshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sshl b30, b29, b28"); + // TEST_SINGLE(sshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sshl h30, h29, h28"); + // TEST_SINGLE(sshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sshl s30, s29, s28"); TEST_SINGLE(sshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sshl d30, d29, d28"); TEST_SINGLE(sqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqshl b30, b29, b28"); @@ -319,9 +319,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three TEST_SINGLE(sqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqshl s30, s29, s28"); TEST_SINGLE(sqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqshl d30, d29, d28"); - //TEST_SINGLE(srshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "srshl b30, b29, b28"); - //TEST_SINGLE(srshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "srshl h30, h29, h28"); - //TEST_SINGLE(srshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "srshl s30, s29, s28"); + // TEST_SINGLE(srshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "srshl b30, b29, b28"); + // TEST_SINGLE(srshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "srshl h30, h29, h28"); + // TEST_SINGLE(srshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "srshl s30, s29, s28"); TEST_SINGLE(srshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "srshl d30, d29, d28"); TEST_SINGLE(sqrshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqrshl b30, b29, b28"); @@ -329,38 +329,38 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three TEST_SINGLE(sqrshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqrshl s30, s29, s28"); TEST_SINGLE(sqrshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqrshl d30, d29, d28"); - //TEST_SINGLE(add(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "add b30, b29, b28"); - //TEST_SINGLE(add(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "add h30, h29, h28"); - //TEST_SINGLE(add(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "add s30, s29, s28"); + // TEST_SINGLE(add(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "add b30, b29, b28"); + // TEST_SINGLE(add(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "add h30, h29, h28"); + // TEST_SINGLE(add(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "add s30, s29, s28"); TEST_SINGLE(add(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "add d30, d29, d28"); - //TEST_SINGLE(cmtst(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmtst b30, b29, b28"); - //TEST_SINGLE(cmtst(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmtst h30, h29, h28"); - //TEST_SINGLE(cmtst(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmtst s30, s29, s28"); + // TEST_SINGLE(cmtst(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmtst b30, b29, b28"); + // TEST_SINGLE(cmtst(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmtst h30, h29, h28"); + // TEST_SINGLE(cmtst(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmtst s30, s29, s28"); TEST_SINGLE(cmtst(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "cmtst d30, d29, d28"); - //TEST_SINGLE(sqdmulh(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmulh b30, b29, b28"); + // TEST_SINGLE(sqdmulh(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmulh b30, b29, b28"); TEST_SINGLE(sqdmulh(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmulh h30, h29, h28"); TEST_SINGLE(sqdmulh(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmulh s30, s29, s28"); - //TEST_SINGLE(sqdmulh(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmulh d30, d29, d28"); + // TEST_SINGLE(sqdmulh(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqdmulh d30, d29, d28"); - //TEST_SINGLE(fmulx(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fmulx b30, b29, b28"); - //TEST_SINGLE(fmulx(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fmulx h30, h29, h28"); + // TEST_SINGLE(fmulx(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fmulx b30, b29, b28"); + // TEST_SINGLE(fmulx(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fmulx h30, h29, h28"); TEST_SINGLE(fmulx(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "fmulx s30, s29, s28"); TEST_SINGLE(fmulx(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "fmulx d30, d29, d28"); - //TEST_SINGLE(fcmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fcmeq b30, b29, b28"); - //TEST_SINGLE(fcmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fcmeq h30, h29, h28"); + // TEST_SINGLE(fcmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fcmeq b30, b29, b28"); + // TEST_SINGLE(fcmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fcmeq h30, h29, h28"); TEST_SINGLE(fcmeq(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "fcmeq s30, s29, s28"); TEST_SINGLE(fcmeq(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "fcmeq d30, d29, d28"); - //TEST_SINGLE(frecps(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "frecps b30, b29, b28"); - //TEST_SINGLE(frecps(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "frecps h30, h29, h28"); + // TEST_SINGLE(frecps(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "frecps b30, b29, b28"); + // TEST_SINGLE(frecps(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "frecps h30, h29, h28"); TEST_SINGLE(frecps(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "frecps s30, s29, s28"); TEST_SINGLE(frecps(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "frecps d30, d29, d28"); - //TEST_SINGLE(frsqrts(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "frsqrts b30, b29, b28"); - //TEST_SINGLE(frsqrts(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "frsqrts h30, h29, h28"); + // TEST_SINGLE(frsqrts(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "frsqrts b30, b29, b28"); + // TEST_SINGLE(frsqrts(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "frsqrts h30, h29, h28"); TEST_SINGLE(frsqrts(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "frsqrts s30, s29, s28"); TEST_SINGLE(frsqrts(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "frsqrts d30, d29, d28"); @@ -374,19 +374,19 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three TEST_SINGLE(uqsub(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "uqsub s30, s29, s28"); TEST_SINGLE(uqsub(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "uqsub d30, d29, d28"); - //TEST_SINGLE(cmhi(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmhi b30, b29, b28"); - //TEST_SINGLE(cmhi(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmhi h30, h29, h28"); - //TEST_SINGLE(cmhi(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmhi s30, s29, s28"); + // TEST_SINGLE(cmhi(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmhi b30, b29, b28"); + // TEST_SINGLE(cmhi(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmhi h30, h29, h28"); + // TEST_SINGLE(cmhi(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmhi s30, s29, s28"); TEST_SINGLE(cmhi(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "cmhi d30, d29, d28"); - //TEST_SINGLE(cmhs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmhs b30, b29, b28"); - //TEST_SINGLE(cmhs(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmhs h30, h29, h28"); - //TEST_SINGLE(cmhs(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmhs s30, s29, s28"); + // TEST_SINGLE(cmhs(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmhs b30, b29, b28"); + // TEST_SINGLE(cmhs(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmhs h30, h29, h28"); + // TEST_SINGLE(cmhs(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmhs s30, s29, s28"); TEST_SINGLE(cmhs(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "cmhs d30, d29, d28"); - //TEST_SINGLE(ushl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "ushl b30, b29, b28"); - //TEST_SINGLE(ushl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "ushl h30, h29, h28"); - //TEST_SINGLE(ushl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "ushl s30, s29, s28"); + // TEST_SINGLE(ushl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "ushl b30, b29, b28"); + // TEST_SINGLE(ushl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "ushl h30, h29, h28"); + // TEST_SINGLE(ushl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "ushl s30, s29, s28"); TEST_SINGLE(ushl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "ushl d30, d29, d28"); TEST_SINGLE(uqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "uqshl b30, b29, b28"); @@ -394,9 +394,9 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three TEST_SINGLE(uqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "uqshl s30, s29, s28"); TEST_SINGLE(uqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "uqshl d30, d29, d28"); - //TEST_SINGLE(urshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "urshl b30, b29, b28"); - //TEST_SINGLE(urshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "urshl h30, h29, h28"); - //TEST_SINGLE(urshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "urshl s30, s29, s28"); + // TEST_SINGLE(urshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "urshl b30, b29, b28"); + // TEST_SINGLE(urshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "urshl h30, h29, h28"); + // TEST_SINGLE(urshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "urshl s30, s29, s28"); TEST_SINGLE(urshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "urshl d30, d29, d28"); TEST_SINGLE(uqrshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "uqrshl b30, b29, b28"); @@ -404,43 +404,43 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar three TEST_SINGLE(uqrshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "uqrshl s30, s29, s28"); TEST_SINGLE(uqrshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "uqrshl d30, d29, d28"); - //TEST_SINGLE(sub(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sub b30, b29, b28"); - //TEST_SINGLE(sub(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sub h30, h29, h28"); - //TEST_SINGLE(sub(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sub s30, s29, s28"); + // TEST_SINGLE(sub(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sub b30, b29, b28"); + // TEST_SINGLE(sub(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sub h30, h29, h28"); + // TEST_SINGLE(sub(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sub s30, s29, s28"); TEST_SINGLE(sub(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sub d30, d29, d28"); - //TEST_SINGLE(cmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmeq b30, b29, b28"); - //TEST_SINGLE(cmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmeq h30, h29, h28"); - //TEST_SINGLE(cmeq(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmeq s30, s29, s28"); + // TEST_SINGLE(cmeq(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "cmeq b30, b29, b28"); + // TEST_SINGLE(cmeq(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "cmeq h30, h29, h28"); + // TEST_SINGLE(cmeq(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "cmeq s30, s29, s28"); TEST_SINGLE(cmeq(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "cmeq d30, d29, d28"); - //TEST_SINGLE(sqrdmulh(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqrdmulh b30, b29, b28"); + // TEST_SINGLE(sqrdmulh(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "sqrdmulh b30, b29, b28"); TEST_SINGLE(sqrdmulh(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "sqrdmulh h30, h29, h28"); TEST_SINGLE(sqrdmulh(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "sqrdmulh s30, s29, s28"); - //TEST_SINGLE(sqrdmulh(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqrdmulh d30, d29, d28"); + // TEST_SINGLE(sqrdmulh(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "sqrdmulh d30, d29, d28"); - //TEST_SINGLE(fcmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fcmge b30, b29, b28"); - //TEST_SINGLE(fcmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fcmge h30, h29, h28"); + // TEST_SINGLE(fcmge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fcmge b30, b29, b28"); + // TEST_SINGLE(fcmge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fcmge h30, h29, h28"); TEST_SINGLE(fcmge(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "fcmge s30, s29, s28"); TEST_SINGLE(fcmge(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "fcmge d30, d29, d28"); - //TEST_SINGLE(facge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "facge b30, b29, b28"); - //TEST_SINGLE(facge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "facge h30, h29, h28"); + // TEST_SINGLE(facge(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "facge b30, b29, b28"); + // TEST_SINGLE(facge(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "facge h30, h29, h28"); TEST_SINGLE(facge(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "facge s30, s29, s28"); TEST_SINGLE(facge(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "facge d30, d29, d28"); - //TEST_SINGLE(fabd(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fabd b30, b29, b28"); - //TEST_SINGLE(fabd(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fabd h30, h29, h28"); + // TEST_SINGLE(fabd(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fabd b30, b29, b28"); + // TEST_SINGLE(fabd(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fabd h30, h29, h28"); TEST_SINGLE(fabd(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "fabd s30, s29, s28"); TEST_SINGLE(fabd(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "fabd d30, d29, d28"); - //TEST_SINGLE(fcmgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fcmgt b30, b29, b28"); - //TEST_SINGLE(fcmgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fcmgt h30, h29, h28"); + // TEST_SINGLE(fcmgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "fcmgt b30, b29, b28"); + // TEST_SINGLE(fcmgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "fcmgt h30, h29, h28"); TEST_SINGLE(fcmgt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "fcmgt s30, s29, s28"); TEST_SINGLE(fcmgt(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "fcmgt d30, d29, d28"); - //TEST_SINGLE(facgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "facgt b30, b29, b28"); - //TEST_SINGLE(facgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "facgt h30, h29, h28"); + // TEST_SINGLE(facgt(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, VReg::v28), "facgt b30, b29, b28"); + // TEST_SINGLE(facgt(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, VReg::v28), "facgt h30, h29, h28"); TEST_SINGLE(facgt(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, VReg::v28), "facgt s30, s29, s28"); TEST_SINGLE(facgt(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, VReg::v28), "facgt d30, d29, d28"); } @@ -452,180 +452,180 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Advanced SIMD scalar shift // TEST_SINGLE(sshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sshr h30, h29, #15"); // TEST_SINGLE(sshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sshr s30, s29, #1"); // TEST_SINGLE(sshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sshr s30, s29, #31"); - TEST_SINGLE(sshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sshr d30, d29, #1"); + TEST_SINGLE(sshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sshr d30, d29, #1"); TEST_SINGLE(sshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sshr d30, d29, #63"); - //TEST_SINGLE(ssra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "ssra b30, b29, #1"); - //TEST_SINGLE(ssra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "ssra b30, b29, #7"); - //TEST_SINGLE(ssra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "ssra h30, h29, #1"); - //TEST_SINGLE(ssra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "ssra h30, h29, #15"); - //TEST_SINGLE(ssra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "ssra s30, s29, #1"); - //TEST_SINGLE(ssra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "ssra s30, s29, #31"); - TEST_SINGLE(ssra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "ssra d30, d29, #1"); + // TEST_SINGLE(ssra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "ssra b30, b29, #1"); + // TEST_SINGLE(ssra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "ssra b30, b29, #7"); + // TEST_SINGLE(ssra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "ssra h30, h29, #1"); + // TEST_SINGLE(ssra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "ssra h30, h29, #15"); + // TEST_SINGLE(ssra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "ssra s30, s29, #1"); + // TEST_SINGLE(ssra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "ssra s30, s29, #31"); + TEST_SINGLE(ssra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "ssra d30, d29, #1"); TEST_SINGLE(ssra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "ssra d30, d29, #63"); - //TEST_SINGLE(srshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "srshr b30, b29, #1"); - //TEST_SINGLE(srshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "srshr b30, b29, #7"); - //TEST_SINGLE(srshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "srshr h30, h29, #1"); - //TEST_SINGLE(srshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "srshr h30, h29, #15"); - //TEST_SINGLE(srshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "srshr s30, s29, #1"); - //TEST_SINGLE(srshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "srshr s30, s29, #31"); - TEST_SINGLE(srshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "srshr d30, d29, #1"); + // TEST_SINGLE(srshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "srshr b30, b29, #1"); + // TEST_SINGLE(srshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "srshr b30, b29, #7"); + // TEST_SINGLE(srshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "srshr h30, h29, #1"); + // TEST_SINGLE(srshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "srshr h30, h29, #15"); + // TEST_SINGLE(srshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "srshr s30, s29, #1"); + // TEST_SINGLE(srshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "srshr s30, s29, #31"); + TEST_SINGLE(srshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "srshr d30, d29, #1"); TEST_SINGLE(srshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "srshr d30, d29, #63"); - //TEST_SINGLE(srsra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "srsra b30, b29, #1"); - //TEST_SINGLE(srsra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "srsra b30, b29, #7"); - //TEST_SINGLE(srsra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "srsra h30, h29, #1"); - //TEST_SINGLE(srsra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "srsra h30, h29, #15"); - //TEST_SINGLE(srsra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "srsra s30, s29, #1"); - //TEST_SINGLE(srsra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "srsra s30, s29, #31"); - TEST_SINGLE(srsra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "srsra d30, d29, #1"); + // TEST_SINGLE(srsra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "srsra b30, b29, #1"); + // TEST_SINGLE(srsra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "srsra b30, b29, #7"); + // TEST_SINGLE(srsra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "srsra h30, h29, #1"); + // TEST_SINGLE(srsra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "srsra h30, h29, #15"); + // TEST_SINGLE(srsra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "srsra s30, s29, #1"); + // TEST_SINGLE(srsra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "srsra s30, s29, #31"); + TEST_SINGLE(srsra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "srsra d30, d29, #1"); TEST_SINGLE(srsra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "srsra d30, d29, #63"); - //TEST_SINGLE(shl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "shl b30, b29, #1"); - //TEST_SINGLE(shl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "shl b30, b29, #7"); - //TEST_SINGLE(shl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "shl h30, h29, #1"); - //TEST_SINGLE(shl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "shl h30, h29, #15"); - //TEST_SINGLE(shl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "shl s30, s29, #1"); - //TEST_SINGLE(shl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "shl s30, s29, #31"); - TEST_SINGLE(shl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "shl d30, d29, #1"); + // TEST_SINGLE(shl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "shl b30, b29, #1"); + // TEST_SINGLE(shl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "shl b30, b29, #7"); + // TEST_SINGLE(shl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "shl h30, h29, #1"); + // TEST_SINGLE(shl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "shl h30, h29, #15"); + // TEST_SINGLE(shl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "shl s30, s29, #1"); + // TEST_SINGLE(shl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "shl s30, s29, #31"); + TEST_SINGLE(shl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "shl d30, d29, #1"); TEST_SINGLE(shl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "shl d30, d29, #63"); - TEST_SINGLE(sqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshl b30, b29, #1"); - TEST_SINGLE(sqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshl b30, b29, #7"); - TEST_SINGLE(sqshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshl h30, h29, #1"); + TEST_SINGLE(sqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshl b30, b29, #1"); + TEST_SINGLE(sqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshl b30, b29, #7"); + TEST_SINGLE(sqshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshl h30, h29, #1"); TEST_SINGLE(sqshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sqshl h30, h29, #15"); - TEST_SINGLE(sqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshl s30, s29, #1"); + TEST_SINGLE(sqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshl s30, s29, #1"); TEST_SINGLE(sqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sqshl s30, s29, #31"); - TEST_SINGLE(sqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshl d30, d29, #1"); + TEST_SINGLE(sqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshl d30, d29, #1"); TEST_SINGLE(sqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqshl d30, d29, #63"); - TEST_SINGLE(sqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshrn b30, h29, #1"); - TEST_SINGLE(sqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshrn b30, h29, #7"); - TEST_SINGLE(sqshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshrn h30, s29, #1"); + TEST_SINGLE(sqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshrn b30, h29, #1"); + TEST_SINGLE(sqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshrn b30, h29, #7"); + TEST_SINGLE(sqshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshrn h30, s29, #1"); TEST_SINGLE(sqshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sqshrn h30, s29, #15"); - TEST_SINGLE(sqshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshrn s30, d29, #1"); + TEST_SINGLE(sqshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshrn s30, d29, #1"); TEST_SINGLE(sqshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sqshrn s30, d29, #31"); - //TEST_SINGLE(sqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshrn d30, d29, #1"); - //TEST_SINGLE(sqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqshrn d30, d29, #63"); + // TEST_SINGLE(sqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshrn d30, d29, #1"); + // TEST_SINGLE(sqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqshrn d30, d29, #63"); - TEST_SINGLE(sqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqrshrn b30, h29, #1"); - TEST_SINGLE(sqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqrshrn b30, h29, #7"); - TEST_SINGLE(sqrshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqrshrn h30, s29, #1"); + TEST_SINGLE(sqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqrshrn b30, h29, #1"); + TEST_SINGLE(sqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqrshrn b30, h29, #7"); + TEST_SINGLE(sqrshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqrshrn h30, s29, #1"); TEST_SINGLE(sqrshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sqrshrn h30, s29, #15"); - TEST_SINGLE(sqrshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqrshrn s30, d29, #1"); + TEST_SINGLE(sqrshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqrshrn s30, d29, #1"); TEST_SINGLE(sqrshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sqrshrn s30, d29, #31"); - //TEST_SINGLE(sqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqrshrn d30, d29, #1"); - //TEST_SINGLE(sqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqrshrn d30, d29, #63"); + // TEST_SINGLE(sqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqrshrn d30, d29, #1"); + // TEST_SINGLE(sqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqrshrn d30, d29, #63"); // TODO: Implement `SCVTF, FCVTZS` in emitter - //TEST_SINGLE(ushr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "ushr b30, b29, #1"); - //TEST_SINGLE(ushr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "ushr b30, b29, #7"); - //TEST_SINGLE(ushr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "ushr h30, h29, #1"); - //TEST_SINGLE(ushr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "ushr h30, h29, #15"); - //TEST_SINGLE(ushr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "ushr s30, s29, #1"); - //TEST_SINGLE(ushr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "ushr s30, s29, #31"); - TEST_SINGLE(ushr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "ushr d30, d29, #1"); + // TEST_SINGLE(ushr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "ushr b30, b29, #1"); + // TEST_SINGLE(ushr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "ushr b30, b29, #7"); + // TEST_SINGLE(ushr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "ushr h30, h29, #1"); + // TEST_SINGLE(ushr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "ushr h30, h29, #15"); + // TEST_SINGLE(ushr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "ushr s30, s29, #1"); + // TEST_SINGLE(ushr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "ushr s30, s29, #31"); + TEST_SINGLE(ushr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "ushr d30, d29, #1"); TEST_SINGLE(ushr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "ushr d30, d29, #63"); - //TEST_SINGLE(usra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "usra b30, b29, #1"); - //TEST_SINGLE(usra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "usra b30, b29, #7"); - //TEST_SINGLE(usra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "usra h30, h29, #1"); - //TEST_SINGLE(usra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "usra h30, h29, #15"); - //TEST_SINGLE(usra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "usra s30, s29, #1"); - //TEST_SINGLE(usra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "usra s30, s29, #31"); - TEST_SINGLE(usra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "usra d30, d29, #1"); + // TEST_SINGLE(usra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "usra b30, b29, #1"); + // TEST_SINGLE(usra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "usra b30, b29, #7"); + // TEST_SINGLE(usra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "usra h30, h29, #1"); + // TEST_SINGLE(usra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "usra h30, h29, #15"); + // TEST_SINGLE(usra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "usra s30, s29, #1"); + // TEST_SINGLE(usra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "usra s30, s29, #31"); + TEST_SINGLE(usra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "usra d30, d29, #1"); TEST_SINGLE(usra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "usra d30, d29, #63"); - //TEST_SINGLE(urshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "urshr b30, b29, #1"); - //TEST_SINGLE(urshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "urshr b30, b29, #7"); - //TEST_SINGLE(urshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "urshr h30, h29, #1"); - //TEST_SINGLE(urshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "urshr h30, h29, #15"); - //TEST_SINGLE(urshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "urshr s30, s29, #1"); - //TEST_SINGLE(urshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "urshr s30, s29, #31"); - TEST_SINGLE(urshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "urshr d30, d29, #1"); + // TEST_SINGLE(urshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "urshr b30, b29, #1"); + // TEST_SINGLE(urshr(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "urshr b30, b29, #7"); + // TEST_SINGLE(urshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "urshr h30, h29, #1"); + // TEST_SINGLE(urshr(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "urshr h30, h29, #15"); + // TEST_SINGLE(urshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "urshr s30, s29, #1"); + // TEST_SINGLE(urshr(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "urshr s30, s29, #31"); + TEST_SINGLE(urshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "urshr d30, d29, #1"); TEST_SINGLE(urshr(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "urshr d30, d29, #63"); - //TEST_SINGLE(ursra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "ursra b30, b29, #1"); - //TEST_SINGLE(ursra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "ursra b30, b29, #7"); - //TEST_SINGLE(ursra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "ursra h30, h29, #1"); - //TEST_SINGLE(ursra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "ursra h30, h29, #15"); - //TEST_SINGLE(ursra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "ursra s30, s29, #1"); - //TEST_SINGLE(ursra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "ursra s30, s29, #31"); - TEST_SINGLE(ursra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "ursra d30, d29, #1"); + // TEST_SINGLE(ursra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "ursra b30, b29, #1"); + // TEST_SINGLE(ursra(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "ursra b30, b29, #7"); + // TEST_SINGLE(ursra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "ursra h30, h29, #1"); + // TEST_SINGLE(ursra(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "ursra h30, h29, #15"); + // TEST_SINGLE(ursra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "ursra s30, s29, #1"); + // TEST_SINGLE(ursra(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "ursra s30, s29, #31"); + TEST_SINGLE(ursra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "ursra d30, d29, #1"); TEST_SINGLE(ursra(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "ursra d30, d29, #63"); - //TEST_SINGLE(sri(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sri b30, b29, #1"); - //TEST_SINGLE(sri(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sri b30, b29, #7"); - //TEST_SINGLE(sri(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sri h30, h29, #1"); - //TEST_SINGLE(sri(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sri h30, h29, #15"); - //TEST_SINGLE(sri(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sri s30, s29, #1"); - //TEST_SINGLE(sri(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sri s30, s29, #31"); - TEST_SINGLE(sri(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sri d30, d29, #1"); + // TEST_SINGLE(sri(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sri b30, b29, #1"); + // TEST_SINGLE(sri(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sri b30, b29, #7"); + // TEST_SINGLE(sri(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sri h30, h29, #1"); + // TEST_SINGLE(sri(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sri h30, h29, #15"); + // TEST_SINGLE(sri(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sri s30, s29, #1"); + // TEST_SINGLE(sri(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sri s30, s29, #31"); + TEST_SINGLE(sri(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sri d30, d29, #1"); TEST_SINGLE(sri(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sri d30, d29, #63"); - //TEST_SINGLE(sli(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sli b30, b29, #1"); - //TEST_SINGLE(sli(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sli b30, b29, #7"); - //TEST_SINGLE(sli(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sli h30, h29, #1"); - //TEST_SINGLE(sli(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sli h30, h29, #15"); - //TEST_SINGLE(sli(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sli s30, s29, #1"); - //TEST_SINGLE(sli(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sli s30, s29, #31"); - TEST_SINGLE(sli(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sli d30, d29, #1"); + // TEST_SINGLE(sli(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sli b30, b29, #1"); + // TEST_SINGLE(sli(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sli b30, b29, #7"); + // TEST_SINGLE(sli(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sli h30, h29, #1"); + // TEST_SINGLE(sli(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sli h30, h29, #15"); + // TEST_SINGLE(sli(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sli s30, s29, #1"); + // TEST_SINGLE(sli(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sli s30, s29, #31"); + TEST_SINGLE(sli(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sli d30, d29, #1"); TEST_SINGLE(sli(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sli d30, d29, #63"); - TEST_SINGLE(sqshlu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshlu b30, b29, #1"); - TEST_SINGLE(sqshlu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshlu b30, b29, #7"); - TEST_SINGLE(sqshlu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshlu h30, h29, #1"); + TEST_SINGLE(sqshlu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshlu b30, b29, #1"); + TEST_SINGLE(sqshlu(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshlu b30, b29, #7"); + TEST_SINGLE(sqshlu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshlu h30, h29, #1"); TEST_SINGLE(sqshlu(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sqshlu h30, h29, #15"); - TEST_SINGLE(sqshlu(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshlu s30, s29, #1"); + TEST_SINGLE(sqshlu(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshlu s30, s29, #1"); TEST_SINGLE(sqshlu(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sqshlu s30, s29, #31"); - TEST_SINGLE(sqshlu(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshlu d30, d29, #1"); + TEST_SINGLE(sqshlu(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshlu d30, d29, #1"); TEST_SINGLE(sqshlu(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqshlu d30, d29, #63"); - TEST_SINGLE(uqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "uqshl b30, b29, #1"); - TEST_SINGLE(uqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "uqshl b30, b29, #7"); - TEST_SINGLE(uqshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "uqshl h30, h29, #1"); + TEST_SINGLE(uqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "uqshl b30, b29, #1"); + TEST_SINGLE(uqshl(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "uqshl b30, b29, #7"); + TEST_SINGLE(uqshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "uqshl h30, h29, #1"); TEST_SINGLE(uqshl(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "uqshl h30, h29, #15"); - TEST_SINGLE(uqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "uqshl s30, s29, #1"); + TEST_SINGLE(uqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "uqshl s30, s29, #1"); TEST_SINGLE(uqshl(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "uqshl s30, s29, #31"); - TEST_SINGLE(uqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "uqshl d30, d29, #1"); + TEST_SINGLE(uqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "uqshl d30, d29, #1"); TEST_SINGLE(uqshl(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "uqshl d30, d29, #63"); - TEST_SINGLE(sqshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshrun b30, h29, #1"); - TEST_SINGLE(sqshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshrun b30, h29, #7"); - TEST_SINGLE(sqshrun(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshrun h30, s29, #1"); + TEST_SINGLE(sqshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqshrun b30, h29, #1"); + TEST_SINGLE(sqshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqshrun b30, h29, #7"); + TEST_SINGLE(sqshrun(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqshrun h30, s29, #1"); TEST_SINGLE(sqshrun(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sqshrun h30, s29, #15"); - TEST_SINGLE(sqshrun(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshrun s30, d29, #1"); + TEST_SINGLE(sqshrun(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqshrun s30, d29, #1"); TEST_SINGLE(sqshrun(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sqshrun s30, d29, #31"); - //TEST_SINGLE(sqshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshrun d30, d29, #1"); - //TEST_SINGLE(sqshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqshrun d30, d29, #63"); + // TEST_SINGLE(sqshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqshrun d30, d29, #1"); + // TEST_SINGLE(sqshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqshrun d30, d29, #63"); - TEST_SINGLE(sqrshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqrshrun b30, h29, #1"); - TEST_SINGLE(sqrshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqrshrun b30, h29, #7"); - TEST_SINGLE(sqrshrun(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqrshrun h30, s29, #1"); + TEST_SINGLE(sqrshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "sqrshrun b30, h29, #1"); + TEST_SINGLE(sqrshrun(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "sqrshrun b30, h29, #7"); + TEST_SINGLE(sqrshrun(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "sqrshrun h30, s29, #1"); TEST_SINGLE(sqrshrun(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "sqrshrun h30, s29, #15"); - TEST_SINGLE(sqrshrun(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqrshrun s30, d29, #1"); + TEST_SINGLE(sqrshrun(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "sqrshrun s30, d29, #1"); TEST_SINGLE(sqrshrun(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "sqrshrun s30, d29, #31"); - //TEST_SINGLE(sqrshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqrshrun d30, d29, #1"); - //TEST_SINGLE(sqrshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqrshrun d30, d29, #63"); + // TEST_SINGLE(sqrshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "sqrshrun d30, d29, #1"); + // TEST_SINGLE(sqrshrun(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "sqrshrun d30, d29, #63"); - TEST_SINGLE(uqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "uqshrn b30, h29, #1"); - TEST_SINGLE(uqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "uqshrn b30, h29, #7"); - TEST_SINGLE(uqshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "uqshrn h30, s29, #1"); + TEST_SINGLE(uqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "uqshrn b30, h29, #1"); + TEST_SINGLE(uqshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "uqshrn b30, h29, #7"); + TEST_SINGLE(uqshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "uqshrn h30, s29, #1"); TEST_SINGLE(uqshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "uqshrn h30, s29, #15"); - TEST_SINGLE(uqshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "uqshrn s30, d29, #1"); + TEST_SINGLE(uqshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "uqshrn s30, d29, #1"); TEST_SINGLE(uqshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "uqshrn s30, d29, #31"); - //TEST_SINGLE(uqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "uqshrn d30, d29, #1"); - //TEST_SINGLE(uqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "uqshrn d30, d29, #63"); + // TEST_SINGLE(uqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "uqshrn d30, d29, #1"); + // TEST_SINGLE(uqshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "uqshrn d30, d29, #63"); - TEST_SINGLE(uqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "uqrshrn b30, h29, #1"); - TEST_SINGLE(uqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "uqrshrn b30, h29, #7"); - TEST_SINGLE(uqrshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "uqrshrn h30, s29, #1"); + TEST_SINGLE(uqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 1), "uqrshrn b30, h29, #1"); + TEST_SINGLE(uqrshrn(ScalarRegSize::i8Bit, VReg::v30, VReg::v29, 7), "uqrshrn b30, h29, #7"); + TEST_SINGLE(uqrshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 1), "uqrshrn h30, s29, #1"); TEST_SINGLE(uqrshrn(ScalarRegSize::i16Bit, VReg::v30, VReg::v29, 15), "uqrshrn h30, s29, #15"); - TEST_SINGLE(uqrshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "uqrshrn s30, d29, #1"); + TEST_SINGLE(uqrshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 1), "uqrshrn s30, d29, #1"); TEST_SINGLE(uqrshrn(ScalarRegSize::i32Bit, VReg::v30, VReg::v29, 31), "uqrshrn s30, d29, #31"); - //TEST_SINGLE(uqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "uqrshrn d30, d29, #1"); - //TEST_SINGLE(uqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "uqrshrn d30, d29, #63"); + // TEST_SINGLE(uqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 1), "uqrshrn d30, d29, #1"); + // TEST_SINGLE(uqrshrn(ScalarRegSize::i64Bit, VReg::v30, VReg::v29, 63), "uqrshrn d30, d29, #63"); // TODO: Implement `UCVTF, FCVTZU' in emitter } @@ -736,7 +736,7 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Floating-point data-process TEST_CASE_METHOD(TestDisassembler, "Emitter: Scalar: Floating-point compare") { // Commented out lines showcase unallocated encodings. - //TEST_SINGLE(fcmp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmp b30, b29"); + // TEST_SINGLE(fcmp(ScalarRegSize::i8Bit, VReg::v30, VReg::v29), "fcmp b30, b29"); TEST_SINGLE(fcmp(ScalarRegSize::i16Bit, VReg::v30, VReg::v29), "fcmp h30, h29"); TEST_SINGLE(fcmp(ScalarRegSize::i32Bit, VReg::v30, VReg::v29), "fcmp s30, s29"); TEST_SINGLE(fcmp(ScalarRegSize::i64Bit, VReg::v30, VReg::v29), "fcmp d30, d29"); diff --git a/FEXCore/unittests/Emitter/TestDisassembler.h b/FEXCore/unittests/Emitter/TestDisassembler.h index 61261f257..c82b1eb93 100644 --- a/FEXCore/unittests/Emitter/TestDisassembler.h +++ b/FEXCore/unittests/Emitter/TestDisassembler.h @@ -9,7 +9,7 @@ #include -class TestDisassembler : public FEXCore::ARMEmitter::Emitter { +class TestDisassembler : public FEXCore::ARMEmitter::Emitter { public: TestDisassembler() { fp = tmpfile(); @@ -38,7 +38,7 @@ public: } uint32_t DisassembleEncoding(size_t Offset = 0) { - const uint32_t *Values = reinterpret_cast(GetBufferBase()); + const uint32_t* Values = reinterpret_cast(GetBufferBase()); SetCursorOffset(0); ResetFP(); return Values[Offset]; @@ -46,7 +46,7 @@ public: fextl::string DisassembleString() { HandleDisasm(); - fextl::string Decoded{}; + fextl::string Decoded {}; char Tmp[512]; uint64_t Addr; uint32_t Encoding; @@ -68,12 +68,10 @@ private: void ResetFP() { fseek(fp, 0, SEEK_SET); } - FILE *fp; + FILE* fp; const vixl::aarch64::Instruction* BufferBegin; std::unique_ptr Disasm; }; #define TEST_SINGLE(emit, expected) \ -{ \ - CHECK((emit, DisassembleSingle()) == expected); \ -} + { CHECK((emit, DisassembleSingle()) == expected); } diff --git a/FEXHeaderUtils/FEXHeaderUtils/BitUtils.h b/FEXHeaderUtils/FEXHeaderUtils/BitUtils.h index 947b95214..8a3ac9954 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/BitUtils.h +++ b/FEXHeaderUtils/FEXHeaderUtils/BitUtils.h @@ -13,66 +13,66 @@ namespace FEXCore { // Determines the number of bits inside of a given type. -template -[[nodiscard]] constexpr size_t BitSize() noexcept { - return sizeof(T) * CHAR_BIT; +template +[[nodiscard]] +constexpr size_t BitSize() noexcept { + return sizeof(T) * CHAR_BIT; } // Swaps the bytes of a 16-bit unsigned value. -[[nodiscard]] inline uint16_t BSwap16(uint16_t value) noexcept { +[[nodiscard]] +inline uint16_t BSwap16(uint16_t value) noexcept { #ifdef __GNUC__ - return __builtin_bswap16(value); + return __builtin_bswap16(value); #else - return (value >> 8) | (value << 8); + return (value >> 8) | (value << 8); #endif } // Swaps the bytes of a 32-bit unsigned value. -[[nodiscard]] inline uint32_t BSwap32(uint32_t value) noexcept { +[[nodiscard]] +inline uint32_t BSwap32(uint32_t value) noexcept { #ifdef __GNUC__ - return __builtin_bswap32(value); + return __builtin_bswap32(value); #else - return ((value & 0xFF000000U) >> 24) | ((value & 0x00FF0000U) >> 8) | - ((value & 0x0000FF00U) << 8) | ((value & 0x000000FFU) << 24); + return ((value & 0xFF000000U) >> 24) | ((value & 0x00FF0000U) >> 8) | ((value & 0x0000FF00U) << 8) | ((value & 0x000000FFU) << 24); #endif } // Swaps the bytes of a 64-bit unsigned value. -[[nodiscard]] inline uint64_t BSwap64(uint64_t value) noexcept { +[[nodiscard]] +inline uint64_t BSwap64(uint64_t value) noexcept { #ifdef __GNUC__ - return __builtin_bswap64(value); + return __builtin_bswap64(value); #else - return ((value & 0xFF00000000000000ULL) >> 56) | ((value & 0x00FF000000000000ULL) >> 40) | - ((value & 0x0000FF0000000000ULL) >> 24) | ((value & 0x000000FF00000000ULL) >> 8) | - ((value & 0x00000000FF000000ULL) << 8) | ((value & 0x0000000000FF0000ULL) << 24) | - ((value & 0x000000000000FF00ULL) << 40) | ((value & 0x00000000000000FFULL) << 56); + return ((value & 0xFF00000000000000ULL) >> 56) | ((value & 0x00FF000000000000ULL) >> 40) | ((value & 0x0000FF0000000000ULL) >> 24) | + ((value & 0x000000FF00000000ULL) >> 8) | ((value & 0x00000000FF000000ULL) << 8) | ((value & 0x0000000000FF0000ULL) << 24) | + ((value & 0x000000000000FF00ULL) << 40) | ((value & 0x00000000000000FFULL) << 56); #endif } // Finds the first least-significant set bit within a given value. // Note that all returned indices are 1-based, not 0-based. -template -[[nodiscard]] constexpr int FindFirstSetBit(T value) noexcept { - static_assert(std::is_unsigned_v, "Type must be unsigned."); +template +[[nodiscard]] +constexpr int FindFirstSetBit(T value) noexcept { + static_assert(std::is_unsigned_v, "Type must be unsigned."); - if (value == 0) { - return 0; - } + if (value == 0) { + return 0; + } - const int trailing_zeroes = std::countr_zero(value); - return trailing_zeroes + 1; + const int trailing_zeroes = std::countr_zero(value); + return trailing_zeroes + 1; } // Stand-in for std::bit_cast until libc++ implements it. -template -[[nodiscard]] inline To BitCast(const From& source) noexcept -{ - static_assert(sizeof(From) == sizeof(To), - "BitCast source and destination types must be equal in size."); - static_assert(std::is_trivially_copyable_v, - "BitCast source type must be trivially copyable."); - static_assert(std::is_trivially_copyable_v, - "BitCast destination type must be trivially copyable."); +template +[[nodiscard]] +inline To BitCast(const From& source) noexcept { + static_assert(sizeof(From) == sizeof(To), "BitCast source and destination types must be equal in size."); + static_assert(std::is_trivially_copyable_v, "BitCast source type must be trivially copyable."); + static_assert(std::is_trivially_copyable_v, "BitCast destination type must be trivially copyable."); std::aligned_storage_t storage; std::memcpy(&storage, &source, sizeof(storage)); diff --git a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h index 7e841c2ad..78fc423aa 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h +++ b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h @@ -19,378 +19,369 @@ #include namespace FHU::Filesystem { - enum class CreateDirectoryResult { - CREATED, - EXISTS, - ERROR, - }; +enum class CreateDirectoryResult { + CREATED, + EXISTS, + ERROR, +}; - enum class CopyOptions { - NONE, - SKIP_EXISTING, - OVERWRITE_EXISTING, - }; +enum class CopyOptions { + NONE, + SKIP_EXISTING, + OVERWRITE_EXISTING, +}; - /** - * @brief Check if a filepath exists. - * - * @param Path The path to check for. - * - * @return True if the file exists, False if it doesn't. - */ - inline bool Exists(const char *Path) { - return access(Path, F_OK) == 0; - } +/** + * @brief Check if a filepath exists. + * + * @param Path The path to check for. + * + * @return True if the file exists, False if it doesn't. + */ +inline bool Exists(const char* Path) { + return access(Path, F_OK) == 0; +} - inline bool Exists(const fextl::string &Path) { - return access(Path.c_str(), F_OK) == 0; - } +inline bool Exists(const fextl::string& Path) { + return access(Path.c_str(), F_OK) == 0; +} - /** - * @brief Renames a file and overwrites if it already exists. - * - * @return No error on rename. - */ - [[nodiscard]] inline std::error_code RenameFile(const fextl::string &From, const fextl::string &To) { - return rename(From.c_str(), To.c_str()) == 0 ? std::error_code{} : std::make_error_code(std::errc::io_error); - } +/** + * @brief Renames a file and overwrites if it already exists. + * + * @return No error on rename. + */ +[[nodiscard]] +inline std::error_code RenameFile(const fextl::string& From, const fextl::string& To) { + return rename(From.c_str(), To.c_str()) == 0 ? std::error_code {} : std::make_error_code(std::errc::io_error); +} #ifndef _WIN32 - inline bool ExistsAt(int FD, const fextl::string &Path) { - return faccessat(FD, Path.c_str(), F_OK, 0) == 0; +inline bool ExistsAt(int FD, const fextl::string& Path) { + return faccessat(FD, Path.c_str(), F_OK, 0) == 0; +} + +/** + * @brief Creates a directory at the provided path. + * + * @param Path The path to create a directory at. + * + * @return Result enum depending. + */ +inline CreateDirectoryResult CreateDirectory(const fextl::string& Path) { + auto Result = ::mkdir(Path.c_str(), 0777); + if (Result == 0) { + return CreateDirectoryResult::CREATED; } - /** - * @brief Creates a directory at the provided path. - * - * @param Path The path to create a directory at. - * - * @return Result enum depending. - */ - inline CreateDirectoryResult CreateDirectory(const fextl::string &Path) { - auto Result = ::mkdir(Path.c_str(), 0777); - if (Result == 0) { - return CreateDirectoryResult::CREATED; + if (Result == -1 && errno == EEXIST) { + // If it exists, we need to check if it is a file or folder. + struct stat buf; + if (stat(Path.c_str(), &buf) == 0) { + // Check to see if the path is a file or folder. Following symlinks. + return S_ISDIR(buf.st_mode) ? CreateDirectoryResult::EXISTS : CreateDirectoryResult::ERROR; } - - if (Result == -1 && errno == EEXIST) { - // If it exists, we need to check if it is a file or folder. - struct stat buf; - if (stat(Path.c_str(), &buf) == 0) { - // Check to see if the path is a file or folder. Following symlinks. - return S_ISDIR(buf.st_mode) ? - CreateDirectoryResult::EXISTS : - CreateDirectoryResult::ERROR; - } - } - - // Couldn't create, or the path that existed wasn't a folder. - return CreateDirectoryResult::ERROR; } - /** - * @brief Creates a directory tree with the provided path. - * - * @param Path The path to create a tree at. - * - * @return True if the directory tree was created or already exists. - */ - inline bool CreateDirectories(const fextl::string &Path) { - // Try to create the directory initially. - if (CreateDirectory(Path) != CreateDirectoryResult::ERROR) { - return true; - } + // Couldn't create, or the path that existed wasn't a folder. + return CreateDirectoryResult::ERROR; +} - // Walk the path in reverse and create paths as we go. - fextl::string TmpPath {Path.substr(0, Path.rfind('/', Path.size() - 1))}; - if (!TmpPath.empty() && CreateDirectories(TmpPath)) { - return CreateDirectory(Path) != CreateDirectoryResult::ERROR; - } - return false; +/** + * @brief Creates a directory tree with the provided path. + * + * @param Path The path to create a tree at. + * + * @return True if the directory tree was created or already exists. + */ +inline bool CreateDirectories(const fextl::string& Path) { + // Try to create the directory initially. + if (CreateDirectory(Path) != CreateDirectoryResult::ERROR) { + return true; } - /** - * @brief Extracts the filename component from a file path. - * - * @param Path The path to create a directory at. - * - * @return The filename component of the path. - */ - inline fextl::string GetFilename(const fextl::string &Path) { - auto LastSeparator = Path.rfind('/'); - if (LastSeparator == fextl::string::npos) { - // No separator. Likely relative `.`, `..`, ``, or empty string. - return Path; - } + // Walk the path in reverse and create paths as we go. + fextl::string TmpPath {Path.substr(0, Path.rfind('/', Path.size() - 1))}; + if (!TmpPath.empty() && CreateDirectories(TmpPath)) { + return CreateDirectory(Path) != CreateDirectoryResult::ERROR; + } + return false; +} - return Path.substr(LastSeparator + 1); +/** + * @brief Extracts the filename component from a file path. + * + * @param Path The path to create a directory at. + * + * @return The filename component of the path. + */ +inline fextl::string GetFilename(const fextl::string& Path) { + auto LastSeparator = Path.rfind('/'); + if (LastSeparator == fextl::string::npos) { + // No separator. Likely relative `.`, `..`, ``, or empty string. + return Path; } - inline fextl::string ParentPath(const fextl::string &Path) { - auto LastSeparator = Path.rfind('/'); + return Path.substr(LastSeparator + 1); +} - if (LastSeparator == fextl::string::npos) { - // No separator. Likely relative `.`, `..`, ``, or empty string. - if (Path == "." || Path == "..") { - // In this edge-case, return nothing to match std::filesystem::path::parent_path behaviour. - return {}; - } - return Path; - } +inline fextl::string ParentPath(const fextl::string& Path) { + auto LastSeparator = Path.rfind('/'); - if (LastSeparator == 0) { - // In the case of root, just return. - return "/"; - } - - auto SubString = Path.substr(0, LastSeparator); - - while (SubString.size() > 1 && SubString.ends_with("/")) { - // If the substring still ended with `/` then we need to string that off as well. - --LastSeparator; - SubString = Path.substr(0, LastSeparator); - } - - return SubString; - } - - inline bool IsRelative(const std::string_view Path) { - return !Path.starts_with('/'); - } - - inline bool IsAbsolute(const std::string_view Path) { - return Path.starts_with('/'); - } - - /** - * @brief Copy a file from a location to another - * - * Behaves similarly to std::filesystem::copy_file but with less copy options. - * - * @param From Source file location. - * @param To Destination file location. - * @param Options Copy options. - * - * @return True if the copy succeeded, false otherwise. - */ - inline bool CopyFile(const fextl::string &From, const fextl::string &To, CopyOptions Options = CopyOptions::NONE) { - const bool DestExists = Exists(To); - if (Options == CopyOptions::SKIP_EXISTING && DestExists) { - // If the destination file exists already and the skip existing flag is set then - // return true without error. - return true; - } - - if (Options == CopyOptions::OVERWRITE_EXISTING && DestExists) { - // If we are overwriting and the file exists then we want to use `sendfile` to overwrite - int SourceFD = open(From.c_str(), O_RDONLY | O_CLOEXEC); - if (SourceFD == -1) { - return false; - } - - int DestinationFD = open(To.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0200); - if (DestinationFD == -1) { - close(SourceFD); - return false; - } - - struct stat buf; - if (fstat(SourceFD, &buf) != 0) { - close(DestinationFD); - close(SourceFD); - return false; - } - - // Set the destination permissions to the original source permissions. - if (fchmod(DestinationFD, buf.st_mode) != 0) { - close(DestinationFD); - close(SourceFD); - return false; - } - bool Result = sendfile(DestinationFD, SourceFD, nullptr, buf.st_size) == buf.st_size; - close(DestinationFD); - close(SourceFD); - return Result; - } - - if (!DestExists) { - // If the destination doesn't exist then just use rename. - return rename(From.c_str(), To.c_str()) == 0; - } - - return false; - } - - inline fextl::string LexicallyNormal(const fextl::string &Path) { - const auto PathSize = Path.size(); - - // Early exit on empty paths. - if (PathSize == 0) { + if (LastSeparator == fextl::string::npos) { + // No separator. Likely relative `.`, `..`, ``, or empty string. + if (Path == "." || Path == "..") { + // In this edge-case, return nothing to match std::filesystem::path::parent_path behaviour. return {}; } + return Path; + } - const auto IsAbsolutePath = IsAbsolute(Path); - const auto EndsWithSeparator = Path.ends_with('/'); - // Count the number of separators up front - const auto SeparatorCount = std::count(Path.begin(), Path.end(), '/'); + if (LastSeparator == 0) { + // In the case of root, just return. + return "/"; + } - // Use std::list to store path elements to avoid iterator invalidation on insert/erase. - // The list is allocated on stack to be more optimal. The size is determined by the - // maximum number of list objects (separator count plus 2) multiplied by the list - // element size (32-bytes per element: the string_view itself and the prev/next pointers). - size_t DataSize = (sizeof(std::string_view) + sizeof(void*) * 2) * (SeparatorCount + 2); - void *Data = alloca(DataSize); - fextl::pmr::fixed_size_monotonic_buffer_resource mbr(Data, DataSize); - std::pmr::polymorphic_allocator pa {&mbr}; - std::pmr::list Parts{pa}; + auto SubString = Path.substr(0, LastSeparator); - size_t CurrentOffset{}; - do { - auto FoundSeperator = Path.find('/', CurrentOffset); - if (FoundSeperator == Path.npos) { - FoundSeperator = PathSize; - } + while (SubString.size() > 1 && SubString.ends_with("/")) { + // If the substring still ended with `/` then we need to string that off as well. + --LastSeparator; + SubString = Path.substr(0, LastSeparator); + } - const auto Begin = Path.begin() + CurrentOffset; - const auto End = Path.begin() + FoundSeperator; - const auto Size = End - Begin; + return SubString; +} - // Only insert parts that contain data. - if (Size != 0) { - Parts.emplace_back(std::string_view(Begin, End)); - } +inline bool IsRelative(const std::string_view Path) { + return !Path.starts_with('/'); +} - if (Size == 0) { - // If the view is empty, skip over the separator. - FoundSeperator += 1; - } +inline bool IsAbsolute(const std::string_view Path) { + return Path.starts_with('/'); +} - CurrentOffset = FoundSeperator; - } while (CurrentOffset != PathSize); +/** + * @brief Copy a file from a location to another + * + * Behaves similarly to std::filesystem::copy_file but with less copy options. + * + * @param From Source file location. + * @param To Destination file location. + * @param Options Copy options. + * + * @return True if the copy succeeded, false otherwise. + */ +inline bool CopyFile(const fextl::string& From, const fextl::string& To, CopyOptions Options = CopyOptions::NONE) { + const bool DestExists = Exists(To); + if (Options == CopyOptions::SKIP_EXISTING && DestExists) { + // If the destination file exists already and the skip existing flag is set then + // return true without error. + return true; + } - size_t CurrentIterDistance{}; - for (auto iter = Parts.begin(); iter != Parts.end();) { - auto &Part = *iter; - if (Part == ".") { - // Erase '.' directory parts if not at root. - if (CurrentIterDistance > 0 || IsAbsolutePath) { - // Erasing this iterator, don't increase iter distances - iter = Parts.erase(iter); - continue; - } - } - - if (Part == "..") { - if (CurrentIterDistance > 0) { - // If not at root then remove both this iterator and the previous one. - // ONLY if the previous iterator is also not ".." - // - // If the previous iterator is '.' then /only/ erase the previous iterator. - auto PreviousIter = iter; - --PreviousIter; - - if (*PreviousIter == ".") { - // Erasing the previous iterator, iterator distance has subtracted by one - --CurrentIterDistance; - Parts.erase(PreviousIter); - } - else if (*PreviousIter != "..") { - // Erasing the previous iterator, iterator distance has subtracted by one - // Also erasing current iterator, which means iterator distance also doesn't increase by one. - --CurrentIterDistance; - Parts.erase(PreviousIter); - iter = Parts.erase(iter); - continue; - } - } - else if (IsAbsolutePath) { - // `..` at the base. Just remove this - iter = Parts.erase(iter); - continue; - } - } - - // Interator distance increased by one. - ++CurrentIterDistance; - ++iter; + if (Options == CopyOptions::OVERWRITE_EXISTING && DestExists) { + // If we are overwriting and the file exists then we want to use `sendfile` to overwrite + int SourceFD = open(From.c_str(), O_RDONLY | O_CLOEXEC); + if (SourceFD == -1) { + return false; } + int DestinationFD = open(To.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0200); + if (DestinationFD == -1) { + close(SourceFD); + return false; + } - // Add a final separator unless the last element is ellipses. - const bool NeedsFinalSeparator = EndsWithSeparator && (!Parts.empty() && Parts.back() != "." && Parts.back() != ".."); - return fextl::fmt::format("{}{}{}", - IsAbsolutePath ? "/" : "", - fmt::join(Parts, "/"), - NeedsFinalSeparator ? "/" : ""); + struct stat buf; + if (fstat(SourceFD, &buf) != 0) { + close(DestinationFD); + close(SourceFD); + return false; + } + + // Set the destination permissions to the original source permissions. + if (fchmod(DestinationFD, buf.st_mode) != 0) { + close(DestinationFD); + close(SourceFD); + return false; + } + bool Result = sendfile(DestinationFD, SourceFD, nullptr, buf.st_size) == buf.st_size; + close(DestinationFD); + close(SourceFD); + return Result; } - inline char *Absolute(const char *Path, char Fill[PATH_MAX]) { - return realpath(Path, Fill); + if (!DestExists) { + // If the destination doesn't exist then just use rename. + return rename(From.c_str(), To.c_str()) == 0; } + + return false; +} + +inline fextl::string LexicallyNormal(const fextl::string& Path) { + const auto PathSize = Path.size(); + + // Early exit on empty paths. + if (PathSize == 0) { + return {}; + } + + const auto IsAbsolutePath = IsAbsolute(Path); + const auto EndsWithSeparator = Path.ends_with('/'); + // Count the number of separators up front + const auto SeparatorCount = std::count(Path.begin(), Path.end(), '/'); + + // Use std::list to store path elements to avoid iterator invalidation on insert/erase. + // The list is allocated on stack to be more optimal. The size is determined by the + // maximum number of list objects (separator count plus 2) multiplied by the list + // element size (32-bytes per element: the string_view itself and the prev/next pointers). + size_t DataSize = (sizeof(std::string_view) + sizeof(void*) * 2) * (SeparatorCount + 2); + void* Data = alloca(DataSize); + fextl::pmr::fixed_size_monotonic_buffer_resource mbr(Data, DataSize); + std::pmr::polymorphic_allocator pa {&mbr}; + std::pmr::list Parts {pa}; + + size_t CurrentOffset {}; + do { + auto FoundSeperator = Path.find('/', CurrentOffset); + if (FoundSeperator == Path.npos) { + FoundSeperator = PathSize; + } + + const auto Begin = Path.begin() + CurrentOffset; + const auto End = Path.begin() + FoundSeperator; + const auto Size = End - Begin; + + // Only insert parts that contain data. + if (Size != 0) { + Parts.emplace_back(std::string_view(Begin, End)); + } + + if (Size == 0) { + // If the view is empty, skip over the separator. + FoundSeperator += 1; + } + + CurrentOffset = FoundSeperator; + } while (CurrentOffset != PathSize); + + size_t CurrentIterDistance {}; + for (auto iter = Parts.begin(); iter != Parts.end();) { + auto& Part = *iter; + if (Part == ".") { + // Erase '.' directory parts if not at root. + if (CurrentIterDistance > 0 || IsAbsolutePath) { + // Erasing this iterator, don't increase iter distances + iter = Parts.erase(iter); + continue; + } + } + + if (Part == "..") { + if (CurrentIterDistance > 0) { + // If not at root then remove both this iterator and the previous one. + // ONLY if the previous iterator is also not ".." + // + // If the previous iterator is '.' then /only/ erase the previous iterator. + auto PreviousIter = iter; + --PreviousIter; + + if (*PreviousIter == ".") { + // Erasing the previous iterator, iterator distance has subtracted by one + --CurrentIterDistance; + Parts.erase(PreviousIter); + } else if (*PreviousIter != "..") { + // Erasing the previous iterator, iterator distance has subtracted by one + // Also erasing current iterator, which means iterator distance also doesn't increase by one. + --CurrentIterDistance; + Parts.erase(PreviousIter); + iter = Parts.erase(iter); + continue; + } + } else if (IsAbsolutePath) { + // `..` at the base. Just remove this + iter = Parts.erase(iter); + continue; + } + } + + // Interator distance increased by one. + ++CurrentIterDistance; + ++iter; + } + + + // Add a final separator unless the last element is ellipses. + const bool NeedsFinalSeparator = EndsWithSeparator && (!Parts.empty() && Parts.back() != "." && Parts.back() != ".."); + return fextl::fmt::format("{}{}{}", IsAbsolutePath ? "/" : "", fmt::join(Parts, "/"), NeedsFinalSeparator ? "/" : ""); +} + +inline char* Absolute(const char* Path, char Fill[PATH_MAX]) { + return realpath(Path, Fill); +} #else - inline fextl::string PathToString(const std::filesystem::path &path) { - return path.string, fextl::FEXAlloc>(); +inline fextl::string PathToString(const std::filesystem::path& path) { + return path.string, fextl::FEXAlloc>(); +} + +inline CreateDirectoryResult CreateDirectory(const fextl::string& Path) { + std::error_code ec; + if (std::filesystem::exists(Path, ec)) { + return CreateDirectoryResult::EXISTS; } - inline CreateDirectoryResult CreateDirectory(const fextl::string &Path) { - std::error_code ec; - if (std::filesystem::exists(Path, ec)) { - return CreateDirectoryResult::EXISTS; - } + return std::filesystem::create_directory(Path, ec) ? CreateDirectoryResult::CREATED : CreateDirectoryResult::ERROR; +} - return std::filesystem::create_directory(Path, ec) ? - CreateDirectoryResult::CREATED : - CreateDirectoryResult::ERROR; +inline bool CreateDirectories(const fextl::string& Path) { + std::error_code ec; + return std::filesystem::exists(Path, ec) || std::filesystem::create_directories(Path, ec); +} + +inline fextl::string GetFilename(const fextl::string& Path) { + return PathToString(std::filesystem::path(Path).filename()); +} + +inline fextl::string ParentPath(const fextl::string& Path) { + return PathToString(std::filesystem::path(Path).parent_path()); +} + +inline bool IsRelative(const std::string_view Path) { + return std::filesystem::path(Path).is_relative(); +} + +inline bool IsAbsolute(const std::string_view Path) { + return std::filesystem::path(Path).is_absolute(); +} + +inline bool CopyFile(const fextl::string& From, const fextl::string& To, CopyOptions Options = CopyOptions::NONE) { + std::filesystem::copy_options options {}; + if (Options == CopyOptions::SKIP_EXISTING) { + options = std::filesystem::copy_options::skip_existing; + } else if (Options == CopyOptions::OVERWRITE_EXISTING) { + options = std::filesystem::copy_options::overwrite_existing; } - inline bool CreateDirectories(const fextl::string &Path) { - std::error_code ec; - return std::filesystem::exists(Path, ec) || std::filesystem::create_directories(Path, ec); + std::error_code ec; + return std::filesystem::copy_file(From, To, options, ec); +} + +inline fextl::string LexicallyNormal(const fextl::string& Path) { + return PathToString(std::filesystem::path(Path).lexically_normal()); +} + +inline char* Absolute(const char* Path, char Fill[PATH_MAX]) { + std::error_code ec; + const auto PathAbsolute = std::filesystem::absolute(Path, ec); + if (!ec) { + strncpy(Fill, PathAbsolute.string().c_str(), sizeof(*Fill)); + return Fill; } - inline fextl::string GetFilename(const fextl::string &Path) { - return PathToString(std::filesystem::path(Path).filename()); - } - - inline fextl::string ParentPath(const fextl::string &Path) { - return PathToString(std::filesystem::path(Path).parent_path()); - } - - inline bool IsRelative(const std::string_view Path) { - return std::filesystem::path(Path).is_relative(); - } - - inline bool IsAbsolute(const std::string_view Path) { - return std::filesystem::path(Path).is_absolute(); - } - - inline bool CopyFile(const fextl::string &From, const fextl::string &To, CopyOptions Options = CopyOptions::NONE) { - std::filesystem::copy_options options{}; - if (Options == CopyOptions::SKIP_EXISTING) { - options = std::filesystem::copy_options::skip_existing; - } - else if (Options == CopyOptions::OVERWRITE_EXISTING) { - options = std::filesystem::copy_options::overwrite_existing; - } - - std::error_code ec; - return std::filesystem::copy_file(From, To, options, ec); - } - - inline fextl::string LexicallyNormal(const fextl::string &Path) { - return PathToString(std::filesystem::path(Path).lexically_normal()); - } - - inline char *Absolute(const char *Path, char Fill[PATH_MAX]) { - std::error_code ec; - const auto PathAbsolute = std::filesystem::absolute(Path, ec); - if (!ec) { - strncpy(Fill, PathAbsolute.string().c_str(), sizeof(*Fill)); - return Fill; - } - - return nullptr; - } + return nullptr; +} #endif -} +} // namespace FHU::Filesystem diff --git a/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h b/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h index ad9a02b1d..80e4a5971 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h +++ b/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h @@ -10,8 +10,8 @@ namespace FHU::Symlinks { #ifndef _WIN32 // Checks to see if a filepath is a symlink. -inline bool IsSymlink(const fextl::string &Filename) { - struct stat Buffer{}; +inline bool IsSymlink(const fextl::string& Filename) { + struct stat Buffer {}; int Result = lstat(Filename.c_str(), &Buffer); return Result == 0 && S_ISLNK(Buffer.st_mode); } @@ -20,7 +20,7 @@ inline bool IsSymlink(const fextl::string &Filename) { // Doesn't handle recursive symlinks. // Doesn't append null terminator character. // Returns a string_view of the resolved path, or an empty view on error. -inline std::string_view ResolveSymlink(const fextl::string &Filename, std::span ResultBuffer) { +inline std::string_view ResolveSymlink(const fextl::string& Filename, std::span ResultBuffer) { ssize_t Result = readlink(Filename.c_str(), ResultBuffer.data(), ResultBuffer.size()); if (Result == -1) { return {}; @@ -29,4 +29,4 @@ inline std::string_view ResolveSymlink(const fextl::string &Filename, std::span< return std::string_view(ResultBuffer.data(), Result); } #endif -} +} // namespace FHU::Symlinks diff --git a/FEXHeaderUtils/FEXHeaderUtils/Syscalls.h b/FEXHeaderUtils/FEXHeaderUtils/Syscalls.h index fdf630e2b..0f8bef3fc 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/Syscalls.h +++ b/FEXHeaderUtils/FEXHeaderUtils/Syscalls.h @@ -52,7 +52,7 @@ namespace FHU::Syscalls { #endif #ifndef _WIN32 -inline int32_t getcpu(uint32_t *cpu, uint32_t *node) { +inline int32_t getcpu(uint32_t* cpu, uint32_t* node) { // Third argument is unused #if defined(HAS_SYSCALL_GETCPU) && HAS_SYSCALL_GETCPU return ::getcpu(cpu, node); @@ -77,15 +77,15 @@ inline int32_t tgkill(pid_t tgid, pid_t tid, int sig) { #endif } -inline int32_t statx(int dirfd, const char *pathname, int32_t flags, uint32_t mask, void *statxbuf) { +inline int32_t statx(int dirfd, const char* pathname, int32_t flags, uint32_t mask, void* statxbuf) { #if defined(HAS_SYSCALL_STATX) && HAS_SYSCALL_STATX - return ::statx(dirfd, pathname, flags, mask, reinterpret_cast(statxbuf)); + return ::statx(dirfd, pathname, flags, mask, reinterpret_cast(statxbuf)); #else return ::syscall(SYS_statx, dirfd, pathname, flags, mask, statxbuf); #endif } -inline int32_t renameat2(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags) { +inline int32_t renameat2(int olddirfd, const char* oldpath, int newdirfd, const char* newpath, unsigned int flags) { #if defined(HAS_SYSCALL_STATX) && HAS_SYSCALL_STATX return ::renameat2(olddirfd, oldpath, newdirfd, newpath, flags); #else @@ -98,7 +98,7 @@ inline int32_t pidfd_open(pid_t pid, unsigned int flags) { } #else -inline int32_t getcpu(uint32_t *cpu, uint32_t *node) { +inline int32_t getcpu(uint32_t* cpu, uint32_t* node) { if (cpu) { *cpu = GetCurrentProcessorNumber(); } @@ -119,4 +119,4 @@ inline int32_t gettid() { #endif -} +} // namespace FHU::Syscalls diff --git a/FEXHeaderUtils/FEXHeaderUtils/TodoDefines.h b/FEXHeaderUtils/FEXHeaderUtils/TodoDefines.h index 2072db79f..69c9f4191 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/TodoDefines.h +++ b/FEXHeaderUtils/FEXHeaderUtils/TodoDefines.h @@ -2,7 +2,7 @@ #pragma once #ifndef DO_PRAGMA -#define DO_PRAGMA(x) _Pragma (#x) +#define DO_PRAGMA(x) _Pragma(#x) #endif #if FEX_WARN_TODO diff --git a/Source/Common/ArgumentLoader.cpp b/Source/Common/ArgumentLoader.cpp index 622e88f57..7a20f0abd 100644 --- a/Source/Common/ArgumentLoader.cpp +++ b/Source/Common/ArgumentLoader.cpp @@ -11,55 +11,55 @@ #include namespace FEX::ArgLoader { - fextl::vector RemainingArgs; - fextl::vector ProgramArguments; +fextl::vector RemainingArgs; +fextl::vector ProgramArguments; - static fextl::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; - void FEX::ArgLoader::ArgLoader::Load() { - optparse::OptionParser Parser{}; - Parser.version(Version); - optparse::OptionGroup CPUGroup(Parser, "CPU Core options"); - optparse::OptionGroup EmulationGroup(Parser, "Emulation options"); - optparse::OptionGroup DebugGroup(Parser, "Debug options"); - optparse::OptionGroup HacksGroup(Parser, "Hacks options"); - optparse::OptionGroup MiscGroup(Parser, "Miscellaneous options"); - optparse::OptionGroup LoggingGroup(Parser, "Logging options"); +static fextl::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; +void FEX::ArgLoader::ArgLoader::Load() { + optparse::OptionParser Parser {}; + Parser.version(Version); + optparse::OptionGroup CPUGroup(Parser, "CPU Core options"); + optparse::OptionGroup EmulationGroup(Parser, "Emulation options"); + optparse::OptionGroup DebugGroup(Parser, "Debug options"); + optparse::OptionGroup HacksGroup(Parser, "Hacks options"); + optparse::OptionGroup MiscGroup(Parser, "Miscellaneous options"); + optparse::OptionGroup LoggingGroup(Parser, "Logging options"); #define BEFORE_PARSE #include - Parser.add_option_group(CPUGroup); - Parser.add_option_group(EmulationGroup); - Parser.add_option_group(DebugGroup); - Parser.add_option_group(HacksGroup); - Parser.add_option_group(MiscGroup); - Parser.add_option_group(LoggingGroup); + Parser.add_option_group(CPUGroup); + Parser.add_option_group(EmulationGroup); + Parser.add_option_group(DebugGroup); + Parser.add_option_group(HacksGroup); + Parser.add_option_group(MiscGroup); + Parser.add_option_group(LoggingGroup); - optparse::Values Options = Parser.parse_args(argc, argv); + optparse::Values Options = Parser.parse_args(argc, argv); - using int32 = int32_t; - using uint32 = uint32_t; + using int32 = int32_t; + using uint32 = uint32_t; #define AFTER_PARSE #include - RemainingArgs = Parser.args(); - ProgramArguments = Parser.parsed_args(); - } - - void LoadWithoutArguments(int _argc, char **_argv) { - // Skip argument 0, which will be the interpreter - for (int i = 1; i < _argc; ++i) { - RemainingArgs.emplace_back(_argv[i]); - } - - // Put the interpreter in ProgramArguments - ProgramArguments.emplace_back(_argv[0]); - } - - fextl::vector Get() { - return RemainingArgs; - } - fextl::vector GetParsedArgs() { - return ProgramArguments; - } - + RemainingArgs = Parser.args(); + ProgramArguments = Parser.parsed_args(); } + +void LoadWithoutArguments(int _argc, char** _argv) { + // Skip argument 0, which will be the interpreter + for (int i = 1; i < _argc; ++i) { + RemainingArgs.emplace_back(_argv[i]); + } + + // Put the interpreter in ProgramArguments + ProgramArguments.emplace_back(_argv[0]); +} + +fextl::vector Get() { + return RemainingArgs; +} +fextl::vector GetParsedArgs() { + return ProgramArguments; +} + +} // namespace FEX::ArgLoader diff --git a/Source/Common/ArgumentLoader.h b/Source/Common/ArgumentLoader.h index 7fd19a054..dbbecf0dc 100644 --- a/Source/Common/ArgumentLoader.h +++ b/Source/Common/ArgumentLoader.h @@ -6,21 +6,21 @@ #include namespace FEX::ArgLoader { - class ArgLoader final : public FEXCore::Config::Layer { - public: - explicit ArgLoader(int _argc, char **_argv) - : FEXCore::Config::Layer(FEXCore::Config::LayerType::LAYER_ARGUMENTS) - , argc {_argc} - , argv {_argv} {} +class ArgLoader final : public FEXCore::Config::Layer { +public: + explicit ArgLoader(int _argc, char** _argv) + : FEXCore::Config::Layer(FEXCore::Config::LayerType::LAYER_ARGUMENTS) + , argc {_argc} + , argv {_argv} {} - void Load(); + void Load(); - private: - int argc{}; - char **argv; - }; +private: + int argc {}; + char** argv; +}; - void LoadWithoutArguments(int _argc, char **_argv); - fextl::vector Get(); - fextl::vector GetParsedArgs(); -} +void LoadWithoutArguments(int _argc, char** _argv); +fextl::vector Get(); +fextl::vector GetParsedArgs(); +} // namespace FEX::ArgLoader diff --git a/Source/Common/Config.cpp b/Source/Common/Config.cpp index 1430479ed..cf92cf172 100644 --- a/Source/Common/Config.cpp +++ b/Source/Common/Config.cpp @@ -39,35 +39,34 @@ namespace JSON { return &*alloc->json_objects->emplace(alloc->json_objects->end()); } - static void LoadJSonConfig(const fextl::string &Config, std::function Func) { + static void LoadJSonConfig(const fextl::string& Config, std::function Func) { fextl::vector Data; if (!FEXCore::FileLoading::LoadFile(Data, Config)) { return; } JsonAllocator Pool { - .PoolObject = { - .init = PoolInit, - .alloc = PoolAlloc, - }, + .PoolObject = + { + .init = PoolInit, + .alloc = PoolAlloc, + }, }; - json_t const *json = json_createWithPool(&Data.at(0), &Pool.PoolObject); + const json_t* json = json_createWithPool(&Data.at(0), &Pool.PoolObject); if (!json) { LogMan::Msg::EFmt("Couldn't create json"); return; } - json_t const* ConfigList = json_getProperty(json, "Config"); + const json_t* ConfigList = json_getProperty(json, "Config"); if (!ConfigList) { // This is a non-error if the configuration file exists but no Config section return; } - for (json_t const* ConfigItem = json_getChild(ConfigList); - ConfigItem != nullptr; - ConfigItem = json_getSibling(ConfigItem)) { + for (const json_t* ConfigItem = json_getChild(ConfigList); ConfigItem != nullptr; ConfigItem = json_getSibling(ConfigItem)) { const char* ConfigName = json_getName(ConfigItem); const char* ConfigString = json_getValue(ConfigItem); @@ -84,476 +83,448 @@ namespace JSON { Func(ConfigName, ConfigString); } } -} +} // namespace JSON - static const fextl::map ConfigToNameLookup = {{ +static const fextl::map ConfigToNameLookup = {{ #define OPT_BASE(type, group, enum, json, default) {FEXCore::Config::ConfigOption::CONFIG_##enum, #json}, #include - }}; +}}; - void SaveLayerToJSON(const fextl::string& Filename, FEXCore::Config::Layer *const Layer) { - char Buffer[4096]; - char *Dest{}; - Dest = json_objOpen(Buffer, nullptr); - Dest = json_objOpen(Dest, "Config"); - for (auto &it : Layer->GetOptionMap()) { - auto &Name = ConfigToNameLookup.find(it.first)->second; - for (auto &var : it.second) { - Dest = json_str(Dest, Name.c_str(), var.c_str()); - } - } - Dest = json_objClose(Dest); - Dest = json_objClose(Dest); - json_end(Dest); - - auto File = FEXCore::File::File(Filename.c_str(), - FEXCore::File::FileModes::WRITE | - FEXCore::File::FileModes::CREATE | - FEXCore::File::FileModes::TRUNCATE); - - if (File.IsValid()) { - File.Write(Buffer, strlen(Buffer)); +void SaveLayerToJSON(const fextl::string& Filename, FEXCore::Config::Layer* const Layer) { + char Buffer[4096]; + char* Dest {}; + Dest = json_objOpen(Buffer, nullptr); + Dest = json_objOpen(Dest, "Config"); + for (auto& it : Layer->GetOptionMap()) { + auto& Name = ConfigToNameLookup.find(it.first)->second; + for (auto& var : it.second) { + Dest = json_str(Dest, Name.c_str(), var.c_str()); } } + Dest = json_objClose(Dest); + Dest = json_objClose(Dest); + json_end(Dest); - // Application loaders - class OptionMapper : public FEXCore::Config::Layer { - public: - explicit OptionMapper(FEXCore::Config::LayerType Layer); + auto File = FEXCore::File::File(Filename.c_str(), + FEXCore::File::FileModes::WRITE | FEXCore::File::FileModes::CREATE | FEXCore::File::FileModes::TRUNCATE); - protected: - void MapNameToOption(const char *ConfigName, const char *ConfigString); - }; + if (File.IsValid()) { + File.Write(Buffer, strlen(Buffer)); + } +} - class MainLoader final : public OptionMapper { - public: - explicit MainLoader(FEXCore::Config::LayerType Type); - explicit MainLoader(fextl::string ConfigFile); - explicit MainLoader(FEXCore::Config::LayerType Type, const char* ConfigFile); +// Application loaders +class OptionMapper : public FEXCore::Config::Layer { +public: + explicit OptionMapper(FEXCore::Config::LayerType Layer); - void Load() override; +protected: + void MapNameToOption(const char* ConfigName, const char* ConfigString); +}; - private: - fextl::string Config; - }; +class MainLoader final : public OptionMapper { +public: + explicit MainLoader(FEXCore::Config::LayerType Type); + explicit MainLoader(fextl::string ConfigFile); + explicit MainLoader(FEXCore::Config::LayerType Type, const char* ConfigFile); - class AppLoader final : public OptionMapper { - public: - explicit AppLoader(const fextl::string& Filename, FEXCore::Config::LayerType Type); - void Load(); + void Load() override; - private: - fextl::string Config; - }; +private: + fextl::string Config; +}; - class EnvLoader final : public FEXCore::Config::Layer { - public: - explicit EnvLoader(char *const _envp[]); - void Load() override; +class AppLoader final : public OptionMapper { +public: + explicit AppLoader(const fextl::string& Filename, FEXCore::Config::LayerType Type); + void Load(); - private: - char *const *envp; - }; +private: + fextl::string Config; +}; - static const fextl::map> ConfigLookup = {{ +class EnvLoader final : public FEXCore::Config::Layer { +public: + explicit EnvLoader(char* const _envp[]); + void Load() override; + +private: + char* const* envp; +}; + +static const fextl::map> ConfigLookup = {{ #define OPT_BASE(type, group, enum, json, default) {#json, FEXCore::Config::ConfigOption::CONFIG_##enum}, #include - }}; +}}; - OptionMapper::OptionMapper(FEXCore::Config::LayerType Layer) - : FEXCore::Config::Layer(Layer) { - } +OptionMapper::OptionMapper(FEXCore::Config::LayerType Layer) + : FEXCore::Config::Layer(Layer) {} - void OptionMapper::MapNameToOption(const char *ConfigName, const char *ConfigString) { - auto it = ConfigLookup.find(ConfigName); - if (it != ConfigLookup.end()) { - const auto KeyOption = it->second; - const auto KeyName = std::string_view(ConfigName); - const auto Value_View = std::string_view(ConfigString); +void OptionMapper::MapNameToOption(const char* ConfigName, const char* ConfigString) { + auto it = ConfigLookup.find(ConfigName); + if (it != ConfigLookup.end()) { + const auto KeyOption = it->second; + const auto KeyName = std::string_view(ConfigName); + const auto Value_View = std::string_view(ConfigString); #define JSONLOADER #include - } } +} - static const fextl::vector> EnvConfigLookup = {{ +static const fextl::vector> EnvConfigLookup = {{ #define OPT_BASE(type, group, enum, json, default) {"FEX_" #enum, FEXCore::Config::ConfigOption::CONFIG_##enum}, #include - }}; +}}; - MainLoader::MainLoader(FEXCore::Config::LayerType Type) - : OptionMapper(Type) - , Config{FEXCore::Config::GetConfigFileLocation(Type == FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN)} { - } +MainLoader::MainLoader(FEXCore::Config::LayerType Type) + : OptionMapper(Type) + , Config {FEXCore::Config::GetConfigFileLocation(Type == FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN)} {} - MainLoader::MainLoader(fextl::string ConfigFile) - : OptionMapper(FEXCore::Config::LayerType::LAYER_MAIN) - , Config{std::move(ConfigFile)} { - } +MainLoader::MainLoader(fextl::string ConfigFile) + : OptionMapper(FEXCore::Config::LayerType::LAYER_MAIN) + , Config {std::move(ConfigFile)} {} - MainLoader::MainLoader(FEXCore::Config::LayerType Type, const char* ConfigFile) - : OptionMapper(Type) - , Config{ConfigFile} { - } +MainLoader::MainLoader(FEXCore::Config::LayerType Type, const char* ConfigFile) + : OptionMapper(Type) + , Config {ConfigFile} {} - void MainLoader::Load() { - JSON::LoadJSonConfig(Config, [this](const char *Name, const char *ConfigString) { - MapNameToOption(Name, ConfigString); - }); - } +void MainLoader::Load() { + JSON::LoadJSonConfig(Config, [this](const char* Name, const char* ConfigString) { MapNameToOption(Name, ConfigString); }); +} - AppLoader::AppLoader(const fextl::string& Filename, FEXCore::Config::LayerType Type) - : OptionMapper(Type) { - const bool Global = Type == FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP || - Type == FEXCore::Config::LayerType::LAYER_GLOBAL_APP; - Config = FEXCore::Config::GetApplicationConfig(Filename, Global); +AppLoader::AppLoader(const fextl::string& Filename, FEXCore::Config::LayerType Type) + : OptionMapper(Type) { + const bool Global = Type == FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP || Type == FEXCore::Config::LayerType::LAYER_GLOBAL_APP; + Config = FEXCore::Config::GetApplicationConfig(Filename, Global); - // Immediately load so we can reload the meta layer - Load(); - } + // Immediately load so we can reload the meta layer + Load(); +} - void AppLoader::Load() { - JSON::LoadJSonConfig(Config, [this](const char *Name, const char *ConfigString) { - MapNameToOption(Name, ConfigString); - }); - } +void AppLoader::Load() { + JSON::LoadJSonConfig(Config, [this](const char* Name, const char* ConfigString) { MapNameToOption(Name, ConfigString); }); +} - EnvLoader::EnvLoader(char *const _envp[]) - : FEXCore::Config::Layer(FEXCore::Config::LayerType::LAYER_ENVIRONMENT) - , envp {_envp} { - } +EnvLoader::EnvLoader(char* const _envp[]) + : FEXCore::Config::Layer(FEXCore::Config::LayerType::LAYER_ENVIRONMENT) + , envp {_envp} {} - void EnvLoader::Load() { - using EnvMapType = fextl::unordered_map; - EnvMapType EnvMap; +void EnvLoader::Load() { + using EnvMapType = fextl::unordered_map; + EnvMapType EnvMap; - for(const char *const *pvar=envp; pvar && *pvar; pvar++) { - std::string_view Var(*pvar); - size_t pos = Var.rfind('='); - if (fextl::string::npos == pos) - continue; + for (const char* const* pvar = envp; pvar && *pvar; pvar++) { + std::string_view Var(*pvar); + size_t pos = Var.rfind('='); + if (fextl::string::npos == pos) { + continue; + } - std::string_view Key = Var.substr(0,pos); - std::string_view Value_View {Var.substr(pos+1)}; - std::optional Value; + std::string_view Key = Var.substr(0, pos); + std::string_view Value_View {Var.substr(pos + 1)}; + std::optional Value; #define ENVLOADER #include - if (Value) { - EnvMap.insert_or_assign(Key, *Value); - } - else { - EnvMap.insert_or_assign(Key, Value_View); - } - } - - auto GetVar = [](EnvMapType &EnvMap, const std::string_view id) -> std::optional { - if (EnvMap.find(id) != EnvMap.end()) - return EnvMap.at(id); - - // If envp[] was empty, search using std::getenv() - const char* vs = std::getenv(id.data()); - if (vs) { - return vs; - } - else { - return std::nullopt; - } - }; - - std::optional Value; - - for (auto &it : EnvConfigLookup) { - if ((Value = GetVar(EnvMap, it.first)).has_value()) { - Set(it.second, fextl::string(*Value)); - } + if (Value) { + EnvMap.insert_or_assign(Key, *Value); + } else { + EnvMap.insert_or_assign(Key, Value_View); } } - fextl::unique_ptr CreateGlobalMainLayer() { - return fextl::make_unique(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN); + auto GetVar = [](EnvMapType& EnvMap, const std::string_view id) -> std::optional { + if (EnvMap.find(id) != EnvMap.end()) { + return EnvMap.at(id); + } + + // If envp[] was empty, search using std::getenv() + const char* vs = std::getenv(id.data()); + if (vs) { + return vs; + } else { + return std::nullopt; + } + }; + + std::optional Value; + + for (auto& it : EnvConfigLookup) { + if ((Value = GetVar(EnvMap, it.first)).has_value()) { + Set(it.second, fextl::string(*Value)); + } + } +} + +fextl::unique_ptr CreateGlobalMainLayer() { + return fextl::make_unique(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN); +} + +fextl::unique_ptr CreateMainLayer(const fextl::string* File) { + if (File) { + return fextl::make_unique(*File); + } else { + return fextl::make_unique(FEXCore::Config::LayerType::LAYER_MAIN); + } +} + +fextl::unique_ptr CreateUserOverrideLayer(const char* AppConfig) { + return fextl::make_unique(FEXCore::Config::LayerType::LAYER_USER_OVERRIDE, AppConfig); +} + +fextl::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type) { + return fextl::make_unique(Filename, Type); +} + +fextl::unique_ptr CreateEnvironmentLayer(char* const _envp[]) { + return fextl::make_unique(_envp); +} + +fextl::string RecoverGuestProgramFilename(fextl::string Program, bool ExecFDInterp, const std::string_view ProgramFDFromEnv) { + // If executed with a FEX FD then the Program argument might be empty. + // In this case we need to scan the FD node to recover the application binary that exists on disk. + // Only do this if the Program argument is empty, since we would prefer the application's expectation + // of application name. + if (!ProgramFDFromEnv.empty() && Program.empty()) { + // Get the `dev` node of the execveat fd string. + Program = "/dev/fd/"; + Program += ProgramFDFromEnv; } - fextl::unique_ptr CreateMainLayer(fextl::string const *File) { - if (File) { - return fextl::make_unique(*File); - } - else { - return fextl::make_unique(FEXCore::Config::LayerType::LAYER_MAIN); + // If we were provided a relative path then we need to canonicalize it to become absolute. + // If the program name isn't resolved to an absolute path then glibc breaks inside it's `_dl_get_origin` function. + // This is because we rewrite `/proc/self/exe` to the absolute program path calculated in here. + if (!Program.starts_with('/')) { + char ExistsTempPath[PATH_MAX]; + char* RealPath = FHU::Filesystem::Absolute(Program.c_str(), ExistsTempPath); + if (RealPath) { + Program = RealPath; } } - fextl::unique_ptr CreateUserOverrideLayer(const char* AppConfig) { - return fextl::make_unique(FEXCore::Config::LayerType::LAYER_USER_OVERRIDE, AppConfig); - } - - fextl::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type) { - return fextl::make_unique(Filename, Type); - } - - fextl::unique_ptr CreateEnvironmentLayer(char *const _envp[]) { - return fextl::make_unique(_envp); - } - - fextl::string RecoverGuestProgramFilename(fextl::string Program, bool ExecFDInterp, const std::string_view ProgramFDFromEnv) { - // If executed with a FEX FD then the Program argument might be empty. - // In this case we need to scan the FD node to recover the application binary that exists on disk. - // Only do this if the Program argument is empty, since we would prefer the application's expectation - // of application name. - if (!ProgramFDFromEnv.empty() && Program.empty()) { - // Get the `dev` node of the execveat fd string. - Program = "/dev/fd/"; - Program += ProgramFDFromEnv; - } - - // If we were provided a relative path then we need to canonicalize it to become absolute. - // If the program name isn't resolved to an absolute path then glibc breaks inside it's `_dl_get_origin` function. - // This is because we rewrite `/proc/self/exe` to the absolute program path calculated in here. - if (!Program.starts_with('/')) { - char ExistsTempPath[PATH_MAX]; - char *RealPath = FHU::Filesystem::Absolute(Program.c_str(), ExistsTempPath); - if (RealPath) { - Program = RealPath; - } - } - - // If FEX was invoked through an FD path (either binfmt_misc or execveat) then we need to check the - // Program to see if it is a symlink to find the real path. - // - // binfmt_misc: Arg[0] is actually the execve `pathname` argument or `/dev/fd/` path - // - `pathname` with execve (See Side Note) - // - FD path with execveat and FD doesn't have an existing file on the disk - // - // ProgramFDFromEnv: Arg[0] is Application provided data or `/dev/fd/` from above fix-up. - // - execveat was either passed no arguments (argv=NULL) or the first argument is an empty string (argv[0]=""). - // - FD path with execveat and FD doesn't have an existing file on the disk - // - // Side Note: - // The `execve` syscall doesn't take an FD but binfmt_misc will give FEX an FD to execute still. - // Arg[0] will always contain the `pathname` argument provided to execve. - // It does not resolve symlinks, and it does not convert the path to absolute. - // - // Examples: - // - Regular execve. Application must exist on disk. - // execve binfmt_misc args layout: `FEXInterpreter ...` - // - Regular execveat with FD. FD is backed by application on disk. - // execveat binfmt_misc args layout: `FEXInterpreter ...` - // - Regular execveat with FD. FD points to file on disk that has been deleted. - // execveat binfmt_misc args layout: `FEXInterpreter /dev/fd/ ...` + // If FEX was invoked through an FD path (either binfmt_misc or execveat) then we need to check the + // Program to see if it is a symlink to find the real path. + // + // binfmt_misc: Arg[0] is actually the execve `pathname` argument or `/dev/fd/` path + // - `pathname` with execve (See Side Note) + // - FD path with execveat and FD doesn't have an existing file on the disk + // + // ProgramFDFromEnv: Arg[0] is Application provided data or `/dev/fd/` from above fix-up. + // - execveat was either passed no arguments (argv=NULL) or the first argument is an empty string (argv[0]=""). + // - FD path with execveat and FD doesn't have an existing file on the disk + // + // Side Note: + // The `execve` syscall doesn't take an FD but binfmt_misc will give FEX an FD to execute still. + // Arg[0] will always contain the `pathname` argument provided to execve. + // It does not resolve symlinks, and it does not convert the path to absolute. + // + // Examples: + // - Regular execve. Application must exist on disk. + // execve binfmt_misc args layout: `FEXInterpreter ...` + // - Regular execveat with FD. FD is backed by application on disk. + // execveat binfmt_misc args layout: `FEXInterpreter ...` + // - Regular execveat with FD. FD points to file on disk that has been deleted. + // execveat binfmt_misc args layout: `FEXInterpreter /dev/fd/ ...` #ifndef _WIN32 - if (ExecFDInterp || !ProgramFDFromEnv.empty()) { - // Only in the case that FEX is executing an FD will the program argument potentially be a symlink. - // This symlink will be in the style of `/dev/fd/`. - // - // If the argument /is/ a symlink then resolve its path to get the original application name. - if (FHU::Symlinks::IsSymlink(Program)) { - char Filename[PATH_MAX]; - auto SymlinkPath = FHU::Symlinks::ResolveSymlink(Program, Filename); - if (SymlinkPath.starts_with('/')) { - // This file was executed through an FD. - // Remove the ` (deleted)` text if the file was deleted after the fact. - // Otherwise just get the symlink without the deleted text. - return fextl::string{SymlinkPath.substr(0, SymlinkPath.rfind(" (deleted)"))}; - } + if (ExecFDInterp || !ProgramFDFromEnv.empty()) { + // Only in the case that FEX is executing an FD will the program argument potentially be a symlink. + // This symlink will be in the style of `/dev/fd/`. + // + // If the argument /is/ a symlink then resolve its path to get the original application name. + if (FHU::Symlinks::IsSymlink(Program)) { + char Filename[PATH_MAX]; + auto SymlinkPath = FHU::Symlinks::ResolveSymlink(Program, Filename); + if (SymlinkPath.starts_with('/')) { + // This file was executed through an FD. + // Remove the ` (deleted)` text if the file was deleted after the fact. + // Otherwise just get the symlink without the deleted text. + return fextl::string {SymlinkPath.substr(0, SymlinkPath.rfind(" (deleted)"))}; } } + } #endif - return Program; + return Program; +} + +ApplicationNames LoadConfig(bool NoFEXArguments, bool LoadProgramConfig, int argc, char** argv, char** const envp, bool ExecFDInterp, + const std::string_view ProgramFDFromEnv) { + FEX::Config::InitializeConfigs(); + FEXCore::Config::Initialize(); + FEXCore::Config::AddLayer(CreateGlobalMainLayer()); + FEXCore::Config::AddLayer(CreateMainLayer()); + + if (NoFEXArguments) { + FEX::ArgLoader::LoadWithoutArguments(argc, argv); + } else { + FEXCore::Config::AddLayer(fextl::make_unique(argc, argv)); } - ApplicationNames LoadConfig( - bool NoFEXArguments, - bool LoadProgramConfig, - int argc, - char **argv, - char **const envp, - bool ExecFDInterp, - const std::string_view ProgramFDFromEnv) { - FEX::Config::InitializeConfigs(); - FEXCore::Config::Initialize(); - FEXCore::Config::AddLayer(CreateGlobalMainLayer()); - FEXCore::Config::AddLayer(CreateMainLayer()); + const char* AppConfig = getenv("FEX_APP_CONFIG"); + if (AppConfig && FHU::Filesystem::Exists(AppConfig)) { + FEXCore::Config::AddLayer(CreateUserOverrideLayer(AppConfig)); + } - if (NoFEXArguments) { - FEX::ArgLoader::LoadWithoutArguments(argc, argv); - } - else { - FEXCore::Config::AddLayer(fextl::make_unique(argc, argv)); + FEXCore::Config::AddLayer(CreateEnvironmentLayer(envp)); + FEXCore::Config::Load(); + + auto Args = FEX::ArgLoader::Get(); + + if (LoadProgramConfig) { + if (Args.empty()) { + // Early exit if we weren't passed an argument + return {}; } - const char *AppConfig = getenv("FEX_APP_CONFIG"); - if (AppConfig && FHU::Filesystem::Exists(AppConfig)) { - FEXCore::Config::AddLayer(CreateUserOverrideLayer(AppConfig)); - } + Args[0] = RecoverGuestProgramFilename(std::move(Args[0]), ExecFDInterp, ProgramFDFromEnv); + fextl::string& Program = Args[0]; - FEXCore::Config::AddLayer(CreateEnvironmentLayer(envp)); - FEXCore::Config::Load(); + bool Wine = false; + fextl::string ProgramName; + for (size_t CurrentProgramNameIndex = 0; CurrentProgramNameIndex < Args.size(); ++CurrentProgramNameIndex) { + auto CurrentProgramName = FHU::Filesystem::GetFilename(Args[CurrentProgramNameIndex]); - auto Args = FEX::ArgLoader::Get(); - - if (LoadProgramConfig) { - if (Args.empty()) { - // Early exit if we weren't passed an argument - return {}; - } - - Args[0] = RecoverGuestProgramFilename(std::move(Args[0]), ExecFDInterp, ProgramFDFromEnv); - fextl::string& Program = Args[0]; - - bool Wine = false; - fextl::string ProgramName; - for (size_t CurrentProgramNameIndex = 0; CurrentProgramNameIndex < Args.size(); ++CurrentProgramNameIndex) { - auto CurrentProgramName = FHU::Filesystem::GetFilename(Args[CurrentProgramNameIndex]); - - if (CurrentProgramName == "wine-preloader" || - CurrentProgramName == "wine64-preloader") { - // Wine preloader is required to be in the format of `wine-preloader ` - // The preloader doesn't execve the executable, instead maps it directly itself - // Skip the next argument since we know it is wine (potentially with custom wine executable name) - ++CurrentProgramNameIndex; - Wine = true; - } - else if(CurrentProgramName == "wine" || - CurrentProgramName == "wine64") { - // Next argument, this isn't the program we want - // - // If we are running wine or wine64 then we should check the next argument for the application name instead. - // wine will change the active program name with `setprogname` or `prctl(PR_SET_NAME`. - // Since FEX needs this data far earlier than libraries we need a different check. - Wine = true; - } - else { - if (Wine == true) { - // If this was path separated with '\' then we need to check that. - auto WinSeparator = CurrentProgramName.find_last_of('\\'); - if (WinSeparator != CurrentProgramName.npos) { - // Used windows separators - CurrentProgramName = CurrentProgramName.substr(WinSeparator + 1); - } + if (CurrentProgramName == "wine-preloader" || CurrentProgramName == "wine64-preloader") { + // Wine preloader is required to be in the format of `wine-preloader ` + // The preloader doesn't execve the executable, instead maps it directly itself + // Skip the next argument since we know it is wine (potentially with custom wine executable name) + ++CurrentProgramNameIndex; + Wine = true; + } else if (CurrentProgramName == "wine" || CurrentProgramName == "wine64") { + // Next argument, this isn't the program we want + // + // If we are running wine or wine64 then we should check the next argument for the application name instead. + // wine will change the active program name with `setprogname` or `prctl(PR_SET_NAME`. + // Since FEX needs this data far earlier than libraries we need a different check. + Wine = true; + } else { + if (Wine == true) { + // If this was path separated with '\' then we need to check that. + auto WinSeparator = CurrentProgramName.find_last_of('\\'); + if (WinSeparator != CurrentProgramName.npos) { + // Used windows separators + CurrentProgramName = CurrentProgramName.substr(WinSeparator + 1); } - - ProgramName = CurrentProgramName; - - // Past any wine program names - break; } + + ProgramName = CurrentProgramName; + + // Past any wine program names + break; } - - FEXCore::Config::AddLayer(CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_GLOBAL_APP)); - FEXCore::Config::AddLayer(CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_LOCAL_APP)); - - auto SteamID = getenv("SteamAppId"); - if (SteamID) { - // If a SteamID exists then let's search for Steam application configs as well. - // We want to key off both the SteamAppId number /and/ the executable since we may not want to thunk all binaries. - fextl::string SteamAppName = fextl::fmt::format("Steam_{}_{}", SteamID, ProgramName); - FEXCore::Config::AddLayer(CreateAppLayer(SteamAppName, FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP)); - FEXCore::Config::AddLayer(CreateAppLayer(SteamAppName, FEXCore::Config::LayerType::LAYER_LOCAL_STEAM_APP)); - } - - return ApplicationNames{std::move(Program), std::move(ProgramName)}; } - return {}; + + FEXCore::Config::AddLayer(CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_GLOBAL_APP)); + FEXCore::Config::AddLayer(CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_LOCAL_APP)); + + auto SteamID = getenv("SteamAppId"); + if (SteamID) { + // If a SteamID exists then let's search for Steam application configs as well. + // We want to key off both the SteamAppId number /and/ the executable since we may not want to thunk all binaries. + fextl::string SteamAppName = fextl::fmt::format("Steam_{}_{}", SteamID, ProgramName); + FEXCore::Config::AddLayer(CreateAppLayer(SteamAppName, FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP)); + FEXCore::Config::AddLayer(CreateAppLayer(SteamAppName, FEXCore::Config::LayerType::LAYER_LOCAL_STEAM_APP)); + } + + return ApplicationNames {std::move(Program), std::move(ProgramName)}; } + return {}; +} #ifndef _WIN32 - char const* FindUserHomeThroughUID() { - auto passwd = getpwuid(geteuid()); - if (passwd) { - return passwd->pw_dir; - } +const char* FindUserHomeThroughUID() { + auto passwd = getpwuid(geteuid()); + if (passwd) { + return passwd->pw_dir; + } + return nullptr; +} + +const char* GetHomeDirectory() { + const char* HomeDir = getenv("HOME"); + + // Try to get home directory from uid + if (!HomeDir) { + HomeDir = FindUserHomeThroughUID(); + } + + // try the PWD + if (!HomeDir) { + HomeDir = getenv("PWD"); + } + + // Still doesn't exit? You get local + if (!HomeDir) { + HomeDir = "."; + } + + return HomeDir; +} +#else +const char* GetHomeDirectory() { + const char* HomeObjectPath = getenv("WINEHOMEDIR"); + if (!HomeObjectPath) { return nullptr; } - const char *GetHomeDirectory() { - char const *HomeDir = getenv("HOME"); - - // Try to get home directory from uid - if (!HomeDir) { - HomeDir = FindUserHomeThroughUID(); - } - - // try the PWD - if (!HomeDir) { - HomeDir = getenv("PWD"); - } - - // Still doesn't exit? You get local - if (!HomeDir) { - HomeDir = "."; - } - - return HomeDir; - } -#else - const char *GetHomeDirectory() { - const char *HomeObjectPath = getenv("WINEHOMEDIR"); - if (!HomeObjectPath) { - return nullptr; - } - - // Skip over the \??\ prefix in the NT path since we want a DOS path - return HomeObjectPath + 4; - } + // Skip over the \??\ prefix in the NT path since we want a DOS path + return HomeObjectPath + 4; +} #endif - fextl::string GetDataDirectory() { - fextl::string DataDir{}; +fextl::string GetDataDirectory() { + fextl::string DataDir {}; - char const *HomeDir = GetHomeDirectory(); - char const *DataXDG = getenv("XDG_DATA_HOME"); - char const *DataOverride = getenv("FEX_APP_DATA_LOCATION"); - if (DataOverride) { - // Data override will override the complete directory - DataDir = DataOverride; - } - else { - DataDir = DataXDG ?: HomeDir; - DataDir += "/.fex-emu/"; - } - return DataDir; - } - - fextl::string GetConfigDirectory(bool Global) { - fextl::string ConfigDir; - if (Global) { - ConfigDir = GLOBAL_DATA_DIRECTORY; - } - else { - char const *HomeDir = GetHomeDirectory(); - char const *ConfigXDG = getenv("XDG_CONFIG_HOME"); - char const *ConfigOverride = getenv("FEX_APP_CONFIG_LOCATION"); - if (ConfigOverride) { - // Config override completely overrides the config directory - ConfigDir = ConfigOverride; - } - else { - ConfigDir = ConfigXDG ? ConfigXDG : HomeDir; - ConfigDir += "/.fex-emu/"; - } - - // Ensure the folder structure is created for our configuration - if (!FHU::Filesystem::Exists(ConfigDir) && - !FHU::Filesystem::CreateDirectories(ConfigDir)) { - // Let's go local in this case - return "./"; - } - } - - return ConfigDir; - } - - fextl::string GetConfigFileLocation(bool Global) { - return GetConfigDirectory(Global) + "Config.json"; - } - - void InitializeConfigs() { - FEXCore::Config::SetDataDirectory(GetDataDirectory()); - FEXCore::Config::SetConfigDirectory(GetConfigDirectory(false), false); - FEXCore::Config::SetConfigDirectory(GetConfigDirectory(true), true); - FEXCore::Config::SetConfigFileLocation(GetConfigFileLocation(false), false); - FEXCore::Config::SetConfigFileLocation(GetConfigFileLocation(true), true); + const char* HomeDir = GetHomeDirectory(); + const char* DataXDG = getenv("XDG_DATA_HOME"); + const char* DataOverride = getenv("FEX_APP_DATA_LOCATION"); + if (DataOverride) { + // Data override will override the complete directory + DataDir = DataOverride; + } else { + DataDir = DataXDG ?: HomeDir; + DataDir += "/.fex-emu/"; } + return DataDir; } + +fextl::string GetConfigDirectory(bool Global) { + fextl::string ConfigDir; + if (Global) { + ConfigDir = GLOBAL_DATA_DIRECTORY; + } else { + const char* HomeDir = GetHomeDirectory(); + const char* ConfigXDG = getenv("XDG_CONFIG_HOME"); + const char* ConfigOverride = getenv("FEX_APP_CONFIG_LOCATION"); + if (ConfigOverride) { + // Config override completely overrides the config directory + ConfigDir = ConfigOverride; + } else { + ConfigDir = ConfigXDG ? ConfigXDG : HomeDir; + ConfigDir += "/.fex-emu/"; + } + + // Ensure the folder structure is created for our configuration + if (!FHU::Filesystem::Exists(ConfigDir) && !FHU::Filesystem::CreateDirectories(ConfigDir)) { + // Let's go local in this case + return "./"; + } + } + + return ConfigDir; +} + +fextl::string GetConfigFileLocation(bool Global) { + return GetConfigDirectory(Global) + "Config.json"; +} + +void InitializeConfigs() { + FEXCore::Config::SetDataDirectory(GetDataDirectory()); + FEXCore::Config::SetConfigDirectory(GetConfigDirectory(false), false); + FEXCore::Config::SetConfigDirectory(GetConfigDirectory(true), true); + FEXCore::Config::SetConfigFileLocation(GetConfigFileLocation(false), false); + FEXCore::Config::SetConfigFileLocation(GetConfigFileLocation(true), true); +} +} // namespace FEX::Config diff --git a/Source/Common/Config.h b/Source/Common/Config.h index 5e7bbeb04..69cfd4296 100644 --- a/Source/Common/Config.h +++ b/Source/Common/Config.h @@ -7,90 +7,82 @@ * @brief This is a singleton for storing global configuration state */ namespace FEX::Config { - class EmptyMapper : public FEXCore::Config::Layer { - public: - explicit EmptyMapper() - : FEXCore::Config::Layer(FEXCore::Config::LayerType::LAYER_MAIN) { - } - void Load() override {} +class EmptyMapper : public FEXCore::Config::Layer { +public: + explicit EmptyMapper() + : FEXCore::Config::Layer(FEXCore::Config::LayerType::LAYER_MAIN) {} + void Load() override {} - protected: - }; +protected: +}; - void SaveLayerToJSON(const fextl::string& Filename, FEXCore::Config::Layer *const Layer); +void SaveLayerToJSON(const fextl::string& Filename, FEXCore::Config::Layer* const Layer); - struct ApplicationNames { - // This is the full path to the program (if it exists). - fextl::string ProgramPath; - // This is the program executable name (if it exists). - fextl::string ProgramName; - }; +struct ApplicationNames { + // This is the full path to the program (if it exists). + fextl::string ProgramPath; + // This is the program executable name (if it exists). + fextl::string ProgramName; +}; - /** - * @brief Loads the FEX and application configurations for the application that is getting ready to run. - * - * @param NoFEXArguments Do we want to parse FEXLoader arguments, Or is this FEXInterpreter? - * @param LoadProgramConfig Do we want to load application specific configurations? - * @param argc The `argc` passed to main(...) - * @param argv The `argv` passed to main(...) - * @param envp The `envp` passed to main(...) - * @param ExecFDInterp If FEX was executed with binfmt_misc FD argument - * @param ProgramFDFromEnv The execveat FD argument passed through FEX - * - * @return The application name and path structure - */ - ApplicationNames LoadConfig( - bool NoFEXArguments, - bool LoadProgramConfig, - int argc, - char **argv, - char **const envp, - bool ExecFDInterp, - const std::string_view ProgramFDFromEnv - ); +/** + * @brief Loads the FEX and application configurations for the application that is getting ready to run. + * + * @param NoFEXArguments Do we want to parse FEXLoader arguments, Or is this FEXInterpreter? + * @param LoadProgramConfig Do we want to load application specific configurations? + * @param argc The `argc` passed to main(...) + * @param argv The `argv` passed to main(...) + * @param envp The `envp` passed to main(...) + * @param ExecFDInterp If FEX was executed with binfmt_misc FD argument + * @param ProgramFDFromEnv The execveat FD argument passed through FEX + * + * @return The application name and path structure + */ +ApplicationNames LoadConfig(bool NoFEXArguments, bool LoadProgramConfig, int argc, char** argv, char** const envp, bool ExecFDInterp, + const std::string_view ProgramFDFromEnv); - const char *GetHomeDirectory(); +const char* GetHomeDirectory(); - fextl::string GetDataDirectory(); - fextl::string GetConfigDirectory(bool Global); - fextl::string GetConfigFileLocation(bool Global); +fextl::string GetDataDirectory(); +fextl::string GetConfigDirectory(bool Global); +fextl::string GetConfigFileLocation(bool Global); - void InitializeConfigs(); +void InitializeConfigs(); - /** - * @brief Loads the global FEX config - * - * @return unique_ptr for that layer - */ - fextl::unique_ptr CreateGlobalMainLayer(); +/** + * @brief Loads the global FEX config + * + * @return unique_ptr for that layer + */ +fextl::unique_ptr CreateGlobalMainLayer(); - /** - * @brief Loads the main application config - * - * @param File Optional override to load a specific config file in to the main layer - * Shouldn't be commonly used - * - * @return unique_ptr for that layer - */ - fextl::unique_ptr CreateMainLayer(fextl::string const *File = nullptr); - fextl::unique_ptr CreateUserOverrideLayer(const char* AppConfig); +/** + * @brief Loads the main application config + * + * @param File Optional override to load a specific config file in to the main layer + * Shouldn't be commonly used + * + * @return unique_ptr for that layer + */ +fextl::unique_ptr CreateMainLayer(const fextl::string* File = nullptr); +fextl::unique_ptr CreateUserOverrideLayer(const char* AppConfig); - /** - * @brief Create an application configuration loader - * - * @param Filename Application filename component - * @param Global Load the global configuration or user accessible file - * - * @return unique_ptr for that layer - */ - fextl::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type); +/** + * @brief Create an application configuration loader + * + * @param Filename Application filename component + * @param Global Load the global configuration or user accessible file + * + * @return unique_ptr for that layer + */ +fextl::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type); - /** - * @brief iCreate an environment configuration loader - * - * @param _envp[] The environment array from main - * - * @return unique_ptr for that layer - */ - fextl::unique_ptr CreateEnvironmentLayer(char *const _envp[]); -} +/** + * @brief iCreate an environment configuration loader + * + * @param _envp[] The environment array from main + * + * @return unique_ptr for that layer + */ +fextl::unique_ptr CreateEnvironmentLayer(char* const _envp[]); +} // namespace FEX::Config diff --git a/Source/Common/EnvironmentLoader.cpp b/Source/Common/EnvironmentLoader.cpp index 2620b9074..e88e6100d 100644 --- a/Source/Common/EnvironmentLoader.cpp +++ b/Source/Common/EnvironmentLoader.cpp @@ -3,11 +3,9 @@ namespace FEX::EnvLoader { - using string = std::string; - using string_view = std::string_view; +using string = std::string; +using string_view = std::string_view; - void Load(char *const envp[]) - { - } +void Load(char* const envp[]) {} -} +} // namespace FEX::EnvLoader diff --git a/Source/Common/EnvironmentLoader.h b/Source/Common/EnvironmentLoader.h index 79b74da74..f926d2fae 100644 --- a/Source/Common/EnvironmentLoader.h +++ b/Source/Common/EnvironmentLoader.h @@ -3,6 +3,6 @@ namespace FEX::EnvLoader { - void Load(char *const envp[]); +void Load(char* const envp[]); } \ No newline at end of file diff --git a/Source/Common/FDUtils.h b/Source/Common/FDUtils.h index a4f66ff37..1477eee56 100644 --- a/Source/Common/FDUtils.h +++ b/Source/Common/FDUtils.h @@ -14,10 +14,9 @@ namespace FEX { -inline -int get_fdpath(int fd, char *SymlinkPath) { +inline int get_fdpath(int fd, char* SymlinkPath) { auto Path = fextl::fmt::format("/proc/self/fd/{}", fd); return readlinkat(AT_FDCWD, Path.c_str(), SymlinkPath, PATH_MAX); } -} +} // namespace FEX diff --git a/Source/Common/FEXServerClient.cpp b/Source/Common/FEXServerClient.cpp index 6717c9cc3..424ecf0a0 100644 --- a/Source/Common/FEXServerClient.cpp +++ b/Source/Common/FEXServerClient.cpp @@ -24,351 +24,341 @@ #include namespace FEXServerClient { - int RequestPIDFDPacket(int ServerSocket, PacketType Type) { - FEXServerRequestPacket Req { - .Header { - .Type = Type, - }, +int RequestPIDFDPacket(int ServerSocket, PacketType Type) { + FEXServerRequestPacket Req { + .Header { + .Type = Type, + }, + }; + + int Result = write(ServerSocket, &Req, sizeof(Req.BasicRequest)); + if (Result != -1) { + // Wait for success response with SCM_RIGHTS + + FEXServerResultPacket Res {}; + struct iovec iov { + .iov_base = &Res, .iov_len = sizeof(Res), }; - int Result = write(ServerSocket, &Req, sizeof(Req.BasicRequest)); - if (Result != -1) { - // Wait for success response with SCM_RIGHTS + struct msghdr msg { + .msg_name = nullptr, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1, + }; - FEXServerResultPacket Res{}; - struct iovec iov { - .iov_base = &Res, - .iov_len = sizeof(Res), - }; + // Setup the ancillary buffer. This is where we will be getting pipe FDs + // We only need 4 bytes for the FD + constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int)); + union AncillaryBuffer { + struct cmsghdr Header; + uint8_t Buffer[CMSG_SIZE]; + }; + AncillaryBuffer AncBuf {}; - struct msghdr msg { - .msg_name = nullptr, - .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, - }; + // Now link to our ancilllary buffer + msg.msg_control = AncBuf.Buffer; + msg.msg_controllen = CMSG_SIZE; - // Setup the ancillary buffer. This is where we will be getting pipe FDs - // We only need 4 bytes for the FD - constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int)); - union AncillaryBuffer { - struct cmsghdr Header; - uint8_t Buffer[CMSG_SIZE]; - }; - AncillaryBuffer AncBuf{}; + ssize_t DataResult = recvmsg(ServerSocket, &msg, 0); + if (DataResult > 0) { + // Now that we have the data, we can extract the FD from the ancillary buffer + struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); - // Now link to our ancilllary buffer - msg.msg_control = AncBuf.Buffer; - msg.msg_controllen = CMSG_SIZE; - - ssize_t DataResult = recvmsg(ServerSocket, &msg, 0); - if (DataResult > 0) { - // Now that we have the data, we can extract the FD from the ancillary buffer - struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); - - // Do some error checking - if (cmsg == nullptr || - cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || - cmsg->cmsg_level != SOL_SOCKET || - cmsg->cmsg_type != SCM_RIGHTS) { - // Couldn't get a socket - } - else { - // Check for Success. - // If type error was returned then the FEXServer doesn't have a log to pipe in to - if (Res.Header.Type == PacketType::TYPE_SUCCESS) { - // Now that we know the cmsg is sane, read the FD - int NewFD{}; - memcpy(&NewFD, CMSG_DATA(cmsg), sizeof(NewFD)); - return NewFD; - } + // Do some error checking + if (cmsg == nullptr || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + // Couldn't get a socket + } else { + // Check for Success. + // If type error was returned then the FEXServer doesn't have a log to pipe in to + if (Res.Header.Type == PacketType::TYPE_SUCCESS) { + // Now that we know the cmsg is sane, read the FD + int NewFD {}; + memcpy(&NewFD, CMSG_DATA(cmsg), sizeof(NewFD)); + return NewFD; } } } + } + return -1; +} + +static int ServerFD {-1}; + +fextl::string GetServerLockFolder() { + return FEXCore::Config::GetDataDirectory() + "Server/"; +} + +fextl::string GetServerLockFile() { + return GetServerLockFolder() + "Server.lock"; +} + +fextl::string GetServerRootFSLockFile() { + return GetServerLockFolder() + "RootFS.lock"; +} + +fextl::string GetTempFolder() { + auto XDGRuntimeEnv = getenv("XDG_RUNTIME_DIR"); + if (XDGRuntimeEnv) { + // If the XDG runtime directory works then use that. + return XDGRuntimeEnv; + } + // Fallback to `/tmp/` if XDG_RUNTIME_DIR doesn't exist. + // Might not be ideal but we don't have much of a choice. + return fextl::string {std::filesystem::temp_directory_path().string()}; +} + +fextl::string GetServerMountFolder() { + // We need a FEXServer mount directory that has some tricky requirements. + // - We don't want to use `/tmp/` if possible. + // - systemd services use `PrivateTmp` feature to gives services their own tmp. + // - We will use this as a fallback path /only/. + // - Can't be `[$XDG_DATA_HOME,$HOME]/.fex-emu/` + // - Might be mounted with a filesystem (sshfs) which can't handle mount points inside it. + // + // Directories it can be in: + // - $XDG_RUNTIME_DIR if set + // - Is typically `/run/user//` + // - systemd `PrivateTmp` feature doesn't touch this. + // - If this path doesn't exist then fallback to `/tmp/` as a last resort. + // - pressure-vessel explicitly creates an internal XDG_RUNTIME_DIR inside its chroot. + // - This is okay since pressure-vessel rbinds the FEX rootfs from the host to `/run/pressure-vessel/interpreter-root`. + auto Folder = GetTempFolder(); + + if (FEXCore::Config::FindContainer() == "pressure-vessel") { + // In pressure-vessel the mount point changes location. + // This is due to pressure-vesssel being a chroot environment. + // It by default maps the host-filesystem to `/run/host/` so we need to redirect. + // After pressure-vessel is fully set up it will set the `FEX_ROOTFS` environment variable, + // which the FEXInterpreter will pick up on. + Folder = "/run/host/" + Folder; + } + + return Folder; +} + +fextl::string GetServerSocketName() { + FEX_CONFIG_OPT(ServerSocketPath, SERVERSOCKETPATH); + if (ServerSocketPath().empty()) { + return fextl::fmt::format("{}.FEXServer.Socket", ::geteuid()); + } + return ServerSocketPath; +} + +int GetServerFD() { + return ServerFD; +} + +int ConnectToServer(ConnectionOption ConnectionOption) { + auto ServerSocketName = GetServerSocketName(); + + // Create the initial unix socket + int SocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (SocketFD == -1) { + LogMan::Msg::EFmt("Couldn't open AF_UNIX socket {} {}", errno, strerror(errno)); return -1; } - static int ServerFD {-1}; + // AF_UNIX has a special feature for named socket paths. + // If the name of the socket begins with `\0` then it is an "abstract" socket address. + // The entirety of the name is used as a path to a socket that doesn't have any filesystem backing. + struct sockaddr_un addr {}; + addr.sun_family = AF_UNIX; + size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1); + addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0 + strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString); + // Include final null character. + size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString; - fextl::string GetServerLockFolder() { - return FEXCore::Config::GetDataDirectory() + "Server/"; - } - - fextl::string GetServerLockFile() { - return GetServerLockFolder() + "Server.lock"; - } - - fextl::string GetServerRootFSLockFile() { - return GetServerLockFolder() + "RootFS.lock"; - } - - fextl::string GetTempFolder() { - auto XDGRuntimeEnv = getenv("XDG_RUNTIME_DIR"); - if (XDGRuntimeEnv) { - // If the XDG runtime directory works then use that. - return XDGRuntimeEnv; + if (connect(SocketFD, reinterpret_cast(&addr), SizeOfAddr) == -1) { + if (ConnectionOption == ConnectionOption::Default || errno != ECONNREFUSED) { + LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {} {}", ServerSocketName, errno, strerror(errno)); } - // Fallback to `/tmp/` if XDG_RUNTIME_DIR doesn't exist. - // Might not be ideal but we don't have much of a choice. - return fextl::string{std::filesystem::temp_directory_path().string()}; + close(SocketFD); + return -1; } - fextl::string GetServerMountFolder() { - // We need a FEXServer mount directory that has some tricky requirements. - // - We don't want to use `/tmp/` if possible. - // - systemd services use `PrivateTmp` feature to gives services their own tmp. - // - We will use this as a fallback path /only/. - // - Can't be `[$XDG_DATA_HOME,$HOME]/.fex-emu/` - // - Might be mounted with a filesystem (sshfs) which can't handle mount points inside it. - // - // Directories it can be in: - // - $XDG_RUNTIME_DIR if set - // - Is typically `/run/user//` - // - systemd `PrivateTmp` feature doesn't touch this. - // - If this path doesn't exist then fallback to `/tmp/` as a last resort. - // - pressure-vessel explicitly creates an internal XDG_RUNTIME_DIR inside its chroot. - // - This is okay since pressure-vessel rbinds the FEX rootfs from the host to `/run/pressure-vessel/interpreter-root`. - auto Folder = GetTempFolder(); - - if (FEXCore::Config::FindContainer() == "pressure-vessel") { - // In pressure-vessel the mount point changes location. - // This is due to pressure-vesssel being a chroot environment. - // It by default maps the host-filesystem to `/run/host/` so we need to redirect. - // After pressure-vessel is fully set up it will set the `FEX_ROOTFS` environment variable, - // which the FEXInterpreter will pick up on. - Folder = "/run/host/" + Folder; - } - - return Folder; - } - - fextl::string GetServerSocketName() { - FEX_CONFIG_OPT(ServerSocketPath, SERVERSOCKETPATH); - if (ServerSocketPath().empty()) { - return fextl::fmt::format("{}.FEXServer.Socket", ::geteuid()); - } - return ServerSocketPath; - } - - int GetServerFD() { - return ServerFD; - } - - int ConnectToServer(ConnectionOption ConnectionOption) { - auto ServerSocketName = GetServerSocketName(); - - // Create the initial unix socket - int SocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (SocketFD == -1) { - LogMan::Msg::EFmt("Couldn't open AF_UNIX socket {} {}", errno, strerror(errno)); - return -1; - } - - // AF_UNIX has a special feature for named socket paths. - // If the name of the socket begins with `\0` then it is an "abstract" socket address. - // The entirety of the name is used as a path to a socket that doesn't have any filesystem backing. - struct sockaddr_un addr{}; - addr.sun_family = AF_UNIX; - size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1); - addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0 - strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString); - // Include final null character. - size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString; - - if (connect(SocketFD, reinterpret_cast(&addr), SizeOfAddr) == -1) { - if (ConnectionOption == ConnectionOption::Default || errno != ECONNREFUSED) { - LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {} {}", ServerSocketName, errno, strerror(errno)); - } - close(SocketFD); - return -1; - } - - return SocketFD; - } - - bool SetupClient(char *InterpreterPath) { - ServerFD = FEXServerClient::ConnectToAndStartServer(InterpreterPath); - if (ServerFD == -1) { - return false; - } - - // If we were started in a container then we want to use the rootfs that they provided. - // In the pressure-vessel case this is a combination of our rootfs and the steam soldier runtime. - if (FEXCore::Config::FindContainer() != "pressure-vessel") { - fextl::string RootFSPath = FEXServerClient::RequestRootFSPath(ServerFD); - - //// If everything has passed then we can now update the rootfs path - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, RootFSPath); - } - - return true; - } - - int ConnectToAndStartServer(char *InterpreterPath) { - int ServerFD = ConnectToServer(ConnectionOption::NoPrintConnectionError); - if (ServerFD == -1) { - // Couldn't connect to the server. Start one - - // Open some pipes for letting us know when the server is ready - int fds[2]{}; - if (pipe2(fds, 0) != 0) { - LogMan::Msg::EFmt("Couldn't open pipe"); - return -1; - } - - fextl::string FEXServerPath = FHU::Filesystem::ParentPath(InterpreterPath) + "/FEXServer"; - // Check if a local FEXServer next to FEXInterpreter exists - // If it does then it takes priority over the installed one - if (!FHU::Filesystem::Exists(FEXServerPath)) { - FEXServerPath = "FEXServer"; - } - - // Set-up our SIGCHLD handler to ignore the signal. - // This is early in the initialization stage so no handlers have been installed. - // - // We want to ignore the signal so that if FEXServer starts in daemon mode, it - // doesn't leave a zombie process around waiting for something to get the result. - struct sigaction action{}; - action.sa_handler = SIG_IGN, - sigaction(SIGCHLD, &action, &action); - - pid_t pid = fork(); - if (pid == 0) { - // Child - close(fds[0]); // Close read end of pipe - - const char *argv[2]; - - argv[0] = FEXServerPath.c_str(); - argv[1] = nullptr; - - if (execvp(argv[0], (char * const*)argv) == -1) { - // Let the parent know that we couldn't execute for some reason - uint64_t error{1}; - write(fds[1], &error, sizeof(error)); - - // Give a hopefully helpful error message for users - LogMan::Msg::EFmt("Couldn't execute: {}", argv[0]); - LogMan::Msg::EFmt("This means the squashFS rootfs won't be mounted."); - LogMan::Msg::EFmt("Expect errors!"); - // Destroy this fork - exit(1); - } - - FEX_UNREACHABLE; - } - else { - // Parent - // Wait for the child to exit so we can check if it is mounted or not - close(fds[1]); // Close write end of the pipe - - // Wait for a message from FEXServer - pollfd PollFD; - PollFD.fd = fds[0]; - PollFD.events = POLLIN | POLLOUT | POLLRDHUP | POLLERR | POLLHUP | POLLNVAL; - - // Wait for a result on the pipe that isn't EINTR - while (poll(&PollFD, 1, -1) == -1 && errno == EINTR); - - for (size_t i = 0; i < 5; ++i) { - ServerFD = ConnectToServer(ConnectionOption::Default); - - if (ServerFD != -1) { - break; - } - - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - if (ServerFD == -1) { - // Still couldn't connect to the socket. - LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} after launching the process", GetServerSocketName()); - } - } - - // Restore the original SIGCHLD handler if it existed. - sigaction(SIGCHLD, &action, nullptr); - } - return ServerFD; - } - - /** - * @name Packet request functions - * @{ */ - void RequestServerKill(int ServerSocket) { - FEXServerRequestPacket Req { - .Header { - .Type = PacketType::TYPE_KILL, - }, - }; - - write(ServerSocket, &Req, sizeof(Req.BasicRequest)); - } - - int RequestLogFD(int ServerSocket) { - return RequestPIDFDPacket(ServerSocket, PacketType::TYPE_GET_LOG_FD); - } - - fextl::string RequestRootFSPath(int ServerSocket) { - FEXServerRequestPacket Req { - .Header { - .Type = PacketType::TYPE_GET_ROOTFS_PATH, - }, - }; - - int Result = write(ServerSocket, &Req, sizeof(Req.BasicRequest)); - if (Result != -1) { - // Wait for success response with data - fextl::vector Data(PATH_MAX + sizeof(FEXServerResultPacket)); - - ssize_t DataResult = recv(ServerSocket, Data.data(), Data.size(), 0); - if (DataResult >= sizeof(FEXServerResultPacket)) { - FEXServerResultPacket *ResultPacket = reinterpret_cast(Data.data()); - if (ResultPacket->Header.Type == PacketType::TYPE_GET_ROOTFS_PATH && - ResultPacket->MountPath.Length > 0) { - return fextl::string(ResultPacket->MountPath.Mount); - } - } - } - - return {}; - } - - int RequestPIDFD(int ServerSocket) { - return RequestPIDFDPacket(ServerSocket, PacketType::TYPE_GET_PID_FD); - } - - /** @} */ - - /** - * @name FEX logging through FEXServer - * @{ */ - - void MsgHandler(int FD, LogMan::DebugLevels Level, char const *Message) { - size_t MsgLen = strlen(Message) + 1; - - Logging::PacketMsg Msg; - Msg.Header = Logging::FillHeader(Logging::PacketTypes::TYPE_MSG); - Msg.MessageLength = MsgLen; - Msg.Level = Level; - - const iovec vec[2] = { - { - .iov_base = &Msg, - .iov_len = sizeof(Msg), - }, - { - .iov_base = const_cast(Message), - .iov_len = Msg.MessageLength, - }, - }; - - writev(FD, vec, 2); - } - - void AssertHandler(int FD, char const *Message) { - MsgHandler(FD, LogMan::DebugLevels::ASSERT, Message); - } - /** @} */ + return SocketFD; } + +bool SetupClient(char* InterpreterPath) { + ServerFD = FEXServerClient::ConnectToAndStartServer(InterpreterPath); + if (ServerFD == -1) { + return false; + } + + // If we were started in a container then we want to use the rootfs that they provided. + // In the pressure-vessel case this is a combination of our rootfs and the steam soldier runtime. + if (FEXCore::Config::FindContainer() != "pressure-vessel") { + fextl::string RootFSPath = FEXServerClient::RequestRootFSPath(ServerFD); + + //// If everything has passed then we can now update the rootfs path + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, RootFSPath); + } + + return true; +} + +int ConnectToAndStartServer(char* InterpreterPath) { + int ServerFD = ConnectToServer(ConnectionOption::NoPrintConnectionError); + if (ServerFD == -1) { + // Couldn't connect to the server. Start one + + // Open some pipes for letting us know when the server is ready + int fds[2] {}; + if (pipe2(fds, 0) != 0) { + LogMan::Msg::EFmt("Couldn't open pipe"); + return -1; + } + + fextl::string FEXServerPath = FHU::Filesystem::ParentPath(InterpreterPath) + "/FEXServer"; + // Check if a local FEXServer next to FEXInterpreter exists + // If it does then it takes priority over the installed one + if (!FHU::Filesystem::Exists(FEXServerPath)) { + FEXServerPath = "FEXServer"; + } + + // Set-up our SIGCHLD handler to ignore the signal. + // This is early in the initialization stage so no handlers have been installed. + // + // We want to ignore the signal so that if FEXServer starts in daemon mode, it + // doesn't leave a zombie process around waiting for something to get the result. + struct sigaction action {}; + action.sa_handler = SIG_IGN, sigaction(SIGCHLD, &action, &action); + + pid_t pid = fork(); + if (pid == 0) { + // Child + close(fds[0]); // Close read end of pipe + + const char* argv[2]; + + argv[0] = FEXServerPath.c_str(); + argv[1] = nullptr; + + if (execvp(argv[0], (char* const*)argv) == -1) { + // Let the parent know that we couldn't execute for some reason + uint64_t error {1}; + write(fds[1], &error, sizeof(error)); + + // Give a hopefully helpful error message for users + LogMan::Msg::EFmt("Couldn't execute: {}", argv[0]); + LogMan::Msg::EFmt("This means the squashFS rootfs won't be mounted."); + LogMan::Msg::EFmt("Expect errors!"); + // Destroy this fork + exit(1); + } + + FEX_UNREACHABLE; + } else { + // Parent + // Wait for the child to exit so we can check if it is mounted or not + close(fds[1]); // Close write end of the pipe + + // Wait for a message from FEXServer + pollfd PollFD; + PollFD.fd = fds[0]; + PollFD.events = POLLIN | POLLOUT | POLLRDHUP | POLLERR | POLLHUP | POLLNVAL; + + // Wait for a result on the pipe that isn't EINTR + while (poll(&PollFD, 1, -1) == -1 && errno == EINTR) + ; + + for (size_t i = 0; i < 5; ++i) { + ServerFD = ConnectToServer(ConnectionOption::Default); + + if (ServerFD != -1) { + break; + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + if (ServerFD == -1) { + // Still couldn't connect to the socket. + LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} after launching the process", GetServerSocketName()); + } + } + + // Restore the original SIGCHLD handler if it existed. + sigaction(SIGCHLD, &action, nullptr); + } + return ServerFD; +} + +/** + * @name Packet request functions + * @{ */ +void RequestServerKill(int ServerSocket) { + FEXServerRequestPacket Req { + .Header { + .Type = PacketType::TYPE_KILL, + }, + }; + + write(ServerSocket, &Req, sizeof(Req.BasicRequest)); +} + +int RequestLogFD(int ServerSocket) { + return RequestPIDFDPacket(ServerSocket, PacketType::TYPE_GET_LOG_FD); +} + +fextl::string RequestRootFSPath(int ServerSocket) { + FEXServerRequestPacket Req { + .Header { + .Type = PacketType::TYPE_GET_ROOTFS_PATH, + }, + }; + + int Result = write(ServerSocket, &Req, sizeof(Req.BasicRequest)); + if (Result != -1) { + // Wait for success response with data + fextl::vector Data(PATH_MAX + sizeof(FEXServerResultPacket)); + + ssize_t DataResult = recv(ServerSocket, Data.data(), Data.size(), 0); + if (DataResult >= sizeof(FEXServerResultPacket)) { + FEXServerResultPacket* ResultPacket = reinterpret_cast(Data.data()); + if (ResultPacket->Header.Type == PacketType::TYPE_GET_ROOTFS_PATH && ResultPacket->MountPath.Length > 0) { + return fextl::string(ResultPacket->MountPath.Mount); + } + } + } + + return {}; +} + +int RequestPIDFD(int ServerSocket) { + return RequestPIDFDPacket(ServerSocket, PacketType::TYPE_GET_PID_FD); +} + +/** @} */ + +/** + * @name FEX logging through FEXServer + * @{ */ + +void MsgHandler(int FD, LogMan::DebugLevels Level, const char* Message) { + size_t MsgLen = strlen(Message) + 1; + + Logging::PacketMsg Msg; + Msg.Header = Logging::FillHeader(Logging::PacketTypes::TYPE_MSG); + Msg.MessageLength = MsgLen; + Msg.Level = Level; + + const iovec vec[2] = { + { + .iov_base = &Msg, + .iov_len = sizeof(Msg), + }, + { + .iov_base = const_cast(Message), + .iov_len = Msg.MessageLength, + }, + }; + + writev(FD, vec, 2); +} + +void AssertHandler(int FD, const char* Message) { + MsgHandler(FD, LogMan::DebugLevels::ASSERT, Message); +} +/** @} */ +} // namespace FEXServerClient diff --git a/Source/Common/FEXServerClient.h b/Source/Common/FEXServerClient.h index 626fec5d5..d0f680a24 100644 --- a/Source/Common/FEXServerClient.h +++ b/Source/Common/FEXServerClient.h @@ -6,152 +6,152 @@ #include namespace FEXServerClient { - enum class PacketType { - // Request and Result - TYPE_KILL, - TYPE_GET_LOG_FD, - TYPE_GET_ROOTFS_PATH, - TYPE_GET_PID_FD, +enum class PacketType { + // Request and Result + TYPE_KILL, + TYPE_GET_LOG_FD, + TYPE_GET_ROOTFS_PATH, + TYPE_GET_PID_FD, - // Result only - TYPE_SUCCESS, - TYPE_ERROR, + // Result only + TYPE_SUCCESS, + TYPE_ERROR, +}; + +union FEXServerRequestPacket { + struct Header { + PacketType Type; + } Header; + + struct { + struct Header Header; + } BasicRequest; +}; + +union FEXServerResultPacket { + struct Header { + PacketType Type; + } Header; + + struct { + struct Header Header; + int32_t PID; + } PID; + + struct { + struct Header Header; + size_t Length; + char Mount[0]; + } MountPath; +}; + +constexpr size_t MAXIMUM_REQUEST_PACKET_SIZE = sizeof(FEXServerRequestPacket); + +fextl::string GetServerLockFolder(); +fextl::string GetServerLockFile(); +fextl::string GetServerRootFSLockFile(); +fextl::string GetTempFolder(); +fextl::string GetServerMountFolder(); +fextl::string GetServerSocketName(); +int GetServerFD(); + +bool SetupClient(char* InterpreterPath); + +/** + * @brief Connect to and start a FEXServer instance if required + * + * @return socket FD for communicating with server + */ +int ConnectToAndStartServer(char* InterpreterPath); + +enum class ConnectionOption { + Default, + NoPrintConnectionError, +}; +/** + * @brief Connect to a FEXServer instance if it exists + * + * @return socket FD for communicating with server + */ +int ConnectToServer(ConnectionOption ConnectionOption = ConnectionOption::Default); + +/** + * @name Packet request functions + * @{ */ +/** + * @brief Request the server to be killed + * + * @param ServerSocket - Socket to the server + */ +void RequestServerKill(int ServerSocket); + +/** + * @brief Request a FEXServer to give us a log FD to write in to + * + * @param ServerSocket - Socket to the server + * + * @return FD for logging in to + */ +int RequestLogFD(int ServerSocket); + +fextl::string RequestRootFSPath(int ServerSocket); + +/** + * @brief Request a FEXServer to give us a pidfd of the process + * + * @param ServerSocket - Socket to the server + * + * @return FD for pidfd + */ +int RequestPIDFD(int ServerSocket); + +/** @} */ + +/** + * @name FEX logging through FEXServer + * @{ */ +namespace Logging { + enum class PacketTypes : uint32_t { + TYPE_MSG, }; - union FEXServerRequestPacket { - struct Header { - PacketType Type; - } Header; - - struct { - struct Header Header; - } BasicRequest; + struct PacketHeader { + uint64_t Timestamp {}; + PacketTypes PacketType {}; + int32_t PID {}; + int32_t TID {}; + uint32_t Pad {}; + char Data[0]; }; - union FEXServerResultPacket { - struct Header { - PacketType Type; - } Header; - - struct { - struct Header Header; - int32_t PID; - } PID; - - struct { - struct Header Header; - size_t Length; - char Mount[0]; - } MountPath; + struct PacketMsg { + PacketHeader Header {}; + size_t MessageLength; + uint32_t Level {}; + uint32_t Pad {}; }; - constexpr size_t MAXIMUM_REQUEST_PACKET_SIZE = sizeof(FEXServerRequestPacket); + static_assert(sizeof(PacketHeader) == 24, "Wrong size"); - fextl::string GetServerLockFolder(); - fextl::string GetServerLockFile(); - fextl::string GetServerRootFSLockFile(); - fextl::string GetTempFolder(); - fextl::string GetServerMountFolder(); - fextl::string GetServerSocketName(); - int GetServerFD(); + [[maybe_unused]] + static PacketHeader FillHeader(Logging::PacketTypes Type) { + struct timespec Time {}; + uint64_t Timestamp {}; + clock_gettime(CLOCK_MONOTONIC, &Time); + Timestamp = Time.tv_sec * 1e9 + Time.tv_nsec; - bool SetupClient(char *InterpreterPath); - - /** - * @brief Connect to and start a FEXServer instance if required - * - * @return socket FD for communicating with server - */ - int ConnectToAndStartServer(char *InterpreterPath); - - enum class ConnectionOption { - Default, - NoPrintConnectionError, - }; - /** - * @brief Connect to a FEXServer instance if it exists - * - * @return socket FD for communicating with server - */ - int ConnectToServer(ConnectionOption ConnectionOption = ConnectionOption::Default); - - /** - * @name Packet request functions - * @{ */ - /** - * @brief Request the server to be killed - * - * @param ServerSocket - Socket to the server - */ - void RequestServerKill(int ServerSocket); - - /** - * @brief Request a FEXServer to give us a log FD to write in to - * - * @param ServerSocket - Socket to the server - * - * @return FD for logging in to - */ - int RequestLogFD(int ServerSocket); - - fextl::string RequestRootFSPath(int ServerSocket); - - /** - * @brief Request a FEXServer to give us a pidfd of the process - * - * @param ServerSocket - Socket to the server - * - * @return FD for pidfd - */ - int RequestPIDFD(int ServerSocket); - - /** @} */ - - /** - * @name FEX logging through FEXServer - * @{ */ - namespace Logging { - enum class PacketTypes : uint32_t { - TYPE_MSG, + Logging::PacketHeader Msg { + .Timestamp = Timestamp, + .PacketType = Type, + .PID = ::getpid(), + .TID = FHU::Syscalls::gettid(), }; - struct PacketHeader { - uint64_t Timestamp{}; - PacketTypes PacketType{}; - int32_t PID{}; - int32_t TID{}; - uint32_t Pad{}; - char Data[0]; - }; - - struct PacketMsg { - PacketHeader Header{}; - size_t MessageLength; - uint32_t Level{}; - uint32_t Pad{}; - }; - - static_assert(sizeof(PacketHeader) == 24, "Wrong size"); - - [[maybe_unused]] - static PacketHeader FillHeader(Logging::PacketTypes Type) { - struct timespec Time{}; - uint64_t Timestamp{}; - clock_gettime(CLOCK_MONOTONIC, &Time); - Timestamp = Time.tv_sec * 1e9 + Time.tv_nsec; - - Logging::PacketHeader Msg { - .Timestamp = Timestamp, - .PacketType = Type, - .PID = ::getpid(), - .TID = FHU::Syscalls::gettid(), - }; - - return Msg; - } + return Msg; } +} // namespace Logging - void MsgHandler(int FD, LogMan::DebugLevels Level, char const *Message); - void AssertHandler(int FD, char const *Message); - /** @} */ -} +void MsgHandler(int FD, LogMan::DebugLevels Level, const char* Message); +void AssertHandler(int FD, const char* Message); +/** @} */ +} // namespace FEXServerClient diff --git a/Source/Common/FileFormatCheck.cpp b/Source/Common/FileFormatCheck.cpp index 6f81772cc..dd37cda02 100644 --- a/Source/Common/FileFormatCheck.cpp +++ b/Source/Common/FileFormatCheck.cpp @@ -7,75 +7,75 @@ #include namespace FEX::FormatCheck { - bool IsSquashFS(fextl::string const &Filename) { - // If it is a regular file then we need to check if it is a valid archive - struct SquashFSHeader { - uint32_t magic; - uint32_t inode_count; - uint32_t mtime; - uint32_t block_size; - uint32_t fragment_entry_count; - uint16_t compression_id; - uint16_t block_log; - uint16_t flags; - uint16_t id_count; - uint16_t version_major; - uint16_t version_minor; - uint64_t More[8]; // More things that don't matter to us - }; +bool IsSquashFS(const fextl::string& Filename) { + // If it is a regular file then we need to check if it is a valid archive + struct SquashFSHeader { + uint32_t magic; + uint32_t inode_count; + uint32_t mtime; + uint32_t block_size; + uint32_t fragment_entry_count; + uint16_t compression_id; + uint16_t block_log; + uint16_t flags; + uint16_t id_count; + uint16_t version_major; + uint16_t version_minor; + uint64_t More[8]; // More things that don't matter to us + }; - SquashFSHeader Header{}; - int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); - if (fd == -1) { - return false; - } - - if (pread(fd, reinterpret_cast(&Header), sizeof(SquashFSHeader), 0) != sizeof(SquashFSHeader)) { - close(fd); - return false; - } - - close(fd); - - // Make sure the cookie matches - if (Header.magic == 0x73717368) { - // Sanity check the version - uint32_t version = (uint32_t)Header.version_major << 16 | Header.version_minor; - if (version >= 0x00040000) { - // Everything is sane, we can add it - return true; - } - } + SquashFSHeader Header {}; + int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); + if (fd == -1) { return false; } - bool IsEroFS(fextl::string const &Filename) { - // v1 of EroFS has a 128byte header - // This lives within a fixed offset inside of the first superblock of the file - // Each superblock is 4096bytes - // - // We only care about the uint32_t at the start of this offset which is the cookie - struct EroFSHeader { - uint32_t Magic; - // Additional data after this if necessary in the future. - }; - - constexpr size_t HEADER_OFFSET = 1024; - constexpr uint32_t COOKIE_MAGIC_V1 = 0xE0F5E1E2; - - EroFSHeader Header{}; - int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); - if (fd == -1) { - return false; - } - - if (pread(fd, reinterpret_cast(&Header), sizeof(EroFSHeader), HEADER_OFFSET) != sizeof(EroFSHeader)) { - close(fd); - return false; - } - + if (pread(fd, reinterpret_cast(&Header), sizeof(SquashFSHeader), 0) != sizeof(SquashFSHeader)) { close(fd); - - return Header.Magic == COOKIE_MAGIC_V1; + return false; } + + close(fd); + + // Make sure the cookie matches + if (Header.magic == 0x73717368) { + // Sanity check the version + uint32_t version = (uint32_t)Header.version_major << 16 | Header.version_minor; + if (version >= 0x00040000) { + // Everything is sane, we can add it + return true; + } + } + return false; } + +bool IsEroFS(const fextl::string& Filename) { + // v1 of EroFS has a 128byte header + // This lives within a fixed offset inside of the first superblock of the file + // Each superblock is 4096bytes + // + // We only care about the uint32_t at the start of this offset which is the cookie + struct EroFSHeader { + uint32_t Magic; + // Additional data after this if necessary in the future. + }; + + constexpr size_t HEADER_OFFSET = 1024; + constexpr uint32_t COOKIE_MAGIC_V1 = 0xE0F5E1E2; + + EroFSHeader Header {}; + int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return false; + } + + if (pread(fd, reinterpret_cast(&Header), sizeof(EroFSHeader), HEADER_OFFSET) != sizeof(EroFSHeader)) { + close(fd); + return false; + } + + close(fd); + + return Header.Magic == COOKIE_MAGIC_V1; +} +} // namespace FEX::FormatCheck diff --git a/Source/Common/FileFormatCheck.h b/Source/Common/FileFormatCheck.h index 716f69394..a7da459cc 100644 --- a/Source/Common/FileFormatCheck.h +++ b/Source/Common/FileFormatCheck.h @@ -4,6 +4,6 @@ #include namespace FEX::FormatCheck { - bool IsSquashFS(fextl::string const &Filename); - bool IsEroFS(fextl::string const &Filename); -} +bool IsSquashFS(const fextl::string& Filename); +bool IsEroFS(const fextl::string& Filename); +} // namespace FEX::FormatCheck diff --git a/Source/Common/StringUtil.cpp b/Source/Common/StringUtil.cpp index d1ab07afd..6072bf3fb 100644 --- a/Source/Common/StringUtil.cpp +++ b/Source/Common/StringUtil.cpp @@ -2,19 +2,15 @@ #include "Common/StringUtil.h" namespace FEX::StringUtil { -void ltrim(fextl::string &s) { - s.erase(std::find_if(s.begin(), s.end(), [](int ch) { - return !std::isspace(ch); - })); +void ltrim(fextl::string& s) { + s.erase(std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); } -void rtrim(fextl::string &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { - return !std::isspace(ch); - }).base(), s.end()); +void rtrim(fextl::string& s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } -void trim(fextl::string &s) { +void trim(fextl::string& s) { ltrim(s); rtrim(s); } -} +} // namespace FEX::StringUtil diff --git a/Source/Common/StringUtil.h b/Source/Common/StringUtil.h index 9ff5ff23a..62c2eddda 100644 --- a/Source/Common/StringUtil.h +++ b/Source/Common/StringUtil.h @@ -5,7 +5,7 @@ #include namespace FEX::StringUtil { -void ltrim(fextl::string &s); -void rtrim(fextl::string &s); -void trim(fextl::string &s); -} +void ltrim(fextl::string& s); +void rtrim(fextl::string& s); +void trim(fextl::string& s); +} // namespace FEX::StringUtil diff --git a/Source/Tools/CodeSizeValidation/Main.cpp b/Source/Tools/CodeSizeValidation/Main.cpp index 89940fee8..4af873149 100644 --- a/Source/Tools/CodeSizeValidation/Main.cpp +++ b/Source/Tools/CodeSizeValidation/Main.cpp @@ -10,207 +10,208 @@ #include namespace CodeSize { - class CodeSizeValidation final { - public: - struct InstructionStats { - uint64_t GuestCodeInstructions{}; - uint64_t HostCodeInstructions{}; +class CodeSizeValidation final { +public: + struct InstructionStats { + uint64_t GuestCodeInstructions {}; + uint64_t HostCodeInstructions {}; - uint64_t HeaderSize{}; - uint64_t TailSize{}; - }; - - using CodeLines = fextl::vector; - using InstructionData = std::pair; - - bool ParseMessage(char const *Message); - - InstructionData *GetDataForRIP(uint64_t RIP) { - return &RIPToStats[RIP]; - } - - bool InfoPrintingDisabled() const { - return SetupInfoDisabled; - } - - void CalculateBaseStats(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread); - private: - void ClearStats() { - RIPToStats.clear(); - } - - void SetBaseStats(InstructionStats const &NewBase) { - BaseStats = NewBase; - } - - void CalculateDifferenceBetweenStats(InstructionData *Nop, InstructionData *Fence); - - uint64_t CurrentRIPParse{}; - bool ConsumingDisassembly{}; - InstructionData *CurrentStats{}; - InstructionStats BaseStats{}; - - fextl::unordered_map RIPToStats; - bool SetupInfoDisabled{}; + uint64_t HeaderSize {}; + uint64_t TailSize {}; }; - constexpr std::string_view RIPMessage = "RIP: 0x"; - constexpr std::string_view GuestCodeMessage = "Guest Code instructions: "; - constexpr std::string_view HostCodeMessage = "Host Code instructions: "; - constexpr std::string_view DisassembleBeginMessage = "Disassemble Begin"; - constexpr std::string_view DisassembleEndMessage = "Disassemble End"; - constexpr std::string_view BlowUpMsg = "Blow-up Amt: "; + using CodeLines = fextl::vector; + using InstructionData = std::pair; - static std::string_view SanitizeDisassembly(std::string_view Message) { - auto it = Message.find(" (addr"); - // If it contains an address calculation, strip it out. - Message = Message.substr(0, it); - if (Message.find("adrp ") != std::string_view::npos || - Message.find("adr ") != std::string_view::npos) { - Message = Message.substr(0, Message.find(" #")); - } - return Message; + bool ParseMessage(const char* Message); + + InstructionData* GetDataForRIP(uint64_t RIP) { + return &RIPToStats[RIP]; } - bool CodeSizeValidation::ParseMessage(char const *Message) { - // std::string_view doesn't have contains until c++23. - std::string_view MessageView {Message}; - if (MessageView.find(RIPMessage) != MessageView.npos) { - // New RIP found - std::string_view RIPView = std::string_view{Message + RIPMessage.size()}; - std::from_chars(RIPView.data(), RIPView.end(), CurrentRIPParse, 16); - CurrentStats = &RIPToStats[CurrentRIPParse]; - return false; - } - - if (MessageView.find(GuestCodeMessage) != MessageView.npos) { - std::string_view CodeSizeView = std::string_view{Message + GuestCodeMessage.size()}; - std::from_chars(CodeSizeView.data(), CodeSizeView.end(), CurrentStats->first.GuestCodeInstructions); - return false; - } - if (MessageView.find(HostCodeMessage) != MessageView.npos) { - std::string_view CodeSizeView = std::string_view{Message + HostCodeMessage.size()}; - std::from_chars(CodeSizeView.data(), CodeSizeView.end(), CurrentStats->first.HostCodeInstructions); - - CurrentStats->first.HostCodeInstructions -= BaseStats.HostCodeInstructions; - return false; - } - if (MessageView.find(DisassembleBeginMessage) != MessageView.npos) { - ConsumingDisassembly = true; - // Just so the output isn't a mess. - return false; - } - if (MessageView.find(DisassembleEndMessage) != MessageView.npos) { - ConsumingDisassembly = false; - // Just so the output isn't a mess. - - // Remove the header and tails. - if (BaseStats.HeaderSize) { - CurrentStats->second.erase(CurrentStats->second.begin(), CurrentStats->second.begin() + BaseStats.HeaderSize); - } - if (BaseStats.TailSize) { - CurrentStats->second.erase(CurrentStats->second.end() - BaseStats.TailSize, CurrentStats->second.end()); - } - return false; - } - - if (MessageView.find(BlowUpMsg) != MessageView.npos) { - return false; - } - - if (ConsumingDisassembly) { - // Currently consuming disassembly. Each line will be a single line of disassembly. - CurrentStats->second.push_back(fextl::string(SanitizeDisassembly(Message))); - return false; - } - - return true; + bool InfoPrintingDisabled() const { + return SetupInfoDisabled; } - void CodeSizeValidation::CalculateDifferenceBetweenStats(InstructionData *Nop, InstructionData *Fence) { - // Expected format. - // adr x0, #-0x4 (addr 0x7fffe9880054) - // str x0, [x28, #184] - // dmb sy - // ldr x0, pc+8 (addr 0x7fffe988006c) - // blr x0 - // unallocated (Unallocated) - // udf #0x7fff - // unallocated (Unallocated) - // udf #0x0 - // - // First two lines are the header. - // Next comes the implementation (0 instruction size for nop, 1 instruction for fence) - // After that is the tail. - - const auto &NOPCode = Nop->second; - const auto &FENCECode = Fence->second; - - LOGMAN_THROW_A_FMT(NOPCode.size() < FENCECode.size(), "NOP code must be smaller than fence!"); - for (size_t i = 0; i < NOPCode.size(); ++i) { - const auto &NOPLine = NOPCode.at(i); - const auto &FENCELine = FENCECode.at(i); - - const auto NOPmnemonic = std::string_view(NOPLine.data(), NOPLine.find(' ')); - const auto FENCEmnemonic = std::string_view(FENCELine.data(), FENCELine.find(' ')); - - if (NOPmnemonic != FENCEmnemonic) { - // Headersize of a block is now `i` number of instructions. - Nop->first.HeaderSize = i; - - // Tail size is going to be the remaining size - Nop->first.TailSize = NOPCode.size() - i; - break; - } - } - - SetBaseStats(Nop->first); + void CalculateBaseStats(FEXCore::Context::Context* CTX, FEXCore::Core::InternalThreadState* Thread); +private: + void ClearStats() { + RIPToStats.clear(); } - void CodeSizeValidation::CalculateBaseStats(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread) { - SetupInfoDisabled = true; - - // Known hardcoded instructions that will generate blocks of particular sizes. - // NOP will never generate any instructions. - constexpr static uint8_t NOP[] = { - 0x90, - }; - - // MFENCE will always generate a block with one instruction. - constexpr static uint8_t MFENCE[] = { - 0x0f, 0xae, 0xf0, - }; - - // Compile the NOP. - CTX->CompileRIP(Thread, (uint64_t)NOP); - // Gather the stats for the NOP. - auto NOPStats = GetDataForRIP((uint64_t)NOP); - - // Compile MFence - CTX->CompileRIP(Thread, (uint64_t)MFENCE); - - // Get MFence stats. - auto MFENCEStats = GetDataForRIP((uint64_t)MFENCE); - - // Now scan the difference in disasembly between NOP and MFENCE to remove the header and tail. - // Just searching for first instruction change. - - CalculateDifferenceBetweenStats(NOPStats, MFENCEStats); - // Now that the stats have been cleared. Clear our currentStats. - ClearStats(); - - // Invalidate the code ranges to be safe. - auto CodeInvalidationlk = FEXCore::GuardSignalDeferringSection(CTX->GetCodeInvalidationMutex(), Thread); - CTX->InvalidateGuestCodeRange(Thread, (uint64_t)NOP, sizeof(NOP)); - CTX->InvalidateGuestCodeRange(Thread, (uint64_t)MFENCE, sizeof(MFENCE)); - SetupInfoDisabled = false; + void SetBaseStats(const InstructionStats& NewBase) { + BaseStats = NewBase; } - static CodeSizeValidation Validation{}; + void CalculateDifferenceBetweenStats(InstructionData* Nop, InstructionData* Fence); + + uint64_t CurrentRIPParse {}; + bool ConsumingDisassembly {}; + InstructionData* CurrentStats {}; + InstructionStats BaseStats {}; + + fextl::unordered_map RIPToStats; + bool SetupInfoDisabled {}; +}; + +constexpr std::string_view RIPMessage = "RIP: 0x"; +constexpr std::string_view GuestCodeMessage = "Guest Code instructions: "; +constexpr std::string_view HostCodeMessage = "Host Code instructions: "; +constexpr std::string_view DisassembleBeginMessage = "Disassemble Begin"; +constexpr std::string_view DisassembleEndMessage = "Disassemble End"; +constexpr std::string_view BlowUpMsg = "Blow-up Amt: "; + +static std::string_view SanitizeDisassembly(std::string_view Message) { + auto it = Message.find(" (addr"); + // If it contains an address calculation, strip it out. + Message = Message.substr(0, it); + if (Message.find("adrp ") != std::string_view::npos || Message.find("adr ") != std::string_view::npos) { + Message = Message.substr(0, Message.find(" #")); + } + return Message; } -void MsgHandler(LogMan::DebugLevels Level, char const *Message) { - const char *CharLevel{LogMan::DebugLevelStr(Level)}; +bool CodeSizeValidation::ParseMessage(const char* Message) { + // std::string_view doesn't have contains until c++23. + std::string_view MessageView {Message}; + if (MessageView.find(RIPMessage) != MessageView.npos) { + // New RIP found + std::string_view RIPView = std::string_view {Message + RIPMessage.size()}; + std::from_chars(RIPView.data(), RIPView.end(), CurrentRIPParse, 16); + CurrentStats = &RIPToStats[CurrentRIPParse]; + return false; + } + + if (MessageView.find(GuestCodeMessage) != MessageView.npos) { + std::string_view CodeSizeView = std::string_view {Message + GuestCodeMessage.size()}; + std::from_chars(CodeSizeView.data(), CodeSizeView.end(), CurrentStats->first.GuestCodeInstructions); + return false; + } + if (MessageView.find(HostCodeMessage) != MessageView.npos) { + std::string_view CodeSizeView = std::string_view {Message + HostCodeMessage.size()}; + std::from_chars(CodeSizeView.data(), CodeSizeView.end(), CurrentStats->first.HostCodeInstructions); + + CurrentStats->first.HostCodeInstructions -= BaseStats.HostCodeInstructions; + return false; + } + if (MessageView.find(DisassembleBeginMessage) != MessageView.npos) { + ConsumingDisassembly = true; + // Just so the output isn't a mess. + return false; + } + if (MessageView.find(DisassembleEndMessage) != MessageView.npos) { + ConsumingDisassembly = false; + // Just so the output isn't a mess. + + // Remove the header and tails. + if (BaseStats.HeaderSize) { + CurrentStats->second.erase(CurrentStats->second.begin(), CurrentStats->second.begin() + BaseStats.HeaderSize); + } + if (BaseStats.TailSize) { + CurrentStats->second.erase(CurrentStats->second.end() - BaseStats.TailSize, CurrentStats->second.end()); + } + return false; + } + + if (MessageView.find(BlowUpMsg) != MessageView.npos) { + return false; + } + + if (ConsumingDisassembly) { + // Currently consuming disassembly. Each line will be a single line of disassembly. + CurrentStats->second.push_back(fextl::string(SanitizeDisassembly(Message))); + return false; + } + + return true; +} + +void CodeSizeValidation::CalculateDifferenceBetweenStats(InstructionData* Nop, InstructionData* Fence) { + // Expected format. + // adr x0, #-0x4 (addr 0x7fffe9880054) + // str x0, [x28, #184] + // dmb sy + // ldr x0, pc+8 (addr 0x7fffe988006c) + // blr x0 + // unallocated (Unallocated) + // udf #0x7fff + // unallocated (Unallocated) + // udf #0x0 + // + // First two lines are the header. + // Next comes the implementation (0 instruction size for nop, 1 instruction for fence) + // After that is the tail. + + const auto& NOPCode = Nop->second; + const auto& FENCECode = Fence->second; + + LOGMAN_THROW_A_FMT(NOPCode.size() < FENCECode.size(), "NOP code must be smaller than fence!"); + for (size_t i = 0; i < NOPCode.size(); ++i) { + const auto& NOPLine = NOPCode.at(i); + const auto& FENCELine = FENCECode.at(i); + + const auto NOPmnemonic = std::string_view(NOPLine.data(), NOPLine.find(' ')); + const auto FENCEmnemonic = std::string_view(FENCELine.data(), FENCELine.find(' ')); + + if (NOPmnemonic != FENCEmnemonic) { + // Headersize of a block is now `i` number of instructions. + Nop->first.HeaderSize = i; + + // Tail size is going to be the remaining size + Nop->first.TailSize = NOPCode.size() - i; + break; + } + } + + SetBaseStats(Nop->first); +} + +void CodeSizeValidation::CalculateBaseStats(FEXCore::Context::Context* CTX, FEXCore::Core::InternalThreadState* Thread) { + SetupInfoDisabled = true; + + // Known hardcoded instructions that will generate blocks of particular sizes. + // NOP will never generate any instructions. + constexpr static uint8_t NOP[] = { + 0x90, + }; + + // MFENCE will always generate a block with one instruction. + constexpr static uint8_t MFENCE[] = { + 0x0f, + 0xae, + 0xf0, + }; + + // Compile the NOP. + CTX->CompileRIP(Thread, (uint64_t)NOP); + // Gather the stats for the NOP. + auto NOPStats = GetDataForRIP((uint64_t)NOP); + + // Compile MFence + CTX->CompileRIP(Thread, (uint64_t)MFENCE); + + // Get MFence stats. + auto MFENCEStats = GetDataForRIP((uint64_t)MFENCE); + + // Now scan the difference in disasembly between NOP and MFENCE to remove the header and tail. + // Just searching for first instruction change. + + CalculateDifferenceBetweenStats(NOPStats, MFENCEStats); + // Now that the stats have been cleared. Clear our currentStats. + ClearStats(); + + // Invalidate the code ranges to be safe. + auto CodeInvalidationlk = FEXCore::GuardSignalDeferringSection(CTX->GetCodeInvalidationMutex(), Thread); + CTX->InvalidateGuestCodeRange(Thread, (uint64_t)NOP, sizeof(NOP)); + CTX->InvalidateGuestCodeRange(Thread, (uint64_t)MFENCE, sizeof(MFENCE)); + SetupInfoDisabled = false; +} + +static CodeSizeValidation Validation {}; +} // namespace CodeSize + +void MsgHandler(LogMan::DebugLevels Level, const char* Message) { + const char* CharLevel {LogMan::DebugLevelStr(Level)}; if (Level == LogMan::INFO) { // Disassemble information is sent through the Info log level. @@ -225,7 +226,7 @@ void MsgHandler(LogMan::DebugLevels Level, char const *Message) { fextl::fmt::print("[{}] {}\n", CharLevel, Message); } -void AssertHandler(char const *Message) { +void AssertHandler(const char* Message) { fextl::fmt::print("[ASSERT] {}\n", Message); // make sure buffers are flushed @@ -243,7 +244,7 @@ struct TestInfo { struct TestHeader { uint64_t Bitness; - uint64_t NumTests{}; + uint64_t NumTests {}; uint64_t EnabledHostFeatures; uint64_t DisabledHostFeatures; uint64_t EnvironmentVariableCount; @@ -251,15 +252,15 @@ struct TestHeader { }; static fextl::vector TestData; -static TestHeader const *TestHeaderData{}; -static TestInfo const *TestsStart{}; -static fextl::vector> EnvironmentVariables{}; +static const TestHeader* TestHeaderData {}; +static const TestInfo* TestsStart {}; +static fextl::vector> EnvironmentVariables {}; -static bool TestInstructions(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread, const char *UpdatedInstructionCountsPath) { +static bool TestInstructions(FEXCore::Context::Context* CTX, FEXCore::Core::InternalThreadState* Thread, const char* UpdatedInstructionCountsPath) { LogMan::Msg::IFmt("Compiling code"); // Tell FEXCore to compile all the instructions upfront. - TestInfo const *CurrentTest = TestsStart; + const TestInfo* CurrentTest = TestsStart; for (size_t i = 0; i < TestHeaderData->NumTests; ++i) { uint64_t CodeRIP = (uint64_t)&CurrentTest->Code[0]; LogMan::Msg::IFmt("Compiling instruction '{}'", CurrentTest->TestInst); @@ -268,7 +269,7 @@ static bool TestInstructions(FEXCore::Context::Context *CTX, FEXCore::Core::Inte CTX->CompileRIPCount(Thread, CodeRIP, CurrentTest->x86InstCount); // Go to the next test. - CurrentTest = reinterpret_cast(&CurrentTest->Code[CurrentTest->CodeSize]); + CurrentTest = reinterpret_cast(&CurrentTest->Code[CurrentTest->CodeSize]); } bool TestsPassed {true}; @@ -283,8 +284,7 @@ static bool TestInstructions(FEXCore::Context::Context *CTX, FEXCore::Core::Inte LogMan::Msg::IFmt("Testing instruction '{}': {} host instructions", CurrentTest->TestInst, INSTStats->first.HostCodeInstructions); // Show the code if the count of instructions changed to something we didn't expect. - bool ShouldShowCode = - INSTStats->first.HostCodeInstructions != CurrentTest->ExpectedInstructionCount; + bool ShouldShowCode = INSTStats->first.HostCodeInstructions != CurrentTest->ExpectedInstructionCount; if (ShouldShowCode) { for (auto Line : INSTStats->second) { @@ -294,21 +294,23 @@ static bool TestInstructions(FEXCore::Context::Context *CTX, FEXCore::Core::Inte if (INSTStats->first.HostCodeInstructions != CurrentTest->ExpectedInstructionCount) { LogMan::Msg::EFmt("Fail: '{}': {} host instructions", CurrentTest->TestInst, INSTStats->first.HostCodeInstructions); - LogMan::Msg::EFmt("Fail: Test took {} instructions but we expected {} instructions!", INSTStats->first.HostCodeInstructions, CurrentTest->ExpectedInstructionCount); + LogMan::Msg::EFmt("Fail: Test took {} instructions but we expected {} instructions!", INSTStats->first.HostCodeInstructions, + CurrentTest->ExpectedInstructionCount); // Fail the test if the instruction count has changed at all. TestsPassed = false; } // Go to the next test. - CurrentTest = reinterpret_cast(&CurrentTest->Code[CurrentTest->CodeSize]); + CurrentTest = reinterpret_cast(&CurrentTest->Code[CurrentTest->CodeSize]); } if (UpdatedInstructionCountsPath) { // Unlink the file. unlink(UpdatedInstructionCountsPath); - FEXCore::File::File FD(UpdatedInstructionCountsPath, FEXCore::File::FileModes::WRITE | FEXCore::File::FileModes::CREATE | FEXCore::File::FileModes::TRUNCATE); + FEXCore::File::File FD(UpdatedInstructionCountsPath, + FEXCore::File::FileModes::WRITE | FEXCore::File::FileModes::CREATE | FEXCore::File::FileModes::TRUNCATE); if (!FD.IsValid()) { // If we couldn't open the file then early exit this. @@ -332,7 +334,7 @@ static bool TestInstructions(FEXCore::Context::Context *CTX, FEXCore::Core::Inte FD.Write(fextl::fmt::format("\t\t\"ExpectedArm64ASM\": [\n", INSTStats->first.HostCodeInstructions)); for (auto it = INSTStats->second.begin(); it != INSTStats->second.end(); ++it) { - const auto &Line = *it; + const auto& Line = *it; const auto NextIt = it + 1; FD.Write(fextl::fmt::format("\t\t\t\"{}\"{}\n", Line, NextIt != INSTStats->second.end() ? "," : "")); } @@ -341,7 +343,7 @@ static bool TestInstructions(FEXCore::Context::Context *CTX, FEXCore::Core::Inte FD.Write(fextl::fmt::format("\t}},\n", CurrentTest->TestInst)); // Go to the next test. - CurrentTest = reinterpret_cast(&CurrentTest->Code[CurrentTest->CodeSize]); + CurrentTest = reinterpret_cast(&CurrentTest->Code[CurrentTest->CodeSize]); } // Print a null member @@ -352,15 +354,15 @@ static bool TestInstructions(FEXCore::Context::Context *CTX, FEXCore::Core::Inte return TestsPassed; } -bool LoadTests(const char *Path) { +bool LoadTests(const char* Path) { if (!FEXCore::FileLoading::LoadFile(TestData, Path)) { return false; } - TestHeaderData = reinterpret_cast(TestData.data()); + TestHeaderData = reinterpret_cast(TestData.data()); // Need to walk past the environment variables to get to the actual tests. - const uint8_t *Data = TestHeaderData->Data; + const uint8_t* Data = TestHeaderData->Data; for (size_t i = 0; i < TestHeaderData->EnvironmentVariableCount; ++i) { // Environment variables are a pair of null terminated strings. Data += strlen(reinterpret_cast(Data)) + 1; @@ -386,7 +388,7 @@ public: void Load() override { fextl::unordered_map EnvMap; - const uint8_t *Data = TestHeaderData->Data; + const uint8_t* Data = TestHeaderData->Data; for (size_t i = 0; i < TestHeaderData->EnvironmentVariableCount; ++i) { // Environment variables are a pair of null terminated strings. const std::string_view Key = reinterpret_cast(Data); @@ -401,21 +403,21 @@ public: if (Value) { EnvMap.insert_or_assign(Key, *Value); - } - else { + } else { EnvMap.insert_or_assign(Key, Value_View); } } auto GetVar = [&](const std::string_view id) -> std::optional { const auto it = EnvMap.find(id); - if (it == EnvMap.end()) + if (it == EnvMap.end()) { return std::nullopt; + } return it->second; }; - for (auto &it : EnvConfigLookup) { + for (auto& it : EnvConfigLookup) { if (auto Value = GetVar(it.first); Value) { Set(it.second, *Value); } @@ -425,9 +427,9 @@ public: private: fextl::vector> Env; }; -} +} // namespace -int main(int argc, char **argv, char **const envp) { +int main(int argc, char** argv, char** const envp) { FEXCore::Allocator::GLIBCScopedFault GLIBFaultScope; LogMan::Throw::InstallHandler(AssertHandler); LogMan::Msg::InstallHandler(MsgHandler); @@ -453,7 +455,9 @@ int main(int argc, char **argv, char **const envp) { // IRJIT. Only works on JITs. FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_CORE, fextl::fmt::format("{}", static_cast(FEXCore::Config::CONFIG_IRJIT))); // Enable block disassembly. - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_DISASSEMBLE, fextl::fmt::format("{}", static_cast(FEXCore::Config::Disassemble::BLOCKS | FEXCore::Config::Disassemble::STATS))); + FEXCore::Config::EraseSet( + FEXCore::Config::CONFIG_DISASSEMBLE, + fextl::fmt::format("{}", static_cast(FEXCore::Config::Disassemble::BLOCKS | FEXCore::Config::Disassemble::STATS))); // Choose bitness. FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_IS64BIT_MODE, TestHeaderData->Bitness == 64 ? "1" : "0"); // Disable telemetry, it can affect instruction counts. @@ -466,18 +470,18 @@ int main(int argc, char **argv, char **const envp) { FEATURE_SVE128 = (1U << 0), FEATURE_SVE256 = (1U << 1), FEATURE_CLZERO = (1U << 2), - FEATURE_RNG = (1U << 3), - FEATURE_FCMA = (1U << 4), - FEATURE_CSSC = (1U << 5), - FEATURE_AFP = (1U << 6), - FEATURE_RPRES = (1U << 7), - FEATURE_FLAGM = (1U << 8), + FEATURE_RNG = (1U << 3), + FEATURE_FCMA = (1U << 4), + FEATURE_CSSC = (1U << 5), + FEATURE_AFP = (1U << 6), + FEATURE_RPRES = (1U << 7), + FEATURE_FLAGM = (1U << 8), FEATURE_FLAGM2 = (1U << 9), FEATURE_CRYPTO = (1U << 10), }; uint64_t SVEWidth = 0; - uint64_t HostFeatureControl{}; + uint64_t HostFeatureControl {}; if (TestHeaderData->EnabledHostFeatures & FEATURE_SVE128) { HostFeatureControl |= static_cast(FEXCore::Config::HostFeatures::ENABLESVE); SVEWidth = 128; diff --git a/Source/Tools/CommonGUI/IMGui.h b/Source/Tools/CommonGUI/IMGui.h index 78a95c078..17cf8b482 100644 --- a/Source/Tools/CommonGUI/IMGui.h +++ b/Source/Tools/CommonGUI/IMGui.h @@ -20,133 +20,131 @@ namespace FEX::GUI { - using TupleReturn = std::tuple; - static TupleReturn SetupIMGui(const char *Name, const fextl::string &Config) { - // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) - { - printf("Error: %s\n", SDL_GetError()); - return TupleReturn{}; - } +using TupleReturn = std::tuple; +static TupleReturn SetupIMGui(const char* Name, const fextl::string& Config) { + // Setup SDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { + printf("Error: %s\n", SDL_GetError()); + return TupleReturn {}; + } - // Create window with graphics context - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow(Name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 640, window_flags); - SDL_GLContext gl_context{}; - const char* glsl_version{}; + // Create window with graphics context + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + SDL_Window* window = SDL_CreateWindow(Name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 640, window_flags); + SDL_GLContext gl_context {}; + const char* glsl_version {}; - // Try a GL 3.0 context + // Try a GL 3.0 context + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + gl_context = SDL_GL_CreateContext(window); + glsl_version = "#version 130"; + + if (!gl_context) { + // 3.0 failed, let's try 2.1 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); gl_context = SDL_GL_CreateContext(window); - glsl_version = "#version 130"; + glsl_version = "#version 120"; if (!gl_context) { - // 3.0 failed, let's try 2.1 + // 2.1 failed, let's try ES 2.0 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); gl_context = SDL_GL_CreateContext(window); - glsl_version = "#version 120"; + glsl_version = "#version 100"; if (!gl_context) { - // 2.1 failed, let's try ES 2.0 - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - gl_context = SDL_GL_CreateContext(window); - glsl_version = "#version 100"; + printf("Couldn't create GL context: %s\n", SDL_GetError()); + return {}; + } + } + } - if (!gl_context) { - printf("Couldn't create GL context: %s\n", SDL_GetError()); - return {}; + SDL_GL_MakeCurrent(window, gl_context); + SDL_GL_SetSwapInterval(1); // Enable vsync + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows + io.IniFilename = &Config.at(0); + + ImGui_ImplSDL2_InitForOpenGL(window, gl_context); + ImGui_ImplOpenGL3_Init(glsl_version); + return std::make_tuple(window, gl_context); +} + +static std::chrono::time_point LastUpdate {}; +constexpr auto UpdateTimeout = std::chrono::seconds(2); +void DrawUI(SDL_Window* window, std::function DrawFunction) { + bool Running {true}; + ImGuiIO& io = ImGui::GetIO(); + while (Running) { + SDL_Event event; + auto Now = std::chrono::high_resolution_clock::now(); + auto Dur = Now - LastUpdate; + + if (Dur < UpdateTimeout || SDL_WaitEvent(nullptr)) { + while (SDL_PollEvent(&event)) { + ImGui_ImplSDL2_ProcessEvent(&event); + if (event.type == SDL_QUIT) { + Running = false; + } + if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) { + Running = false; } } } - SDL_GL_MakeCurrent(window, gl_context); - SDL_GL_SetSwapInterval(1); // Enable vsync + // Start the Dear ImGui frame + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(window); + Running &= DrawFunction(); - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows - io.IniFilename = &Config.at(0); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - ImGui_ImplSDL2_InitForOpenGL(window, gl_context); - ImGui_ImplOpenGL3_Init(glsl_version); - return std::make_tuple(window, gl_context); - } - - static std::chrono::time_point LastUpdate{}; - constexpr auto UpdateTimeout = std::chrono::seconds(2); - void DrawUI(SDL_Window *window, std::function DrawFunction) { - bool Running {true}; - ImGuiIO& io = ImGui::GetIO(); - while (Running) { - SDL_Event event; - auto Now = std::chrono::high_resolution_clock::now(); - auto Dur = Now - LastUpdate; - - if (Dur < UpdateTimeout || SDL_WaitEvent(nullptr)) - { - while (SDL_PollEvent(&event)) { - ImGui_ImplSDL2_ProcessEvent(&event); - if (event.type == SDL_QUIT) - Running = false; - if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) - Running = false; - } - } - - // Start the Dear ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplSDL2_NewFrame(window); - Running &= DrawFunction(); - - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); - SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - SDL_GL_MakeCurrent(backup_current_window, backup_current_context); - } - - SDL_GL_SwapWindow(window); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); + SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + SDL_GL_MakeCurrent(backup_current_window, backup_current_context); } - } - - void Shutdown(SDL_Window *window, SDL_GLContext gl_context) { - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); - - SDL_GL_DeleteContext(gl_context); - SDL_DestroyWindow(window); - SDL_Quit(); - } - - void HadUpdate() { - LastUpdate = std::chrono::high_resolution_clock::now(); - - // Update the window - SDL_Event Event{}; - Event.type = SDL_USEREVENT; - SDL_PushEvent(&Event); + SDL_GL_SwapWindow(window); } } + +void Shutdown(SDL_Window* window, SDL_GLContext gl_context) { + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + + SDL_GL_DeleteContext(gl_context); + SDL_DestroyWindow(window); + SDL_Quit(); +} + +void HadUpdate() { + LastUpdate = std::chrono::high_resolution_clock::now(); + + // Update the window + SDL_Event Event {}; + Event.type = SDL_USEREVENT; + SDL_PushEvent(&Event); +} +} // namespace FEX::GUI diff --git a/Source/Tools/CommonTools/CodeLoader.h b/Source/Tools/CommonTools/CodeLoader.h index c9d612d51..f7fd4d2c4 100644 --- a/Source/Tools/CommonTools/CodeLoader.h +++ b/Source/Tools/CommonTools/CodeLoader.h @@ -16,7 +16,7 @@ namespace FEX { * @brief Code loader class so the CPU backend can load code in a generic fashion * * This class is expected to have multiple different style of code loaders -*/ + */ class CodeLoader { public: virtual ~CodeLoader() = default; @@ -36,15 +36,19 @@ public: */ virtual uint64_t DefaultRIP() const = 0; - virtual fextl::vector const *GetApplicationArguments() { return nullptr; } - virtual void GetExecveArguments(fextl::vector *Args) {} + virtual const fextl::vector* GetApplicationArguments() { + return nullptr; + } + virtual void GetExecveArguments(fextl::vector* Args) {} virtual void GetAuxv(uint64_t& addr, uint64_t& size) {} - using IRHandler = std::function; + using IRHandler = std::function; virtual void AddIR(IRHandler Handler) {} - virtual uint64_t GetBaseOffset() const { return 0; } + virtual uint64_t GetBaseOffset() const { + return 0; + } }; -} +} // namespace FEX diff --git a/Source/Tools/CommonTools/DummyHandlers.cpp b/Source/Tools/CommonTools/DummyHandlers.cpp index db5b58c17..73285ed1e 100644 --- a/Source/Tools/CommonTools/DummyHandlers.cpp +++ b/Source/Tools/CommonTools/DummyHandlers.cpp @@ -2,19 +2,19 @@ #include "DummyHandlers.h" namespace FEX::DummyHandlers { - thread_local FEXCore::Core::InternalThreadState *TLSThread; +thread_local FEXCore::Core::InternalThreadState* TLSThread; - void DummySignalDelegator::RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) { - TLSThread = Thread; - } +void DummySignalDelegator::RegisterTLSState(FEXCore::Core::InternalThreadState* Thread) { + TLSThread = Thread; +} - void DummySignalDelegator::UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) { - TLSThread = nullptr; - } +void DummySignalDelegator::UninstallTLSState(FEXCore::Core::InternalThreadState* Thread) { + TLSThread = nullptr; +} - FEXCore::Core::InternalThreadState *DummySignalDelegator::GetTLSThread() { - return TLSThread; - } +FEXCore::Core::InternalThreadState* DummySignalDelegator::GetTLSThread() { + return TLSThread; +} fextl::unique_ptr CreateSyscallHandler() { return fextl::make_unique(); @@ -23,4 +23,4 @@ fextl::unique_ptr CreateSyscallHandler() { fextl::unique_ptr CreateSignalDelegator() { return fextl::make_unique(); } -} +} // namespace FEX::DummyHandlers diff --git a/Source/Tools/CommonTools/DummyHandlers.h b/Source/Tools/CommonTools/DummyHandlers.h index 8f31509e5..e58f614d2 100644 --- a/Source/Tools/CommonTools/DummyHandlers.h +++ b/Source/Tools/CommonTools/DummyHandlers.h @@ -5,9 +5,9 @@ namespace FEX::DummyHandlers { -class DummySyscallHandler: public FEXCore::HLE::SyscallHandler, public FEXCore::Allocator::FEXAllocOperators { - public: - uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) override { +class DummySyscallHandler : public FEXCore::HLE::SyscallHandler, public FEXCore::Allocator::FEXAllocOperators { +public: + uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args) override { // Don't do anything return 0; } @@ -18,27 +18,27 @@ class DummySyscallHandler: public FEXCore::HLE::SyscallHandler, public FEXCore:: } // These are no-ops implementations of the SyscallHandler API - FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestAddr) override { + FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestAddr) override { return {0, 0}; } }; class DummySignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::Allocator::FEXAllocOperators { - public: - void SignalThread(FEXCore::Core::InternalThreadState *Thread, FEXCore::Core::SignalEvent Event) override {} +public: + void SignalThread(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::SignalEvent Event) override {} - FEXCore::Core::InternalThreadState *GetBackingTLSThread() { + FEXCore::Core::InternalThreadState* GetBackingTLSThread() { return GetTLSThread(); } - protected: - void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread); - void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread); +protected: + void RegisterTLSState(FEXCore::Core::InternalThreadState* Thread); + void UninstallTLSState(FEXCore::Core::InternalThreadState* Thread); - private: - FEXCore::Core::InternalThreadState *GetTLSThread(); +private: + FEXCore::Core::InternalThreadState* GetTLSThread(); }; fextl::unique_ptr CreateSyscallHandler(); fextl::unique_ptr CreateSignalDelegator(); -} +} // namespace FEX::DummyHandlers diff --git a/Source/Tools/CommonTools/HarnessHelpers.h b/Source/Tools/CommonTools/HarnessHelpers.h index 3be418d74..f342aa2ed 100644 --- a/Source/Tools/CommonTools/HarnessHelpers.h +++ b/Source/Tools/CommonTools/HarnessHelpers.h @@ -27,456 +27,500 @@ #include namespace FEX::HarnessHelper { - inline bool CompareStates(FEXCore::Core::CPUState const& State1, - FEXCore::Core::CPUState const& State2, - uint64_t MatchMask, - bool OutputGPRs, - bool SupportsAVX) { - bool Matches = true; +inline bool CompareStates(const FEXCore::Core::CPUState& State1, const FEXCore::Core::CPUState& State2, uint64_t MatchMask, bool OutputGPRs, + bool SupportsAVX) { + bool Matches = true; - const auto DumpGPRs = [OutputGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { - if (!OutputGPRs) { - return; - } - if (A == B) { - return; - } - - fextl::fmt::print("{}: 0x{:016x} {} 0x{:016x}\n", Name, A, A==B ? "==" : "!=", B); - }; - - const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B){ - DumpGPRs(Name, A, B); - Matches &= A == B; - }; - - // RIP - if (MatchMask & 1) { - CheckGPRs("RIP", State1.rip, State2.rip); + const auto DumpGPRs = [OutputGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { + if (!OutputGPRs) { + return; + } + if (A == B) { + return; } - MatchMask >>= 1; + fextl::fmt::print("{}: 0x{:016x} {} 0x{:016x}\n", Name, A, A == B ? "==" : "!=", B); + }; - // GPRS - for (unsigned i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i, MatchMask >>= 1) { + const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { + DumpGPRs(Name, A, B); + Matches &= A == B; + }; + + // RIP + if (MatchMask & 1) { + CheckGPRs("RIP", State1.rip, State2.rip); + } + + MatchMask >>= 1; + + // GPRS + for (unsigned i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i, MatchMask >>= 1) { + if (MatchMask & 1) { + CheckGPRs(fextl::fmt::format("GPR{}", i), State1.gregs[i], State2.gregs[i]); + } + } + + // XMM + if (SupportsAVX) { + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) { if (MatchMask & 1) { - CheckGPRs(fextl::fmt::format("GPR{}", i), State1.gregs[i], State2.gregs[i]); + CheckGPRs(fextl::fmt::format("XMM0_{}", i), State1.xmm.avx.data[i][0], State2.xmm.avx.data[i][0]); + CheckGPRs(fextl::fmt::format("XMM1_{}", i), State1.xmm.avx.data[i][1], State2.xmm.avx.data[i][1]); } } + } else { + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) { + if (MatchMask & 1) { + CheckGPRs(fextl::fmt::format("XMM0_{}", i), State1.xmm.sse.data[i][0], State2.xmm.sse.data[i][0]); + CheckGPRs(fextl::fmt::format("XMM1_{}", i), State1.xmm.sse.data[i][1], State2.xmm.sse.data[i][1]); + } + } + } - // XMM - if (SupportsAVX) { - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) { - if (MatchMask & 1) { - CheckGPRs(fextl::fmt::format("XMM0_{}", i), State1.xmm.avx.data[i][0], State2.xmm.avx.data[i][0]); - CheckGPRs(fextl::fmt::format("XMM1_{}", i), State1.xmm.avx.data[i][1], State2.xmm.avx.data[i][1]); - } - } - } else { - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) { - if (MatchMask & 1) { - CheckGPRs(fextl::fmt::format("XMM0_{}", i), State1.xmm.sse.data[i][0], State2.xmm.sse.data[i][0]); - CheckGPRs(fextl::fmt::format("XMM1_{}", i), State1.xmm.sse.data[i][1], State2.xmm.sse.data[i][1]); + // GS + if (MatchMask & 1) { + CheckGPRs("GS", State1.gs_cached, State2.gs_cached); + } + MatchMask >>= 1; + + // FS + if (MatchMask & 1) { + CheckGPRs("FS", State1.fs_cached, State2.fs_cached); + } + + return Matches; +} + +class ConfigLoader final { +public: + void Init(const fextl::string& ConfigFilename) { + FEXCore::FileLoading::LoadFile(RawConfigFile, ConfigFilename); + memcpy(&BaseConfig, RawConfigFile.data(), sizeof(ConfigStructBase)); + GetEnvironmentOptions(); + } + + fextl::vector> GetEnvironmentOptions() { + fextl::vector> Env {}; + + uintptr_t DataOffset = BaseConfig.OptionEnvOptionOffset; + for (unsigned i = 0; i < BaseConfig.OptionEnvOptionCount; ++i) { + // Environment variables are null terminated strings + std::string_view Key = RawConfigFile.data() + DataOffset; + std::string_view Value = RawConfigFile.data() + DataOffset + Key.size() + 1; + DataOffset += Key.size() + Value.size() + 2; + Env.emplace_back(Key, Value); + } + return Env; + } + + bool CompareStates(const FEXCore::Core::CPUState* State1, const FEXCore::Core::CPUState* State2, bool SupportsAVX) { + bool Matches = true; + uint64_t MatchMask = BaseConfig.OptionMatch & ~BaseConfig.OptionIgnore; + if (State1 && State2) { + Matches &= FEX::HarnessHelper::CompareStates(*State1, *State2, MatchMask, ConfigDumpGPRs(), SupportsAVX); + } + + if (BaseConfig.OptionRegDataCount > 0) { + static constexpr std::array OffsetArrayAVX = {{ + offsetof(FEXCore::Core::CPUState, rip), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBP]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSP]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R8]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R9]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R10]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R11]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R12]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R13]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R14]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R15]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[0][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[1][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[2][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[3][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[4][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[5][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[6][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[7][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[8][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[9][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[10][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[11][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[12][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[13][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[14][0]), + offsetof(FEXCore::Core::CPUState, xmm.avx.data[15][0]), + offsetof(FEXCore::Core::CPUState, gs_cached), + offsetof(FEXCore::Core::CPUState, fs_cached), + offsetof(FEXCore::Core::CPUState, mm[0][0]), + offsetof(FEXCore::Core::CPUState, mm[1][0]), + offsetof(FEXCore::Core::CPUState, mm[2][0]), + offsetof(FEXCore::Core::CPUState, mm[3][0]), + offsetof(FEXCore::Core::CPUState, mm[4][0]), + offsetof(FEXCore::Core::CPUState, mm[5][0]), + offsetof(FEXCore::Core::CPUState, mm[6][0]), + offsetof(FEXCore::Core::CPUState, mm[7][0]), + }}; + static constexpr std::array OffsetArraySSE = {{ + offsetof(FEXCore::Core::CPUState, rip), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBP]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSP]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R8]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R9]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R10]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R11]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R12]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R13]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R14]), + offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R15]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[0][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[1][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[2][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[3][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[4][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[5][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[6][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[7][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[8][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[9][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[10][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[11][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[12][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[13][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[14][0]), + offsetof(FEXCore::Core::CPUState, xmm.sse.data[15][0]), + offsetof(FEXCore::Core::CPUState, gs_cached), + offsetof(FEXCore::Core::CPUState, fs_cached), + offsetof(FEXCore::Core::CPUState, mm[0][0]), + offsetof(FEXCore::Core::CPUState, mm[1][0]), + offsetof(FEXCore::Core::CPUState, mm[2][0]), + offsetof(FEXCore::Core::CPUState, mm[3][0]), + offsetof(FEXCore::Core::CPUState, mm[4][0]), + offsetof(FEXCore::Core::CPUState, mm[5][0]), + offsetof(FEXCore::Core::CPUState, mm[6][0]), + offsetof(FEXCore::Core::CPUState, mm[7][0]), + }}; + + uintptr_t DataOffset = BaseConfig.OptionRegDataOffset; + for (unsigned i = 0; i < BaseConfig.OptionRegDataCount; ++i) { + RegDataStructBase* RegData = reinterpret_cast(RawConfigFile.data() + DataOffset); + [[maybe_unused]] std::bitset<64> RegFlags = RegData->RegKey; + assert(RegFlags.count() == 1 && "Must set reg data explicitly per register"); + + size_t NameIndex = FEXCore::FindFirstSetBit(RegData->RegKey) - 1; + auto Offset = SupportsAVX ? OffsetArrayAVX[NameIndex] : OffsetArraySSE[NameIndex]; + uint64_t* State1Data = reinterpret_cast(reinterpret_cast(State1) + Offset); + uint64_t* State2Data = reinterpret_cast(reinterpret_cast(State2) + Offset); + + const auto DumpGPRs = [this](const fextl::string& Name, uint64_t A, uint64_t B) { + if (!ConfigDumpGPRs()) { + return; + } + + fextl::fmt::print("{}: 0x{:016x} {} 0x{:016x} (Expected)\n", Name, A, A == B ? "==" : "!=", B); + }; + + const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { + DumpGPRs(Name, A, B); + Matches &= A == B; + }; + + for (size_t j = 0; j < RegData->RegDataCount; ++j) { + fextl::string Name; + if (NameIndex == 0) { // RIP + Name = "RIP"; + } else if (NameIndex >= 1 && NameIndex < 17) { + Name = fextl::fmt::format("GPR{}", NameIndex - 1); + } else if (NameIndex >= 17 && NameIndex < 33) { + Name = fextl::fmt::format("XMM[{}][{}]", NameIndex - 17, j); + } else if (NameIndex == 33) { + Name = "gs"; + } else if (NameIndex == 34) { + Name = "fs"; + } else if (NameIndex >= 35 && NameIndex < 43) { + Name = fextl::fmt::format("MM[{}][{}]", NameIndex - 35, j); + } + + if (State1) { + CheckGPRs(fextl::fmt::format("Core1: {}: ", Name), State1Data[j], RegData->RegValues[j]); + } + if (State2) { + CheckGPRs(fextl::fmt::format("Core2: {}: ", Name), State2Data[j], RegData->RegValues[j]); + } } + + // Get the correct data offset + DataOffset += sizeof(RegDataStructBase) + RegData->RegDataCount * 8; } } - - // GS - if (MatchMask & 1) { - CheckGPRs("GS", State1.gs_cached, State2.gs_cached); - } - MatchMask >>= 1; - - // FS - if (MatchMask & 1) { - CheckGPRs("FS", State1.fs_cached, State2.fs_cached); - } - return Matches; } - class ConfigLoader final { - public: - void Init(fextl::string const &ConfigFilename) { - FEXCore::FileLoading::LoadFile(RawConfigFile, ConfigFilename); - memcpy(&BaseConfig, RawConfigFile.data(), sizeof(ConfigStructBase)); - GetEnvironmentOptions(); + fextl::map GetMemoryRegions() { + fextl::map regions; + + uintptr_t DataOffset = BaseConfig.OptionMemoryRegionOffset; + for (unsigned i = 0; i < BaseConfig.OptionMemoryRegionCount; ++i) { + MemoryRegionBase* Region = reinterpret_cast(RawConfigFile.data() + DataOffset); + regions[Region->Region] = Region->Size; + + DataOffset += sizeof(MemoryRegionBase); } - fextl::vector> GetEnvironmentOptions() { - fextl::vector> Env{}; + return regions; + } - uintptr_t DataOffset = BaseConfig.OptionEnvOptionOffset; - for (unsigned i = 0; i < BaseConfig.OptionEnvOptionCount; ++i) { - // Environment variables are null terminated strings - std::string_view Key = RawConfigFile.data() + DataOffset; - std::string_view Value = RawConfigFile.data() + DataOffset + Key.size() + 1; - DataOffset += Key.size() + Value.size() + 2; - Env.emplace_back(Key, Value); - } - return Env; + void LoadMemory() { + uintptr_t DataOffset = BaseConfig.OptionMemDataOffset; + for (unsigned i = 0; i < BaseConfig.OptionMemDataCount; ++i) { + MemDataStructBase* MemData = reinterpret_cast(RawConfigFile.data() + DataOffset); + memcpy(reinterpret_cast(MemData->address), &MemData->data, MemData->length); + DataOffset += sizeof(MemDataStructBase) + MemData->length; } + } - bool CompareStates(FEXCore::Core::CPUState const* State1, FEXCore::Core::CPUState const* State2, bool SupportsAVX) { - bool Matches = true; - uint64_t MatchMask = BaseConfig.OptionMatch & ~BaseConfig.OptionIgnore; - if (State1 && State2) { - Matches &= FEX::HarnessHelper::CompareStates(*State1, *State2, MatchMask, ConfigDumpGPRs(), SupportsAVX); - } + bool Is64BitMode() const { + return BaseConfig.OptionMode == 1; + } - if (BaseConfig.OptionRegDataCount > 0) { - static constexpr std::array OffsetArrayAVX = {{ - offsetof(FEXCore::Core::CPUState, rip), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBP]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSP]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R8]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R9]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R10]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R11]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R12]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R13]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R14]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R15]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[0][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[1][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[2][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[3][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[4][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[5][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[6][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[7][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[8][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[9][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[10][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[11][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[12][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[13][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[14][0]), - offsetof(FEXCore::Core::CPUState, xmm.avx.data[15][0]), - offsetof(FEXCore::Core::CPUState, gs_cached), - offsetof(FEXCore::Core::CPUState, fs_cached), - offsetof(FEXCore::Core::CPUState, mm[0][0]), - offsetof(FEXCore::Core::CPUState, mm[1][0]), - offsetof(FEXCore::Core::CPUState, mm[2][0]), - offsetof(FEXCore::Core::CPUState, mm[3][0]), - offsetof(FEXCore::Core::CPUState, mm[4][0]), - offsetof(FEXCore::Core::CPUState, mm[5][0]), - offsetof(FEXCore::Core::CPUState, mm[6][0]), - offsetof(FEXCore::Core::CPUState, mm[7][0]), - }}; - static constexpr std::array OffsetArraySSE = {{ - offsetof(FEXCore::Core::CPUState, rip), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RBP]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSP]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R8]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R9]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R10]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R11]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R12]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R13]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R14]), - offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_R15]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[0][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[1][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[2][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[3][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[4][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[5][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[6][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[7][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[8][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[9][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[10][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[11][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[12][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[13][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[14][0]), - offsetof(FEXCore::Core::CPUState, xmm.sse.data[15][0]), - offsetof(FEXCore::Core::CPUState, gs_cached), - offsetof(FEXCore::Core::CPUState, fs_cached), - offsetof(FEXCore::Core::CPUState, mm[0][0]), - offsetof(FEXCore::Core::CPUState, mm[1][0]), - offsetof(FEXCore::Core::CPUState, mm[2][0]), - offsetof(FEXCore::Core::CPUState, mm[3][0]), - offsetof(FEXCore::Core::CPUState, mm[4][0]), - offsetof(FEXCore::Core::CPUState, mm[5][0]), - offsetof(FEXCore::Core::CPUState, mm[6][0]), - offsetof(FEXCore::Core::CPUState, mm[7][0]), - }}; + enum HostFeatures { + FEATURE_ANY = 0, + FEATURE_3DNOW = (1 << 0), + FEATURE_SSE4A = (1 << 1), + FEATURE_AVX = (1 << 2), + FEATURE_RAND = (1 << 3), + FEATURE_SHA = (1 << 4), + FEATURE_CLZERO = (1 << 5), + FEATURE_BMI1 = (1 << 6), + FEATURE_BMI2 = (1 << 7), + FEATURE_CLWB = (1 << 8), + FEATURE_LINUX = (1 << 9), + FEATURE_AVX2 = (1 << 10), + }; - uintptr_t DataOffset = BaseConfig.OptionRegDataOffset; - for (unsigned i = 0; i < BaseConfig.OptionRegDataCount; ++i) { - RegDataStructBase *RegData = reinterpret_cast(RawConfigFile.data() + DataOffset); - [[maybe_unused]] std::bitset<64> RegFlags = RegData->RegKey; - assert(RegFlags.count() == 1 && "Must set reg data explicitly per register"); + bool Requires3DNow() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_3DNOW; + } + bool RequiresSSE4A() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_SSE4A; + } + bool RequiresAVX() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_AVX; + } + bool RequiresAVX2() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_AVX2; + } + bool RequiresRAND() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_RAND; + } + bool RequiresSHA() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_SHA; + } + bool RequiresCLZERO() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_CLZERO; + } + bool RequiresBMI1() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_BMI1; + } + bool RequiresBMI2() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_BMI2; + } + bool RequiresCLWB() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_CLWB; + } + bool RequiresLinux() const { + return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_LINUX; + } - size_t NameIndex = FEXCore::FindFirstSetBit(RegData->RegKey) - 1; - auto Offset = SupportsAVX ? OffsetArrayAVX[NameIndex] : OffsetArraySSE[NameIndex]; - uint64_t *State1Data = reinterpret_cast(reinterpret_cast(State1) + Offset); - uint64_t *State2Data = reinterpret_cast(reinterpret_cast(State2) + Offset); +private: + FEX_CONFIG_OPT(ConfigDumpGPRs, DUMPGPRS); - const auto DumpGPRs = [this](const fextl::string& Name, uint64_t A, uint64_t B) { - if (!ConfigDumpGPRs()) { - return; - } + struct ConfigStructBase { + uint64_t OptionMatch; + uint64_t OptionIgnore; + uint64_t OptionStackSize; + uint64_t OptionEntryPoint; + uint32_t OptionABI; + uint32_t OptionMode; + uint32_t OptionHostFeatures; + uint32_t OptionMemoryRegionOffset; + uint32_t OptionMemoryRegionCount; + uint32_t OptionRegDataOffset; + uint32_t OptionRegDataCount; + uint32_t OptionMemDataOffset; + uint32_t OptionMemDataCount; + uint32_t OptionEnvOptionOffset; + uint32_t OptionEnvOptionCount; + uint8_t AdditionalData[]; + } FEX_PACKED; - fextl::fmt::print("{}: 0x{:016x} {} 0x{:016x} (Expected)\n", Name, A, A==B ? "==" : "!=", B); - }; + struct MemoryRegionBase { + uint64_t Region; + uint64_t Size; + } FEX_PACKED; - const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { - DumpGPRs(Name, A, B); - Matches &= A == B; - }; + struct RegDataStructBase { + uint32_t RegDataCount; + uint64_t RegKey; + uint64_t RegValues[]; + } FEX_PACKED; - for (size_t j = 0; j < RegData->RegDataCount; ++j) { - fextl::string Name; - if (NameIndex == 0) // RIP - Name = "RIP"; - else if (NameIndex >= 1 && NameIndex < 17) - Name = fextl::fmt::format("GPR{}", NameIndex - 1); - else if (NameIndex >= 17 && NameIndex < 33) - Name = fextl::fmt::format("XMM[{}][{}]", NameIndex - 17, j); - else if (NameIndex == 33) - Name = "gs"; - else if (NameIndex == 34) - Name ="fs"; - else if (NameIndex >= 35 && NameIndex < 43) { - Name = fextl::fmt::format("MM[{}][{}]", NameIndex - 35, j); - } + struct MemDataStructBase { + uint64_t address; + uint32_t length; + uint8_t data[]; + } FEX_PACKED; - if (State1) { - CheckGPRs(fextl::fmt::format("Core1: {}: ", Name), State1Data[j], RegData->RegValues[j]); - } - if (State2) { - CheckGPRs(fextl::fmt::format("Core2: {}: ", Name), State2Data[j], RegData->RegValues[j]); - } - } + fextl::vector RawConfigFile; + ConfigStructBase BaseConfig; +}; - // Get the correct data offset - DataOffset += sizeof(RegDataStructBase) + RegData->RegDataCount * 8; - } - } - return Matches; +class HarnessCodeLoader final : public FEX::CodeLoader { +public: + + HarnessCodeLoader(const fextl::string& Filename, const fextl::string& ConfigFilename) { + FEXCore::FileLoading::LoadFile(RawASMFile, Filename); + + Config.Init(ConfigFilename); + } + + uint64_t StackSize() const override { + return sysconf(_SC_PAGESIZE); + } + + uint64_t GetStackPointer() override { + if (Config.Is64BitMode()) { + return reinterpret_cast(FEXCore::Allocator::VirtualAlloc(StackSize())) + StackSize(); + } else { + uint64_t Result = reinterpret_cast(FEXCore::Allocator::VirtualAlloc(reinterpret_cast(STACK_OFFSET), StackSize())); + LOGMAN_THROW_AA_FMT(Result != ~0ULL, "Stack Pointer mmap failed"); + return Result + StackSize(); } + } - fextl::map GetMemoryRegions() { - fextl::map regions; + uint64_t DefaultRIP() const override { + return RIP; + } - uintptr_t DataOffset = BaseConfig.OptionMemoryRegionOffset; - for (unsigned i = 0; i < BaseConfig.OptionMemoryRegionCount; ++i) { - MemoryRegionBase *Region = reinterpret_cast(RawConfigFile.data() + DataOffset); - regions[Region->Region] = Region->Size; - - DataOffset += sizeof(MemoryRegionBase); - } - - return regions; - } - - void LoadMemory() { - uintptr_t DataOffset = BaseConfig.OptionMemDataOffset; - for (unsigned i = 0; i < BaseConfig.OptionMemDataCount; ++i) { - MemDataStructBase *MemData = reinterpret_cast(RawConfigFile.data() + DataOffset); - memcpy(reinterpret_cast(MemData->address), &MemData->data, MemData->length); - DataOffset += sizeof(MemDataStructBase) + MemData->length; - } - } - - bool Is64BitMode() const { return BaseConfig.OptionMode == 1; } - - enum HostFeatures { - FEATURE_ANY = 0, - FEATURE_3DNOW = (1 << 0), - FEATURE_SSE4A = (1 << 1), - FEATURE_AVX = (1 << 2), - FEATURE_RAND = (1 << 3), - FEATURE_SHA = (1 << 4), - FEATURE_CLZERO = (1 << 5), - FEATURE_BMI1 = (1 << 6), - FEATURE_BMI2 = (1 << 7), - FEATURE_CLWB = (1 << 8), - FEATURE_LINUX = (1 << 9), - FEATURE_AVX2 = (1 << 10), + bool MapMemory() { + bool LimitedSize = true; + auto DoMMap = [](uint64_t Address, size_t Size) -> void* { + void* Result = FEXCore::Allocator::VirtualAlloc(reinterpret_cast(Address), Size, true); + LOGMAN_THROW_AA_FMT(Result == reinterpret_cast(Address), "Map Memory mmap failed"); + return Result; }; - bool Requires3DNow() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_3DNOW; } - bool RequiresSSE4A() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_SSE4A; } - bool RequiresAVX() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_AVX; } - bool RequiresAVX2() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_AVX2; } - bool RequiresRAND() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_RAND; } - bool RequiresSHA() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_SHA; } - bool RequiresCLZERO() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_CLZERO; } - bool RequiresBMI1() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_BMI1; } - bool RequiresBMI2() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_BMI2; } - bool RequiresCLWB() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_CLWB; } - bool RequiresLinux() const { return BaseConfig.OptionHostFeatures & HostFeatures::FEATURE_LINUX; } + const auto AllocPageSize = sysconf(_SC_PAGESIZE); + if (LimitedSize) { + DoMMap(0xe000'0000, AllocPageSize * 10); - private: - FEX_CONFIG_OPT(ConfigDumpGPRs, DUMPGPRS); - - struct ConfigStructBase { - uint64_t OptionMatch; - uint64_t OptionIgnore; - uint64_t OptionStackSize; - uint64_t OptionEntryPoint; - uint32_t OptionABI; - uint32_t OptionMode; - uint32_t OptionHostFeatures; - uint32_t OptionMemoryRegionOffset; - uint32_t OptionMemoryRegionCount; - uint32_t OptionRegDataOffset; - uint32_t OptionRegDataCount; - uint32_t OptionMemDataOffset; - uint32_t OptionMemDataCount; - uint32_t OptionEnvOptionOffset; - uint32_t OptionEnvOptionCount; - uint8_t AdditionalData[]; - } FEX_PACKED; - - struct MemoryRegionBase { - uint64_t Region; - uint64_t Size; - } FEX_PACKED; - - struct RegDataStructBase { - uint32_t RegDataCount; - uint64_t RegKey; - uint64_t RegValues[]; - } FEX_PACKED; - - struct MemDataStructBase { - uint64_t address; - uint32_t length; - uint8_t data[]; - } FEX_PACKED; - - fextl::vector RawConfigFile; - ConfigStructBase BaseConfig; - }; - - class HarnessCodeLoader final : public FEX::CodeLoader { - public: - - HarnessCodeLoader(fextl::string const &Filename, fextl::string const &ConfigFilename) { - FEXCore::FileLoading::LoadFile(RawASMFile, Filename); - - Config.Init(ConfigFilename); + // SIB8 + // We test [-128, -126] (Bottom) + // We test [-8, 8] (Middle) + // We test [120, 127] (Top) + // Can fit in two pages + DoMMap(0xe800'0000 - AllocPageSize, AllocPageSize * 2); + } else { + // This is scratch memory location and SIB8 location + DoMMap(0xe000'0000, 0x1000'0000); + // This is for large SIB 32bit displacement testing + DoMMap(0x2'0000'0000, 0x1'0000'1000); } - uint64_t StackSize() const override { - return sysconf(_SC_PAGESIZE); - } - - uint64_t GetStackPointer() override { - if (Config.Is64BitMode()) { - return reinterpret_cast(FEXCore::Allocator::VirtualAlloc(StackSize())) + StackSize(); - } - else { - uint64_t Result = reinterpret_cast(FEXCore::Allocator::VirtualAlloc(reinterpret_cast(STACK_OFFSET), StackSize())); - LOGMAN_THROW_AA_FMT(Result != ~0ULL, "Stack Pointer mmap failed"); - return Result + StackSize(); - } - } - - uint64_t DefaultRIP() const override { - return RIP; - } - - bool MapMemory() { - bool LimitedSize = true; - auto DoMMap = [](uint64_t Address, size_t Size) -> void* { - void *Result = FEXCore::Allocator::VirtualAlloc(reinterpret_cast(Address), Size, true); - LOGMAN_THROW_AA_FMT(Result == reinterpret_cast(Address), "Map Memory mmap failed"); - return Result; - }; - - const auto AllocPageSize = sysconf(_SC_PAGESIZE); - if (LimitedSize) { - DoMMap(0xe000'0000, AllocPageSize * 10); - - // SIB8 - // We test [-128, -126] (Bottom) - // We test [-8, 8] (Middle) - // We test [120, 127] (Top) - // Can fit in two pages - DoMMap(0xe800'0000 - AllocPageSize, AllocPageSize * 2); - } - else { - // This is scratch memory location and SIB8 location - DoMMap(0xe000'0000, 0x1000'0000); - // This is for large SIB 32bit displacement testing - DoMMap(0x2'0000'0000, 0x1'0000'1000); - } - - // Map in the memory region for the test file + // Map in the memory region for the test file #ifndef _WIN32 - size_t Length = FEXCore::AlignUp(RawASMFile.size(), FEXCore::Utils::FEX_PAGE_SIZE); - auto ASMPtr = FEXCore::Allocator::VirtualAlloc(reinterpret_cast(Code_start_page), Length, true); + size_t Length = FEXCore::AlignUp(RawASMFile.size(), FEXCore::Utils::FEX_PAGE_SIZE); + auto ASMPtr = FEXCore::Allocator::VirtualAlloc(reinterpret_cast(Code_start_page), Length, true); #else - // Special magic DOS area that starts at 0x1'0000 - auto ASMPtr = FEXCore::Allocator::VirtualAlloc(reinterpret_cast(1), 0x110000 - 1, true); + // Special magic DOS area that starts at 0x1'0000 + auto ASMPtr = FEXCore::Allocator::VirtualAlloc(reinterpret_cast(1), 0x110000 - 1, true); #endif - LOGMAN_THROW_A_FMT((uint64_t)ASMPtr == Code_start_page, "Couldn't allocate code at expected page: 0x{:x} != 0x{:x}", (uint64_t)ASMPtr, Code_start_page); - memcpy(ASMPtr, RawASMFile.data(), RawASMFile.size()); - RIP = Code_start_page; + LOGMAN_THROW_A_FMT((uint64_t)ASMPtr == Code_start_page, "Couldn't allocate code at expected page: 0x{:x} != 0x{:x}", (uint64_t)ASMPtr, + Code_start_page); + memcpy(ASMPtr, RawASMFile.data(), RawASMFile.size()); + RIP = Code_start_page; - // Map the memory regions the test file asks for - for (auto& [region, size] : Config.GetMemoryRegions()) { - DoMMap(region, size); - } - - LoadMemory(); - - return true; + // Map the memory regions the test file asks for + for (auto& [region, size] : Config.GetMemoryRegions()) { + DoMMap(region, size); } - void LoadMemory() { - // Memory base here starts at the start location we passed back with GetLayout() - // This will write at [CODE_START_RANGE + 0, RawFile.size() ) - Config.LoadMemory(); - } + LoadMemory(); - fextl::vector> GetEnvironmentOptions() { - return Config.GetEnvironmentOptions(); - } + return true; + } - bool CompareStates(FEXCore::Core::CPUState const* State1, FEXCore::Core::CPUState const* State2, bool SupportsAVX) { - return Config.CompareStates(State1, State2, SupportsAVX); - } + void LoadMemory() { + // Memory base here starts at the start location we passed back with GetLayout() + // This will write at [CODE_START_RANGE + 0, RawFile.size() ) + Config.LoadMemory(); + } - bool Is64BitMode() const { return Config.Is64BitMode(); } - bool Requires3DNow() const { return Config.Requires3DNow(); } - bool RequiresSSE4A() const { return Config.RequiresSSE4A(); } - bool RequiresAVX() const { return Config.RequiresAVX(); } - bool RequiresAVX2() const { return Config.RequiresAVX2(); } - bool RequiresRAND() const { return Config.RequiresRAND(); } - bool RequiresSHA() const { return Config.RequiresSHA(); } - bool RequiresCLZERO() const { return Config.RequiresCLZERO(); } - bool RequiresBMI1() const { return Config.RequiresBMI1(); } - bool RequiresBMI2() const { return Config.RequiresBMI2(); } - bool RequiresCLWB() const { return Config.RequiresCLWB(); } - bool RequiresLinux() const { return Config.RequiresLinux(); } + fextl::vector> GetEnvironmentOptions() { + return Config.GetEnvironmentOptions(); + } - private: - constexpr static uint64_t STACK_OFFSET = 0xc000'0000; - // Zero is special case to know when we are done - uint64_t Code_start_page = 0x1'0000; - uint64_t RIP {}; + bool CompareStates(const FEXCore::Core::CPUState* State1, const FEXCore::Core::CPUState* State2, bool SupportsAVX) { + return Config.CompareStates(State1, State2, SupportsAVX); + } - fextl::vector RawASMFile; - ConfigLoader Config; - }; + bool Is64BitMode() const { + return Config.Is64BitMode(); + } + bool Requires3DNow() const { + return Config.Requires3DNow(); + } + bool RequiresSSE4A() const { + return Config.RequiresSSE4A(); + } + bool RequiresAVX() const { + return Config.RequiresAVX(); + } + bool RequiresAVX2() const { + return Config.RequiresAVX2(); + } + bool RequiresRAND() const { + return Config.RequiresRAND(); + } + bool RequiresSHA() const { + return Config.RequiresSHA(); + } + bool RequiresCLZERO() const { + return Config.RequiresCLZERO(); + } + bool RequiresBMI1() const { + return Config.RequiresBMI1(); + } + bool RequiresBMI2() const { + return Config.RequiresBMI2(); + } + bool RequiresCLWB() const { + return Config.RequiresCLWB(); + } + bool RequiresLinux() const { + return Config.RequiresLinux(); + } -} +private: + constexpr static uint64_t STACK_OFFSET = 0xc000'0000; + // Zero is special case to know when we are done + uint64_t Code_start_page = 0x1'0000; + uint64_t RIP {}; + + fextl::vector RawASMFile; + ConfigLoader Config; +}; + +} // namespace FEX::HarnessHelper diff --git a/Source/Tools/CommonTools/Linux/Utils/ELFContainer.cpp b/Source/Tools/CommonTools/Linux/Utils/ELFContainer.cpp index d6f4a8ff7..a6c3a0d86 100644 --- a/Source/Tools/CommonTools/Linux/Utils/ELFContainer.cpp +++ b/Source/Tools/CommonTools/Linux/Utils/ELFContainer.cpp @@ -26,31 +26,27 @@ $end_info$ namespace ELFLoader { - static ELFContainer::ELFType CheckELFType(uint8_t* Data) { - if (Data[EI_MAG0] != ELFMAG0 || - Data[EI_MAG1] != ELFMAG1 || - Data[EI_MAG2] != ELFMAG2 || - Data[EI_MAG3] != ELFMAG3) { - return ELFContainer::ELFType::TYPE_NONE; - } - - if (Data[EI_CLASS] == ELFCLASS32) { - Elf32_Ehdr *Header = reinterpret_cast(Data); - if (Header->e_machine == EM_386) { - return ELFContainer::ELFType::TYPE_X86_32; - } - } - else if (Data[EI_CLASS] == ELFCLASS64) { - Elf64_Ehdr *Header = reinterpret_cast(Data); - if (Header->e_machine == EM_X86_64) { - return ELFContainer::ELFType::TYPE_X86_64; - } - } - - return ELFContainer::ELFType::TYPE_OTHER_ELF; +static ELFContainer::ELFType CheckELFType(uint8_t* Data) { + if (Data[EI_MAG0] != ELFMAG0 || Data[EI_MAG1] != ELFMAG1 || Data[EI_MAG2] != ELFMAG2 || Data[EI_MAG3] != ELFMAG3) { + return ELFContainer::ELFType::TYPE_NONE; } -ELFContainer::ELFType ELFContainer::GetELFType(fextl::string const &Filename) { + if (Data[EI_CLASS] == ELFCLASS32) { + Elf32_Ehdr* Header = reinterpret_cast(Data); + if (Header->e_machine == EM_386) { + return ELFContainer::ELFType::TYPE_X86_32; + } + } else if (Data[EI_CLASS] == ELFCLASS64) { + Elf64_Ehdr* Header = reinterpret_cast(Data); + if (Header->e_machine == EM_X86_64) { + return ELFContainer::ELFType::TYPE_X86_64; + } + } + + return ELFContainer::ELFType::TYPE_OTHER_ELF; +} + +ELFContainer::ELFType ELFContainer::GetELFType(const fextl::string& Filename) { // Open the Filename to determine if it is a shebang file. int FD = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); if (FD == -1) { @@ -69,7 +65,7 @@ ELFContainer::ELFType ELFContainer::GetELFType(int FD) { // We can't use dup since that makes the FD have the same underlying state backing both FDs. // We need to first determine the file size through fstat. - struct stat buf{}; + struct stat buf {}; if (fstat(FD, &buf) == -1) { // Couldn't get size. return ELFType::TYPE_NONE; @@ -94,7 +90,7 @@ ELFContainer::ELFType ELFContainer::GetELFType(int FD) { return CheckELFType(reinterpret_cast(&RawFile.at(0))); } -ELFContainer::ELFContainer(fextl::string const &Filename, fextl::string const &RootFS, bool CustomInterpreter) { +ELFContainer::ELFContainer(const fextl::string& Filename, const fextl::string& RootFS, bool CustomInterpreter) { Loaded = true; if (!LoadELF(Filename)) { LogMan::Msg::EFmt("Couldn't Load ELF file"); @@ -106,16 +102,15 @@ ELFContainer::ELFContainer(fextl::string const &Filename, fextl::string const &R // If we we are dynamic application then we have an interpreter program header // We need to load that ELF instead if it exists // We are no longer dynamic since we are executing the interpreter - const char *RawString{}; + const char* RawString {}; if (Mode == MODE_32BIT) { RawString = &RawFile.at(InterpreterHeader._32->p_offset); - } - else { + } else { RawString = &RawFile.at(InterpreterHeader._64->p_offset); } fextl::string RootFSLink = RootFS + RawString; char Filename[PATH_MAX]; - while(FHU::Symlinks::IsSymlink(RootFSLink)) { + while (FHU::Symlinks::IsSymlink(RootFSLink)) { // Do some special handling if the RootFS's linker is a symlink // Ubuntu's rootFS by default provides an absolute location symlink to the linker // Resolve this around back to the rootfs @@ -123,22 +118,19 @@ ELFContainer::ELFContainer(fextl::string const &Filename, fextl::string const &R if (FHU::Filesystem::IsAbsolute(SymlinkTarget)) { RootFSLink = RootFS; RootFSLink += SymlinkTarget; - } - else { + } else { break; } } if (LoadELF(RootFSLink)) { // Found the interpreter in the rootfs - } - else if (!LoadELF(RawString)) { + } else if (!LoadELF(RawString)) { LogMan::Msg::EFmt("Failed to find guest ELF's interpter '{}'", RawString); LogMan::Msg::EFmt("Did you forget to set an x86 rootfs? Currently '{}'", RootFS); Loaded = false; return; } - } - else if (InterpreterHeader._64) { + } else if (InterpreterHeader._64) { GetDynamicLibs(); } @@ -148,14 +140,14 @@ ELFContainer::ELFContainer(fextl::string const &Filename, fextl::string const &R // Print Information // PrintHeader(); - //PrintSectionHeaders(); - //PrintProgramHeaders(); - //PrintSymbolTable(); - //PrintRelocationTable(); - //PrintInitArray(); - //PrintDynamicTable(); + // PrintSectionHeaders(); + // PrintProgramHeaders(); + // PrintSymbolTable(); + // PrintRelocationTable(); + // PrintInitArray(); + // PrintDynamicTable(); - //LOGMAN_THROW_AA_FMT(InterpreterHeader == nullptr, "Can only handle static programs"); + // LOGMAN_THROW_AA_FMT(InterpreterHeader == nullptr, "Can only handle static programs"); } ELFContainer::~ELFContainer() { @@ -168,7 +160,7 @@ ELFContainer::~ELFContainer() { RawFile.clear(); } -bool ELFContainer::LoadELF(fextl::string const &Filename) { +bool ELFContainer::LoadELF(const fextl::string& Filename) { if (!FEXCore::FileLoading::LoadFile(RawFile, Filename)) { return false; } @@ -178,20 +170,16 @@ bool ELFContainer::LoadELF(fextl::string const &Filename) { SectionHeaders.clear(); ProgramHeaders.clear(); - uint8_t *Ident = reinterpret_cast(&RawFile.at(0)); + uint8_t* Ident = reinterpret_cast(&RawFile.at(0)); - if (Ident[EI_MAG0] != ELFMAG0 || - Ident[EI_MAG1] != ELFMAG1 || - Ident[EI_MAG2] != ELFMAG2 || - Ident[EI_MAG3] != ELFMAG3) { + if (Ident[EI_MAG0] != ELFMAG0 || Ident[EI_MAG1] != ELFMAG1 || Ident[EI_MAG2] != ELFMAG2 || Ident[EI_MAG3] != ELFMAG3) { LogMan::Msg::EFmt("ELF missing magic cookie"); return false; } if (Ident[EI_CLASS] == ELFCLASS32) { return LoadELF_32(); - } - else if (Ident[EI_CLASS] == ELFCLASS64) { + } else if (Ident[EI_CLASS] == ELFCLASS64) { return LoadELF_64(); } @@ -202,8 +190,7 @@ bool ELFContainer::LoadELF(fextl::string const &Filename) { bool ELFContainer::LoadELF_32() { Mode = MODE_32BIT; - memcpy(&Header, reinterpret_cast(&RawFile.at(0)), - sizeof(Elf32_Ehdr)); + memcpy(&Header, reinterpret_cast(&RawFile.at(0)), sizeof(Elf32_Ehdr)); LOGMAN_THROW_AA_FMT(Header._32.e_phentsize == sizeof(Elf32_Phdr), "PH Entry size wasn't correct size"); LOGMAN_THROW_AA_FMT(Header._32.e_shentsize == sizeof(Elf32_Shdr), "PH Entry size wasn't correct size"); @@ -215,10 +202,8 @@ bool ELFContainer::LoadELF_32() { SectionHeaders.resize(Header._32.e_shnum); ProgramHeaders.resize(Header._32.e_phnum); - Elf32_Shdr *RawShdrs = - reinterpret_cast(&RawFile.at(Header._32.e_shoff)); - Elf32_Phdr *RawPhdrs = - reinterpret_cast(&RawFile.at(Header._32.e_phoff)); + Elf32_Shdr* RawShdrs = reinterpret_cast(&RawFile.at(Header._32.e_shoff)); + Elf32_Phdr* RawPhdrs = reinterpret_cast(&RawFile.at(Header._32.e_phoff)); for (uint32_t i = 0; i < Header._32.e_shnum; ++i) { SectionHeaders[i]._32 = &RawShdrs[i]; @@ -228,7 +213,7 @@ bool ELFContainer::LoadELF_32() { ProgramHeaders[i]._32 = &RawPhdrs[i]; if (ProgramHeaders[i]._32->p_type == PT_INTERP) { InterpreterHeader = ProgramHeaders[i]; - DynamicLinker = reinterpret_cast(&RawFile.at(InterpreterHeader._32->p_offset)); + DynamicLinker = reinterpret_cast(&RawFile.at(InterpreterHeader._32->p_offset)); } } @@ -243,8 +228,7 @@ bool ELFContainer::LoadELF_32() { bool ELFContainer::LoadELF_64() { Mode = MODE_64BIT; - memcpy(&Header, reinterpret_cast(&RawFile.at(0)), - sizeof(Elf64_Ehdr)); + memcpy(&Header, reinterpret_cast(&RawFile.at(0)), sizeof(Elf64_Ehdr)); LOGMAN_THROW_AA_FMT(Header._64.e_phentsize == 56, "PH Entry size wasn't 56"); LOGMAN_THROW_AA_FMT(Header._64.e_shentsize == 64, "PH Entry size wasn't 64"); @@ -256,10 +240,8 @@ bool ELFContainer::LoadELF_64() { SectionHeaders.resize(Header._64.e_shnum); ProgramHeaders.resize(Header._64.e_phnum); - Elf64_Shdr *RawShdrs = - reinterpret_cast(&RawFile.at(Header._64.e_shoff)); - Elf64_Phdr *RawPhdrs = - reinterpret_cast(&RawFile.at(Header._64.e_phoff)); + Elf64_Shdr* RawShdrs = reinterpret_cast(&RawFile.at(Header._64.e_shoff)); + Elf64_Phdr* RawPhdrs = reinterpret_cast(&RawFile.at(Header._64.e_phoff)); for (uint32_t i = 0; i < Header._64.e_shnum; ++i) { SectionHeaders[i]._64 = &RawShdrs[i]; @@ -269,7 +251,7 @@ bool ELFContainer::LoadELF_64() { ProgramHeaders[i]._64 = &RawPhdrs[i]; if (ProgramHeaders[i]._64->p_type == PT_INTERP) { InterpreterHeader = ProgramHeaders[i]; - DynamicLinker = reinterpret_cast(&RawFile.at(InterpreterHeader._64->p_offset)); + DynamicLinker = reinterpret_cast(&RawFile.at(InterpreterHeader._64->p_offset)); } } @@ -284,9 +266,9 @@ bool ELFContainer::LoadELF_64() { void ELFContainer::WriteLoadableSections(MemoryWriter Writer, uint64_t Offset) { if (Mode == MODE_32BIT) { for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) { - Elf32_Phdr const *hdr = ProgramHeaders.at(i)._32; + const Elf32_Phdr* hdr = ProgramHeaders.at(i)._32; if (hdr->p_type == PT_LOAD) { - //LogMan::Msg::DFmt("PT_LOAD: Base: {} Offset: [0x{:x}, 0x{:x})", Offset, hdr->p_paddr, hdr->p_filesz); + // LogMan::Msg::DFmt("PT_LOAD: Base: {} Offset: [0x{:x}, 0x{:x})", Offset, hdr->p_paddr, hdr->p_filesz); Writer(&RawFile.at(hdr->p_offset), Offset + hdr->p_paddr, hdr->p_filesz); } @@ -294,10 +276,9 @@ void ELFContainer::WriteLoadableSections(MemoryWriter Writer, uint64_t Offset) { Writer(&RawFile.at(hdr->p_offset), Offset + hdr->p_paddr, hdr->p_filesz); } } - } - else { + } else { for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) { - Elf64_Phdr const *hdr = ProgramHeaders.at(i)._64; + const Elf64_Phdr* hdr = ProgramHeaders.at(i)._64; if (hdr->p_type == PT_LOAD) { Writer(&RawFile.at(hdr->p_offset), Offset + hdr->p_paddr, hdr->p_filesz); } @@ -309,27 +290,32 @@ void ELFContainer::WriteLoadableSections(MemoryWriter Writer, uint64_t Offset) { } } -ELFSymbol const *ELFContainer::GetSymbol(char const *Name) { +const ELFSymbol* ELFContainer::GetSymbol(const char* Name) { auto Sym = SymbolMap.find(Name); - if (Sym == SymbolMap.end()) + if (Sym == SymbolMap.end()) { return nullptr; + } return Sym->second; } -ELFSymbol const *ELFContainer::GetSymbol(uint64_t Address) { +const ELFSymbol* ELFContainer::GetSymbol(uint64_t Address) { auto Sym = SymbolMapByAddress.find(Address); - if (Sym == SymbolMapByAddress.end()) + if (Sym == SymbolMapByAddress.end()) { return nullptr; + } return Sym->second; } -ELFSymbol const *ELFContainer::GetSymbolInRange(RangeType Address) { +const ELFSymbol* ELFContainer::GetSymbolInRange(RangeType Address) { auto Sym = SymbolMapByAddress.upper_bound(Address.first); - if (Sym != SymbolMapByAddress.begin()) + if (Sym != SymbolMapByAddress.begin()) { --Sym; - if (Sym == SymbolMapByAddress.end()) + } + if (Sym == SymbolMapByAddress.end()) { return nullptr; + } - if ((Sym->second->Address + Sym->second->Size) < Address.first) + if ((Sym->second->Address + Sym->second->Size) < Address.first) { return nullptr; + } return Sym->second; } @@ -341,7 +327,7 @@ void ELFContainer::CalculateMemoryLayouts() { if (Mode == MODE_32BIT) { for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) { - Elf32_Phdr *hdr = ProgramHeaders.at(i)._32; + Elf32_Phdr* hdr = ProgramHeaders.at(i)._32; if (hdr->p_memsz > 0) { MinPhysAddr = std::min(MinPhysAddr, static_cast(hdr->p_paddr)); MaxPhysAddr = std::max(MaxPhysAddr, static_cast(hdr->p_paddr) + hdr->p_memsz); @@ -350,10 +336,9 @@ void ELFContainer::CalculateMemoryLayouts() { TLSHeader._32 = hdr; } } - } - else { + } else { for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) { - Elf64_Phdr *hdr = ProgramHeaders.at(i)._64; + Elf64_Phdr* hdr = ProgramHeaders.at(i)._64; // Many elfs have program region labeled .GNU_STACK which is empty and has a null address. // It's used to mark the memory protection flags of the stack. @@ -384,16 +369,16 @@ void ELFContainer::CalculateMemoryLayouts() { void ELFContainer::CalculateSymbols() { // Find the symbol table if (Mode == MODE_32BIT) { - Elf32_Shdr const *SymTabHeader{nullptr}; - Elf32_Shdr const *StringTableHeader{nullptr}; - char const *StrTab{nullptr}; + const Elf32_Shdr* SymTabHeader {nullptr}; + const Elf32_Shdr* StringTableHeader {nullptr}; + const char* StrTab {nullptr}; - Elf32_Shdr const *DynSymTabHeader{nullptr}; - Elf32_Shdr const *DynStringTableHeader{nullptr}; - char const *DynStrTab{nullptr}; + const Elf32_Shdr* DynSymTabHeader {nullptr}; + const Elf32_Shdr* DynStringTableHeader {nullptr}; + const char* DynStrTab {nullptr}; for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf32_Shdr const *hdr = SectionHeaders.at(i)._32; + const Elf32_Shdr* hdr = SectionHeaders.at(i)._32; if (hdr->sh_type == SHT_SYMTAB) { SymTabHeader = hdr; break; @@ -401,7 +386,7 @@ void ELFContainer::CalculateSymbols() { } for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf32_Shdr const *hdr = SectionHeaders.at(i)._32; + const Elf32_Shdr* hdr = SectionHeaders.at(i)._32; if (hdr->sh_type == SHT_DYNSYM) { DynSymTabHeader = hdr; break; @@ -416,10 +401,8 @@ void ELFContainer::CalculateSymbols() { uint64_t NumSymTabSymbols = 0; uint64_t NumDynSymSymbols = 0; if (SymTabHeader) { - LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), - "Symbol table string table section is wrong"); - LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf32_Sym), - "Entry size doesn't match symbol entry"); + LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), "Symbol table string table section is wrong"); + LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf32_Sym), "Entry size doesn't match symbol entry"); StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32; StrTab = &RawFile.at(StringTableHeader->sh_offset); @@ -427,10 +410,8 @@ void ELFContainer::CalculateSymbols() { } if (DynSymTabHeader) { - LOGMAN_THROW_A_FMT(DynSymTabHeader->sh_link < SectionHeaders.size(), - "Symbol table string table section is wrong"); - LOGMAN_THROW_AA_FMT(DynSymTabHeader->sh_entsize == sizeof(Elf32_Sym), - "Entry size doesn't match symbol entry"); + LOGMAN_THROW_A_FMT(DynSymTabHeader->sh_link < SectionHeaders.size(), "Symbol table string table section is wrong"); + LOGMAN_THROW_AA_FMT(DynSymTabHeader->sh_entsize == sizeof(Elf32_Sym), "Entry size doesn't match symbol entry"); DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._32; DynStrTab = &RawFile.at(DynStringTableHeader->sh_offset); @@ -442,13 +423,11 @@ void ELFContainer::CalculateSymbols() { Symbols.resize(NumSymbols); for (uint64_t i = 0; i < NumSymTabSymbols; ++i) { uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize; - Elf32_Sym const *Symbol = - reinterpret_cast(&RawFile.at(offset)); - if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && - Symbol->st_value != 0) { - char const * Name = &StrTab[Symbol->st_name]; + const Elf32_Sym* Symbol = reinterpret_cast(&RawFile.at(offset)); + if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && Symbol->st_value != 0) { + const char* Name = &StrTab[Symbol->st_name]; if (Name[0] != '\0') { - ELFSymbol *DefinedSymbol = &Symbols.at(i); + ELFSymbol* DefinedSymbol = &Symbols.at(i); DefinedSymbol->FileOffset = offset; DefinedSymbol->Address = Symbol->st_value; DefinedSymbol->Size = Symbol->st_size; @@ -465,13 +444,11 @@ void ELFContainer::CalculateSymbols() { for (uint64_t i = 0; i < NumDynSymSymbols; ++i) { uint64_t offset = DynSymTabHeader->sh_offset + i * DynSymTabHeader->sh_entsize; - Elf32_Sym const *Symbol = - reinterpret_cast(&RawFile.at(offset)); - if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && - Symbol->st_value != 0) { - char const * Name = &DynStrTab[Symbol->st_name]; + const Elf32_Sym* Symbol = reinterpret_cast(&RawFile.at(offset)); + if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && Symbol->st_value != 0) { + const char* Name = &DynStrTab[Symbol->st_name]; if (Name[0] != '\0') { - ELFSymbol *DefinedSymbol = &Symbols.at(NumSymTabSymbols + i); + ELFSymbol* DefinedSymbol = &Symbols.at(NumSymTabSymbols + i); DefinedSymbol->FileOffset = offset; DefinedSymbol->Address = Symbol->st_value; DefinedSymbol->Size = Symbol->st_size; @@ -486,10 +463,10 @@ void ELFContainer::CalculateSymbols() { } } - Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32; - char const *SHStrings = &RawFile.at(StrHeader->sh_offset); + const Elf32_Shdr* StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf32_Shdr const *hdr = SectionHeaders.at(i)._32; + const Elf32_Shdr* hdr = SectionHeaders.at(i)._32; if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) { auto eh_frame_hdr = &RawFile.at(hdr->sh_offset); // we only handle this specific unwind table encoding @@ -506,7 +483,7 @@ void ELFContainer::CalculateSymbols() { int32_t fde; }; - entry *Table = (entry*)(eh_frame_hdr+12); + entry* Table = (entry*)(eh_frame_hdr + 12); for (int f = 0; f < fde_count; f++) { uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset); UnwindEntries.push_back(Entry); @@ -515,18 +492,17 @@ void ELFContainer::CalculateSymbols() { break; } } - } - else { - Elf64_Shdr const *SymTabHeader{nullptr}; - Elf64_Shdr const *StringTableHeader{nullptr}; - char const *StrTab{nullptr}; + } else { + const Elf64_Shdr* SymTabHeader {nullptr}; + const Elf64_Shdr* StringTableHeader {nullptr}; + const char* StrTab {nullptr}; - Elf64_Shdr const *DynSymTabHeader{nullptr}; - Elf64_Shdr const *DynStringTableHeader{nullptr}; - char const *DynStrTab{nullptr}; + const Elf64_Shdr* DynSymTabHeader {nullptr}; + const Elf64_Shdr* DynStringTableHeader {nullptr}; + const char* DynStrTab {nullptr}; for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders.at(i)._64; + const Elf64_Shdr* hdr = SectionHeaders.at(i)._64; if (hdr->sh_type == SHT_SYMTAB) { SymTabHeader = hdr; break; @@ -534,7 +510,7 @@ void ELFContainer::CalculateSymbols() { } for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders.at(i)._64; + const Elf64_Shdr* hdr = SectionHeaders.at(i)._64; if (hdr->sh_type == SHT_DYNSYM) { DynSymTabHeader = hdr; break; @@ -549,10 +525,8 @@ void ELFContainer::CalculateSymbols() { uint64_t NumSymTabSymbols = 0; uint64_t NumDynSymSymbols = 0; if (SymTabHeader) { - LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), - "Symbol table string table section is wrong"); - LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf64_Sym), - "Entry size doesn't match symbol entry"); + LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), "Symbol table string table section is wrong"); + LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf64_Sym), "Entry size doesn't match symbol entry"); StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64; StrTab = &RawFile.at(StringTableHeader->sh_offset); @@ -560,10 +534,8 @@ void ELFContainer::CalculateSymbols() { } if (DynSymTabHeader) { - LOGMAN_THROW_A_FMT(DynSymTabHeader->sh_link < SectionHeaders.size(), - "Symbol table string table section is wrong"); - LOGMAN_THROW_AA_FMT(DynSymTabHeader->sh_entsize == sizeof(Elf64_Sym), - "Entry size doesn't match symbol entry"); + LOGMAN_THROW_A_FMT(DynSymTabHeader->sh_link < SectionHeaders.size(), "Symbol table string table section is wrong"); + LOGMAN_THROW_AA_FMT(DynSymTabHeader->sh_entsize == sizeof(Elf64_Sym), "Entry size doesn't match symbol entry"); DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._64; DynStrTab = &RawFile.at(DynStringTableHeader->sh_offset); @@ -575,13 +547,11 @@ void ELFContainer::CalculateSymbols() { Symbols.resize(NumSymbols); for (uint64_t i = 0; i < NumSymTabSymbols; ++i) { uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize; - Elf64_Sym const *Symbol = - reinterpret_cast(&RawFile.at(offset)); - if (ELF64_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && - Symbol->st_value != 0) { - char const * Name = &StrTab[Symbol->st_name]; + const Elf64_Sym* Symbol = reinterpret_cast(&RawFile.at(offset)); + if (ELF64_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && Symbol->st_value != 0) { + const char* Name = &StrTab[Symbol->st_name]; if (Name[0] != '\0') { - ELFSymbol *DefinedSymbol = &Symbols.at(i); + ELFSymbol* DefinedSymbol = &Symbols.at(i); DefinedSymbol->FileOffset = offset; DefinedSymbol->Address = Symbol->st_value; DefinedSymbol->Size = Symbol->st_size; @@ -598,13 +568,11 @@ void ELFContainer::CalculateSymbols() { for (uint64_t i = 0; i < NumDynSymSymbols; ++i) { uint64_t offset = DynSymTabHeader->sh_offset + i * DynSymTabHeader->sh_entsize; - Elf64_Sym const *Symbol = - reinterpret_cast(&RawFile.at(offset)); - if (ELF64_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && - Symbol->st_value != 0) { - char const * Name = &DynStrTab[Symbol->st_name]; + const Elf64_Sym* Symbol = reinterpret_cast(&RawFile.at(offset)); + if (ELF64_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && Symbol->st_value != 0) { + const char* Name = &DynStrTab[Symbol->st_name]; if (Name[0] != '\0') { - ELFSymbol *DefinedSymbol = &Symbols.at(NumSymTabSymbols + i); + ELFSymbol* DefinedSymbol = &Symbols.at(NumSymTabSymbols + i); DefinedSymbol->FileOffset = offset; DefinedSymbol->Address = Symbol->st_value; DefinedSymbol->Size = Symbol->st_size; @@ -619,10 +587,10 @@ void ELFContainer::CalculateSymbols() { } } - Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64; - char const *SHStrings = &RawFile.at(StrHeader->sh_offset); + const Elf64_Shdr* StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders.at(i)._64; + const Elf64_Shdr* hdr = SectionHeaders.at(i)._64; if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) { auto eh_frame_hdr = &RawFile.at(hdr->sh_offset); // we only handle this specific unwind table encoding @@ -639,7 +607,7 @@ void ELFContainer::CalculateSymbols() { int32_t fde; }; - entry *Table = (entry*)(eh_frame_hdr+12); + entry* Table = (entry*)(eh_frame_hdr + 12); for (int f = 0; f < fde_count; f++) { uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset); UnwindEntries.push_back(Entry); @@ -654,33 +622,36 @@ void ELFContainer::CalculateSymbols() { void ELFContainer::GetDynamicLibs() { if (Mode == MODE_32BIT) { for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf32_Shdr const *hdr = SectionHeaders.at(i)._32; + const Elf32_Shdr* hdr = SectionHeaders.at(i)._32; if (hdr->sh_type == SHT_DYNAMIC) { - Elf32_Shdr const *StrHeader = SectionHeaders.at(hdr->sh_link)._32; - char const *SHStrings = &RawFile.at(StrHeader->sh_offset); + const Elf32_Shdr* StrHeader = SectionHeaders.at(hdr->sh_link)._32; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; i < Entries; ++j) { - Elf32_Dyn const *Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); - if (Dynamic->d_tag == DT_NULL) break; + const Elf32_Dyn* Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); + if (Dynamic->d_tag == DT_NULL) { + break; + } if (Dynamic->d_tag == DT_NEEDED) { NecessaryLibs.emplace_back(&SHStrings[Dynamic->d_un.d_val]); } } } } - } - else { + } else { for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders.at(i)._64; + const Elf64_Shdr* hdr = SectionHeaders.at(i)._64; if (hdr->sh_type == SHT_DYNAMIC) { - Elf64_Shdr const *StrHeader = SectionHeaders.at(hdr->sh_link)._64; - char const *SHStrings = &RawFile.at(StrHeader->sh_offset); + const Elf64_Shdr* StrHeader = SectionHeaders.at(hdr->sh_link)._64; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; i < Entries; ++j) { - Elf64_Dyn const *Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); - if (Dynamic->d_tag == DT_NULL) break; + const Elf64_Dyn* Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); + if (Dynamic->d_tag == DT_NULL) { + break; + } if (Dynamic->d_tag == DT_NEEDED) { NecessaryLibs.emplace_back(&SHStrings[Dynamic->d_un.d_val]); } @@ -691,7 +662,7 @@ void ELFContainer::GetDynamicLibs() { } void ELFContainer::AddSymbols(SymbolAdder Adder) { - for (auto &Sym : Symbols) { + for (auto& Sym : Symbols) { if (Sym.FileOffset) { Adder(&Sym); } @@ -718,8 +689,7 @@ void ELFContainer::PrintHeader() const { LogMan::Msg::IFmt("PH Entry Size: {}", Header._32.e_phentsize); LogMan::Msg::IFmt("SH Entry Size: {}", Header._32.e_shentsize); LogMan::Msg::IFmt("SH Str Index: {}", Header._32.e_shstrndx); - } - else { + } else { LogMan::Msg::IFmt("Type: {}", Header._64.e_type); LogMan::Msg::IFmt("Machine: {}", Header._64.e_machine); LogMan::Msg::IFmt("Version: {}", Header._64.e_version); @@ -738,12 +708,11 @@ void ELFContainer::PrintHeader() const { void ELFContainer::PrintSectionHeaders() const { if (Mode == MODE_32BIT) { - LOGMAN_THROW_A_FMT(Header._32.e_shstrndx < SectionHeaders.size(), - "String index section is wrong index!"); - Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32; - char const *SHStrings = &RawFile.at(StrHeader->sh_offset); + LOGMAN_THROW_A_FMT(Header._32.e_shstrndx < SectionHeaders.size(), "String index section is wrong index!"); + const Elf32_Shdr* StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); for (size_t i = 0; i < SectionHeaders.size(); ++i) { - Elf32_Shdr const *hdr = SectionHeaders[i]._32; + const Elf32_Shdr* hdr = SectionHeaders[i]._32; LogMan::Msg::IFmt("Index: {}", i); LogMan::Msg::IFmt("Name: {}", &SHStrings[hdr->sh_name]); LogMan::Msg::IFmt("Type: {}", hdr->sh_type); @@ -756,14 +725,12 @@ void ELFContainer::PrintSectionHeaders() const { LogMan::Msg::IFmt("AddrAlign: {}", hdr->sh_addralign); LogMan::Msg::IFmt("Entry Size: {}", hdr->sh_entsize); } - } - else { - LOGMAN_THROW_A_FMT(Header._64.e_shstrndx < SectionHeaders.size(), - "String index section is wrong index!"); - Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64; - char const *SHStrings = &RawFile.at(StrHeader->sh_offset); + } else { + LOGMAN_THROW_A_FMT(Header._64.e_shstrndx < SectionHeaders.size(), "String index section is wrong index!"); + const Elf64_Shdr* StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); for (size_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders[i]._64; + const Elf64_Shdr* hdr = SectionHeaders[i]._64; LogMan::Msg::IFmt("Index: {}", i); LogMan::Msg::IFmt("Name: {}", &SHStrings[hdr->sh_name]); LogMan::Msg::IFmt("Type: {}", hdr->sh_type); @@ -781,10 +748,9 @@ void ELFContainer::PrintSectionHeaders() const { void ELFContainer::PrintProgramHeaders() const { if (Mode == MODE_32BIT) { - LOGMAN_THROW_A_FMT(Header._32.e_shstrndx < SectionHeaders.size(), - "String index section is wrong index!"); + LOGMAN_THROW_A_FMT(Header._32.e_shstrndx < SectionHeaders.size(), "String index section is wrong index!"); for (size_t i = 0; i < ProgramHeaders.size(); ++i) { - Elf32_Phdr const *hdr = ProgramHeaders[i]._32; + const Elf32_Phdr* hdr = ProgramHeaders[i]._32; LogMan::Msg::IFmt("Type: {}", hdr->p_type); LogMan::Msg::IFmt("Flags: {}", hdr->p_flags); LogMan::Msg::IFmt("Offset: {}", hdr->p_offset); @@ -794,12 +760,10 @@ void ELFContainer::PrintProgramHeaders() const { LogMan::Msg::IFmt("MemSize: {}", hdr->p_memsz); LogMan::Msg::IFmt("Align: {}", hdr->p_align); } - } - else { - LOGMAN_THROW_A_FMT(Header._64.e_shstrndx < SectionHeaders.size(), - "String index section is wrong index!"); + } else { + LOGMAN_THROW_A_FMT(Header._64.e_shstrndx < SectionHeaders.size(), "String index section is wrong index!"); for (size_t i = 0; i < ProgramHeaders.size(); ++i) { - Elf64_Phdr const *hdr = ProgramHeaders[i]._64; + const Elf64_Phdr* hdr = ProgramHeaders[i]._64; LogMan::Msg::IFmt("Type: {}", hdr->p_type); LogMan::Msg::IFmt("Flags: {}", hdr->p_flags); LogMan::Msg::IFmt("Offset: {}", hdr->p_offset); @@ -815,11 +779,11 @@ void ELFContainer::PrintProgramHeaders() const { void ELFContainer::PrintSymbolTable() const { if (Mode == MODE_32BIT) { // Find the symbol table - Elf32_Shdr const *SymTabHeader{nullptr}; - Elf32_Shdr const *StringTableHeader{nullptr}; - char const *StrTab{nullptr}; + const Elf32_Shdr* SymTabHeader {nullptr}; + const Elf32_Shdr* StringTableHeader {nullptr}; + const char* StrTab {nullptr}; for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf32_Shdr const *hdr = SectionHeaders.at(i)._32; + const Elf32_Shdr* hdr = SectionHeaders.at(i)._32; if (hdr->sh_type == SHT_SYMTAB) { SymTabHeader = hdr; break; @@ -830,10 +794,8 @@ void ELFContainer::PrintSymbolTable() const { return; } - LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), - "Symbol table string table section is wrong"); - LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf32_Sym), - "Entry size doesn't match symbol entry"); + LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), "Symbol table string table section is wrong"); + LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf32_Sym), "Entry size doesn't match symbol entry"); StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32; StrTab = &RawFile.at(StringTableHeader->sh_offset); @@ -841,20 +803,18 @@ void ELFContainer::PrintSymbolTable() const { const uint64_t NumSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize; for (uint64_t i = 0; i < NumSymbols; ++i) { const uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize; - const auto *Symbol = reinterpret_cast(&RawFile.at(offset)); + const auto* Symbol = reinterpret_cast(&RawFile.at(offset)); - LogMan::Msg::IFmt("{} : {:x} {} {} {} {} {}", i, Symbol->st_value, Symbol->st_size, - uint32_t(Symbol->st_info), uint32_t(Symbol->st_other), - Symbol->st_shndx, &StrTab[Symbol->st_name]); + LogMan::Msg::IFmt("{} : {:x} {} {} {} {} {}", i, Symbol->st_value, Symbol->st_size, uint32_t(Symbol->st_info), + uint32_t(Symbol->st_other), Symbol->st_shndx, &StrTab[Symbol->st_name]); } - } - else { + } else { // Find the symbol table - Elf64_Shdr const *SymTabHeader{nullptr}; - Elf64_Shdr const *StringTableHeader{nullptr}; - char const *StrTab{nullptr}; + const Elf64_Shdr* SymTabHeader {nullptr}; + const Elf64_Shdr* StringTableHeader {nullptr}; + const char* StrTab {nullptr}; for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders.at(i)._64; + const Elf64_Shdr* hdr = SectionHeaders.at(i)._64; if (hdr->sh_type == SHT_SYMTAB) { SymTabHeader = hdr; break; @@ -865,10 +825,8 @@ void ELFContainer::PrintSymbolTable() const { return; } - LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), - "Symbol table string table section is wrong"); - LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf64_Sym), - "Entry size doesn't match symbol entry"); + LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(), "Symbol table string table section is wrong"); + LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf64_Sym), "Entry size doesn't match symbol entry"); StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64; StrTab = &RawFile.at(StringTableHeader->sh_offset); @@ -876,34 +834,31 @@ void ELFContainer::PrintSymbolTable() const { const uint64_t NumSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize; for (uint64_t i = 0; i < NumSymbols; ++i) { const uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize; - const auto *Symbol = reinterpret_cast(&RawFile.at(offset)); + const auto* Symbol = reinterpret_cast(&RawFile.at(offset)); - LogMan::Msg::IFmt("{} : {:x} {} {} {} {} {}", i, Symbol->st_value, Symbol->st_size, - uint32_t(Symbol->st_info), uint32_t(Symbol->st_other), - Symbol->st_shndx, &StrTab[Symbol->st_name]); + LogMan::Msg::IFmt("{} : {:x} {} {} {} {} {}", i, Symbol->st_value, Symbol->st_size, uint32_t(Symbol->st_info), + uint32_t(Symbol->st_other), Symbol->st_shndx, &StrTab[Symbol->st_name]); } } } void ELFContainer::PrintRelocationTable() const { if (Mode == MODE_32BIT) { - } - else { - Elf64_Shdr const *RelaHeader{nullptr}; - Elf64_Shdr const *DynSymHeader {nullptr}; + } else { + const Elf64_Shdr* RelaHeader {nullptr}; + const Elf64_Shdr* DynSymHeader {nullptr}; - Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64; - char const *SHStrings = &RawFile.at(StrHeader->sh_offset); + const Elf64_Shdr* StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); - Elf64_Shdr const *StringTableHeader{nullptr}; - char const *StrTab{nullptr}; + const Elf64_Shdr* StringTableHeader {nullptr}; + const char* StrTab {nullptr}; for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders.at(i)._64; + const Elf64_Shdr* hdr = SectionHeaders.at(i)._64; if (hdr->sh_type == SHT_REL) { LogMan::Msg::DFmt("Unhandled REL section"); - } - else if (hdr->sh_type == SHT_RELA) { + } else if (hdr->sh_type == SHT_RELA) { RelaHeader = hdr; LogMan::Msg::DFmt("Relocation Section: '{}'", &SHStrings[RelaHeader->sh_name]); @@ -920,10 +875,10 @@ void ELFContainer::PrintRelocationTable() const { } const size_t EntryCount = RelaHeader->sh_size / RelaHeader->sh_entsize; - const auto *Entries = reinterpret_cast(&RawFile.at(RelaHeader->sh_offset)); + const auto* Entries = reinterpret_cast(&RawFile.at(RelaHeader->sh_offset)); for (size_t j = 0; j < EntryCount; ++j) { - const auto *Entry = &Entries[j]; + const auto* Entry = &Entries[j]; const uint32_t Sym = Entry->r_info >> 32; const uint32_t Type = Entry->r_info & ~0U; LogMan::Msg::DFmt("RELA Entry {}", j); @@ -933,7 +888,7 @@ void ELFContainer::PrintRelocationTable() const { LOGMAN_THROW_AA_FMT(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match"); const uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize; - const auto *Symbol = reinterpret_cast(&RawFile.at(offset)); + const auto* Symbol = reinterpret_cast(&RawFile.at(offset)); LogMan::Msg::DFmt("\tSym Name: '{}'", &StrTab[Symbol->st_name]); } @@ -941,29 +896,21 @@ void ELFContainer::PrintRelocationTable() const { LogMan::Msg::DFmt("\tadded: 0x{:x}", Entry->r_addend); if (Type == R_X86_64_IRELATIVE) { // 37/0x25 LogMan::Msg::DFmt("\tR_x86_64_IRELATIVE"); - } - else if (Type == R_X86_64_64) { + } else if (Type == R_X86_64_64) { LogMan::Msg::DFmt("\tR_X86_64_64"); - } - else if (Type == R_X86_64_RELATIVE) { + } else if (Type == R_X86_64_RELATIVE) { LogMan::Msg::DFmt("\tR_X86_64_RELATIVE"); - } - else if (Type == R_X86_64_GLOB_DAT) { + } else if (Type == R_X86_64_GLOB_DAT) { LogMan::Msg::DFmt("\tR_X86_64_GLOB_DAT"); - } - else if (Type == R_X86_64_JUMP_SLOT) { + } else if (Type == R_X86_64_JUMP_SLOT) { LogMan::Msg::DFmt("\tR_X86_64_JUMP_SLOT"); - } - else if (Type == R_X86_64_DTPMOD64) { + } else if (Type == R_X86_64_DTPMOD64) { LogMan::Msg::DFmt("\tR_X86_64_DTPMOD64"); - } - else if (Type == R_X86_64_DTPOFF64) { + } else if (Type == R_X86_64_DTPOFF64) { LogMan::Msg::DFmt("\tR_X86_64_DTPOFF64"); - } - else if (Type == R_X86_64_TPOFF64) { + } else if (Type == R_X86_64_TPOFF64) { LogMan::Msg::DFmt("\tR_X86_64_TPOFF64"); - } - else { + } else { LogMan::Msg::DFmt("Unknown relocation type: {}(0x{:x})", Type, Type); } } @@ -972,22 +919,20 @@ void ELFContainer::PrintRelocationTable() const { } } -void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, SymbolGetter Getter) { +void ELFContainer::FixupRelocations(void* ELFBase, uint64_t GuestELFBase, SymbolGetter Getter) { if (Mode == MODE_32BIT) { - } - else { - Elf64_Shdr const *RelaHeader{nullptr}; - Elf64_Shdr const *DynSymHeader {nullptr}; + } else { + const Elf64_Shdr* RelaHeader {nullptr}; + const Elf64_Shdr* DynSymHeader {nullptr}; - Elf64_Shdr const *StringTableHeader{nullptr}; - char const *StrTab{nullptr}; + const Elf64_Shdr* StringTableHeader {nullptr}; + const char* StrTab {nullptr}; for (size_t i = 0; i < SectionHeaders.size(); ++i) { - const auto *hdr = SectionHeaders[i]._64; + const auto* hdr = SectionHeaders[i]._64; if (hdr->sh_type == SHT_REL) { LogMan::Msg::DFmt("Unhandled REL section"); - } - else if (hdr->sh_type == SHT_RELA) { + } else if (hdr->sh_type == SHT_RELA) { RelaHeader = hdr; if (RelaHeader->sh_info != 0) { @@ -1003,52 +948,47 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol } const size_t EntryCount = RelaHeader->sh_size / RelaHeader->sh_entsize; - const auto *Entries = reinterpret_cast(&RawFile.at(RelaHeader->sh_offset)); + const auto* Entries = reinterpret_cast(&RawFile.at(RelaHeader->sh_offset)); for (size_t j = 0; j < EntryCount; ++j) { - const auto *Entry = &Entries[j]; + const auto* Entry = &Entries[j]; const uint32_t Sym = Entry->r_info >> 32; const uint32_t Type = Entry->r_info & ~0U; - const Elf64_Sym *EntrySymbol{nullptr}; - const char *EntrySymbolName{nullptr}; + const Elf64_Sym* EntrySymbol {nullptr}; + const char* EntrySymbolName {nullptr}; if (DynSymHeader && Sym != 0) { LOGMAN_THROW_AA_FMT(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match"); const uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize; - EntrySymbol = reinterpret_cast(&RawFile.at(offset)); + EntrySymbol = reinterpret_cast(&RawFile.at(offset)); EntrySymbolName = &StrTab[EntrySymbol->st_name]; } if (Type == R_X86_64_IRELATIVE) { // 37/0x25 // Indirect (B + A) - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); *Location = GuestELFBase + Entry->r_addend; - } - else if (Type == R_X86_64_64) { + } else if (Type == R_X86_64_64) { // S + A - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); if (EntrySymbol != nullptr) { auto ELFSym = Getter(EntrySymbolName, 0); if (ELFSym != nullptr) { *Location = ELFSym->Address + Entry->r_addend; - } - else { + } else { *Location = 0xDEADBEEFBAD0DAD2ULL; } - } - else { + } else { *Location = 0xDEADBEEFBAD0DAD2ULL; } - } - else if (Type == R_X86_64_RELATIVE) { + } else if (Type == R_X86_64_RELATIVE) { // B + A - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); *Location = GuestELFBase + Entry->r_addend; - } - else if (Type == R_X86_64_GLOB_DAT) { + } else if (Type == R_X86_64_GLOB_DAT) { // XXX: This is way wrong // S - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); if (EntrySymbol != nullptr) { auto ELFSym = Getter(EntrySymbolName, 2); // Leave out Symbols from the main executable and only grab non-weak @@ -1061,20 +1001,17 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol if (ELFSym != nullptr) { *Location = ELFSym->Address; - } - else { + } else { // XXX: This seems to be a loader edge case that if the symbol doesn't exist // and it is a weakly defined GLOB_DAT type then it is allowed to continue? // If we set Location to a value then apps crash } - } - else { + } else { *Location = 0xDEADBEEFBAD0DAD1ULL; } - } - else if (Type == R_X86_64_JUMP_SLOT) { + } else if (Type == R_X86_64_JUMP_SLOT) { // S - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); if (EntrySymbol != nullptr) { auto ELFSym = Getter(EntrySymbolName, 0); if (!ELFSym) { // XXX: Try again @@ -1083,53 +1020,43 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol if (ELFSym != nullptr) { *Location = ELFSym->Address; - } - else { + } else { // XXX: This seems to be a loader edge case that if the symbol doesn't exist // and it is a weakly defined GLOB_DAT type then it is allowed to continue? *Location = 0xDEADBEEFBAD0DAD5ULL; } - } - else { + } else { *Location = 0xDEADBEEFBAD0DAD4ULL; } - } - else if (Type == R_X86_64_DTPMOD64) { + } else if (Type == R_X86_64_DTPMOD64) { // XXX: This is supposed to be the ID of the module that the symbol comes from for TLS purposes? - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); *Location = 0; - } - else if (Type == R_X86_64_DTPOFF64) { - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + } else if (Type == R_X86_64_DTPOFF64) { + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); if (EntrySymbol != nullptr) { *Location = EntrySymbol->st_value + Entry->r_addend; - } - else { + } else { *Location = 0xDEADBEEFBAD0DAD6ULL; } - } - else if (Type == R_X86_64_TPOFF64) { - uint64_t *Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); + } else if (Type == R_X86_64_TPOFF64) { + uint64_t* Location = reinterpret_cast(reinterpret_cast(ELFBase) + Entry->r_offset); if (EntrySymbol != nullptr) { // XXX: This is supposed to be a symbol with a TLS offset? *Location = EntrySymbol->st_value + Entry->r_addend; - } - else { + } else { // If we set Location to a value then apps crash // *Location = 0xDEADBEEFBAD0DAD3ULL; LogMan::Msg::DFmt("TPOFF without Entry? {:x} + {:x} + {:x}", GuestELFBase, TLSHeader._64->p_paddr, Entry->r_addend); if (1) { *Location = TLSHeader._64->p_paddr + Entry->r_addend; - } - else if (Entry->r_offset == 0x1e3dc8) { + } else if (Entry->r_offset == 0x1e3dc8) { *Location = 0xDEADBEEFBAD0DAD8ULL; - } - else { + } else { *Location = Entry->r_addend - 0xb00'0; } } - } - else { + } else { LogMan::Msg::DFmt("Unknown relocation type: {}(0x{:x})", Type, Type); } } @@ -1141,24 +1068,23 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol void ELFContainer::PrintInitArray() const { if (Mode == MODE_32BIT) { for (size_t i = 0; i < SectionHeaders.size(); ++i) { - const auto *hdr = SectionHeaders[i]._32; + const auto* hdr = SectionHeaders[i]._32; if (hdr->sh_type == SHT_INIT_ARRAY) { const size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; j < Entries; ++j) { LogMan::Msg::DFmt("init_array[{}]", j); - LogMan::Msg::DFmt("\t{}", *reinterpret_cast(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize))); + LogMan::Msg::DFmt("\t{}", *reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize))); } } } - } - else { + } else { for (size_t i = 0; i < SectionHeaders.size(); ++i) { - const auto *hdr = SectionHeaders[i]._64; + const auto* hdr = SectionHeaders[i]._64; if (hdr->sh_type == SHT_INIT_ARRAY) { const size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; j < Entries; ++j) { LogMan::Msg::DFmt("init_array[{}]", j); - LogMan::Msg::DFmt("\t{}", *reinterpret_cast(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize))); + LogMan::Msg::DFmt("\t{}", *reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize))); } } } @@ -1168,22 +1094,20 @@ void ELFContainer::PrintInitArray() const { void ELFContainer::PrintDynamicTable() const { if (Mode == MODE_32BIT) { for (size_t i = 0; i < SectionHeaders.size(); ++i) { - const auto *hdr = SectionHeaders[i]._32; + const auto* hdr = SectionHeaders[i]._32; if (hdr->sh_type == SHT_DYNAMIC) { - const auto *StrHeader = SectionHeaders.at(hdr->sh_link)._32; - const char *SHStrings = &RawFile.at(StrHeader->sh_offset); + const auto* StrHeader = SectionHeaders.at(hdr->sh_link)._32; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); const size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; i < Entries; ++j) { - const auto *Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); -#define PRINT(x, y, z) x (Dynamic->d_tag == DT_##y ) LogMan::Msg::DFmt("Dyn {}: (" #y ") 0x{:x}", j, Dynamic->d_un.z); + const auto* Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); +#define PRINT(x, y, z) x(Dynamic->d_tag == DT_##y) LogMan::Msg::DFmt("Dyn {}: (" #y ") 0x{:x}", j, Dynamic->d_un.z); if (Dynamic->d_tag == DT_NULL) { break; - } - else if (Dynamic->d_tag == DT_NEEDED) { + } else if (Dynamic->d_tag == DT_NEEDED) { LogMan::Msg::DFmt("Dyn {}: (NEEDED) '{}'", j, &SHStrings[Dynamic->d_un.d_val]); - } - else if (Dynamic->d_tag == DT_SONAME) { + } else if (Dynamic->d_tag == DT_SONAME) { LogMan::Msg::DFmt("Dyn {}: (SONAME) '{}'", j, &SHStrings[Dynamic->d_un.d_val]); } PRINT(else if, HASH, d_val) @@ -1220,31 +1144,27 @@ void ELFContainer::PrintDynamicTable() const { PRINT(else if, VERDEF, d_val) PRINT(else if, VERDEFNUM, d_val) PRINT(else if, FLAGS, d_val) - else - LogMan::Msg::DFmt("Unknown dynamic section: {}(0x{:x})", Dynamic->d_tag, Dynamic->d_tag); + else LogMan::Msg::DFmt("Unknown dynamic section: {}(0x{:x})", Dynamic->d_tag, Dynamic->d_tag); #undef PRINT } } } - } - else { + } else { for (size_t i = 0; i < SectionHeaders.size(); ++i) { - const auto *hdr = SectionHeaders[i]._64; + const auto* hdr = SectionHeaders[i]._64; if (hdr->sh_type == SHT_DYNAMIC) { - const auto *StrHeader = SectionHeaders.at(hdr->sh_link)._64; - const char *SHStrings = &RawFile.at(StrHeader->sh_offset); + const auto* StrHeader = SectionHeaders.at(hdr->sh_link)._64; + const char* SHStrings = &RawFile.at(StrHeader->sh_offset); const size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; i < Entries; ++j) { - const auto *Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); -#define PRINT(x, y, z) x (Dynamic->d_tag == DT_##y ) LogMan::Msg::DFmt("Dyn {}: (" #y ") 0x{:x}", j, Dynamic->d_un.z); + const auto* Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); +#define PRINT(x, y, z) x(Dynamic->d_tag == DT_##y) LogMan::Msg::DFmt("Dyn {}: (" #y ") 0x{:x}", j, Dynamic->d_un.z); if (Dynamic->d_tag == DT_NULL) { break; - } - else if (Dynamic->d_tag == DT_NEEDED) { + } else if (Dynamic->d_tag == DT_NEEDED) { LogMan::Msg::DFmt("Dyn {}: (NEEDED) '{}'", j, &SHStrings[Dynamic->d_un.d_val]); - } - else if (Dynamic->d_tag == DT_SONAME) { + } else if (Dynamic->d_tag == DT_SONAME) { LogMan::Msg::DFmt("Dyn {}: (SONAME) '{}'", j, &SHStrings[Dynamic->d_un.d_val]); } PRINT(else if, HASH, d_val) @@ -1281,8 +1201,7 @@ void ELFContainer::PrintDynamicTable() const { PRINT(else if, VERDEF, d_val) PRINT(else if, VERDEFNUM, d_val) PRINT(else if, FLAGS, d_val) - else - LogMan::Msg::DFmt("Unknown dynamic section: {}(0x{:x})", Dynamic->d_tag, Dynamic->d_tag); + else LogMan::Msg::DFmt("Unknown dynamic section: {}(0x{:x})", Dynamic->d_tag, Dynamic->d_tag); #undef PRINT } } @@ -1290,16 +1209,18 @@ void ELFContainer::PrintDynamicTable() const { } } -void ELFContainer::GetInitLocations(uint64_t GuestELFBase, fextl::vector *Locations) { +void ELFContainer::GetInitLocations(uint64_t GuestELFBase, fextl::vector* Locations) { if (Mode == MODE_32BIT) { // If INIT exists then add that first for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf32_Shdr const *hdr = SectionHeaders.at(i)._32; + const Elf32_Shdr* hdr = SectionHeaders.at(i)._32; if (hdr->sh_type == SHT_DYNAMIC) { size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; i < Entries; ++j) { - Elf32_Dyn const *Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); - if (Dynamic->d_tag == DT_NULL) break; + const Elf32_Dyn* Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); + if (Dynamic->d_tag == DT_NULL) { + break; + } if (Dynamic->d_tag == DT_INIT) { Locations->emplace_back(GuestELFBase + Dynamic->d_un.d_val); } @@ -1309,24 +1230,25 @@ void ELFContainer::GetInitLocations(uint64_t GuestELFBase, fextl::vectorsh_type == SHT_INIT_ARRAY) { size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; j < Entries; ++j) { - Locations->emplace_back(GuestELFBase + *reinterpret_cast(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize))); + Locations->emplace_back(GuestELFBase + *reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize))); } } } - } - else { + } else { // If INIT exists then add that first for (uint32_t i = 0; i < SectionHeaders.size(); ++i) { - Elf64_Shdr const *hdr = SectionHeaders.at(i)._64; + const Elf64_Shdr* hdr = SectionHeaders.at(i)._64; if (hdr->sh_type == SHT_DYNAMIC) { size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; i < Entries; ++j) { - Elf64_Dyn const *Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); - if (Dynamic->d_tag == DT_NULL) break; + const Elf64_Dyn* Dynamic = reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize)); + if (Dynamic->d_tag == DT_NULL) { + break; + } if (Dynamic->d_tag == DT_INIT) { Locations->emplace_back(GuestELFBase + Dynamic->d_un.d_val); } @@ -1336,11 +1258,11 @@ void ELFContainer::GetInitLocations(uint64_t GuestELFBase, fextl::vectorsh_type == SHT_INIT_ARRAY) { size_t Entries = hdr->sh_size / hdr->sh_entsize; for (size_t j = 0; j < Entries; ++j) { - Locations->emplace_back(GuestELFBase + *reinterpret_cast(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize))); + Locations->emplace_back(GuestELFBase + *reinterpret_cast(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize))); } } } diff --git a/Source/Tools/CommonTools/Linux/Utils/ELFContainer.h b/Source/Tools/CommonTools/Linux/Utils/ELFContainer.h index 3d0f259ea..56076bf44 100644 --- a/Source/Tools/CommonTools/Linux/Utils/ELFContainer.h +++ b/Source/Tools/CommonTools/Linux/Utils/ELFContainer.h @@ -15,11 +15,11 @@ // Add macros which are missing in some versions of #ifndef ELF32_ST_VISIBILITY -#define ELF32_ST_VISIBILITY(o) ((o) & 0x3) +#define ELF32_ST_VISIBILITY(o) ((o)&0x3) #endif #ifndef ELF64_ST_VISIBILITY -#define ELF64_ST_VISIBILITY(o) ((o) & 0x3) +#define ELF64_ST_VISIBILITY(o) ((o)&0x3) #endif namespace ELFLoader { @@ -30,19 +30,18 @@ struct ELFSymbol { uint8_t Type; uint8_t Bind; uint16_t SectionIndex; - char const *Name; + const char* Name; }; class ELFContainer { public: - ELFContainer(fextl::string const &Filename, fextl::string const &RootFS, bool CustomInterpreter); + ELFContainer(const fextl::string& Filename, const fextl::string& RootFS, bool CustomInterpreter); ~ELFContainer(); uint64_t GetEntryPoint() const { if (Mode == MODE_32BIT) { return Header._32.e_entry; - } - else { + } else { return Header._64.e_entry; } } @@ -50,8 +49,7 @@ public: using MemoryLayout = std::tuple; MemoryLayout GetLayout() const { - return std::make_tuple(MinPhysicalMemoryLocation, MaxPhysicalMemoryLocation, - PhysicalMemorySize); + return std::make_tuple(MinPhysicalMemoryLocation, MaxPhysicalMemoryLocation, PhysicalMemorySize); } struct BRKInfo { @@ -64,26 +62,36 @@ public: } // Data, Physical, Size - using MemoryWriter = std::function; + using MemoryWriter = std::function; void WriteLoadableSections(MemoryWriter Writer, uint64_t Offset = 0); - ELFSymbol const *GetSymbol(char const *Name); - ELFSymbol const *GetSymbol(uint64_t Address); + const ELFSymbol* GetSymbol(const char* Name); + const ELFSymbol* GetSymbol(uint64_t Address); using RangeType = std::pair; - ELFSymbol const *GetSymbolInRange(RangeType Address); + const ELFSymbol* GetSymbolInRange(RangeType Address); - bool WasDynamic() const { return DynamicProgram; } - bool HasDynamicLinker() const { return !DynamicLinker.empty(); } - bool WasLoaded() const { return Loaded; } - fextl::string &InterpreterLocation() { return DynamicLinker; } + bool WasDynamic() const { + return DynamicProgram; + } + bool HasDynamicLinker() const { + return !DynamicLinker.empty(); + } + bool WasLoaded() const { + return Loaded; + } + fextl::string& InterpreterLocation() { + return DynamicLinker; + } - fextl::vector const *GetNecessaryLibs() const { return &NecessaryLibs; } + const fextl::vector* GetNecessaryLibs() const { + return &NecessaryLibs; + } void PrintRelocationTable() const; - using SymbolGetter = std::function; - void FixupRelocations(void *ELFBase, uint64_t GuestELFBase, SymbolGetter Getter); + using SymbolGetter = std::function; + void FixupRelocations(void* ELFBase, uint64_t GuestELFBase, SymbolGetter Getter); using SymbolAdder = std::function; void AddSymbols(SymbolAdder Adder); @@ -91,15 +99,16 @@ public: using UnwindAdder = std::function; void AddUnwindEntries(UnwindAdder Adder); - void GetInitLocations(uint64_t GuestELFBase, fextl::vector *Locations); + void GetInitLocations(uint64_t GuestELFBase, fextl::vector* Locations); - bool HasTLS() const { return TLSHeader._64 != nullptr; } + bool HasTLS() const { + return TLSHeader._64 != nullptr; + } uint64_t GetTLSBase() const { if (GetMode() == ELFMode::MODE_64BIT) { return TLSHeader._64->p_vaddr; - } - else { + } else { return TLSHeader._32->p_vaddr; } } @@ -109,8 +118,12 @@ public: MODE_64BIT, }; - ELFMode GetMode() const { return Mode; } - size_t GetProgramHeaderCount() const { return ProgramHeaders.size(); } + ELFMode GetMode() const { + return Mode; + } + size_t GetProgramHeaderCount() const { + return ProgramHeaders.size(); + } enum ELFType { TYPE_NONE, @@ -118,15 +131,15 @@ public: TYPE_X86_32, TYPE_OTHER_ELF, }; - static ELFType GetELFType(fextl::string const &Filename); + static ELFType GetELFType(const fextl::string& Filename); static ELFType GetELFType(int FD); - static bool IsSupportedELF(fextl::string const &Filename) { + static bool IsSupportedELF(const fextl::string& Filename) { ELFType Type = GetELFType(Filename); return Type == TYPE_X86_64 || Type == TYPE_X86_32; } private: - bool LoadELF(fextl::string const &Filename); + bool LoadELF(const fextl::string& Filename); bool LoadELF_32(); bool LoadELF_64(); void CalculateMemoryLayouts(); @@ -148,13 +161,13 @@ private: } Header; union SectionHeader { - Elf32_Shdr *_32; - Elf64_Shdr *_64; + Elf32_Shdr* _32; + Elf64_Shdr* _64; }; union ProgramHeader { - Elf32_Phdr *_32; - Elf64_Phdr *_64; + Elf32_Phdr* _32; + Elf64_Phdr* _64; }; ELFMode Mode; @@ -162,21 +175,21 @@ private: fextl::vector ProgramHeaders; fextl::vector Symbols; fextl::vector UnwindEntries; - fextl::unordered_map SymbolMap; - fextl::map SymbolMapByAddress; + fextl::unordered_map SymbolMap; + fextl::map SymbolMapByAddress; - fextl::vector NecessaryLibs; + fextl::vector NecessaryLibs; - uint64_t MinPhysicalMemoryLocation{0}; - uint64_t MaxPhysicalMemoryLocation{0}; - uint64_t PhysicalMemorySize{0}; + uint64_t MinPhysicalMemoryLocation {0}; + uint64_t MaxPhysicalMemoryLocation {0}; + uint64_t PhysicalMemorySize {0}; - uint64_t BRKBase{}; - uint64_t BRKSize{}; - ProgramHeader InterpreterHeader{}; - bool DynamicProgram{false}; + uint64_t BRKBase {}; + uint64_t BRKSize {}; + ProgramHeader InterpreterHeader {}; + bool DynamicProgram {false}; fextl::string DynamicLinker; - ProgramHeader TLSHeader{}; + ProgramHeader TLSHeader {}; bool Loaded {false}; }; diff --git a/Source/Tools/CommonTools/Linux/Utils/ELFParser.h b/Source/Tools/CommonTools/Linux/Utils/ELFParser.h index 9de7afda7..b4d43e56d 100644 --- a/Source/Tools/CommonTools/Linux/Utils/ELFParser.h +++ b/Source/Tools/CommonTools/Linux/Utils/ELFParser.h @@ -82,10 +82,11 @@ struct ELFParser { } // Convert to 64 bit header - for (int i = 0; i < EI_NIDENT; i++) + for (int i = 0; i < EI_NIDENT; i++) { ehdr.e_ident[i] = hdr32.e_ident[i]; + } - #define COPY(name) ehdr.name = hdr32.name +#define COPY(name) ehdr.name = hdr32.name COPY(e_type); COPY(e_machine); COPY(e_version); @@ -99,7 +100,7 @@ struct ELFParser { COPY(e_shentsize); COPY(e_shnum); COPY(e_shstrndx); - #undef COPY +#undef COPY if (ehdr.e_machine != EM_386) { LogMan::Msg::EFmt("Invalid e_machine from '{}'", fd); @@ -157,7 +158,7 @@ struct ELFParser { phdrs.resize(ehdr.e_phnum); for (int i = 0; i < ehdr.e_phnum; i++) { - #define COPY(name) phdrs[i].name = phdrs32[i].name +#define COPY(name) phdrs[i].name = phdrs32[i].name COPY(p_type); COPY(p_offset); @@ -168,7 +169,7 @@ struct ELFParser { COPY(p_flags); COPY(p_align); - #undef COPY +#undef COPY } } else { phdrs.resize(ehdr.e_phnum); @@ -223,7 +224,7 @@ struct ELFParser { return {}; } - bool ReadElf(const fextl::string &file) { + bool ReadElf(const fextl::string& file) { int NewFD = ::open(file.c_str(), O_RDONLY); return ReadElf(NewFD); diff --git a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.cpp b/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.cpp index 48c19b0dc..5d8d8dcdb 100644 --- a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.cpp +++ b/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.cpp @@ -2,8 +2,8 @@ /* $info$ tags: glue|elf-parsing -desc: Part of our now defunct ld-linux replacement, keeps tracks of all symbols, loads elfs, handles relocations. Small parts of this are used. -$end_info$ +desc: Part of our now defunct ld-linux replacement, keeps tracks of all symbols, loads elfs, handles relocations. Small parts of this are +used. $end_info$ */ #include "Linux/Utils/ELFSymbolDatabase.h" @@ -33,8 +33,7 @@ void ELFSymbolDatabase::FillLibrarySearchPaths() { LibrarySearchPaths.emplace_back("/usr/local/lib/x86_64-linux-gnu"); LibrarySearchPaths.emplace_back("/lib/x86_64-linux-gnu"); LibrarySearchPaths.emplace_back("/usr/lib/x86_64-linux-gnu"); - } - else { + } else { LibrarySearchPaths.emplace_back("/usr/local/lib/i386-linux-gnu"); LibrarySearchPaths.emplace_back("/lib/i386-linux-gnu"); LibrarySearchPaths.emplace_back("/usr/lib/i386-linux-gnu"); @@ -52,8 +51,8 @@ void ELFSymbolDatabase::FillLibrarySearchPaths() { } } -bool ELFSymbolDatabase::FindLibraryFile(fextl::string *Result, const char *Library) { - for (auto &Path : LibrarySearchPaths) { +bool ELFSymbolDatabase::FindLibraryFile(fextl::string* Result, const char* Library) { + for (auto& Path : LibrarySearchPaths) { const fextl::string TmpPath = fextl::fmt::format("{}/{}", Path, Library); if (FHU::Filesystem::Exists(TmpPath)) { *Result = TmpPath; @@ -63,7 +62,7 @@ bool ELFSymbolDatabase::FindLibraryFile(fextl::string *Result, const char *Libra return false; } -ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file) +ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer* file) : File {file} { FillLibrarySearchPaths(); @@ -75,8 +74,8 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file) fextl::vector UnfilledDependencies; fextl::vector NewLibraries; - auto FillDependencies = [&UnfilledDependencies, this](ELFInfo *ELF) { - for (auto &Lib : *ELF->Container->GetNecessaryLibs()) { + auto FillDependencies = [&UnfilledDependencies, this](ELFInfo* ELF) { + for (auto& Lib : *ELF->Container->GetNecessaryLibs()) { if (NameToELF.find(Lib) == NameToELF.end()) { UnfilledDependencies.emplace_back(Lib); } @@ -84,15 +83,15 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file) }; auto LoadDependencies = [&UnfilledDependencies, &NewLibraries, this]() { - for (auto &Lib : UnfilledDependencies) { + for (auto& Lib : UnfilledDependencies) { if (NameToELF.find(Lib) == NameToELF.end()) { fextl::string LibraryPath; #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED bool Found = #endif - FindLibraryFile(&LibraryPath, Lib.c_str()); + FindLibraryFile(&LibraryPath, Lib.c_str()); LOGMAN_THROW_A_FMT(Found, "Couldn't find library '{}'", Lib); - auto Info = DynamicELFInfo.emplace_back(new ELFInfo{}); + auto Info = DynamicELFInfo.emplace_back(new ELFInfo {}); Info->Name = Lib; Info->Container = new ::ELFLoader::ELFContainer(LibraryPath, {}, true); NewLibraries.emplace_back(Info); @@ -141,8 +140,7 @@ void ELFSymbolDatabase::FillMemoryLayouts(uint64_t DefinedBase) { if (!DefinedBase) { if (File->GetMode() == ELFContainer::MODE_64BIT) { ELFBases = 0x1'0000'0000; - } - else { + } else { // 32bit we will just load at the lowest memory address we can // Which on Linux is at 0x1'0000 ELFBases = 0x1'0000; @@ -166,8 +164,7 @@ void ELFSymbolDatabase::FillMemoryLayouts(uint64_t DefinedBase) { ELFBases += CurrentELFAlignedSize; ELFMemorySize += CurrentELFAlignedSize; - } - else { + } else { LocalInfo.CustomLayout = File->GetLayout(); uint64_t CurrentELFBase = std::get<0>(LocalInfo.CustomLayout); uint64_t CurrentELFAlignedSize = FEXCore::AlignUp(std::get<2>(LocalInfo.CustomLayout), 4096); @@ -207,16 +204,18 @@ void ELFSymbolDatabase::FillInitializationOrder() { std::set AlreadyInList; while (true) { - if (InitializationOrder.size() == DynamicELFInfo.size()) + if (InitializationOrder.size() == DynamicELFInfo.size()) { break; + } - for (auto &ELF : DynamicELFInfo) { + for (auto& ELF : DynamicELFInfo) { // If this ELF is already in the list then skip it - if (AlreadyInList.find(ELF->Name) != AlreadyInList.end()) + if (AlreadyInList.find(ELF->Name) != AlreadyInList.end()) { continue; + } bool AllLibsLoaded = true; - for (auto &Lib : *ELF->Container->GetNecessaryLibs()) { + for (auto& Lib : *ELF->Container->GetNecessaryLibs()) { if (AlreadyInList.find(Lib) == AlreadyInList.end()) { AllLibsLoaded = false; break; @@ -232,7 +231,7 @@ void ELFSymbolDatabase::FillInitializationOrder() { } void ELFSymbolDatabase::FillSymbols() { - auto LocalSymbolFiller = [this](ELFLoader::ELFSymbol *Symbol) { + auto LocalSymbolFiller = [this](ELFLoader::ELFSymbol* Symbol) { Symbols.emplace_back(Symbol); Symbol->Address += LocalInfo.GuestBase; SymbolMap[Symbol->Name] = Symbol; @@ -249,7 +248,7 @@ void ELFSymbolDatabase::FillSymbols() { // Let us fill symbols based on initialization order for (auto ELF : InitializationOrder) { - auto SymbolFiller = [this, &ELF](ELFLoader::ELFSymbol *Symbol) { + auto SymbolFiller = [this, &ELF](ELFLoader::ELFSymbol* Symbol) { Symbols.emplace_back(Symbol); // Offset the address by the guest base Symbol->Address += ELF->GuestBase; @@ -267,7 +266,6 @@ void ELFSymbolDatabase::FillSymbols() { ELF->Container->AddSymbols(SymbolFiller); } - } void ELFSymbolDatabase::MapMemoryRegions(std::function Mapper) { @@ -279,7 +277,7 @@ void ELFSymbolDatabase::MapMemoryRegions(std::function ELFLoader::ELFSymbol* { - SymbolTableType &TablePtr = SymbolMap; - if (Table == 0) + auto SymbolGetter = [this](const char* SymbolName, uint8_t Table) -> ELFLoader::ELFSymbol* { + SymbolTableType& TablePtr = SymbolMap; + if (Table == 0) { TablePtr = SymbolMap; - else if (Table == 1) // Global + } else if (Table == 1) { // Global TablePtr = SymbolMapGlobalOnly; - else if (Table == 2) // NoWeak + } else if (Table == 2) { // NoWeak TablePtr = SymbolMapNoWeak; - else if (Table == 3) // No Main + } else if (Table == 3) { // No Main TablePtr = SymbolMapNoMain; - else if (Table == 4) // No Main No Weak + } else if (Table == 4) { // No Main No Weak TablePtr = SymbolMapNoMainNoWeak; + } auto Sym = TablePtr.find(SymbolName); - if (Sym == TablePtr.end()) + if (Sym == TablePtr.end()) { return nullptr; + } return Sym->second; }; @@ -331,27 +331,31 @@ uint64_t ELFSymbolDatabase::DefaultRIP() const { return File->GetEntryPoint() + LocalInfo.GuestBase; } -ELFSymbol const *ELFSymbolDatabase::GetSymbolInRange(RangeType Address) { +const ELFSymbol* ELFSymbolDatabase::GetSymbolInRange(RangeType Address) { auto Sym = SymbolMapByAddress.upper_bound(Address.first); - if (Sym != SymbolMapByAddress.begin()) + if (Sym != SymbolMapByAddress.begin()) { --Sym; - if (Sym == SymbolMapByAddress.end()) + } + if (Sym == SymbolMapByAddress.end()) { return nullptr; + } - if ((Sym->second->Address + Sym->second->Size) < Address.first) + if ((Sym->second->Address + Sym->second->Size) < Address.first) { return nullptr; + } - if (Sym->second->Address > Address.first) + if (Sym->second->Address > Address.first) { return nullptr; + } return Sym->second; } -void ELFSymbolDatabase::GetInitLocations(fextl::vector *Locations) { +void ELFSymbolDatabase::GetInitLocations(fextl::vector* Locations) { // Walk the initialization order and fill the locations for initializations for (auto ELF : InitializationOrder) { ELF->Container->GetInitLocations(ELF->GuestBase, Locations); } } -} +} // namespace ELFLoader diff --git a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.h b/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.h index 05823dd7b..17b001ac1 100644 --- a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.h +++ b/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.h @@ -15,7 +15,7 @@ namespace ELFLoader { class ELFSymbolDatabase final { public: - ELFSymbolDatabase(::ELFLoader::ELFContainer *file); + ELFSymbolDatabase(::ELFLoader::ELFContainer* file); ~ELFSymbolDatabase(); uint64_t GetElfBase() const; @@ -26,44 +26,44 @@ public: uint64_t DefaultRIP() const; using RangeType = std::pair; - ::ELFLoader::ELFSymbol const *GetSymbolInRange(RangeType Address); - ::ELFLoader::ELFSymbol const *GetGlobalSymbolInRange(RangeType Address); - ::ELFLoader::ELFSymbol const *GetNoWeakSymbolInRange(RangeType Address); + const ::ELFLoader::ELFSymbol* GetSymbolInRange(RangeType Address); + const ::ELFLoader::ELFSymbol* GetGlobalSymbolInRange(RangeType Address); + const ::ELFLoader::ELFSymbol* GetNoWeakSymbolInRange(RangeType Address); - void GetInitLocations(fextl::vector *Locations); + void GetInitLocations(fextl::vector* Locations); private: - ::ELFLoader::ELFContainer *File; + ::ELFLoader::ELFContainer* File; struct ELFInfo { fextl::string Name; ::ELFLoader::ELFContainer* Container; ::ELFLoader::ELFContainer::MemoryLayout CustomLayout; - void *ELFBase; + void* ELFBase; uint64_t GuestBase; }; ELFInfo LocalInfo; fextl::vector DynamicELFInfo; fextl::vector InitializationOrder; - uint64_t ELFMemorySize{}; + uint64_t ELFMemorySize {}; bool FixedNoReplace {true}; - void *ELFBase{}; + void* ELFBase {}; fextl::unordered_map NameToELF; fextl::vector LibrarySearchPaths; // Symbols fextl::vector Symbols; - using SymbolTableType = fextl::unordered_map; + using SymbolTableType = fextl::unordered_map; SymbolTableType SymbolMap; SymbolTableType SymbolMapGlobalOnly; SymbolTableType SymbolMapNoWeak; SymbolTableType SymbolMapNoMain; SymbolTableType SymbolMapNoMainNoWeak; - fextl::map SymbolMapByAddress; + fextl::map SymbolMapByAddress; - bool FindLibraryFile(fextl::string *Result, const char *Library); + bool FindLibraryFile(fextl::string* Result, const char* Library); void FillLibrarySearchPaths(); void FillMemoryLayouts(uint64_t DefinedBase); void FillInitializationOrder(); @@ -71,7 +71,6 @@ private: void HandleRelocations(); - ::ELFLoader::ELFSymbol const *GetSymbolFromTable(RangeType Address, fextl::unordered_map &Table); + const ::ELFLoader::ELFSymbol* GetSymbolFromTable(RangeType Address, fextl::unordered_map& Table); }; -} - +} // namespace ELFLoader diff --git a/Source/Tools/FEXBash/FEXBash.cpp b/Source/Tools/FEXBash/FEXBash.cpp index a8bee5960..f52d8ff02 100644 --- a/Source/Tools/FEXBash/FEXBash.cpp +++ b/Source/Tools/FEXBash/FEXBash.cpp @@ -23,7 +23,7 @@ $end_info$ #include #include -int main(int argc, char **argv, char **const envp) { +int main(int argc, char** argv, char** const envp) { FEXCore::Config::Initialize(); FEXCore::Config::AddLayer(FEX::Config::CreateGlobalMainLayer()); FEXCore::Config::AddLayer(FEX::Config::CreateMainLayer()); @@ -53,7 +53,7 @@ int main(int argc, char **argv, char **const envp) { if (!std::filesystem::exists(FEXInterpreterPath)) { FEXInterpreterPath = FEXCore::Config::FindContainerPrefix() + FEXINTERPRETER_PATH; } - const char *FEXArgs[] = { + const char* FEXArgs[] = { FEXInterpreterPath.c_str(), Args.empty() ? BinBashPath.c_str() : BinShPath.c_str(), "-c", @@ -88,15 +88,15 @@ int main(int argc, char **argv, char **const envp) { // But in case the user has set the PS1 environment variable then still prepend // // To get the shell variables as an environment variable then you can do `PS1=$PS1 FEXBash` - std::vector Envp{}; - char *PS1Env{}; + std::vector Envp {}; + char* PS1Env {}; for (unsigned i = 0;; ++i) { - if (envp[i] == nullptr) + if (envp[i] == nullptr) { break; + } if (strstr(envp[i], "PS1=") == envp[i]) { PS1Env = envp[i]; - } - else { + } else { Envp.emplace_back(envp[i]); } } @@ -108,5 +108,5 @@ int main(int argc, char **argv, char **const envp) { Envp.emplace_back(PS1.c_str()); Envp.emplace_back(nullptr); - return execve(Argv[0], const_cast(&Argv.at(0)), const_cast(&Envp[0])); + return execve(Argv[0], const_cast(&Argv.at(0)), const_cast(&Envp[0])); } diff --git a/Source/Tools/FEXConfig/Main.cpp b/Source/Tools/FEXConfig/Main.cpp index 1952721a6..54655ec81 100644 --- a/Source/Tools/FEXConfig/Main.cpp +++ b/Source/Tools/FEXConfig/Main.cpp @@ -19,884 +19,844 @@ #include namespace fextl { - // Helper to convert a std::filesystem::path to a fextl::string. - inline fextl::string string_from_path(std::filesystem::path const &Path) { - return Path.string().c_str(); - } +// Helper to convert a std::filesystem::path to a fextl::string. +inline fextl::string string_from_path(const std::filesystem::path& Path) { + return Path.string().c_str(); } +} // namespace fextl namespace { - static std::chrono::time_point GlobalTime{}; +static std::chrono::time_point GlobalTime {}; - static bool ConfigOpen{}; - static bool ConfigChanged{}; - static int EnvironmentVariableSelected{}; - static int HostEnvironmentVariableSelected{}; - static int NamedRootFSSelected{-1}; +static bool ConfigOpen {}; +static bool ConfigChanged {}; +static int EnvironmentVariableSelected {}; +static int HostEnvironmentVariableSelected {}; +static int NamedRootFSSelected {-1}; - static fextl::string ConfigFilename{}; - static fextl::unique_ptr LoadedConfig{}; +static fextl::string ConfigFilename {}; +static fextl::unique_ptr LoadedConfig {}; - static const char EnvironmentPopupName[] = "#New Environment Variable"; - static const char HostEnvironmentPopupName[] = "#New Host Environment Variable"; - static const char SavedPopupAppName[] = "#SavedApp"; - static const char OpenedPopupAppName[] = "#OpenedApp"; +static const char EnvironmentPopupName[] = "#New Environment Variable"; +static const char HostEnvironmentPopupName[] = "#New Host Environment Variable"; +static const char SavedPopupAppName[] = "#SavedApp"; +static const char OpenedPopupAppName[] = "#OpenedApp"; - static bool OpenMsgPopup{}; - static bool SaveMsgIsOpen{}; - static std::string MsgMessage{}; - static const char MsgPopupName[] = "#Msg"; - static std::chrono::high_resolution_clock::time_point MsgTimerStart{}; +static bool OpenMsgPopup {}; +static bool SaveMsgIsOpen {}; +static std::string MsgMessage {}; +static const char MsgPopupName[] = "#Msg"; +static std::chrono::high_resolution_clock::time_point MsgTimerStart {}; - static bool SelectedOpenFile{}; - static bool SelectedSaveFileAs{}; - static ImGuiFs::Dialog DialogSaveAs{}; - static ImGuiFs::Dialog DialogOpen{}; +static bool SelectedOpenFile {}; +static bool SelectedSaveFileAs {}; +static ImGuiFs::Dialog DialogSaveAs {}; +static ImGuiFs::Dialog DialogOpen {}; - // Named rootfs - static std::vector NamedRootFS{}; - static std::mutex NamedRootFSUpdator{}; +// Named rootfs +static std::vector NamedRootFS {}; +static std::mutex NamedRootFSUpdator {}; - static std::atomic INotifyFD{-1}; - static int INotifyFolderFD{}; - static std::thread INotifyThreadHandle{}; - static std::atomic_bool INotifyShutdown{}; +static std::atomic INotifyFD {-1}; +static int INotifyFolderFD {}; +static std::thread INotifyThreadHandle {}; +static std::atomic_bool INotifyShutdown {}; - void OpenMsgMessagePopup(fextl::string Message) { - OpenMsgPopup = true; - MsgMessage = Message; - MsgTimerStart = std::chrono::high_resolution_clock::now(); - FEX::GUI::HadUpdate(); - } +void OpenMsgMessagePopup(fextl::string Message) { + OpenMsgPopup = true; + MsgMessage = Message; + MsgTimerStart = std::chrono::high_resolution_clock::now(); + FEX::GUI::HadUpdate(); +} - void LoadDefaultSettings() { - ConfigOpen = true; - ConfigFilename = {}; - LoadedConfig = fextl::make_unique(); -#define OPT_BASE(type, group, enum, json, default) \ - LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(default)); -#define OPT_STR(group, enum, json, default) \ - LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, default); -#define OPT_STRARRAY(group, enum, json, default) // Do nothing +void LoadDefaultSettings() { + ConfigOpen = true; + ConfigFilename = {}; + LoadedConfig = fextl::make_unique(); +#define OPT_BASE(type, group, enum, json, default) LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(default)); +#define OPT_STR(group, enum, json, default) LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, default); +#define OPT_STRARRAY(group, enum, json, default) // Do nothing #define OPT_STRENUM(group, enum, json, default) \ - LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(FEXCore::ToUnderlying(default))); + LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(FEXCore::ToUnderlying(default))); #include - // Erase unnamed options which shouldn't be set - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS_INTERPRETER); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_INTERPRETER_INSTALLED); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_FILENAME); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_CONFIG_NAME); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS64BIT_MODE); - } + // Erase unnamed options which shouldn't be set + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS_INTERPRETER); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_INTERPRETER_INSTALLED); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_FILENAME); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_CONFIG_NAME); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS64BIT_MODE); +} - bool OpenFile(fextl::string Filename, bool LoadDefault = false) { - std::error_code ec{}; - if (!std::filesystem::exists(Filename, ec)) { - if (LoadDefault) { - LoadDefaultSettings(); - ConfigFilename = Filename; - OpenMsgMessagePopup("Opened with default options: " + Filename); - return true; - } - OpenMsgMessagePopup("Couldn't open: " + Filename); - return false; +bool OpenFile(fextl::string Filename, bool LoadDefault = false) { + std::error_code ec {}; + if (!std::filesystem::exists(Filename, ec)) { + if (LoadDefault) { + LoadDefaultSettings(); + ConfigFilename = Filename; + OpenMsgMessagePopup("Opened with default options: " + Filename); + return true; } - ConfigOpen = true; - ConfigFilename = Filename; - LoadedConfig = FEX::Config::CreateMainLayer(&Filename); - LoadedConfig->Load(); + OpenMsgMessagePopup("Couldn't open: " + Filename); + return false; + } + ConfigOpen = true; + ConfigFilename = Filename; + LoadedConfig = FEX::Config::CreateMainLayer(&Filename); + LoadedConfig->Load(); - // Load default options and only overwrite only if the option didn't exist + // Load default options and only overwrite only if the option didn't exist #define OPT_BASE(type, group, enum, json, default) \ - if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(default)); } + if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { \ + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(default)); \ + } #define OPT_STR(group, enum, json, default) \ - if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, default); } -#define OPT_STRARRAY(group, enum, json, default) // Do nothing + if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { \ + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, default); \ + } +#define OPT_STRARRAY(group, enum, json, default) // Do nothing #define OPT_STRENUM(group, enum, json, default) \ - if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(FEXCore::ToUnderlying(default))); } + if (!LoadedConfig->OptionExists(FEXCore::Config::ConfigOption::CONFIG_##enum)) { \ + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_##enum, std::to_string(FEXCore::ToUnderlying(default))); \ + } #include - // Erase unnamed options which shouldn't be set - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS_INTERPRETER); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_INTERPRETER_INSTALLED); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_FILENAME); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_CONFIG_NAME); - LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS64BIT_MODE); + // Erase unnamed options which shouldn't be set + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS_INTERPRETER); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_INTERPRETER_INSTALLED); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_FILENAME); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_APP_CONFIG_NAME); + LoadedConfig->Erase(FEXCore::Config::ConfigOption::CONFIG_IS64BIT_MODE); - return true; - } + return true; +} - void LoadNamedRootFSFolder() { - std::scoped_lock lk{NamedRootFSUpdator}; - NamedRootFS.clear(); - fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; - std::error_code ec{}; - if (!std::filesystem::exists(RootFS, ec)) { - // Doesn't exist, create the the folder as a user convenience - if (!std::filesystem::create_directories(RootFS, ec)) { - // Well I guess we failed - return; - } +void LoadNamedRootFSFolder() { + std::scoped_lock lk {NamedRootFSUpdator}; + NamedRootFS.clear(); + fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; + std::error_code ec {}; + if (!std::filesystem::exists(RootFS, ec)) { + // Doesn't exist, create the the folder as a user convenience + if (!std::filesystem::create_directories(RootFS, ec)) { + // Well I guess we failed + return; } - for (auto &it : std::filesystem::directory_iterator(RootFS)) { - if (it.is_directory()) { + } + for (auto& it : std::filesystem::directory_iterator(RootFS)) { + if (it.is_directory()) { + NamedRootFS.emplace_back(it.path().filename()); + } else if (it.is_regular_file()) { + // If it is a regular file then we need to check if it is a valid archive + if (it.path().extension() == ".sqsh" && FEX::FormatCheck::IsSquashFS(fextl::string_from_path(it.path()))) { + NamedRootFS.emplace_back(it.path().filename()); + } else if (it.path().extension() == ".ero" && FEX::FormatCheck::IsEroFS(fextl::string_from_path(it.path()))) { NamedRootFS.emplace_back(it.path().filename()); } - else if (it.is_regular_file()) { - // If it is a regular file then we need to check if it is a valid archive - if (it.path().extension() == ".sqsh" && - FEX::FormatCheck::IsSquashFS(fextl::string_from_path(it.path()))) { - NamedRootFS.emplace_back(it.path().filename()); - } - else if (it.path().extension() == ".ero" && - FEX::FormatCheck::IsEroFS(fextl::string_from_path(it.path()))) { - NamedRootFS.emplace_back(it.path().filename()); - } - } - } - std::sort(NamedRootFS.begin(), NamedRootFS.end()); - } - - void INotifyThread() { - while (!INotifyShutdown) { - constexpr size_t DATA_SIZE = (16 * (sizeof(struct inotify_event) + NAME_MAX + 1)); - char buf[DATA_SIZE]; - int Ret{}; - do { - fd_set Set{}; - FD_ZERO(&Set); - FD_SET(INotifyFD, &Set); - struct timeval tv{}; - // 50 ms - tv.tv_usec = 50000; - Ret = select(INotifyFD + 1, &Set, nullptr, nullptr, &tv); - } while (Ret == 0 && INotifyFD != -1); - - if (Ret == -1 || INotifyFD == -1) { - // Just return on error - INotifyShutdown = true; - return; - } - - // Spin through the events, we don't actually care what they are - while (read(INotifyFD, buf, DATA_SIZE) > 0); - - // Now update the named vector - LoadNamedRootFSFolder(); - - FEX::GUI::HadUpdate(); } } + std::sort(NamedRootFS.begin(), NamedRootFS.end()); +} - void SetupINotify() { - if (INotifyFD != -1) { - // Already setup +void INotifyThread() { + while (!INotifyShutdown) { + constexpr size_t DATA_SIZE = (16 * (sizeof(struct inotify_event) + NAME_MAX + 1)); + char buf[DATA_SIZE]; + int Ret {}; + do { + fd_set Set {}; + FD_ZERO(&Set); + FD_SET(INotifyFD, &Set); + struct timeval tv {}; + // 50 ms + tv.tv_usec = 50000; + Ret = select(INotifyFD + 1, &Set, nullptr, nullptr, &tv); + } while (Ret == 0 && INotifyFD != -1); + + if (Ret == -1 || INotifyFD == -1) { + // Just return on error + INotifyShutdown = true; return; } - INotifyFD = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - INotifyShutdown = false; + // Spin through the events, we don't actually care what they are + while (read(INotifyFD, buf, DATA_SIZE) > 0) + ; - fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; - INotifyFolderFD = inotify_add_watch(INotifyFD, RootFS.c_str(), IN_CREATE | IN_DELETE); - if (INotifyFolderFD != -1) { - INotifyThreadHandle = std::thread(INotifyThread); - } + // Now update the named vector + LoadNamedRootFSFolder(); + + FEX::GUI::HadUpdate(); + } +} + +void SetupINotify() { + if (INotifyFD != -1) { + // Already setup + return; } - void ShutdownINotify() { - close(INotifyFD); - INotifyFD = -1; - if (INotifyThreadHandle.joinable()) { - INotifyThreadHandle.join(); - } + INotifyFD = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + INotifyShutdown = false; + + fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; + INotifyFolderFD = inotify_add_watch(INotifyFD, RootFS.c_str(), IN_CREATE | IN_DELETE); + if (INotifyFolderFD != -1) { + INotifyThreadHandle = std::thread(INotifyThread); + } +} + +void ShutdownINotify() { + close(INotifyFD); + INotifyFD = -1; + if (INotifyThreadHandle.joinable()) { + INotifyThreadHandle.join(); + } +} + +void SaveFile(fextl::string Filename) { + if (SaveMsgIsOpen) { + // Don't try saving a file while the message is already open. + // Stops us from spam saving the file to the filesystem. + return; } - void SaveFile(fextl::string Filename) { - if (SaveMsgIsOpen) { - // Don't try saving a file while the message is already open. - // Stops us from spam saving the file to the filesystem. - return; - } - - if (!ConfigOpen) { - OpenMsgMessagePopup("Can't save file when config isn't open"); - return; - } - - FEX::Config::SaveLayerToJSON(Filename, LoadedConfig.get()); - ConfigChanged = false; - ConfigFilename = Filename; - OpenMsgMessagePopup("Config Saved to: '" + Filename + "'"); - SaveMsgIsOpen = true; - - // Output in terminal as well - printf("Config Saved to: '%s'\n", ConfigFilename.c_str()); + if (!ConfigOpen) { + OpenMsgMessagePopup("Can't save file when config isn't open"); + return; } - void CloseConfig() { - ConfigOpen = false; - ConfigFilename = {}; - ConfigChanged = false; - LoadedConfig.reset(); - } + FEX::Config::SaveLayerToJSON(Filename, LoadedConfig.get()); + ConfigChanged = false; + ConfigFilename = Filename; + OpenMsgMessagePopup("Config Saved to: '" + Filename + "'"); + SaveMsgIsOpen = true; - void FillCPUConfig() { - char BlockSize[32]{}; + // Output in terminal as well + printf("Config Saved to: '%s'\n", ConfigFilename.c_str()); +} - if (ImGui::BeginTabItem("CPU")) { - std::optional Value{}; - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_MAXINST); - if (Value.has_value() && !(*Value)->empty()) { - strncpy(BlockSize, &(*Value)->at(0), 32); - } - if (ImGui::InputText("Block Size:", BlockSize, 32, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_MAXINST, BlockSize); - ConfigChanged = true; - } +void CloseConfig() { + ConfigOpen = false; + ConfigFilename = {}; + ConfigChanged = false; + LoadedConfig.reset(); +} - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_MULTIBLOCK); - bool Multiblock = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Multiblock", &Multiblock)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_MULTIBLOCK, Multiblock ? "1" : "0"); - ConfigChanged = true; - } +void FillCPUConfig() { + char BlockSize[32] {}; - ImGui::EndTabItem(); + if (ImGui::BeginTabItem("CPU")) { + std::optional Value {}; + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_MAXINST); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(BlockSize, &(*Value)->at(0), 32); } - } - - template - bool EnvironmentVariableFiller(void *data, int idx, const char** out_text) { - static char TmpString[256]; - auto Value = LoadedConfig->All(Option); - if (Value.has_value()) { - auto List = (*Value); - auto it = List->begin(); - - // Since this is a list, we don't have a linear allocator that we can just jump to an element - // Just do a quick spin - for (int i = 0; i < idx; ++i) - ++it; - - snprintf(TmpString, 256, "%s", it->c_str()); - *out_text = TmpString; - - return true; + if (ImGui::InputText("Block Size:", BlockSize, 32, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_MAXINST, BlockSize); + ConfigChanged = true; } - return false; - } - - bool NamedRootFSVariableFiller(void *data, int idx, const char** out_text) { - std::scoped_lock lk{NamedRootFSUpdator}; - static char TmpString[256]; - if (idx >= 0 && idx < NamedRootFS.size()) { - // Since this is a list, we don't have a linear allocator that we can just jump to an element - // Just do a quick spin - snprintf(TmpString, 256, "%s", NamedRootFS.at(idx).c_str()); - *out_text = TmpString; - - return true; + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_MULTIBLOCK); + bool Multiblock = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Multiblock", &Multiblock)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_MULTIBLOCK, Multiblock ? "1" : "0"); + ConfigChanged = true; } - return false; + ImGui::EndTabItem(); } +} - - template - void DeleteEnvironmentVariable(int idx) { - auto Value = LoadedConfig->All(Option); +template +bool EnvironmentVariableFiller(void* data, int idx, const char** out_text) { + static char TmpString[256]; + auto Value = LoadedConfig->All(Option); + if (Value.has_value()) { auto List = (*Value); auto it = List->begin(); // Since this is a list, we don't have a linear allocator that we can just jump to an element // Just do a quick spin - for (int i = 0; i < idx; ++i) + for (int i = 0; i < idx; ++i) { ++it; + } - List->erase(it); - ConfigChanged = true; + snprintf(TmpString, 256, "%s", it->c_str()); + *out_text = TmpString; + + return true; } - void AddNewEnvironmentVariable() { - char Environment[256]{}; - char HostEnvironment[256]{}; + return false; +} - if (ImGui::BeginPopup(EnvironmentPopupName)) { - if (ImGui::InputText("New Environment", Environment, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_ENV, Environment); - ImGui::CloseCurrentPopup(); - ConfigChanged = true; - } +bool NamedRootFSVariableFiller(void* data, int idx, const char** out_text) { + std::scoped_lock lk {NamedRootFSUpdator}; + static char TmpString[256]; + if (idx >= 0 && idx < NamedRootFS.size()) { + // Since this is a list, we don't have a linear allocator that we can just jump to an element + // Just do a quick spin + snprintf(TmpString, 256, "%s", NamedRootFS.at(idx).c_str()); + *out_text = TmpString; - ImGui::EndPopup(); + return true; + } + + return false; +} + + +template +void DeleteEnvironmentVariable(int idx) { + auto Value = LoadedConfig->All(Option); + auto List = (*Value); + auto it = List->begin(); + + // Since this is a list, we don't have a linear allocator that we can just jump to an element + // Just do a quick spin + for (int i = 0; i < idx; ++i) { + ++it; + } + + List->erase(it); + ConfigChanged = true; +} + +void AddNewEnvironmentVariable() { + char Environment[256] {}; + char HostEnvironment[256] {}; + + if (ImGui::BeginPopup(EnvironmentPopupName)) { + if (ImGui::InputText("New Environment", Environment, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_ENV, Environment); + ImGui::CloseCurrentPopup(); + ConfigChanged = true; } + ImGui::EndPopup(); + } + + ImGui::PushID(1); + if (ImGui::BeginPopup(HostEnvironmentPopupName)) { + if (ImGui::InputText("New Environment", HostEnvironment, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_HOSTENV, HostEnvironment); + ImGui::CloseCurrentPopup(); + ConfigChanged = true; + } + + ImGui::EndPopup(); + } + ImGui::PopID(); +} + +void FillEmulationConfig() { + char RootFS[256] {}; + char ThunkHostPath[256] {}; + char ThunkGuestPath[256] {}; + char ThunkConfigPath[256] {}; + + int NumEnvironmentVariables {}; + int NumHostEnvironmentVariables {}; + int NumRootFSPaths = NamedRootFS.size(); + + if (ImGui::BeginTabItem("Emulation")) { + auto Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_ROOTFS); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(RootFS, &(*Value)->at(0), 256); + } + ImGui::Text("Available named RootFS folders: %d", NumRootFSPaths); + + if (ImGui::ListBox("Named RootFS folders", &NamedRootFSSelected, NamedRootFSVariableFiller, nullptr, NumRootFSPaths)) { + strncpy(RootFS, NamedRootFS.at(NamedRootFSSelected).c_str(), 256); + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ROOTFS, RootFS); + ConfigChanged = true; + } + + if (ImGui::InputText("RootFS:", RootFS, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + NamedRootFSSelected = -1; + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ROOTFS, RootFS); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBS); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(ThunkHostPath, &(*Value)->at(0), 256); + } + if (ImGui::InputText("Thunk Host library folder:", ThunkHostPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBS, ThunkHostPath); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBS); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(ThunkGuestPath, &(*Value)->at(0), 256); + } + if (ImGui::InputText("Thunk Guest library folder:", ThunkGuestPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBS, ThunkGuestPath); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIG); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(ThunkConfigPath, &(*Value)->at(0), 256); + } + if (ImGui::InputText("Thunk Config file:", ThunkConfigPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIG, ThunkConfigPath); + ConfigChanged = true; + } + + auto ValueList = LoadedConfig->All(FEXCore::Config::ConfigOption::CONFIG_ENV); + auto ValueHostList = LoadedConfig->All(FEXCore::Config::ConfigOption::CONFIG_HOSTENV); + if (ValueList.has_value()) { + NumEnvironmentVariables = (*ValueList)->size(); + } + + if (ValueHostList.has_value()) { + NumHostEnvironmentVariables = (*ValueHostList)->size(); + } + + ImGui::Text("Number of environment variables: %d", NumEnvironmentVariables); + + ImGui::ListBox("Environment variables", &EnvironmentVariableSelected, + EnvironmentVariableFiller, nullptr, NumEnvironmentVariables); + + if (ImGui::SmallButton("+")) { + ImGui::OpenPopup(EnvironmentPopupName); + } + + if (NumEnvironmentVariables) { + ImGui::SameLine(); + if (ImGui::SmallButton("-")) { + DeleteEnvironmentVariable(EnvironmentVariableSelected); + EnvironmentVariableSelected = std::max(0, EnvironmentVariableSelected - 1); + } + } + + ImGui::PushID(1); - if (ImGui::BeginPopup(HostEnvironmentPopupName)) { - if (ImGui::InputText("New Environment", HostEnvironment, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->Set(FEXCore::Config::ConfigOption::CONFIG_HOSTENV, HostEnvironment); - ImGui::CloseCurrentPopup(); - ConfigChanged = true; - } + ImGui::Text("Number of Host environment variables: %d", NumHostEnvironmentVariables); - ImGui::EndPopup(); + ImGui::ListBox("Host Env variables", &HostEnvironmentVariableSelected, + EnvironmentVariableFiller, nullptr, NumHostEnvironmentVariables); + + if (ImGui::SmallButton("+")) { + ImGui::OpenPopup(HostEnvironmentPopupName); + } + + if (NumHostEnvironmentVariables) { + ImGui::SameLine(); + if (ImGui::SmallButton("-")) { + DeleteEnvironmentVariable(HostEnvironmentVariableSelected); + HostEnvironmentVariableSelected = std::max(0, HostEnvironmentVariableSelected - 1); + } } ImGui::PopID(); - } - void FillEmulationConfig() { - char RootFS[256]{}; - char ThunkHostPath[256]{}; - char ThunkGuestPath[256]{}; - char ThunkConfigPath[256]{}; + // Only draws if popup is open + AddNewEnvironmentVariable(); - int NumEnvironmentVariables{}; - int NumHostEnvironmentVariables{}; - int NumRootFSPaths = NamedRootFS.size(); - - if (ImGui::BeginTabItem("Emulation")) { - auto Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_ROOTFS); - if (Value.has_value() && !(*Value)->empty()) { - strncpy(RootFS, &(*Value)->at(0), 256); - } - ImGui::Text("Available named RootFS folders: %d", NumRootFSPaths); - - if (ImGui::ListBox("Named RootFS folders", &NamedRootFSSelected, NamedRootFSVariableFiller, nullptr, NumRootFSPaths)) { - strncpy(RootFS, NamedRootFS.at(NamedRootFSSelected).c_str(), 256); - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ROOTFS, RootFS); - ConfigChanged = true; - } - - if (ImGui::InputText("RootFS:", RootFS, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - NamedRootFSSelected = -1; - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ROOTFS, RootFS); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBS); - if (Value.has_value() && !(*Value)->empty()) { - strncpy(ThunkHostPath, &(*Value)->at(0), 256); - } - if (ImGui::InputText("Thunk Host library folder:", ThunkHostPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKHOSTLIBS, ThunkHostPath); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBS); - if (Value.has_value() && !(*Value)->empty()) { - strncpy(ThunkGuestPath, &(*Value)->at(0), 256); - } - if (ImGui::InputText("Thunk Guest library folder:", ThunkGuestPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKGUESTLIBS, ThunkGuestPath); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIG); - if (Value.has_value() && !(*Value)->empty()) { - strncpy(ThunkConfigPath, &(*Value)->at(0), 256); - } - if (ImGui::InputText("Thunk Config file:", ThunkConfigPath, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_THUNKCONFIG, ThunkConfigPath); - ConfigChanged = true; - } - - auto ValueList = LoadedConfig->All(FEXCore::Config::ConfigOption::CONFIG_ENV); - auto ValueHostList = LoadedConfig->All(FEXCore::Config::ConfigOption::CONFIG_HOSTENV); - if (ValueList.has_value()) { - NumEnvironmentVariables = (*ValueList)->size(); - } - - if (ValueHostList.has_value()) { - NumHostEnvironmentVariables = (*ValueHostList)->size(); - } - - ImGui::Text("Number of environment variables: %d", NumEnvironmentVariables); - - ImGui::ListBox("Environment variables", &EnvironmentVariableSelected, EnvironmentVariableFiller, nullptr, NumEnvironmentVariables); - - if (ImGui::SmallButton("+")) { - ImGui::OpenPopup(EnvironmentPopupName); - } - - if (NumEnvironmentVariables) { - ImGui::SameLine(); - if (ImGui::SmallButton("-")) { - DeleteEnvironmentVariable(EnvironmentVariableSelected); - EnvironmentVariableSelected = std::max(0, EnvironmentVariableSelected - 1); - } - } - - - ImGui::PushID(1); - ImGui::Text("Number of Host environment variables: %d", NumHostEnvironmentVariables); - - ImGui::ListBox("Host Env variables", &HostEnvironmentVariableSelected, EnvironmentVariableFiller, nullptr, NumHostEnvironmentVariables); - - if (ImGui::SmallButton("+")) { - ImGui::OpenPopup(HostEnvironmentPopupName); - } - - if (NumHostEnvironmentVariables) { - ImGui::SameLine(); - if (ImGui::SmallButton("-")) { - DeleteEnvironmentVariable(HostEnvironmentVariableSelected); - HostEnvironmentVariableSelected = std::max(0, HostEnvironmentVariableSelected - 1); - } - } - ImGui::PopID(); - - // Only draws if popup is open - AddNewEnvironmentVariable(); - - ImGui::Text("Debugging:"); - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_O0); - bool DisablePasses = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Disable Optimization Passes", &DisablePasses)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_O0, DisablePasses ? "1" : "0"); - ConfigChanged = true; - } - - ImGui::Text("Ahead Of Time JIT Options:"); - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_AOTIRGENERATE); - bool AOTGenerate = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Generate", &AOTGenerate)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_AOTIRGENERATE, AOTGenerate ? "1" : "0"); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_AOTIRCAPTURE); - bool AOTCapture = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Capture", &AOTCapture)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_AOTIRCAPTURE, AOTCapture ? "1" : "0"); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_AOTIRLOAD); - bool AOTLoad = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Load", &AOTLoad)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_AOTIRLOAD, AOTLoad ? "1" : "0"); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_CACHEOBJECTCODECOMPILATION); - - ImGui::Text("Cache JIT object code:"); - int CacheJITObjectCode = 0; - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_CACHEOBJECTCODECOMPILATION); - if (Value.has_value()) { - if (**Value == "0") { - CacheJITObjectCode = FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE; - } else if (**Value == "1") { - CacheJITObjectCode = FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READ; - } else if (**Value == "2") { - CacheJITObjectCode = FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READWRITE; - } - } - - bool CacheChanged = false; - CacheChanged |= ImGui::RadioButton("Off", &CacheJITObjectCode, FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE); ImGui::SameLine(); - CacheChanged |= ImGui::RadioButton("Read-only", &CacheJITObjectCode, FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READ); ImGui::SameLine(); - CacheChanged |= ImGui::RadioButton("Read/Write", &CacheJITObjectCode, FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READWRITE); - - if (CacheChanged) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_CACHEOBJECTCODECOMPILATION, std::to_string(CacheJITObjectCode)); - ConfigChanged = true; - } - - ImGui::EndTabItem(); + ImGui::Text("Debugging:"); + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_O0); + bool DisablePasses = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Disable Optimization Passes", &DisablePasses)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_O0, DisablePasses ? "1" : "0"); + ConfigChanged = true; } - } - void FillLoggingConfig() { - char LogFile[256]{}; - char IRDump[256]{}; - - if (ImGui::BeginTabItem("Logging")) { - auto Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_SILENTLOG); - bool SilentLog = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Silent Logging", &SilentLog)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SILENTLOG, SilentLog ? "1" : "0"); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_OUTPUTLOG); - if (Value.has_value() && !(*Value)->empty()) { - strncpy(LogFile, &(*Value)->at(0), 256); - } - if (ImGui::InputText("Output log file:", LogFile, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_OUTPUTLOG, LogFile); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_DUMPIR); - if (Value.has_value() && !(*Value)->empty()) { - strncpy(IRDump, &(*Value)->at(0), 256); - } - if (ImGui::InputText("IR Dump location:", IRDump, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_DUMPIR, IRDump); - ConfigChanged = true; - } - - ImGui::EndTabItem(); + ImGui::Text("Ahead Of Time JIT Options:"); + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_AOTIRGENERATE); + bool AOTGenerate = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Generate", &AOTGenerate)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_AOTIRGENERATE, AOTGenerate ? "1" : "0"); + ConfigChanged = true; } - } - void FillHackConfig() { - if (ImGui::BeginTabItem("Hacks")) { - auto Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_TSOENABLED); - auto VectorTSO = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_VECTORTSOENABLED); - auto MemcpyTSO = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_MEMCPYSETTSOENABLED); - - bool TSOEnabled = Value.has_value() && **Value == "1"; - bool VectorTSOEnabled = VectorTSO.has_value() && **VectorTSO == "1"; - bool MemcpyTSOEnabled = MemcpyTSO.has_value() && **MemcpyTSO == "1"; - - if (ImGui::Checkbox("TSO Enabled", &TSOEnabled)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_TSOENABLED, TSOEnabled ? "1" : "0"); - ConfigChanged = true; - } - - if (TSOEnabled) { - if (ImGui::TreeNodeEx("TSO sub-options", ImGuiTreeNodeFlags_Leaf)) { - if (ImGui::Checkbox("Vector TSO Enabled", &VectorTSOEnabled)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_VECTORTSOENABLED, VectorTSOEnabled ? "1" : "0"); - ConfigChanged = true; - } - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text("Disables TSO emulation on vector load/store instructions"); - ImGui::EndTooltip(); - } - - if (ImGui::Checkbox("Memcpy TSO Enabled", &MemcpyTSOEnabled)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_MEMCPYSETTSOENABLED, MemcpyTSOEnabled ? "1" : "0"); - ConfigChanged = true; - } - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text("Disables TSO emulation on memcpy/memset instructions"); - ImGui::EndTooltip(); - } - - ImGui::TreePop(); - } - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_PARANOIDTSO); - bool ParanoidTSOEnabled = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Paranoid TSO Enabled", &ParanoidTSOEnabled)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_PARANOIDTSO, ParanoidTSOEnabled ? "1" : "0"); - ConfigChanged = true; - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_X87REDUCEDPRECISION); - bool X87ReducedPrecision = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("X87 Reduced Precision", &X87ReducedPrecision)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_X87REDUCEDPRECISION, X87ReducedPrecision ? "1" : "0"); - ConfigChanged = true; - } - - ImGui::Text("SMC Checks: "); - int SMCChecks = FEXCore::Config::CONFIG_SMC_MTRACK; - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_SMCCHECKS); - if (Value.has_value()) { - if (**Value == "0") { - SMCChecks = FEXCore::Config::CONFIG_SMC_NONE; - } else if (**Value == "1") { - SMCChecks = FEXCore::Config::CONFIG_SMC_MTRACK; - } else if (**Value == "2") { - SMCChecks = FEXCore::Config::CONFIG_SMC_FULL; - } - } - - bool SMCChanged = false; - SMCChanged |= ImGui::RadioButton("None", &SMCChecks, FEXCore::Config::CONFIG_SMC_NONE); ImGui::SameLine(); - SMCChanged |= ImGui::RadioButton("MTrack (Default)", &SMCChecks, FEXCore::Config::CONFIG_SMC_MTRACK); ImGui::SameLine(); - SMCChanged |= ImGui::RadioButton("Full", &SMCChecks, FEXCore::Config::CONFIG_SMC_FULL); - - if (SMCChanged) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SMCCHECKS, std::to_string(SMCChecks)); - } - - Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_ABILOCALFLAGS); - bool UnsafeLocalFlags = Value.has_value() && **Value == "1"; - if (ImGui::Checkbox("Unsafe local flags optimization", &UnsafeLocalFlags)) { - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ABILOCALFLAGS, UnsafeLocalFlags ? "1" : "0"); - ConfigChanged = true; - } - - ImGui::EndTabItem(); + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_AOTIRCAPTURE); + bool AOTCapture = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Capture", &AOTCapture)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_AOTIRCAPTURE, AOTCapture ? "1" : "0"); + ConfigChanged = true; } - } - static const std::map ConfigToNameLookup = {{ + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_AOTIRLOAD); + bool AOTLoad = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Load", &AOTLoad)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_AOTIRLOAD, AOTLoad ? "1" : "0"); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_CACHEOBJECTCODECOMPILATION); + + ImGui::Text("Cache JIT object code:"); + int CacheJITObjectCode = 0; + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_CACHEOBJECTCODECOMPILATION); + if (Value.has_value()) { + if (**Value == "0") { + CacheJITObjectCode = FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE; + } else if (**Value == "1") { + CacheJITObjectCode = FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READ; + } else if (**Value == "2") { + CacheJITObjectCode = FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READWRITE; + } + } + + bool CacheChanged = false; + CacheChanged |= ImGui::RadioButton("Off", &CacheJITObjectCode, FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE); + ImGui::SameLine(); + CacheChanged |= ImGui::RadioButton("Read-only", &CacheJITObjectCode, FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READ); + ImGui::SameLine(); + CacheChanged |= ImGui::RadioButton("Read/Write", &CacheJITObjectCode, FEXCore::Config::ConfigObjectCodeHandler::CONFIG_READWRITE); + + if (CacheChanged) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_CACHEOBJECTCODECOMPILATION, std::to_string(CacheJITObjectCode)); + ConfigChanged = true; + } + + ImGui::EndTabItem(); + } +} + +void FillLoggingConfig() { + char LogFile[256] {}; + char IRDump[256] {}; + + if (ImGui::BeginTabItem("Logging")) { + auto Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_SILENTLOG); + bool SilentLog = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Silent Logging", &SilentLog)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SILENTLOG, SilentLog ? "1" : "0"); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_OUTPUTLOG); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(LogFile, &(*Value)->at(0), 256); + } + if (ImGui::InputText("Output log file:", LogFile, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_OUTPUTLOG, LogFile); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_DUMPIR); + if (Value.has_value() && !(*Value)->empty()) { + strncpy(IRDump, &(*Value)->at(0), 256); + } + if (ImGui::InputText("IR Dump location:", IRDump, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_DUMPIR, IRDump); + ConfigChanged = true; + } + + ImGui::EndTabItem(); + } +} + +void FillHackConfig() { + if (ImGui::BeginTabItem("Hacks")) { + auto Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_TSOENABLED); + auto VectorTSO = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_VECTORTSOENABLED); + auto MemcpyTSO = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_MEMCPYSETTSOENABLED); + + bool TSOEnabled = Value.has_value() && **Value == "1"; + bool VectorTSOEnabled = VectorTSO.has_value() && **VectorTSO == "1"; + bool MemcpyTSOEnabled = MemcpyTSO.has_value() && **MemcpyTSO == "1"; + + if (ImGui::Checkbox("TSO Enabled", &TSOEnabled)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_TSOENABLED, TSOEnabled ? "1" : "0"); + ConfigChanged = true; + } + + if (TSOEnabled) { + if (ImGui::TreeNodeEx("TSO sub-options", ImGuiTreeNodeFlags_Leaf)) { + if (ImGui::Checkbox("Vector TSO Enabled", &VectorTSOEnabled)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_VECTORTSOENABLED, VectorTSOEnabled ? "1" : "0"); + ConfigChanged = true; + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("Disables TSO emulation on vector load/store instructions"); + ImGui::EndTooltip(); + } + + if (ImGui::Checkbox("Memcpy TSO Enabled", &MemcpyTSOEnabled)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_MEMCPYSETTSOENABLED, MemcpyTSOEnabled ? "1" : "0"); + ConfigChanged = true; + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("Disables TSO emulation on memcpy/memset instructions"); + ImGui::EndTooltip(); + } + + ImGui::TreePop(); + } + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_PARANOIDTSO); + bool ParanoidTSOEnabled = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Paranoid TSO Enabled", &ParanoidTSOEnabled)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_PARANOIDTSO, ParanoidTSOEnabled ? "1" : "0"); + ConfigChanged = true; + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_X87REDUCEDPRECISION); + bool X87ReducedPrecision = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("X87 Reduced Precision", &X87ReducedPrecision)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_X87REDUCEDPRECISION, X87ReducedPrecision ? "1" : "0"); + ConfigChanged = true; + } + + ImGui::Text("SMC Checks: "); + int SMCChecks = FEXCore::Config::CONFIG_SMC_MTRACK; + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_SMCCHECKS); + if (Value.has_value()) { + if (**Value == "0") { + SMCChecks = FEXCore::Config::CONFIG_SMC_NONE; + } else if (**Value == "1") { + SMCChecks = FEXCore::Config::CONFIG_SMC_MTRACK; + } else if (**Value == "2") { + SMCChecks = FEXCore::Config::CONFIG_SMC_FULL; + } + } + + bool SMCChanged = false; + SMCChanged |= ImGui::RadioButton("None", &SMCChecks, FEXCore::Config::CONFIG_SMC_NONE); + ImGui::SameLine(); + SMCChanged |= ImGui::RadioButton("MTrack (Default)", &SMCChecks, FEXCore::Config::CONFIG_SMC_MTRACK); + ImGui::SameLine(); + SMCChanged |= ImGui::RadioButton("Full", &SMCChecks, FEXCore::Config::CONFIG_SMC_FULL); + + if (SMCChanged) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SMCCHECKS, std::to_string(SMCChecks)); + } + + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_ABILOCALFLAGS); + bool UnsafeLocalFlags = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("Unsafe local flags optimization", &UnsafeLocalFlags)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ABILOCALFLAGS, UnsafeLocalFlags ? "1" : "0"); + ConfigChanged = true; + } + + ImGui::EndTabItem(); + } +} + +static const std::map ConfigToNameLookup = {{ #define OPT_BASE(type, group, enum, json, default) {FEXCore::Config::ConfigOption::CONFIG_##enum, #json}, #include - }}; +}}; - struct TmpString { - char Str[256]; - std::string Name; - }; - static std::vector> AdvancedOptions{}; +struct TmpString { + char Str[256]; + std::string Name; +}; +static std::vector> AdvancedOptions {}; - void UpdateAdvancedOptionsVector() { - AdvancedOptions.clear(); - // Push everything in to our vector table that we can modify instead of the map +void UpdateAdvancedOptionsVector() { + AdvancedOptions.clear(); + // Push everything in to our vector table that we can modify instead of the map + auto Options = LoadedConfig->GetOptionMap(); + AdvancedOptions.resize(Options.size()); + + size_t i = 0; + for (auto& Option : Options) { + auto ConfigName = ConfigToNameLookup.find(Option.first); + auto& AdvancedOption = AdvancedOptions.at(i); + AdvancedOption.resize(Option.second.size()); + size_t j = 0; + for (auto& OptionList : Option.second) { + strcpy(AdvancedOption[j].Str, OptionList.c_str()); + AdvancedOption[j].Name = ConfigName->second; + if (Option.second.size() > 1) { + AdvancedOption[j].Name += " " + std::to_string(j); + } + ++j; + } + ++i; + } +} + +void FillAdvancedConfig() { + if (ImGui::BeginTabItem("Advanced")) { auto Options = LoadedConfig->GetOptionMap(); - AdvancedOptions.resize(Options.size()); - size_t i = 0; - for (auto &Option : Options) { - auto ConfigName = ConfigToNameLookup.find(Option.first); - auto &AdvancedOption = AdvancedOptions.at(i); - AdvancedOption.resize(Option.second.size()); - size_t j = 0; - for (auto &OptionList : Option.second) { - strcpy(AdvancedOption[j].Str, OptionList.c_str()); - AdvancedOption[j].Name = ConfigName->second; - if (Option.second.size() > 1) { - AdvancedOption[j].Name += " " + std::to_string(j); - } - ++j; - } - ++i; + if (ImGui::SmallButton("Refresh") || AdvancedOptions.size() != Options.size()) { + UpdateAdvancedOptionsVector(); } - } - void FillAdvancedConfig() { - if (ImGui::BeginTabItem("Advanced")) { - auto Options = LoadedConfig->GetOptionMap(); + if (Options.size()) { + ImGui::Columns(2); + size_t i = 0; + for (auto& Option : Options) { + auto ConfigName = ConfigToNameLookup.find(Option.first); + ImGui::Text("%s", ConfigName->second.c_str()); + ImGui::NextColumn(); - if (ImGui::SmallButton("Refresh") || AdvancedOptions.size() != Options.size()) { - UpdateAdvancedOptionsVector(); - } + auto& AdvancedOption = AdvancedOptions.at(i); + size_t j = 0; - if (Options.size()) { - ImGui::Columns(2); - size_t i = 0; - for (auto &Option : Options) { - auto ConfigName = ConfigToNameLookup.find(Option.first); - ImGui::Text("%s", ConfigName->second.c_str()); - ImGui::NextColumn(); + bool Stop = false; + for (auto& OptionList : AdvancedOption) { + // ImGui::Text("%s", OptionList.Str); + if (ImGui::InputText(OptionList.Name.c_str(), OptionList.Str, sizeof(TmpString), ImGuiInputTextFlags_EnterReturnsTrue)) { + if (Option.second.size() == 1) { + LoadedConfig->EraseSet(Option.first, OptionList.Str); + } else { + auto& All = Option.second; + auto Iter = All.begin(); + std::advance(Iter, j); + *Iter = OptionList.Str; - auto &AdvancedOption = AdvancedOptions.at(i); - size_t j = 0; - - bool Stop = false; - for (auto &OptionList : AdvancedOption) { - //ImGui::Text("%s", OptionList.Str); - if (ImGui::InputText(OptionList.Name.c_str(), OptionList.Str, sizeof(TmpString), ImGuiInputTextFlags_EnterReturnsTrue)) { - if (Option.second.size() == 1) { - LoadedConfig->EraseSet(Option.first, OptionList.Str); + LoadedConfig->Erase(Option.first); + for (auto& Value : All) { + LoadedConfig->Set(Option.first, Value); } - else { - auto &All = Option.second; - auto Iter = All.begin(); - std::advance(Iter, j); - *Iter = OptionList.Str; - - LoadedConfig->Erase(Option.first); - for (auto &Value : All) { - LoadedConfig->Set(Option.first, Value); - } - - } - ConfigChanged = true; - UpdateAdvancedOptionsVector(); } - - ImGui::SameLine(); - - ImGui::PushID(OptionList.Name.c_str()); - if (ImGui::SmallButton("-")) { - if (Option.second.size() == 1) { - LoadedConfig->Erase(Option.first); - } - else { - auto &All = Option.second; - auto Iter = All.begin(); - std::advance(Iter, j); - All.erase(Iter); - - LoadedConfig->Erase(Option.first); - for (auto &Value : All) { - LoadedConfig->Set(Option.first, Value); - } - } - Stop = true; - ConfigChanged = true; - UpdateAdvancedOptionsVector(); - } - ImGui::PopID(); - - ++j; + ConfigChanged = true; + UpdateAdvancedOptionsVector(); } - ImGui::NextColumn(); - ++i; - if (Stop) { - break; + ImGui::SameLine(); + + ImGui::PushID(OptionList.Name.c_str()); + if (ImGui::SmallButton("-")) { + if (Option.second.size() == 1) { + LoadedConfig->Erase(Option.first); + } else { + auto& All = Option.second; + auto Iter = All.begin(); + std::advance(Iter, j); + All.erase(Iter); + + LoadedConfig->Erase(Option.first); + for (auto& Value : All) { + LoadedConfig->Set(Option.first, Value); + } + } + Stop = true; + ConfigChanged = true; + UpdateAdvancedOptionsVector(); } + ImGui::PopID(); + + ++j; + } + + ImGui::NextColumn(); + ++i; + if (Stop) { + break; } } - ImGui::EndTabItem(); } + ImGui::EndTabItem(); } +} - void FillConfigWindow() { - ImGui::BeginTabBar("Config"); - FillCPUConfig(); - FillEmulationConfig(); - FillLoggingConfig(); - FillHackConfig(); - FillAdvancedConfig(); - ImGui::EndTabBar(); - } +void FillConfigWindow() { + ImGui::BeginTabBar("Config"); + FillCPUConfig(); + FillEmulationConfig(); + FillLoggingConfig(); + FillHackConfig(); + FillAdvancedConfig(); + ImGui::EndTabBar(); +} - bool DrawUI() { - ImGuiIO& io = ImGui::GetIO(); - auto current_time = std::chrono::high_resolution_clock::now(); - auto Diff = std::chrono::duration_cast(current_time - GlobalTime); - io.DeltaTime = Diff.count() > 0 ? Diff.count() : 1.0f/60.0f; - GlobalTime = current_time; +bool DrawUI() { + ImGuiIO& io = ImGui::GetIO(); + auto current_time = std::chrono::high_resolution_clock::now(); + auto Diff = std::chrono::duration_cast(current_time - GlobalTime); + io.DeltaTime = Diff.count() > 0 ? Diff.count() : 1.0f / 60.0f; + GlobalTime = current_time; - ImGui::NewFrame(); + ImGui::NewFrame(); - // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, - // because it would be confusing to have two docking targets within each others. - ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; - ImGuiViewport* viewport = ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(viewport->Pos); - ImGui::SetNextWindowSize(viewport->Size); - ImGui::SetNextWindowViewport(viewport->ID); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; - window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, + // because it would be confusing to have two docking targets within each others. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; + ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->Pos); + ImGui::SetNextWindowSize(viewport->Size); + ImGui::SetNextWindowViewport(viewport->ID); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - ImGui::Begin("DockSpace", nullptr, window_flags); - ImGui::PopStyleVar(3); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + ImGui::Begin("DockSpace", nullptr, window_flags); + ImGui::PopStyleVar(3); - struct { - bool Open{}; - bool OpenDefault{}; - bool OpenAppProfile{}; - bool Save{}; - bool SaveAs{}; - bool SaveDefault{}; - bool Close{}; - bool Quit{}; - } Selected; + struct { + bool Open {}; + bool OpenDefault {}; + bool OpenAppProfile {}; + bool Save {}; + bool SaveAs {}; + bool SaveDefault {}; + bool Close {}; + bool Quit {}; + } Selected; - char AppName[256]{}; + char AppName[256] {}; - if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("File")) { - ImGui::MenuItem("Open", "CTRL+O", &Selected.Open, true); - ImGui::MenuItem("Open from default location", "CTRL+SHIFT+O", &Selected.OpenDefault, true); - ImGui::MenuItem("Open App profile", "CTRL+I", &Selected.OpenAppProfile, true); + if (ImGui::BeginMenuBar()) { + if (ImGui::BeginMenu("File")) { + ImGui::MenuItem("Open", "CTRL+O", &Selected.Open, true); + ImGui::MenuItem("Open from default location", "CTRL+SHIFT+O", &Selected.OpenDefault, true); + ImGui::MenuItem("Open App profile", "CTRL+I", &Selected.OpenAppProfile, true); - ImGui::MenuItem("Save", "CTRL+S", &Selected.Save, true); - ImGui::MenuItem("Save As", "CTRL+SHIFT+S", &Selected.SaveAs, true); - ImGui::MenuItem("Save As App profile", "CTRL+E", nullptr, true); - ImGui::MenuItem("Save Default", "CTRL+SHIFT+P", &Selected.SaveDefault, true); + ImGui::MenuItem("Save", "CTRL+S", &Selected.Save, true); + ImGui::MenuItem("Save As", "CTRL+SHIFT+S", &Selected.SaveAs, true); + ImGui::MenuItem("Save As App profile", "CTRL+E", nullptr, true); + ImGui::MenuItem("Save Default", "CTRL+SHIFT+P", &Selected.SaveDefault, true); - ImGui::MenuItem("Close", "CTRL+W", &Selected.Close, true); - ImGui::MenuItem("Quit", "CTRL+Q", &Selected.Quit, true); + ImGui::MenuItem("Close", "CTRL+W", &Selected.Close, true); + ImGui::MenuItem("Quit", "CTRL+Q", &Selected.Quit, true); - ImGui::EndMenu(); - } - - ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::GetFrameHeight()); - - if (ConfigOpen) { - if (ConfigChanged) { - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(1.0, 1.0, 0.0, 1.0)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.0, 1.0, 0.0, 1.0)); - } - else { - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0, 1.0, 0.0, 1.0)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.0, 1.0, 0.0, 1.0)); - } - } - else { - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(1.0, 0.0, 0.0, 1.0)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.0, 0.0, 0.0, 1.0)); - } - - ImGui::RadioButton("", true); - ImGui::PopStyleColor(2); - - ImGui::EndMenuBar(); + ImGui::EndMenu(); } + ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::GetFrameHeight()); + if (ConfigOpen) { - if (ImGui::BeginChild("#Config")) { - FillConfigWindow(); + if (ConfigChanged) { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(1.0, 1.0, 0.0, 1.0)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.0, 1.0, 0.0, 1.0)); + } else { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0, 1.0, 0.0, 1.0)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.0, 1.0, 0.0, 1.0)); } - - if (ImGui::IsKeyPressed(SDL_SCANCODE_E) && io.KeyCtrl && !io.KeyShift) { - ImGui::OpenPopup(SavedPopupAppName); - } - - ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x + viewport->Size.x / 2, viewport->Pos.y + viewport->Size.y / 2), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - if (ImGui::BeginPopupModal(SavedPopupAppName)) { - ImGui::SetKeyboardFocusHere(); - if (ImGui::InputText("App name", AppName, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { - fextl::string AppNameString = AppName; - fextl::string Filename = FEXCore::Config::GetApplicationConfig(AppNameString, false); - SaveFile(Filename); - ImGui::CloseCurrentPopup(); - } - - if (ImGui::IsKeyPressed(SDL_SCANCODE_ESCAPE)) { - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - - ImGui::EndChild(); + } else { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(1.0, 0.0, 0.0, 1.0)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.0, 0.0, 0.0, 1.0)); } - // Need this frame delay loop since ImGui doesn't allow us to enable a popup near the end of the frame - if (OpenMsgPopup) { - ImGui::OpenPopup(MsgPopupName); - OpenMsgPopup = false; + ImGui::RadioButton("", true); + ImGui::PopStyleColor(2); + + ImGui::EndMenuBar(); + } + + if (ConfigOpen) { + if (ImGui::BeginChild("#Config")) { + FillConfigWindow(); } - if (Selected.OpenAppProfile || - (ImGui::IsKeyPressed(SDL_SCANCODE_I) && io.KeyCtrl && !io.KeyShift)) { - ImGui::OpenPopup(OpenedPopupAppName); + if (ImGui::IsKeyPressed(SDL_SCANCODE_E) && io.KeyCtrl && !io.KeyShift) { + ImGui::OpenPopup(SavedPopupAppName); } - // Center the saved popup in the center of the window - ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x + viewport->Size.x / 2, viewport->Pos.y + viewport->Size.y / 2), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - - if (ImGui::BeginPopup(MsgPopupName)) { - ImGui::Text("%s", MsgMessage.c_str()); - if ((std::chrono::high_resolution_clock::now() - MsgTimerStart) >= std::chrono::seconds(2)) { - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - else if (SaveMsgIsOpen) { - SaveMsgIsOpen = false; - } - - ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x + viewport->Size.x / 2, viewport->Pos.y + viewport->Size.y / 2), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - if (ImGui::BeginPopupModal(OpenedPopupAppName)) { - + ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x + viewport->Size.x / 2, viewport->Pos.y + viewport->Size.y / 2), ImGuiCond_Appearing, + ImVec2(0.5f, 0.5f)); + if (ImGui::BeginPopupModal(SavedPopupAppName)) { ImGui::SetKeyboardFocusHere(); if (ImGui::InputText("App name", AppName, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { fextl::string AppNameString = AppName; fextl::string Filename = FEXCore::Config::GetApplicationConfig(AppNameString, false); - OpenFile(Filename, false); + SaveFile(Filename); ImGui::CloseCurrentPopup(); } @@ -906,70 +866,108 @@ namespace { ImGui::EndPopup(); } - if (Selected.Open || - (ImGui::IsKeyPressed(SDL_SCANCODE_O) && io.KeyCtrl && !io.KeyShift)) { - SelectedOpenFile = true; - } - if (Selected.OpenDefault || - (ImGui::IsKeyPressed(SDL_SCANCODE_O) && io.KeyCtrl && io.KeyShift)) { - if (OpenFile(FEXCore::Config::GetConfigFileLocation(), true)) { - LoadNamedRootFSFolder(); - SetupINotify(); - } - } - - if (Selected.Save || - (ImGui::IsKeyPressed(SDL_SCANCODE_S) && io.KeyCtrl && !io.KeyShift)) { - SaveFile(ConfigFilename); - } - if (Selected.SaveAs || - (ImGui::IsKeyPressed(SDL_SCANCODE_S) && io.KeyCtrl && io.KeyShift)) { - SelectedSaveFileAs = true; - } - - if (Selected.SaveDefault || - (ImGui::IsKeyPressed(SDL_SCANCODE_P) && io.KeyCtrl && io.KeyShift)) { - SaveFile(FEXCore::Config::GetConfigFileLocation()); - } - if (Selected.Close || - (ImGui::IsKeyPressed(SDL_SCANCODE_W) && io.KeyCtrl && !io.KeyShift)) { - CloseConfig(); - ShutdownINotify(); - } - - if (Selected.Quit || - (ImGui::IsKeyPressed(SDL_SCANCODE_Q) && io.KeyCtrl && !io.KeyShift)) { - Selected.Quit = true; - } - - ImGui::End(); // End dockspace - - char const *InitialPath; - char const *File; - - InitialPath = DialogOpen.chooseFileDialog(SelectedOpenFile, "./", ".json", "#Chose a config to load"); - File = DialogOpen.getChosenPath(); - if (strlen(InitialPath) > 0 && strlen(File) > 0) { - OpenFile(File); - } - - InitialPath = DialogSaveAs.saveFileDialog(SelectedSaveFileAs, "./", "Config.json", ".json", "#Choose where to save a config"); - File = DialogSaveAs.getChosenPath(); - if (strlen(InitialPath) > 0 && strlen(File) > 0) { - SaveFile(File); - } - - SelectedOpenFile = false; - SelectedSaveFileAs = false; - - ImGui::Render(); - - // Return true to keep rendering - return !Selected.Quit; + ImGui::EndChild(); } -} -int main(int argc, char **argv) { + // Need this frame delay loop since ImGui doesn't allow us to enable a popup near the end of the frame + if (OpenMsgPopup) { + ImGui::OpenPopup(MsgPopupName); + OpenMsgPopup = false; + } + + if (Selected.OpenAppProfile || (ImGui::IsKeyPressed(SDL_SCANCODE_I) && io.KeyCtrl && !io.KeyShift)) { + ImGui::OpenPopup(OpenedPopupAppName); + } + + // Center the saved popup in the center of the window + ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x + viewport->Size.x / 2, viewport->Pos.y + viewport->Size.y / 2), ImGuiCond_Appearing, + ImVec2(0.5f, 0.5f)); + + if (ImGui::BeginPopup(MsgPopupName)) { + ImGui::Text("%s", MsgMessage.c_str()); + if ((std::chrono::high_resolution_clock::now() - MsgTimerStart) >= std::chrono::seconds(2)) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } else if (SaveMsgIsOpen) { + SaveMsgIsOpen = false; + } + + ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x + viewport->Size.x / 2, viewport->Pos.y + viewport->Size.y / 2), ImGuiCond_Appearing, + ImVec2(0.5f, 0.5f)); + if (ImGui::BeginPopupModal(OpenedPopupAppName)) { + + ImGui::SetKeyboardFocusHere(); + if (ImGui::InputText("App name", AppName, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { + fextl::string AppNameString = AppName; + fextl::string Filename = FEXCore::Config::GetApplicationConfig(AppNameString, false); + OpenFile(Filename, false); + ImGui::CloseCurrentPopup(); + } + + if (ImGui::IsKeyPressed(SDL_SCANCODE_ESCAPE)) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + if (Selected.Open || (ImGui::IsKeyPressed(SDL_SCANCODE_O) && io.KeyCtrl && !io.KeyShift)) { + SelectedOpenFile = true; + } + if (Selected.OpenDefault || (ImGui::IsKeyPressed(SDL_SCANCODE_O) && io.KeyCtrl && io.KeyShift)) { + if (OpenFile(FEXCore::Config::GetConfigFileLocation(), true)) { + LoadNamedRootFSFolder(); + SetupINotify(); + } + } + + if (Selected.Save || (ImGui::IsKeyPressed(SDL_SCANCODE_S) && io.KeyCtrl && !io.KeyShift)) { + SaveFile(ConfigFilename); + } + if (Selected.SaveAs || (ImGui::IsKeyPressed(SDL_SCANCODE_S) && io.KeyCtrl && io.KeyShift)) { + SelectedSaveFileAs = true; + } + + if (Selected.SaveDefault || (ImGui::IsKeyPressed(SDL_SCANCODE_P) && io.KeyCtrl && io.KeyShift)) { + SaveFile(FEXCore::Config::GetConfigFileLocation()); + } + if (Selected.Close || (ImGui::IsKeyPressed(SDL_SCANCODE_W) && io.KeyCtrl && !io.KeyShift)) { + CloseConfig(); + ShutdownINotify(); + } + + if (Selected.Quit || (ImGui::IsKeyPressed(SDL_SCANCODE_Q) && io.KeyCtrl && !io.KeyShift)) { + Selected.Quit = true; + } + + ImGui::End(); // End dockspace + + const char* InitialPath; + const char* File; + + InitialPath = DialogOpen.chooseFileDialog(SelectedOpenFile, "./", ".json", "#Chose a config to load"); + File = DialogOpen.getChosenPath(); + if (strlen(InitialPath) > 0 && strlen(File) > 0) { + OpenFile(File); + } + + InitialPath = DialogSaveAs.saveFileDialog(SelectedSaveFileAs, "./", "Config.json", ".json", "#Choose where to save a config"); + File = DialogSaveAs.getChosenPath(); + if (strlen(InitialPath) > 0 && strlen(File) > 0) { + SaveFile(File); + } + + SelectedOpenFile = false; + SelectedSaveFileAs = false; + + ImGui::Render(); + + // Return true to keep rendering + return !Selected.Quit; +} +} // namespace + +int main(int argc, char** argv) { FEX::Config::InitializeConfigs(); fextl::string ImGUIConfig = FEXCore::Config::GetConfigDirectory(false) + "FEXConfig_imgui.ini"; @@ -983,8 +981,7 @@ int main(int argc, char **argv) { LoadNamedRootFSFolder(); SetupINotify(); } - } - else { + } else { if (OpenFile(FEXCore::Config::GetConfigFileLocation(), true)) { LoadNamedRootFSFolder(); SetupINotify(); diff --git a/Source/Tools/FEXGDBReader/FEXGDBReader.cpp b/Source/Tools/FEXGDBReader/FEXGDBReader.cpp index 36e909bd0..c1aa9812f 100644 --- a/Source/Tools/FEXGDBReader/FEXGDBReader.cpp +++ b/Source/Tools/FEXGDBReader/FEXGDBReader.cpp @@ -12,19 +12,19 @@ GDB_DECLARE_GPL_COMPATIBLE_READER; #define debugf(...) extern "C" { -static enum gdb_status read_debug_info(struct gdb_reader_funcs *self, struct gdb_symbol_callbacks *cbs, void *memory, long memory_sz) { - - info_t *info = (info_t *)memory; - blocks_t *blocks = (blocks_t *)(info->blocks_ofs + (long)memory); - gdb_line_mapping *lines = (gdb_line_mapping *)(info->lines_ofs + (long)memory); +static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb_symbol_callbacks* cbs, void* memory, long memory_sz) { + + info_t* info = (info_t*)memory; + blocks_t* blocks = (blocks_t*)(info->blocks_ofs + (long)memory); + gdb_line_mapping* lines = (gdb_line_mapping*)(info->lines_ofs + (long)memory); debugf("info: %p\n", info); debugf("info: s %p\n", info->filename); debugf("info: s %s\n", info->filename); debugf("info: l %d\n", info->nlines); debugf("info: b %d\n", info->nblocks); - struct gdb_object *object = cbs->object_open(cbs); - struct gdb_symtab *symtab = cbs->symtab_open(cbs, object, info->filename); + struct gdb_object* object = cbs->object_open(cbs); + struct gdb_symtab* symtab = cbs->symtab_open(cbs, object, info->filename); for (int i = 0; i < info->nblocks; i++) { debugf("info: %d\n", i); @@ -50,16 +50,18 @@ static enum gdb_status read_debug_info(struct gdb_reader_funcs *self, struct gdb return GDB_SUCCESS; } -enum gdb_status unwind_frame(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs) { return GDB_SUCCESS; } +enum gdb_status unwind_frame(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs) { + return GDB_SUCCESS; +} -struct gdb_frame_id get_frame_id(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs) { +struct gdb_frame_id get_frame_id(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs) { struct gdb_frame_id frame = {0x1234000, 0}; return frame; } -void destroy_reader(struct gdb_reader_funcs *self) {} +void destroy_reader(struct gdb_reader_funcs* self) {} -extern struct gdb_reader_funcs *gdb_init_reader(void) { +extern struct gdb_reader_funcs* gdb_init_reader(void) { static struct gdb_reader_funcs funcs = {GDB_READER_INTERFACE_VERSION, NULL, read_debug_info, unwind_frame, get_frame_id, destroy_reader}; return &funcs; } diff --git a/Source/Tools/FEXGetConfig/Main.cpp b/Source/Tools/FEXGetConfig/Main.cpp index fe6ebc427..e22da24a7 100644 --- a/Source/Tools/FEXGetConfig/Main.cpp +++ b/Source/Tools/FEXGetConfig/Main.cpp @@ -13,7 +13,7 @@ #include #include -int main(int argc, char **argv, char **envp) { +int main(int argc, char** argv, char** envp) { FEXCore::Config::Initialize(); FEXCore::Config::AddLayer(FEX::Config::CreateGlobalMainLayer()); FEXCore::Config::AddLayer(FEX::Config::CreateMainLayer()); @@ -22,23 +22,15 @@ int main(int argc, char **argv, char **envp) { FEXCore::Config::Load(); // Load the arguments - optparse::OptionParser Parser = optparse::OptionParser() - .description("Simple application to get a couple of FEX options"); + optparse::OptionParser Parser = optparse::OptionParser().description("Simple application to get a couple of FEX options"); - Parser.add_option("--install-prefix") - .action("store_true") - .help("Print the FEX install prefix"); + Parser.add_option("--install-prefix").action("store_true").help("Print the FEX install prefix"); - Parser.add_option("--app") - .help("Load an application profile for this application if it exists"); + Parser.add_option("--app").help("Load an application profile for this application if it exists"); - Parser.add_option("--current-rootfs") - .action("store_true") - .help("Print the directory that contains the FEX rootfs. Mounted in the case of squashfs"); + Parser.add_option("--current-rootfs").action("store_true").help("Print the directory that contains the FEX rootfs. Mounted in the case of squashfs"); - Parser.add_option("--version") - .action("store_true") - .help("Print the installed FEX-Emu version"); + Parser.add_option("--version").action("store_true").help("Print the installed FEX-Emu version"); optparse::Values Options = Parser.parse_args(argc, argv); diff --git a/Source/Tools/FEXLoader/AOT/AOTGenerator.cpp b/Source/Tools/FEXLoader/AOT/AOTGenerator.cpp index 88c4d44ef..aeddae3cf 100644 --- a/Source/Tools/FEXLoader/AOT/AOTGenerator.cpp +++ b/Source/Tools/FEXLoader/AOT/AOTGenerator.cpp @@ -16,21 +16,22 @@ #include namespace FEX::AOT { -void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection &Section) { +void AOTGenSection(FEXCore::Context::Context* CTX, ELFCodeLoader::LoadedSection& Section) { // Make sure this section is executable and big enough - if (!Section.Executable || Section.Size < 16) + if (!Section.Executable || Section.Size < 16) { return; + } fextl::set InitialBranchTargets; // Load the ELF again with symbol parsing this time - ELFLoader::ELFContainer container{Section.Filename, "", true}; + ELFLoader::ELFContainer container {Section.Filename, "", true}; // Add symbols to the branch targets list container.AddSymbols([&](ELFLoader::ELFSymbol* sym) { auto Destination = sym->Address + Section.ElfBase; - if (! (Destination >= Section.Base && Destination <= (Section.Base + Section.Size)) ) { + if (!(Destination >= Section.Base && Destination <= (Section.Base + Section.Size))) { return; // outside of current section, unlikely to be real code } @@ -43,7 +44,7 @@ void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection container.AddUnwindEntries([&](uintptr_t Entry) { auto Destination = Entry + Section.ElfBase; - if (! (Destination >= Section.Base && Destination <= (Section.Base + Section.Size)) ) { + if (!(Destination >= Section.Base && Destination <= (Section.Base + Section.Size))) { return; // outside of current section, unlikely to be real code } @@ -54,7 +55,7 @@ void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection // Scan the executable section and try to find function entries for (size_t Offset = 0; Offset < (Section.Size - 16); Offset++) { - uint8_t *pCode = (uint8_t *)(Section.Base + Offset); + uint8_t* pCode = (uint8_t*)(Section.Base + Offset); // Possible CALL if (*pCode == 0xE8) { @@ -63,11 +64,13 @@ void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection auto DestinationPtr = (uint8_t*)Destination; - if (! (Destination >= Section.Base && Destination <= (Section.Base + Section.Size)) ) + if (!(Destination >= Section.Base && Destination <= (Section.Base + Section.Size))) { continue; // outside of current section, unlikely to be real code + } - if (DestinationPtr[0] == 0 && DestinationPtr[1] == 0) + if (DestinationPtr[0] == 0 && DestinationPtr[1] == 0) { continue; // add al, [rax], unlikely to be real code + } InitialBranchTargets.insert(Destination); } @@ -88,7 +91,7 @@ void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection // Setup BranchTargets, Compiled sets from InitiaBranchTargets Compiled.insert(InitialBranchTargets.begin(), InitialBranchTargets.end()); - for (auto BranchTarget: InitialBranchTargets) { + for (auto BranchTarget : InitialBranchTargets) { BranchTargets.push(BranchTarget); } @@ -132,12 +135,14 @@ void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection if (ExternalBranchesLocal.size() > 0) { // Add them to the "to process" list QueueMutex.lock(); - for(auto Destination: ExternalBranchesLocal) { - if (! (Destination >= Section.Base && Destination <= (Section.Base + Section.Size)) ) - continue; - if (Compiled.contains(Destination)) - continue; - Compiled.insert(Destination); + for (auto Destination : ExternalBranchesLocal) { + if (!(Destination >= Section.Base && Destination <= (Section.Base + Section.Size))) { + continue; + } + if (Compiled.contains(Destination)) { + continue; + } + Compiled.insert(Destination); BranchTargets.push(Destination); } QueueMutex.unlock(); @@ -156,7 +161,7 @@ void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection } // Make sure all threads are finished - for (auto & Thread: ThreadPool) { + for (auto& Thread : ThreadPool) { Thread.join(); } @@ -164,4 +169,4 @@ void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection LogMan::Msg::IFmt("\nAll Done: {}", counter.load()); } -} +} // namespace FEX::AOT diff --git a/Source/Tools/FEXLoader/AOT/AOTGenerator.h b/Source/Tools/FEXLoader/AOT/AOTGenerator.h index 32cde0d49..5ce3eaa60 100644 --- a/Source/Tools/FEXLoader/AOT/AOTGenerator.h +++ b/Source/Tools/FEXLoader/AOT/AOTGenerator.h @@ -4,5 +4,5 @@ #include "ELFCodeLoader.h" namespace FEX::AOT { - void AOTGenSection(FEXCore::Context::Context *CTX, ELFCodeLoader::LoadedSection &Section); +void AOTGenSection(FEXCore::Context::Context* CTX, ELFCodeLoader::LoadedSection& Section); } diff --git a/Source/Tools/FEXLoader/ELFCodeLoader.h b/Source/Tools/FEXLoader/ELFCodeLoader.h index ffb5ec10e..6e5da79b3 100644 --- a/Source/Tools/FEXLoader/ELFCodeLoader.h +++ b/Source/Tools/FEXLoader/ELFCodeLoader.h @@ -38,7 +38,7 @@ #include #define PAGE_START(x) ((x) & ~(uintptr_t)(4095)) -#define PAGE_OFFSET(x) ((x) & 4095) +#define PAGE_OFFSET(x) ((x)&4095) #define PAGE_ALIGN(x) (((x) + 4095) & ~(uintptr_t)(4095)) class ELFCodeLoader final : public FEX::CodeLoader { @@ -54,18 +54,18 @@ class ELFCodeLoader final : public FEX::CodeLoader { uintptr_t BrkStart; uintptr_t StackPointer; - size_t CalculateTotalElfSize(const fextl::vector &headers) - { - auto first = std::find_if(headers.begin(), headers.end(), [](const Elf64_Phdr &Header) { return Header.p_type == PT_LOAD; }); - auto last = std::find_if(headers.rbegin(), headers.rend(), [](const Elf64_Phdr &Header) { return Header.p_type == PT_LOAD; }); + size_t CalculateTotalElfSize(const fextl::vector& headers) { + auto first = std::find_if(headers.begin(), headers.end(), [](const Elf64_Phdr& Header) { return Header.p_type == PT_LOAD; }); + auto last = std::find_if(headers.rbegin(), headers.rend(), [](const Elf64_Phdr& Header) { return Header.p_type == PT_LOAD; }); - if (first == headers.end()) + if (first == headers.end()) { return 0; + } return PAGE_ALIGN(last->p_vaddr + last->p_memsz); } - bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr &Header, int prot, int flags, FEX::HLE::SyscallHandler *const Handler) { + bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr& Header, int prot, int flags, FEX::HLE::SyscallHandler* const Handler) { auto addr = Base + PAGE_START(Header.p_vaddr); auto size = Header.p_filesz + PAGE_OFFSET(Header.p_vaddr); @@ -78,7 +78,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { return true; } - void *rv = Handler->GuestMmap(nullptr, (void*)addr, size, prot, flags, file.fd, off); + void* rv = Handler->GuestMmap(nullptr, (void*)addr, size, prot, flags, file.fd, off); if (rv == MAP_FAILED) { // uhoh, something went wrong @@ -95,22 +95,25 @@ class ELFCodeLoader final : public FEX::CodeLoader { } } - int MapFlags(const Elf64_Phdr &Header) { + int MapFlags(const Elf64_Phdr& Header) { int rv = 0; - if (Header.p_flags & PF_R) + if (Header.p_flags & PF_R) { rv |= PROT_READ; + } - if (Header.p_flags & PF_W) + if (Header.p_flags & PF_W) { rv |= PROT_WRITE; + } - if (Header.p_flags & PF_X) + if (Header.p_flags & PF_X) { rv |= PROT_EXEC; + } return rv; } - std::optional LoadElfFile(ELFParser& Elf, uintptr_t *BrkBase, FEX::HLE::SyscallHandler *const Handler, uint64_t LoadHint = 0) { + std::optional LoadElfFile(ELFParser& Elf, uintptr_t* BrkBase, FEX::HLE::SyscallHandler* const Handler, uint64_t LoadHint = 0) { uintptr_t LoadBase = 0; @@ -121,20 +124,22 @@ class ELFCodeLoader final : public FEX::CodeLoader { if (Elf.ehdr.e_type == ET_DYN) { // needs base address auto TotalSize = CalculateTotalElfSize(Elf.phdrs) + (BrkBase ? BRK_SIZE : 0); - LoadBase = (uintptr_t)Handler->GuestMmap(nullptr, reinterpret_cast(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + LoadBase = + (uintptr_t)Handler->GuestMmap(nullptr, reinterpret_cast(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if ((void*)LoadBase == MAP_FAILED) { return {}; } - //fprintf(stderr, "elf %d: %lx-%lx\n", Elf.fd, LoadBase, LoadBase + TotalSize); + // fprintf(stderr, "elf %d: %lx-%lx\n", Elf.fd, LoadBase, LoadBase + TotalSize); if (BrkBase) { *BrkBase = LoadBase + (TotalSize - BRK_SIZE); } } - for(const auto &Header: Elf.phdrs) { - if (Header.p_type != PT_LOAD) + for (const auto& Header : Elf.phdrs) { + if (Header.p_type != PT_LOAD) { continue; + } int MapProt = MapFlags(Header); int MapType = MAP_PRIVATE | MAP_DENYWRITE | MAP_FIXED; @@ -177,8 +182,8 @@ class ELFCodeLoader final : public FEX::CodeLoader { return LoadBase; } - static bool GetRandom(void *Data, size_t DataSize) { - ssize_t Result{}; + static bool GetRandom(void* Data, size_t DataSize) { + ssize_t Result {}; do { // This is guaranteed to not be interrupted by a signal, // since fewer than 256 bytes of RNG data are requested @@ -188,9 +193,9 @@ class ELFCodeLoader final : public FEX::CodeLoader { return Result != -1; } - public: +public: - static fextl::string ResolveRootfsFile(fextl::string const &File, fextl::string RootFS) { + static fextl::string ResolveRootfsFile(const fextl::string& File, fextl::string RootFS) { // If the path is relative then just run that if (File[0] != '/') { return File; @@ -199,7 +204,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { fextl::string RootFSLink = RootFS + File; char Filename[PATH_MAX]; - while(FHU::Symlinks::IsSymlink(RootFSLink.c_str())) { + while (FHU::Symlinks::IsSymlink(RootFSLink.c_str())) { // Do some special handling if the RootFS's linker is a symlink // Ubuntu's rootFS by default provides an absolute location symlink to the linker // Resolve this around back to the rootfs @@ -207,8 +212,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { if (SymlinkPath.starts_with('/')) { RootFSLink = RootFS; RootFSLink += SymlinkPath; - } - else { + } else { break; } } @@ -227,16 +231,18 @@ class ELFCodeLoader final : public FEX::CodeLoader { fextl::vector Sections; - ELFCodeLoader(fextl::string const &Filename, const std::string_view FEXFDString, fextl::string const &RootFS, [[maybe_unused]] fextl::vector const &args, fextl::vector const &ParsedArgs, char **const envp = nullptr, FEXCore::Config::Value *AdditionalEnvp = nullptr) : - Args {args} { + ELFCodeLoader(const fextl::string& Filename, const std::string_view FEXFDString, const fextl::string& RootFS, + [[maybe_unused]] const fextl::vector& args, const fextl::vector& ParsedArgs, + char** const envp = nullptr, FEXCore::Config::Value* AdditionalEnvp = nullptr) + : Args {args} { bool LoadedWithFD = false; int FD = getauxval(AT_EXECFD); if (!FEXFDString.empty()) { // If we passed the execve FD to us then use that. - const char *StartPtr = FEXFDString.data(); - char *EndPtr{}; + const char* StartPtr = FEXFDString.data(); + char* EndPtr {}; FD = ::strtol(StartPtr, &EndPtr, 10); if (EndPtr == StartPtr) { LogMan::Msg::AFmt("FEXInterpreter passed invalid FD to exececute: {}", FEXFDString); @@ -252,8 +258,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { return; } LoadedWithFD = true; - } - else { + } else { if (!MainElf.ReadElf(ResolveRootfsFile(Filename, RootFS)) && !MainElf.ReadElf(Filename)) { return; } @@ -273,28 +278,29 @@ class ELFCodeLoader final : public FEX::CodeLoader { #define AT_FLAGS_PRESERVE_ARGV0 1 #endif uint32_t HostKernel = FEX::HLE::SyscallHandler::CalculateHostKernelVersion(); - if ((HostKernel >= FEX::HLE::SyscallHandler::KernelVersion(5, 12, 0) && - (AtFlags & AT_FLAGS_PRESERVE_ARGV0)) || - LoadedWithFD){ + if ((HostKernel >= FEX::HLE::SyscallHandler::KernelVersion(5, 12, 0) && (AtFlags & AT_FLAGS_PRESERVE_ARGV0)) || LoadedWithFD) { // Erase the initial argument from the list in this case Args.erase(Args.begin()); } // Append any additional arguments from config - for (auto &Arg : AdditionalArguments.All()) { + for (auto& Arg : AdditionalArguments.All()) { Args.emplace_back(Arg); } if (!MainElf.InterpreterElf.empty()) { - if (!InterpElf.ReadElf(ResolveRootfsFile(MainElf.InterpreterElf, RootFS)) && !InterpElf.ReadElf(MainElf.InterpreterElf)) + if (!InterpElf.ReadElf(ResolveRootfsFile(MainElf.InterpreterElf, RootFS)) && !InterpElf.ReadElf(MainElf.InterpreterElf)) { return; + } - if (!InterpElf.InterpreterElf.empty()) + if (!InterpElf.InterpreterElf.empty()) { return; + } - if (InterpElf.type != MainElf.type) + if (InterpElf.type != MainElf.type) { return; + } } ElfValid = true; @@ -302,8 +308,9 @@ class ELFCodeLoader final : public FEX::CodeLoader { if (!!envp) { // If we had envp passed in then make sure to set it up on the guest for (unsigned i = 0;; ++i) { - if (envp[i] == nullptr) + if (envp[i] == nullptr) { break; + } EnvironmentVariables.emplace_back(envp[i]); } } @@ -328,7 +335,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { EnvironmentBackingSize += EnvironmentVariables[i].size() + 1; } - for (auto &Arg : ParsedArgs) { + for (auto& Arg : ParsedArgs) { LoaderArgs.emplace_back(Arg.c_str()); } } @@ -337,9 +344,15 @@ class ELFCodeLoader final : public FEX::CodeLoader { Sections.clear(); } - virtual uint64_t StackSize() const override { return STACK_SIZE; } - virtual uint64_t GetStackPointer() override { return StackPointer; } - virtual uint64_t DefaultRIP() const override { return Entrypoint; }; + virtual uint64_t StackSize() const override { + return STACK_SIZE; + } + virtual uint64_t GetStackPointer() override { + return StackPointer; + } + virtual uint64_t DefaultRIP() const override { + return Entrypoint; + }; struct auxv32_t { uint32_t key; @@ -351,11 +364,12 @@ class ELFCodeLoader final : public FEX::CodeLoader { uint64_t val; }; - bool MapMemory(FEX::HLE::SyscallHandler *const Handler) { - for (auto Header: MainElf.phdrs) { + bool MapMemory(FEX::HLE::SyscallHandler* const Handler) { + for (auto Header : MainElf.phdrs) { if (Header.p_type == PT_GNU_STACK) { - if (Header.p_flags & PF_X) + if (Header.p_flags & PF_X) { ExecutableStack = true; + } } // We ignore LOPROC..HIPROC here, kernel has a platform specific hook about it @@ -379,13 +393,13 @@ class ELFCodeLoader final : public FEX::CodeLoader { // // MAP_GROWSDOWN is required here. The default stack pointer allocated by the kernel is mapped with it. // Some libraries (like libfmod) will have a PT_GNU_STACK with executable stack bit set - // On dlopen glibc will check its current stack allocation permission bits (using internal expectations of allocation, not /proc/self/maps) - // If stack hasn't been allocated as executable then it will proceed to mprotect the range with the executable bit set + // On dlopen glibc will check its current stack allocation permission bits (using internal expectations of allocation, not + // /proc/self/maps) If stack hasn't been allocated as executable then it will proceed to mprotect the range with the executable bit set // Then it will mprotect the base stack page with `PROT_READ|PROT_WRITE|PROT_EXEC|PROT_GROWSDOWN` // If the original stack memory region wasn't allocated with MAP_GROWSDOWN then the mprotect with PROT_GROWSDOWN will fail with EINVAL // - // This is still technically a memory leak if the stack grows, but since the primary thread's stack only gets destroyed on process close, this is - // fine. + // This is still technically a memory leak if the stack grows, but since the primary thread's stack only gets destroyed on process + // close, this is fine. // Stacks need to be allocated at the hint location just like on a real x86 system. // These are 128MB regions on both x86-64 and x86. @@ -396,16 +410,17 @@ class ELFCodeLoader final : public FEX::CodeLoader { // Wine-preloader is expecting to allocate 32MB out of the total 128MB stack space in this case. Leaving 96MB for the application. // // If FEX doesn't allocate the stack in this region (nullptr mmap hint) then later allocations that FEX does will /eventually/ - // end up inside of this address space that wine allocates. This usually ends up being a JIT CodeBuffer, which zeroes the memory and faults with a - // SIGILL. + // end up inside of this address space that wine allocates. This usually ends up being a JIT CodeBuffer, which zeroes the memory and + // faults with a SIGILL. // // On the upside, this more accurately emulates how the kernel allocates stack space for the application when hinting at the location. // - void* StackPointerBase{}; + void* StackPointerBase {}; uint64_t StackHint = Is64BitMode() ? STACK_HINT_64 : STACK_HINT_32; // Allocate the base of the full 128MB stack range. - StackPointerBase = Handler->GuestMmap(nullptr, reinterpret_cast(StackHint), FULL_STACK_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0); + StackPointerBase = Handler->GuestMmap(nullptr, reinterpret_cast(StackHint), FULL_STACK_SIZE, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0); if (StackPointerBase == reinterpret_cast(~0ULL)) { LogMan::Msg::EFmt("Allocating stack failed"); @@ -413,9 +428,9 @@ class ELFCodeLoader final : public FEX::CodeLoader { } // Allocate with permissions the 8MB of regular stack size. - StackPointer = reinterpret_cast(Handler->GuestMmap(nullptr, - reinterpret_cast(reinterpret_cast(StackPointerBase) + FULL_STACK_SIZE - StackSize()), - StackSize(), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0)); + StackPointer = reinterpret_cast( + Handler->GuestMmap(nullptr, reinterpret_cast(reinterpret_cast(StackPointerBase) + FULL_STACK_SIZE - StackSize()), + StackSize(), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0)); if (StackPointer == ~0ULL) { LogMan::Msg::EFmt("Allocating stack failed"); @@ -450,14 +465,13 @@ class ELFCodeLoader final : public FEX::CodeLoader { // 55ccaf8d2000-55ccaf8d4000 rw-p 00020000 00:2a 4 /tmp/.FEXMount178532-oiFrTF/usr/bin/ls // 55ccaf8d4000-55ccb00d5000 rw-p 00000000 00:00 0 // <... Snip of misc allocations ...> - // 7fffff6c2000-7fffff6c4000 r--p 00000000 00:2a 22 /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 - // 7fffff6c4000-7fffff6ee000 r-xp 00002000 00:2a 22 /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 - // 7fffff6ee000-7fffff6f9000 r--p 0002c000 00:2a 22 /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 - // 7fffff6f9000-7fffff6fa000 ---p 00000000 00:00 0 - // 7fffff6fa000-7fffff6fe000 rw-p 00037000 00:2a 22 /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 - // 7fffff7fe000-7fffffffe000 rw-p 00000000 00:00 0 - // 7fffffffe000-7ffffffff000 r--p 00000000 08:82 7082611 /usr/share/fex-emu/GuestThunks/libVDSO-guest.so - // 7ffffffff000-800000000000 rw-p 00000000 00:00 0 + // 7fffff6c2000-7fffff6c4000 r--p 00000000 00:2a 22 /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 7fffff6c4000-7fffff6ee000 + // r-xp 00002000 00:2a 22 /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 7fffff6ee000-7fffff6f9000 + // r--p 0002c000 00:2a 22 /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 7fffff6f9000-7fffff6fa000 + // ---p 00000000 00:00 0 7fffff6fa000-7fffff6fe000 rw-p 00037000 00:2a 22 + // /tmp/.FEXMount178532-oiFrTF/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 7fffff7fe000-7fffffffe000 rw-p 00000000 00:00 0 7fffffffe000-7ffffffff000 + // r--p 00000000 08:82 7082611 /usr/share/fex-emu/GuestThunks/libVDSO-guest.so 7ffffffff000-800000000000 rw-p + // 00000000 00:00 0 uint64_t ELFLoadHint = 0; if (!MainElf.InterpreterElf.empty()) { @@ -487,8 +501,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { // live way outside the VA space. uint64_t HostVASize = 1ULL << FEXCore::Allocator::DetermineVASize(); ELFLoadHint = std::min(HostVASize, TASK_SIZE_64) / 3 * 2; - } - else { + } else { ELFLoadHint = TASK_SIZE_32 / 3 * 2; } #define ASLR_LOAD @@ -500,7 +513,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { if (!NoRandomize) { constexpr uint64_t ASLR_BITS_64 = 28; constexpr uint64_t ASLR_BITS_32 = 8; - uint64_t ASLR_Offset{}; + uint64_t ASLR_Offset {}; if (!GetRandom(&ASLR_Offset, sizeof(ASLR_Offset))) { // getrandom failed for some reason. ASLR_Offset = 0; @@ -509,8 +522,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { if (Is64BitMode()) { ASLR_Offset &= (1ULL << ASLR_BITS_64) - 1; - } - else { + } else { ASLR_Offset &= (1ULL << ASLR_BITS_32) - 1; } @@ -540,7 +552,8 @@ class ELFCodeLoader final : public FEX::CodeLoader { // XXX Randomise brk? - BrkStart = (uint64_t)Handler->GuestMmap(nullptr, (void*)BrkBase, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + BrkStart = + (uint64_t)Handler->GuestMmap(nullptr, (void*)BrkBase, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); if ((void*)BrkStart == MAP_FAILED) { LogMan::Msg::EFmt("Failed to allocate BRK @ {:x}, {}\n", BrkBase, errno); @@ -558,33 +571,33 @@ class ELFCodeLoader final : public FEX::CodeLoader { // All done // Setup AuxVars - AuxVariables.emplace_back(auxv_t{11, getauxval(AT_UID)}); // AT_UID - AuxVariables.emplace_back(auxv_t{12, getauxval(AT_EUID)}); // AT_EUID - AuxVariables.emplace_back(auxv_t{13, getauxval(AT_GID)}); // AT_GID - AuxVariables.emplace_back(auxv_t{14, getauxval(AT_EGID)}); // AT_EGID - AuxVariables.emplace_back(auxv_t{17, getauxval(AT_CLKTCK)}); // AT_CLKTIK - AuxVariables.emplace_back(auxv_t{6, 0x1000}); // AT_PAGESIZE - AuxRandom = &AuxVariables.emplace_back(auxv_t{25, ~0ULL}); // AT_RANDOM - AuxVariables.emplace_back(auxv_t{23, getauxval(AT_SECURE)}); // AT_SECURE - AuxVariables.emplace_back(auxv_t{8, 0}); // AT_FLAGS - AuxVariables.emplace_back(auxv_t{5, MainElf.phdrs.size()}); // AT_PHNUM - AuxVariables.emplace_back(auxv_t{16, HWCap}); // AT_HWCAP - AuxVariables.emplace_back(auxv_t{26, HWCap2}); // AT_HWCAP2 - AuxVariables.emplace_back(auxv_t{51, CalculateSignalStackSize()}); // AT_MINSIGSTKSZ - AuxPlatform = &AuxVariables.emplace_back(auxv_t{24, ~0ULL}); // AT_PLATFORM - AuxExecFN = &AuxVariables.emplace_back(auxv_t{AT_EXECFN, ~0ULL}); // AT_EXECFN + AuxVariables.emplace_back(auxv_t {11, getauxval(AT_UID)}); // AT_UID + AuxVariables.emplace_back(auxv_t {12, getauxval(AT_EUID)}); // AT_EUID + AuxVariables.emplace_back(auxv_t {13, getauxval(AT_GID)}); // AT_GID + AuxVariables.emplace_back(auxv_t {14, getauxval(AT_EGID)}); // AT_EGID + AuxVariables.emplace_back(auxv_t {17, getauxval(AT_CLKTCK)}); // AT_CLKTIK + AuxVariables.emplace_back(auxv_t {6, 0x1000}); // AT_PAGESIZE + AuxRandom = &AuxVariables.emplace_back(auxv_t {25, ~0ULL}); // AT_RANDOM + AuxVariables.emplace_back(auxv_t {23, getauxval(AT_SECURE)}); // AT_SECURE + AuxVariables.emplace_back(auxv_t {8, 0}); // AT_FLAGS + AuxVariables.emplace_back(auxv_t {5, MainElf.phdrs.size()}); // AT_PHNUM + AuxVariables.emplace_back(auxv_t {16, HWCap}); // AT_HWCAP + AuxVariables.emplace_back(auxv_t {26, HWCap2}); // AT_HWCAP2 + AuxVariables.emplace_back(auxv_t {51, CalculateSignalStackSize()}); // AT_MINSIGSTKSZ + AuxPlatform = &AuxVariables.emplace_back(auxv_t {24, ~0ULL}); // AT_PLATFORM + AuxExecFN = &AuxVariables.emplace_back(auxv_t {AT_EXECFN, ~0ULL}); // AT_EXECFN if (Is64BitMode()) { - AuxVariables.emplace_back(auxv_t{4, 0x38}); // AT_PHENT - } - else { - AuxVariables.emplace_back(auxv_t{4, 0x20}); // AT_PHENT + AuxVariables.emplace_back(auxv_t {4, 0x38}); // AT_PHENT + } else { + AuxVariables.emplace_back(auxv_t {4, 0x20}); // AT_PHENT auto VSyscallEntry = FEX::VDSO::GetVSyscallEntry(VDSOBase); if (!VSyscallEntry) [[unlikely]] { // If the VDSO thunk doesn't exist then we might not have a vsyscall entry. // Newer glibc requires vsyscall to exist now. So let's allocate a buffer and stick a vsyscall in to it. - auto VSyscallPage = Handler->GuestMmap(nullptr, nullptr, FEXCore::Utils::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + auto VSyscallPage = + Handler->GuestMmap(nullptr, nullptr, FEXCore::Utils::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); constexpr static uint8_t VSyscallCode[] = { 0xcd, 0x80, // int 0x80 0xc3, // ret @@ -594,18 +607,18 @@ class ELFCodeLoader final : public FEX::CodeLoader { VSyscallEntry = reinterpret_cast(VSyscallPage); } - AuxVariables.emplace_back(auxv_t{32, VSyscallEntry}); // AT_SYSINFO - Entry point to syscall + AuxVariables.emplace_back(auxv_t {32, VSyscallEntry}); // AT_SYSINFO - Entry point to syscall } if (VDSOBase) { - AuxVariables.emplace_back(auxv_t{33, reinterpret_cast(VDSOBase)}); // AT_SYSINFO_EHDR - Address of the start of VDSO + AuxVariables.emplace_back(auxv_t {33, reinterpret_cast(VDSOBase)}); // AT_SYSINFO_EHDR - Address of the start of VDSO } - AuxVariables.emplace_back(auxv_t{3, MainElfBase + MainElf.ehdr.e_phoff}); // Program header - AuxVariables.emplace_back(auxv_t{7, InterpeterElfBase}); // AT_BASE - Interpreter address - AuxVariables.emplace_back(auxv_t{9, MainElfEntrypoint}); // AT_ENTRY + AuxVariables.emplace_back(auxv_t {3, MainElfBase + MainElf.ehdr.e_phoff}); // Program header + AuxVariables.emplace_back(auxv_t {7, InterpeterElfBase}); // AT_BASE - Interpreter address + AuxVariables.emplace_back(auxv_t {9, MainElfEntrypoint}); // AT_ENTRY - AuxVariables.emplace_back(auxv_t{0, 0}); // Null ender + AuxVariables.emplace_back(auxv_t {0, 0}); // Null ender SetupStack(); @@ -616,31 +629,23 @@ class ELFCodeLoader final : public FEX::CodeLoader { } // Helper for stack setup - template - static void SetupPointers( - uintptr_t StackPointer, - uint64_t AuxVOffset, - uint64_t ArgumentOffset, - uint64_t EnvpOffset, - const fextl::vector &Args, - const fextl::vector &EnvironmentVariables, - const fextl::list &AuxVariables, - uint64_t *AuxTabBase, - uint64_t *AuxTabSize - ) { + template + static void SetupPointers(uintptr_t StackPointer, uint64_t AuxVOffset, uint64_t ArgumentOffset, uint64_t EnvpOffset, + const fextl::vector& Args, const fextl::vector& EnvironmentVariables, + const fextl::list& AuxVariables, uint64_t* AuxTabBase, uint64_t* AuxTabSize) { // Pointer list offsets - PointerType *ArgumentPointers = reinterpret_cast(StackPointer + PointerSize); - PointerType *PadPointers = reinterpret_cast(StackPointer + PointerSize + Args.size() * PointerSize); - PointerType *EnvpPointers = reinterpret_cast(StackPointer + PointerSize + Args.size() * PointerSize + PointerSize); - AuxType *AuxVPointers = reinterpret_cast(StackPointer + AuxVOffset); + PointerType* ArgumentPointers = reinterpret_cast(StackPointer + PointerSize); + PointerType* PadPointers = reinterpret_cast(StackPointer + PointerSize + Args.size() * PointerSize); + PointerType* EnvpPointers = reinterpret_cast(StackPointer + PointerSize + Args.size() * PointerSize + PointerSize); + AuxType* AuxVPointers = reinterpret_cast(StackPointer + AuxVOffset); // Arguments memory lives after everything else - uint8_t *ArgumentBackingBase = reinterpret_cast(StackPointer + ArgumentOffset); - uint8_t *EnvpBackingBase = reinterpret_cast(StackPointer + EnvpOffset); + uint8_t* ArgumentBackingBase = reinterpret_cast(StackPointer + ArgumentOffset); + uint8_t* EnvpBackingBase = reinterpret_cast(StackPointer + EnvpOffset); PointerType ArgumentBackingBaseGuest = StackPointer + ArgumentOffset; PointerType EnvpBackingBaseGuest = StackPointer + EnvpOffset; - *reinterpret_cast(StackPointer + 0) = Args.size(); + *reinterpret_cast(StackPointer + 0) = Args.size(); PadPointers[0] = 0; // If we don't have any, just make sure the first is nullptr @@ -680,7 +685,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { // Last envp needs to be nullptr EnvpPointers[EnvironmentVariables.size()] = 0; - for (size_t i = 0; auto const &Variable : AuxVariables) { + for (size_t i = 0; const auto& Variable : AuxVariables) { AuxVPointers[i].key = Variable.key; AuxVPointers[i].val = Variable.val; ++i; @@ -696,19 +701,18 @@ class ELFCodeLoader final : public FEX::CodeLoader { // Set up our initial CPU state uint64_t SizeOfPointer = Is64BitMode() ? 8 : 4; - uint64_t TotalArgumentMemSize{}; + uint64_t TotalArgumentMemSize {}; - TotalArgumentMemSize += SizeOfPointer; // Argument counter size - TotalArgumentMemSize += SizeOfPointer * Args.size(); // Pointers to strings - TotalArgumentMemSize += SizeOfPointer; // Padding for something + TotalArgumentMemSize += SizeOfPointer; // Argument counter size + TotalArgumentMemSize += SizeOfPointer * Args.size(); // Pointers to strings + TotalArgumentMemSize += SizeOfPointer; // Padding for something TotalArgumentMemSize += SizeOfPointer * EnvironmentVariables.size(); // Argument location for envp - TotalArgumentMemSize += SizeOfPointer; // envp nullptr ender + TotalArgumentMemSize += SizeOfPointer; // envp nullptr ender uint64_t AuxVOffset = TotalArgumentMemSize; if (SizeOfPointer == 8) { TotalArgumentMemSize += sizeof(auxv_t) * AuxVariables.size(); - } - else { + } else { TotalArgumentMemSize += sizeof(auxv32_t) * AuxVariables.size(); } @@ -722,7 +726,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { uint64_t RandomNumberLocation = TotalArgumentMemSize; TotalArgumentMemSize += 16; - uint64_t PlatformNameLocation = TotalArgumentMemSize; + uint64_t PlatformNameLocation = TotalArgumentMemSize; TotalArgumentMemSize += platform_string_max_size; uint64_t ExecFNLocation = TotalArgumentMemSize; @@ -733,25 +737,23 @@ class ELFCodeLoader final : public FEX::CodeLoader { // Setup our AUXP values that need memory now that the stack is setup AuxPlatform->val = StackPointer + PlatformNameLocation; - char *PlatformLoc = reinterpret_cast(AuxPlatform->val); + char* PlatformLoc = reinterpret_cast(AuxPlatform->val); memset(PlatformLoc, 0, platform_string_max_size); if (Is64BitMode()) { strncpy(PlatformLoc, platform_name_x86_64.data(), platform_string_max_size); - } - else { + } else { strncpy(PlatformLoc, platform_name_i686.data(), platform_string_max_size); } // Random value is always 128bits AuxRandom->val = StackPointer + RandomNumberLocation; - uint64_t *RandomLoc = reinterpret_cast(AuxRandom->val); - uint64_t *HostRandom = reinterpret_cast(getauxval(AT_RANDOM)); + uint64_t* RandomLoc = reinterpret_cast(AuxRandom->val); + uint64_t* HostRandom = reinterpret_cast(getauxval(AT_RANDOM)); if (HostRandom) { // Pass through the host's random values RandomLoc[0] = HostRandom[0]; RandomLoc[1] = HostRandom[1]; - } - else { + } else { // Nothing provided from the kernel, generate our own random values. if (!GetRandom(&RandomLoc[0], sizeof(uint64_t) * 2)) { // getrandom failed for some reason. @@ -780,35 +782,20 @@ class ELFCodeLoader final : public FEX::CodeLoader { // [envpend, +8): nullptr if (SizeOfPointer == 8) { - SetupPointers( - StackPointer, - AuxVOffset, - ArgumentOffset, - EnvpOffset, - Args, - EnvironmentVariables, - AuxVariables, - &AuxTabBase, - &AuxTabSize - ); - } - else { - SetupPointers( - StackPointer, - AuxVOffset, - ArgumentOffset, - EnvpOffset, - Args, - EnvironmentVariables, - AuxVariables, - &AuxTabBase, - &AuxTabSize - ); + SetupPointers(StackPointer, AuxVOffset, ArgumentOffset, EnvpOffset, Args, EnvironmentVariables, AuxVariables, + &AuxTabBase, &AuxTabSize); + } else { + SetupPointers(StackPointer, AuxVOffset, ArgumentOffset, EnvpOffset, Args, EnvironmentVariables, AuxVariables, + &AuxTabBase, &AuxTabSize); } } - fextl::vector const *GetApplicationArguments() override { return &Args; } - void GetExecveArguments(fextl::vector *Args) override { *Args = LoaderArgs; } + const fextl::vector* GetApplicationArguments() override { + return &Args; + } + void GetExecveArguments(fextl::vector* Args) override { + *Args = LoaderArgs; + } void GetAuxv(uint64_t& addr, uint64_t& size) override { addr = AuxTabBase; @@ -824,7 +811,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { } ::ELFLoader::ELFContainer::BRKInfo GetBRKInfo() { - return ::ELFLoader::ELFContainer::BRKInfo { BrkStart, BRK_SIZE }; + return ::ELFLoader::ELFContainer::BRKInfo {BrkStart, BRK_SIZE}; } bool ELFWasLoaded() { @@ -835,7 +822,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { VDSOBase = Base; } - void CalculateHWCaps(FEXCore::Context::Context *ctx) { + void CalculateHWCaps(FEXCore::Context::Context* ctx) { // HWCAP is just CPUID function 0x1, the EDX result auto res_1 = ctx->RunCPUIDFunction(1, 0); auto res_7 = ctx->RunCPUIDFunction(7, 0); @@ -865,30 +852,27 @@ class ELFCodeLoader final : public FEX::CodeLoader { // - siginfo_t // Size of state requiring to be stored is different between 32-bit and 64-bit. - uint64_t Result{}; + uint64_t Result {}; if (Is64BitMode()) { Result += sizeof(FEXCore::x86_64::ucontext_t); Result = FEXCore::AlignUp(Result, alignof(FEXCore::x86_64::ucontext_t)); if (SupportsAVX) { Result += sizeof(FEXCore::x86_64::xstate); Result = FEXCore::AlignUp(Result, alignof(FEXCore::x86_64::xstate)); - } - else { + } else { Result += sizeof(FEXCore::x86_64::_libc_fpstate); Result = FEXCore::AlignUp(Result, alignof(FEXCore::x86_64::_libc_fpstate)); } Result += sizeof(siginfo_t); Result = FEXCore::AlignUp(Result, alignof(siginfo_t)); - } - else { + } else { Result += sizeof(FEXCore::x86::ucontext_t); Result = FEXCore::AlignUp(Result, alignof(FEXCore::x86::ucontext_t)); if (SupportsAVX) { Result += sizeof(FEXCore::x86::xstate); Result = FEXCore::AlignUp(Result, alignof(FEXCore::x86::xstate)); - } - else { + } else { Result += sizeof(FEXCore::x86::_libc_fpstate); Result = FEXCore::AlignUp(Result, alignof(FEXCore::x86::_libc_fpstate)); } @@ -908,21 +892,21 @@ class ELFCodeLoader final : public FEX::CodeLoader { fextl::vector Args; fextl::vector EnvironmentVariables; - fextl::vector LoaderArgs; + fextl::vector LoaderArgs; fextl::list AuxVariables; uint64_t AuxTabBase, AuxTabSize; - uint64_t ArgumentBackingSize{}; - uint64_t EnvironmentBackingSize{}; - uint64_t BaseOffset{}; - void* VDSOBase{}; - uint64_t HWCap{}; - uint64_t HWCap2{}; - bool SupportsAVX{}; + uint64_t ArgumentBackingSize {}; + uint64_t EnvironmentBackingSize {}; + uint64_t BaseOffset {}; + void* VDSOBase {}; + uint64_t HWCap {}; + uint64_t HWCap2 {}; + bool SupportsAVX {}; - auxv_t *AuxRandom{}; - auxv_t *AuxPlatform{}; - auxv_t *AuxExecFN{}; + auxv_t* AuxRandom {}; + auxv_t* AuxPlatform {}; + auxv_t* AuxExecFN {}; static constexpr std::string_view platform_name_x86_64 = "x86_64"; static constexpr std::string_view platform_name_i686 = "i686"; @@ -931,5 +915,4 @@ class ELFCodeLoader final : public FEX::CodeLoader { FEX_CONFIG_OPT(AdditionalArguments, ADDITIONALARGUMENTS); FEX_CONFIG_OPT(InjectLibSegFault, INJECTLIBSEGFAULT); - }; diff --git a/Source/Tools/FEXLoader/FEXLoader.cpp b/Source/Tools/FEXLoader/FEXLoader.cpp index 797ba75c1..66e38a6ca 100644 --- a/Source/Tools/FEXLoader/FEXLoader.cpp +++ b/Source/Tools/FEXLoader/FEXLoader.cpp @@ -65,7 +65,7 @@ static bool SilentLog; static int OutputFD {-1}; static bool ExecutedWithFD {false}; -void MsgHandler(LogMan::DebugLevels Level, char const *Message) { +void MsgHandler(LogMan::DebugLevels Level, const char* Message) { if (SilentLog) { return; } @@ -75,7 +75,7 @@ void MsgHandler(LogMan::DebugLevels Level, char const *Message) { fsync(OutputFD); } -void AssertHandler(char const *Message) { +void AssertHandler(const char* Message) { if (SilentLog) { return; } @@ -88,53 +88,53 @@ void AssertHandler(char const *Message) { } // Anonymous namespace namespace FEXServerLogging { - int FEXServerFD{-1}; - void MsgHandler(LogMan::DebugLevels Level, char const *Message) { - FEXServerClient::MsgHandler(FEXServerFD, Level, Message); - } - - void AssertHandler(char const *Message) { - FEXServerClient::AssertHandler(FEXServerFD, Message); - } +int FEXServerFD {-1}; +void MsgHandler(LogMan::DebugLevels Level, const char* Message) { + FEXServerClient::MsgHandler(FEXServerFD, Level, Message); } +void AssertHandler(const char* Message) { + FEXServerClient::AssertHandler(FEXServerFD, Message); +} +} // namespace FEXServerLogging + namespace AOTIR { - class AOTIRWriterFD final : public FEXCore::Context::AOTIRWriter { - public: - AOTIRWriterFD(const fextl::string &Path) { - // Create and truncate if exists. - constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; - FD = open(Path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, USER_PERMS); - } +class AOTIRWriterFD final : public FEXCore::Context::AOTIRWriter { +public: + AOTIRWriterFD(const fextl::string& Path) { + // Create and truncate if exists. + constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; + FD = open(Path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, USER_PERMS); + } - operator bool() const { - return FD != -1; - } + operator bool() const { + return FD != -1; + } - void Write(const void* Data, size_t Size) override { - write(FD, Data, Size); - } + void Write(const void* Data, size_t Size) override { + write(FD, Data, Size); + } - size_t Offset() override { - return lseek(FD, 0, SEEK_CUR); - } + size_t Offset() override { + return lseek(FD, 0, SEEK_CUR); + } - void Close() override { - if (FD != -1) { - close(FD); - FD = -1; - } - } + void Close() override { + if (FD != -1) { + close(FD); + FD = -1; + } + } - virtual ~AOTIRWriterFD() { - Close(); - } - private: - int FD{-1}; - }; -} + virtual ~AOTIRWriterFD() { + Close(); + } +private: + int FD {-1}; +}; +} // namespace AOTIR -void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fextl::vector *args) { +void InterpreterHandler(fextl::string* Filename, const fextl::string& RootFS, fextl::vector* args) { // Open the Filename to determine if it is a shebang file. int FD = open(Filename->c_str(), O_RDONLY | O_CLOEXEC); if (FD == -1) { @@ -154,13 +154,10 @@ void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fe } // Handle shebang files - if (Data[0] == '#' && - Data[1] == '!') { - fextl::string InterpreterLine { - Data.begin() + 2, // strip off "#!" prefix - std::find(Data.begin(), Data.end(), '\n') - }; - fextl::vector ShebangArguments{}; + if (Data[0] == '#' && Data[1] == '!') { + fextl::string InterpreterLine {Data.begin() + 2, // strip off "#!" prefix + std::find(Data.begin(), Data.end(), '\n')}; + fextl::vector ShebangArguments {}; // Shebang line can have a single argument fextl::istringstream InterpreterSS(InterpreterLine); @@ -173,7 +170,7 @@ void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fe } // Executable argument - fextl::string &ShebangProgram = ShebangArguments[0]; + fextl::string& ShebangProgram = ShebangArguments[0]; // If the filename is absolute then prepend the rootfs // If it is relative then don't append the rootfs @@ -188,7 +185,7 @@ void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fe close(FD); } -void RootFSRedirect(fextl::string *Filename, fextl::string const &RootFS) { +void RootFSRedirect(fextl::string* Filename, const fextl::string& RootFS) { auto RootFSLink = ELFCodeLoader::ResolveRootfsFile(*Filename, RootFS); if (FHU::Filesystem::Exists(RootFSLink)) { @@ -196,7 +193,7 @@ void RootFSRedirect(fextl::string *Filename, fextl::string const &RootFS) { } } -bool RanAsInterpreter(const char *Program) { +bool RanAsInterpreter(const char* Program) { return ExecutedWithFD || FEXLOADER_AS_INTERPRETER; } @@ -204,14 +201,12 @@ bool IsInterpreterInstalled() { // The interpreter is installed if both the binfmt_misc handlers are available // Or if we were originally executed with FD. Which means the interpreter is installed - return ExecutedWithFD || - (access("/proc/sys/fs/binfmt_misc/FEX-x86", F_OK) == 0 && - access("/proc/sys/fs/binfmt_misc/FEX-x86_64", F_OK) == 0); + return ExecutedWithFD || (access("/proc/sys/fs/binfmt_misc/FEX-x86", F_OK) == 0 && access("/proc/sys/fs/binfmt_misc/FEX-x86_64", F_OK) == 0); } namespace FEX::TSO { - void SetupTSOEmulation(FEXCore::Context::Context *CTX) { - // We need to check if these are defined or not. This is a very fresh feature. +void SetupTSOEmulation(FEXCore::Context::Context* CTX) { + // We need to check if these are defined or not. This is a very fresh feature. #ifndef PR_GET_MEM_MODEL #define PR_GET_MEM_MODEL 0x6d4d444c #endif @@ -224,50 +219,45 @@ namespace FEX::TSO { #ifndef PR_SET_MEM_MODEL_TSO #define PR_SET_MEM_MODEL_TSO 1 #endif - // Check to see if this is supported. - auto Result = prctl(PR_GET_MEM_MODEL, 0, 0, 0, 0); - if (Result == -1) { - // Unsupported, early exit. - return; - } + // Check to see if this is supported. + auto Result = prctl(PR_GET_MEM_MODEL, 0, 0, 0, 0); + if (Result == -1) { + // Unsupported, early exit. + return; + } - FEX_CONFIG_OPT(TSOEnabled, TSOENABLED); + FEX_CONFIG_OPT(TSOEnabled, TSOENABLED); - if (!TSOEnabled()) { - // TSO emulation isn't even enabled, early exit. - return; - } + if (!TSOEnabled()) { + // TSO emulation isn't even enabled, early exit. + return; + } - if (Result == PR_SET_MEM_MODEL_DEFAULT) { - // Try to set the TSO mode if we are currently default. - Result = prctl(PR_SET_MEM_MODEL, PR_SET_MEM_MODEL_TSO, 0, 0, 0); - if (Result == 0) { - // TSO mode successfully enabled. Tell the context to disable TSO emulation through atomics. - // This flag gets inherited on thread creation, so FEX only needs to set it at the start. - CTX->SetHardwareTSOSupport(true); - } + if (Result == PR_SET_MEM_MODEL_DEFAULT) { + // Try to set the TSO mode if we are currently default. + Result = prctl(PR_SET_MEM_MODEL, PR_SET_MEM_MODEL_TSO, 0, 0, 0); + if (Result == 0) { + // TSO mode successfully enabled. Tell the context to disable TSO emulation through atomics. + // This flag gets inherited on thread creation, so FEX only needs to set it at the start. + CTX->SetHardwareTSOSupport(true); } } } +} // namespace FEX::TSO -int main(int argc, char **argv, char **const envp) { +int main(int argc, char** argv, char** const envp) { auto SBRKPointer = FEXCore::Allocator::DisableSBRKAllocations(); FEXCore::Allocator::GLIBCScopedFault GLIBFaultScope; const bool IsInterpreter = RanAsInterpreter(argv[0]); ExecutedWithFD = getauxval(AT_EXECFD) != 0; const char* FEXFD = getenv("FEX_EXECVEFD"); - const std::string_view FEXFDView = FEXFD ? std::string_view{FEXFD} : std::string_view{}; + const std::string_view FEXFDView = FEXFD ? std::string_view {FEXFD} : std::string_view {}; LogMan::Throw::InstallHandler(AssertHandler); LogMan::Msg::InstallHandler(MsgHandler); - auto Program = FEX::Config::LoadConfig( - IsInterpreter, - true, - argc, argv, envp, - ExecutedWithFD, - FEXFDView); + auto Program = FEX::Config::LoadConfig(IsInterpreter, true, argc, argv, envp, ExecutedWithFD, FEXFDView); if (Program.ProgramPath.empty() && !FEXFD) { // Early exit if we weren't passed an argument @@ -316,8 +306,7 @@ int main(int argc, char **argv, char **const envp) { if (::SilentLog) { LogMan::Throw::UnInstallHandlers(); LogMan::Msg::UnInstallHandlers(); - } - else { + } else { auto LogFile = OutputLog(); // If stderr or stdout then we need to dup the FD // In some cases some applications will close stderr and stdout @@ -328,11 +317,9 @@ int main(int argc, char **argv, char **const envp) { // can run in to problems of writing to some file if (LogFile == "stderr") { OutputFD = dup(STDERR_FILENO); - } - else if (LogFile == "stdout") { + } else if (LogFile == "stdout") { OutputFD = dup(STDOUT_FILENO); - } - else if (LogFile == "server") { + } else if (LogFile == "server") { LogMan::Throw::UnInstallHandlers(); LogMan::Msg::UnInstallHandlers(); @@ -341,8 +328,7 @@ int main(int argc, char **argv, char **const envp) { LogMan::Throw::InstallHandler(FEXServerLogging::AssertHandler); LogMan::Msg::InstallHandler(FEXServerLogging::MsgHandler); } - } - else if (!LogFile.empty()) { + } else if (!LogFile.empty()) { OutputFD = open(LogFile.c_str(), O_CREAT | O_CLOEXEC | O_WRONLY); } } @@ -372,13 +358,13 @@ int main(int argc, char **argv, char **const envp) { } // Before we go any further, set all of our host environment variables that the config has provided - for (auto &HostEnv : HostEnvironment.All()) { + for (auto& HostEnv : HostEnvironment.All()) { // We are going to keep these alive in memory. // No need to split the string with setenv putenv(HostEnv.data()); } - ELFCodeLoader Loader{Program.ProgramPath, FEXFDView, LDPath(), Args, ParsedArgs, envp, &Environment}; + ELFCodeLoader Loader {Program.ProgramPath, FEXFDView, LDPath(), Args, ParsedArgs, envp, &Environment}; if (!Loader.ELFWasLoaded()) { // Loader couldn't load this program for some reason @@ -386,8 +372,7 @@ int main(int argc, char **argv, char **const envp) { #ifdef _M_ARM_64 fextl::fmt::print(stderr, "This is likely due to a misconfigured x86-64 RootFS\n"); fextl::fmt::print(stderr, "Current RootFS path set to '{}'\n", LDPath()); - if (LDPath().empty() || - FHU::Filesystem::Exists(LDPath()) == false) { + if (LDPath().empty() || FHU::Filesystem::Exists(LDPath()) == false) { fextl::fmt::print(stderr, "RootFS path doesn't exist. This is required on AArch64 hosts\n"); fextl::fmt::print(stderr, "Use FEXRootFSFetcher to download a RootFS\n"); } @@ -399,16 +384,14 @@ int main(int argc, char **argv, char **const envp) { // Don't need to canonicalize Program.ProgramPath, Config loader will have resolved this already. FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, Program.ProgramPath); FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_CONFIG_NAME, Program.ProgramName); - } - else if (FEXFD) { + } else if (FEXFD) { // Anonymous program. FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, ""); FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_CONFIG_NAME, ""); - } - else { + } else { { char ExistsTempPath[PATH_MAX]; - char *RealPath = realpath(Program.ProgramPath.c_str(), ExistsTempPath); + char* RealPath = realpath(Program.ProgramPath.c_str(), ExistsTempPath); if (RealPath) { FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, fextl::string(RealPath)); } @@ -459,8 +442,8 @@ int main(int argc, char **argv, char **const envp) { auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), Program.ProgramName); - auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get()) - : FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator)); + auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get()) : + FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator)); // Now that we have the syscall handler. Track some FDs that are FEX owned. if (OutputFD != -1) { @@ -514,7 +497,7 @@ int main(int argc, char **argv, char **const envp) { FEXCore::Context::ExitReason ShutdownReason = FEXCore::Context::ExitReason::EXIT_SHUTDOWN; // There might already be an exit handler, leave it installed - if(!CTX->GetExitHandler()) { + if (!CTX->GetExitHandler()) { CTX->SetExitHandler([&](uint64_t thread, FEXCore::Context::ExitReason reason) { if (reason != FEXCore::Context::ExitReason::EXIT_DEBUG) { ShutdownReason = reason; @@ -528,7 +511,7 @@ int main(int argc, char **argv, char **const envp) { LogMan::Msg::IFmt("Warning: AOTIR is experimental, and might lead to crashes. " "Capture doesn't work with programs that fork."); - CTX->SetAOTIRLoader([](const fextl::string &fileid) -> int { + CTX->SetAOTIRLoader([](const fextl::string& fileid) -> int { const auto filepath = fextl::fmt::format("{}/aotir/{}.aotir", FEXCore::Config::GetDataDirectory(), fileid); return open(filepath.c_str(), O_RDONLY); }); @@ -556,7 +539,7 @@ int main(int argc, char **argv, char **const envp) { } if (AOTIRGenerate()) { - for(auto &Section: Loader.Sections) { + for (auto& Section : Loader.Sections) { FEX::AOT::AOTGenSection(CTX.get(), Section); } } else { @@ -611,8 +594,7 @@ int main(int argc, char **argv, char **const envp) { if (ShutdownReason == FEXCore::Context::ExitReason::EXIT_SHUTDOWN) { return ProgramStatus; - } - else { + } else { return -64 | ShutdownReason; } } diff --git a/Source/Tools/FEXRootFSFetcher/Main.cpp b/Source/Tools/FEXRootFSFetcher/Main.cpp index 5edc97bcf..77864144a 100644 --- a/Source/Tools/FEXRootFSFetcher/Main.cpp +++ b/Source/Tools/FEXRootFSFetcher/Main.cpp @@ -22,1150 +22,1076 @@ #include namespace ArgOptions { - bool AssumeYes = false; - enum class CompressedImageOption { - OPTION_ASK, - OPTION_EXTRACT, - OPTION_ASIS, - }; +bool AssumeYes = false; +enum class CompressedImageOption { + OPTION_ASK, + OPTION_EXTRACT, + OPTION_ASIS, +}; - CompressedImageOption CompressedUsageOption {CompressedImageOption::OPTION_ASK}; +CompressedImageOption CompressedUsageOption {CompressedImageOption::OPTION_ASK}; - enum class ListQueryOption { - OPTION_ASK, - OPTION_FIRST, - }; +enum class ListQueryOption { + OPTION_ASK, + OPTION_FIRST, +}; - ListQueryOption DistroListOption {ListQueryOption::OPTION_ASK}; +ListQueryOption DistroListOption {ListQueryOption::OPTION_ASK}; - fextl::vector RemainingArgs; +fextl::vector RemainingArgs; - std::string DistroName{}; - std::string DistroVersion{}; +std::string DistroName {}; +std::string DistroVersion {}; - void ParseArguments(int argc, char **argv) { - optparse::OptionParser Parser = optparse::OptionParser() - .description("Tool for fetching RootFS from FEXServers") - .add_help_option(true); +void ParseArguments(int argc, char** argv) { + optparse::OptionParser Parser = optparse::OptionParser().description("Tool for fetching RootFS from FEXServers").add_help_option(true); - Parser.add_option("-y", "--assume-yes") - .action("store_true") - .help("Assume yes to prompts"); + Parser.add_option("-y", "--assume-yes").action("store_true").help("Assume yes to prompts"); - Parser.add_option("-x", "--extract") - .action("store_true") - .help("Extract compressed image"); + Parser.add_option("-x", "--extract").action("store_true").help("Extract compressed image"); - Parser.add_option("-a", "--as-is") - .action("store_true") - .help("Use compressed image as-is"); + Parser.add_option("-a", "--as-is").action("store_true").help("Use compressed image as-is"); - Parser.add_option("--distro-name") - .help("Which distro name to select"); + Parser.add_option("--distro-name").help("Which distro name to select"); - Parser.add_option("--distro-version") - .help("Which distro version to select"); + Parser.add_option("--distro-version").help("Which distro version to select"); - Parser.add_option("--distro-list-first") - .action("store_true") - .help("When presented the distro-list option, automatically select the first distro if there isn't an exact match."); + Parser.add_option("--distro-list-first").action("store_true").help("When presented the distro-list option, automatically select the first distro if there isn't an exact match."); - optparse::Values Options = Parser.parse_args(argc, argv); + optparse::Values Options = Parser.parse_args(argc, argv); - if (Options.is_set_by_user("assume_yes")) { - AssumeYes = Options.get("assume_yes"); - } - - if (Options.is_set_by_user("extract")) { - CompressedUsageOption = CompressedImageOption::OPTION_EXTRACT; - } - - if (Options.is_set_by_user("as_is")) { - CompressedUsageOption = CompressedImageOption::OPTION_ASIS; - } - - if (Options.is_set_by_user("distro_list_first")) { - DistroListOption = ListQueryOption::OPTION_FIRST; - } - - if (Options.is_set_by_user("distro_name")) { - DistroName = Options["distro_name"]; - } - - if (Options.is_set_by_user("distro_version")) { - DistroVersion = Options["distro_version"]; - } - - RemainingArgs = Parser.args(); + if (Options.is_set_by_user("assume_yes")) { + AssumeYes = Options.get("assume_yes"); } + + if (Options.is_set_by_user("extract")) { + CompressedUsageOption = CompressedImageOption::OPTION_EXTRACT; + } + + if (Options.is_set_by_user("as_is")) { + CompressedUsageOption = CompressedImageOption::OPTION_ASIS; + } + + if (Options.is_set_by_user("distro_list_first")) { + DistroListOption = ListQueryOption::OPTION_FIRST; + } + + if (Options.is_set_by_user("distro_name")) { + DistroName = Options["distro_name"]; + } + + if (Options.is_set_by_user("distro_version")) { + DistroVersion = Options["distro_version"]; + } + + RemainingArgs = Parser.args(); } +} // namespace ArgOptions namespace Exec { - int32_t ExecAndWaitForResponse(const char *path, char* const* args) { - pid_t pid = fork(); - if (pid == 0) { - execvp(path, args); - _exit(-1); +int32_t ExecAndWaitForResponse(const char* path, char* const* args) { + pid_t pid = fork(); + if (pid == 0) { + execvp(path, args); + _exit(-1); + } else { + int32_t Status {}; + waitpid(pid, &Status, 0); + if (WIFEXITED(Status)) { + return (int8_t)WEXITSTATUS(Status); } - else { - int32_t Status{}; - waitpid(pid, &Status, 0); - if (WIFEXITED(Status)) { - return (int8_t)WEXITSTATUS(Status); - } - } - - return -1; } - int32_t ExecAndWaitForResponseRedirect(const char *path, char* const* args, int stdoutRedirect = -2, int stderrRedirect = -2) { - pid_t pid = fork(); - if (pid == 0) { - if (stdoutRedirect == -1) { + return -1; +} + +int32_t ExecAndWaitForResponseRedirect(const char* path, char* const* args, int stdoutRedirect = -2, int stderrRedirect = -2) { + pid_t pid = fork(); + if (pid == 0) { + if (stdoutRedirect == -1) { + close(STDOUT_FILENO); + } else if (stdoutRedirect == -2) { + // Do nothing + } else { + if (stdoutRedirect != STDOUT_FILENO) { close(STDOUT_FILENO); } - else if (stdoutRedirect == -2) { - // Do nothing - } - else { - if (stdoutRedirect != STDOUT_FILENO) { - close(STDOUT_FILENO); - } - dup2(stdoutRedirect, STDOUT_FILENO); - } - if (stderrRedirect == -1) { + dup2(stdoutRedirect, STDOUT_FILENO); + } + if (stderrRedirect == -1) { + close(STDERR_FILENO); + } else if (stderrRedirect == -2) { + // Do nothing + } else { + if (stderrRedirect != STDOUT_FILENO) { close(STDERR_FILENO); } - else if (stderrRedirect == -2) { - // Do nothing - } - else { - if (stderrRedirect != STDOUT_FILENO) { - close(STDERR_FILENO); - } - dup2(stderrRedirect, STDERR_FILENO); - } - execvp(path, args); - _exit(-1); + dup2(stderrRedirect, STDERR_FILENO); } - else { - int32_t Status{}; - while (waitpid(pid, &Status, 0) == -1 && errno == EINTR); - if (WIFEXITED(Status)) { - return (int8_t)WEXITSTATUS(Status); - } + execvp(path, args); + _exit(-1); + } else { + int32_t Status {}; + while (waitpid(pid, &Status, 0) == -1 && errno == EINTR) + ; + if (WIFEXITED(Status)) { + return (int8_t)WEXITSTATUS(Status); } - - return -1; } - std::string ExecAndWaitForResponseText(const char *path, char* const* args) { - int fd[2]; - pipe(fd); - - pid_t pid = fork(); - - if (pid == 0) { - close(fd[0]); // Close read side - - // Redirect stdout to pipe - dup2(fd[1], STDOUT_FILENO); - - // Close stderr - close(STDERR_FILENO); - - // We can now close the pipe since the duplications take care of the rest - close(fd[1]); - - execvp(path, args); - _exit(-1); - } - else { - close(fd[1]); // Close write side - - // Nothing larger than this - char Buffer[1024]{}; - std::string Output{}; - - // Read the pipe until it closes - while (size_t Size = read(fd[0], Buffer, sizeof(Buffer))) { - Output += std::string_view(Buffer, Size); - } - - int32_t Status{}; - while (waitpid(pid, &Status, 0) == -1 && errno == EINTR); - if (WIFEXITED(Status)) { - // Return what we've read - close(fd[0]); - return Output; - } - } - - return {}; - } + return -1; } +std::string ExecAndWaitForResponseText(const char* path, char* const* args) { + int fd[2]; + pipe(fd); + + pid_t pid = fork(); + + if (pid == 0) { + close(fd[0]); // Close read side + + // Redirect stdout to pipe + dup2(fd[1], STDOUT_FILENO); + + // Close stderr + close(STDERR_FILENO); + + // We can now close the pipe since the duplications take care of the rest + close(fd[1]); + + execvp(path, args); + _exit(-1); + } else { + close(fd[1]); // Close write side + + // Nothing larger than this + char Buffer[1024] {}; + std::string Output {}; + + // Read the pipe until it closes + while (size_t Size = read(fd[0], Buffer, sizeof(Buffer))) { + Output += std::string_view(Buffer, Size); + } + + int32_t Status {}; + while (waitpid(pid, &Status, 0) == -1 && errno == EINTR) + ; + if (WIFEXITED(Status)) { + // Return what we've read + close(fd[0]); + return Output; + } + } + + return {}; +} +} // namespace Exec + namespace WorkingAppsTester { - static bool Has_Curl {false}; - static bool Has_Squashfuse {false}; - static bool Has_Unsquashfs {false}; +static bool Has_Curl {false}; +static bool Has_Squashfuse {false}; +static bool Has_Unsquashfs {false}; - // EroFS specific - static bool Has_EroFSFuse {false}; - static bool Has_EroFSFsck {false}; +// EroFS specific +static bool Has_EroFSFuse {false}; +static bool Has_EroFSFsck {false}; - void CheckCurl() { - // Check if curl exists on the host - std::vector ExecveArgs = { - "curl", - "-V", - nullptr, - }; - - int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); - Has_Curl = Result != -1; - } - - void CheckSquashfuse() { - std::vector ExecveArgs = { - "squashfuse", - "--help", - nullptr, - }; - - int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); - Has_Squashfuse = Result != -1; - } - - void CheckUnsquashfs() { - std::vector ExecveArgs = { - "unsquashfs", - "--help", - nullptr, - }; - - int fd = ::syscall(SYS_memfd_create, "stdout", 0); - int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), fd, fd); - Has_Unsquashfs = Result != -1; - if (Has_Unsquashfs) { - // Seek back to the start - lseek(fd, 0, SEEK_SET); - - // Unsquashfs needs to support zstd - // Scan its output to find the zstd compressor - FILE *fp = fdopen(fd, "r"); - char *Line {nullptr}; - size_t Len; - - bool ReadingDecompressors = false; - bool SupportsZSTD = false; - while (getline(&Line, &Len, fp) != -1) { - if (!ReadingDecompressors) { - if (strstr(Line, "Decompressors available")) { - ReadingDecompressors = true; - } - } - else { - if (strstr(Line, "zstd")) { - SupportsZSTD = true; - } - } - } - - free(Line); - fclose(fp); - - // Disable unsquashfs if it doesn't support ZSTD - if (!SupportsZSTD) { - Has_Unsquashfs = false; - } - } - close(fd); - } - - // EroFS specific tests - void CheckEroFSFuse() { - std::vector ExecveArgs = { - "erofsfuse", - "--help", - nullptr, - }; - - int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); - Has_EroFSFuse = Result != -1; - } - - void CheckEroFSFsck() { - std::vector ExecveArgs = { - "fsck.erofs", - "-V", - nullptr, - }; - - int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); - Has_EroFSFsck = Result != -1; - } - - void Init() { - CheckCurl(); - CheckSquashfuse(); - CheckUnsquashfs(); - CheckEroFSFuse(); - CheckEroFSFsck(); - } -} - -namespace DistroQuery { - struct DistroInfo { - std::string DistroName; - std::string DistroVersion; - bool RollingRelease; - bool Unknown; +void CheckCurl() { + // Check if curl exists on the host + std::vector ExecveArgs = { + "curl", + "-V", + nullptr, }; - DistroInfo GetDistroInfo() { - // Detect these files in order - // - // /etc/lsb-release - // eg: - // DISTRIB_ID=Ubuntu - // DISTRIB_RELEASE=21.10 - // DISTRIB_CODENAME=impish - // DISTRIB_DESCRIPTION="Ubuntu 21.10" - // - // /etc/os-release - // eg: - // PRETTY_NAME="Ubuntu 21.10" - // NAME="Ubuntu" - // VERSION_ID="21.10" - // VERSION="21.10 (Impish Indri)" - // VERSION_CODENAME=impish - // ID=ubuntu - // ID_LIKE=debian - // HOME_URL="https://www.ubuntu.com/" - // SUPPORT_URL="https://help.ubuntu.com/" - // BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" - // PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" - // UBUNTU_CODENAME=impish - // - // /etc/debian_version - // eg: - // 11.0 - // - // uname -r - // eg: - // 5.13.0-22-generic - DistroInfo Info{}; - uint32_t FoundCount{}; + int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); + Has_Curl = Result != -1; +} - if (std::filesystem::exists("/etc/lsb-release")) { - std::fstream File ("/etc/lsb-release", std::fstream::in); - std::string Line; - while (std::getline(File, Line)) { - if (File.eof() || FoundCount == 2) { - break; +void CheckSquashfuse() { + std::vector ExecveArgs = { + "squashfuse", + "--help", + nullptr, + }; + + int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); + Has_Squashfuse = Result != -1; +} + +void CheckUnsquashfs() { + std::vector ExecveArgs = { + "unsquashfs", + "--help", + nullptr, + }; + + int fd = ::syscall(SYS_memfd_create, "stdout", 0); + int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), fd, fd); + Has_Unsquashfs = Result != -1; + if (Has_Unsquashfs) { + // Seek back to the start + lseek(fd, 0, SEEK_SET); + + // Unsquashfs needs to support zstd + // Scan its output to find the zstd compressor + FILE* fp = fdopen(fd, "r"); + char* Line {nullptr}; + size_t Len; + + bool ReadingDecompressors = false; + bool SupportsZSTD = false; + while (getline(&Line, &Len, fp) != -1) { + if (!ReadingDecompressors) { + if (strstr(Line, "Decompressors available")) { + ReadingDecompressors = true; } - - std::stringstream ss(Line); - std::string Key, Value; - std::getline(ss, Key, '='); - std::getline(ss, Value, '='); - - if (Key == "DISTRIB_ID") { - auto ToLower = [](auto Str) { - std::transform(Str.begin(), Str.end(), Str.begin(), - [](unsigned char c){ return std::tolower(c); }); - return Str; - }; - Info.DistroName = ToLower(Value); - ++FoundCount; - } - else if (Key == "DISTRIB_RELEASE") { - Info.DistroVersion = Value; - ++FoundCount; + } else { + if (strstr(Line, "zstd")) { + SupportsZSTD = true; } } } - if (FoundCount == 2) { - Info.Unknown = false; - if (Info.DistroName == "arch") { - Info.RollingRelease = true; - } - return Info; + free(Line); + fclose(fp); + + // Disable unsquashfs if it doesn't support ZSTD + if (!SupportsZSTD) { + Has_Unsquashfs = false; } - FoundCount = 0; + } + close(fd); +} - if (std::filesystem::exists("/etc/os-release")) { - std::fstream File ("/etc/os-release", std::fstream::in); - std::string Line; - while (std::getline(File, Line)) { - if (File.eof() || FoundCount == 2) { - break; - } +// EroFS specific tests +void CheckEroFSFuse() { + std::vector ExecveArgs = { + "erofsfuse", + "--help", + nullptr, + }; - std::stringstream ss(Line); - std::string Key, Value; - std::getline(ss, Key, '='); - std::getline(ss, Value, '='); + int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); + Has_EroFSFuse = Result != -1; +} - if (Key == "ID") { - Info.DistroName = Value; - ++FoundCount; - } - else if (Key == "VERSION_ID") { - // Ubuntu provides VERSION_ID - // Strip the two quotes from the VERSION_ID - Value = Value.substr(1, Value.size() - 2); - Info.DistroVersion = Value; - ++FoundCount; - } - else if (Key == "IMAGE_VERSION") { - // Arch provides IMAGE_VERSION - Info.DistroVersion = Value; - ++FoundCount; - } +void CheckEroFSFsck() { + std::vector ExecveArgs = { + "fsck.erofs", + "-V", + nullptr, + }; + + int32_t Result = Exec::ExecAndWaitForResponseRedirect(ExecveArgs[0], const_cast(ExecveArgs.data()), -1, -1); + Has_EroFSFsck = Result != -1; +} + +void Init() { + CheckCurl(); + CheckSquashfuse(); + CheckUnsquashfs(); + CheckEroFSFuse(); + CheckEroFSFsck(); +} +} // namespace WorkingAppsTester + +namespace DistroQuery { +struct DistroInfo { + std::string DistroName; + std::string DistroVersion; + bool RollingRelease; + bool Unknown; +}; + +DistroInfo GetDistroInfo() { + // Detect these files in order + // + // /etc/lsb-release + // eg: + // DISTRIB_ID=Ubuntu + // DISTRIB_RELEASE=21.10 + // DISTRIB_CODENAME=impish + // DISTRIB_DESCRIPTION="Ubuntu 21.10" + // + // /etc/os-release + // eg: + // PRETTY_NAME="Ubuntu 21.10" + // NAME="Ubuntu" + // VERSION_ID="21.10" + // VERSION="21.10 (Impish Indri)" + // VERSION_CODENAME=impish + // ID=ubuntu + // ID_LIKE=debian + // HOME_URL="https://www.ubuntu.com/" + // SUPPORT_URL="https://help.ubuntu.com/" + // BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" + // PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" + // UBUNTU_CODENAME=impish + // + // /etc/debian_version + // eg: + // 11.0 + // + // uname -r + // eg: + // 5.13.0-22-generic + DistroInfo Info {}; + uint32_t FoundCount {}; + + if (std::filesystem::exists("/etc/lsb-release")) { + std::fstream File("/etc/lsb-release", std::fstream::in); + std::string Line; + while (std::getline(File, Line)) { + if (File.eof() || FoundCount == 2) { + break; } - } - if (FoundCount == 2) { - Info.Unknown = false; - if (Info.DistroName == "arch") { - Info.RollingRelease = true; - } - return Info; - } - FoundCount = 0; + std::stringstream ss(Line); + std::string Key, Value; + std::getline(ss, Key, '='); + std::getline(ss, Value, '='); - if (std::filesystem::exists("/etc/debian_version")) { - std::fstream File ("/etc/debian_version", std::fstream::in); - std::string Line; - - Info.DistroName = "debian"; - ++FoundCount; - while (std::getline(File, Line)) { - Info.DistroVersion = Line; + if (Key == "DISTRIB_ID") { + auto ToLower = [](auto Str) { + std::transform(Str.begin(), Str.end(), Str.begin(), [](unsigned char c) { return std::tolower(c); }); + return Str; + }; + Info.DistroName = ToLower(Value); + ++FoundCount; + } else if (Key == "DISTRIB_RELEASE") { + Info.DistroVersion = Value; ++FoundCount; } } + } - if (FoundCount == 2) { - Info.Unknown = false; - return Info; + if (FoundCount == 2) { + Info.Unknown = false; + if (Info.DistroName == "arch") { + Info.RollingRelease = true; } - - Info.DistroName = "Unknown"; - Info.DistroVersion = {}; - Info.Unknown = true; return Info; } + FoundCount = 0; + + if (std::filesystem::exists("/etc/os-release")) { + std::fstream File("/etc/os-release", std::fstream::in); + std::string Line; + while (std::getline(File, Line)) { + if (File.eof() || FoundCount == 2) { + break; + } + + std::stringstream ss(Line); + std::string Key, Value; + std::getline(ss, Key, '='); + std::getline(ss, Value, '='); + + if (Key == "ID") { + Info.DistroName = Value; + ++FoundCount; + } else if (Key == "VERSION_ID") { + // Ubuntu provides VERSION_ID + // Strip the two quotes from the VERSION_ID + Value = Value.substr(1, Value.size() - 2); + Info.DistroVersion = Value; + ++FoundCount; + } else if (Key == "IMAGE_VERSION") { + // Arch provides IMAGE_VERSION + Info.DistroVersion = Value; + ++FoundCount; + } + } + } + + if (FoundCount == 2) { + Info.Unknown = false; + if (Info.DistroName == "arch") { + Info.RollingRelease = true; + } + return Info; + } + FoundCount = 0; + + if (std::filesystem::exists("/etc/debian_version")) { + std::fstream File("/etc/debian_version", std::fstream::in); + std::string Line; + + Info.DistroName = "debian"; + ++FoundCount; + while (std::getline(File, Line)) { + Info.DistroVersion = Line; + ++FoundCount; + } + } + + if (FoundCount == 2) { + Info.Unknown = false; + return Info; + } + + Info.DistroName = "Unknown"; + Info.DistroVersion = {}; + Info.Unknown = true; + return Info; } +} // namespace DistroQuery namespace WebFileFetcher { - struct FileTargets { - // These two are for matching version checks - std::string DistroMatch; - std::string VersionMatch; +struct FileTargets { + // These two are for matching version checks + std::string DistroMatch; + std::string VersionMatch; - // This is a human readable name - std::string DistroName; + // This is a human readable name + std::string DistroName; - // This is the URL - fextl::string URL; + // This is the URL + fextl::string URL; - // This is the hash of the file - std::string Hash; + // This is the hash of the file + std::string Hash; - // FileType - enum class FileType { - TYPE_UNKNOWN, - TYPE_SQUASHFS, - TYPE_EROFS, - }; - FileType Type; + // FileType + enum class FileType { + TYPE_UNKNOWN, + TYPE_SQUASHFS, + TYPE_EROFS, + }; + FileType Type; +}; + +const static std::string DownloadURL = "https://rootfs.fex-emu.gg/RootFS_links.json"; + +std::string DownloadToString(const std::string& URL) { + std::vector ExecveArgs = { + "curl", + URL.c_str(), + nullptr, }; - const static std::string DownloadURL = "https://rootfs.fex-emu.gg/RootFS_links.json"; + return Exec::ExecAndWaitForResponseText(ExecveArgs[0], const_cast(ExecveArgs.data())); +} - std::string DownloadToString(const std::string &URL) { - std::vector ExecveArgs = { - "curl", - URL.c_str(), - nullptr, - }; +bool DownloadToPath(const fextl::string& URL, const fextl::string& Path) { + auto filename = URL.substr(URL.find_last_of('/') + 1); + auto PathName = Path + filename; - return Exec::ExecAndWaitForResponseText(ExecveArgs[0], const_cast(ExecveArgs.data())); - } - - bool DownloadToPath(const fextl::string &URL, const fextl::string &Path) { - auto filename = URL.substr(URL.find_last_of('/') + 1); - auto PathName = Path + filename; - - std::vector ExecveArgs = { - "curl", - URL.c_str(), - "-o", - PathName.c_str(), - nullptr, - }; - - return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; - } - - bool DownloadToPathWithZenityProgress(const fextl::string &URL, const fextl::string &Path) { - auto filename = URL.substr(URL.find_last_of('/') + 1); - auto PathName = Path + filename; - - // -# for progress bar - // -o for output file - // -f for silent fail - std::string CurlPipe = fmt::format("curl -C - -#f {} -o {} 2>&1", URL, PathName); - const std::string StdBuf = "stdbuf -oL tr '\\r' '\\n'"; - const std::string SedBuf = "sed -u 's/[^0-9]*\\([0-9]*\\).*/\\1/'"; - // zenity --auto-close can't be used since `curl -C` for whatever reason prints 100% at the start. - // Making zenity vanish immediately - const std::string ZenityBuf = "zenity --time-remaining --progress --no-cancel --title 'Downloading'"; - std::string BigArgs = - fmt::format("{} | {} | {} | {}", CurlPipe, StdBuf, SedBuf, ZenityBuf); - std::vector ExecveArgs = { - "/bin/sh", - "-c", - BigArgs.c_str(), - nullptr, - }; - - return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; - } - - struct JsonAllocator { - jsonPool_t PoolObject; - std::unique_ptr> json_objects; + std::vector ExecveArgs = { + "curl", URL.c_str(), "-o", PathName.c_str(), nullptr, }; - static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero"); - json_t* PoolInit(jsonPool_t* Pool) { - JsonAllocator* alloc = reinterpret_cast(Pool); - alloc->json_objects = std::make_unique>(); - return &*alloc->json_objects->emplace(alloc->json_objects->end()); + return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; +} + +bool DownloadToPathWithZenityProgress(const fextl::string& URL, const fextl::string& Path) { + auto filename = URL.substr(URL.find_last_of('/') + 1); + auto PathName = Path + filename; + + // -# for progress bar + // -o for output file + // -f for silent fail + std::string CurlPipe = fmt::format("curl -C - -#f {} -o {} 2>&1", URL, PathName); + const std::string StdBuf = "stdbuf -oL tr '\\r' '\\n'"; + const std::string SedBuf = "sed -u 's/[^0-9]*\\([0-9]*\\).*/\\1/'"; + // zenity --auto-close can't be used since `curl -C` for whatever reason prints 100% at the start. + // Making zenity vanish immediately + const std::string ZenityBuf = "zenity --time-remaining --progress --no-cancel --title 'Downloading'"; + std::string BigArgs = fmt::format("{} | {} | {} | {}", CurlPipe, StdBuf, SedBuf, ZenityBuf); + std::vector ExecveArgs = { + "/bin/sh", + "-c", + BigArgs.c_str(), + nullptr, + }; + + return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; +} + +struct JsonAllocator { + jsonPool_t PoolObject; + std::unique_ptr> json_objects; +}; +static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero"); + +json_t* PoolInit(jsonPool_t* Pool) { + JsonAllocator* alloc = reinterpret_cast(Pool); + alloc->json_objects = std::make_unique>(); + return &*alloc->json_objects->emplace(alloc->json_objects->end()); +} + +json_t* PoolAlloc(jsonPool_t* Pool) { + JsonAllocator* alloc = reinterpret_cast(Pool); + return &*alloc->json_objects->emplace(alloc->json_objects->end()); +} + +std::optional> GetRootFSLinks() { + // Decode the filetargets + std::string Data = DownloadToString(DownloadURL); + + if (Data.empty()) { + return std::nullopt; } - json_t* PoolAlloc(jsonPool_t* Pool) { - JsonAllocator* alloc = reinterpret_cast(Pool); - return &*alloc->json_objects->emplace(alloc->json_objects->end()); - } - - std::optional> GetRootFSLinks() { - // Decode the filetargets - std::string Data = DownloadToString(DownloadURL); - - if (Data.empty()) { - return std::nullopt; - } - - JsonAllocator Pool { - .PoolObject = { + JsonAllocator Pool { + .PoolObject = + { .init = PoolInit, .alloc = PoolAlloc, }, - }; + }; - json_t const *json = json_createWithPool(&Data.at(0), &Pool.PoolObject); - if (!json) { - fprintf(stderr, "Couldn't create json"); - return {}; - } - - json_t const* RootList = json_getProperty(json, "v1"); - - if (!RootList) { - fprintf(stderr, "Couldn't get root list"); - return {}; - } - - std::vector Targets; - - for (json_t const* RootItem = json_getChild(RootList); - RootItem != nullptr; - RootItem = json_getSibling(RootItem)) { - - FileTargets Target; - Target.DistroName = json_getName(RootItem); - - for (json_t const* DataItem = json_getChild(RootItem); - DataItem != nullptr; - DataItem = json_getSibling(DataItem)) { - auto DataName = std::string_view {json_getName(DataItem)}; - - if (DataName == "DistroMatch") { - Target.DistroMatch = json_getValue(DataItem); - } - else if (DataName == "DistroVersion") { - Target.VersionMatch = json_getValue(DataItem); - } - else if (DataName == "URL") { - Target.URL = json_getValue(DataItem); - } - else if (DataName == "Hash") { - Target.Hash = json_getValue(DataItem); - } - else if (DataName == "Type") { - auto DataValue = std::string_view {json_getValue(DataItem)}; - if (DataValue == "squashfs") { - Target.Type = FileTargets::FileType::TYPE_SQUASHFS; - } - else if (DataValue == "erofs") { - Target.Type = FileTargets::FileType::TYPE_EROFS; - } - else { - Target.Type = FileTargets::FileType::TYPE_UNKNOWN; - } - } - } - bool SupportsSquashFS = WorkingAppsTester::Has_Squashfuse || WorkingAppsTester::Has_Unsquashfs; - bool SupportsEroFS = WorkingAppsTester::Has_EroFSFuse; - if ((Target.Type == FileTargets::FileType::TYPE_SQUASHFS && SupportsSquashFS) || - (Target.Type == FileTargets::FileType::TYPE_EROFS && SupportsEroFS)) { - // If we don't understand the type, then we can't use this. - // Additionally if the type is erofs but the user doesn't have erofsfuse, then we can't use this - Targets.emplace_back(Target); - } - } - - return Targets; + const json_t* json = json_createWithPool(&Data.at(0), &Pool.PoolObject); + if (!json) { + fprintf(stderr, "Couldn't create json"); + return {}; } + + const json_t* RootList = json_getProperty(json, "v1"); + + if (!RootList) { + fprintf(stderr, "Couldn't get root list"); + return {}; + } + + std::vector Targets; + + for (const json_t* RootItem = json_getChild(RootList); RootItem != nullptr; RootItem = json_getSibling(RootItem)) { + + FileTargets Target; + Target.DistroName = json_getName(RootItem); + + for (const json_t* DataItem = json_getChild(RootItem); DataItem != nullptr; DataItem = json_getSibling(DataItem)) { + auto DataName = std::string_view {json_getName(DataItem)}; + + if (DataName == "DistroMatch") { + Target.DistroMatch = json_getValue(DataItem); + } else if (DataName == "DistroVersion") { + Target.VersionMatch = json_getValue(DataItem); + } else if (DataName == "URL") { + Target.URL = json_getValue(DataItem); + } else if (DataName == "Hash") { + Target.Hash = json_getValue(DataItem); + } else if (DataName == "Type") { + auto DataValue = std::string_view {json_getValue(DataItem)}; + if (DataValue == "squashfs") { + Target.Type = FileTargets::FileType::TYPE_SQUASHFS; + } else if (DataValue == "erofs") { + Target.Type = FileTargets::FileType::TYPE_EROFS; + } else { + Target.Type = FileTargets::FileType::TYPE_UNKNOWN; + } + } + } + bool SupportsSquashFS = WorkingAppsTester::Has_Squashfuse || WorkingAppsTester::Has_Unsquashfs; + bool SupportsEroFS = WorkingAppsTester::Has_EroFSFuse; + if ((Target.Type == FileTargets::FileType::TYPE_SQUASHFS && SupportsSquashFS) || + (Target.Type == FileTargets::FileType::TYPE_EROFS && SupportsEroFS)) { + // If we don't understand the type, then we can't use this. + // Additionally if the type is erofs but the user doesn't have erofsfuse, then we can't use this + Targets.emplace_back(Target); + } + } + + return Targets; } +} // namespace WebFileFetcher namespace Zenity { - bool ExecWithQuestion(const fextl::string &Question) { - fextl::string TextArg = "--text=" + Question; - const char *Args[] = { - "zenity", - "--question", - TextArg.c_str(), - nullptr, - }; +bool ExecWithQuestion(const fextl::string& Question) { + fextl::string TextArg = "--text=" + Question; + const char* Args[] = { + "zenity", + "--question", + TextArg.c_str(), + nullptr, + }; - int32_t Result = Exec::ExecAndWaitForResponse(Args[0], const_cast(Args)); - // 0 on Yes, 1 on No - return Result == 0; + int32_t Result = Exec::ExecAndWaitForResponse(Args[0], const_cast(Args)); + // 0 on Yes, 1 on No + return Result == 0; +} + +void ExecWithInfo(const fextl::string& Text) { + fextl::string TextArg = "--text=" + Text; + const char* Args[] = { + "zenity", + "--info", + TextArg.c_str(), + nullptr, + }; + + Exec::ExecAndWaitForResponse(Args[0], const_cast(Args)); +} + +bool AskForConfirmation(const fextl::string& Question) { + return ArgOptions::AssumeYes || ExecWithQuestion(Question); +} + +int32_t AskForConfirmationList(const fextl::string& Text, const std::vector& Arguments) { + fextl::string TextArg = "--text=" + Text; + + std::vector ExecveArgs = { + "zenity", "--list", TextArg.c_str(), "--hide-header", "--column=Index", "--column=Text", "--hide-column=1", + }; + + std::vector NumberArgs; + for (size_t i = 0; i < Arguments.size(); ++i) { + NumberArgs.emplace_back(std::to_string(i)); } - void ExecWithInfo(const fextl::string &Text) { - fextl::string TextArg = "--text=" + Text; - const char *Args[] = { - "zenity", - "--info", - TextArg.c_str(), - nullptr, - }; - - Exec::ExecAndWaitForResponse(Args[0], const_cast(Args)); + for (size_t i = 0; i < Arguments.size(); ++i) { + const auto& Arg = Arguments[i]; + ExecveArgs.emplace_back(NumberArgs[i].c_str()); + ExecveArgs.emplace_back(Arg.c_str()); } + ExecveArgs.emplace_back(nullptr); - bool AskForConfirmation(const fextl::string &Question) { - return ArgOptions::AssumeYes || ExecWithQuestion(Question); + auto Result = Exec::ExecAndWaitForResponseText(ExecveArgs[0], const_cast(ExecveArgs.data())); + if (Result.empty()) { + return -1; } + return std::stoi(Result); +} - int32_t AskForConfirmationList(const fextl::string &Text, const std::vector &Arguments) { - fextl::string TextArg = "--text=" + Text; +int32_t AskForComplexConfirmationList(const std::string& Text, const std::vector& Arguments) { + std::string TextArg = "--text=" + Text; - std::vector ExecveArgs = { - "zenity", - "--list", - TextArg.c_str(), - "--hide-header", - "--column=Index", - "--column=Text", - "--hide-column=1", - }; + std::vector ExecveArgs = { + "zenity", + "--list", + TextArg.c_str(), + }; - std::vector NumberArgs; - for (size_t i = 0; i < Arguments.size(); ++i) { - NumberArgs.emplace_back(std::to_string(i)); - } - - for (size_t i = 0; i < Arguments.size(); ++i) { - const auto &Arg = Arguments[i]; - ExecveArgs.emplace_back(NumberArgs[i].c_str()); - ExecveArgs.emplace_back(Arg.c_str()); - } - ExecveArgs.emplace_back(nullptr); - - auto Result = Exec::ExecAndWaitForResponseText(ExecveArgs[0], const_cast(ExecveArgs.data())); - if (Result.empty()) { - return -1; - } - return std::stoi(Result); + for (auto& Arg : Arguments) { + ExecveArgs.emplace_back(Arg.c_str()); } + ExecveArgs.emplace_back(nullptr); - int32_t AskForComplexConfirmationList(const std::string &Text, const std::vector &Arguments) { - std::string TextArg = "--text=" + Text; - - std::vector ExecveArgs = { - "zenity", - "--list", - TextArg.c_str(), - }; - - for (auto &Arg : Arguments) { - ExecveArgs.emplace_back(Arg.c_str()); - } - ExecveArgs.emplace_back(nullptr); - - auto Result = Exec::ExecAndWaitForResponseText(ExecveArgs[0], const_cast(ExecveArgs.data())); - if (Result.empty()) { - return -1; - } - return std::stoi(Result); + auto Result = Exec::ExecAndWaitForResponseText(ExecveArgs[0], const_cast(ExecveArgs.data())); + if (Result.empty()) { + return -1; } + return std::stoi(Result); +} - int32_t AskForDistroSelection(DistroQuery::DistroInfo &Info, std::vector &Targets) { - // Search for an exact match - int32_t DistroIndex = -1; - if (!Info.Unknown) { - for (size_t i = 0; i < Targets.size(); ++i) { - const auto &Target = Targets[i]; +int32_t AskForDistroSelection(DistroQuery::DistroInfo& Info, std::vector& Targets) { + // Search for an exact match + int32_t DistroIndex = -1; + if (!Info.Unknown) { + for (size_t i = 0; i < Targets.size(); ++i) { + const auto& Target = Targets[i]; - bool ExactMatch = Target.DistroMatch == Info.DistroName && - (Info.RollingRelease || Target.VersionMatch == Info.DistroVersion); - if (ExactMatch) { - fextl::string Question = fextl::fmt::format("Found exact match for distro '{}'. Do you want to select this image?", Target.DistroName); - if (ExecWithQuestion(Question)) { - DistroIndex = i; - break; - } + bool ExactMatch = Target.DistroMatch == Info.DistroName && (Info.RollingRelease || Target.VersionMatch == Info.DistroVersion); + if (ExactMatch) { + fextl::string Question = fextl::fmt::format("Found exact match for distro '{}'. Do you want to select this image?", Target.DistroName); + if (ExecWithQuestion(Question)) { + DistroIndex = i; + break; } } } - - if (DistroIndex != -1) { - return DistroIndex; - } - - if (ArgOptions::DistroListOption == ArgOptions::ListQueryOption::OPTION_FIRST) { - // Return the first option if not an exact match. - return 0; - } - - std::vector Args; - - Args.emplace_back("--column=Index"); - Args.emplace_back("--column=Distro"); - Args.emplace_back("--hide-column=1"); - for (size_t i = 0; i < Targets.size(); ++i) { - const auto &Target = Targets[i]; - Args.emplace_back(std::to_string(i)); - Args.emplace_back(Target.DistroName); - } - - std::string Text = "RootFS list selection"; - return AskForComplexConfirmationList(Text, Args); } - bool ValidateCheckExists(const WebFileFetcher::FileTargets &Target) { - fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; - auto filename = Target.URL.substr(Target.URL.find_last_of('/') + 1); - auto PathName = RootFS + filename; - uint64_t ExpectedHash = std::stoul(Target.Hash, nullptr, 16); + if (DistroIndex != -1) { + return DistroIndex; + } - std::error_code ec; - if (std::filesystem::exists(PathName, ec)) { - const std::vector Args { - "Overwrite", - "Validate", - }; - fextl::string Text = filename + " already exists. What do you want to do?"; - int Result = AskForConfirmationList(Text, Args); - if (Result == -1) { + if (ArgOptions::DistroListOption == ArgOptions::ListQueryOption::OPTION_FIRST) { + // Return the first option if not an exact match. + return 0; + } + + std::vector Args; + + Args.emplace_back("--column=Index"); + Args.emplace_back("--column=Distro"); + Args.emplace_back("--hide-column=1"); + for (size_t i = 0; i < Targets.size(); ++i) { + const auto& Target = Targets[i]; + Args.emplace_back(std::to_string(i)); + Args.emplace_back(Target.DistroName); + } + + std::string Text = "RootFS list selection"; + return AskForComplexConfirmationList(Text, Args); +} + +bool ValidateCheckExists(const WebFileFetcher::FileTargets& Target) { + fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; + auto filename = Target.URL.substr(Target.URL.find_last_of('/') + 1); + auto PathName = RootFS + filename; + uint64_t ExpectedHash = std::stoul(Target.Hash, nullptr, 16); + + std::error_code ec; + if (std::filesystem::exists(PathName, ec)) { + const std::vector Args { + "Overwrite", + "Validate", + }; + fextl::string Text = filename + " already exists. What do you want to do?"; + int Result = AskForConfirmationList(Text, Args); + if (Result == -1) { + return false; + } + + auto Res = XXFileHash::HashFile(PathName); + if (Result == 0) { + if (Res.first == true && Res.second == ExpectedHash) { + fextl::string Text = fextl::fmt::format("{} matches expected hash. Skipping download", filename); + ExecWithInfo(Text); return false; } + } else if (Result == 1) { + if (Res.first == false || Res.second != ExpectedHash) { + return AskForConfirmation("RootFS doesn't match hash!\nDo you want to redownload?"); + } else { + fextl::string Text = fextl::fmt::format("{} matches expected hash", filename); + ExecWithInfo(Text); + return false; + } + } + } - auto Res = XXFileHash::HashFile(PathName); - if (Result == 0) { - if (Res.first == true && - Res.second == ExpectedHash) { - fextl::string Text = fextl::fmt::format("{} matches expected hash. Skipping download", filename); - ExecWithInfo(Text); - return false; - } - } - else if (Result == 1) { - if (Res.first == false || - Res.second != ExpectedHash) { - return AskForConfirmation("RootFS doesn't match hash!\nDo you want to redownload?"); - } - else { - fextl::string Text = fextl::fmt::format("{} matches expected hash", filename); - ExecWithInfo(Text); - return false; - } + return true; +} + +bool ValidateDownloadSelection(const WebFileFetcher::FileTargets& Target) { + fextl::string Text = fextl::fmt::format("Selected Rootfs: {}\n", Target.DistroName); + Text += fmt::format("\tURL: {}\n", Target.URL); + Text += fmt::format("Are you sure that you want to download this image"); + + if (AskForConfirmation(Text)) { + fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; + std::error_code ec {}; + if (!std::filesystem::exists(RootFS, ec)) { + // Doesn't exist, create the the folder as a user convenience + if (!std::filesystem::create_directories(RootFS, ec)) { + // Well I guess we failed + Text = fmt::format("Couldn't create {} path for storing RootFS", RootFS); + ExecWithInfo(Text); + return false; } } + if (!WebFileFetcher::DownloadToPathWithZenityProgress(Target.URL, RootFS)) { + return false; + } + return true; } - - bool ValidateDownloadSelection(const WebFileFetcher::FileTargets &Target) { - fextl::string Text = fextl::fmt::format("Selected Rootfs: {}\n", Target.DistroName); - Text += fmt::format("\tURL: {}\n", Target.URL); - Text += fmt::format("Are you sure that you want to download this image"); - - if (AskForConfirmation(Text)) { - fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; - std::error_code ec{}; - if (!std::filesystem::exists(RootFS, ec)) { - // Doesn't exist, create the the folder as a user convenience - if (!std::filesystem::create_directories(RootFS, ec)) { - // Well I guess we failed - Text = fmt::format("Couldn't create {} path for storing RootFS", RootFS); - ExecWithInfo(Text); - return false; - } - } - - if (!WebFileFetcher::DownloadToPathWithZenityProgress(Target.URL, RootFS)) { - return false; - } - - return true; - } - return false; - } + return false; } +} // namespace Zenity namespace TTY { - bool AskForConfirmation(const fextl::string &Question) { - if (ArgOptions::AssumeYes) { - return true; - } - - auto ToLowerInPlace = [](auto &Str) { - std::transform(Str.begin(), Str.end(), Str.begin(), - [](unsigned char c){ return std::tolower(c); }); - }; - - std::cout << Question << std::endl; - std::cout << "Response {y,yes,1} or {n,no,0}" << std::endl; - std::string Response; - std::cin >> Response; - - ToLowerInPlace(Response); - if (Response == "y" || - Response == "yes" || - Response == "1") { - return true; - } - else if (Response == "n" || - Response == "no" || - Response == "0") { - return false; - } - else { - std::cout << "Unknown response. Assuming no" << std::endl; - return false; - } - } - - void ExecWithInfo(const fextl::string &Text) { - std::cout << Text << std::endl; - } - - int32_t AskForConfirmationList(const fextl::string &Text, const std::vector &List) { - fmt::print("{}\n", Text); - fmt::print("Options:\n"); - fmt::print("\t0: Cancel\n"); - - for (size_t i = 0; i < List.size(); ++i) { - fmt::print("\t{}: {}\n", i+1, List[i]); - } - - fmt::print("\t\nResponse {{1-{}}} or 0 to cancel\n", List.size()); - fextl::string Response; - std::cin >> Response; - - int32_t ResponseInt = std::stol(Response.data(), nullptr, 0); - if (ResponseInt == 0) { - return -1; - } - else if (ResponseInt >= 1 && - (ResponseInt - 1) < List.size()) { - return ResponseInt - 1; - } - else { - std::cout << "Unknown response. Assuming cancel" << std::endl; - return -1; - } - } - - int32_t AskForDistroSelection(DistroQuery::DistroInfo &Info, std::vector &Targets) { - // Search for an exact match - int32_t DistroIndex = -1; - if (!Info.Unknown) { - for (size_t i = 0; i < Targets.size(); ++i) { - const auto &Target = Targets[i]; - - bool ExactMatch = Target.DistroMatch == Info.DistroName && - Target.VersionMatch == Info.DistroVersion; - if (ExactMatch) { - fextl::string Question = fextl::fmt::format("Found exact match for distro '{}'. Do you want to select this image?", Target.DistroName); - if (AskForConfirmation(Question)) { - DistroIndex = i; - break; - } - } - } - } - - if (DistroIndex != -1) { - return DistroIndex; - } - - if (ArgOptions::DistroListOption == ArgOptions::ListQueryOption::OPTION_FIRST) { - // Return the first option if not an exact match. - return 0; - } - - std::vector Args; - for (size_t i = 0; i < Targets.size(); ++i) { - const auto &Target = Targets[i]; - Args.emplace_back(Target.DistroName); - } - - fextl::string Text = "RootFS list selection"; - return AskForConfirmationList(Text, Args); - } - - bool ValidateCheckExists(const WebFileFetcher::FileTargets &Target) { - fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; - auto filename = Target.URL.substr(Target.URL.find_last_of('/') + 1); - auto PathName = RootFS + filename; - uint64_t ExpectedHash = std::stoul(Target.Hash, nullptr, 16); - - std::error_code ec; - if (std::filesystem::exists(PathName, ec)) { - const std::vector Args { - "Overwrite", - "Validate", - }; - fextl::string Text = filename + " already exists. What do you want to do?"; - int Result = AskForConfirmationList(Text, Args); - if (Result == -1) { - return false; - } - fmt::print("Validating RootFS hash...\n"); - auto Res = XXFileHash::HashFile(PathName); - if (Result == 0) { - if (Res.first == true && - Res.second == ExpectedHash) { - fmt::print("{} matches expected hash. Skipping downloading\n", filename); - return false; - } - } - else if (Result == 1) { - if (Res.first == false || - Res.second != ExpectedHash) { - fmt::print("RootFS doesn't match hash!\n"); - return AskForConfirmation("Do you want to redownload?"); - } - else { - fmt::print("{} matches expected hash\n", filename); - return false; - } - } - } - +bool AskForConfirmation(const fextl::string& Question) { + if (ArgOptions::AssumeYes) { return true; } - bool ValidateDownloadSelection(const WebFileFetcher::FileTargets &Target) { - fmt::print("Selected Rootfs: {}\n", Target.DistroName); - fmt::print("\tURL: {}\n", Target.URL); + auto ToLowerInPlace = [](auto& Str) { + std::transform(Str.begin(), Str.end(), Str.begin(), [](unsigned char c) { return std::tolower(c); }); + }; - if (AskForConfirmation("Are you sure that you want to download this image")) { - fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; - std::error_code ec{}; - if (!std::filesystem::exists(RootFS, ec)) { - // Doesn't exist, create the the folder as a user convenience - if (!std::filesystem::create_directories(RootFS, ec)) { - // Well I guess we failed - fmt::print("Couldn't create {} path for storing RootFS\n", RootFS); - return false; - } - } - auto DoDownload = [&Target, &RootFS]() -> bool { - if (!WebFileFetcher::DownloadToPath(Target.URL, RootFS)) { - fmt::print("Couldn't download RootFS\n"); - return false; - } + std::cout << Question << std::endl; + std::cout << "Response {y,yes,1} or {n,no,0}" << std::endl; + std::string Response; + std::cin >> Response; - return true; - }; - - while (DoDownload() == false) { - if (AskForConfirmation("Curl RootFS download failed. Do you want to retry?")) { - // Loop to retry - } - else { - return false; - } - } - - // Got here then we passed - return true; - } + ToLowerInPlace(Response); + if (Response == "y" || Response == "yes" || Response == "1") { + return true; + } else if (Response == "n" || Response == "no" || Response == "0") { + return false; + } else { + std::cout << "Unknown response. Assuming no" << std::endl; return false; } } +void ExecWithInfo(const fextl::string& Text) { + std::cout << Text << std::endl; +} + +int32_t AskForConfirmationList(const fextl::string& Text, const std::vector& List) { + fmt::print("{}\n", Text); + fmt::print("Options:\n"); + fmt::print("\t0: Cancel\n"); + + for (size_t i = 0; i < List.size(); ++i) { + fmt::print("\t{}: {}\n", i + 1, List[i]); + } + + fmt::print("\t\nResponse {{1-{}}} or 0 to cancel\n", List.size()); + fextl::string Response; + std::cin >> Response; + + int32_t ResponseInt = std::stol(Response.data(), nullptr, 0); + if (ResponseInt == 0) { + return -1; + } else if (ResponseInt >= 1 && (ResponseInt - 1) < List.size()) { + return ResponseInt - 1; + } else { + std::cout << "Unknown response. Assuming cancel" << std::endl; + return -1; + } +} + +int32_t AskForDistroSelection(DistroQuery::DistroInfo& Info, std::vector& Targets) { + // Search for an exact match + int32_t DistroIndex = -1; + if (!Info.Unknown) { + for (size_t i = 0; i < Targets.size(); ++i) { + const auto& Target = Targets[i]; + + bool ExactMatch = Target.DistroMatch == Info.DistroName && Target.VersionMatch == Info.DistroVersion; + if (ExactMatch) { + fextl::string Question = fextl::fmt::format("Found exact match for distro '{}'. Do you want to select this image?", Target.DistroName); + if (AskForConfirmation(Question)) { + DistroIndex = i; + break; + } + } + } + } + + if (DistroIndex != -1) { + return DistroIndex; + } + + if (ArgOptions::DistroListOption == ArgOptions::ListQueryOption::OPTION_FIRST) { + // Return the first option if not an exact match. + return 0; + } + + std::vector Args; + for (size_t i = 0; i < Targets.size(); ++i) { + const auto& Target = Targets[i]; + Args.emplace_back(Target.DistroName); + } + + fextl::string Text = "RootFS list selection"; + return AskForConfirmationList(Text, Args); +} + +bool ValidateCheckExists(const WebFileFetcher::FileTargets& Target) { + fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; + auto filename = Target.URL.substr(Target.URL.find_last_of('/') + 1); + auto PathName = RootFS + filename; + uint64_t ExpectedHash = std::stoul(Target.Hash, nullptr, 16); + + std::error_code ec; + if (std::filesystem::exists(PathName, ec)) { + const std::vector Args { + "Overwrite", + "Validate", + }; + fextl::string Text = filename + " already exists. What do you want to do?"; + int Result = AskForConfirmationList(Text, Args); + if (Result == -1) { + return false; + } + fmt::print("Validating RootFS hash...\n"); + auto Res = XXFileHash::HashFile(PathName); + if (Result == 0) { + if (Res.first == true && Res.second == ExpectedHash) { + fmt::print("{} matches expected hash. Skipping downloading\n", filename); + return false; + } + } else if (Result == 1) { + if (Res.first == false || Res.second != ExpectedHash) { + fmt::print("RootFS doesn't match hash!\n"); + return AskForConfirmation("Do you want to redownload?"); + } else { + fmt::print("{} matches expected hash\n", filename); + return false; + } + } + } + + return true; +} + +bool ValidateDownloadSelection(const WebFileFetcher::FileTargets& Target) { + fmt::print("Selected Rootfs: {}\n", Target.DistroName); + fmt::print("\tURL: {}\n", Target.URL); + + if (AskForConfirmation("Are you sure that you want to download this image")) { + fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; + std::error_code ec {}; + if (!std::filesystem::exists(RootFS, ec)) { + // Doesn't exist, create the the folder as a user convenience + if (!std::filesystem::create_directories(RootFS, ec)) { + // Well I guess we failed + fmt::print("Couldn't create {} path for storing RootFS\n", RootFS); + return false; + } + } + auto DoDownload = [&Target, &RootFS]() -> bool { + if (!WebFileFetcher::DownloadToPath(Target.URL, RootFS)) { + fmt::print("Couldn't download RootFS\n"); + return false; + } + + return true; + }; + + while (DoDownload() == false) { + if (AskForConfirmation("Curl RootFS download failed. Do you want to retry?")) { + // Loop to retry + } else { + return false; + } + } + + // Got here then we passed + return true; + } + return false; +} +} // namespace TTY + namespace { - bool IsTTY{}; +bool IsTTY {}; - std::function _AskForConfirmation; - std::function _ExecWithInfo; - std::function &List)> _AskForConfirmationList; - std::function &Targets)> _AskForDistroSelection; - std::function _ValidateCheckExists; - std::function _ValidateDownloadSelection; +std::function _AskForConfirmation; +std::function _ExecWithInfo; +std::function& List)> _AskForConfirmationList; +std::function& Targets)> _AskForDistroSelection; +std::function _ValidateCheckExists; +std::function _ValidateDownloadSelection; - void CheckTTY() { - IsTTY = isatty(STDOUT_FILENO); +void CheckTTY() { + IsTTY = isatty(STDOUT_FILENO); - if (IsTTY) { - _AskForConfirmation = TTY::AskForConfirmation; - _ExecWithInfo = TTY::ExecWithInfo; - _AskForConfirmationList = TTY::AskForConfirmationList; - _AskForDistroSelection = TTY::AskForDistroSelection; - _ValidateCheckExists = TTY::ValidateCheckExists; - _ValidateDownloadSelection = TTY::ValidateDownloadSelection; - } - else { - _AskForConfirmation = Zenity::AskForConfirmation; - _ExecWithInfo = Zenity::ExecWithInfo; - _AskForConfirmationList = Zenity::AskForConfirmationList; - _AskForDistroSelection = Zenity::AskForDistroSelection; - _ValidateCheckExists = Zenity::ValidateCheckExists; - _ValidateDownloadSelection = Zenity::ValidateDownloadSelection; - } - } - - bool AskForConfirmation(const fextl::string &Question) { - return _AskForConfirmation(Question); - } - - void ExecWithInfo(const fextl::string &Text) { - _ExecWithInfo(Text); - } - - int32_t AskForConfirmationList(const fextl::string &Text, const std::vector &Arguments) { - return _AskForConfirmationList(Text, Arguments); - } - - int32_t AskForDistroSelection(std::vector &Targets) { - auto Info = DistroQuery::GetDistroInfo(); - - if (!ArgOptions::DistroName.empty()) { - Info.DistroName = ArgOptions::DistroName; - } - if (!ArgOptions::DistroVersion.empty()) { - Info.DistroVersion = ArgOptions::DistroVersion; - } - - return _AskForDistroSelection(Info, Targets); - } - - bool ValidateCheckExists(const WebFileFetcher::FileTargets &Target) { - return _ValidateCheckExists(Target); - } - - bool ValidateDownloadSelection(const WebFileFetcher::FileTargets &Target) { - return _ValidateDownloadSelection(Target); + if (IsTTY) { + _AskForConfirmation = TTY::AskForConfirmation; + _ExecWithInfo = TTY::ExecWithInfo; + _AskForConfirmationList = TTY::AskForConfirmationList; + _AskForDistroSelection = TTY::AskForDistroSelection; + _ValidateCheckExists = TTY::ValidateCheckExists; + _ValidateDownloadSelection = TTY::ValidateDownloadSelection; + } else { + _AskForConfirmation = Zenity::AskForConfirmation; + _ExecWithInfo = Zenity::ExecWithInfo; + _AskForConfirmationList = Zenity::AskForConfirmationList; + _AskForDistroSelection = Zenity::AskForDistroSelection; + _ValidateCheckExists = Zenity::ValidateCheckExists; + _ValidateDownloadSelection = Zenity::ValidateDownloadSelection; } } +bool AskForConfirmation(const fextl::string& Question) { + return _AskForConfirmation(Question); +} + +void ExecWithInfo(const fextl::string& Text) { + _ExecWithInfo(Text); +} + +int32_t AskForConfirmationList(const fextl::string& Text, const std::vector& Arguments) { + return _AskForConfirmationList(Text, Arguments); +} + +int32_t AskForDistroSelection(std::vector& Targets) { + auto Info = DistroQuery::GetDistroInfo(); + + if (!ArgOptions::DistroName.empty()) { + Info.DistroName = ArgOptions::DistroName; + } + if (!ArgOptions::DistroVersion.empty()) { + Info.DistroVersion = ArgOptions::DistroVersion; + } + + return _AskForDistroSelection(Info, Targets); +} + +bool ValidateCheckExists(const WebFileFetcher::FileTargets& Target) { + return _ValidateCheckExists(Target); +} + +bool ValidateDownloadSelection(const WebFileFetcher::FileTargets& Target) { + return _ValidateDownloadSelection(Target); +} +} // namespace + namespace ConfigSetter { - void SetRootFSAsDefault(const fextl::string &RootFS) { - fextl::string Filename = FEXCore::Config::GetConfigFileLocation(); - auto LoadedConfig = FEX::Config::CreateMainLayer(&Filename); - LoadedConfig->Load(); - LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ROOTFS, RootFS); - FEX::Config::SaveLayerToJSON(Filename, LoadedConfig.get()); - } +void SetRootFSAsDefault(const fextl::string& RootFS) { + fextl::string Filename = FEXCore::Config::GetConfigFileLocation(); + auto LoadedConfig = FEX::Config::CreateMainLayer(&Filename); + LoadedConfig->Load(); + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_ROOTFS, RootFS); + FEX::Config::SaveLayerToJSON(Filename, LoadedConfig.get()); } +} // namespace ConfigSetter namespace UnSquash { - bool UnsquashRootFS(const fextl::string &Path, const fextl::string &RootFS, const fextl::string &FolderName) { - auto TargetFolder = Path + FolderName; +bool UnsquashRootFS(const fextl::string& Path, const fextl::string& RootFS, const fextl::string& FolderName) { + auto TargetFolder = Path + FolderName; - bool Extract = true; - std::error_code ec; - if (std::filesystem::exists(TargetFolder, ec)) { - fextl::string Question = "Target folder \"" + FolderName + "\" already exists. Overwrite?"; - if (AskForConfirmation(Question)) { - if (std::filesystem::remove_all(TargetFolder, ec) != ~0ULL) { - Extract = true; - } + bool Extract = true; + std::error_code ec; + if (std::filesystem::exists(TargetFolder, ec)) { + fextl::string Question = "Target folder \"" + FolderName + "\" already exists. Overwrite?"; + if (AskForConfirmation(Question)) { + if (std::filesystem::remove_all(TargetFolder, ec) != ~0ULL) { + Extract = true; } } - - if (Extract) { - const std::vector ExecveArgs = { - "unsquashfs", - "-f", - "-d", - TargetFolder.c_str(), - RootFS.c_str(), - nullptr, - }; - - return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; - } - - return false; } - bool ExtractEroFS(const fextl::string &Path, const fextl::string &RootFS, const fextl::string &FolderName) { - auto TargetFolder = Path + FolderName; + if (Extract) { + const std::vector ExecveArgs = { + "unsquashfs", "-f", "-d", TargetFolder.c_str(), RootFS.c_str(), nullptr, + }; - bool Extract = true; - std::error_code ec; - if (std::filesystem::exists(TargetFolder, ec)) { - fextl::string Question = "Target folder \"" + FolderName + "\" already exists. Overwrite?"; - if (AskForConfirmation(Question)) { - if (std::filesystem::remove_all(TargetFolder, ec) != ~0ULL) { - Extract = true; - } - if (ec) { - ExecWithInfo("Couldn't remove previous directory. Won't extract."); - } - } - } - - if (Extract) { - ExecWithInfo("Extracting Erofs. This might take a few minutes."); - - const auto ExtractOption = fmt::format("--extract={}", TargetFolder); - const std::vector ExecveArgs = { - "fsck.erofs", - ExtractOption.c_str(), - RootFS.c_str(), - nullptr, - }; - - return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; - } - - return false; + return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; } + + return false; } -int main(int argc, char **argv, char **const envp) { +bool ExtractEroFS(const fextl::string& Path, const fextl::string& RootFS, const fextl::string& FolderName) { + auto TargetFolder = Path + FolderName; + + bool Extract = true; + std::error_code ec; + if (std::filesystem::exists(TargetFolder, ec)) { + fextl::string Question = "Target folder \"" + FolderName + "\" already exists. Overwrite?"; + if (AskForConfirmation(Question)) { + if (std::filesystem::remove_all(TargetFolder, ec) != ~0ULL) { + Extract = true; + } + if (ec) { + ExecWithInfo("Couldn't remove previous directory. Won't extract."); + } + } + } + + if (Extract) { + ExecWithInfo("Extracting Erofs. This might take a few minutes."); + + const auto ExtractOption = fmt::format("--extract={}", TargetFolder); + const std::vector ExecveArgs = { + "fsck.erofs", + ExtractOption.c_str(), + RootFS.c_str(), + nullptr, + }; + + return Exec::ExecAndWaitForResponse(ExecveArgs[0], const_cast(ExecveArgs.data())) == 0; + } + + return false; +} +} // namespace UnSquash + +int main(int argc, char** argv, char** const envp) { CheckTTY(); - FEX::Config::LoadConfig( - true, - false, - argc, argv, envp, - false, {} - ); + FEX::Config::LoadConfig(true, false, argc, argv, envp, false, {}); // Reload the meta layer FEXCore::Config::ReloadMetaLayer(); @@ -1176,8 +1102,7 @@ int main(int argc, char **argv, char **const envp) { auto Res = XXFileHash::HashFile(ArgOptions::RemainingArgs[0]); if (Res.first) { fmt::print("{} has hash: {:x}\n", ArgOptions::RemainingArgs[0], Res.second); - } - else { + } else { fmt::print("Couldn't generate hash for {}\n", ArgOptions::RemainingArgs[0]); } return 0; @@ -1189,9 +1114,7 @@ int main(int argc, char **argv, char **const envp) { ExecWithInfo("curl is required to use this tool. Please install curl before using."); return -1; } - if (!WorkingAppsTester::Has_Squashfuse && - !WorkingAppsTester::Has_Unsquashfs && - !WorkingAppsTester::Has_EroFSFuse) { + if (!WorkingAppsTester::Has_Squashfuse && !WorkingAppsTester::Has_Unsquashfs && !WorkingAppsTester::Has_EroFSFuse) { // We need at least one tool to mount or extract image files ExecWithInfo("squashfuse, unsquashfs, or erofsfuse is required to use this tool. Please install one before using."); return -1; @@ -1200,12 +1123,10 @@ int main(int argc, char **argv, char **const envp) { FEX_CONFIG_OPT(LDPath, ROOTFS); std::error_code ec; - fextl::string Question{}; - if (LDPath().empty() || - std::filesystem::exists(LDPath(), ec) == false) { + fextl::string Question {}; + if (LDPath().empty() || std::filesystem::exists(LDPath(), ec) == false) { Question = "RootFS not found. Do you want to try and download one?"; - } - else { + } else { Question = "RootFS is already in use. Do you want to check the download list?"; } @@ -1225,15 +1146,14 @@ int main(int argc, char **argv, char **const envp) { int32_t DistroIndex = AskForDistroSelection(Targets); if (DistroIndex != -1) { - const auto &Target = Targets[DistroIndex]; + const auto& Target = Targets[DistroIndex]; fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/"; auto filename = Target.URL.substr(Target.URL.find_last_of('/') + 1); auto PathName = RootFS + filename; if (!ValidateCheckExists(Target)) { // Keep going - } - else { + } else { auto ValidateDownload = [&Target, &PathName]() -> std::pair { std::error_code ec; if (ValidateDownloadSelection(Target)) { @@ -1241,20 +1161,17 @@ int main(int argc, char **argv, char **const envp) { if (std::filesystem::exists(PathName, ec)) { auto Res = XXFileHash::HashFile(PathName); - if (Res.first == false || - Res.second != ExpectedHash) { + if (Res.first == false || Res.second != ExpectedHash) { fextl::string Text = fextl::fmt::format("Couldn't hash the rootfs or hash didn't match\n"); Text += fmt::format("Hash {:x} != Expected Hash {:x}\n", Res.second, ExpectedHash); ExecWithInfo(Text); return std::make_pair(-1, true); } - } - else { + } else { ExecWithInfo("Correctly downloaded RootFS but doesn't exist?"); return std::make_pair(-1, false); } - } - else { + } else { ExecWithInfo("Couldn't download rootfs for some reason."); return std::make_pair(-1, false); } @@ -1262,64 +1179,58 @@ int main(int argc, char **argv, char **const envp) { return std::make_pair(0, false); }; - std::pair Result{}; - while ((Result = ValidateDownload()).second == true && - Result.first == -1) { + std::pair Result {}; + while ((Result = ValidateDownload()).second == true && Result.first == -1) { if (AskForConfirmation("Do you want to try downloading the RootFS again?")) { // Continue the loop - } - else { + } else { // Didn't want to retry, just exit now return Result.first; } } // Early exit on other errors - if (Result.first == -1 && - Result.second == false) { + if (Result.first == -1 && Result.second == false) { return Result.first; } } struct ExtractStrings { - char const *ExtractOrAsIs; - char const *AsIsSinceMounterNonFunctional; - char const *AsIsSinceExtractorNonFunctional; - char const *AsIsSinceNothingWorks; + const char* ExtractOrAsIs; + const char* AsIsSinceMounterNonFunctional; + const char* AsIsSinceExtractorNonFunctional; + const char* AsIsSinceNothingWorks; }; ArgOptions::CompressedImageOption UseImageAs {ArgOptions::CompressedUsageOption}; - bool HasExtractor{}; - bool HasMounter{}; - std::function ExtractHelper; + bool HasExtractor {}; + bool HasMounter {}; + std::function ExtractHelper; ExtractStrings ExtractingStrings; if (Target.Type == WebFileFetcher::FileTargets::FileType::TYPE_SQUASHFS) { HasExtractor = WorkingAppsTester::Has_Unsquashfs; HasMounter = WorkingAppsTester::Has_Squashfuse; ExtractHelper = UnSquash::UnsquashRootFS; - ExtractingStrings = - { - "Do you wish to extract the squashfs file or use it as-is?", - "Squashfuse doesn't work. Do you wish to extract the squashfs file?", - "Unsquashfs doesn't work. Do you want to use the squashfs file as-is?", - "Unsquashfs and squashfuse isn't working. Leaving rootfs as-is", - }; - } - else if (Target.Type == WebFileFetcher::FileTargets::FileType::TYPE_EROFS) { + ExtractingStrings = { + "Do you wish to extract the squashfs file or use it as-is?", + "Squashfuse doesn't work. Do you wish to extract the squashfs file?", + "Unsquashfs doesn't work. Do you want to use the squashfs file as-is?", + "Unsquashfs and squashfuse isn't working. Leaving rootfs as-is", + }; + } else if (Target.Type == WebFileFetcher::FileTargets::FileType::TYPE_EROFS) { HasExtractor = WorkingAppsTester::Has_EroFSFsck; HasMounter = WorkingAppsTester::Has_EroFSFuse; ExtractHelper = UnSquash::ExtractEroFS; - ExtractingStrings = - { - "Do you wish to extract the erofs file or use it as-is?", - "erofsfuse doesn't work. Do you wish to extract the erofs file?", - "Extracting erofs doesn't work. Do you want to use the erofs file as-is?", - "Extracting erofs and erofsfuse isn't working. Leaving rootfs as-is", - }; + ExtractingStrings = { + "Do you wish to extract the erofs file or use it as-is?", + "erofsfuse doesn't work. Do you wish to extract the erofs file?", + "Extracting erofs doesn't work. Do you want to use the erofs file as-is?", + "Extracting erofs and erofsfuse isn't working. Leaving rootfs as-is", + }; } - int32_t Result{}; + int32_t Result {}; std::vector Args = { "Extract", "As-Is", @@ -1331,20 +1242,17 @@ int main(int argc, char **argv, char **const envp) { Result = AskForConfirmationList(ExtractingStrings.ExtractOrAsIs, Args); if (Result == 0) { UseImageAs = ArgOptions::CompressedImageOption::OPTION_EXTRACT; - } - else if (Result == 1) { + } else if (Result == 1) { UseImageAs = ArgOptions::CompressedImageOption::OPTION_ASIS; } - } - else { + } else { Args.pop_back(); Result = AskForConfirmationList(ExtractingStrings.AsIsSinceMounterNonFunctional, Args); if (Result == 0) { UseImageAs = ArgOptions::CompressedImageOption::OPTION_EXTRACT; } } - } - else { + } else { if (HasMounter) { Args.erase(Args.begin()); Result = AskForConfirmationList(ExtractingStrings.AsIsSinceExtractorNonFunctional, Args); @@ -1352,8 +1260,7 @@ int main(int argc, char **argv, char **const envp) { // We removed an argument, Just change "As-Is" from 0 to 1 for later logic to work UseImageAs = ArgOptions::CompressedImageOption::OPTION_ASIS; } - } - else { + } else { Args.erase(Args.begin()); ExecWithInfo(ExtractingStrings.AsIsSinceNothingWorks); UseImageAs = ArgOptions::CompressedImageOption::OPTION_ASIS; diff --git a/Source/Tools/FEXRootFSFetcher/XXFileHash.cpp b/Source/Tools/FEXRootFSFetcher/XXFileHash.cpp index 93f7a37b5..4fd11a678 100644 --- a/Source/Tools/FEXRootFSFetcher/XXFileHash.cpp +++ b/Source/Tools/FEXRootFSFetcher/XXFileHash.cpp @@ -9,66 +9,66 @@ #include namespace XXFileHash { - // 32MB blocks - constexpr static size_t BLOCK_SIZE = 32 * 1024 * 1024; - std::pair HashFile(const fextl::string &Filepath) { - int fd = open(Filepath.c_str(), O_RDONLY); - if (fd == -1) { - return {false, 0}; - } - - auto HadError = [fd]() -> std::pair { - close(fd); - return {false, 0}; - }; - // Get file size - off_t Size = lseek(fd, 0, SEEK_END); - double SizeD = Size; - - // Reset to beginning - lseek(fd, 0, SEEK_SET); - - // Set up XXHash state - XXH3_state_t* const State = XXH3_createState(); - XXH64_hash_t const Seed = 0; - - if (!State) { - return HadError(); - } - - if (XXH3_64bits_reset_withSeed(State, Seed) == XXH_ERROR) { - return HadError(); - } - - std::vector Data(BLOCK_SIZE); - off_t CurrentOffset = 0; - auto Now = std::chrono::high_resolution_clock::now(); - - // Let the kernel know that we will be reading linearly - posix_fadvise(fd, 0, Size, POSIX_FADV_SEQUENTIAL); - while (CurrentOffset < Size) { - - ssize_t Result = pread(fd, Data.data(), BLOCK_SIZE, CurrentOffset); - if (Result == -1) { - return HadError(); - } - - if (XXH3_64bits_update(State, Data.data(), Result) == XXH_ERROR) { - return HadError(); - } - auto Cur = std::chrono::high_resolution_clock::now(); - auto Dur = Cur - Now; - if (Dur >= std::chrono::seconds(1)) { - fmt::print("{:.2}% hashed\n", (double)CurrentOffset / SizeD * 100.0); - Now = Cur; - } - CurrentOffset += Result; - } - - XXH64_hash_t const Hash = XXH3_64bits_digest(State); - XXH3_freeState(State); - - close(fd); - return {true, Hash}; +// 32MB blocks +constexpr static size_t BLOCK_SIZE = 32 * 1024 * 1024; +std::pair HashFile(const fextl::string& Filepath) { + int fd = open(Filepath.c_str(), O_RDONLY); + if (fd == -1) { + return {false, 0}; } + + auto HadError = [fd]() -> std::pair { + close(fd); + return {false, 0}; + }; + // Get file size + off_t Size = lseek(fd, 0, SEEK_END); + double SizeD = Size; + + // Reset to beginning + lseek(fd, 0, SEEK_SET); + + // Set up XXHash state + XXH3_state_t* const State = XXH3_createState(); + const XXH64_hash_t Seed = 0; + + if (!State) { + return HadError(); + } + + if (XXH3_64bits_reset_withSeed(State, Seed) == XXH_ERROR) { + return HadError(); + } + + std::vector Data(BLOCK_SIZE); + off_t CurrentOffset = 0; + auto Now = std::chrono::high_resolution_clock::now(); + + // Let the kernel know that we will be reading linearly + posix_fadvise(fd, 0, Size, POSIX_FADV_SEQUENTIAL); + while (CurrentOffset < Size) { + + ssize_t Result = pread(fd, Data.data(), BLOCK_SIZE, CurrentOffset); + if (Result == -1) { + return HadError(); + } + + if (XXH3_64bits_update(State, Data.data(), Result) == XXH_ERROR) { + return HadError(); + } + auto Cur = std::chrono::high_resolution_clock::now(); + auto Dur = Cur - Now; + if (Dur >= std::chrono::seconds(1)) { + fmt::print("{:.2}% hashed\n", (double)CurrentOffset / SizeD * 100.0); + Now = Cur; + } + CurrentOffset += Result; + } + + const XXH64_hash_t Hash = XXH3_64bits_digest(State); + XXH3_freeState(State); + + close(fd); + return {true, Hash}; } +} // namespace XXFileHash diff --git a/Source/Tools/FEXRootFSFetcher/XXFileHash.h b/Source/Tools/FEXRootFSFetcher/XXFileHash.h index fa4c34046..a0d735bbb 100644 --- a/Source/Tools/FEXRootFSFetcher/XXFileHash.h +++ b/Source/Tools/FEXRootFSFetcher/XXFileHash.h @@ -3,6 +3,5 @@ #include namespace XXFileHash { - std::pair HashFile(const fextl::string &Filepath); +std::pair HashFile(const fextl::string& Filepath); } - diff --git a/Source/Tools/FEXServer/ArgumentLoader.cpp b/Source/Tools/FEXServer/ArgumentLoader.cpp index b27540299..c7c1aa252 100644 --- a/Source/Tools/FEXServer/ArgumentLoader.cpp +++ b/Source/Tools/FEXServer/ArgumentLoader.cpp @@ -7,50 +7,32 @@ #include namespace FEXServer::Config { - static fextl::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; +static fextl::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; - FEXServerOptions Load(int argc, char **argv) { - FEXServerOptions FEXOptions{}; - optparse::OptionParser Parser = optparse::OptionParser() - .version(Version); +FEXServerOptions Load(int argc, char** argv) { + FEXServerOptions FEXOptions {}; + optparse::OptionParser Parser = optparse::OptionParser().version(Version); - Parser.add_option("-k", "--kill") - .action("store_true") - .set_default(false) - .help("Shutdown an already active FEXServer"); + Parser.add_option("-k", "--kill").action("store_true").set_default(false).help("Shutdown an already active FEXServer"); - Parser.add_option("-f", "--foreground") - .action("store_true") - .set_default(false) - .help("Run this FEXServer in the foreground"); + Parser.add_option("-f", "--foreground").action("store_true").set_default(false).help("Run this FEXServer in the foreground"); - Parser.add_option("-p", "--persistent") - .action("store") - .type("int") - .set_default(0) - .set_optional_value(true) - .metavar("n") - .help("Make FEXServer persistent. Optional number of seconds"); + Parser.add_option("-p", "--persistent").action("store").type("int").set_default(0).set_optional_value(true).metavar("n").help("Make FEXServer persistent. Optional number of seconds"); - Parser.add_option("-w", "--wait") - .action("store_true") - .set_default(false) - .help("Wait for the FEXServer to shutdown"); + Parser.add_option("-w", "--wait").action("store_true").set_default(false).help("Wait for the FEXServer to shutdown"); - Parser.add_option("-v") - .action("version") - .help("Version string"); + Parser.add_option("-v").action("version").help("Version string"); - optparse::Values Options = Parser.parse_args(argc, argv); + optparse::Values Options = Parser.parse_args(argc, argv); - FEXOptions.Kill = Options.get("kill"); - FEXOptions.Foreground = Options.get("foreground"); - FEXOptions.Wait = Options.get("wait"); - if (FEXOptions.Wait) { - FEXOptions.Foreground = true; - } - FEXOptions.PersistentTimeout = Options.get("persistent"); - - return FEXOptions; + FEXOptions.Kill = Options.get("kill"); + FEXOptions.Foreground = Options.get("foreground"); + FEXOptions.Wait = Options.get("wait"); + if (FEXOptions.Wait) { + FEXOptions.Foreground = true; } + FEXOptions.PersistentTimeout = Options.get("persistent"); + + return FEXOptions; } +} // namespace FEXServer::Config diff --git a/Source/Tools/FEXServer/ArgumentLoader.h b/Source/Tools/FEXServer/ArgumentLoader.h index e8c8f5b12..910f8962c 100644 --- a/Source/Tools/FEXServer/ArgumentLoader.h +++ b/Source/Tools/FEXServer/ArgumentLoader.h @@ -3,12 +3,12 @@ #include namespace FEXServer::Config { - struct FEXServerOptions { - bool Kill; - bool Foreground; - bool Wait; - uint32_t PersistentTimeout; - }; +struct FEXServerOptions { + bool Kill; + bool Foreground; + bool Wait; + uint32_t PersistentTimeout; +}; - FEXServerOptions Load(int argc, char **argv); -} +FEXServerOptions Load(int argc, char** argv); +} // namespace FEXServer::Config diff --git a/Source/Tools/FEXServer/Logger.cpp b/Source/Tools/FEXServer/Logger.cpp index 644909651..6c57352f7 100644 --- a/Source/Tools/FEXServer/Logger.cpp +++ b/Source/Tools/FEXServer/Logger.cpp @@ -8,142 +8,135 @@ #include namespace Logging { - void ClientMsgHandler(int FD, uint64_t Timestamp, uint32_t PID, uint32_t TID, uint32_t Level, const char* Msg); +void ClientMsgHandler(int FD, uint64_t Timestamp, uint32_t PID, uint32_t TID, uint32_t Level, const char* Msg); } namespace Logger { - std::vector PollFDs{}; - std::mutex IncomingPollFDsLock{}; - std::vector IncomingPollFDs{}; - std::thread LogThread; - std::atomic ShouldShutdown {false}; - std::atomic LoggerThreadTID{}; +std::vector PollFDs {}; +std::mutex IncomingPollFDsLock {}; +std::vector IncomingPollFDs {}; +std::thread LogThread; +std::atomic ShouldShutdown {false}; +std::atomic LoggerThreadTID {}; - void HandleLogData(int Socket) { - std::vector Data(1500); - size_t CurrentRead{}; - while (true) { - int Read = read(Socket, &Data.at(CurrentRead), Data.size() - CurrentRead); - if (Read > 0) { - CurrentRead += Read; - if (CurrentRead == Data.size()) { - Data.resize(Data.size() << 1); - } - else { - // No more to read - break; - } - } - else { - if (errno == EWOULDBLOCK) { - // no error - } - else { - perror("read"); - } +void HandleLogData(int Socket) { + std::vector Data(1500); + size_t CurrentRead {}; + while (true) { + int Read = read(Socket, &Data.at(CurrentRead), Data.size() - CurrentRead); + if (Read > 0) { + CurrentRead += Read; + if (CurrentRead == Data.size()) { + Data.resize(Data.size() << 1); + } else { + // No more to read break; } - } - - size_t CurrentOffset{}; - while (CurrentOffset < CurrentRead) { - FEXServerClient::Logging::PacketHeader *Header = reinterpret_cast(&Data[CurrentOffset]); - if (Header->PacketType == FEXServerClient::Logging::PacketTypes::TYPE_MSG) { - FEXServerClient::Logging::PacketMsg *Msg = reinterpret_cast(&Data[CurrentOffset]); - const char *MsgText = reinterpret_cast(&Data[CurrentOffset + sizeof(FEXServerClient::Logging::PacketMsg)]); - Logging::ClientMsgHandler(Socket, Msg->Header.Timestamp, Msg->Header.PID, Msg->Header.TID, Msg->Level, MsgText); - - CurrentOffset += sizeof(FEXServerClient::Logging::PacketMsg) + Msg->MessageLength; - } - else { - CurrentOffset = CurrentRead; + } else { + if (errno == EWOULDBLOCK) { + // no error + } else { + perror("read"); } + break; } } - void LogThreadFunc() { - LoggerThreadTID = FHU::Syscalls::gettid(); + size_t CurrentOffset {}; + while (CurrentOffset < CurrentRead) { + FEXServerClient::Logging::PacketHeader* Header = reinterpret_cast(&Data[CurrentOffset]); + if (Header->PacketType == FEXServerClient::Logging::PacketTypes::TYPE_MSG) { + FEXServerClient::Logging::PacketMsg* Msg = reinterpret_cast(&Data[CurrentOffset]); + const char* MsgText = reinterpret_cast(&Data[CurrentOffset + sizeof(FEXServerClient::Logging::PacketMsg)]); + Logging::ClientMsgHandler(Socket, Msg->Header.Timestamp, Msg->Header.PID, Msg->Header.TID, Msg->Level, MsgText); - while (!ShouldShutdown) { - struct timespec ts{}; - ts.tv_sec = 5; + CurrentOffset += sizeof(FEXServerClient::Logging::PacketMsg) + Msg->MessageLength; + } else { + CurrentOffset = CurrentRead; + } + } +} - { - std::unique_lock lk {IncomingPollFDsLock}; - PollFDs.insert(PollFDs.end(), std::make_move_iterator(IncomingPollFDs.begin()), std::make_move_iterator(IncomingPollFDs.end())); - IncomingPollFDs.clear(); - } - if (PollFDs.size() == 0) { - pselect(0, nullptr, nullptr, nullptr, &ts, nullptr); - } - else { - int Result = ppoll(&PollFDs.at(0), PollFDs.size(), &ts, nullptr); - if (Result > 0) { - // Walk the FDs and see if we got any results - for (auto it = PollFDs.begin(); it != PollFDs.end(); ) { - bool Erase{}; - if (it->revents != 0) { - if (it->revents & POLLIN) { - // Data from the socket - HandleLogData(it->fd); - } - else if (it->revents & (POLLHUP | POLLERR | POLLNVAL | POLLRDHUP)) { - // Error or hangup, close the socket and erase it from our list - Erase = true; - close(it->fd); - } +void LogThreadFunc() { + LoggerThreadTID = FHU::Syscalls::gettid(); - it->revents = 0; - --Result; + while (!ShouldShutdown) { + struct timespec ts {}; + ts.tv_sec = 5; + + { + std::unique_lock lk {IncomingPollFDsLock}; + PollFDs.insert(PollFDs.end(), std::make_move_iterator(IncomingPollFDs.begin()), std::make_move_iterator(IncomingPollFDs.end())); + IncomingPollFDs.clear(); + } + if (PollFDs.size() == 0) { + pselect(0, nullptr, nullptr, nullptr, &ts, nullptr); + } else { + int Result = ppoll(&PollFDs.at(0), PollFDs.size(), &ts, nullptr); + if (Result > 0) { + // Walk the FDs and see if we got any results + for (auto it = PollFDs.begin(); it != PollFDs.end();) { + bool Erase {}; + if (it->revents != 0) { + if (it->revents & POLLIN) { + // Data from the socket + HandleLogData(it->fd); + } else if (it->revents & (POLLHUP | POLLERR | POLLNVAL | POLLRDHUP)) { + // Error or hangup, close the socket and erase it from our list + Erase = true; + close(it->fd); } - if (Erase) { - it = PollFDs.erase(it); - } - else { - ++it; - } + it->revents = 0; + --Result; + } - if (Result == 0) { - // Early break if we've consumed all the results - break; - } + if (Erase) { + it = PollFDs.erase(it); + } else { + ++it; + } + + if (Result == 0) { + // Early break if we've consumed all the results + break; } } } } } +} - void StartLogThread() { - LogThread = std::thread(LogThreadFunc); +void StartLogThread() { + LogThread = std::thread(LogThreadFunc); +} + +void AppendLogFD(int FD) { + { + std::unique_lock lk {IncomingPollFDsLock}; + IncomingPollFDs.emplace_back(pollfd { + .fd = FD, + .events = POLLIN, + .revents = 0, + }); } - void AppendLogFD(int FD) { - { - std::unique_lock lk {IncomingPollFDsLock}; - IncomingPollFDs.emplace_back(pollfd { - .fd = FD, - .events = POLLIN, - .revents = 0, - }); - } + // Wake up the thread immediately + FHU::Syscalls::tgkill(::getpid(), LoggerThreadTID, SIGUSR1); +} - // Wake up the thread immediately - FHU::Syscalls::tgkill(::getpid(), LoggerThreadTID, SIGUSR1); - } +bool LogThreadRunning() { + return LogThread.joinable(); +} - bool LogThreadRunning() { - return LogThread.joinable(); - } +void Shutdown() { + ShouldShutdown = true; - void Shutdown() { - ShouldShutdown = true; + // Wake up the thread immediately + FHU::Syscalls::tgkill(::getpid(), LoggerThreadTID, SIGUSR1); - // Wake up the thread immediately - FHU::Syscalls::tgkill(::getpid(), LoggerThreadTID, SIGUSR1); - - if (LogThread.joinable()) { - LogThread.join(); - } + if (LogThread.joinable()) { + LogThread.join(); } } +} // namespace Logger diff --git a/Source/Tools/FEXServer/Logger.h b/Source/Tools/FEXServer/Logger.h index fb0228623..6ac1bda1f 100644 --- a/Source/Tools/FEXServer/Logger.h +++ b/Source/Tools/FEXServer/Logger.h @@ -2,8 +2,8 @@ #pragma once namespace Logger { - void AppendLogFD(int FD); - void StartLogThread(); - bool LogThreadRunning(); - void Shutdown(); -} +void AppendLogFD(int FD); +void StartLogThread(); +bool LogThreadRunning(); +void Shutdown(); +} // namespace Logger diff --git a/Source/Tools/FEXServer/Main.cpp b/Source/Tools/FEXServer/Main.cpp index fae923822..9cdb6c816 100644 --- a/Source/Tools/FEXServer/Main.cpp +++ b/Source/Tools/FEXServer/Main.cpp @@ -25,79 +25,78 @@ #include namespace Logging { - void MsgHandler(LogMan::DebugLevels Level, char const *Message) { - const auto Output = fmt::format("[{}] {}\n", LogMan::DebugLevelStr(Level), Message); - write(STDOUT_FILENO, Output.c_str(), Output.size()); - } - - void AssertHandler(char const *Message) { - const auto Output = fmt::format("[ASSERT] {}\n", Message); - write(STDOUT_FILENO, Output.c_str(), Output.size()); - } - - void ClientMsgHandler(int FD, uint64_t Timestamp, uint32_t PID, uint32_t TID, uint32_t Level, const char* Msg) { - const auto Output = fmt::format("[{}][{}][{}.{}] {}\n", LogMan::DebugLevelStr(Level), Timestamp, PID, TID, Msg); - write(STDERR_FILENO, Output.c_str(), Output.size()); - } +void MsgHandler(LogMan::DebugLevels Level, const char* Message) { + const auto Output = fmt::format("[{}] {}\n", LogMan::DebugLevelStr(Level), Message); + write(STDOUT_FILENO, Output.c_str(), Output.size()); } +void AssertHandler(const char* Message) { + const auto Output = fmt::format("[ASSERT] {}\n", Message); + write(STDOUT_FILENO, Output.c_str(), Output.size()); +} + +void ClientMsgHandler(int FD, uint64_t Timestamp, uint32_t PID, uint32_t TID, uint32_t Level, const char* Msg) { + const auto Output = fmt::format("[{}][{}][{}.{}] {}\n", LogMan::DebugLevelStr(Level), Timestamp, PID, TID, Msg); + write(STDERR_FILENO, Output.c_str(), Output.size()); +} +} // namespace Logging + namespace { - void ActionHandler(int sig, siginfo_t *info, void *context) { - // FEX_TODO("Fix this"); - if (sig == SIGINT) { - // Someone trying to kill us. Shutdown. - ProcessPipe::Shutdown(); - return; - } - _exit(1); - } - - void ActionIgnore(int sig, siginfo_t *info, void *context) { - } - - void SetupSignals() { - // Setup our signal handlers now so we can capture some events - struct sigaction act{}; - act.sa_sigaction = ActionHandler; - act.sa_flags = SA_SIGINFO; - - // SIGTERM if something is trying to terminate us - sigaction(SIGTERM, &act, nullptr); - // SIGINT if something is trying to terminate us - sigaction(SIGINT, &act, nullptr); - - // SIGUSR1 just to interrupt syscalls - act.sa_sigaction = ActionIgnore; - sigaction(SIGUSR1, &act, nullptr); - - // Ignore SIGPIPE, we will be checking for pipe closure which could send this signal - signal(SIGPIPE, SIG_IGN); - // SIGCHLD if squashfuse exits early. - // Ignore it for now - signal(SIGCHLD, SIG_IGN); - } - - /** - * @brief Deparents itself by forking and terminating the parent process. - */ - void DeparentSelf() { - auto SystemdEnv = getenv("INVOCATION_ID"); - if (SystemdEnv) { - // If FEXServer was launched through systemd then don't deparent, otherwise systemd kills the entire server. - return; - } - - pid_t pid = fork(); - - if (pid != 0) { - // Parent is leaving to force this process to deparent itself - // This lets this process become the child of whatever the reaper parent is - _exit(0); - } +void ActionHandler(int sig, siginfo_t* info, void* context) { + // FEX_TODO("Fix this"); + if (sig == SIGINT) { + // Someone trying to kill us. Shutdown. + ProcessPipe::Shutdown(); + return; } + _exit(1); } -int main(int argc, char **argv, char **const envp) { +void ActionIgnore(int sig, siginfo_t* info, void* context) {} + +void SetupSignals() { + // Setup our signal handlers now so we can capture some events + struct sigaction act {}; + act.sa_sigaction = ActionHandler; + act.sa_flags = SA_SIGINFO; + + // SIGTERM if something is trying to terminate us + sigaction(SIGTERM, &act, nullptr); + // SIGINT if something is trying to terminate us + sigaction(SIGINT, &act, nullptr); + + // SIGUSR1 just to interrupt syscalls + act.sa_sigaction = ActionIgnore; + sigaction(SIGUSR1, &act, nullptr); + + // Ignore SIGPIPE, we will be checking for pipe closure which could send this signal + signal(SIGPIPE, SIG_IGN); + // SIGCHLD if squashfuse exits early. + // Ignore it for now + signal(SIGCHLD, SIG_IGN); +} + +/** + * @brief Deparents itself by forking and terminating the parent process. + */ +void DeparentSelf() { + auto SystemdEnv = getenv("INVOCATION_ID"); + if (SystemdEnv) { + // If FEXServer was launched through systemd then don't deparent, otherwise systemd kills the entire server. + return; + } + + pid_t pid = fork(); + + if (pid != 0) { + // Parent is leaving to force this process to deparent itself + // This lets this process become the child of whatever the reaper parent is + _exit(0); + } +} +} // namespace + +int main(int argc, char** argv, char** const envp) { auto Options = FEXServer::Config::Load(argc, argv); SetupSignals(); @@ -115,12 +114,7 @@ int main(int argc, char **argv, char **const envp) { DeparentSelf(); } - FEX::Config::LoadConfig( - true, - false, - argc, argv, envp, - false, {} - ); + FEX::Config::LoadConfig(true, false, argc, argv, envp, false, {}); // Reload the meta layer FEXCore::Config::ReloadMetaLayer(); @@ -139,7 +133,8 @@ int main(int argc, char **argv, char **const envp) { PollFD.events = POLLIN | POLLOUT | POLLRDHUP | POLLERR | POLLHUP | POLLNVAL; // Wait for a result on the pipe that isn't EINTR - while (poll(&PollFD, 1, -1) == -1 && errno == EINTR); + while (poll(&PollFD, 1, -1) == -1 && errno == EINTR) + ; LogMan::Msg::IFmt("[FEXServer] FEXServer shutdown"); } diff --git a/Source/Tools/FEXServer/PipeScanner.cpp b/Source/Tools/FEXServer/PipeScanner.cpp index 15dd72d41..fdbc844a9 100644 --- a/Source/Tools/FEXServer/PipeScanner.cpp +++ b/Source/Tools/FEXServer/PipeScanner.cpp @@ -7,44 +7,44 @@ #include namespace PipeScanner { - std::vector IncomingPipes{}; +std::vector IncomingPipes {}; - // Scan and store any pipe files. - // This will capture all pipe files so needs to be executed early. - // This ensures we find any pipe files from execve for waiting FEXInterpreters. - void ScanForPipes() { - DIR *fd = opendir("/proc/self/fd"); - if (fd) { - struct dirent *dir{}; - do { - dir = readdir(fd); - if (dir) { - char *end{}; - int open_fd = std::strtol(dir->d_name, &end, 8); - if (end != dir->d_name) { - struct stat stat{}; - int result = fstat(open_fd, &stat); - if (result == -1) { - continue; - } - if (stat.st_mode & S_IFIFO) { - // Close any incoming pipes - IncomingPipes.emplace_back(open_fd); - } +// Scan and store any pipe files. +// This will capture all pipe files so needs to be executed early. +// This ensures we find any pipe files from execve for waiting FEXInterpreters. +void ScanForPipes() { + DIR* fd = opendir("/proc/self/fd"); + if (fd) { + struct dirent* dir {}; + do { + dir = readdir(fd); + if (dir) { + char* end {}; + int open_fd = std::strtol(dir->d_name, &end, 8); + if (end != dir->d_name) { + struct stat stat {}; + int result = fstat(open_fd, &stat); + if (result == -1) { + continue; + } + if (stat.st_mode & S_IFIFO) { + // Close any incoming pipes + IncomingPipes.emplace_back(open_fd); } } - } while (dir); + } + } while (dir); - closedir(fd); - } - } - - void ClosePipes() { - for (auto pipe : IncomingPipes) { - int Null{0}; - write(pipe, &Null, sizeof(Null)); - close(pipe); - } - IncomingPipes.clear(); + closedir(fd); } } + +void ClosePipes() { + for (auto pipe : IncomingPipes) { + int Null {0}; + write(pipe, &Null, sizeof(Null)); + close(pipe); + } + IncomingPipes.clear(); +} +} // namespace PipeScanner diff --git a/Source/Tools/FEXServer/PipeScanner.h b/Source/Tools/FEXServer/PipeScanner.h index 1f74e3f37..ced8f8a0e 100644 --- a/Source/Tools/FEXServer/PipeScanner.h +++ b/Source/Tools/FEXServer/PipeScanner.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT #pragma once namespace PipeScanner { - void ScanForPipes(); - void ClosePipes(); -} +void ScanForPipes(); +void ClosePipes(); +} // namespace PipeScanner diff --git a/Source/Tools/FEXServer/ProcessPipe.cpp b/Source/Tools/FEXServer/ProcessPipe.cpp index 2be8cd271..69b52b568 100644 --- a/Source/Tools/FEXServer/ProcessPipe.cpp +++ b/Source/Tools/FEXServer/ProcessPipe.cpp @@ -16,133 +16,102 @@ #include namespace ProcessPipe { - constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; - int ServerLockFD {-1}; - int ServerSocketFD{-1}; - std::atomic ShouldShutdown {false}; - time_t RequestTimeout {10}; - bool Foreground {false}; - std::vector PollFDs{}; +constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; +int ServerLockFD {-1}; +int ServerSocketFD {-1}; +std::atomic ShouldShutdown {false}; +time_t RequestTimeout {10}; +bool Foreground {false}; +std::vector PollFDs {}; - // FD count watching - constexpr size_t static MAX_FD_DISTANCE = 32; - rlimit MaxFDs{}; - std::atomic NumFilesOpened{}; +// FD count watching +constexpr size_t static MAX_FD_DISTANCE = 32; +rlimit MaxFDs {}; +std::atomic NumFilesOpened {}; - size_t GetNumFilesOpen() { - // Walk /proc/self/fd/ to see how many open files we currently have - const std::filesystem::path self{"/proc/self/fd/"}; +size_t GetNumFilesOpen() { + // Walk /proc/self/fd/ to see how many open files we currently have + const std::filesystem::path self {"/proc/self/fd/"}; - return std::distance(std::filesystem::directory_iterator{self}, std::filesystem::directory_iterator{}); + return std::distance(std::filesystem::directory_iterator {self}, std::filesystem::directory_iterator {}); +} + +void GetMaxFDs() { + // Get our kernel limit for the number of open files + if (getrlimit(RLIMIT_NOFILE, &MaxFDs) != 0) { + fprintf(stderr, "[FEXMountDaemon] getrlimit(RLIMIT_NOFILE) returned error %d %s\n", errno, strerror(errno)); } - void GetMaxFDs() { - // Get our kernel limit for the number of open files - if (getrlimit(RLIMIT_NOFILE, &MaxFDs) != 0) { - fprintf(stderr, "[FEXMountDaemon] getrlimit(RLIMIT_NOFILE) returned error %d %s\n", errno, strerror(errno)); - } + // Walk /proc/self/fd/ to see how many open files we currently have + NumFilesOpened = GetNumFilesOpen(); +} - // Walk /proc/self/fd/ to see how many open files we currently have - NumFilesOpened = GetNumFilesOpen(); +void CheckRaiseFDLimit() { + if (NumFilesOpened < (MaxFDs.rlim_cur - MAX_FD_DISTANCE)) { + // No need to raise the limit. + return; } - void CheckRaiseFDLimit() { - if (NumFilesOpened < (MaxFDs.rlim_cur - MAX_FD_DISTANCE)) { - // No need to raise the limit. - return; - } - - if (MaxFDs.rlim_cur == MaxFDs.rlim_max) { - fprintf(stderr, "[FEXMountDaemon] Our open FD limit is already set to max and we are wanting to increase it\n"); - fprintf(stderr, "[FEXMountDaemon] FEXMountDaemon will now no longer be able to track new instances of FEX\n"); - fprintf(stderr, "[FEXMountDaemon] Current limit is %zd(hard %zd) FDs and we are at %zd\n", MaxFDs.rlim_cur, MaxFDs.rlim_max, GetNumFilesOpen()); - fprintf(stderr, "[FEXMountDaemon] Ask your administrator to raise your kernel's hard limit on open FDs\n"); - return; - } - - rlimit NewLimit = MaxFDs; - - // Just multiply by two - NewLimit.rlim_cur <<= 1; - - // Now limit to the hard max - NewLimit.rlim_cur = std::min(NewLimit.rlim_cur, NewLimit.rlim_max); - - if (setrlimit(RLIMIT_NOFILE, &NewLimit) != 0) { - fprintf(stderr, "[FEXMountDaemon] Couldn't raise FD limit to %zd even though our hard limit is %zd\n", NewLimit.rlim_cur, NewLimit.rlim_max); - } - else { - // Set the new limit - MaxFDs = NewLimit; - } + if (MaxFDs.rlim_cur == MaxFDs.rlim_max) { + fprintf(stderr, "[FEXMountDaemon] Our open FD limit is already set to max and we are wanting to increase it\n"); + fprintf(stderr, "[FEXMountDaemon] FEXMountDaemon will now no longer be able to track new instances of FEX\n"); + fprintf(stderr, "[FEXMountDaemon] Current limit is %zd(hard %zd) FDs and we are at %zd\n", MaxFDs.rlim_cur, MaxFDs.rlim_max, + GetNumFilesOpen()); + fprintf(stderr, "[FEXMountDaemon] Ask your administrator to raise your kernel's hard limit on open FDs\n"); + return; } - bool InitializeServerPipe() { - auto ServerFolder = FEXServerClient::GetServerLockFolder(); + rlimit NewLimit = MaxFDs; - std::error_code ec{}; - if (!std::filesystem::exists(ServerFolder, ec)) { - // Doesn't exist, create the the folder as a user convenience - if (!std::filesystem::create_directories(ServerFolder, ec)) { - LogMan::Msg::EFmt("Couldn't create server pipe folder at: {}", ServerFolder); - return false; - } - } + // Just multiply by two + NewLimit.rlim_cur <<= 1; - auto ServerLockPath = FEXServerClient::GetServerLockFile(); + // Now limit to the hard max + NewLimit.rlim_cur = std::min(NewLimit.rlim_cur, NewLimit.rlim_max); - // Now this is some tricky locking logic to ensure that we only ever have one server running - // The logic is as follows: - // - Try to make the lock file - // - If Exists then check to see if it is a stale handle - // - Stale checking means opening the file that we know exists - // - Then we try getting a write lock - // - If we fail to get the write lock, then leave - // - Otherwise continue down the codepath and degrade to read lock - // - Else try to acquire a write lock to ensure only one FEXServer exists - // - // - Once a write lock is acquired, downgrade it to a read lock - // - This ensures that future FEXServers won't race to create multiple read locks - int Ret = open(ServerLockPath.c_str(), O_RDWR | O_CREAT | O_CLOEXEC | O_EXCL, USER_PERMS); - ServerLockFD = Ret; + if (setrlimit(RLIMIT_NOFILE, &NewLimit) != 0) { + fprintf(stderr, "[FEXMountDaemon] Couldn't raise FD limit to %zd even though our hard limit is %zd\n", NewLimit.rlim_cur, NewLimit.rlim_max); + } else { + // Set the new limit + MaxFDs = NewLimit; + } +} - if (Ret == -1 && errno == EEXIST) { - // If the lock exists then it might be a stale connection. - // Check the lock status to see if another process is still alive. - ServerLockFD = open(ServerLockPath.c_str(), O_RDWR | O_CLOEXEC, USER_PERMS); - if (ServerLockFD != -1) { - // Now that we have opened the file, try to get a write lock. - flock lk { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; - Ret = fcntl(ServerLockFD, F_SETLK, &lk); +bool InitializeServerPipe() { + auto ServerFolder = FEXServerClient::GetServerLockFolder(); - if (Ret != -1) { - // Write lock was gained, we can now continue onward. - } - else { - // We couldn't get a write lock, this means that another process already owns a lock on the lock - close(ServerLockFD); - ServerLockFD = -1; - return false; - } - } - else { - // File couldn't get opened even though it existed? - // Must have raced something here. - return false; - } - } - else if (Ret == -1) { - // Unhandled error. - LogMan::Msg::EFmt("Unable to create FEXServer named lock file at: {} {} {}", ServerLockPath, errno, strerror(errno)); + std::error_code ec {}; + if (!std::filesystem::exists(ServerFolder, ec)) { + // Doesn't exist, create the the folder as a user convenience + if (!std::filesystem::create_directories(ServerFolder, ec)) { + LogMan::Msg::EFmt("Couldn't create server pipe folder at: {}", ServerFolder); return false; } - else { - // FIFO file was created. Try to get a write lock + } + + auto ServerLockPath = FEXServerClient::GetServerLockFile(); + + // Now this is some tricky locking logic to ensure that we only ever have one server running + // The logic is as follows: + // - Try to make the lock file + // - If Exists then check to see if it is a stale handle + // - Stale checking means opening the file that we know exists + // - Then we try getting a write lock + // - If we fail to get the write lock, then leave + // - Otherwise continue down the codepath and degrade to read lock + // - Else try to acquire a write lock to ensure only one FEXServer exists + // + // - Once a write lock is acquired, downgrade it to a read lock + // - This ensures that future FEXServers won't race to create multiple read locks + int Ret = open(ServerLockPath.c_str(), O_RDWR | O_CREAT | O_CLOEXEC | O_EXCL, USER_PERMS); + ServerLockFD = Ret; + + if (Ret == -1 && errno == EEXIST) { + // If the lock exists then it might be a stale connection. + // Check the lock status to see if another process is still alive. + ServerLockFD = open(ServerLockPath.c_str(), O_RDWR | O_CLOEXEC, USER_PERMS); + if (ServerLockFD != -1) { + // Now that we have opened the file, try to get a write lock. flock lk { .l_type = F_WRLCK, .l_whence = SEEK_SET, @@ -151,17 +120,27 @@ namespace ProcessPipe { }; Ret = fcntl(ServerLockFD, F_SETLK, &lk); - if (Ret == -1) { - // Couldn't get a write lock, something else must have got it + if (Ret != -1) { + // Write lock was gained, we can now continue onward. + } else { + // We couldn't get a write lock, this means that another process already owns a lock on the lock close(ServerLockFD); ServerLockFD = -1; return false; } + } else { + // File couldn't get opened even though it existed? + // Must have raced something here. + return false; } - - // Now that a write lock is held, downgrade it to a read lock + } else if (Ret == -1) { + // Unhandled error. + LogMan::Msg::EFmt("Unable to create FEXServer named lock file at: {} {} {}", ServerLockPath, errno, strerror(errno)); + return false; + } else { + // FIFO file was created. Try to get a write lock flock lk { - .l_type = F_RDLCK, + .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 0, @@ -169,381 +148,370 @@ namespace ProcessPipe { Ret = fcntl(ServerLockFD, F_SETLK, &lk); if (Ret == -1) { - // This shouldn't occur - LogMan::Msg::EFmt("Unable to downgrade a write lock to a read lock {} {} {}", ServerLockPath, errno, strerror(errno)); + // Couldn't get a write lock, something else must have got it close(ServerLockFD); ServerLockFD = -1; return false; } - - return true; } - bool InitializeServerSocket() { - auto ServerSocketName = FEXServerClient::GetServerSocketName(); + // Now that a write lock is held, downgrade it to a read lock + flock lk { + .l_type = F_RDLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + Ret = fcntl(ServerLockFD, F_SETLK, &lk); - // Create the initial unix socket - ServerSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (ServerSocketFD == -1) { - LogMan::Msg::EFmt("Couldn't create AF_UNIX socket: {} {}\n", errno, strerror(errno)); - return false; - } - - struct sockaddr_un addr{}; - addr.sun_family = AF_UNIX; - size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1); - addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0 - strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString); - // Include final null character. - size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString; - - // Bind the socket to the path - int Result = bind(ServerSocketFD, reinterpret_cast(&addr), SizeOfAddr); - if (Result == -1) { - LogMan::Msg::EFmt("Couldn't bind AF_UNIX socket '{}': {} {}\n", addr.sun_path, errno, strerror(errno)); - close(ServerSocketFD); - ServerSocketFD = -1; - return false; - } - - listen(ServerSocketFD, 16); - PollFDs.emplace_back(pollfd { - .fd = ServerSocketFD, - .events = POLLIN, - .revents = 0, - }); - - return true; + if (Ret == -1) { + // This shouldn't occur + LogMan::Msg::EFmt("Unable to downgrade a write lock to a read lock {} {} {}", ServerLockPath, errno, strerror(errno)); + close(ServerLockFD); + ServerLockFD = -1; + return false; } - void SendEmptyErrorPacket(int Socket) { - FEXServerClient::FEXServerResultPacket Res { - .Header { - .Type = FEXServerClient::PacketType::TYPE_ERROR, - }, - }; + return true; +} +bool InitializeServerSocket() { + auto ServerSocketName = FEXServerClient::GetServerSocketName(); + + // Create the initial unix socket + ServerSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (ServerSocketFD == -1) { + LogMan::Msg::EFmt("Couldn't create AF_UNIX socket: {} {}\n", errno, strerror(errno)); + return false; + } + + struct sockaddr_un addr {}; + addr.sun_family = AF_UNIX; + size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1); + addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0 + strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString); + // Include final null character. + size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString; + + // Bind the socket to the path + int Result = bind(ServerSocketFD, reinterpret_cast(&addr), SizeOfAddr); + if (Result == -1) { + LogMan::Msg::EFmt("Couldn't bind AF_UNIX socket '{}': {} {}\n", addr.sun_path, errno, strerror(errno)); + close(ServerSocketFD); + ServerSocketFD = -1; + return false; + } + + listen(ServerSocketFD, 16); + PollFDs.emplace_back(pollfd { + .fd = ServerSocketFD, + .events = POLLIN, + .revents = 0, + }); + + return true; +} + +void SendEmptyErrorPacket(int Socket) { + FEXServerClient::FEXServerResultPacket Res { + .Header { + .Type = FEXServerClient::PacketType::TYPE_ERROR, + }, + }; + + struct iovec iov { + .iov_base = &Res, .iov_len = sizeof(Res), + }; + + struct msghdr msg { + .msg_name = nullptr, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1, + }; + + sendmsg(Socket, &msg, 0); +} + +void SendFDSuccessPacket(int Socket, int FD) { + FEXServerClient::FEXServerResultPacket Res { + .Header { + .Type = FEXServerClient::PacketType::TYPE_SUCCESS, + }, + }; + + struct iovec iov { + .iov_base = &Res, .iov_len = sizeof(Res), + }; + + struct msghdr msg { + .msg_name = nullptr, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1, + }; + + // Setup the ancillary buffer. This is where we will be getting pipe FDs + // We only need 4 bytes for the FD + constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int)); + union AncillaryBuffer { + struct cmsghdr Header; + uint8_t Buffer[CMSG_SIZE]; + }; + AncillaryBuffer AncBuf {}; + + // Now link to our ancilllary buffer + msg.msg_control = AncBuf.Buffer; + msg.msg_controllen = CMSG_SIZE; + + // Now we need to setup the ancillary buffer data. We are only sending an FD + struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + // We are giving the daemon the write side of the pipe + memcpy(CMSG_DATA(cmsg), &FD, sizeof(int)); + + sendmsg(Socket, &msg, 0); +} + +void HandleSocketData(int Socket) { + std::vector Data(1500); + size_t CurrentRead {}; + + // Get the current number of FDs of the process before we start handling sockets. + GetMaxFDs(); + + while (true) { struct iovec iov { - .iov_base = &Res, - .iov_len = sizeof(Res), + .iov_base = &Data.at(CurrentRead), .iov_len = Data.size() - CurrentRead, }; struct msghdr msg { - .msg_name = nullptr, - .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, + .msg_name = nullptr, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1, }; - sendmsg(Socket, &msg, 0); + ssize_t Read = recvmsg(Socket, &msg, 0); + if (Read <= msg.msg_iov->iov_len) { + CurrentRead += Read; + if (CurrentRead == Data.size()) { + Data.resize(Data.size() << 1); + } else { + // No more to read + break; + } + } else { + if (errno == EWOULDBLOCK) { + // no error + } else { + perror("read"); + } + break; + } } - void SendFDSuccessPacket(int Socket, int FD) { - FEXServerClient::FEXServerResultPacket Res { - .Header { - .Type = FEXServerClient::PacketType::TYPE_SUCCESS, - }, - }; + size_t CurrentOffset {}; + while (CurrentOffset < CurrentRead) { + FEXServerClient::FEXServerRequestPacket* Req = reinterpret_cast(&Data[CurrentOffset]); + switch (Req->Header.Type) { + case FEXServerClient::PacketType::TYPE_KILL: + ShouldShutdown = true; + CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::BasicRequest); + break; + case FEXServerClient::PacketType::TYPE_GET_LOG_FD: { + if (Logger::LogThreadRunning()) { + int fds[2] {}; + pipe2(fds, 0); + // 0 = Read + // 1 = Write + Logger::AppendLogFD(fds[0]); - struct iovec iov { - .iov_base = &Res, - .iov_len = sizeof(Res), - }; + SendFDSuccessPacket(Socket, fds[1]); - struct msghdr msg { - .msg_name = nullptr, - .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, - }; + // Close the write side now, doesn't matter to us + close(fds[1]); - // Setup the ancillary buffer. This is where we will be getting pipe FDs - // We only need 4 bytes for the FD - constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int)); - union AncillaryBuffer { - struct cmsghdr Header; - uint8_t Buffer[CMSG_SIZE]; - }; - AncillaryBuffer AncBuf{}; + // Check if we need to increase the FD limit. + ++NumFilesOpened; + CheckRaiseFDLimit(); + } else { + // Log thread isn't running. Let FEXInterpreter know it can't have one. + SendEmptyErrorPacket(Socket); + } - // Now link to our ancilllary buffer - msg.msg_control = AncBuf.Buffer; - msg.msg_controllen = CMSG_SIZE; + CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::Header); + break; + } + case FEXServerClient::PacketType::TYPE_GET_ROOTFS_PATH: { + fextl::string MountFolder = SquashFS::GetMountFolder(); - // Now we need to setup the ancillary buffer data. We are only sending an FD - struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; + FEXServerClient::FEXServerResultPacket Res { + .MountPath { + .Header { + .Type = FEXServerClient::PacketType::TYPE_GET_ROOTFS_PATH, + }, + .Length = MountFolder.size() + 1, + }, + }; - // We are giving the daemon the write side of the pipe - memcpy(CMSG_DATA(cmsg), &FD, sizeof(int)); + char Null {}; - sendmsg(Socket, &msg, 0); - } - - void HandleSocketData(int Socket) { - std::vector Data(1500); - size_t CurrentRead{}; - - // Get the current number of FDs of the process before we start handling sockets. - GetMaxFDs(); - - while (true) { - struct iovec iov { - .iov_base = &Data.at(CurrentRead), - .iov_len = Data.size() - CurrentRead, + iovec iov[3] { + { + .iov_base = &Res, + .iov_len = sizeof(Res), + }, + { + .iov_base = MountFolder.data(), + .iov_len = MountFolder.size(), + }, + { + .iov_base = &Null, + .iov_len = 1, + }, }; struct msghdr msg { - .msg_name = nullptr, - .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, + .msg_name = nullptr, .msg_namelen = 0, .msg_iov = iov, .msg_iovlen = 3, }; - ssize_t Read = recvmsg(Socket, &msg, 0); - if (Read <= msg.msg_iov->iov_len) { - CurrentRead += Read; - if (CurrentRead == Data.size()) { - Data.resize(Data.size() << 1); - } - else { - // No more to read - break; - } - } - else { - if (errno == EWOULDBLOCK) { - // no error - } - else { - perror("read"); - } - break; - } + sendmsg(Socket, &msg, 0); + + CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::BasicRequest); + break; } + case FEXServerClient::PacketType::TYPE_GET_PID_FD: { + int FD = FHU::Syscalls::pidfd_open(::getpid(), 0); - size_t CurrentOffset{}; - while (CurrentOffset < CurrentRead) { - FEXServerClient::FEXServerRequestPacket *Req = reinterpret_cast(&Data[CurrentOffset]); - switch (Req->Header.Type) { - case FEXServerClient::PacketType::TYPE_KILL: - ShouldShutdown = true; - CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::BasicRequest); - break; - case FEXServerClient::PacketType::TYPE_GET_LOG_FD: { - if (Logger::LogThreadRunning()) { - int fds[2]{}; - pipe2(fds, 0); - // 0 = Read - // 1 = Write - Logger::AppendLogFD(fds[0]); + if (FD < 0) { + // Couldn't get PIDFD due to too old of kernel. + // Return a pipe to track the same information. + // + int fds[2]; + pipe2(fds, O_CLOEXEC); + SendFDSuccessPacket(Socket, fds[0]); - SendFDSuccessPacket(Socket, fds[1]); + // Close the read side now, doesn't matter to us + close(fds[0]); - // Close the write side now, doesn't matter to us - close(fds[1]); + // Check if we need to increase the FD limit. + ++NumFilesOpened; + CheckRaiseFDLimit(); - // Check if we need to increase the FD limit. - ++NumFilesOpened; - CheckRaiseFDLimit(); - } - else { - // Log thread isn't running. Let FEXInterpreter know it can't have one. - SendEmptyErrorPacket(Socket); - } + // Write side will naturally close on process exit, letting the other process know we have exited. + } else { + SendFDSuccessPacket(Socket, FD); - CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::Header); - break; - } - case FEXServerClient::PacketType::TYPE_GET_ROOTFS_PATH: { - fextl::string MountFolder = SquashFS::GetMountFolder(); - - FEXServerClient::FEXServerResultPacket Res { - .MountPath { - .Header { - .Type = FEXServerClient::PacketType::TYPE_GET_ROOTFS_PATH, - }, - .Length = MountFolder.size() + 1, - }, - }; - - char Null{}; - - iovec iov[3] { - { - .iov_base = &Res, - .iov_len = sizeof(Res), - }, - { - .iov_base = MountFolder.data(), - .iov_len = MountFolder.size(), - }, - { - .iov_base = &Null, - .iov_len = 1, - }, - }; - - struct msghdr msg { - .msg_name = nullptr, - .msg_namelen = 0, - .msg_iov = iov, - .msg_iovlen = 3, - }; - - sendmsg(Socket, &msg, 0); - - CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::BasicRequest); - break; - } - case FEXServerClient::PacketType::TYPE_GET_PID_FD: { - int FD = FHU::Syscalls::pidfd_open(::getpid(), 0); - - if (FD < 0) { - // Couldn't get PIDFD due to too old of kernel. - // Return a pipe to track the same information. - // - int fds[2]; - pipe2(fds, O_CLOEXEC); - SendFDSuccessPacket(Socket, fds[0]); - - // Close the read side now, doesn't matter to us - close(fds[0]); - - // Check if we need to increase the FD limit. - ++NumFilesOpened; - CheckRaiseFDLimit(); - - // Write side will naturally close on process exit, letting the other process know we have exited. - } - else { - SendFDSuccessPacket(Socket, FD); - - // Close the FD now since we've sent it - close(FD); - } - - CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::Header); - break; - } - // Invalid - case FEXServerClient::PacketType::TYPE_ERROR: - default: - // Something sent us an invalid packet. To ensure we don't spin infinitely, consume all the data. - LogMan::Msg::EFmt("[FEXServer] InvalidPacket size received 0x{:x} bytes", CurrentRead - CurrentOffset); - CurrentOffset = CurrentRead; - break; + // Close the FD now since we've sent it + close(FD); } + + CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::Header); + break; } - } - - void CloseConnections() { - // Close the server pipe so new processes will know to spin up a new FEXServer. - // This one is closing - close (ServerLockFD); - - // Close the server socket so no more connections can be started - close(ServerSocketFD); - } - - void WaitForRequests() { - auto LastDataTime = std::chrono::system_clock::now(); - - while (!ShouldShutdown) { - struct timespec ts{}; - ts.tv_sec = RequestTimeout; - - int Result = ppoll(&PollFDs.at(0), PollFDs.size(), &ts, nullptr); - std::vector NewPollFDs{}; - - if (Result > 0) { - // Walk the FDs and see if we got any results - for (auto it = PollFDs.begin(); it != PollFDs.end(); ) { - auto &Event = *it; - bool Erase{}; - - if (Event.revents != 0) { - if (Event.fd == ServerSocketFD) { - if (Event.revents & POLLIN) { - // If it is the listen socket then we have a new connection - struct sockaddr_storage Addr{}; - socklen_t AddrSize{}; - int NewFD = accept(ServerSocketFD, reinterpret_cast(&Addr), &AddrSize); - - // Add the new client to the temporary array - NewPollFDs.emplace_back(pollfd { - .fd = NewFD, - .events = POLLIN | POLLPRI | POLLRDHUP, - .revents = 0, - }); - } - else if (Event.revents & (POLLHUP | POLLERR | POLLNVAL)) { - // Listen socket error or shutting down - break; - } - } - else { - if (Event.revents & POLLIN) { - // Data from the socket - HandleSocketData(Event.fd); - } - - if (Event.revents & (POLLHUP | POLLERR | POLLNVAL | POLLRDHUP)) { - // Error or hangup, close the socket and erase it from our list - Erase = true; - close(Event.fd); - } - } - - Event.revents = 0; - --Result; - } - - if (Erase) { - it = PollFDs.erase(it); - } - else { - ++it; - } - - if (Result == 0) { - // Early break if we've consumed all the results - break; - } - } - - // Insert the new FDs to poll - PollFDs.insert(PollFDs.begin(), NewPollFDs.begin(), NewPollFDs.end()); - - LastDataTime = std::chrono::system_clock::now(); - } - else { - auto Now = std::chrono::system_clock::now(); - auto Diff = Now - LastDataTime; - if (Diff >= std::chrono::seconds(RequestTimeout) && - !Foreground && - PollFDs.size() == 1) { - // If we aren't running in the foreground and we have no connections after a timeout - // Then we can just go ahead and leave - ShouldShutdown = true; - LogMan::Msg::DFmt("[FEXServer] Shutting Down"); - } - } + // Invalid + case FEXServerClient::PacketType::TYPE_ERROR: + default: + // Something sent us an invalid packet. To ensure we don't spin infinitely, consume all the data. + LogMan::Msg::EFmt("[FEXServer] InvalidPacket size received 0x{:x} bytes", CurrentRead - CurrentOffset); + CurrentOffset = CurrentRead; + break; } - - CloseConnections(); - } - - void SetConfiguration(bool Foreground, uint32_t PersistentTimeout) { - ProcessPipe::Foreground = Foreground; - ProcessPipe::RequestTimeout = PersistentTimeout; - } - - void Shutdown() { - ShouldShutdown = true; } } +void CloseConnections() { + // Close the server pipe so new processes will know to spin up a new FEXServer. + // This one is closing + close(ServerLockFD); + // Close the server socket so no more connections can be started + close(ServerSocketFD); +} + +void WaitForRequests() { + auto LastDataTime = std::chrono::system_clock::now(); + + while (!ShouldShutdown) { + struct timespec ts {}; + ts.tv_sec = RequestTimeout; + + int Result = ppoll(&PollFDs.at(0), PollFDs.size(), &ts, nullptr); + std::vector NewPollFDs {}; + + if (Result > 0) { + // Walk the FDs and see if we got any results + for (auto it = PollFDs.begin(); it != PollFDs.end();) { + auto& Event = *it; + bool Erase {}; + + if (Event.revents != 0) { + if (Event.fd == ServerSocketFD) { + if (Event.revents & POLLIN) { + // If it is the listen socket then we have a new connection + struct sockaddr_storage Addr {}; + socklen_t AddrSize {}; + int NewFD = accept(ServerSocketFD, reinterpret_cast(&Addr), &AddrSize); + + // Add the new client to the temporary array + NewPollFDs.emplace_back(pollfd { + .fd = NewFD, + .events = POLLIN | POLLPRI | POLLRDHUP, + .revents = 0, + }); + } else if (Event.revents & (POLLHUP | POLLERR | POLLNVAL)) { + // Listen socket error or shutting down + break; + } + } else { + if (Event.revents & POLLIN) { + // Data from the socket + HandleSocketData(Event.fd); + } + + if (Event.revents & (POLLHUP | POLLERR | POLLNVAL | POLLRDHUP)) { + // Error or hangup, close the socket and erase it from our list + Erase = true; + close(Event.fd); + } + } + + Event.revents = 0; + --Result; + } + + if (Erase) { + it = PollFDs.erase(it); + } else { + ++it; + } + + if (Result == 0) { + // Early break if we've consumed all the results + break; + } + } + + // Insert the new FDs to poll + PollFDs.insert(PollFDs.begin(), NewPollFDs.begin(), NewPollFDs.end()); + + LastDataTime = std::chrono::system_clock::now(); + } else { + auto Now = std::chrono::system_clock::now(); + auto Diff = Now - LastDataTime; + if (Diff >= std::chrono::seconds(RequestTimeout) && !Foreground && PollFDs.size() == 1) { + // If we aren't running in the foreground and we have no connections after a timeout + // Then we can just go ahead and leave + ShouldShutdown = true; + LogMan::Msg::DFmt("[FEXServer] Shutting Down"); + } + } + } + + CloseConnections(); +} + +void SetConfiguration(bool Foreground, uint32_t PersistentTimeout) { + ProcessPipe::Foreground = Foreground; + ProcessPipe::RequestTimeout = PersistentTimeout; +} + +void Shutdown() { + ShouldShutdown = true; +} +} // namespace ProcessPipe diff --git a/Source/Tools/FEXServer/ProcessPipe.h b/Source/Tools/FEXServer/ProcessPipe.h index f8900ae36..5c3f4c9b5 100644 --- a/Source/Tools/FEXServer/ProcessPipe.h +++ b/Source/Tools/FEXServer/ProcessPipe.h @@ -3,9 +3,9 @@ #include namespace ProcessPipe { - bool InitializeServerPipe(); - bool InitializeServerSocket(); - void WaitForRequests(); - void SetConfiguration(bool Foreground, uint32_t PersistentTimeout); - void Shutdown(); -} +bool InitializeServerPipe(); +bool InitializeServerSocket(); +void WaitForRequests(); +void SetConfiguration(bool Foreground, uint32_t PersistentTimeout); +void Shutdown(); +} // namespace ProcessPipe diff --git a/Source/Tools/FEXServer/SquashFS.cpp b/Source/Tools/FEXServer/SquashFS.cpp index 430ad3883..62e976c29 100644 --- a/Source/Tools/FEXServer/SquashFS.cpp +++ b/Source/Tools/FEXServer/SquashFS.cpp @@ -14,59 +14,28 @@ namespace SquashFS { - constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; - int ServerRootFSLockFD {-1}; - int FuseMountPID{}; - fextl::string MountFolder{}; +constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; +int ServerRootFSLockFD {-1}; +int FuseMountPID {}; +fextl::string MountFolder {}; - void ShutdownImagePID() { - if (FuseMountPID) { - FHU::Syscalls::tgkill(FuseMountPID, FuseMountPID, SIGINT); - } +void ShutdownImagePID() { + if (FuseMountPID) { + FHU::Syscalls::tgkill(FuseMountPID, FuseMountPID, SIGINT); } +} - bool InitializeSquashFSPipe() { - auto RootFSLockFile = FEXServerClient::GetServerRootFSLockFile(); +bool InitializeSquashFSPipe() { + auto RootFSLockFile = FEXServerClient::GetServerRootFSLockFile(); - int Ret = open(RootFSLockFile.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_EXCL | O_CLOEXEC, USER_PERMS); - ServerRootFSLockFD = Ret; - if (Ret == -1 && errno == EEXIST) { - // If the fifo exists then it might be a stale connection. - // Check the lock status to see if another process is still alive. - ServerRootFSLockFD = open(RootFSLockFile.c_str(), O_RDWR | O_CLOEXEC, USER_PERMS); - if (ServerRootFSLockFD != -1) { - // Now that we have opened the file, try to get a write lock. - flock lk { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; - Ret = fcntl(ServerRootFSLockFD, F_SETLK, &lk); - - if (Ret != -1) { - // Write lock was gained, we can now continue onward. - } - else { - // We couldn't get a write lock, this means that another process already owns a lock on the fifo - close(ServerRootFSLockFD); - ServerRootFSLockFD = -1; - return false; - } - } - else { - // File couldn't get opened even though it existed? - // Must have raced something here. - return false; - } - } - else if (Ret == -1) { - // Unhandled error. - LogMan::Msg::EFmt("[FEXServer] Unable to create FEXServer RootFS lock file at: {} {} {}", RootFSLockFile, errno, strerror(errno)); - return false; - } - else { - // FIFO file was created. Try to get a write lock + int Ret = open(RootFSLockFile.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_EXCL | O_CLOEXEC, USER_PERMS); + ServerRootFSLockFD = Ret; + if (Ret == -1 && errno == EEXIST) { + // If the fifo exists then it might be a stale connection. + // Check the lock status to see if another process is still alive. + ServerRootFSLockFD = open(RootFSLockFile.c_str(), O_RDWR | O_CLOEXEC, USER_PERMS); + if (ServerRootFSLockFD != -1) { + // Now that we have opened the file, try to get a write lock. flock lk { .l_type = F_WRLCK, .l_whence = SEEK_SET, @@ -75,201 +44,228 @@ namespace SquashFS { }; Ret = fcntl(ServerRootFSLockFD, F_SETLK, &lk); - if (Ret == -1) { - // Couldn't get a write lock, something else must have got it + if (Ret != -1) { + // Write lock was gained, we can now continue onward. + } else { + // We couldn't get a write lock, this means that another process already owns a lock on the fifo close(ServerRootFSLockFD); ServerRootFSLockFD = -1; return false; } + } else { + // File couldn't get opened even though it existed? + // Must have raced something here. + return false; } - - return true; - } - - bool DowngradeRootFSPipeToReadLock() { + } else if (Ret == -1) { + // Unhandled error. + LogMan::Msg::EFmt("[FEXServer] Unable to create FEXServer RootFS lock file at: {} {} {}", RootFSLockFile, errno, strerror(errno)); + return false; + } else { + // FIFO file was created. Try to get a write lock flock lk { - .l_type = F_RDLCK, + .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 0, }; - int Ret = fcntl(ServerRootFSLockFD, F_SETLK, &lk); + Ret = fcntl(ServerRootFSLockFD, F_SETLK, &lk); if (Ret == -1) { - // This shouldn't occur - LogMan::Msg::EFmt("[FEXServer] Unable to downgrade a rootfs write lock to a read lock {} {}", errno, strerror(errno)); + // Couldn't get a write lock, something else must have got it close(ServerRootFSLockFD); ServerRootFSLockFD = -1; return false; } - - return true; } - bool MountRootFSImagePath(const fextl::string &SquashFS, bool EroFS) { - pid_t ParentTID = ::getpid(); - MountFolder = fmt::format("{}/.FEXMount{}-XXXXXX", FEXServerClient::GetServerMountFolder(), ParentTID); - char *MountFolderStr = MountFolder.data(); + return true; +} - // Make the temporary mount folder - if (mkdtemp(MountFolderStr) == nullptr) { - LogMan::Msg::EFmt("[FEXServer] Couldn't create temporary mount name: {}", MountFolder); - return false; +bool DowngradeRootFSPipeToReadLock() { + flock lk { + .l_type = F_RDLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + int Ret = fcntl(ServerRootFSLockFD, F_SETLK, &lk); + + if (Ret == -1) { + // This shouldn't occur + LogMan::Msg::EFmt("[FEXServer] Unable to downgrade a rootfs write lock to a read lock {} {}", errno, strerror(errno)); + close(ServerRootFSLockFD); + ServerRootFSLockFD = -1; + return false; + } + + return true; +} + +bool MountRootFSImagePath(const fextl::string& SquashFS, bool EroFS) { + pid_t ParentTID = ::getpid(); + MountFolder = fmt::format("{}/.FEXMount{}-XXXXXX", FEXServerClient::GetServerMountFolder(), ParentTID); + char* MountFolderStr = MountFolder.data(); + + // Make the temporary mount folder + if (mkdtemp(MountFolderStr) == nullptr) { + LogMan::Msg::EFmt("[FEXServer] Couldn't create temporary mount name: {}", MountFolder); + return false; + } + + // Change the permissions + if (chmod(MountFolderStr, 0777) != 0) { + LogMan::Msg::EFmt("[FEXServer] Couldn't change permissions on temporary mount: {}", MountFolder); + rmdir(MountFolderStr); + return false; + } + + // Create local FDs so our internal forks can communicate + int fds[2]; + pipe2(fds, 0); + + int pid = fork(); + if (pid == 0) { + // Child + close(fds[0]); // Close read side + const char* argv[4]; + argv[0] = EroFS ? "erofsfuse" : "squashfuse"; + argv[1] = SquashFS.c_str(); + argv[2] = MountFolder.c_str(); + argv[3] = nullptr; + + // Try and execute {erofsfuse, squashfuse} to mount our rootfs + if (execvpe(argv[0], (char* const*)argv, environ) == -1) { + // Give a hopefully helpful error message for users + LogMan::Msg::EFmt("[FEXServer] '{}' Couldn't execute for some reason: {} {}\n", argv[0], errno, strerror(errno)); + LogMan::Msg::EFmt("[FEXServer] To mount squashfs rootfs files you need {} installed\n", argv[0]); + LogMan::Msg::EFmt("[FEXServer] Check your FUSE setup.\n"); + + // Let the parent know that we couldn't execute for some reason + uint64_t error {1}; + write(fds[1], &error, sizeof(error)); + + // End the child + exit(1); } + } else { + FuseMountPID = pid; + // Parent + // Wait for the child to exit + // This will happen with execvpe of squashmount or exit on failure + while (waitpid(pid, nullptr, 0) == -1 && errno == EINTR) + ; - // Change the permissions - if (chmod(MountFolderStr, 0777) != 0) { - LogMan::Msg::EFmt("[FEXServer] Couldn't change permissions on temporary mount: {}", MountFolder); + // Check the child pipe for messages + pollfd PollFD; + PollFD.fd = fds[0]; + PollFD.events = POLLIN; + + int Result = poll(&PollFD, 1, 0); + + if (Result == 1 && PollFD.revents & POLLIN) { + // Child couldn't execvpe for whatever reason + // Remove the mount path and leave Just in case it was created rmdir(MountFolderStr); - return false; - } - - // Create local FDs so our internal forks can communicate - int fds[2]; - pipe2(fds, 0); - - int pid = fork(); - if (pid == 0) { - // Child - close(fds[0]); // Close read side - const char *argv[4]; - argv[0] = EroFS ? "erofsfuse" : "squashfuse"; - argv[1] = SquashFS.c_str(); - argv[2] = MountFolder.c_str(); - argv[3] = nullptr; - - // Try and execute {erofsfuse, squashfuse} to mount our rootfs - if (execvpe(argv[0], (char * const*)argv, environ) == -1) { - // Give a hopefully helpful error message for users - LogMan::Msg::EFmt("[FEXServer] '{}' Couldn't execute for some reason: {} {}\n", argv[0], errno, strerror(errno)); - LogMan::Msg::EFmt("[FEXServer] To mount squashfs rootfs files you need {} installed\n", argv[0]); - LogMan::Msg::EFmt("[FEXServer] Check your FUSE setup.\n"); - - // Let the parent know that we couldn't execute for some reason - uint64_t error{1}; - write(fds[1], &error, sizeof(error)); - - // End the child - exit(1); - } - } - else { - FuseMountPID = pid; - // Parent - // Wait for the child to exit - // This will happen with execvpe of squashmount or exit on failure - while (waitpid(pid, nullptr, 0) == -1 && errno == EINTR); - - // Check the child pipe for messages - pollfd PollFD; - PollFD.fd = fds[0]; - PollFD.events = POLLIN; - - int Result = poll(&PollFD, 1, 0); - - if (Result == 1 && PollFD.revents & POLLIN) { - // Child couldn't execvpe for whatever reason - // Remove the mount path and leave Just in case it was created - rmdir(MountFolderStr); - - // Close the pipe now - close(fds[0]); - - LogMan::Msg::EFmt("[FEXServer] Couldn't mount squashfs\n"); - return false; - } // Close the pipe now close(fds[0]); - } - // Write to the lock file where we are mounted - write(ServerRootFSLockFD, MountFolder.c_str(), MountFolder.size()); - fdatasync(ServerRootFSLockFD); - - return true; - } - - void UnmountRootFS() { - FEX_CONFIG_OPT(LDPath, ROOTFS); - if (!FEX::FormatCheck::IsSquashFS(LDPath()) && !FEX::FormatCheck::IsEroFS(LDPath())) { - return; - } - - SquashFS::ShutdownImagePID(); - - // Handle final mount removal - // fusermount for unmounting the mountpoint, then the {erfsfuse, squashfuse} will exit automatically - int pid = fork(); - - if (pid == 0) { - const char *argv[5]; - argv[0] = "fusermount"; - argv[1] = "-u"; - argv[2] = "-q"; - argv[3] = MountFolder.c_str(); - argv[4] = nullptr; - - if (execvp(argv[0], (char * const*)argv) == -1) { - fprintf(stderr, "fusermount failed to execute. You may have an mount living at '%s' to clean up now\n", MountFolder.c_str()); - fprintf(stderr, "Try `%s %s %s %s`\n", argv[0], argv[1], argv[2], argv[3]); - exit(1); - } - } - else { - // Wait for fusermount to leave - while (waitpid(pid, nullptr, 0) == -1 && errno == EINTR); - - // Remove the mount path - rmdir(MountFolder.c_str()); - - // Remove the rootfs lock file - auto RootFSLockFile = FEXServerClient::GetServerRootFSLockFile(); - unlink(RootFSLockFile.c_str()); - } - } - - bool InitializeSquashFS() { - FEX_CONFIG_OPT(LDPath, ROOTFS); - - MountFolder = LDPath(); - - bool IsSquashFS {false}; - bool IsEroFS {false}; - - // Check if the image is an EroFS - IsEroFS = FEX::FormatCheck::IsEroFS(MountFolder); - - if (!IsEroFS) { - // Check if the image is an SquashFS - IsSquashFS = FEX::FormatCheck::IsSquashFS(MountFolder); - } - - if (!IsSquashFS && !IsEroFS) { - // If this isn't a rootfs image then we have nothing to do here - return true; - } - - if (!InitializeSquashFSPipe()) { - LogMan::Msg::EFmt("[FEXServer] Couldn't initialize SquashFSPipe"); + LogMan::Msg::EFmt("[FEXServer] Couldn't mount squashfs\n"); return false; } - // Setup rootfs here - if (!MountRootFSImagePath(LDPath(), IsEroFS)) { - LogMan::Msg::EFmt("[FEXServer] Couldn't mount squashfs path"); - return false; - } - - if (!DowngradeRootFSPipeToReadLock()) { - LogMan::Msg::EFmt("[FEXServer] Couldn't downgrade read lock"); - return false; - } - - return true; + // Close the pipe now + close(fds[0]); } - fextl::string GetMountFolder() { - return MountFolder; + // Write to the lock file where we are mounted + write(ServerRootFSLockFD, MountFolder.c_str(), MountFolder.size()); + fdatasync(ServerRootFSLockFD); + + return true; +} + +void UnmountRootFS() { + FEX_CONFIG_OPT(LDPath, ROOTFS); + if (!FEX::FormatCheck::IsSquashFS(LDPath()) && !FEX::FormatCheck::IsEroFS(LDPath())) { + return; + } + + SquashFS::ShutdownImagePID(); + + // Handle final mount removal + // fusermount for unmounting the mountpoint, then the {erfsfuse, squashfuse} will exit automatically + int pid = fork(); + + if (pid == 0) { + const char* argv[5]; + argv[0] = "fusermount"; + argv[1] = "-u"; + argv[2] = "-q"; + argv[3] = MountFolder.c_str(); + argv[4] = nullptr; + + if (execvp(argv[0], (char* const*)argv) == -1) { + fprintf(stderr, "fusermount failed to execute. You may have an mount living at '%s' to clean up now\n", MountFolder.c_str()); + fprintf(stderr, "Try `%s %s %s %s`\n", argv[0], argv[1], argv[2], argv[3]); + exit(1); + } + } else { + // Wait for fusermount to leave + while (waitpid(pid, nullptr, 0) == -1 && errno == EINTR) + ; + + // Remove the mount path + rmdir(MountFolder.c_str()); + + // Remove the rootfs lock file + auto RootFSLockFile = FEXServerClient::GetServerRootFSLockFile(); + unlink(RootFSLockFile.c_str()); } } + +bool InitializeSquashFS() { + FEX_CONFIG_OPT(LDPath, ROOTFS); + + MountFolder = LDPath(); + + bool IsSquashFS {false}; + bool IsEroFS {false}; + + // Check if the image is an EroFS + IsEroFS = FEX::FormatCheck::IsEroFS(MountFolder); + + if (!IsEroFS) { + // Check if the image is an SquashFS + IsSquashFS = FEX::FormatCheck::IsSquashFS(MountFolder); + } + + if (!IsSquashFS && !IsEroFS) { + // If this isn't a rootfs image then we have nothing to do here + return true; + } + + if (!InitializeSquashFSPipe()) { + LogMan::Msg::EFmt("[FEXServer] Couldn't initialize SquashFSPipe"); + return false; + } + + // Setup rootfs here + if (!MountRootFSImagePath(LDPath(), IsEroFS)) { + LogMan::Msg::EFmt("[FEXServer] Couldn't mount squashfs path"); + return false; + } + + if (!DowngradeRootFSPipeToReadLock()) { + LogMan::Msg::EFmt("[FEXServer] Couldn't downgrade read lock"); + return false; + } + + return true; +} + +fextl::string GetMountFolder() { + return MountFolder; +} +} // namespace SquashFS diff --git a/Source/Tools/FEXServer/SquashFS.h b/Source/Tools/FEXServer/SquashFS.h index 8d3cf0c9a..b349846d4 100644 --- a/Source/Tools/FEXServer/SquashFS.h +++ b/Source/Tools/FEXServer/SquashFS.h @@ -3,7 +3,7 @@ #include namespace SquashFS { - bool InitializeSquashFS(); - void UnmountRootFS(); - fextl::string GetMountFolder(); -} +bool InitializeSquashFS(); +void UnmountRootFS(); +fextl::string GetMountFolder(); +} // namespace SquashFS diff --git a/Source/Tools/LinuxEmulation/ArchHelpers/MContext.h b/Source/Tools/LinuxEmulation/ArchHelpers/MContext.h index 84846d1f4..9dbaf625f 100644 --- a/Source/Tools/LinuxEmulation/ArchHelpers/MContext.h +++ b/Source/Tools/LinuxEmulation/ArchHelpers/MContext.h @@ -147,7 +147,7 @@ static inline uint64_t GetArmPState(void* ucontext) { return GetMContext(ucontext)->pstate; } -static inline uint64_t *GetArmGPRs(void* ucontext) { +static inline uint64_t* GetArmGPRs(void* ucontext) { return reinterpret_cast(GetMContext(ucontext)->regs); } @@ -157,7 +157,7 @@ static inline void SetArmReg(void* ucontext, uint32_t id, uint64_t val) { static inline __uint128_t GetArmFPR(void* ucontext, uint32_t id) { auto MContext = GetMContext(ucontext); - HostFPRState *HostState = reinterpret_cast(&MContext->__reserved[0]); + HostFPRState* HostState = reinterpret_cast(&MContext->__reserved[0]); LOGMAN_THROW_AA_FMT(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x{:08x}", HostState->Head.Magic); return HostState->FPRs[id]; @@ -203,7 +203,7 @@ static inline uint32_t GetProtectFlags(void* ucontext) { uint64_t ESR = GetArmESR(ucontext); LOGMAN_THROW_A_FMT((ESR & ESR1_EC) == ESR1_EC_DataAbort, "Unknown ESR1 EC type: 0x{:x} != 0x{:x}", ESR & ESR1_EC, ESR1_EC_DataAbort); - uint32_t ProtectFlags{}; + uint32_t ProtectFlags {}; if ((ESR & ESR1_DataAbort_Level) == ESR1_DataAbort_Level_EL0) { // Always a user error for us. ProtectFlags |= FEXCore::X86State::X86_PF_USER; @@ -219,8 +219,8 @@ static inline uint32_t GetProtectFlags(void* ucontext) { } using ContextBackup = ArmContextBackup; -template -static inline void BackupContext(void* ucontext, T *Backup) { +template +static inline void BackupContext(void* ucontext, T* Backup) { if constexpr (std::is_same::value) { auto _ucontext = GetUContext(ucontext); auto _mcontext = GetMContext(ucontext); @@ -231,7 +231,7 @@ static inline void BackupContext(void* ucontext, T *Backup) { Backup->PState = _mcontext->pstate; // Host FPR state starts at _mcontext->reserved[0]; - HostFPRState *HostState = reinterpret_cast(&_mcontext->__reserved[0]); + HostFPRState* HostState = reinterpret_cast(&_mcontext->__reserved[0]); LOGMAN_THROW_AA_FMT(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x{:08x}", HostState->Head.Magic); Backup->FPSR = HostState->FPSR; Backup->FPCR = HostState->FPCR; @@ -249,15 +249,15 @@ static inline void BackupContext(void* ucontext, T *Backup) { } } -template -static inline void RestoreContext(void* ucontext, T *Backup) { +template +static inline void RestoreContext(void* ucontext, T* Backup) { if constexpr (std::is_same::value) { LOGMAN_THROW_A_FMT(Backup->StackCookie == STACK_COOKIE_MAGIC, "Stack cookie didn't match! 0x{:x}", Backup->StackCookie); auto _ucontext = GetUContext(ucontext); auto _mcontext = GetMContext(ucontext); - HostFPRState *HostState = reinterpret_cast(&_mcontext->__reserved[0]); + HostFPRState* HostState = reinterpret_cast(&_mcontext->__reserved[0]); LOGMAN_THROW_AA_FMT(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x{:08x}", HostState->Head.Magic); memcpy(&HostState->FPRs[0], &Backup->FPRs[0], 32 * sizeof(__uint128_t)); HostState->FPCR = Backup->FPCR; @@ -287,7 +287,7 @@ static inline uint64_t GetSp(void* ucontext) { static inline uint64_t GetPc(void* ucontext) { return GetMContext(ucontext)->gregs[REG_RIP]; - } +} static inline void SetSp(void* ucontext, uint64_t val) { GetMContext(ucontext)->gregs[REG_RSP] = val; @@ -321,7 +321,7 @@ static inline uint64_t GetArmPState(void* ucontext) { ERROR_AND_DIE_FMT("Not implemented for x86 host"); } -static inline uint64_t *GetArmGPRs(void* ucontext) { +static inline uint64_t* GetArmGPRs(void* ucontext) { ERROR_AND_DIE_FMT("Not implemented for x86 host"); } @@ -330,8 +330,8 @@ static inline uint32_t GetProtectFlags(void* ucontext) { } using ContextBackup = X86ContextBackup; -template -static inline void BackupContext(void* ucontext, T *Backup) { +template +static inline void BackupContext(void* ucontext, T* Backup) { if constexpr (std::is_same::value) { auto _ucontext = GetUContext(ucontext); auto _mcontext = GetMContext(ucontext); @@ -354,8 +354,8 @@ static inline void BackupContext(void* ucontext, T *Backup) { } } -template -static inline void RestoreContext(void* ucontext, T *Backup) { +template +static inline void RestoreContext(void* ucontext, T* Backup) { if constexpr (std::is_same::value) { LOGMAN_THROW_A_FMT(Backup->StackCookie == STACK_COOKIE_MAGIC, "Stack cookie didn't match! 0x{:x}", Backup->StackCookie); @@ -379,4 +379,4 @@ static inline void RestoreContext(void* ucontext, T *Backup) { #else #endif -} // namespace FEXCore::ArchHelpers::Context +} // namespace FEX::ArchHelpers::Context diff --git a/Source/Tools/LinuxEmulation/ArchHelpers/UContext.h b/Source/Tools/LinuxEmulation/ArchHelpers/UContext.h index 89bd25557..7cccecfe4 100644 --- a/Source/Tools/LinuxEmulation/ArchHelpers/UContext.h +++ b/Source/Tools/LinuxEmulation/ArchHelpers/UContext.h @@ -10,421 +10,421 @@ #include namespace FEXCore { - namespace x86_64 { - // uc_flags flags - ///< Has extended FP state - constexpr uint64_t UC_FP_XSTATE = (1ULL << 0); - ///< Set when kernel saves SS register from 64bit code - constexpr uint64_t UC_SIGCONTEXT_SS = (1ULL << 1); - ///< Set when kernel will strictly restore the SS - constexpr uint64_t UC_STRICT_RESTORE_SS = (1ULL << 2); +namespace x86_64 { + // uc_flags flags + ///< Has extended FP state + constexpr uint64_t UC_FP_XSTATE = (1ULL << 0); + ///< Set when kernel saves SS register from 64bit code + constexpr uint64_t UC_SIGCONTEXT_SS = (1ULL << 1); + ///< Set when kernel will strictly restore the SS + constexpr uint64_t UC_STRICT_RESTORE_SS = (1ULL << 2); - ///< Describes the signal stack - struct FEX_PACKED stack_t { - void *ss_sp; - int32_t ss_flags; - uint32_t : 32; - size_t ss_size; - }; - static_assert(sizeof(FEXCore::x86_64::stack_t) == 24, "This needs to be the right size"); + ///< Describes the signal stack + struct FEX_PACKED stack_t { + void* ss_sp; + int32_t ss_flags; + uint32_t : 32; + size_t ss_size; + }; + static_assert(sizeof(FEXCore::x86_64::stack_t) == 24, "This needs to be the right size"); - /** - * Describes the software specific bytes added at the end of the - * fpstate to identify whether or not an extended context area is - * present and what kind of extended features are present in said - * context area. - */ - struct FEX_PACKED fpx_sw_bytes { - static constexpr uint32_t FP_XSTATE_MAGIC = 0x46505853; + /** + * Describes the software specific bytes added at the end of the + * fpstate to identify whether or not an extended context area is + * present and what kind of extended features are present in said + * context area. + */ + struct FEX_PACKED fpx_sw_bytes { + static constexpr uint32_t FP_XSTATE_MAGIC = 0x46505853; - enum FeatureFlag : uint32_t { - FEATURE_FP = 1U << 0, - FEATURE_SSE = 1U << 1, - FEATURE_YMM = 1U << 2, - FEATURE_BNDREGS = 1U << 3, - FEATURE_BNDCSR = 1U << 4, - FEATURE_OPMASK = 1U << 5, - FEATURE_ZMM_Hi256 = 1U << 6, - FEATURE_Hi16_ZMM = 1U << 7, - FEATURE_PT_UNIMPL = 1U << 8, - FEATURE_PKRU = 1U << 9, - FEATURE_PASID = 1U << 10, - FEATURE_RESERVED11 = 1U << 11, - FEATURE_RESERVED12 = 1U << 12, - FEATURE_RESERVED13 = 1U << 13, - FEATURE_RESERVED14 = 1U << 14, - FEATURE_LBR = 1U << 15, - FEATURE_RESERVED16 = 1U << 16, - FEATURE_XTILE_CFG = 1U << 17, - FEATURE_XTILE_DATA = 1U << 18, - }; - - bool HasExtendedContext() const { - return magic1 == FP_XSTATE_MAGIC; - } - - bool HasYMMH() const { - return (xfeatures & FEATURE_YMM) != 0; - } - - // If magic1 is set to FP_XSTATE_MAGIC, then the encompassing - // frame is an xstate frame. If 0, then it's a legacy frame. - uint32_t magic1; - - // Total size of the fpstate area - // - magic1 = 0 -> sizeof(fpstate) - // - magic1 = FP_XSTATE_MAGIC -> sizeof(xstate) + extensions (if any) - uint32_t extended_size; - - // Feature bitmask describing supported features. - uint64_t xfeatures; - - // Actual XSAVE state size, based on above xfeatures - uint32_t xstate_size; - - // Reserved data - uint32_t padding[7]; - }; - static_assert(sizeof(fpx_sw_bytes) == 48); - - struct FEX_PACKED _libc_fpstate { - // This is in FXSAVE format - uint16_t fcw; - uint16_t fsw; - uint16_t ftw; - uint16_t fop; - uint64_t fip; - uint64_t fdp; - uint32_t mxcsr; - uint32_t mxcsr_mask; - __uint128_t _st[8]; - __uint128_t _xmm[16]; - uint32_t _res[12]; - - // Linux uses 12 of the bytes relegated for software purposes - // to store info describing any existing XSAVE context data. - fpx_sw_bytes sw_reserved; - }; - static_assert(sizeof(FEXCore::x86_64::_libc_fpstate) == 512, "This needs to be the right size"); - - struct FEX_PACKED xstate_header { - uint64_t xfeatures; - uint64_t reserved1[2]; - uint64_t reserved2[5]; - }; - static_assert(sizeof(xstate_header) == 64); - - struct FEX_PACKED ymmh_state { - __uint128_t ymmh_space[16]; - }; - static_assert(sizeof(ymmh_state) == 256); - - /** - * Extended state that includes both the main fpstate - * and the extended state. - */ - struct FEX_PACKED xstate { - _libc_fpstate fpstate; - xstate_header xstate_hdr; - ymmh_state ymmh; - }; - static_assert(sizeof(xstate) == 832); - - ///< The order of these must match the GNU ordering - enum ContextRegs { - FEX_REG_R8 = 0, - FEX_REG_R9, - FEX_REG_R10, - FEX_REG_R11, - FEX_REG_R12, - FEX_REG_R13, - FEX_REG_R14, - FEX_REG_R15, - FEX_REG_RDI, - FEX_REG_RSI, - FEX_REG_RBP, - FEX_REG_RBX, - FEX_REG_RDX, - FEX_REG_RAX, - FEX_REG_RCX, - FEX_REG_RSP, - FEX_REG_RIP, - FEX_REG_EFL, - FEX_REG_CSGSFS, - FEX_REG_ERR, - FEX_REG_TRAPNO, - FEX_REG_OLDMASK, - FEX_REG_CR2, - }; - static_assert(FEX_REG_CR2 == 22, "Oops"); - - struct FEX_PACKED mcontext_t { - uint64_t gregs[23]; - FEXCore::x86_64::_libc_fpstate *fpregs; - uint64_t __reserved[8]; - }; - static_assert(sizeof(FEXCore::x86_64::mcontext_t) == 256, "This needs to be the right size"); - - struct FEX_PACKED sigset_t { - uint64_t val[16]; - }; - static_assert(sizeof(FEXCore::x86_64::sigset_t) == 128, "This needs to be the right size"); - - struct FEX_PACKED ucontext_t { - uint64_t uc_flags; - FEXCore::x86_64::ucontext_t *uc_link; - FEXCore::x86_64::stack_t uc_stack; - FEXCore::x86_64::mcontext_t uc_mcontext; - FEXCore::x86_64::sigset_t uc_sigmask; - }; - static_assert(offsetof(FEXCore::x86_64::ucontext_t, uc_mcontext) == 40, "Needs to be correct"); - - static_assert(sizeof(FEXCore::x86_64::ucontext_t) == 424, "This needs to be the right size"); - } - - namespace x86 { - // uc_flags flags - ///< Has extended FP state - constexpr uint64_t UC_FP_XSTATE = (1ULL << 0); - - ///< The order of these must match the GNU ordering - enum ContextRegs { - FEX_REG_GS = 0, - FEX_REG_FS, - FEX_REG_ES, - FEX_REG_DS, - FEX_REG_RDI, - FEX_REG_RSI, - FEX_REG_RBP, - FEX_REG_RSP, - FEX_REG_RBX, - FEX_REG_RDX, - FEX_REG_RCX, - FEX_REG_RAX, - FEX_REG_TRAPNO, - FEX_REG_ERR, - FEX_REG_EIP, - FEX_REG_CS, - FEX_REG_EFL, - FEX_REG_UESP, - FEX_REG_SS - }; - static_assert(FEX_REG_SS == 18, "Oops"); - - union sigval_t { - int sival_int; - uint32_t sival_ptr; // XXX: Should be compat_ptr + enum FeatureFlag : uint32_t { + FEATURE_FP = 1U << 0, + FEATURE_SSE = 1U << 1, + FEATURE_YMM = 1U << 2, + FEATURE_BNDREGS = 1U << 3, + FEATURE_BNDCSR = 1U << 4, + FEATURE_OPMASK = 1U << 5, + FEATURE_ZMM_Hi256 = 1U << 6, + FEATURE_Hi16_ZMM = 1U << 7, + FEATURE_PT_UNIMPL = 1U << 8, + FEATURE_PKRU = 1U << 9, + FEATURE_PASID = 1U << 10, + FEATURE_RESERVED11 = 1U << 11, + FEATURE_RESERVED12 = 1U << 12, + FEATURE_RESERVED13 = 1U << 13, + FEATURE_RESERVED14 = 1U << 14, + FEATURE_LBR = 1U << 15, + FEATURE_RESERVED16 = 1U << 16, + FEATURE_XTILE_CFG = 1U << 17, + FEATURE_XTILE_DATA = 1U << 18, }; - struct FEX_PACKED siginfo_t { - int si_signo; - int si_errno; - int si_code; - union { - uint32_t pad[29]; - /* tgkill siginfo_t */ - struct { - int32_t pid; - int32_t uid; - } _kill; - /* SIGPOLL */ - struct { - int32_t band; - int32_t fd; - } _poll; - /* SIGILL, SIGFPE, SIGSEGV, SIBUS */ - struct { - uint32_t addr; - } _sigfault; - /* SIGCHLD */ - struct { - int32_t pid; - int32_t uid; - int32_t status; - int32_t utime; - int32_t stime; - } _sigchld; - /* RT signals */ - struct { - int32_t pid; - int32_t uid; - union { - int32_t sival_int; - uint32_t sival_ptr; // compat_ptr - } sigval; - } _rt; - /* SIGALRM, SIGVTALRM */ - struct { - int tid; - int overrun; - FEXCore::x86::sigval_t sigval; - } _timer; - /* SIGSYS */ - struct { - uint32_t call_addr; // compat_ptr - int32_t syscall; - uint32_t arch; - } _sigsys; - } _sifields; + bool HasExtendedContext() const { + return magic1 == FP_XSTATE_MAGIC; + } - union HostSigInfo_t { - // This anonymous struct needs to match the host definition - struct { - uint32_t si_signo; - uint32_t si_errno; - uint32_t si_code; + bool HasYMMH() const { + return (xfeatures & FEATURE_YMM) != 0; + } - uint32_t __pad0; + // If magic1 is set to FP_XSTATE_MAGIC, then the encompassing + // frame is an xstate frame. If 0, then it's a legacy frame. + uint32_t magic1; - // Pad[28] is a union for all the sifields - uint32_t _pad[28]; - } FEXDef; - ::siginfo_t host{}; - }; - static_assert(sizeof(HostSigInfo_t) == 128, "This needs to be the right size"); + // Total size of the fpstate area + // - magic1 = 0 -> sizeof(fpstate) + // - magic1 = FP_XSTATE_MAGIC -> sizeof(xstate) + extensions (if any) + uint32_t extended_size; - siginfo_t() = delete; + // Feature bitmask describing supported features. + uint64_t xfeatures; - operator ::siginfo_t() const { - // The definition of siginfo_t changes depending on the host environment - // It is guaranteed to be 128 bytes and the kernel interface is the same for all of them - // Since we only run on Linux - HostSigInfo_t val{}; + // Actual XSAVE state size, based on above xfeatures + uint32_t xstate_size; - val.FEXDef.si_signo = si_signo; - val.FEXDef.si_errno = si_errno; - val.FEXDef.si_code = si_code; + // Reserved data + uint32_t padding[7]; + }; + static_assert(sizeof(fpx_sw_bytes) == 48); - // Host siginfo has a pad member that is set to zeros - val.FEXDef.__pad0 = 0; + struct FEX_PACKED _libc_fpstate { + // This is in FXSAVE format + uint16_t fcw; + uint16_t fsw; + uint16_t ftw; + uint16_t fop; + uint64_t fip; + uint64_t fdp; + uint32_t mxcsr; + uint32_t mxcsr_mask; + __uint128_t _st[8]; + __uint128_t _xmm[16]; + uint32_t _res[12]; - // Copy over the union - // The union is different sizes on 64-bit versus 32-bit - memcpy(val.FEXDef._pad, _sifields.pad, std::min(sizeof(val.FEXDef._pad), sizeof(_sifields.pad))); + // Linux uses 12 of the bytes relegated for software purposes + // to store info describing any existing XSAVE context data. + fpx_sw_bytes sw_reserved; + }; + static_assert(sizeof(FEXCore::x86_64::_libc_fpstate) == 512, "This needs to be the right size"); - return val.host; - } + struct FEX_PACKED xstate_header { + uint64_t xfeatures; + uint64_t reserved1[2]; + uint64_t reserved2[5]; + }; + static_assert(sizeof(xstate_header) == 64); - siginfo_t(::siginfo_t val) { - HostSigInfo_t host; - host.host = val; + struct FEX_PACKED ymmh_state { + __uint128_t ymmh_space[16]; + }; + static_assert(sizeof(ymmh_state) == 256); - si_signo = host.FEXDef.si_signo; - si_errno = host.FEXDef.si_errno; - si_code = host.FEXDef.si_code; + /** + * Extended state that includes both the main fpstate + * and the extended state. + */ + struct FEX_PACKED xstate { + _libc_fpstate fpstate; + xstate_header xstate_hdr; + ymmh_state ymmh; + }; + static_assert(sizeof(xstate) == 832); - // Copy over the union - // The union is different sizes on 64-bit versus 32-bit - memcpy(_sifields.pad, host.FEXDef._pad, std::min(sizeof(host.FEXDef._pad), sizeof(_sifields.pad))); - } - static_assert(offsetof(::siginfo_t, si_signo) == offsetof(HostSigInfo_t, FEXDef.si_signo), "si_signo in wrong location?"); - static_assert(offsetof(::siginfo_t, si_errno) == offsetof(HostSigInfo_t, FEXDef.si_errno), "si_errno in wrong location?"); - static_assert(offsetof(::siginfo_t, si_code) == offsetof(HostSigInfo_t, FEXDef.si_code), "si_code in wrong location?"); + ///< The order of these must match the GNU ordering + enum ContextRegs { + FEX_REG_R8 = 0, + FEX_REG_R9, + FEX_REG_R10, + FEX_REG_R11, + FEX_REG_R12, + FEX_REG_R13, + FEX_REG_R14, + FEX_REG_R15, + FEX_REG_RDI, + FEX_REG_RSI, + FEX_REG_RBP, + FEX_REG_RBX, + FEX_REG_RDX, + FEX_REG_RAX, + FEX_REG_RCX, + FEX_REG_RSP, + FEX_REG_RIP, + FEX_REG_EFL, + FEX_REG_CSGSFS, + FEX_REG_ERR, + FEX_REG_TRAPNO, + FEX_REG_OLDMASK, + FEX_REG_CR2, + }; + static_assert(FEX_REG_CR2 == 22, "Oops"); + + struct FEX_PACKED mcontext_t { + uint64_t gregs[23]; + FEXCore::x86_64::_libc_fpstate* fpregs; + uint64_t __reserved[8]; + }; + static_assert(sizeof(FEXCore::x86_64::mcontext_t) == 256, "This needs to be the right size"); + + struct FEX_PACKED sigset_t { + uint64_t val[16]; + }; + static_assert(sizeof(FEXCore::x86_64::sigset_t) == 128, "This needs to be the right size"); + + struct FEX_PACKED ucontext_t { + uint64_t uc_flags; + FEXCore::x86_64::ucontext_t* uc_link; + FEXCore::x86_64::stack_t uc_stack; + FEXCore::x86_64::mcontext_t uc_mcontext; + FEXCore::x86_64::sigset_t uc_sigmask; + }; + static_assert(offsetof(FEXCore::x86_64::ucontext_t, uc_mcontext) == 40, "Needs to be correct"); + + static_assert(sizeof(FEXCore::x86_64::ucontext_t) == 424, "This needs to be the right size"); +} // namespace x86_64 + +namespace x86 { + // uc_flags flags + ///< Has extended FP state + constexpr uint64_t UC_FP_XSTATE = (1ULL << 0); + + ///< The order of these must match the GNU ordering + enum ContextRegs { + FEX_REG_GS = 0, + FEX_REG_FS, + FEX_REG_ES, + FEX_REG_DS, + FEX_REG_RDI, + FEX_REG_RSI, + FEX_REG_RBP, + FEX_REG_RSP, + FEX_REG_RBX, + FEX_REG_RDX, + FEX_REG_RCX, + FEX_REG_RAX, + FEX_REG_TRAPNO, + FEX_REG_ERR, + FEX_REG_EIP, + FEX_REG_CS, + FEX_REG_EFL, + FEX_REG_UESP, + FEX_REG_SS + }; + static_assert(FEX_REG_SS == 18, "Oops"); + + union sigval_t { + int sival_int; + uint32_t sival_ptr; // XXX: Should be compat_ptr + }; + + struct FEX_PACKED siginfo_t { + int si_signo; + int si_errno; + int si_code; + union { + uint32_t pad[29]; + /* tgkill siginfo_t */ + struct { + int32_t pid; + int32_t uid; + } _kill; + /* SIGPOLL */ + struct { + int32_t band; + int32_t fd; + } _poll; + /* SIGILL, SIGFPE, SIGSEGV, SIBUS */ + struct { + uint32_t addr; + } _sigfault; + /* SIGCHLD */ + struct { + int32_t pid; + int32_t uid; + int32_t status; + int32_t utime; + int32_t stime; + } _sigchld; + /* RT signals */ + struct { + int32_t pid; + int32_t uid; + union { + int32_t sival_int; + uint32_t sival_ptr; // compat_ptr + } sigval; + } _rt; + /* SIGALRM, SIGVTALRM */ + struct { + int tid; + int overrun; + FEXCore::x86::sigval_t sigval; + } _timer; + /* SIGSYS */ + struct { + uint32_t call_addr; // compat_ptr + int32_t syscall; + uint32_t arch; + } _sigsys; + } _sifields; + + union HostSigInfo_t { + // This anonymous struct needs to match the host definition + struct { + uint32_t si_signo; + uint32_t si_errno; + uint32_t si_code; + + uint32_t __pad0; + + // Pad[28] is a union for all the sifields + uint32_t _pad[28]; + } FEXDef; + ::siginfo_t host {}; }; - static_assert(sizeof(FEXCore::x86::siginfo_t) == 128, "This needs to be the right size"); + static_assert(sizeof(HostSigInfo_t) == 128, "This needs to be the right size"); - struct FEX_PACKED stack_t { - uint32_t ss_sp; // XXX: should be compat_ptr - int ss_flags; - uint32_t ss_size; - }; + siginfo_t() = delete; - static_assert(sizeof(FEXCore::x86::stack_t) == 12, "This needs to be the right size"); + operator ::siginfo_t() const { + // The definition of siginfo_t changes depending on the host environment + // It is guaranteed to be 128 bytes and the kernel interface is the same for all of them + // Since we only run on Linux + HostSigInfo_t val {}; - struct FEX_PACKED mcontext_t { - uint32_t gregs[19]; - uint32_t fpregs; // XXX: should be compat_ptr - uint32_t oldmask; - uint32_t cr2; - }; - static_assert(sizeof(FEXCore::x86::mcontext_t) == 88, "This needs to be the right size"); + val.FEXDef.si_signo = si_signo; + val.FEXDef.si_errno = si_errno; + val.FEXDef.si_code = si_code; - struct _libc_fpreg { - uint16_t significand[4]; - uint16_t exponent; - }; - static_assert(sizeof(FEXCore::x86::_libc_fpreg) == 10, "This needs to be the right size"); + // Host siginfo has a pad member that is set to zeros + val.FEXDef.__pad0 = 0; - // Same layout on both x86 and x86_64 - using fpx_sw_bytes = x86_64::fpx_sw_bytes; - using xstate_header = x86_64::xstate_header; - using ymmh_state = x86_64::ymmh_state; + // Copy over the union + // The union is different sizes on 64-bit versus 32-bit + memcpy(val.FEXDef._pad, _sifields.pad, std::min(sizeof(val.FEXDef._pad), sizeof(_sifields.pad))); - enum fpstate_magic { - // Legacy fpstate - MAGIC_FPU = 0xFFFF'0000, - // Contains extended state information - MAGIC_XFPSTATE = 0x0, - }; - struct FEX_PACKED _libc_fpstate { - uint32_t fcw; - uint32_t fsw; - uint32_t ftw; - uint32_t fop; - uint32_t cssel; - uint32_t dataoff; - uint32_t datasel; - FEXCore::x86::_libc_fpreg _st[8]; - uint32_t status; + return val.host; + } - // Extended FPU data - uint32_t pad[6]; // Ignored FXSR data - uint32_t mxcsr; - uint32_t reserved; - __uint128_t _st_pad[8]; // Ignored st data - __uint128_t _xmm[8]; // First 8 XMM registers - uint32_t pad2[44]; // Second 8 XMM registers plus padding - fpx_sw_bytes sw_reserved; // extended state encoding - }; - static_assert(sizeof(FEXCore::x86::_libc_fpstate) == 624, "This needs to be the right size"); + siginfo_t(::siginfo_t val) { + HostSigInfo_t host; + host.host = val; - /** - * Extended state that includes both the main fpstate - * and the extended state. - */ - struct FEX_PACKED xstate { - _libc_fpstate fpstate; - xstate_header xstate_hdr; - ymmh_state ymmh; - }; - static_assert(sizeof(xstate) == 944); + si_signo = host.FEXDef.si_signo; + si_errno = host.FEXDef.si_errno; + si_code = host.FEXDef.si_code; - struct FEX_PACKED ucontext_t { - uint32_t uc_flags; - uint32_t uc_link; // XXX: should be a compat_ptr - FEXCore::x86::stack_t uc_stack; - FEXCore::x86::mcontext_t uc_mcontext; - FEXCore::x86_64::sigset_t uc_sigmask; // This matches across architectures - }; - static_assert(sizeof(FEXCore::x86::ucontext_t) == 236, "This needs to be the right size"); + // Copy over the union + // The union is different sizes on 64-bit versus 32-bit + memcpy(_sifields.pad, host.FEXDef._pad, std::min(sizeof(host.FEXDef._pad), sizeof(_sifields.pad))); + } + static_assert(offsetof(::siginfo_t, si_signo) == offsetof(HostSigInfo_t, FEXDef.si_signo), "si_signo in wrong location?"); + static_assert(offsetof(::siginfo_t, si_errno) == offsetof(HostSigInfo_t, FEXDef.si_errno), "si_errno in wrong location?"); + static_assert(offsetof(::siginfo_t, si_code) == offsetof(HostSigInfo_t, FEXDef.si_code), "si_code in wrong location?"); + }; + static_assert(sizeof(FEXCore::x86::siginfo_t) == 128, "This needs to be the right size"); - ///< Non-rt signal context. - // - // Needs to match the format expected from signal handlers without SA_SIGINFO set. - struct sigcontext { - uint32_t gs; - uint32_t fs; - uint32_t es; - uint32_t ds; - uint32_t di; - uint32_t si; - uint32_t bp; - uint32_t sp; - uint32_t bx; - uint32_t dx; - uint32_t cx; - uint32_t ax; - uint32_t trapno; - uint32_t err; - uint32_t ip; - uint32_t cs; - uint32_t flags; - uint32_t sp_at_signal; - uint32_t ss; + struct FEX_PACKED stack_t { + uint32_t ss_sp; // XXX: should be compat_ptr + int ss_flags; + uint32_t ss_size; + }; - uint32_t fpstate; - uint32_t oldmask; - uint32_t cr2; - }; - } -} + static_assert(sizeof(FEXCore::x86::stack_t) == 12, "This needs to be the right size"); + + struct FEX_PACKED mcontext_t { + uint32_t gregs[19]; + uint32_t fpregs; // XXX: should be compat_ptr + uint32_t oldmask; + uint32_t cr2; + }; + static_assert(sizeof(FEXCore::x86::mcontext_t) == 88, "This needs to be the right size"); + + struct _libc_fpreg { + uint16_t significand[4]; + uint16_t exponent; + }; + static_assert(sizeof(FEXCore::x86::_libc_fpreg) == 10, "This needs to be the right size"); + + // Same layout on both x86 and x86_64 + using fpx_sw_bytes = x86_64::fpx_sw_bytes; + using xstate_header = x86_64::xstate_header; + using ymmh_state = x86_64::ymmh_state; + + enum fpstate_magic { + // Legacy fpstate + MAGIC_FPU = 0xFFFF'0000, + // Contains extended state information + MAGIC_XFPSTATE = 0x0, + }; + struct FEX_PACKED _libc_fpstate { + uint32_t fcw; + uint32_t fsw; + uint32_t ftw; + uint32_t fop; + uint32_t cssel; + uint32_t dataoff; + uint32_t datasel; + FEXCore::x86::_libc_fpreg _st[8]; + uint32_t status; + + // Extended FPU data + uint32_t pad[6]; // Ignored FXSR data + uint32_t mxcsr; + uint32_t reserved; + __uint128_t _st_pad[8]; // Ignored st data + __uint128_t _xmm[8]; // First 8 XMM registers + uint32_t pad2[44]; // Second 8 XMM registers plus padding + fpx_sw_bytes sw_reserved; // extended state encoding + }; + static_assert(sizeof(FEXCore::x86::_libc_fpstate) == 624, "This needs to be the right size"); + + /** + * Extended state that includes both the main fpstate + * and the extended state. + */ + struct FEX_PACKED xstate { + _libc_fpstate fpstate; + xstate_header xstate_hdr; + ymmh_state ymmh; + }; + static_assert(sizeof(xstate) == 944); + + struct FEX_PACKED ucontext_t { + uint32_t uc_flags; + uint32_t uc_link; // XXX: should be a compat_ptr + FEXCore::x86::stack_t uc_stack; + FEXCore::x86::mcontext_t uc_mcontext; + FEXCore::x86_64::sigset_t uc_sigmask; // This matches across architectures + }; + static_assert(sizeof(FEXCore::x86::ucontext_t) == 236, "This needs to be the right size"); + + ///< Non-rt signal context. + // + // Needs to match the format expected from signal handlers without SA_SIGINFO set. + struct sigcontext { + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + uint32_t di; + uint32_t si; + uint32_t bp; + uint32_t sp; + uint32_t bx; + uint32_t dx; + uint32_t cx; + uint32_t ax; + uint32_t trapno; + uint32_t err; + uint32_t ip; + uint32_t cs; + uint32_t flags; + uint32_t sp_at_signal; + uint32_t ss; + + uint32_t fpstate; + uint32_t oldmask; + uint32_t cr2; + }; +} // namespace x86 +} // namespace FEXCore diff --git a/Source/Tools/LinuxEmulation/ArchHelpers/WinContext.h b/Source/Tools/LinuxEmulation/ArchHelpers/WinContext.h index 56283460f..72caffba4 100644 --- a/Source/Tools/LinuxEmulation/ArchHelpers/WinContext.h +++ b/Source/Tools/LinuxEmulation/ArchHelpers/WinContext.h @@ -30,7 +30,7 @@ static inline void SetState(PCONTEXT Context, uint64_t val) { Context->X28 = val; } -static inline uint64_t *GetArmGPRs(PCONTEXT Context) { +static inline uint64_t* GetArmGPRs(PCONTEXT Context) { return Context->X; } #endif @@ -60,12 +60,12 @@ static inline void SetState(PCONTEXT Context, uint64_t val) { Context->R14 = val; } -static inline uint64_t *GetArmGPRs(PCONTEXT Context) { +static inline uint64_t* GetArmGPRs(PCONTEXT Context) { ERROR_AND_DIE_FMT("Not implemented for x86 host"); } #endif -} +} // namespace FEX::ArchHelpers::Context #endif diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h index 54e7cfe70..f454a2df1 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h @@ -476,4 +476,4 @@ enum Syscalls_Arm64 { SYSCALL_Arm64_epoll_wait_old = ~0, SYSCALL_Arm64_newfstatat = ~0, }; -} +} // namespace FEX::HLE::Arm64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp index bf74c64e2..9c6383096 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp @@ -34,357 +34,273 @@ $end_info$ #include namespace FEX::EmulatedFile { - /** - * @brief Generates a temporary file using raw FDs - * - * Since we are hooking syscalls that are expecting to use raw FDs, we need to make sure to also use raw FDs. - * The guest application can leave these FDs dangling. - * - * Using glibc tmpfile creates a FILE which glibc tracks and will try cleaning up on application exit. - * If we are running a 32-bit application then this dangling FILE will be allocated using the FEX allcator - * Which will have already been cleaned up on shutdown. - * - * Dangling raw FD is safe since if the guest doesn't close them, then the kernel cleans them up on application close. - * - * @return A temporary file that we can use - */ - static int GenTmpFD(const char *pathname, int flags) { - uint32_t memfd_flags {MFD_ALLOW_SEALING}; - if (flags & O_CLOEXEC) memfd_flags |= MFD_CLOEXEC; - - return memfd_create(pathname, memfd_flags); +/** + * @brief Generates a temporary file using raw FDs + * + * Since we are hooking syscalls that are expecting to use raw FDs, we need to make sure to also use raw FDs. + * The guest application can leave these FDs dangling. + * + * Using glibc tmpfile creates a FILE which glibc tracks and will try cleaning up on application exit. + * If we are running a 32-bit application then this dangling FILE will be allocated using the FEX allcator + * Which will have already been cleaned up on shutdown. + * + * Dangling raw FD is safe since if the guest doesn't close them, then the kernel cleans them up on application close. + * + * @return A temporary file that we can use + */ +static int GenTmpFD(const char* pathname, int flags) { + uint32_t memfd_flags {MFD_ALLOW_SEALING}; + if (flags & O_CLOEXEC) { + memfd_flags |= MFD_CLOEXEC; } - // Seal the tmpfd features by sealing them all. - // Makes the tmpfd read-only. - static void SealTmpFD(int fd) { - fcntl(fd, F_ADD_SEALS, - F_SEAL_SEAL | - F_SEAL_SHRINK | - F_SEAL_GROW | - F_SEAL_WRITE | - F_SEAL_FUTURE_WRITE); - } + return memfd_create(pathname, memfd_flags); +} - fextl::string GenerateCPUInfo(FEXCore::Context::Context *ctx, uint32_t CPUCores) { - fextl::ostringstream cpu_stream{}; - auto res_0 = ctx->RunCPUIDFunction(0, 0); - auto res_1 = ctx->RunCPUIDFunction(1, 0); - auto res_6 = ctx->RunCPUIDFunction(6, 0); - auto res_7 = ctx->RunCPUIDFunction(7, 0); - auto res_10 = ctx->RunCPUIDFunction(0x10, 0); +// Seal the tmpfd features by sealing them all. +// Makes the tmpfd read-only. +static void SealTmpFD(int fd) { + fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_FUTURE_WRITE); +} - auto res_8000_0001 = ctx->RunCPUIDFunction(0x8000'0001, 0); - auto res_8000_0007 = ctx->RunCPUIDFunction(0x8000'0007, 0); - auto res_8000_0008 = ctx->RunCPUIDFunction(0x8000'0008, 0); - auto res_8000_000a = ctx->RunCPUIDFunction(0x8000'000a, 0); - auto res_8000_001f = ctx->RunCPUIDFunction(0x8000'001f, 0); +fextl::string GenerateCPUInfo(FEXCore::Context::Context* ctx, uint32_t CPUCores) { + fextl::ostringstream cpu_stream {}; + auto res_0 = ctx->RunCPUIDFunction(0, 0); + auto res_1 = ctx->RunCPUIDFunction(1, 0); + auto res_6 = ctx->RunCPUIDFunction(6, 0); + auto res_7 = ctx->RunCPUIDFunction(7, 0); + auto res_10 = ctx->RunCPUIDFunction(0x10, 0); - union VendorID { - struct { - uint32_t id; - char Str[13]; - }; - struct { - FEXCore::CPUID::FunctionResults cpuid; - uint8_t null; - }; + auto res_8000_0001 = ctx->RunCPUIDFunction(0x8000'0001, 0); + auto res_8000_0007 = ctx->RunCPUIDFunction(0x8000'0007, 0); + auto res_8000_0008 = ctx->RunCPUIDFunction(0x8000'0008, 0); + auto res_8000_000a = ctx->RunCPUIDFunction(0x8000'000a, 0); + auto res_8000_001f = ctx->RunCPUIDFunction(0x8000'001f, 0); + + union VendorID { + struct { + uint32_t id; + char Str[13]; }; - - union ModelName { - struct { - char Str[49]; - }; - struct { - FEXCore::CPUID::FunctionResults cpuid_2; - FEXCore::CPUID::FunctionResults cpuid_3; - FEXCore::CPUID::FunctionResults cpuid_4; - uint8_t null; - }; - }; - - union Info { + struct { FEXCore::CPUID::FunctionResults cpuid; - struct { - unsigned Stepping : 4; - unsigned Model : 4; - unsigned FamilyID : 4; - unsigned Type : 4; - unsigned ExModelID : 4; - unsigned ExFamilyID : 8; - unsigned : 4; - }; + uint8_t null; }; + }; - VendorID vendorid {}; - vendorid.cpuid = {res_0.eax, res_0.ebx, res_0.edx, res_0.ecx}; - vendorid.null = 0; + union ModelName { + struct { + char Str[49]; + }; + struct { + FEXCore::CPUID::FunctionResults cpuid_2; + FEXCore::CPUID::FunctionResults cpuid_3; + FEXCore::CPUID::FunctionResults cpuid_4; + uint8_t null; + }; + }; - Info info {res_1}; + union Info { + FEXCore::CPUID::FunctionResults cpuid; + struct { + unsigned Stepping : 4; + unsigned Model : 4; + unsigned FamilyID : 4; + unsigned Type : 4; + unsigned ExModelID : 4; + unsigned ExFamilyID : 8; + unsigned : 4; + }; + }; - uint32_t Family = info.FamilyID + (info.FamilyID == 0xF ? info.ExFamilyID : 0); - fextl::ostringstream flags_data{}; - // Generate the flags data up front - // This is the same per core - { -#define FLAG(flag, name) if (flag) { flags_data << name << " "; } - FLAG(res_1.edx & (1 << 0), "fpu") - FLAG(res_1.edx & (1 << 1), "vme") - FLAG(res_1.edx & (1 << 2), "de") - FLAG(res_1.edx & (1 << 3), "pse") - FLAG(res_1.edx & (1 << 4), "tsc") - FLAG(res_1.edx & (1 << 5), "msr") - FLAG(res_1.edx & (1 << 6), "pae") - FLAG(res_1.edx & (1 << 7), "mce") - FLAG(res_1.edx & (1 << 8), "cx8") - FLAG(res_1.edx & (1 << 9), "apic") - FLAG(res_1.edx & (1 << 11), "sep") - FLAG(res_1.edx & (1 << 12), "mtrr") - FLAG(res_1.edx & (1 << 13), "pge") - FLAG(res_1.edx & (1 << 14), "mca") - FLAG(res_1.edx & (1 << 15), "cmov") - FLAG(res_1.edx & (1 << 16), "pat") - FLAG(res_1.edx & (1 << 17), "pse36") - FLAG(res_1.edx & (1 << 18), "pn") - FLAG(res_1.edx & (1 << 19), "clflush") - FLAG(res_1.edx & (1 << 21), "ds") // XXX - FLAG(res_1.edx & (1 << 22), "acpi") // XXX - FLAG(res_1.edx & (1 << 23), "mmx") - FLAG(res_1.edx & (1 << 24), "fxsr") - FLAG(res_1.edx & (1 << 25), "sse") - FLAG(res_1.edx & (1 << 26), "sse2") - FLAG(res_1.edx & (1 << 27), "ss") - FLAG(res_1.edx & (1 << 28), "ht") - FLAG(res_1.edx & (1 << 29), "tm") - FLAG(res_1.edx & (1 << 30), "ia64") - FLAG(res_1.edx & (1 << 31), "pbe") + VendorID vendorid {}; + vendorid.cpuid = {res_0.eax, res_0.ebx, res_0.edx, res_0.ecx}; + vendorid.null = 0; - FLAG(res_8000_0001.edx & (1 << 11), - "syscall") - FLAG(res_8000_0001.edx & (1 << 19), - "mp") - FLAG(res_8000_0001.edx & (1 << 20), - "nx") - FLAG(res_8000_0001.edx & (1 << 22), - "mmxext") - FLAG(res_8000_0001.edx & (1 << 25), - "fxsr_opt") - FLAG(res_8000_0001.edx & (1 << 26), - "pdpe1gb") - FLAG(res_8000_0001.edx & (1 << 27), - "rdtscp") - FLAG(res_8000_0001.edx & (1 << 29), - "lm") - FLAG(res_8000_0001.edx & (1 << 31), - "3dnow") - FLAG(res_8000_0001.edx & (1 << 30), - "3dnowext") + Info info {res_1}; - FLAG(res_8000_0007.edx & (1 << 8), - "constant_tsc") + uint32_t Family = info.FamilyID + (info.FamilyID == 0xF ? info.ExFamilyID : 0); + fextl::ostringstream flags_data {}; + // Generate the flags data up front + // This is the same per core + { +#define FLAG(flag, name) \ + if (flag) { \ + flags_data << name << " "; \ + } + FLAG(res_1.edx & (1 << 0), "fpu") + FLAG(res_1.edx & (1 << 1), "vme") + FLAG(res_1.edx & (1 << 2), "de") + FLAG(res_1.edx & (1 << 3), "pse") + FLAG(res_1.edx & (1 << 4), "tsc") + FLAG(res_1.edx & (1 << 5), "msr") + FLAG(res_1.edx & (1 << 6), "pae") + FLAG(res_1.edx & (1 << 7), "mce") + FLAG(res_1.edx & (1 << 8), "cx8") + FLAG(res_1.edx & (1 << 9), "apic") + FLAG(res_1.edx & (1 << 11), "sep") + FLAG(res_1.edx & (1 << 12), "mtrr") + FLAG(res_1.edx & (1 << 13), "pge") + FLAG(res_1.edx & (1 << 14), "mca") + FLAG(res_1.edx & (1 << 15), "cmov") + FLAG(res_1.edx & (1 << 16), "pat") + FLAG(res_1.edx & (1 << 17), "pse36") + FLAG(res_1.edx & (1 << 18), "pn") + FLAG(res_1.edx & (1 << 19), "clflush") + FLAG(res_1.edx & (1 << 21), "ds") // XXX + FLAG(res_1.edx & (1 << 22), "acpi") // XXX + FLAG(res_1.edx & (1 << 23), "mmx") + FLAG(res_1.edx & (1 << 24), "fxsr") + FLAG(res_1.edx & (1 << 25), "sse") + FLAG(res_1.edx & (1 << 26), "sse2") + FLAG(res_1.edx & (1 << 27), "ss") + FLAG(res_1.edx & (1 << 28), "ht") + FLAG(res_1.edx & (1 << 29), "tm") + FLAG(res_1.edx & (1 << 30), "ia64") + FLAG(res_1.edx & (1 << 31), "pbe") - // We are not a uniprocessor running in SMP mode - FLAG(false, "up") - // Timer is always running - FLAG(true, "art") - // No Intel perfmon - FLAG(false, "arch_perfmon") - // No precise event based sampling - FLAG(false, "pebs") - // No branch trace store - FLAG(false, "bts") + FLAG(res_8000_0001.edx & (1 << 11), "syscall") + FLAG(res_8000_0001.edx & (1 << 19), "mp") + FLAG(res_8000_0001.edx & (1 << 20), "nx") + FLAG(res_8000_0001.edx & (1 << 22), "mmxext") + FLAG(res_8000_0001.edx & (1 << 25), "fxsr_opt") + FLAG(res_8000_0001.edx & (1 << 26), "pdpe1gb") + FLAG(res_8000_0001.edx & (1 << 27), "rdtscp") + FLAG(res_8000_0001.edx & (1 << 29), "lm") + FLAG(res_8000_0001.edx & (1 << 31), "3dnow") + FLAG(res_8000_0001.edx & (1 << 30), "3dnowext") - FLAG(true, "rep_good") - FLAG(res_8000_0007.edx & (1 << 12), - "tm") + FLAG(res_8000_0007.edx & (1 << 8), "constant_tsc") - // Always support long nop - FLAG(true, "nopl") + // We are not a uniprocessor running in SMP mode + FLAG(false, "up") + // Timer is always running + FLAG(true, "art") + // No Intel perfmon + FLAG(false, "arch_perfmon") + // No precise event based sampling + FLAG(false, "pebs") + // No branch trace store + FLAG(false, "bts") - // Always expose topology information - FLAG(true, "xtoplogy") + FLAG(true, "rep_good") + FLAG(res_8000_0007.edx & (1 << 12), "tm") - // Atom/geode only? - FLAG(false, "tsc_reliable") - FLAG(res_8000_0007.edx & (1 << 8), - "nonstop_tsc") + // Always support long nop + FLAG(true, "nopl") - // We always support CPUID - FLAG(true, "cpuid") - FLAG(Family > 0x16, - "extd_apicid") - FLAG(false, "amd_dcm") // Never claim to be a multi node processor - FLAG(res_8000_0007.edx & (1 << 11), - "aperfmperf") + // Always expose topology information + FLAG(true, "xtoplogy") - // Need to check ARM documentation if we can support this? - FLAG(false, "nonstop_tsc_s3") + // Atom/geode only? + FLAG(false, "tsc_reliable") + FLAG(res_8000_0007.edx & (1 << 8), "nonstop_tsc") - // We can calculate this flag on AArch64 - FLAG(true, "tsc_known_freq") + // We always support CPUID + FLAG(true, "cpuid") + FLAG(Family > 0x16, "extd_apicid") + FLAG(false, "amd_dcm") // Never claim to be a multi node processor + FLAG(res_8000_0007.edx & (1 << 11), "aperfmperf") - FLAG(res_1.ecx & (1 << 0), - "pni") - FLAG(res_1.ecx & (1 << 1), - "pclmulqdq") - FLAG(res_1.ecx & (1 << 2), - "dtes64") - FLAG(res_1.ecx & (1 << 3), - "monitor") - FLAG(res_1.ecx & (1 << 4), - "ds_cpl") - FLAG(res_1.ecx & (1 << 5), - "vmx") - FLAG(res_1.ecx & (1 << 6), - "smx") - FLAG(res_1.ecx & (1 << 7), - "est") - FLAG(res_1.ecx & (1 << 8), - "tm2") - FLAG(res_1.ecx & (1 << 9), - "ssse3") - FLAG(res_1.ecx & (1 << 11), - "sdbg") - FLAG(res_1.ecx & (1 << 12), - "fma") - FLAG(res_1.ecx & (1 << 13), - "cx16") - FLAG(res_1.ecx & (1 << 14), - "xptr") - FLAG(res_1.ecx & (1 << 15), - "pdcm") - FLAG(res_1.ecx & (1 << 17), - "pcid") - FLAG(res_1.ecx & (1 << 18), - "dca") - FLAG(res_1.ecx & (1 << 19), - "sse4_1") - FLAG(res_1.ecx & (1 << 20), - "sse4_2") - FLAG(res_1.ecx & (1 << 21), - "x2apic") - FLAG(res_1.ecx & (1 << 22), - "movbe") - FLAG(res_1.ecx & (1 << 23), - "popcnt") - FLAG(res_1.ecx & (1 << 24), - "tsc_deadline_timer") - FLAG(res_1.ecx & (1 << 25), - "aes") - FLAG(res_1.ecx & (1 << 26), - "xsave") - FLAG(res_1.ecx & (1 << 28), - "avx") - FLAG(res_1.ecx & (1 << 29), - "f16c") - FLAG(res_1.ecx & (1 << 30), - "rdrand") - FLAG(res_1.ecx & (1 << 31), - "hypervisor") + // Need to check ARM documentation if we can support this? + FLAG(false, "nonstop_tsc_s3") - FLAG(res_8000_0001.ecx & (1 << 0), - "lahf_lm") - FLAG(res_8000_0001.ecx & (1 << 1), - "cmp_legacy") - FLAG(res_8000_0001.ecx & (1 << 2), - "svm") - FLAG(res_8000_0001.ecx & (1 << 3), - "extapic") - FLAG(res_8000_0001.ecx & (1 << 4), - "cr8_legacy") - FLAG(res_8000_0001.ecx & (1 << 5), - "abm") - FLAG(res_8000_0001.ecx & (1 << 6), - "sse4a") - FLAG(res_8000_0001.ecx & (1 << 7), - "misalignsse") - FLAG(res_8000_0001.ecx & (1 << 8), - "3dnowprefetch") - FLAG(res_8000_0001.ecx & (1 << 9), - "osvw") - FLAG(res_8000_0001.ecx & (1 << 10), - "ibs") - FLAG(res_8000_0001.ecx & (1 << 11), - "xop") - FLAG(res_8000_0001.ecx & (1 << 12), - "skinit") - FLAG(res_8000_0001.ecx & (1 << 13), - "wdt") - FLAG(res_8000_0001.ecx & (1 << 15), - "lwp") - FLAG(res_8000_0001.ecx & (1 << 16), - "fma4") - FLAG(res_8000_0001.ecx & (1 << 17), - "tce") - FLAG(res_8000_0001.ecx & (1 << 19), - "nodeid_msr") - FLAG(res_8000_0001.ecx & (1 << 21), - "tbm") - FLAG(res_8000_0001.ecx & (1 << 22), - "topoext") - FLAG(res_8000_0001.ecx & (1 << 23), - "perfctr_core") - FLAG(res_8000_0001.ecx & (1 << 24), - "perfctr_nb") - FLAG(res_8000_0001.ecx & (1 << 26), - "bpext") - FLAG(res_8000_0001.ecx & (1 << 27), - "ptsc") + // We can calculate this flag on AArch64 + FLAG(true, "tsc_known_freq") - FLAG(res_8000_0001.ecx & (1 << 28), - "perfctr_llc") - FLAG(res_8000_0001.ecx & (1 << 29), - "mwaitx") + FLAG(res_1.ecx & (1 << 0), "pni") + FLAG(res_1.ecx & (1 << 1), "pclmulqdq") + FLAG(res_1.ecx & (1 << 2), "dtes64") + FLAG(res_1.ecx & (1 << 3), "monitor") + FLAG(res_1.ecx & (1 << 4), "ds_cpl") + FLAG(res_1.ecx & (1 << 5), "vmx") + FLAG(res_1.ecx & (1 << 6), "smx") + FLAG(res_1.ecx & (1 << 7), "est") + FLAG(res_1.ecx & (1 << 8), "tm2") + FLAG(res_1.ecx & (1 << 9), "ssse3") + FLAG(res_1.ecx & (1 << 11), "sdbg") + FLAG(res_1.ecx & (1 << 12), "fma") + FLAG(res_1.ecx & (1 << 13), "cx16") + FLAG(res_1.ecx & (1 << 14), "xptr") + FLAG(res_1.ecx & (1 << 15), "pdcm") + FLAG(res_1.ecx & (1 << 17), "pcid") + FLAG(res_1.ecx & (1 << 18), "dca") + FLAG(res_1.ecx & (1 << 19), "sse4_1") + FLAG(res_1.ecx & (1 << 20), "sse4_2") + FLAG(res_1.ecx & (1 << 21), "x2apic") + FLAG(res_1.ecx & (1 << 22), "movbe") + FLAG(res_1.ecx & (1 << 23), "popcnt") + FLAG(res_1.ecx & (1 << 24), "tsc_deadline_timer") + FLAG(res_1.ecx & (1 << 25), "aes") + FLAG(res_1.ecx & (1 << 26), "xsave") + FLAG(res_1.ecx & (1 << 28), "avx") + FLAG(res_1.ecx & (1 << 29), "f16c") + FLAG(res_1.ecx & (1 << 30), "rdrand") + FLAG(res_1.ecx & (1 << 31), "hypervisor") - // We don't support ring 3 supporting mwait - FLAG(false, "ring3mwait") - // We don't support Intel CPUID fault support - FLAG(false, "cpuid_fault") - FLAG(res_8000_0007.edx & (1 << 9), - "cpb") - FLAG(res_6.ecx & (1 << 3), - "epb") - FLAG(res_10.ebx & (1 << 1), - "cat_l3") - FLAG(res_10.ebx & (1 << 2), - "cat_l2") - FLAG(false, // Needs leaf support - "cdp_l3") - FLAG(false, "invpcid_single") - FLAG(res_8000_0007.edx & (1 << 7), - "hw_pstate") - FLAG(res_8000_001f.eax & (1 << 0), - "sme") + FLAG(res_8000_0001.ecx & (1 << 0), "lahf_lm") + FLAG(res_8000_0001.ecx & (1 << 1), "cmp_legacy") + FLAG(res_8000_0001.ecx & (1 << 2), "svm") + FLAG(res_8000_0001.ecx & (1 << 3), "extapic") + FLAG(res_8000_0001.ecx & (1 << 4), "cr8_legacy") + FLAG(res_8000_0001.ecx & (1 << 5), "abm") + FLAG(res_8000_0001.ecx & (1 << 6), "sse4a") + FLAG(res_8000_0001.ecx & (1 << 7), "misalignsse") + FLAG(res_8000_0001.ecx & (1 << 8), "3dnowprefetch") + FLAG(res_8000_0001.ecx & (1 << 9), "osvw") + FLAG(res_8000_0001.ecx & (1 << 10), "ibs") + FLAG(res_8000_0001.ecx & (1 << 11), "xop") + FLAG(res_8000_0001.ecx & (1 << 12), "skinit") + FLAG(res_8000_0001.ecx & (1 << 13), "wdt") + FLAG(res_8000_0001.ecx & (1 << 15), "lwp") + FLAG(res_8000_0001.ecx & (1 << 16), "fma4") + FLAG(res_8000_0001.ecx & (1 << 17), "tce") + FLAG(res_8000_0001.ecx & (1 << 19), "nodeid_msr") + FLAG(res_8000_0001.ecx & (1 << 21), "tbm") + FLAG(res_8000_0001.ecx & (1 << 22), "topoext") + FLAG(res_8000_0001.ecx & (1 << 23), "perfctr_core") + FLAG(res_8000_0001.ecx & (1 << 24), "perfctr_nb") + FLAG(res_8000_0001.ecx & (1 << 26), "bpext") + FLAG(res_8000_0001.ecx & (1 << 27), "ptsc") - // Kernel page table isolation. - FLAG(false, "pti") + FLAG(res_8000_0001.ecx & (1 << 28), "perfctr_llc") + FLAG(res_8000_0001.ecx & (1 << 29), "mwaitx") - // We don't support Intel's Protected Processor Inventory Number - FLAG(false, "intel_ppin") - FLAG(false, // Needs leaf support - "cdp_l2") + // We don't support ring 3 supporting mwait + FLAG(false, "ring3mwait") + // We don't support Intel CPUID fault support + FLAG(false, "cpuid_fault") + FLAG(res_8000_0007.edx & (1 << 9), "cpb") + FLAG(res_6.ecx & (1 << 3), "epb") + FLAG(res_10.ebx & (1 << 1), "cat_l3") + FLAG(res_10.ebx & (1 << 2), "cat_l2") + FLAG(false, // Needs leaf support + "cdp_l3") + FLAG(false, "invpcid_single") + FLAG(res_8000_0007.edx & (1 << 7), "hw_pstate") + FLAG(res_8000_001f.eax & (1 << 0), "sme") - FLAG(res_8000_0008.ebx & (1 << 6), - "mba") - FLAG(res_8000_001f.eax & (1 << 1), - "sev") + // Kernel page table isolation. + FLAG(false, "pti") - { - // Speculative bug workarounds - // We don't claim to have these bugs, so we don't need to claim these flags - FLAG(res_7.edx & (1 << 31), - "ssbd") - FLAG(false, "ibrs") - FLAG(false, "ibpb") + // We don't support Intel's Protected Processor Inventory Number + FLAG(false, "intel_ppin") + FLAG(false, // Needs leaf support + "cdp_l2") - FLAG(res_7.edx & (1 << 27), - "stibp") + FLAG(res_8000_0008.ebx & (1 << 6), "mba") + FLAG(res_8000_001f.eax & (1 << 1), "sev") - FLAG(false, "ibrs_enhanced") - } + {// Speculative bug workarounds + // We don't claim to have these bugs, so we don't need to claim these flags + FLAG(res_7.edx & (1 << 31), "ssbd") FLAG(false, "ibrs") FLAG(false, "ibpb") - // We don't support Intel's TPR Shadow feature - FLAG(false, "tpr_shadow") + FLAG(res_7.edx & (1 << 27), "stibp") + + FLAG(false, "ibrs_enhanced")} + + // We don't support Intel's TPR Shadow feature + FLAG(false, "tpr_shadow") // Intel virtual NMI FLAG(false, "vnmi") // Intel FlexPriority @@ -397,423 +313,289 @@ namespace FEX::EmulatedFile { // Prefer VMMCall to VMCall FLAG(false, "vmmcall") // Intel extended page table access dirty bit - FLAG(false, "ept_ad") - FLAG(res_7.ebx & (1 << 0), - "fsgsbase") - FLAG(res_7.ebx & (1 << 1), - "tsc_adjust") - FLAG(res_7.ebx & (1 << 3), - "bmi1") - FLAG(res_7.ebx & (1 << 4), - "hle") - FLAG(res_7.ebx & (1 << 5), - "avx2") - FLAG(res_7.ebx & (1 << 7), - "smep") - FLAG(res_7.ebx & (1 << 8), - "bmi2") - FLAG(res_7.ebx & (1 << 9), - "erms") - FLAG(res_7.ebx & (1 << 10), - "invpcid") - FLAG(res_7.ebx & (1 << 11), - "rtm") - FLAG(false, // Needs leaf support - "cqm") - FLAG(res_7.ebx & (1 << 14), - "mpx") - FLAG(false, // Needs leaf support - "rdt_a") - FLAG(res_7.ebx & (1 << 16), - "avx512f") - FLAG(res_7.ebx & (1 << 17), - "avx512dq") - FLAG(res_7.ebx & (1 << 18), - "rdseed") - FLAG(res_7.ebx & (1 << 19), - "adx") - FLAG(res_7.ebx & (1 << 20), - "smap") - FLAG(res_7.ebx & (1 << 21), - "avx512ifma") - FLAG(res_7.ebx & (1 << 23), - "clflushopt") - FLAG(res_7.ebx & (1 << 24), - "clwb") - FLAG(res_7.ebx & (1 << 25), - "intel_pt") - FLAG(res_7.ebx & (1 << 26), - "avx512pf") - FLAG(res_7.ebx & (1 << 27), - "avx512er") - FLAG(res_7.ebx & (1 << 28), - "avx512cd") - FLAG(res_7.ebx & (1 << 29), - "sha_ni") - FLAG(res_7.ebx & (1 << 30), - "avx512bw") - FLAG(res_7.ebx & (1 << 31), - "avx512vl") - FLAG(false, // Needs leaf support // res_d.eax & (1 << 0) // Leaf 1h - "xsaveopt") - FLAG(false, // Needs leaf support // res_d.eax & (1 << 1) // Leaf 1h - "xsavec") - FLAG(false, // Needs leaf support // res_d.eax & (1 << 2) // Leaf 1h - "xgetbv1") - FLAG(false, // Needs leaf support // res_d.eax & (1 << 3) // Leaf 1h - "xsaves") + FLAG(false, "ept_ad") FLAG(res_7.ebx & (1 << 0), "fsgsbase") FLAG(res_7.ebx & (1 << 1), "tsc_adjust") + FLAG(res_7.ebx & (1 << 3), "bmi1") FLAG(res_7.ebx & (1 << 4), "hle") FLAG(res_7.ebx & (1 << 5), "avx2") + FLAG(res_7.ebx & (1 << 7), "smep") FLAG(res_7.ebx & (1 << 8), "bmi2") FLAG(res_7.ebx & (1 << 9), "erms") + FLAG(res_7.ebx & (1 << 10), "invpcid") FLAG(res_7.ebx & (1 << 11), + "rtm") FLAG(false, // Needs leaf support + "cqm") FLAG(res_7.ebx & (1 << 14), + "mpx") FLAG(false, // Needs leaf support + "rdt_a") FLAG(res_7.ebx & (1 << 16), "avx512f") + FLAG(res_7.ebx & (1 << 17), "avx512dq") FLAG(res_7.ebx & (1 << 18), "rdseed") FLAG(res_7.ebx & (1 << 19), "adx") + FLAG(res_7.ebx & (1 << 20), "smap") FLAG(res_7.ebx & (1 << 21), "avx512ifma") FLAG(res_7.ebx & (1 << 23), "clflushopt") + FLAG(res_7.ebx & (1 << 24), "clwb") FLAG(res_7.ebx & (1 << 25), "intel_pt") FLAG(res_7.ebx & (1 << 26), "avx512pf") + FLAG(res_7.ebx & (1 << 27), "avx512er") FLAG(res_7.ebx & (1 << 28), "avx512cd") FLAG(res_7.ebx & (1 << 29), "sha_ni") + FLAG(res_7.ebx & (1 << 30), "avx512bw") FLAG(res_7.ebx & (1 << 31), + "avx512vl") + FLAG(false, // Needs leaf support // res_d.eax & (1 << 0) // Leaf 1h + "xsaveopt") FLAG(false, // Needs leaf support // res_d.eax & (1 << 1) // Leaf 1h + "xsavec") FLAG(false, // Needs leaf support // res_d.eax & (1 << 2) // Leaf 1h + "xgetbv1") FLAG(false, // Needs leaf support // res_d.eax & (1 << 3) // Leaf 1h + "xsaves") - FLAG(false, // Needs leaf support - "avx512_bf16") - FLAG(res_8000_0008.ebx & (1 << 0), - "clzero") - FLAG(res_8000_0008.ebx & (1 << 1), - "irperf") - FLAG(res_8000_0008.ebx & (1 << 2), - "xsaveerptr") + FLAG(false, // Needs leaf support + "avx512_bf16") FLAG(res_8000_0008.ebx & (1 << 0), "clzero") FLAG(res_8000_0008.ebx & (1 << 1), "irperf") + FLAG(res_8000_0008.ebx & (1 << 2), "xsaveerptr") // Intel digital thermal sensor FLAG(false, "dtherm") // Intel turbo boost - FLAG(false, "ida") - FLAG(res_6.eax & (1 << 2), - "arat") + FLAG(false, "ida") FLAG(res_6.eax & (1 << 2), "arat") // Power limit notification controls FLAG(false, "pln") // Intel package thermal status FLAG(false, "pts") // Intel Hardware P-state features - FLAG(false, "hwp") - FLAG(false, "hwp_notify") - FLAG(false, "hwp_act_window") - FLAG(false, "hwp_epp") - FLAG(false, "hwp_pkg_req") + FLAG(false, "hwp") FLAG(false, "hwp_notify") FLAG(false, "hwp_act_window") FLAG(false, "hwp_epp") FLAG(false, "hwp_pkg_req") - FLAG(res_8000_000a.ebx & (1 << 0), - "npt") - FLAG(res_8000_000a.ebx & (1 << 1), - "lbrv") - FLAG(res_8000_000a.ebx & (1 << 2), - "svm_lock") - FLAG(res_8000_000a.ebx & (1 << 3), - "nrip_save") - FLAG(res_8000_000a.ebx & (1 << 4), - "tsc_scale") - FLAG(res_8000_000a.ebx & (1 << 5), - "vmcb_clean") - FLAG(res_8000_000a.ebx & (1 << 6), - "flushbyasid") - FLAG(res_8000_000a.ebx & (1 << 7), - "decodeassists") - FLAG(res_8000_000a.ebx & (1 << 10), - "pausefilter") - FLAG(res_8000_000a.ebx & (1 << 12), - "pfthreshold") - FLAG(res_8000_000a.ebx & (1 << 13), - "avic") - FLAG(res_8000_000a.ebx & (1 << 15), - "v_vmsave_vmload") - FLAG(res_8000_000a.ebx & (1 << 16), - "vgif") + FLAG(res_8000_000a.ebx & (1 << 0), "npt") FLAG(res_8000_000a.ebx & (1 << 1), "lbrv") FLAG(res_8000_000a.ebx & (1 << 2), "svm_lock") + FLAG(res_8000_000a.ebx & (1 << 3), "nrip_save") FLAG(res_8000_000a.ebx & (1 << 4), "tsc_scale") + FLAG(res_8000_000a.ebx & (1 << 5), "vmcb_clean") FLAG(res_8000_000a.ebx & (1 << 6), "flushbyasid") + FLAG(res_8000_000a.ebx & (1 << 7), "decodeassists") FLAG(res_8000_000a.ebx & (1 << 10), "pausefilter") + FLAG(res_8000_000a.ebx & (1 << 12), "pfthreshold") FLAG(res_8000_000a.ebx & (1 << 13), "avic") + FLAG(res_8000_000a.ebx & (1 << 15), "v_vmsave_vmload") FLAG(res_8000_000a.ebx & (1 << 16), "vgif") - FLAG(res_7.ecx & (1 << 1), - "avx512vbmi") - FLAG(res_7.ecx & (1 << 2), - "umip") - FLAG(res_7.ecx & (1 << 3), - "pku") - FLAG(res_7.ecx & (1 << 4), - "ospke") - FLAG(res_7.ecx & (1 << 5), - "waitpkg") - FLAG(res_7.ecx & (1 << 6), - "avx512_vbmi2") - FLAG(res_7.ecx & (1 << 8), - "gfni") - FLAG(res_7.ecx & (1 << 9), - "vaes") - FLAG(res_7.ecx & (1 << 10), - "vpclmulqdq") - FLAG(res_7.ecx & (1 << 11), - "avx512_vnni") - FLAG(res_7.ecx & (1 << 12), - "avx512_bitalg") - FLAG(res_7.ecx & (1 << 13), - "tme") - FLAG(res_7.ecx & (1 << 14), - "avx512_vpopcntdq") - FLAG(res_7.ecx & (1 << 16), - "la57") - FLAG(res_7.ecx & (1 << 22), - "rdpid") - FLAG(res_7.ecx & (1 << 25), - "cldemote") - FLAG(res_7.ecx & (1 << 27), - "movdiri") - FLAG(res_7.ecx & (1 << 28), - "movdir64b") + FLAG(res_7.ecx & (1 << 1), "avx512vbmi") FLAG(res_7.ecx & (1 << 2), "umip") FLAG(res_7.ecx & (1 << 3), "pku") + FLAG(res_7.ecx & (1 << 4), "ospke") FLAG(res_7.ecx & (1 << 5), "waitpkg") FLAG(res_7.ecx & (1 << 6), "avx512_vbmi2") + FLAG(res_7.ecx & (1 << 8), "gfni") FLAG(res_7.ecx & (1 << 9), "vaes") FLAG(res_7.ecx & (1 << 10), "vpclmulqdq") + FLAG(res_7.ecx & (1 << 11), "avx512_vnni") FLAG(res_7.ecx & (1 << 12), "avx512_bitalg") + FLAG(res_7.ecx & (1 << 13), "tme") FLAG(res_7.ecx & (1 << 14), "avx512_vpopcntdq") + FLAG(res_7.ecx & (1 << 16), "la57") FLAG(res_7.ecx & (1 << 22), "rdpid") FLAG(res_7.ecx & (1 << 25), "cldemot" + "e") + FLAG(res_7.ecx & (1 << 27), "movdiri") FLAG(res_7.ecx & (1 << 28), "movdir64b") - FLAG(res_8000_0007.ebx & (1 << 0), - "overflow_recov") - FLAG(res_8000_0007.ebx & (1 << 1), - "succor") - FLAG(res_8000_0007.ebx & (1 << 3), - "smca") + FLAG(res_8000_0007.ebx & (1 << 0), "overflow_recov") FLAG(res_8000_0007.ebx & (1 << 1), "succor") + FLAG(res_8000_0007.ebx & (1 << 3), "smca") - FLAG(res_7.edx & (1 << 2), - "avx512_4vnniw") - FLAG(res_7.edx & (1 << 3), - "avx512_4fmaps") - FLAG(res_7.edx & (1 << 4), - "fsrm") - FLAG(res_7.edx & (1 << 8), - "avx512_vp2intersect") - FLAG(res_7.edx & (1 << 10), - "md_clear") - FLAG(res_7.edx & (1 << 14), - "serialize") - FLAG(res_7.edx & (1 << 18), - "pconfig") - FLAG(res_7.edx & (1 << 19), - "arch_lbr") - FLAG(res_7.edx & (1 << 28), - "flush_l1d") - FLAG(res_7.edx & (1 << 29), - "arch_capabilities") - } - - for (int i = 0; i < CPUCores; ++i) { - cpu_stream << "processor\t: " << i << std::endl; // Logical id - cpu_stream << "vendor_id\t: " << vendorid.Str << std::endl; - cpu_stream << "cpu family\t: " << Family << std::endl; - cpu_stream << "model\t\t: " << (info.Model + (info.FamilyID >= 6 ? (info.ExModelID << 4) : 0)) << std::endl; - ModelName modelname {}; - auto res_8000_0002 = ctx->RunCPUIDFunctionName(0x8000'0002, 0, i); - auto res_8000_0003 = ctx->RunCPUIDFunctionName(0x8000'0003, 0, i); - auto res_8000_0004 = ctx->RunCPUIDFunctionName(0x8000'0004, 0, i); - modelname.cpuid_2 = res_8000_0002; - modelname.cpuid_3 = res_8000_0003; - modelname.cpuid_4 = res_8000_0004; - modelname.null = 0; - - cpu_stream << "model name\t: " << modelname.Str << std::endl; - cpu_stream << "stepping\t: " << info.Stepping << std::endl; - cpu_stream << "microcode\t: 0x0" << std::endl; - cpu_stream << "cpu MHz\t\t: 3000" << std::endl; - cpu_stream << "cache size\t: 512 KB" << std::endl; - cpu_stream << "physical id\t: 0" << std::endl; // Socket id (always 0 for a single socket system) - cpu_stream << "siblings\t: " << CPUCores << std::endl; // Number of logical cores - cpu_stream << "core id\t\t: " << i << std::endl; // Physical id - cpu_stream << "cpu cores\t: " << CPUCores << std::endl; // Number of physical cores - cpu_stream << "apicid\t\t: " << i << std::endl; - cpu_stream << "initial apicid\t: " << i << std::endl; - cpu_stream << "fpu\t\t: " << (res_1.edx & (1 << 0) ? "yes" : "no") << std::endl; - cpu_stream << "fpu_exception\t: " << (res_1.edx & (1 << 0) ? "yes" : "no") << std::endl; - cpu_stream << "cpuid level\t: " << vendorid.id << std::endl; - cpu_stream << "wp\t\t: yes" << std::endl; - cpu_stream << "flags\t\t: " << flags_data.str() << std::endl; - - // We don't have any bugs, don't question it - cpu_stream << "bugs\t\t: " << std::endl; - cpu_stream << "bogomips\t: 8000.0" << std::endl; - // These next four aren't necessarily correct - cpu_stream << "TLB size\t: 2560 4K pages" << std::endl; - cpu_stream << "clflush size\t: 64" << std::endl; - cpu_stream << "cache_alignment\t : 64" << std::endl; - - // Cortex-A is 40 or 44 bits physical, and 48/52 virtual - // Choose the lesser configuration - cpu_stream << "address sizes\t: 40 bits physical, 48 bits virtual" << std::endl; - - // No power management but required to report - cpu_stream << "power management: " << std::endl; - - cpu_stream << std::endl; - } - - return cpu_stream.str(); + FLAG(res_7.edx & (1 << 2), "avx512_4vnniw") FLAG(res_7.edx & (1 << 3), "avx512_4fmaps") + FLAG(res_7.edx & (1 << 4), "fsrm") FLAG(res_7.edx & (1 << 8), "avx512_vp2intersect") + FLAG(res_7.edx & (1 << 10), "md_clear") FLAG(res_7.edx & (1 << 14), "serialize") + FLAG(res_7.edx & (1 << 18), "pconfig") FLAG(res_7.edx & (1 << 19), "arch_lbr") + FLAG(res_7.edx & (1 << 28), "flush_l1d") FLAG(res_7.edx & (1 << 29), "arch_capabilities") } - EmulatedFDManager::EmulatedFDManager(FEXCore::Context::Context *ctx) - : CTX {ctx} - , ThreadsConfig { FEXCore::CPUInfo::CalculateNumberOfCPUs() } { - FDReadCreators["/proc/cpuinfo"] = [&](FEXCore::Context::Context *ctx, int32_t fd, const char *pathname, int32_t flags, mode_t mode) -> int32_t { - // Only allow a single thread to initialize the cpu_info. - // Jit in-case multiple threads try to initialize at once. - // Check if deferred cpuinfo initialization has occured. - std::call_once(cpu_info_initialized, [&]() { cpu_info = GenerateCPUInfo(ctx, ThreadsConfig); }); + for (int i = 0; i < CPUCores; ++i) { + cpu_stream << "processor\t: " << i << std::endl; // Logical id + cpu_stream << "vendor_id\t: " << vendorid.Str << std::endl; + cpu_stream << "cpu family\t: " << Family << std::endl; + cpu_stream << "model\t\t: " << (info.Model + (info.FamilyID >= 6 ? (info.ExModelID << 4) : 0)) << std::endl; + ModelName modelname {}; + auto res_8000_0002 = ctx->RunCPUIDFunctionName(0x8000'0002, 0, i); + auto res_8000_0003 = ctx->RunCPUIDFunctionName(0x8000'0003, 0, i); + auto res_8000_0004 = ctx->RunCPUIDFunctionName(0x8000'0004, 0, i); + modelname.cpuid_2 = res_8000_0002; + modelname.cpuid_3 = res_8000_0003; + modelname.cpuid_4 = res_8000_0004; + modelname.null = 0; - int FD = GenTmpFD(pathname, flags); - write(FD, (void*)&cpu_info.at(0), cpu_info.size()); - lseek(FD, 0, SEEK_SET); - SealTmpFD(FD); - return FD; - }; + cpu_stream << "model name\t: " << modelname.Str << std::endl; + cpu_stream << "stepping\t: " << info.Stepping << std::endl; + cpu_stream << "microcode\t: 0x0" << std::endl; + cpu_stream << "cpu MHz\t\t: 3000" << std::endl; + cpu_stream << "cache size\t: 512 KB" << std::endl; + cpu_stream << "physical id\t: 0" << std::endl; // Socket id (always 0 for a single socket system) + cpu_stream << "siblings\t: " << CPUCores << std::endl; // Number of logical cores + cpu_stream << "core id\t\t: " << i << std::endl; // Physical id + cpu_stream << "cpu cores\t: " << CPUCores << std::endl; // Number of physical cores + cpu_stream << "apicid\t\t: " << i << std::endl; + cpu_stream << "initial apicid\t: " << i << std::endl; + cpu_stream << "fpu\t\t: " << (res_1.edx & (1 << 0) ? "yes" : "no") << std::endl; + cpu_stream << "fpu_exception\t: " << (res_1.edx & (1 << 0) ? "yes" : "no") << std::endl; + cpu_stream << "cpuid level\t: " << vendorid.id << std::endl; + cpu_stream << "wp\t\t: yes" << std::endl; + cpu_stream << "flags\t\t: " << flags_data.str() << std::endl; - FDReadCreators["/proc/sys/kernel/osrelease"] = [&](FEXCore::Context::Context *ctx, int32_t fd, const char *pathname, int32_t flags, mode_t mode) -> int32_t { - int FD = GenTmpFD(pathname, flags); - uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - char Tmp[64]{}; - snprintf(Tmp, sizeof(Tmp), "%d.%d.%d\n", - FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), - FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); - // + 1 to ensure null at the end - write(FD, Tmp, strlen(Tmp) + 1); - lseek(FD, 0, SEEK_SET); - SealTmpFD(FD); - return FD; - }; + // We don't have any bugs, don't question it + cpu_stream << "bugs\t\t: " << std::endl; + cpu_stream << "bogomips\t: 8000.0" << std::endl; + // These next four aren't necessarily correct + cpu_stream << "TLB size\t: 2560 4K pages" << std::endl; + cpu_stream << "clflush size\t: 64" << std::endl; + cpu_stream << "cache_alignment\t : 64" << std::endl; - FDReadCreators["/proc/version"] = [&](FEXCore::Context::Context *ctx, int32_t fd, const char *pathname, int32_t flags, mode_t mode) -> int32_t { - int FD = GenTmpFD(pathname, flags); - // UTS version NEEDS to be in a format that can pass to `date -d` - // Format of this is Linux version (@) () # {SMP, PREEMPT, PREEMPT_RT} \n" - const char kernel_version[] = "Linux version %d.%d.%d (FEX@FEX) (clang) #" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__ "\n"; - uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - char Tmp[sizeof(kernel_version) + 64]{}; - snprintf(Tmp, sizeof(Tmp), kernel_version, - FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), - FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); - // + 1 to ensure null at the end - write(FD, Tmp, strlen(Tmp) + 1); - lseek(FD, 0, SEEK_SET); - SealTmpFD(FD); - return FD; - }; + // Cortex-A is 40 or 44 bits physical, and 48/52 virtual + // Choose the lesser configuration + cpu_stream << "address sizes\t: 40 bits physical, 48 bits virtual" << std::endl; - auto NumCPUCores = [&](FEXCore::Context::Context *ctx, int32_t fd, const char *pathname, int32_t flags, mode_t mode) -> int32_t { - int FD = GenTmpFD(pathname, flags); - write(FD, (void*)&cpus_online.at(0), cpus_online.size()); - lseek(FD, 0, SEEK_SET); - SealTmpFD(FD); - return FD; - }; + // No power management but required to report + cpu_stream << "power management: " << std::endl; - FDReadCreators["/sys/devices/system/cpu/online"] = NumCPUCores; - FDReadCreators["/sys/devices/system/cpu/present"] = NumCPUCores; - - fextl::string procAuxv = fextl::fmt::format("/proc/{}/auxv", getpid()); - - FDReadCreators[procAuxv] = &EmulatedFDManager::ProcAuxv; - FDReadCreators["/proc/self/auxv"] = &EmulatedFDManager::ProcAuxv; - - auto cmdline_handler = [&](FEXCore::Context::Context *ctx, int32_t fd, const char *pathname, int32_t flags, mode_t mode) -> int32_t { - int FD = GenTmpFD(pathname, flags); - auto CodeLoader = FEX::HLE::_SyscallHandler->GetCodeLoader(); - auto Args = CodeLoader->GetApplicationArguments(); - char NullChar{}; - // cmdline is an array of null terminated arguments - for (size_t i = 0; i < Args->size(); ++i) { - auto &Arg = Args->at(i); - write(FD, Arg.c_str(), Arg.size()); - // Finish off with a null terminator - write(FD, &NullChar, sizeof(uint8_t)); - } - - // One additional null terminator to finish the list - lseek(FD, 0, SEEK_SET); - SealTmpFD(FD); - return FD; - }; - - FDReadCreators["/proc/self/cmdline"] = cmdline_handler; - fextl::string procCmdLine = fextl::fmt::format("/proc/{}/cmdline", getpid()); - FDReadCreators[procCmdLine] = cmdline_handler; - - if (ThreadsConfig > 1) { - cpus_online = fextl::fmt::format("0-{}", ThreadsConfig - 1); - } - else { - cpus_online = "0"; - } + cpu_stream << std::endl; } - EmulatedFDManager::~EmulatedFDManager() { - } + return cpu_stream.str(); +} - int32_t EmulatedFDManager::OpenAt(int dirfs, const char *pathname, int flags, uint32_t mode) { - char Tmp[PATH_MAX]; - const char *Path{}; - - auto Creator = FDReadCreators.end(); - if (pathname) { - Creator = FDReadCreators.find(pathname); - Path = pathname; - } - - if (Creator == FDReadCreators.end()) { - if (((pathname && pathname[0] != '/') || // If pathname exists then it must not be absolute - !pathname) && - dirfs != AT_FDCWD) { - // Passed in a dirfd that isn't magic FDCWD - // We need to get the path from the fd now - auto PathLength = FEX::get_fdpath(dirfs, Tmp); - if (PathLength != -1) { - if (pathname) { - Tmp[PathLength] = '/'; - PathLength += 1; - strncpy(&Tmp[PathLength], pathname, PATH_MAX - PathLength); - } - else { - Tmp[PathLength] = '\0'; - } - Path = Tmp; - } - else if (pathname) { - Path = pathname; - } - } - else { - if (!pathname || pathname[0] == 0) { - return -1; - } - - Path = pathname; - } - - bool exists = access(Path, F_OK) == 0; - bool RealPathExists = false; - - if (exists) { - // If realpath fails then the temporary buffer is in an undefined state. - // Need to use another temporary just in-case realpath doesn't succeed. - char ExistsTempPath[PATH_MAX]; - char *RealPath = realpath(Path, ExistsTempPath); - if (RealPath) { - RealPathExists = true; - Creator = FDReadCreators.find(RealPath); - } - } - - if (!RealPathExists) { - Creator = FDReadCreators.find(FHU::Filesystem::LexicallyNormal(Path)); - } - - if (Creator == FDReadCreators.end()) { - return -1; - } - } - - return Creator->second(CTX, dirfs, Path, flags, mode); - } - - int32_t EmulatedFDManager::ProcAuxv(FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) - { - uint64_t auxvBase=0, auxvSize=0; - FEX::HLE::_SyscallHandler->GetCodeLoader()->GetAuxv(auxvBase, auxvSize); - if (!auxvBase) { - LogMan::Msg::DFmt("Failed to get Auxv stack address"); - return -1; - } +EmulatedFDManager::EmulatedFDManager(FEXCore::Context::Context* ctx) + : CTX {ctx} + , ThreadsConfig {FEXCore::CPUInfo::CalculateNumberOfCPUs()} { + FDReadCreators["/proc/cpuinfo"] = [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) -> int32_t { + // Only allow a single thread to initialize the cpu_info. + // Jit in-case multiple threads try to initialize at once. + // Check if deferred cpuinfo initialization has occured. + std::call_once(cpu_info_initialized, [&]() { cpu_info = GenerateCPUInfo(ctx, ThreadsConfig); }); int FD = GenTmpFD(pathname, flags); - write(FD, (void*)auxvBase, auxvSize); + write(FD, (void*)&cpu_info.at(0), cpu_info.size()); lseek(FD, 0, SEEK_SET); SealTmpFD(FD); return FD; + }; + + FDReadCreators["/proc/sys/kernel/osrelease"] = [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, + mode_t mode) -> int32_t { + int FD = GenTmpFD(pathname, flags); + uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); + char Tmp[64] {}; + snprintf(Tmp, sizeof(Tmp), "%d.%d.%d\n", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), + FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + // + 1 to ensure null at the end + write(FD, Tmp, strlen(Tmp) + 1); + lseek(FD, 0, SEEK_SET); + SealTmpFD(FD); + return FD; + }; + + FDReadCreators["/proc/version"] = [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) -> int32_t { + int FD = GenTmpFD(pathname, flags); + // UTS version NEEDS to be in a format that can pass to `date -d` + // Format of this is Linux version (@) () # {SMP, PREEMPT, PREEMPT_RT} \n" + const char kernel_version[] = "Linux version %d.%d.%d (FEX@FEX) (clang) #" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__ "\n"; + uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); + char Tmp[sizeof(kernel_version) + 64] {}; + snprintf(Tmp, sizeof(Tmp), kernel_version, FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), + FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + // + 1 to ensure null at the end + write(FD, Tmp, strlen(Tmp) + 1); + lseek(FD, 0, SEEK_SET); + SealTmpFD(FD); + return FD; + }; + + auto NumCPUCores = [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) -> int32_t { + int FD = GenTmpFD(pathname, flags); + write(FD, (void*)&cpus_online.at(0), cpus_online.size()); + lseek(FD, 0, SEEK_SET); + SealTmpFD(FD); + return FD; + }; + + FDReadCreators["/sys/devices/system/cpu/online"] = NumCPUCores; + FDReadCreators["/sys/devices/system/cpu/present"] = NumCPUCores; + + fextl::string procAuxv = fextl::fmt::format("/proc/{}/auxv", getpid()); + + FDReadCreators[procAuxv] = &EmulatedFDManager::ProcAuxv; + FDReadCreators["/proc/self/auxv"] = &EmulatedFDManager::ProcAuxv; + + auto cmdline_handler = [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) -> int32_t { + int FD = GenTmpFD(pathname, flags); + auto CodeLoader = FEX::HLE::_SyscallHandler->GetCodeLoader(); + auto Args = CodeLoader->GetApplicationArguments(); + char NullChar {}; + // cmdline is an array of null terminated arguments + for (size_t i = 0; i < Args->size(); ++i) { + auto& Arg = Args->at(i); + write(FD, Arg.c_str(), Arg.size()); + // Finish off with a null terminator + write(FD, &NullChar, sizeof(uint8_t)); + } + + // One additional null terminator to finish the list + lseek(FD, 0, SEEK_SET); + SealTmpFD(FD); + return FD; + }; + + FDReadCreators["/proc/self/cmdline"] = cmdline_handler; + fextl::string procCmdLine = fextl::fmt::format("/proc/{}/cmdline", getpid()); + FDReadCreators[procCmdLine] = cmdline_handler; + + if (ThreadsConfig > 1) { + cpus_online = fextl::fmt::format("0-{}", ThreadsConfig - 1); + } else { + cpus_online = "0"; } } +EmulatedFDManager::~EmulatedFDManager() {} + +int32_t EmulatedFDManager::OpenAt(int dirfs, const char* pathname, int flags, uint32_t mode) { + char Tmp[PATH_MAX]; + const char* Path {}; + + auto Creator = FDReadCreators.end(); + if (pathname) { + Creator = FDReadCreators.find(pathname); + Path = pathname; + } + + if (Creator == FDReadCreators.end()) { + if (((pathname && pathname[0] != '/') || // If pathname exists then it must not be absolute + !pathname) && + dirfs != AT_FDCWD) { + // Passed in a dirfd that isn't magic FDCWD + // We need to get the path from the fd now + auto PathLength = FEX::get_fdpath(dirfs, Tmp); + if (PathLength != -1) { + if (pathname) { + Tmp[PathLength] = '/'; + PathLength += 1; + strncpy(&Tmp[PathLength], pathname, PATH_MAX - PathLength); + } else { + Tmp[PathLength] = '\0'; + } + Path = Tmp; + } else if (pathname) { + Path = pathname; + } + } else { + if (!pathname || pathname[0] == 0) { + return -1; + } + + Path = pathname; + } + + bool exists = access(Path, F_OK) == 0; + bool RealPathExists = false; + + if (exists) { + // If realpath fails then the temporary buffer is in an undefined state. + // Need to use another temporary just in-case realpath doesn't succeed. + char ExistsTempPath[PATH_MAX]; + char* RealPath = realpath(Path, ExistsTempPath); + if (RealPath) { + RealPathExists = true; + Creator = FDReadCreators.find(RealPath); + } + } + + if (!RealPathExists) { + Creator = FDReadCreators.find(FHU::Filesystem::LexicallyNormal(Path)); + } + + if (Creator == FDReadCreators.end()) { + return -1; + } + } + + return Creator->second(CTX, dirfs, Path, flags, mode); +} + +int32_t EmulatedFDManager::ProcAuxv(FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) { + uint64_t auxvBase = 0, auxvSize = 0; + FEX::HLE::_SyscallHandler->GetCodeLoader()->GetAuxv(auxvBase, auxvSize); + if (!auxvBase) { + LogMan::Msg::DFmt("Failed to get Auxv stack address"); + return -1; + } + + int FD = GenTmpFD(pathname, flags); + write(FD, (void*)auxvBase, auxvSize); + lseek(FD, 0, SEEK_SET); + SealTmpFD(FD); + return FD; +} +} // namespace FEX::EmulatedFile diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.h index 71a46c21e..a1ce479af 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.h @@ -15,25 +15,25 @@ $end_info$ #include namespace FEXCore::Context { - class Context; +class Context; } namespace FEX::EmulatedFile { - class EmulatedFDManager { - public: - EmulatedFDManager(FEXCore::Context::Context *ctx); - ~EmulatedFDManager(); - int32_t OpenAt(int dirfs, const char *pathname, int flags, uint32_t mode); +class EmulatedFDManager { +public: + EmulatedFDManager(FEXCore::Context::Context* ctx); + ~EmulatedFDManager(); + int32_t OpenAt(int dirfs, const char* pathname, int flags, uint32_t mode); - private: - FEXCore::Context::Context *CTX; - fextl::string cpus_online{}; - std::once_flag cpu_info_initialized{}; - fextl::string cpu_info{}; - using FDReadStringFunc = std::function; - fextl::unordered_map FDReadCreators; +private: + FEXCore::Context::Context* CTX; + fextl::string cpus_online {}; + std::once_flag cpu_info_initialized {}; + fextl::string cpu_info {}; + using FDReadStringFunc = std::function; + fextl::unordered_map FDReadCreators; - static int32_t ProcAuxv(FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode); - const uint32_t ThreadsConfig; - }; -} + static int32_t ProcAuxv(FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode); + const uint32_t ThreadsConfig; +}; +} // namespace FEX::EmulatedFile diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/FaultSafeMemcpy.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/FaultSafeMemcpy.cpp index 63954f5f9..f4abf5b25 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/FaultSafeMemcpy.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/FaultSafeMemcpy.cpp @@ -3,8 +3,7 @@ namespace FEX::HLE::FaultSafeMemcpy { #ifdef _M_ARM_64 -__attribute__((naked)) -size_t CopyFromUser(void *Dest, const void* Src, size_t Size) { +__attribute__((naked)) size_t CopyFromUser(void* Dest, const void* Src, size_t Size) { __asm volatile(R"( // Early exit if a memcpy of size zero. cbz x2, 2f; @@ -19,12 +18,11 @@ size_t CopyFromUser(void *Dest, const void* Src, size_t Size) { 2: mov x0, 0; ret; - )" - ::: "memory"); + )" :: + : "memory"); } -__attribute__((naked)) -size_t CopyToUser(void *Dest, const void* Src, size_t Size) { +__attribute__((naked)) size_t CopyToUser(void* Dest, const void* Src, size_t Size) { __asm volatile(R"( // Early exit if a memcpy of size zero. cbz x2, 2f; @@ -39,28 +37,27 @@ size_t CopyToUser(void *Dest, const void* Src, size_t Size) { 2: mov x0, 0; ret; - )" - ::: "memory"); + )" :: + : "memory"); } extern "C" uint64_t CopyFromUser_FaultInst; -void * const CopyFromUser_FaultLocation = &CopyFromUser_FaultInst; +void* const CopyFromUser_FaultLocation = &CopyFromUser_FaultInst; extern "C" uint64_t CopyToUser_FaultInst; -void * const CopyToUser_FaultLocation = &CopyToUser_FaultInst; +void* const CopyToUser_FaultLocation = &CopyToUser_FaultInst; bool IsFaultLocation(uint64_t PC) { - return reinterpret_cast(PC) == CopyFromUser_FaultLocation || - reinterpret_cast(PC) == CopyToUser_FaultLocation; + return reinterpret_cast(PC) == CopyFromUser_FaultLocation || reinterpret_cast(PC) == CopyToUser_FaultLocation; } #else -size_t CopyFromUser(void *Dest, const void* Src, size_t Size) { +size_t CopyFromUser(void* Dest, const void* Src, size_t Size) { memcpy(Dest, Src, Size); return Size; } -size_t CopyToUser(void *Dest, const void* Src, size_t Size) { +size_t CopyToUser(void* Dest, const void* Src, size_t Size) { memcpy(Dest, Src, Size); return Size; } @@ -69,4 +66,4 @@ bool IsFaultLocation(uint64_t PC) { return false; } #endif -} +} // namespace FEX::HLE::FaultSafeMemcpy diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp index 75941f9e3..bd74e64d7 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp @@ -43,24 +43,24 @@ $end_info$ #include namespace JSON { - struct JsonAllocator { - jsonPool_t PoolObject; - fextl::unique_ptr> json_objects; - }; - static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero"); +struct JsonAllocator { + jsonPool_t PoolObject; + fextl::unique_ptr> json_objects; +}; +static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero"); - json_t* PoolInit(jsonPool_t* Pool) { - JsonAllocator* alloc = reinterpret_cast(Pool); - alloc->json_objects = fextl::make_unique>(); - return &*alloc->json_objects->emplace(alloc->json_objects->end()); - } - - json_t* PoolAlloc(jsonPool_t* Pool) { - JsonAllocator* alloc = reinterpret_cast(Pool); - return &*alloc->json_objects->emplace(alloc->json_objects->end()); - } +json_t* PoolInit(jsonPool_t* Pool) { + JsonAllocator* alloc = reinterpret_cast(Pool); + alloc->json_objects = fextl::make_unique>(); + return &*alloc->json_objects->emplace(alloc->json_objects->end()); } +json_t* PoolAlloc(jsonPool_t* Pool) { + JsonAllocator* alloc = reinterpret_cast(Pool); + return &*alloc->json_objects->emplace(alloc->json_objects->end()); +} +} // namespace JSON + namespace FEX::HLE { bool FileManager::RootFSPathExists(const char* Filepath) { LOGMAN_THROW_A_FMT(Filepath && Filepath[0] == '/', "Filepath needs to be absolute"); @@ -74,10 +74,9 @@ void FileManager::LoadThunkDatabase(fextl::unordered_map PathPrefixes{}; + fextl::vector PathPrefixes {}; if (RootFSIsMultiarch) { // Multi-arch debian distros have a fairly complex arrangement of filepaths. // These fractal out to the combination of library prefixes with arch suffixes. @@ -89,15 +88,12 @@ void FileManager::LoadThunkDatabase(fextl::unordered_mapsecond.LibraryName = json_getValue(LibraryItem); - } - else if (ItemName == "Depends") { + } else if (ItemName == "Depends") { jsonType_t PropertyType = json_getType(LibraryItem); if (PropertyType == JSON_TEXT) { DBObject->second.Depends.insert(json_getValue(LibraryItem)); - } - else if (PropertyType == JSON_ARRAY) { - for (json_t const* Depend = json_getChild(LibraryItem); Depend != nullptr; Depend = json_getSibling(Depend)) { + } else if (PropertyType == JSON_ARRAY) { + for (const json_t* Depend = json_getChild(LibraryItem); Depend != nullptr; Depend = json_getSibling(Depend)) { DBObject->second.Depends.insert(json_getValue(Depend)); } } - } - else if (ItemName == "Overlay") { + } else if (ItemName == "Overlay") { auto AddWithReplacement = [HomeDirectory, &PathPrefixes](ThunkDBObject& DBObject, fextl::string LibraryItem) { // Walk through template string and fill in prefixes from right to left using namespace std::string_view_literals; - const std::pair PrefixHome { "@HOME@"sv, LibraryItem.find("@HOME@") }; - const std::pair PrefixLib { "@PREFIX_LIB@"sv, LibraryItem.find("@PREFIX_LIB@") }; + const std::pair PrefixHome {"@HOME@"sv, LibraryItem.find("@HOME@")}; + const std::pair PrefixLib {"@PREFIX_LIB@"sv, LibraryItem.find("@PREFIX_LIB@")}; fextl::string::size_type PrefixPositions[] = { - PrefixHome.second, PrefixLib.second, + PrefixHome.second, + PrefixLib.second, }; // Sort offsets in descending order to enable safe in-place replacement - std::sort(std::begin(PrefixPositions), std::end(PrefixPositions), std::greater<>{}); + std::sort(std::begin(PrefixPositions), std::end(PrefixPositions), std::greater<> {}); for (auto& LibPrefix : PathPrefixes) { fextl::string Replacement = LibraryItem; @@ -195,9 +188,8 @@ void FileManager::LoadThunkDatabase(fextl::unordered_mapsecond, json_getValue(LibraryItem)); - } - else if (PropertyType == JSON_ARRAY) { - for (json_t const* Overlay = json_getChild(LibraryItem); Overlay != nullptr; Overlay = json_getSibling(Overlay)) { + } else if (PropertyType == JSON_ARRAY) { + for (const json_t* Overlay = json_getChild(LibraryItem); Overlay != nullptr; Overlay = json_getSibling(Overlay)) { AddWithReplacement(DBObject->second, json_getValue(Overlay)); } } @@ -207,7 +199,7 @@ void FileManager::LoadThunkDatabase(fextl::unordered_map FileData; if (FEXCore::FileLoading::LoadFile(FileData, Path)) { JSON::JsonAllocator Pool { - .PoolObject = { - .init = JSON::PoolInit, - .alloc = JSON::PoolAlloc, - }, + .PoolObject = + { + .init = JSON::PoolInit, + .alloc = JSON::PoolAlloc, + }, }; // If a thunks DB property exists then we pull in data from the thunks database - json_t const *json = json_createWithPool(&FileData.at(0), &Pool.PoolObject); - json_t const* ThunksDB = json_getProperty( json, "ThunksDB" ); + const json_t* json = json_createWithPool(&FileData.at(0), &Pool.PoolObject); + const json_t* ThunksDB = json_getProperty(json, "ThunksDB"); if (!ThunksDB) { continue; } - for (json_t const* Item = json_getChild(ThunksDB); Item != nullptr; Item = json_getSibling(Item)) { - const char *LibraryName = json_getName(Item); + for (const json_t* Item = json_getChild(ThunksDB); Item != nullptr; Item = json_getSibling(Item)) { + const char* LibraryName = json_getName(Item); bool LibraryEnabled = json_getInteger(Item) != 0; // If the library is enabled then find it in the DB auto DBObject = ThunkDB.find(LibraryName); @@ -295,8 +286,8 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) } // Now that we loaded the thunks object, walk through and ensure dependencies are enabled as well - auto ThunkGuestPath = Is64BitMode() ? ThunkGuestLibs() : ThunkGuestLibs32() ; - for (auto const &DBObject : ThunkDB) { + auto ThunkGuestPath = Is64BitMode() ? ThunkGuestLibs() : ThunkGuestLibs32(); + for (const auto& DBObject : ThunkDB) { if (!DBObject.second.Enabled) { continue; } @@ -310,23 +301,23 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) bool Is64BitMode; void SetupOverlay(const ThunkDBObject& DBDepend) { - auto ThunkPath = fextl::fmt::format("{}/{}", ThunkGuestPath, DBDepend.LibraryName); - if (!FHU::Filesystem::Exists(ThunkPath)) { - if (!Is64BitMode) { - // Guest libraries not existing is expected since not all libraries are thunked on 32-bit - return; - } - ERROR_AND_DIE_FMT("Requested thunking via guest library \"{}\" that does not exist", ThunkPath); + auto ThunkPath = fextl::fmt::format("{}/{}", ThunkGuestPath, DBDepend.LibraryName); + if (!FHU::Filesystem::Exists(ThunkPath)) { + if (!Is64BitMode) { + // Guest libraries not existing is expected since not all libraries are thunked on 32-bit + return; } + ERROR_AND_DIE_FMT("Requested thunking via guest library \"{}\" that does not exist", ThunkPath); + } - for (const auto& Overlay : DBDepend.Overlays) { - // Direct full path in guest RootFS to our overlay file - ThunkOverlays.emplace(Overlay, ThunkPath); - } + for (const auto& Overlay : DBDepend.Overlays) { + // Direct full path in guest RootFS to our overlay file + ThunkOverlays.emplace(Overlay, ThunkPath); + } }; - void InsertDependencies(const fextl::unordered_set &Depends) { - for (auto const &Depend : Depends) { + void InsertDependencies(const fextl::unordered_set& Depends) { + for (const auto& Depend : Depends) { auto& DBDepend = ThunkDB.at(Depend); if (DBDepend.Enabled) { continue; @@ -339,7 +330,7 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) InsertDependencies(DBDepend.Depends); } }; - } DBObjectHandler { ThunkOverlays, ThunkDB, ThunkGuestPath, Is64BitMode() }; + } DBObjectHandler {ThunkOverlays, ThunkDB, ThunkGuestPath, Is64BitMode()}; DBObjectHandler.SetupOverlay(DBObject.second); DBObjectHandler.InsertDependencies(DBObject.second.Depends); @@ -388,9 +379,9 @@ FileManager::~FileManager() { close(RootFSFD); } -fextl::string FileManager::GetEmulatedPath(const char *pathname, bool FollowSymlink) { - if (!pathname || // If no pathname - pathname[0] != '/' || // If relative +fextl::string FileManager::GetEmulatedPath(const char* pathname, bool FollowSymlink) { + if (!pathname || // If no pathname + pathname[0] != '/' || // If relative strcmp(pathname, "/") == 0) { // If we are getting root return {}; } @@ -408,13 +399,12 @@ fextl::string FileManager::GetEmulatedPath(const char *pathname, bool FollowSyml fextl::string Path = RootFSPath + pathname; if (FollowSymlink) { char Filename[PATH_MAX]; - while(FEX::HLE::IsSymlink(AT_FDCWD, Path.c_str())) { + while (FEX::HLE::IsSymlink(AT_FDCWD, Path.c_str())) { auto SymlinkSize = FEX::HLE::GetSymlink(AT_FDCWD, Path.c_str(), Filename, PATH_MAX - 1); if (SymlinkSize > 0 && Filename[0] == '/') { Path = RootFSPath; Path += std::string_view(Filename, SymlinkSize); - } - else { + } else { break; } } @@ -422,7 +412,7 @@ fextl::string FileManager::GetEmulatedPath(const char *pathname, bool FollowSyml return Path; } -std::pair FileManager::GetEmulatedFDPath(int dirfd, const char *pathname, bool FollowSymlink, FDPathTmpData &TmpFilename) { +std::pair FileManager::GetEmulatedFDPath(int dirfd, const char* pathname, bool FollowSymlink, FDPathTmpData& TmpFilename) { constexpr auto NoEntry = std::make_pair(-1, nullptr); if (!pathname) { @@ -436,8 +426,8 @@ std::pair FileManager::GetEmulatedFDPath(int dirfd, const char } if (pathname[0] != '/' || // If relative - pathname[1] == 0 || // If we are getting root - dirfd != AT_FDCWD) { // If dirfd isn't special FDCWD + pathname[1] == 0 || // If we are getting root + dirfd != AT_FDCWD) { // If dirfd isn't special FDCWD return NoEntry; } @@ -452,22 +442,22 @@ std::pair FileManager::GetEmulatedFDPath(int dirfd, const char } // Starting subpath is the pathname passed in. - const char *SubPath = pathname; + const char* SubPath = pathname; // Current index for the temporary path to use. - uint32_t CurrentIndex{}; + uint32_t CurrentIndex {}; // The two temporary paths. - const std::array TmpPaths ={ + const std::array TmpPaths = { TmpFilename[0], TmpFilename[1], }; if (FollowSymlink) { // Check if the combination of RootFS FD and subpath with the front '/' stripped off is a symlink. - bool HadAtLeastOne{}; - struct stat Buffer{}; - for(;;) { + bool HadAtLeastOne {}; + struct stat Buffer {}; + for (;;) { // We need to check if the filepath exists and is a symlink. // If the initial filepath doesn't exist then early exit. // If it did exist at some state then trace it all all the way to the final link. @@ -497,15 +487,13 @@ std::pair FileManager::GetEmulatedFDPath(int dirfd, const char CurrentTmp[SymlinkSize] = 0; SubPath = CurrentTmp; CurrentIndex ^= 1; - } - else { + } else { // If the path wasn't a symlink or wasn't absolute. // 1) Break early, returning the previous found result. // 2) If first iteration then we return `pathname`. break; } - } - else { + } else { break; } } @@ -515,7 +503,7 @@ std::pair FileManager::GetEmulatedFDPath(int dirfd, const char return std::make_pair(RootFSFD, &SubPath[1]); } -std::optional FileManager::GetSelf(const char *Pathname) { +std::optional FileManager::GetSelf(const char* Pathname) { if (SupportsProcFSInterpreter) { // FEX doesn't need to track procfs/exe if this is supported. return Pathname; @@ -528,9 +516,7 @@ std::optional FileManager::GetSelf(const char *Pathname) { char PidSelfPath[50]; snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID); - if (strcmp(Pathname, "/proc/self/exe") == 0 || - strcmp(Pathname, "/proc/thread-self/exe") == 0 || - strcmp(Pathname, PidSelfPath) == 0) { + if (strcmp(Pathname, "/proc/self/exe") == 0 || strcmp(Pathname, "/proc/thread-self/exe") == 0 || strcmp(Pathname, PidSelfPath) == 0) { return Filename(); } @@ -556,9 +542,9 @@ static bool ShouldSkipOpenInEmu(int flags) { return false; } -uint64_t FileManager::Open(const char *pathname, int flags, uint32_t mode) { +uint64_t FileManager::Open(const char* pathname, int flags, uint32_t mode) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; int fd = -1; if (!ShouldSkipOpenInEmu(flags)) { @@ -595,8 +581,7 @@ uint64_t FileManager::CloseRange(unsigned int first, unsigned int last, unsigned #define CLOSE_RANGE_CLOEXEC (1U << 2) #endif #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - if (!(flags & CLOSE_RANGE_CLOEXEC) && - CheckIfFDRangeInTrackedSet(first, last)) { + if (!(flags & CLOSE_RANGE_CLOEXEC) && CheckIfFDRangeInTrackedSet(first, last)) { LogMan::Msg::EFmt("{} closing FEX FDs in range ({}, {})", __func__, first, last); RemoveFEXFDRange(first, last); } @@ -605,92 +590,95 @@ uint64_t FileManager::CloseRange(unsigned int first, unsigned int last, unsigned return ::syscall(SYSCALL_DEF(close_range), first, last, flags); } -uint64_t FileManager::Stat(const char *pathname, void *buf) { +uint64_t FileManager::Stat(const char* pathname, void* buf) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; // Stat follows symlinks FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(AT_FDCWD, SelfPath, true, TmpFilename); if (Path.first != -1) { uint64_t Result = ::fstatat(Path.first, Path.second, reinterpret_cast(buf), 0); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::stat(SelfPath, reinterpret_cast(buf)); } -uint64_t FileManager::Lstat(const char *pathname, void *buf) { +uint64_t FileManager::Lstat(const char* pathname, void* buf) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; // lstat does not follow symlinks FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(AT_FDCWD, SelfPath, false, TmpFilename); if (Path.first != -1) { uint64_t Result = ::fstatat(Path.first, Path.second, reinterpret_cast(buf), AT_SYMLINK_NOFOLLOW); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::lstat(pathname, reinterpret_cast(buf)); } -uint64_t FileManager::Access(const char *pathname, [[maybe_unused]] int mode) { +uint64_t FileManager::Access(const char* pathname, [[maybe_unused]] int mode) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; // Access follows symlinks FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(AT_FDCWD, SelfPath, true, TmpFilename); if (Path.first != -1) { uint64_t Result = ::faccessat(Path.first, Path.second, mode, 0); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::access(SelfPath, mode); } -uint64_t FileManager::FAccessat(int dirfd, const char *pathname, int mode) { +uint64_t FileManager::FAccessat(int dirfd, const char* pathname, int mode) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(dirfd, SelfPath, true, TmpFilename); if (Path.first != -1) { uint64_t Result = ::syscall(SYSCALL_DEF(faccessat), Path.first, Path.second, mode); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::syscall(SYS_faccessat, dirfd, SelfPath, mode); } -uint64_t FileManager::FAccessat2(int dirfd, const char *pathname, int mode, int flags) { +uint64_t FileManager::FAccessat2(int dirfd, const char* pathname, int mode, int flags) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(dirfd, SelfPath, (flags & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); if (Path.first != -1) { uint64_t Result = ::syscall(SYSCALL_DEF(faccessat2), Path.first, Path.second, mode, flags); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::syscall(SYSCALL_DEF(faccessat2), dirfd, SelfPath, mode, flags); } -uint64_t FileManager::Readlink(const char *pathname, char *buf, size_t bufsiz) { +uint64_t FileManager::Readlink(const char* pathname, char* buf, size_t bufsiz) { if (!SupportsProcFSInterpreter) { // calculate the non-self link to exe // Some executables do getpid, stat("/proc/$pid/exe") char PidSelfPath[50]; snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID); - if (strcmp(pathname, "/proc/self/exe") == 0 || - strcmp(pathname, "/proc/thread-self/exe") == 0 || - strcmp(pathname, PidSelfPath) == 0) { + if (strcmp(pathname, "/proc/self/exe") == 0 || strcmp(pathname, "/proc/thread-self/exe") == 0 || strcmp(pathname, PidSelfPath) == 0) { auto App = Filename(); strncpy(buf, App.c_str(), bufsiz); return std::min(bufsiz, App.size()); @@ -701,11 +689,11 @@ uint64_t FileManager::Readlink(const char *pathname, char *buf, size_t bufsiz) { auto Path = GetEmulatedFDPath(AT_FDCWD, pathname, false, TmpFilename); if (Path.first != -1) { uint64_t Result = ::readlinkat(Path.first, Path.second, buf, bufsiz); - if (Result != -1) + if (Result != -1) { return Result; + } - if (Result == -1 && - errno == EINVAL) { + if (Result == -1 && errno == EINVAL) { // This means that the file wasn't a symlink // This is expected behaviour return -errno; @@ -715,30 +703,31 @@ uint64_t FileManager::Readlink(const char *pathname, char *buf, size_t bufsiz) { return ::readlink(pathname, buf, bufsiz); } -uint64_t FileManager::Chmod(const char *pathname, mode_t mode) { +uint64_t FileManager::Chmod(const char* pathname, mode_t mode) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(AT_FDCWD, SelfPath, false, TmpFilename); if (Path.first != -1) { uint64_t Result = ::fchmodat(Path.first, Path.second, mode, 0); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::chmod(SelfPath, mode); } -uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { +uint64_t FileManager::Readlinkat(int dirfd, const char* pathname, char* buf, size_t bufsiz) { // calculate the non-self link to exe // Some executables do getpid, stat("/proc/$pid/exe") // Can't use `GetSelf` directly here since readlink{at,} returns EINVAL if it isn't a symlink // Self is always a symlink and isn't expected to fail - fextl::string Path{}; + fextl::string Path {}; if (((pathname && pathname[0] != '/') || // If pathname exists then it must not be absolute - !pathname) && - dirfd != AT_FDCWD) { + !pathname) && + dirfd != AT_FDCWD) { // Passed in a dirfd that isn't magic FDCWD // We need to get the path from the fd now char Tmp[PATH_MAX] = ""; @@ -754,12 +743,10 @@ uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, siz } Path += pathname; } - } - else { + } else { if (!pathname || strlen(pathname) == 0) { return -1; - } - else if (pathname) { + } else if (pathname) { Path = pathname; } } @@ -768,9 +755,7 @@ uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, siz char PidSelfPath[50]; snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID); - if (Path == "/proc/self/exe" || - Path == "/proc/thread-self/exe" || - Path == PidSelfPath) { + if (Path == "/proc/self/exe" || Path == "/proc/thread-self/exe" || Path == PidSelfPath) { auto App = Filename(); strncpy(buf, App.c_str(), bufsiz); return std::min(bufsiz, App.size()); @@ -781,11 +766,11 @@ uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, siz auto NewPath = GetEmulatedFDPath(dirfd, pathname, false, TmpFilename); if (NewPath.first != -1) { uint64_t Result = ::readlinkat(NewPath.first, NewPath.second, buf, bufsiz); - if (Result != -1) + if (Result != -1) { return Result; + } - if (Result == -1 && - errno == EINVAL) { + if (Result == -1 && errno == EINVAL) { // This means that the file wasn't a symlink // This is expected behaviour return -errno; @@ -795,9 +780,9 @@ uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, siz return ::readlinkat(dirfd, pathname, buf, bufsiz); } -uint64_t FileManager::Openat([[maybe_unused]] int dirfs, const char *pathname, int flags, uint32_t mode) { +uint64_t FileManager::Openat([[maybe_unused]] int dirfs, const char* pathname, int flags, uint32_t mode) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; int32_t fd = -1; @@ -819,9 +804,9 @@ uint64_t FileManager::Openat([[maybe_unused]] int dirfs, const char *pathname, i return fd; } -uint64_t FileManager::Openat2(int dirfs, const char *pathname, FEX::HLE::open_how *how, size_t usize) { +uint64_t FileManager::Openat2(int dirfs, const char* pathname, FEX::HLE::open_how* how, size_t usize) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; int32_t fd = -1; @@ -841,50 +826,52 @@ uint64_t FileManager::Openat2(int dirfs, const char *pathname, FEX::HLE::open_ho } return fd; - } -uint64_t FileManager::Statx(int dirfd, const char *pathname, int flags, uint32_t mask, struct statx *statxbuf) { +uint64_t FileManager::Statx(int dirfd, const char* pathname, int flags, uint32_t mask, struct statx* statxbuf) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(dirfd, SelfPath, (flags & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); if (Path.first != -1) { uint64_t Result = FHU::Syscalls::statx(Path.first, Path.second, flags, mask, statxbuf); - if (Result != -1) + if (Result != -1) { return Result; + } } return FHU::Syscalls::statx(dirfd, SelfPath, flags, mask, statxbuf); } -uint64_t FileManager::Mknod(const char *pathname, mode_t mode, dev_t dev) { +uint64_t FileManager::Mknod(const char* pathname, mode_t mode, dev_t dev) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(AT_FDCWD, SelfPath, false, TmpFilename); if (Path.first != -1) { uint64_t Result = ::mknodat(Path.first, Path.second, mode, dev); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::mknod(SelfPath, mode, dev); } -uint64_t FileManager::Statfs(const char *path, void *buf) { +uint64_t FileManager::Statfs(const char* path, void* buf) { auto Path = GetEmulatedPath(path); if (!Path.empty()) { uint64_t Result = ::statfs(Path.c_str(), reinterpret_cast(buf)); - if (Result != -1) + if (Result != -1) { return Result; + } } return ::statfs(path, reinterpret_cast(buf)); } -uint64_t FileManager::NewFSStatAt(int dirfd, const char *pathname, struct stat *buf, int flag) { +uint64_t FileManager::NewFSStatAt(int dirfd, const char* pathname, struct stat* buf, int flag) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(dirfd, SelfPath, (flag & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); @@ -897,9 +884,9 @@ uint64_t FileManager::NewFSStatAt(int dirfd, const char *pathname, struct stat * return ::fstatat(dirfd, SelfPath, buf, flag); } -uint64_t FileManager::NewFSStatAt64(int dirfd, const char *pathname, struct stat64 *buf, int flag) { +uint64_t FileManager::NewFSStatAt64(int dirfd, const char* pathname, struct stat64* buf, int flag) { auto NewPath = GetSelf(pathname); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; FDPathTmpData TmpFilename; auto Path = GetEmulatedFDPath(dirfd, SelfPath, (flag & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); @@ -912,9 +899,9 @@ uint64_t FileManager::NewFSStatAt64(int dirfd, const char *pathname, struct stat return ::fstatat64(dirfd, SelfPath, buf, flag); } -uint64_t FileManager::Setxattr(const char *path, const char *name, const void *value, size_t size, int flags) { +uint64_t FileManager::Setxattr(const char* path, const char* name, const void* value, size_t size, int flags) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, true); if (!Path.empty()) { @@ -927,9 +914,9 @@ uint64_t FileManager::Setxattr(const char *path, const char *name, const void *v return ::setxattr(SelfPath, name, value, size, flags); } -uint64_t FileManager::LSetxattr(const char *path, const char *name, const void *value, size_t size, int flags) { +uint64_t FileManager::LSetxattr(const char* path, const char* name, const void* value, size_t size, int flags) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, false); if (!Path.empty()) { @@ -942,9 +929,9 @@ uint64_t FileManager::LSetxattr(const char *path, const char *name, const void * return ::lsetxattr(SelfPath, name, value, size, flags); } -uint64_t FileManager::Getxattr(const char *path, const char *name, void *value, size_t size) { +uint64_t FileManager::Getxattr(const char* path, const char* name, void* value, size_t size) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, true); if (!Path.empty()) { @@ -957,9 +944,9 @@ uint64_t FileManager::Getxattr(const char *path, const char *name, void *value, return ::getxattr(SelfPath, name, value, size); } -uint64_t FileManager::LGetxattr(const char *path, const char *name, void *value, size_t size) { +uint64_t FileManager::LGetxattr(const char* path, const char* name, void* value, size_t size) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, false); if (!Path.empty()) { @@ -972,9 +959,9 @@ uint64_t FileManager::LGetxattr(const char *path, const char *name, void *value, return ::lgetxattr(SelfPath, name, value, size); } -uint64_t FileManager::Listxattr(const char *path, char *list, size_t size) { +uint64_t FileManager::Listxattr(const char* path, char* list, size_t size) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, true); if (!Path.empty()) { @@ -987,9 +974,9 @@ uint64_t FileManager::Listxattr(const char *path, char *list, size_t size) { return ::listxattr(SelfPath, list, size); } -uint64_t FileManager::LListxattr(const char *path, char *list, size_t size) { +uint64_t FileManager::LListxattr(const char* path, char* list, size_t size) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, false); if (!Path.empty()) { @@ -1002,9 +989,9 @@ uint64_t FileManager::LListxattr(const char *path, char *list, size_t size) { return ::llistxattr(SelfPath, list, size); } -uint64_t FileManager::Removexattr(const char *path, const char *name) { +uint64_t FileManager::Removexattr(const char* path, const char* name) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, true); if (!Path.empty()) { @@ -1017,9 +1004,9 @@ uint64_t FileManager::Removexattr(const char *path, const char *name) { return ::removexattr(SelfPath, name); } -uint64_t FileManager::LRemovexattr(const char *path, const char *name) { +uint64_t FileManager::LRemovexattr(const char* path, const char* name) { auto NewPath = GetSelf(path); - const char *SelfPath = NewPath ? NewPath->data() : nullptr; + const char* SelfPath = NewPath ? NewPath->data() : nullptr; auto Path = GetEmulatedPath(SelfPath, false); if (!Path.empty()) { @@ -1032,4 +1019,4 @@ uint64_t FileManager::LRemovexattr(const char *path, const char *name) { return ::lremovexattr(SelfPath, name); } -} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h index 547b60abf..0180e3bb2 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h @@ -29,15 +29,15 @@ class Context; namespace FEX::HLE { [[maybe_unused]] -static bool IsSymlink(int FD, const char *Filename) { +static bool IsSymlink(int FD, const char* Filename) { // Checks to see if a filepath is a symlink. - struct stat Buffer{}; + struct stat Buffer {}; int Result = fstatat(FD, Filename, &Buffer, AT_SYMLINK_NOFOLLOW); return Result == 0 && S_ISLNK(Buffer.st_mode); } [[maybe_unused]] -static ssize_t GetSymlink(int FD, const char *Filename, char *ResultBuffer, size_t ResultBufferSize) { +static ssize_t GetSymlink(int FD, const char* Filename, char* ResultBuffer, size_t ResultBufferSize) { return readlinkat(FD, Filename, ResultBuffer, ResultBufferSize); } @@ -46,47 +46,51 @@ struct open_how; class FileManager final { public: FileManager() = delete; - FileManager(FileManager &&) = delete; + FileManager(FileManager&&) = delete; - FileManager(FEXCore::Context::Context *ctx); + FileManager(FEXCore::Context::Context* ctx); ~FileManager(); - uint64_t Open(const char *pathname, int flags, uint32_t mode); + uint64_t Open(const char* pathname, int flags, uint32_t mode); uint64_t Close(int fd); uint64_t CloseRange(unsigned int first, unsigned int last, unsigned int flags); - uint64_t Stat(const char *pathname, void *buf); - uint64_t Lstat(const char *path, void *buf); - uint64_t Access(const char *pathname, int mode); - uint64_t FAccessat(int dirfd, const char *pathname, int mode); - uint64_t FAccessat2(int dirfd, const char *pathname, int mode, int flags); - uint64_t Readlink(const char *pathname, char *buf, size_t bufsiz); - uint64_t Chmod(const char *pathname, mode_t mode); - uint64_t Readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz); - uint64_t Openat(int dirfs, const char *pathname, int flags, uint32_t mode); - uint64_t Openat2(int dirfs, const char *pathname, FEX::HLE::open_how *how, size_t usize); - uint64_t Statx(int dirfd, const char *pathname, int flags, uint32_t mask, struct statx *statxbuf); - uint64_t Mknod(const char *pathname, mode_t mode, dev_t dev); - uint64_t NewFSStatAt(int dirfd, const char *pathname, struct stat *buf, int flag); - uint64_t NewFSStatAt64(int dirfd, const char *pathname, struct stat64 *buf, int flag); - uint64_t Setxattr(const char *path, const char *name, const void *value, size_t size, int flags); - uint64_t LSetxattr(const char *path, const char *name, const void *value, size_t size, int flags); - uint64_t Getxattr(const char *path, const char *name, void *value, size_t size); - uint64_t LGetxattr(const char *path, const char *name, void *value, size_t size); - uint64_t Listxattr(const char *path, char *list, size_t size); - uint64_t LListxattr(const char *path, char *list, size_t size); - uint64_t Removexattr(const char *path, const char *name); - uint64_t LRemovexattr(const char *path, const char *name); + uint64_t Stat(const char* pathname, void* buf); + uint64_t Lstat(const char* path, void* buf); + uint64_t Access(const char* pathname, int mode); + uint64_t FAccessat(int dirfd, const char* pathname, int mode); + uint64_t FAccessat2(int dirfd, const char* pathname, int mode, int flags); + uint64_t Readlink(const char* pathname, char* buf, size_t bufsiz); + uint64_t Chmod(const char* pathname, mode_t mode); + uint64_t Readlinkat(int dirfd, const char* pathname, char* buf, size_t bufsiz); + uint64_t Openat(int dirfs, const char* pathname, int flags, uint32_t mode); + uint64_t Openat2(int dirfs, const char* pathname, FEX::HLE::open_how* how, size_t usize); + uint64_t Statx(int dirfd, const char* pathname, int flags, uint32_t mask, struct statx* statxbuf); + uint64_t Mknod(const char* pathname, mode_t mode, dev_t dev); + uint64_t NewFSStatAt(int dirfd, const char* pathname, struct stat* buf, int flag); + uint64_t NewFSStatAt64(int dirfd, const char* pathname, struct stat64* buf, int flag); + uint64_t Setxattr(const char* path, const char* name, const void* value, size_t size, int flags); + uint64_t LSetxattr(const char* path, const char* name, const void* value, size_t size, int flags); + uint64_t Getxattr(const char* path, const char* name, void* value, size_t size); + uint64_t LGetxattr(const char* path, const char* name, void* value, size_t size); + uint64_t Listxattr(const char* path, char* list, size_t size); + uint64_t LListxattr(const char* path, char* list, size_t size); + uint64_t Removexattr(const char* path, const char* name); + uint64_t LRemovexattr(const char* path, const char* name); // vfs - uint64_t Statfs(const char *path, void *buf); + uint64_t Statfs(const char* path, void* buf); - std::optional GetSelf(const char *Pathname); + std::optional GetSelf(const char* Pathname); - void UpdatePID(uint32_t PID) { CurrentPID = PID; } + void UpdatePID(uint32_t PID) { + CurrentPID = PID; + } - fextl::string GetEmulatedPath(const char *pathname, bool FollowSymlink = false); + fextl::string GetEmulatedPath(const char* pathname, bool FollowSymlink = false); using FDPathTmpData = std::array; - std::pair GetEmulatedFDPath(int dirfd, const char *pathname, bool FollowSymlink, FDPathTmpData &TmpFilename); + std::pair GetEmulatedFDPath(int dirfd, const char* pathname, bool FollowSymlink, FDPathTmpData& TmpFilename); - bool SupportsProcFSInterpreterPath() const { return SupportsProcFSInterpreter; } + bool SupportsProcFSInterpreterPath() const { + return SupportsProcFSInterpreter; + } #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED void TrackFEXFD(int FD) noexcept { @@ -102,9 +106,7 @@ public: void RemoveFEXFDRange(int begin, int end) noexcept { std::lock_guard lk(FEXTrackingFDMutex); - std::erase_if(FEXTrackingFDs, [begin, end](int FD) { - return FD >= begin && (FD <= end || end == -1); - }); + std::erase_if(FEXTrackingFDs, [begin, end](int FD) { return FD >= begin && (FD <= end || end == -1); }); } bool CheckIfFDInTrackedSet(int FD) noexcept { @@ -116,17 +118,23 @@ public: std::lock_guard lk(FEXTrackingFDMutex); // Just linear scan since the number of tracking FDs is low. for (auto it : FEXTrackingFDs) { - if (it >= begin && (it <= end || end == -1)) return true; + if (it >= begin && (it <= end || end == -1)) { + return true; + } } return false; } #else void TrackFEXFD(int FD) const noexcept {} - bool CheckIfFDInTrackedSet(int FD) const noexcept { return false; } + bool CheckIfFDInTrackedSet(int FD) const noexcept { + return false; + } void RemoveFEXFD(int FD) const noexcept {} void RemoveFEXFDRange(int begin, int end) const noexcept {} - bool CheckIfFDRangeInTrackedSet(int begin, int end) const noexcept { return false; } + bool CheckIfFDRangeInTrackedSet(int begin, int end) const noexcept { + return false; + } #endif private: @@ -141,7 +149,7 @@ private: fextl::string LibraryName; fextl::unordered_set Depends; fextl::vector Overlays; - bool Enabled{}; + bool Enabled {}; }; void LoadThunkDatabase(fextl::unordered_map& ThunkDB, bool Global); FEX::EmulatedFile::EmulatedFDManager EmuFD; @@ -155,8 +163,8 @@ private: FEX_CONFIG_OPT(ThunkConfig, THUNKCONFIG); FEX_CONFIG_OPT(AppConfigName, APP_CONFIG_NAME); FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); - uint32_t CurrentPID{}; - int RootFSFD{AT_FDCWD}; - bool SupportsProcFSInterpreter{}; + uint32_t CurrentPID {}; + int RootFSFD {AT_FDCWD}; + bool SupportsProcFSInterpreter {}; }; -} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp index db2139bbf..64cde6515 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp @@ -58,57 +58,35 @@ $end_info$ #include "LinuxSyscalls/GdbServer.h" -namespace FEX -{ +namespace FEX { constexpr std::array FlagNames = { - "CF", - "", - "PF", - "", - "AF", - "", - "ZF", - "SF", - "TF", - "IF", - "DF", - "OF", - "IOPL", - "", - "NT", - "", - "RF", - "VM", - "AC", - "VIF", - "VIP", - "ID", + "CF", "", "PF", "", "AF", "", "ZF", "SF", "TF", "IF", "DF", "OF", "IOPL", "", "NT", "", "RF", "VM", "AC", "VIF", "VIP", "ID", }; -static std::string_view const& GetFlagName(unsigned Flag) { +static const std::string_view& GetFlagName(unsigned Flag) { return FlagNames[Flag]; } static std::string_view const GetGRegName(unsigned Reg) { switch (Reg) { - case FEXCore::X86State::REG_RAX: return "rax"; - case FEXCore::X86State::REG_RBX: return "rbx"; - case FEXCore::X86State::REG_RCX: return "rcx"; - case FEXCore::X86State::REG_RDX: return "rdx"; - case FEXCore::X86State::REG_RSP: return "rsp"; - case FEXCore::X86State::REG_RBP: return "rbp"; - case FEXCore::X86State::REG_RSI: return "rsi"; - case FEXCore::X86State::REG_RDI: return "rdi"; - case FEXCore::X86State::REG_R8: return "r8"; - case FEXCore::X86State::REG_R9: return "r9"; - case FEXCore::X86State::REG_R10: return "r10"; - case FEXCore::X86State::REG_R11: return "r11"; - case FEXCore::X86State::REG_R12: return "r12"; - case FEXCore::X86State::REG_R13: return "r13"; - case FEXCore::X86State::REG_R14: return "r14"; - case FEXCore::X86State::REG_R15: return "r15"; - default: FEX_UNREACHABLE; + case FEXCore::X86State::REG_RAX: return "rax"; + case FEXCore::X86State::REG_RBX: return "rbx"; + case FEXCore::X86State::REG_RCX: return "rcx"; + case FEXCore::X86State::REG_RDX: return "rdx"; + case FEXCore::X86State::REG_RSP: return "rsp"; + case FEXCore::X86State::REG_RBP: return "rbp"; + case FEXCore::X86State::REG_RSI: return "rsi"; + case FEXCore::X86State::REG_RDI: return "rdi"; + case FEXCore::X86State::REG_R8: return "r8"; + case FEXCore::X86State::REG_R9: return "r9"; + case FEXCore::X86State::REG_R10: return "r10"; + case FEXCore::X86State::REG_R11: return "r11"; + case FEXCore::X86State::REG_R12: return "r12"; + case FEXCore::X86State::REG_R13: return "r13"; + case FEXCore::X86State::REG_R14: return "r14"; + case FEXCore::X86State::REG_R15: return "r15"; + default: FEX_UNREACHABLE; } } @@ -137,7 +115,7 @@ GdbServer::~GdbServer() { } } -GdbServer::GdbServer(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *SignalDelegation, FEX::HLE::SyscallHandler *const SyscallHandler) +GdbServer::GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* SignalDelegation, FEX::HLE::SyscallHandler* const SyscallHandler) : CTX(ctx) , SyscallHandler {SyscallHandler} { // Pass all signals by default @@ -156,7 +134,9 @@ GdbServer::GdbServer(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator * // This is a total hack as there is currently no way to resume once hitting a segfault // But it's semi-useful for debugging. for (uint32_t Signal = 0; Signal <= FEX::HLE::SignalDelegator::MAX_SIGNALS; ++Signal) { - SignalDelegation->RegisterHostSignalHandler(Signal, [this] (FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) { + SignalDelegation->RegisterHostSignalHandler( + Signal, + [this](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) { if (PassSignals[Signal]) { // Pass signal to the guest return false; @@ -168,40 +148,42 @@ GdbServer::GdbServer(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator * WaitForThreadWakeup(); return true; - }, true); + }, + true); } StartThread(); } -static int calculateChecksum(const fextl::string &packet) { +static int calculateChecksum(const fextl::string& packet) { unsigned char checksum = 0; - for (const char &c : packet) { + for (const char& c : packet) { checksum += c; } return checksum; } -static fextl::string hexstring(fextl::istringstream &ss, int delm) { +static fextl::string hexstring(fextl::istringstream& ss, int delm) { fextl::string ret; char hexString[3] = {0, 0, 0}; while (ss.peek() != delm) { ss.read(hexString, 2); int c = std::strtoul(hexString, nullptr, 16); - ret.push_back((char) c); + ret.push_back((char)c); } - if (delm != -1) + if (delm != -1) { ss.get(); + } return ret; } -static fextl::string encodeHex(const unsigned char *data, size_t length) { +static fextl::string encodeHex(const unsigned char* data, size_t length) { fextl::ostringstream ss; - for (size_t i=0; i < length; i++) { + for (size_t i = 0; i < length; i++) { ss << std::setfill('0') << std::setw(2) << std::hex << int(data[i]); } return ss.str(); @@ -222,8 +204,8 @@ static fextl::string getThreadName(uint32_t ThreadID) { // Takes a serial stream and reads a single packet // Un-escapes chars, checks the checksum and request a retransmit if it fails. // Once the checksum is validated, it acknowledges and returns the packet in a string -fextl::string GdbServer::ReadPacket(std::iostream &stream) { - fextl::string packet{}; +fextl::string GdbServer::ReadPacket(std::iostream& stream) { + fextl::string packet {}; // The GDB "Remote Serial Protocal" was originally 7bit clean for use on serial ports. // Binary data is useally hex encoded. However some later extentions just put @@ -235,38 +217,37 @@ fextl::string GdbServer::ReadPacket(std::iostream &stream) { // The checksum is a single unsigned byte sum of the data, hex encoded. int c; - while ((c = stream.get()) > 0 ) { - switch(c) { - case '$': // start of packet - if (packet.size() != 0) - LogMan::Msg::EFmt("Dropping unexpected data: \"{}\"", packet); - - // clear any existing data, must have been a mistake. - packet = fextl::string(); - break; - case '}': // escape char - { - char escaped; - stream >> escaped; - packet.push_back(escaped ^ 0x20); - break; + while ((c = stream.get()) > 0) { + switch (c) { + case '$': // start of packet + if (packet.size() != 0) { + LogMan::Msg::EFmt("Dropping unexpected data: \"{}\"", packet); } - case '#': // end of packet - { - char hexString[3] = {0, 0, 0}; - stream.read(hexString, 2); - int expected_checksum = std::strtoul(hexString, nullptr, 16); - if (calculateChecksum(packet) == expected_checksum) { - return packet; - } else { - LogMan::Msg::EFmt("Received Invalid Packet: ${}#{:02x}", packet, expected_checksum); - } - break; + // clear any existing data, must have been a mistake. + packet = fextl::string(); + break; + case '}': // escape char + { + char escaped; + stream >> escaped; + packet.push_back(escaped ^ 0x20); + break; + } + case '#': // end of packet + { + char hexString[3] = {0, 0, 0}; + stream.read(hexString, 2); + int expected_checksum = std::strtoul(hexString, nullptr, 16); + + if (calculateChecksum(packet) == expected_checksum) { + return packet; + } else { + LogMan::Msg::EFmt("Received Invalid Packet: ${}#{:02x}", packet, expected_checksum); } - default: - packet.push_back((char) c); - break; + break; + } + default: packet.push_back((char)c); break; } } @@ -276,41 +257,38 @@ fextl::string GdbServer::ReadPacket(std::iostream &stream) { static fextl::string escapePacket(const fextl::string& packet) { fextl::ostringstream ss; - for(const auto &c : packet) { + for (const auto& c : packet) { switch (c) { - case '$': - case '#': - case '*': - case '}': { - char escaped = c ^ 0x20; - ss << '}' << (escaped); - break; - } - default: - ss << c; - break; + case '$': + case '#': + case '*': + case '}': { + char escaped = c ^ 0x20; + ss << '}' << (escaped); + break; + } + default: ss << c; break; } } return ss.str(); } -void GdbServer::SendPacket(std::ostream &stream, const fextl::string& packet) { +void GdbServer::SendPacket(std::ostream& stream, const fextl::string& packet) { const auto escaped = escapePacket(packet); const auto str = fextl::fmt::format("${}#{:02x}", escaped, calculateChecksum(escaped)); stream << str << std::flush; } -void GdbServer::SendACK(std::ostream &stream, bool NACK) { +void GdbServer::SendACK(std::ostream& stream, bool NACK) { if (NoAckMode) { return; } if (NACK) { stream << "-" << std::flush; - } - else { + } else { stream << "+" << std::flush; } @@ -338,14 +316,14 @@ struct FEX_PACKED GDBContextDefinition { }; fextl::string GdbServer::readRegs() { - GDBContextDefinition GDB{}; - FEXCore::Core::CPUState state{}; + GDBContextDefinition GDB {}; + FEXCore::Core::CPUState state {}; auto Threads = SyscallHandler->TM.GetThreads(); - FEXCore::Core::InternalThreadState *CurrentThread { Threads->at(0) }; + FEXCore::Core::InternalThreadState* CurrentThread {Threads->at(0)}; bool Found = false; - for (auto &Thread : *Threads) { + for (auto& Thread : *Threads) { if (Thread->ThreadManager.GetTID() != CurrentDebuggingThread) { continue; } @@ -373,7 +351,7 @@ fextl::string GdbServer::readRegs() { // Currently unsupported GDB.fctrl = 0x37F; - GDB.fstat = static_cast(state.flags[FEXCore::X86State::X87FLAG_TOP_LOC]) << 11; + GDB.fstat = static_cast(state.flags[FEXCore::X86State::X87FLAG_TOP_LOC]) << 11; GDB.fstat |= static_cast(state.flags[FEXCore::X86State::X87FLAG_C0_LOC]) << 8; GDB.fstat |= static_cast(state.flags[FEXCore::X86State::X87FLAG_C1_LOC]) << 9; GDB.fstat |= static_cast(state.flags[FEXCore::X86State::X87FLAG_C2_LOC]) << 10; @@ -381,7 +359,7 @@ fextl::string GdbServer::readRegs() { memcpy(&GDB.xmm[0], &state.xmm.avx.data[0], sizeof(GDB.xmm)); - return encodeHex((unsigned char *)&GDB, sizeof(GDBContextDefinition)); + return encodeHex((unsigned char*)&GDB, sizeof(GDBContextDefinition)); } GdbServer::HandledPacketType GdbServer::readReg(const fextl::string& packet) { @@ -390,13 +368,13 @@ GdbServer::HandledPacketType GdbServer::readReg(const fextl::string& packet) { ss.get(); // Drop first letter ss >> std::hex >> addr; - FEXCore::Core::CPUState state{}; + FEXCore::Core::CPUState state {}; auto Threads = SyscallHandler->TM.GetThreads(); - FEXCore::Core::InternalThreadState *CurrentThread { Threads->at(0) }; + FEXCore::Core::InternalThreadState* CurrentThread {Threads->at(0)}; bool Found = false; - for (auto &Thread : *Threads) { + for (auto& Thread : *Threads) { if (Thread->ThreadManager.GetTID() != CurrentDebuggingThread) { continue; } @@ -412,55 +390,42 @@ GdbServer::HandledPacketType GdbServer::readReg(const fextl::string& packet) { } - if (addr >= offsetof(GDBContextDefinition, gregs[0]) && - addr < offsetof(GDBContextDefinition, gregs[16])) { - return {encodeHex((unsigned char *)(&state.gregs[addr / sizeof(uint64_t)]), sizeof(uint64_t)), HandledPacketType::TYPE_ACK}; - } - else if (addr == offsetof(GDBContextDefinition, rip)) { - return {encodeHex((unsigned char *)(&state.rip), sizeof(uint64_t)), HandledPacketType::TYPE_ACK}; - } - else if (addr == offsetof(GDBContextDefinition, eflags)) { + if (addr >= offsetof(GDBContextDefinition, gregs[0]) && addr < offsetof(GDBContextDefinition, gregs[16])) { + return {encodeHex((unsigned char*)(&state.gregs[addr / sizeof(uint64_t)]), sizeof(uint64_t)), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(GDBContextDefinition, rip)) { + return {encodeHex((unsigned char*)(&state.rip), sizeof(uint64_t)), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(GDBContextDefinition, eflags)) { uint32_t eflags = CTX->ReconstructCompactedEFLAGS(CurrentThread, false, nullptr, 0); - return {encodeHex((unsigned char *)(&eflags), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } - else if (addr >= offsetof(GDBContextDefinition, cs) && - addr < offsetof(GDBContextDefinition, mm[0])) { - uint32_t Empty{}; - return {encodeHex((unsigned char *)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } - else if (addr >= offsetof(GDBContextDefinition, mm[0]) && - addr < offsetof(GDBContextDefinition, mm[8])) { - return {encodeHex((unsigned char *)(&state.mm[(addr - offsetof(GDBContextDefinition, mm[0])) / sizeof(X80Float)]), sizeof(X80Float)), HandledPacketType::TYPE_ACK}; - } - else if (addr == offsetof(GDBContextDefinition, fctrl)) { + return {encodeHex((unsigned char*)(&eflags), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(GDBContextDefinition, cs) && addr < offsetof(GDBContextDefinition, mm[0])) { + uint32_t Empty {}; + return {encodeHex((unsigned char*)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(GDBContextDefinition, mm[0]) && addr < offsetof(GDBContextDefinition, mm[8])) { + return {encodeHex((unsigned char*)(&state.mm[(addr - offsetof(GDBContextDefinition, mm[0])) / sizeof(X80Float)]), sizeof(X80Float)), + HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(GDBContextDefinition, fctrl)) { // XXX: We don't support this yet uint32_t FCW = 0x37F; - return {encodeHex((unsigned char *)(&FCW), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } - else if (addr == offsetof(GDBContextDefinition, fstat)) { - uint32_t FSW{}; + return {encodeHex((unsigned char*)(&FCW), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(GDBContextDefinition, fstat)) { + uint32_t FSW {}; FSW = static_cast(state.flags[FEXCore::X86State::X87FLAG_TOP_LOC]) << 11; FSW |= static_cast(state.flags[FEXCore::X86State::X87FLAG_C0_LOC]) << 8; FSW |= static_cast(state.flags[FEXCore::X86State::X87FLAG_C1_LOC]) << 9; FSW |= static_cast(state.flags[FEXCore::X86State::X87FLAG_C2_LOC]) << 10; FSW |= static_cast(state.flags[FEXCore::X86State::X87FLAG_C3_LOC]) << 14; - return {encodeHex((unsigned char *)(&FSW), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } - else if (addr >= offsetof(GDBContextDefinition, dummies[0]) && - addr < offsetof(GDBContextDefinition, dummies[6])) { - uint32_t Empty{}; - return {encodeHex((unsigned char *)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; - } - else if (addr >= offsetof(GDBContextDefinition, xmm[0][0]) && - addr < offsetof(GDBContextDefinition, xmm[16][0])) { + return {encodeHex((unsigned char*)(&FSW), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(GDBContextDefinition, dummies[0]) && addr < offsetof(GDBContextDefinition, dummies[6])) { + uint32_t Empty {}; + return {encodeHex((unsigned char*)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr >= offsetof(GDBContextDefinition, xmm[0][0]) && addr < offsetof(GDBContextDefinition, xmm[16][0])) { const auto XmmIndex = (addr - offsetof(GDBContextDefinition, xmm[0][0])) / FEXCore::Core::CPUState::XMM_AVX_REG_SIZE; - const auto *Data = (unsigned char *)&state.xmm.avx.data[XmmIndex][0]; + const auto* Data = (unsigned char*)&state.xmm.avx.data[XmmIndex][0]; return {encodeHex(Data, FEXCore::Core::CPUState::XMM_AVX_REG_SIZE), HandledPacketType::TYPE_ACK}; - } - else if (addr == offsetof(GDBContextDefinition, mxcsr)) { - uint32_t Empty{}; - return {encodeHex((unsigned char *)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; + } else if (addr == offsetof(GDBContextDefinition, mxcsr)) { + uint32_t Empty {}; + return {encodeHex((unsigned char*)(&Empty), sizeof(uint32_t)), HandledPacketType::TYPE_ACK}; } LogMan::Msg::EFmt("Unknown GDB register 0x{:x}", addr); @@ -475,116 +440,116 @@ fextl::string buildTargetXML() { xml << "\n"; xml << "i386:x86-64\n"; xml << "GNU/Linux\n"; - xml << "\n"; + xml << "\n"; - xml << "\n"; - // flags register - for(int i = 0; i < 22; i++) { - auto name = GetFlagName(i); - if (name.empty()) { - continue; - } - xml << "\t\n"; - } - xml << "\n"; - - int32_t TargetSize{}; - auto reg = [&](std::string_view name, std::string_view type, int size) { - TargetSize += size; - xml << "" << std::endl; - }; - - // Register ordering. - // We want to just memcpy our x86 state to gdb, so we tell it the ordering. - - // GPRs - for (uint32_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; i++) { - reg(GetGRegName(i), "int64", 64); - } - - reg("rip", "code_ptr", 64); - - reg("eflags", "fex_eflags", 32); - - // Fake registers which GDB requires, but we don't support; - // We stick them past the end of our cpu state. - - // non-userspace segment registers - reg("cs", "int32", 32); - reg("ss", "int32", 32); - reg("ds", "int32", 32); - reg("es", "int32", 32); - - reg("fs", "int32", 32); - reg("gs", "int32", 32); - - // x87 stack - for (int i=0; i < 8; i++) { - reg(fextl::fmt::format("st{}", i), "i387_ext", 80); - } - - // x87 control - reg("fctrl", "int32", 32); - reg("fstat", "int32", 32); - reg("ftag", "int32", 32); - reg("fiseg", "int32", 32); - reg("fioff", "int32", 32); - reg("foseg", "int32", 32); - reg("fooff", "int32", 32); - reg("fop", "int32", 32); - - - xml << "\n"; - xml << "\n"; - xml << - R"( - - - - - - - - - - - - - - - )"; - - // SSE regs - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - reg(fextl::fmt::format("xmm{}", i), "vec128", 128); - } - - reg("mxcsr", "int", 32); - - xml << "\n"; - - xml << ""; - xml << - R"( - - - - - - - - - - - - - - - )"; - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - reg(fmt::format("ymm{}h", i), "vec128", 128); + xml << "\n"; + // flags register + for (int i = 0; i < 22; i++) { + auto name = GetFlagName(i); + if (name.empty()) { + continue; } - xml << "\n"; + xml << "\t\n"; + } + xml << "\n"; + + int32_t TargetSize {}; + auto reg = [&](std::string_view name, std::string_view type, int size) { + TargetSize += size; + xml << "" << std::endl; + }; + + // Register ordering. + // We want to just memcpy our x86 state to gdb, so we tell it the ordering. + + // GPRs + for (uint32_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; i++) { + reg(GetGRegName(i), "int64", 64); + } + + reg("rip", "code_ptr", 64); + + reg("eflags", "fex_eflags", 32); + + // Fake registers which GDB requires, but we don't support; + // We stick them past the end of our cpu state. + + // non-userspace segment registers + reg("cs", "int32", 32); + reg("ss", "int32", 32); + reg("ds", "int32", 32); + reg("es", "int32", 32); + + reg("fs", "int32", 32); + reg("gs", "int32", 32); + + // x87 stack + for (int i = 0; i < 8; i++) { + reg(fextl::fmt::format("st{}", i), "i387_ext", 80); + } + + // x87 control + reg("fctrl", "int32", 32); + reg("fstat", "int32", 32); + reg("ftag", "int32", 32); + reg("fiseg", "int32", 32); + reg("fioff", "int32", 32); + reg("foseg", "int32", 32); + reg("fooff", "int32", 32); + reg("fop", "int32", 32); + + + xml << "\n"; + xml << "\n"; + xml << + R"( + + + + + + + + + + + + + + + )"; + + // SSE regs + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + reg(fextl::fmt::format("xmm{}", i), "vec128", 128); + } + + reg("mxcsr", "int", 32); + + xml << "\n"; + + xml << ""; + xml << + R"( + + + + + + + + + + + + + + + )"; + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + reg(fmt::format("ymm{}h", i), "vec128", 128); + } + xml << "\n"; xml << ""; xml << std::flush; @@ -628,7 +593,7 @@ void GdbServer::buildLibraryMap() { fextl::map> SegmentMaps; // 7ff5dd6d2000-7ff5dd6d3000 rw-p 0000a000 103:0b 1881447 /usr/lib/x86_64-linux-gnu/libnss_compat.so.2 - fextl::string const &RuntimeExecutable = Filename(); + const fextl::string& RuntimeExecutable = Filename(); while (std::getline(MapsStream, Line)) { auto ss = fextl::istringstream(Line); fextl::string Tmp; @@ -650,7 +615,7 @@ void GdbServer::buildLibraryMap() { Name = FEXCore::StringUtils::Trim(Name); - struct stat sb{}; + struct stat sb {}; if (stat(Name.c_str(), &sb) != -1) { if (S_ISCHR(sb.st_mode)) { // Skip this special file type @@ -670,9 +635,9 @@ void GdbServer::buildLibraryMap() { } xml << "\n"; - for (auto &Array : SegmentMaps) { + for (auto& Array : SegmentMaps) { xml << "\t\n"; - for (auto &Data : Array.second) { + for (auto& Data : Array.second) { xml << "\t\t\n"; } xml << "\t\n"; @@ -684,7 +649,7 @@ void GdbServer::buildLibraryMap() { LibraryMapChanged = false; } -GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string &packet) { +GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string& packet) { fextl::string object; fextl::string rw; fextl::string annex; @@ -704,8 +669,7 @@ GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string &packet) std::getline(ss, annex, ':'); if (annex == "") { annex_pid = getpid(); - } - else { + } else { auto ss_pid = fextl::istringstream(annex); ss_pid >> std::hex >> annex_pid; } @@ -714,18 +678,22 @@ GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string &packet) ss >> std::hex >> length; // Bail on any errors - if (ss.fail() || !ss.eof() || expectXfer != "qXfer" || rw != "read" || expectComma != ',') + if (ss.fail() || !ss.eof() || expectXfer != "qXfer" || rw != "read" || expectComma != ',') { return {"E00", HandledPacketType::TYPE_ACK}; + } } // Lambda to correctly encode any reply auto encode = [&](fextl::string data) -> fextl::string { - if (offset == data.size()) + if (offset == data.size()) { return "l"; - if (offset >= data.size()) + } + if (offset >= data.size()) { return "E34"; // ERANGE - if ((data.size() - offset) > length) + } + if ((data.size() - offset) > length) { return "m" + data.substr(offset, length); + } return "l" + data.substr(offset); }; @@ -738,8 +706,9 @@ GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string &packet) } if (object == "features") { - if (annex == "target.xml") + if (annex == "target.xml") { return {encode(buildTargetXML()), HandledPacketType::TYPE_ACK}; + } return {"E00", HandledPacketType::TYPE_ACK}; } @@ -751,7 +720,7 @@ GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string &packet) ThreadString.clear(); fextl::ostringstream ss; ss << "\n"; - for (auto &Thread : *Threads) { + for (auto& Thread : *Threads) { // Thread id is in hex without 0x prefix const auto ThreadName = getThreadName(Thread->ThreadManager.GetTID()); ss << "ThreadManager.GetTID() << "\""; @@ -792,13 +761,12 @@ GdbServer::HandledPacketType GdbServer::handleXfer(const fextl::string &packet) if (Is64BitMode()) { data.resize(auxv_size); memcpy(data.data(), reinterpret_cast(auxv_ptr), data.size()); - } - else { + } else { // We need to transcode from 32-bit auxv_t to 64-bit data.resize(auxv_size / sizeof(Elf32_auxv_t) * sizeof(Elf64_auxv_t)); size_t NumAuxv = auxv_size / sizeof(Elf32_auxv_t); for (size_t i = 0; i < NumAuxv; ++i) { - Elf32_auxv_t *auxv = reinterpret_cast(auxv_ptr + i * sizeof(Elf32_auxv_t)); + Elf32_auxv_t* auxv = reinterpret_cast(auxv_ptr + i * sizeof(Elf32_auxv_t)); Elf64_auxv_t tmp; tmp.a_type = auxv->a_type; tmp.a_un.a_val = auxv->a_un.a_val; @@ -821,13 +789,14 @@ static size_t CheckMemMapping(uint64_t Address, size_t Size) { fextl::string Line; while (std::getline(MapsStream, Line)) { - if (MapsStream.eof()) break; + if (MapsStream.eof()) { + break; + } uint64_t Begin, End; - char r,w,x,p; + char r, w, x, p; if (sscanf(Line.c_str(), "%lx-%lx %c%c%c%c", &Begin, &End, &r, &w, &x, &p) == 6) { - if (Begin <= Address && - End > Address) { - ssize_t Overrun{}; + if (Begin <= Address && End > Address) { + ssize_t Overrun {}; if (AddressEnd > End) { Overrun = AddressEnd - End; } @@ -846,7 +815,7 @@ GdbServer::HandledPacketType GdbServer::handleProgramOffsets() { return {std::move(str), HandledPacketType::TYPE_ACK}; } -GdbServer::HandledPacketType GdbServer::handleMemory(const fextl::string &packet) { +GdbServer::HandledPacketType GdbServer::handleMemory(const fextl::string& packet) { bool write; size_t addr; size_t length; @@ -859,7 +828,7 @@ GdbServer::HandledPacketType GdbServer::handleMemory(const fextl::string &packet ss >> std::hex >> length; if (write) { - ss.get(); // discard colon + ss.get(); // discard colon data = hexstring(ss, -1); // grab data until end of file. } @@ -886,16 +855,19 @@ GdbServer::HandledPacketType GdbServer::handleMemory(const fextl::string &packet } } -GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) { - const auto match = [&](const char *str) -> bool { return packet.rfind(str, 0) == 0; }; - const auto MatchStr = [](const fextl::string &Str, const char *str) -> bool { return Str.rfind(str, 0) == 0; }; +GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string& packet) { + const auto match = [&](const char* str) -> bool { + return packet.rfind(str, 0) == 0; + }; + const auto MatchStr = [](const fextl::string& Str, const char* str) -> bool { + return Str.rfind(str, 0) == 0; + }; - const auto split = [](const fextl::string &Str, char deliminator) -> fextl::vector { + const auto split = [](const fextl::string& Str, char deliminator) -> fextl::vector { fextl::vector Elements; fextl::istringstream Input(Str); - for (fextl::string line; - std::getline(Input, line); - Elements.emplace_back(line)); + for (fextl::string line; std::getline(Input, line); Elements.emplace_back(line)) + ; return Elements; }; @@ -912,7 +884,7 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) // For feature documentation // https://sourceware.org/gdb/current/onlinedocs/gdb/General-Query-Packets.html#qSupported - fextl::string SupportedFeatures{}; + fextl::string SupportedFeatures {}; // Required features SupportedFeatures += "PacketSize=32768;"; @@ -947,7 +919,7 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) // TODO: If we want to support conditional breakpoints then we need to support single stepping. // SupportedFeatures += "ConditionalBreakpoints+;"; - for (auto &Feature : Features) { + for (auto& Feature : Features) { if (MatchStr(Feature, "swbreak+")) { SupportedFeatures += "swbreak+;"; } @@ -1013,7 +985,7 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) // Returns the current Thread ID auto Threads = SyscallHandler->TM.GetThreads(); fextl::ostringstream ss; - ss << "m" << std::hex << Threads->at(0)->ThreadManager.TID; + ss << "m" << std::hex << Threads->at(0)->ThreadManager.TID; return {ss.str(), HandledPacketType::TYPE_ACK}; } if (match("QStartNoAckMode")) { @@ -1030,8 +1002,7 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) if (Symbol_Val.empty() && Symbol_name.empty()) { return {"OK", HandledPacketType::TYPE_ACK}; - } - else { + } else { return {"", HandledPacketType::TYPE_UNKNOWN}; } } @@ -1046,7 +1017,7 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) ss.get(); // discard colon // We now have a semi-colon deliminated list of signals to pass to the guest process - for (fextl::string tmp; std::getline(ss, tmp, ';'); ) { + for (fextl::string tmp; std::getline(ss, tmp, ';');) { uint32_t Signal = std::stoi(tmp.c_str(), nullptr, 16); if (Signal < FEX::HLE::SignalDelegator::MAX_SIGNALS) { PassSignals[Signal] = true; @@ -1069,7 +1040,7 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) // os_build:362e332e332d3036303330332d67656e65726963; // os_kernel:2332303233303531373133333620534d5020505245454d50545f44594e414d494320576564204d61792031372031333a34353a3139205554432032303233; // hostname:7279616e682d545235303030; - fextl::string HostFeatures{}; + fextl::string HostFeatures {}; // 64-bit always returned for the host environment. // qProcessInfo will return i386 or not. @@ -1079,11 +1050,11 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) // Always little-endian. HostFeatures += "endian:little;"; - struct utsname buf{}; + struct utsname buf {}; if (uname(&buf) != -1) { - uint32_t Major{}; - uint32_t Minor{}; - uint32_t Patch{}; + uint32_t Major {}; + uint32_t Minor {}; + uint32_t Patch {}; // Parse kernel version in the form of `..[Optional Data]` const auto End = buf.release + sizeof(buf.release); @@ -1116,30 +1087,29 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) GdbServer::HandledPacketType GdbServer::ThreadAction(char action, uint32_t tid) { switch (action) { - case 'c': { - SyscallHandler->TM.Run(); - ThreadBreakEvent.NotifyAll(); - SyscallHandler->TM.WaitForThreadsToRun(); - return {"", HandledPacketType::TYPE_ONLYACK}; + case 'c': { + SyscallHandler->TM.Run(); + ThreadBreakEvent.NotifyAll(); + SyscallHandler->TM.WaitForThreadsToRun(); + return {"", HandledPacketType::TYPE_ONLYACK}; + } + case 's': { + SyscallHandler->TM.Step(); + SendPacketPair({"OK", HandledPacketType::TYPE_ACK}); + fextl::string str = fextl::fmt::format("T05thread:{:02x};", getpid()); + if (LibraryMapChanged) { + // If libraries have changed then let gdb know + str += "library:1;"; } - case 's': { - SyscallHandler->TM.Step(); - SendPacketPair({"OK", HandledPacketType::TYPE_ACK}); - fextl::string str = fextl::fmt::format("T05thread:{:02x};", getpid()); - if (LibraryMapChanged) { - // If libraries have changed then let gdb know - str += "library:1;"; - } - SendPacketPair({std::move(str), HandledPacketType::TYPE_ACK}); - return {"OK", HandledPacketType::TYPE_ACK}; - } - case 't': - // This thread isn't part of the thread pool - SyscallHandler->TM.Stop(); - return {"OK", HandledPacketType::TYPE_ACK}; - default: - return {"E00", HandledPacketType::TYPE_ACK}; + SendPacketPair({std::move(str), HandledPacketType::TYPE_ACK}); + return {"OK", HandledPacketType::TYPE_ACK}; + } + case 't': + // This thread isn't part of the thread pool + SyscallHandler->TM.Stop(); + return {"OK", HandledPacketType::TYPE_ACK}; + default: return {"E00", HandledPacketType::TYPE_ACK}; } } @@ -1153,15 +1123,19 @@ GdbServer::HandledPacketType GdbServer::handleV(const fextl::string& packet) { return std::nullopt; }; - const auto F = [](int result) -> fextl::string { return fextl::fmt::format("F{:x}", result); }; - const auto F_error = []() -> fextl::string { return fextl::fmt::format("F-1,{:x}", errno); }; - const auto F_data = [](int result, const fextl::string& data) -> fextl::string { + const auto F = [](int result) -> fextl::string { + return fextl::fmt::format("F{:x}", result); + }; + const auto F_error = []() -> fextl::string { + return fextl::fmt::format("F-1,{:x}", errno); + }; + const auto F_data = [](int result, const fextl::string& data) -> fextl::string { // Binary encoded data is raw appended to the end return fextl::fmt::format("F{:#x};", result) + data; }; std::optional ss; - if((ss = match("vFile:open:"))) { + if ((ss = match("vFile:open:"))) { fextl::string filename; int flags; int mode; @@ -1173,19 +1147,19 @@ GdbServer::HandledPacketType GdbServer::handleV(const fextl::string& packet) { return {F(open(filename.c_str(), flags, mode)), HandledPacketType::TYPE_ACK}; } - if((ss = match("vFile:setfs:"))) { + if ((ss = match("vFile:setfs:"))) { int pid; *ss >> pid; return {F(pid == 0 ? 0 : -1), HandledPacketType::TYPE_ACK}; // Only support the common filesystem } - if((ss = match("vFile:close:"))) { + if ((ss = match("vFile:close:"))) { int fd; *ss >> std::hex >> fd; close(fd); return {F(0), HandledPacketType::TYPE_ACK}; } - if((ss = match("vFile:pread:"))) { + if ((ss = match("vFile:pread:"))) { int fd, count, offset; *ss >> std::hex >> fd; @@ -1215,8 +1189,8 @@ GdbServer::HandledPacketType GdbServer::handleV(const fextl::string& packet) { // FIXME: We also claim to support continue with signal... because it's compulsory } if ((ss = match("vCont;"))) { - char action{}; - int thread{}; + char action {}; + int thread {}; action = ss->get(); @@ -1234,8 +1208,10 @@ GdbServer::HandledPacketType GdbServer::handleV(const fextl::string& packet) { return {"", HandledPacketType::TYPE_ACK}; } -GdbServer::HandledPacketType GdbServer::handleThreadOp(const fextl::string &packet) { - const auto match = [&](const char *str) -> bool { return packet.rfind(str, 0) == 0; }; +GdbServer::HandledPacketType GdbServer::handleThreadOp(const fextl::string& packet) { + const auto match = [&](const char* str) -> bool { + return packet.rfind(str, 0) == 0; + }; if (match("Hc")) { // Sets thread to this ID for stepping @@ -1262,11 +1238,11 @@ GdbServer::HandledPacketType GdbServer::handleThreadOp(const fextl::string &pack return {"", HandledPacketType::TYPE_UNKNOWN}; } -GdbServer::HandledPacketType GdbServer::handleBreakpoint(const fextl::string &packet) { +GdbServer::HandledPacketType GdbServer::handleBreakpoint(const fextl::string& packet) { auto ss = fextl::istringstream(packet); // Don't do anything with set breakpoints yet - [[maybe_unused]] bool Set{}; + [[maybe_unused]] bool Set {}; uint64_t Addr; uint64_t Type; Set = ss.get() == 'Z'; @@ -1279,75 +1255,66 @@ GdbServer::HandledPacketType GdbServer::handleBreakpoint(const fextl::string &pa return {"OK", HandledPacketType::TYPE_ACK}; } -GdbServer::HandledPacketType GdbServer::ProcessPacket(const fextl::string &packet) { +GdbServer::HandledPacketType GdbServer::ProcessPacket(const fextl::string& packet) { switch (packet[0]) { - case '?': { - // Indicates the reason that the thread has stopped - // Behaviour changes if the target is in non-stop mode - // Binja doesn't support S response here - fextl::string str = fextl::fmt::format("T00thread:{:x};", getpid()); - return {std::move(str), HandledPacketType::TYPE_ACK}; - } - case 'c': - // Continue - return ThreadAction('c', 0); - case 'D': - // Detach - // Ensure the threads are back in running state on detach - SyscallHandler->TM.Run(); - SyscallHandler->TM.WaitForThreadsToRun(); - return {"OK", HandledPacketType::TYPE_ACK}; - case 'g': - // We might be running while we try reading - // Pause up front - SyscallHandler->TM.Pause(); - return {readRegs(), HandledPacketType::TYPE_ACK}; - case 'p': - return readReg(packet); - case 'q': - case 'Q': - return handleQuery(packet); - case 'v': - return handleV(packet); - case 'm': // Memory read - case 'M': // Memory write - return handleMemory(packet); - case 'H': // Sets thread for subsequent operations - return handleThreadOp(packet); - case '!': // Enable extended mode - case 'T': // Is a thread alive? - return {"OK", HandledPacketType::TYPE_ACK}; - case 's': // Step - return ThreadAction('s', 0); - case 'z': // Remove breakpoint or watchpoint - case 'Z': // Inserts breakpoint or watchpoint - return handleBreakpoint(packet); - case 'k': // Kill the process - SyscallHandler->TM.Stop(); - SyscallHandler->TM.WaitForIdle(); // Block until exit - return {"", HandledPacketType::TYPE_NONE}; - default: - return {"", HandledPacketType::TYPE_UNKNOWN}; + case '?': { + // Indicates the reason that the thread has stopped + // Behaviour changes if the target is in non-stop mode + // Binja doesn't support S response here + fextl::string str = fextl::fmt::format("T00thread:{:x};", getpid()); + return {std::move(str), HandledPacketType::TYPE_ACK}; + } + case 'c': + // Continue + return ThreadAction('c', 0); + case 'D': + // Detach + // Ensure the threads are back in running state on detach + SyscallHandler->TM.Run(); + SyscallHandler->TM.WaitForThreadsToRun(); + return {"OK", HandledPacketType::TYPE_ACK}; + case 'g': + // We might be running while we try reading + // Pause up front + SyscallHandler->TM.Pause(); + return {readRegs(), HandledPacketType::TYPE_ACK}; + case 'p': return readReg(packet); + case 'q': + case 'Q': return handleQuery(packet); + case 'v': return handleV(packet); + case 'm': // Memory read + case 'M': // Memory write + return handleMemory(packet); + case 'H': // Sets thread for subsequent operations + return handleThreadOp(packet); + case '!': // Enable extended mode + case 'T': // Is a thread alive? + return {"OK", HandledPacketType::TYPE_ACK}; + case 's': // Step + return ThreadAction('s', 0); + case 'z': // Remove breakpoint or watchpoint + case 'Z': // Inserts breakpoint or watchpoint + return handleBreakpoint(packet); + case 'k': // Kill the process + SyscallHandler->TM.Stop(); + SyscallHandler->TM.WaitForIdle(); // Block until exit + return {"", HandledPacketType::TYPE_NONE}; + default: return {"", HandledPacketType::TYPE_UNKNOWN}; } } void GdbServer::SendPacketPair(const HandledPacketType& response) { std::lock_guard lk(sendMutex); - if (response.TypeResponse == HandledPacketType::TYPE_ACK || - response.TypeResponse == HandledPacketType::TYPE_ONLYACK) { + if (response.TypeResponse == HandledPacketType::TYPE_ACK || response.TypeResponse == HandledPacketType::TYPE_ONLYACK) { SendACK(*CommsStream, false); - } - else if (response.TypeResponse == HandledPacketType::TYPE_NACK || - response.TypeResponse == HandledPacketType::TYPE_ONLYNACK) { + } else if (response.TypeResponse == HandledPacketType::TYPE_NACK || response.TypeResponse == HandledPacketType::TYPE_ONLYNACK) { SendACK(*CommsStream, true); } if (response.TypeResponse == HandledPacketType::TYPE_UNKNOWN) { SendPacket(*CommsStream, ""); - } - else if (response.TypeResponse != HandledPacketType::TYPE_ONLYNACK && - response.TypeResponse != HandledPacketType::TYPE_ONLYACK && - response.TypeResponse != HandledPacketType::TYPE_NONE) { + } else if (response.TypeResponse != HandledPacketType::TYPE_ONLYNACK && response.TypeResponse != HandledPacketType::TYPE_ONLYACK && + response.TypeResponse != HandledPacketType::TYPE_NONE) { SendPacket(*CommsStream, response.Response); } } @@ -1355,23 +1322,19 @@ void GdbServer::SendPacketPair(const HandledPacketType& response) { GdbServer::WaitForConnectionResult GdbServer::WaitForConnection() { while (!CoreShuttingDown.load()) { struct pollfd PollFD { - .fd = ListenSocket, - .events = POLLIN | POLLPRI | POLLRDHUP, - .revents = 0, + .fd = ListenSocket, .events = POLLIN | POLLPRI | POLLRDHUP, .revents = 0, }; int Result = ppoll(&PollFD, 1, nullptr, nullptr); if (Result > 0) { if (PollFD.revents & POLLIN) { CommsStream = OpenSocket(); return WaitForConnectionResult::CONNECTION; - } - else if (PollFD.revents & (POLLHUP | POLLERR | POLLNVAL)) { + } else if (PollFD.revents & (POLLHUP | POLLERR | POLLNVAL)) { // Listen socket error or shutting down LogMan::Msg::EFmt("[GdbServer] gdbserver shutting down: {}"); return WaitForConnectionResult::ERROR; } - } - else if (Result == -1) { + } else if (Result == -1) { LogMan::Msg::EFmt("[GdbServer] poll failure: {}", errno); } } @@ -1392,56 +1355,55 @@ void GdbServer::GdbServerLoop() { break; } - HandledPacketType response{}; + HandledPacketType response {}; // Outer server loop. Handles packet start, ACK/NAK and break int c; - while ((c = CommsStream->get()) >= 0 ) { - switch (c) { - case '$': { - auto packet = ReadPacket(*CommsStream); - response = ProcessPacket(packet); - SendPacketPair(response); - if (response.TypeResponse == HandledPacketType::TYPE_UNKNOWN) { - LogMan::Msg::DFmt("Unknown packet {}", packet); - } - break; + while ((c = CommsStream->get()) >= 0) { + switch (c) { + case '$': { + auto packet = ReadPacket(*CommsStream); + response = ProcessPacket(packet); + SendPacketPair(response); + if (response.TypeResponse == HandledPacketType::TYPE_UNKNOWN) { + LogMan::Msg::DFmt("Unknown packet {}", packet); } - case '+': - // ACK, do nothing. - break; - case '-': - // NAK, Resend requested - { - std::lock_guard lk(sendMutex); - SendPacket(*CommsStream, response.Response); - } - break; - case '\x03': { // ASCII EOT - SyscallHandler->TM.Pause(); - fextl::string str = fextl::fmt::format("T02thread:{:02x};", getpid()); - if (LibraryMapChanged) { - // If libraries have changed then let gdb know - str += "library:1;"; - } - SendPacketPair({std::move(str), HandledPacketType::TYPE_ACK}); - break; - } - default: - LogMan::Msg::DFmt("GdbServer: Unexpected byte {} ({:02x})", static_cast(c), c); + break; + } + case '+': + // ACK, do nothing. + break; + case '-': + // NAK, Resend requested + { + std::lock_guard lk(sendMutex); + SendPacket(*CommsStream, response.Response); } + break; + case '\x03': { // ASCII EOT + SyscallHandler->TM.Pause(); + fextl::string str = fextl::fmt::format("T02thread:{:02x};", getpid()); + if (LibraryMapChanged) { + // If libraries have changed then let gdb know + str += "library:1;"; + } + SendPacketPair({std::move(str), HandledPacketType::TYPE_ACK}); + break; + } + default: LogMan::Msg::DFmt("GdbServer: Unexpected byte {} ({:02x})", static_cast(c), c); + } } { - std::lock_guard lk(sendMutex); - CommsStream.reset(); + std::lock_guard lk(sendMutex); + CommsStream.reset(); } } CloseListenSocket(); } -static void* ThreadHandler(void *Arg) { +static void* ThreadHandler(void* Arg) { FEXCore::Threads::SetThreadName("FEX:gdbserver"); auto This = reinterpret_cast(Arg); This->GdbServerLoop(); @@ -1469,13 +1431,13 @@ void GdbServer::OpenListenSocket() { return; } - struct sockaddr_un addr{}; + struct sockaddr_un addr {}; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, GdbUnixSocketPath.data(), sizeof(addr.sun_path)); size_t SizeOfAddr = offsetof(sockaddr_un, sun_path) + GdbUnixSocketPath.size(); // Bind the socket to the path - int Result{}; + int Result {}; for (int attempt = 0; attempt < 2; ++attempt) { Result = bind(ListenSocket, reinterpret_cast(&addr), SizeOfAddr); if (Result == 0) { @@ -1509,13 +1471,13 @@ void GdbServer::CloseListenSocket() { fextl::unique_ptr GdbServer::OpenSocket() { // Block until a connection arrives - struct sockaddr_storage their_addr{}; - socklen_t addr_size{}; + struct sockaddr_storage their_addr {}; + socklen_t addr_size {}; - int new_fd = accept(ListenSocket, (struct sockaddr *)&their_addr, &addr_size); + int new_fd = accept(ListenSocket, (struct sockaddr*)&their_addr, &addr_size); return fextl::make_unique(new_fd); } #endif -} // namespace FEXCore +} // namespace FEX diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h index 425c8b309..0fb3ac0e7 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.h @@ -25,89 +25,86 @@ namespace FEX { class GdbServer { public: - GdbServer(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *SignalDelegation, FEX::HLE::SyscallHandler *const SyscallHandler); - ~GdbServer(); + GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* SignalDelegation, FEX::HLE::SyscallHandler* const SyscallHandler); + ~GdbServer(); - // Public for threading - void GdbServerLoop(); + // Public for threading + void GdbServerLoop(); - void AlertLibrariesChanged() { - LibraryMapChanged = true; - } + void AlertLibrariesChanged() { + LibraryMapChanged = true; + } private: - void Break(int signal); + void Break(int signal); - void OpenListenSocket(); - void CloseListenSocket(); - enum class WaitForConnectionResult { - CONNECTION, - ERROR, + void OpenListenSocket(); + void CloseListenSocket(); + enum class WaitForConnectionResult { + CONNECTION, + ERROR, + }; + WaitForConnectionResult WaitForConnection(); + fextl::unique_ptr OpenSocket(); + void StartThread(); + fextl::string ReadPacket(std::iostream& stream); + void SendPacket(std::ostream& stream, const fextl::string& packet); + + void SendACK(std::ostream& stream, bool NACK); + + Event ThreadBreakEvent {}; + void WaitForThreadWakeup(); + + struct HandledPacketType { + fextl::string Response {}; + enum ResponseType { + TYPE_NONE, + TYPE_UNKNOWN, + TYPE_ACK, + TYPE_NACK, + TYPE_ONLYACK, + TYPE_ONLYNACK, }; - WaitForConnectionResult WaitForConnection(); - fextl::unique_ptr OpenSocket(); - void StartThread(); - fextl::string ReadPacket(std::iostream &stream); - void SendPacket(std::ostream &stream, const fextl::string& packet); + ResponseType TypeResponse {}; + }; - void SendACK(std::ostream &stream, bool NACK); + void SendPacketPair(const HandledPacketType& packetPair); + HandledPacketType ProcessPacket(const fextl::string& packet); + HandledPacketType handleQuery(const fextl::string& packet); + HandledPacketType handleXfer(const fextl::string& packet); + HandledPacketType handleMemory(const fextl::string& packet); + HandledPacketType handleV(const fextl::string& packet); + HandledPacketType handleThreadOp(const fextl::string& packet); + HandledPacketType handleBreakpoint(const fextl::string& packet); + HandledPacketType handleProgramOffsets(); - Event ThreadBreakEvent{}; - void WaitForThreadWakeup(); + HandledPacketType ThreadAction(char action, uint32_t tid); - struct HandledPacketType { - fextl::string Response{}; - enum ResponseType { - TYPE_NONE, - TYPE_UNKNOWN, - TYPE_ACK, - TYPE_NACK, - TYPE_ONLYACK, - TYPE_ONLYNACK, - }; - ResponseType TypeResponse{}; - }; + fextl::string readRegs(); + HandledPacketType readReg(const fextl::string& packet); - void SendPacketPair(const HandledPacketType& packetPair); - HandledPacketType ProcessPacket(const fextl::string &packet); - HandledPacketType handleQuery(const fextl::string &packet); - HandledPacketType handleXfer(const fextl::string &packet); - HandledPacketType handleMemory(const fextl::string &packet); - HandledPacketType handleV(const fextl::string& packet); - HandledPacketType handleThreadOp(const fextl::string &packet); - HandledPacketType handleBreakpoint(const fextl::string &packet); - HandledPacketType handleProgramOffsets(); + FEXCore::Context::Context* CTX; + FEX::HLE::SyscallHandler* const SyscallHandler; + fextl::unique_ptr gdbServerThread; + fextl::unique_ptr CommsStream; + std::mutex sendMutex; + bool SettingNoAckMode {false}; + bool NoAckMode {false}; + bool NonStopMode {false}; + fextl::string ThreadString {}; + fextl::string OSDataString {}; + void buildLibraryMap(); + std::atomic LibraryMapChanged = true; + std::atomic CoreShuttingDown {}; + fextl::string LibraryMapString {}; - HandledPacketType ThreadAction(char action, uint32_t tid); - - fextl::string readRegs(); - HandledPacketType readReg(const fextl::string& packet); - - FEXCore::Context::Context *CTX; - FEX::HLE::SyscallHandler *const SyscallHandler; - fextl::unique_ptr gdbServerThread; - fextl::unique_ptr CommsStream; - std::mutex sendMutex; - bool SettingNoAckMode{false}; - bool NoAckMode{false}; - bool NonStopMode{false}; - fextl::string ThreadString{}; - fextl::string OSDataString{}; - void buildLibraryMap(); - std::atomic LibraryMapChanged = true; - std::atomic CoreShuttingDown{}; - fextl::string LibraryMapString{}; - - // Used to keep track of which signals to pass to the guest - std::array PassSignals{}; - uint32_t CurrentDebuggingThread{}; - int ListenSocket{}; - fextl::string GdbUnixSocketPath{}; - FEX_CONFIG_OPT(Filename, APP_FILENAME); - FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); + // Used to keep track of which signals to pass to the guest + std::array PassSignals {}; + uint32_t CurrentDebuggingThread {}; + int ListenSocket {}; + fextl::string GdbUnixSocketPath {}; + FEX_CONFIG_OPT(Filename, APP_FILENAME); + FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); }; -} - - - +} // namespace FEX diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.cpp index e30196bf7..e4095a81d 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.cpp @@ -39,18 +39,17 @@ public: LastKeyLocation = TOP_KEY; LastKeyLocation32Bit = TOP_KEY32BIT; FindPageRangePtr = &MemAllocator32Bit::FindPageRange_TopDown; - } - else { + } else { LastScanLocation = BASE_KEY; LastKeyLocation = BASE_KEY; FindPageRangePtr = &MemAllocator32Bit::FindPageRange; } } - void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override; - int Munmap(void *addr, size_t length) override; - void *Mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) override; - uint64_t Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t *ResultAddress) override; + void* Mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) override; + int Munmap(void* addr, size_t length) override; + void* Mremap(void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) override; + uint64_t Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t* ResultAddress) override; uint64_t Shmdt(const void* shmaddr) override; static constexpr bool SearchDown = true; @@ -76,15 +75,15 @@ private: // Set that contains 4k mapped pages // This is the full 32bit memory range std::bitset<0x10'0000> MappedPages; - fextl::map PageToShm{}; - uint64_t LastScanLocation{}; - uint64_t LastKeyLocation{}; - uint64_t LastKeyLocation32Bit{}; - std::mutex AllocMutex{}; + fextl::map PageToShm {}; + uint64_t LastScanLocation {}; + uint64_t LastKeyLocation {}; + uint64_t LastKeyLocation32Bit {}; + std::mutex AllocMutex {}; uint64_t FindPageRange(uint64_t Start, size_t Pages) const; uint64_t FindPageRange_TopDown(uint64_t Start, size_t Pages) const; - using FindHandler = uint64_t(MemAllocator32Bit::*)(uint64_t Start, size_t Pages) const; - FindHandler FindPageRangePtr{}; + using FindHandler = uint64_t (MemAllocator32Bit::*)(uint64_t Start, size_t Pages) const; + FindHandler FindPageRangePtr {}; }; uint64_t MemAllocator32Bit::FindPageRange(uint64_t Start, size_t Pages) const { @@ -113,8 +112,7 @@ uint64_t MemAllocator32Bit::FindPageRange(uint64_t Start, size_t Pages) const { uint64_t MemAllocator32Bit::FindPageRange_TopDown(uint64_t Start, size_t Pages) const { // Linear range scan - while (Start >= BASE_KEY && - Start <= TOP_KEY) { + while (Start >= BASE_KEY && Start <= TOP_KEY) { bool Free = true; uint64_t Offset = 0; @@ -134,8 +132,8 @@ uint64_t MemAllocator32Bit::FindPageRange_TopDown(uint64_t Start, size_t Pages) return 0; } -void *MemAllocator32Bit::Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - std::scoped_lock lk{AllocMutex}; +void* MemAllocator32Bit::Mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + std::scoped_lock lk {AllocMutex}; size_t PagesLength = FEXCore::AlignUp(length, FEXCore::Utils::FEX_PAGE_SIZE) >> FEXCore::Utils::FEX_PAGE_SHIFT; uintptr_t Addr = reinterpret_cast(addr); @@ -143,8 +141,7 @@ void *MemAllocator32Bit::Mmap(void *addr, size_t length, int prot, int flags, in // Define MAP_FIXED_NOREPLACE ourselves to ensure we always parse this flag constexpr int FEX_MAP_FIXED_NOREPLACE = 0x100000; - bool Fixed = ((flags & MAP_FIXED) || - (flags & FEX_MAP_FIXED_NOREPLACE)); + bool Fixed = ((flags & MAP_FIXED) || (flags & FEX_MAP_FIXED_NOREPLACE)); // Both Addr and length must be page aligned if (Addr & ~FEXCore::Utils::FEX_PAGE_MASK) { @@ -152,8 +149,7 @@ void *MemAllocator32Bit::Mmap(void *addr, size_t length, int prot, int flags, in } // If we do have an fd then offset must be page aligned - if (fd != -1 && - offset & ~FEXCore::Utils::FEX_PAGE_MASK) { + if (fd != -1 && offset & ~FEXCore::Utils::FEX_PAGE_MASK) { return reinterpret_cast(-EINVAL); } @@ -177,116 +173,91 @@ void *MemAllocator32Bit::Mmap(void *addr, size_t length, int prot, int flags, in // Remove the MAP_32BIT flag if it exists now flags &= ~FEX::HLE::X86_64_MAP_32BIT; - auto AllocateNoHint = [&]() -> void*{ + auto AllocateNoHint = [&]() -> void* { bool Wrapped = false; uint64_t BottomPage = Map32Bit && (LastScanLocation >= LastKeyLocation32Bit) ? LastKeyLocation32Bit : LastScanLocation; -restart: - { - // Linear range scan - uint64_t LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); - if (LowerPage == 0) { - // Try again but this time from the start - BottomPage = Map32Bit ? LastKeyLocation32Bit : LastKeyLocation; - LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); +restart : { + // Linear range scan + uint64_t LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); + if (LowerPage == 0) { + // Try again but this time from the start + BottomPage = Map32Bit ? LastKeyLocation32Bit : LastKeyLocation; + LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); + } + + uint64_t UpperPage = LowerPage + PagesLength; + if (LowerPage == 0) { + return reinterpret_cast(-ENOMEM); + } + { + // Try and map the range + void* MappedPtr = + ::mmap(reinterpret_cast(LowerPage << FEXCore::Utils::FEX_PAGE_SHIFT), length, prot, flags | FEX_MAP_FIXED_NOREPLACE, fd, offset); + + if (MappedPtr == MAP_FAILED && errno != EEXIST) { + return reinterpret_cast(-errno); + } else if (MappedPtr == MAP_FAILED || MappedPtr >= reinterpret_cast(TOP_KEY << FEXCore::Utils::FEX_PAGE_SHIFT)) { + // Handles the case where MAP_FIXED_NOREPLACE failed with MAP_FAILED + // or if the host system's kernel isn't new enough then it returns the wrong pointer + if (MappedPtr != MAP_FAILED && MappedPtr >= reinterpret_cast(TOP_KEY << FEXCore::Utils::FEX_PAGE_SHIFT)) { + // Make sure to munmap this so we don't leak memory + ::munmap(MappedPtr, length); } - uint64_t UpperPage = LowerPage + PagesLength; - if (LowerPage == 0) { - return reinterpret_cast(-ENOMEM); + if (UpperPage == TOP_KEY) { + BottomPage = BASE_KEY; + Wrapped = true; + goto restart; + } else if (Wrapped && LowerPage >= LastScanLocation) { + // We linear scanned the entire memory range. Give up + return (void*)(uintptr_t)-errno; + } else { + // Try again + if (SearchDown) { + --BottomPage; + } else { + ++BottomPage; + } + goto restart; } - { - // Try and map the range - void *MappedPtr = ::mmap( - reinterpret_cast(LowerPage << FEXCore::Utils::FEX_PAGE_SHIFT), - length, - prot, - flags | FEX_MAP_FIXED_NOREPLACE, - fd, - offset); - - if (MappedPtr == MAP_FAILED && - errno != EEXIST) { - return reinterpret_cast(-errno); - } - else if (MappedPtr == MAP_FAILED || - MappedPtr >= reinterpret_cast(TOP_KEY << FEXCore::Utils::FEX_PAGE_SHIFT)) { - // Handles the case where MAP_FIXED_NOREPLACE failed with MAP_FAILED - // or if the host system's kernel isn't new enough then it returns the wrong pointer - if (MappedPtr != MAP_FAILED && - MappedPtr >= reinterpret_cast(TOP_KEY << FEXCore::Utils::FEX_PAGE_SHIFT)) { - // Make sure to munmap this so we don't leak memory - ::munmap(MappedPtr, length); - } - - if (UpperPage == TOP_KEY) { - BottomPage = BASE_KEY; - Wrapped = true; - goto restart; - } - else if (Wrapped && - LowerPage >= LastScanLocation) { - // We linear scanned the entire memory range. Give up - return (void*)(uintptr_t)-errno; - } - else { - // Try again - if (SearchDown) { - --BottomPage; - } - else { - ++BottomPage; - } - goto restart; - } - } - else { - if (SearchDown) { - LastScanLocation = LowerPage; - } - else { - LastScanLocation = UpperPage; - } - SetUsedPages(LowerPage, PagesLength); - return MappedPtr; - } + } else { + if (SearchDown) { + LastScanLocation = LowerPage; + } else { + LastScanLocation = UpperPage; } + SetUsedPages(LowerPage, PagesLength); + return MappedPtr; } + } +} }; // Find a region that fits our address if (Addr == 0) { return AllocateNoHint(); - } - else { - void *MappedPtr = ::mmap( - reinterpret_cast(PageAddr << FEXCore::Utils::FEX_PAGE_SHIFT), - PagesLength << FEXCore::Utils::FEX_PAGE_SHIFT, - prot, - flags, - fd, - offset); + } else { + void* MappedPtr = ::mmap(reinterpret_cast(PageAddr << FEXCore::Utils::FEX_PAGE_SHIFT), + PagesLength << FEXCore::Utils::FEX_PAGE_SHIFT, prot, flags, fd, offset); - if (MappedPtr >= reinterpret_cast(TOP_KEY << FEXCore::Utils::FEX_PAGE_SHIFT) && - (flags & FEX_MAP_FIXED_NOREPLACE)) { + if (MappedPtr >= reinterpret_cast(TOP_KEY << FEXCore::Utils::FEX_PAGE_SHIFT) && (flags & FEX_MAP_FIXED_NOREPLACE)) { // Handles the case where MAP_FIXED_NOREPLACE isn't handled by the host system's // kernel and returns the wrong pointer // Make sure to munmap this so we don't leak memory ::munmap(MappedPtr, length); return reinterpret_cast(-EEXIST); - } - else if (MappedPtr != MAP_FAILED) { + } else if (MappedPtr != MAP_FAILED) { SetUsedPages(PageAddr, PagesLength); return MappedPtr; - } - else { + } else { return reinterpret_cast(-errno); } } return 0; } -int MemAllocator32Bit::Munmap(void *addr, size_t length) { - std::scoped_lock lk{AllocMutex}; +int MemAllocator32Bit::Munmap(void* addr, size_t length) { + std::scoped_lock lk {AllocMutex}; size_t PagesLength = FEXCore::AlignUp(length, FEXCore::Utils::FEX_PAGE_SIZE) >> FEXCore::Utils::FEX_PAGE_SHIFT; uintptr_t Addr = reinterpret_cast(addr); @@ -330,14 +301,14 @@ int MemAllocator32Bit::Munmap(void *addr, size_t length) { return 0; } -void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) { +void* MemAllocator32Bit::Mremap(void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) { size_t OldPagesLength = FEXCore::AlignUp(old_size, FEXCore::Utils::FEX_PAGE_SIZE) >> FEXCore::Utils::FEX_PAGE_SHIFT; size_t NewPagesLength = FEXCore::AlignUp(new_size, FEXCore::Utils::FEX_PAGE_SIZE) >> FEXCore::Utils::FEX_PAGE_SHIFT; { - std::scoped_lock lk{AllocMutex}; + std::scoped_lock lk {AllocMutex}; if (flags & MREMAP_FIXED) { - void *MappedPtr = ::mremap(old_address, old_size, new_size, flags, new_address); + void* MappedPtr = ::mremap(old_address, old_size, new_size, flags, new_address); if (MappedPtr != MAP_FAILED) { if (!(flags & MREMAP_DONTUNMAP)) { @@ -349,17 +320,15 @@ void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_s // Map the new pages uintptr_t NewAddr = reinterpret_cast(MappedPtr); SetUsedPages(NewAddr >> FEXCore::Utils::FEX_PAGE_SHIFT, NewPagesLength); - } - else { + } else { return reinterpret_cast(-errno); } - } - else { + } else { uintptr_t OldAddr = reinterpret_cast(old_address); uintptr_t OldPageAddr = OldAddr >> FEXCore::Utils::FEX_PAGE_SHIFT; if (NewPagesLength < OldPagesLength) { - void *MappedPtr = ::mremap(old_address, old_size, new_size, flags & ~MREMAP_MAYMOVE); + void* MappedPtr = ::mremap(old_address, old_size, new_size, flags & ~MREMAP_MAYMOVE); if (MappedPtr != MAP_FAILED) { // Clear the pages that we just shrunk @@ -367,14 +336,12 @@ void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_s uintptr_t NewPageAddr = reinterpret_cast(MappedPtr) >> FEXCore::Utils::FEX_PAGE_SHIFT; SetFreePages(NewPageAddr + NewPagesLength, OldPagesLength - NewPagesLength); return MappedPtr; - } - else { + } else { return reinterpret_cast(-errno); } - } - else { + } else { // Scan the region forward from our first region's endd to see if it can be extended - bool CanExtend{true}; + bool CanExtend {true}; for (size_t i = OldPagesLength; i < NewPagesLength; ++i) { if (MappedPages[OldPageAddr + i]) { @@ -384,7 +351,7 @@ void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_s } if (CanExtend) { - void *MappedPtr = ::mremap(old_address, old_size, new_size, flags & ~MREMAP_MAYMOVE); + void* MappedPtr = ::mremap(old_address, old_size, new_size, flags & ~MREMAP_MAYMOVE); if (MappedPtr != MAP_FAILED) { // Map the new pages @@ -392,8 +359,7 @@ void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_s uintptr_t NewAddr = reinterpret_cast(MappedPtr); SetUsedPages(NewAddr >> FEXCore::Utils::FEX_PAGE_SHIFT, NewPagesLength); return MappedPtr; - } - else if (!(flags & MREMAP_MAYMOVE)) { + } else if (!(flags & MREMAP_MAYMOVE)) { // We have one more chance if MAYMOVE is specified return reinterpret_cast(-errno); } @@ -407,8 +373,8 @@ void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_s // New Size is >= old size // First, try and allocate a region the size of the new size - void *MappedPtr = this->Mmap(nullptr, new_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - std::scoped_lock lk{AllocMutex}; + void* MappedPtr = this->Mmap(nullptr, new_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + std::scoped_lock lk {AllocMutex}; if (FEX::HLE::HasSyscallError(MappedPtr)) { // Couldn't find a region that fit our space return MappedPtr; @@ -419,12 +385,11 @@ void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_s MappedPtr = ::mremap(old_address, old_size, new_size, flags | MREMAP_FIXED | MREMAP_MAYMOVE, MappedPtr); if (MappedPtr != MAP_FAILED) { - if (!(flags & MREMAP_DONTUNMAP) && - MappedPtr != old_address) { + if (!(flags & MREMAP_DONTUNMAP) && MappedPtr != old_address) { // If we have both MREMAP_DONTUNMAP not set and the new pointer is at a new location // Make sure to clear the old mapping uintptr_t OldAddr = reinterpret_cast(old_address); - SetFreePages(OldAddr >> FEXCore::Utils::FEX_PAGE_SHIFT , OldPagesLength); + SetFreePages(OldAddr >> FEXCore::Utils::FEX_PAGE_SHIFT, OldPagesLength); } // Map the new pages @@ -438,16 +403,15 @@ void *MemAllocator32Bit::Mremap(void *old_address, size_t old_size, size_t new_s return reinterpret_cast(-errno); } -uint64_t MemAllocator32Bit::Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t *ResultAddress) { - std::scoped_lock lk{AllocMutex}; +uint64_t MemAllocator32Bit::Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t* ResultAddress) { + std::scoped_lock lk {AllocMutex}; if (shmaddr != nullptr) { // shmaddr must be valid uint64_t Result = reinterpret_cast(::shmat(shmid, shmaddr, shmflg)); if (Result != -1) { uint32_t SmallRet = Result >> 32; - if (!(SmallRet == 0 || - SmallRet == ~0U)) { + if (!(SmallRet == 0 || SmallRet == ~0U)) { LOGMAN_MSG_A_FMT("Syscall returning something with data in the upper 32bits! BUG!"); return -ENOMEM; } @@ -461,7 +425,7 @@ uint64_t MemAllocator32Bit::Shmat(int shmid, const void* shmaddr, int shmflg, ui *ResultAddress = Result; // We must get the shm size and track it - struct shmid_ds buf{}; + struct shmid_ds buf {}; if (shmctl(shmid, IPC_STAT, &buf) == 0) { // Map the new pages @@ -471,88 +435,76 @@ uint64_t MemAllocator32Bit::Shmat(int shmid, const void* shmaddr, int shmflg, ui // Zero on working result Result = 0; - } - else { + } else { Result = -errno; } return Result; - } - else { + } else { // We must get the shm size and track it - struct shmid_ds buf{}; - uint64_t PagesLength{}; + struct shmid_ds buf {}; + uint64_t PagesLength {}; if (shmctl(shmid, IPC_STAT, &buf) == 0) { PagesLength = FEXCore::AlignUp(buf.shm_segsz, FEXCore::Utils::FEX_PAGE_SIZE) >> FEXCore::Utils::FEX_PAGE_SHIFT; - } - else { + } else { return -EINVAL; } bool Wrapped = false; uint64_t BottomPage = LastScanLocation; -restart: - { - // Linear range scan - uint64_t LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); - if (LowerPage == 0) { - // Try again but this time from the start +restart : { + // Linear range scan + uint64_t LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); + if (LowerPage == 0) { + // Try again but this time from the start + BottomPage = LastKeyLocation; + LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); + } + + uint64_t UpperPage = LowerPage + PagesLength; + if (LowerPage == 0) { + return -ENOMEM; + } + { + // Try and map the range + void* MappedPtr = ::shmat(shmid, reinterpret_cast(LowerPage << FEXCore::Utils::FEX_PAGE_SHIFT), shmflg); + + if (MappedPtr == MAP_FAILED) { + if (UpperPage == TOP_KEY) { BottomPage = LastKeyLocation; - LowerPage = (this->*FindPageRangePtr)(BottomPage, PagesLength); + Wrapped = true; + goto restart; + } else if (Wrapped && LowerPage >= LastScanLocation) { + // We linear scanned the entire memory range. Give up + return -errno; + } else { + // Try again + BottomPage += PagesLength; + goto restart; } - - uint64_t UpperPage = LowerPage + PagesLength; - if (LowerPage == 0) { - return -ENOMEM; + } else { + if (SearchDown) { + LastScanLocation = LowerPage; + } else { + LastScanLocation = UpperPage; } - { - // Try and map the range - void *MappedPtr = ::shmat( - shmid, - reinterpret_cast(LowerPage << FEXCore::Utils::FEX_PAGE_SHIFT), - shmflg); + // Set the range as mapped + SetUsedPages(LowerPage, PagesLength); - if (MappedPtr == MAP_FAILED) { - if (UpperPage == TOP_KEY) { - BottomPage = LastKeyLocation; - Wrapped = true; - goto restart; - } - else if (Wrapped && - LowerPage >= LastScanLocation) { - // We linear scanned the entire memory range. Give up - return -errno; - } - else { - // Try again - BottomPage += PagesLength; - goto restart; - } - } - else { - if (SearchDown) { - LastScanLocation = LowerPage; - } - else { - LastScanLocation = UpperPage; - } - // Set the range as mapped - SetUsedPages(LowerPage, PagesLength); + *ResultAddress = reinterpret_cast(MappedPtr); - *ResultAddress = reinterpret_cast(MappedPtr); + // Add to the map + PageToShm[LowerPage] = shmid; - // Add to the map - PageToShm[LowerPage] = shmid; - - // Zero on working result - return 0; - } - } + // Zero on working result + return 0; } } +} + } } uint64_t MemAllocator32Bit::Shmdt(const void* shmaddr) { - std::scoped_lock lk{AllocMutex}; + std::scoped_lock lk {AllocMutex}; uint32_t AddrPage = reinterpret_cast(shmaddr) >> FEXCore::Utils::FEX_PAGE_SHIFT; auto it = PageToShm.find(AddrPage); @@ -570,7 +522,7 @@ uint64_t MemAllocator32Bit::Shmdt(const void* shmaddr) { class MemAllocatorPassThrough final : public FEX::HLE::MemAllocator { public: - void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override { + void* Mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) override { uint64_t Result = (uint64_t)::mmap(addr, length, prot, flags, fd, offset); if (Result == ~0ULL) { return reinterpret_cast(-errno); @@ -578,12 +530,12 @@ public: return reinterpret_cast(Result); } - int Munmap(void *addr, size_t length) override { + int Munmap(void* addr, size_t length) override { uint64_t Result = (uint64_t)::munmap(addr, length); SYSCALL_ERRNO(); } - void *Mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) override { + void* Mremap(void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) override { uint64_t Result = (uint64_t)::mremap(old_address, old_size, new_size, flags, new_address); if (Result == ~0ULL) { return reinterpret_cast(-errno); @@ -591,7 +543,7 @@ public: return reinterpret_cast(Result); } - uint64_t Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t *ResultAddress) override { + uint64_t Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t* ResultAddress) override { uint64_t Result = (uint64_t)::shmat(shmid, reinterpret_cast(shmaddr), shmflg); if (Result != ~0ULL) { *ResultAddress = Result; @@ -614,4 +566,4 @@ fextl::unique_ptr CreatePassthroughAllocator() { return fextl::make_unique(); } -} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.h index 01ffecda5..dd6ae074f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/LinuxAllocator.h @@ -7,18 +7,18 @@ #include namespace FEX::HLE { - constexpr uint32_t X86_64_MAP_32BIT = 0x40; +constexpr uint32_t X86_64_MAP_32BIT = 0x40; - class MemAllocator { - public: - virtual ~MemAllocator() = default; - virtual void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) = 0; - virtual int Munmap(void *addr, size_t length) = 0; - virtual void *Mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) = 0; - virtual uint64_t Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t *ResultAddress) = 0; - virtual uint64_t Shmdt(const void* shmaddr) = 0; - }; +class MemAllocator { +public: + virtual ~MemAllocator() = default; + virtual void* Mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) = 0; + virtual int Munmap(void* addr, size_t length) = 0; + virtual void* Mremap(void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) = 0; + virtual uint64_t Shmat(int shmid, const void* shmaddr, int shmflg, uint32_t* ResultAddress) = 0; + virtual uint64_t Shmdt(const void* shmaddr) = 0; +}; - fextl::unique_ptr Create32BitAllocator(); - fextl::unique_ptr CreatePassthroughAllocator(); -} +fextl::unique_ptr Create32BitAllocator(); +fextl::unique_ptr CreatePassthroughAllocator(); +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.cpp index 7e8d3735f..31a9f5207 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.cpp @@ -14,16 +14,17 @@ namespace FEXCore::Utils { namespace { -class NetBuf final : public std::streambuf, public FEXCore::Allocator::FEXAllocOperators { -public: - explicit NetBuf(int socketfd) : socket{socketfd} { - reset_output_buffer(); + class NetBuf final : public std::streambuf, public FEXCore::Allocator::FEXAllocOperators { + public: + explicit NetBuf(int socketfd) + : socket {socketfd} { + reset_output_buffer(); } ~NetBuf() override { - close(socket); + close(socket); } -private: + private: std::streamsize xsputn(const char* buffer, std::streamsize size) override; std::streambuf::int_type underflow() override; @@ -31,84 +32,84 @@ private: int sync() override; void reset_output_buffer() { - // we always leave room for one extra char - setp(std::begin(output_buffer), std::end(output_buffer) -1); + // we always leave room for one extra char + setp(std::begin(output_buffer), std::end(output_buffer) - 1); } - int flushBuffer(const char *buffer, size_t size); + int flushBuffer(const char* buffer, size_t size); int socket; std::array output_buffer; std::array input_buffer; // enough for a typical packet -}; + }; -int NetBuf::flushBuffer(const char *buffer, size_t size) { + int NetBuf::flushBuffer(const char* buffer, size_t size) { #ifndef _WIN32 size_t total = 0; // Send data while (total < size) { - size_t sent = send(socket, (const void*)(buffer + total), size - total, MSG_NOSIGNAL); - if (sent == -1) { - // lets just assume all errors are end of file. - return -1; - } - total += sent; + size_t sent = send(socket, (const void*)(buffer + total), size - total, MSG_NOSIGNAL); + if (sent == -1) { + // lets just assume all errors are end of file. + return -1; + } + total += sent; } return 0; #else - ERROR_AND_DIE_FMT("Unsupported"); + ERROR_AND_DIE_FMT("Unsupported"); #endif -} + } -std::streamsize NetBuf::xsputn(const char* buffer, std::streamsize size) { + std::streamsize NetBuf::xsputn(const char* buffer, std::streamsize size) { size_t buf_remaining = epptr() - pptr(); // Check if the string fits neatly in our buffer if (size <= buf_remaining) { - ::memcpy(pptr(), buffer, size); - pbump(size); - return size; + ::memcpy(pptr(), buffer, size); + pbump(size); + return size; } // Otherwise, flush the buffer first if (sync() < 0) { - return traits_type::eof(); + return traits_type::eof(); } if (size > sizeof(output_buffer) / 2) { - // If we have a large string, bypass the buffer - flushBuffer(buffer, size); - return size; + // If we have a large string, bypass the buffer + flushBuffer(buffer, size); + return size; } else { - return xsputn(buffer, size); + return xsputn(buffer, size); } -} + } -std::streambuf::int_type NetBuf::overflow(std::streambuf::int_type ch) { + std::streambuf::int_type NetBuf::overflow(std::streambuf::int_type ch) { // we always leave room for one extra char - *pptr() = (char) ch; + *pptr() = (char)ch; pbump(1); return sync(); -} + } -int NetBuf::sync() { + int NetBuf::sync() { // Flush and reset output buffer to zero if (flushBuffer(pbase(), pptr() - pbase()) < 0) { - return -1; + return -1; } reset_output_buffer(); return 0; -} + } -std::streambuf::int_type NetBuf::underflow() { + std::streambuf::int_type NetBuf::underflow() { #ifndef _WIN32 - ssize_t size = recv(socket, (void *)std::begin(input_buffer), sizeof(input_buffer), 0); + ssize_t size = recv(socket, (void*)std::begin(input_buffer), sizeof(input_buffer), 0); if (size <= 0) { - setg(nullptr, nullptr, nullptr); - return traits_type::eof(); + setg(nullptr, nullptr, nullptr); + return traits_type::eof(); } setg(&input_buffer[0], &input_buffer[0], &input_buffer[size]); @@ -117,13 +118,14 @@ std::streambuf::int_type NetBuf::underflow() { #else ERROR_AND_DIE_FMT("Unsupported"); #endif -} + } } // Anonymous namespace -NetStream::NetStream(int socketfd) : std::iostream(new NetBuf(socketfd)) {} +NetStream::NetStream(int socketfd) + : std::iostream(new NetBuf(socketfd)) {} NetStream::~NetStream() { - delete rdbuf(); + delete rdbuf(); } } // namespace FEXCore::Utils diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.h index f7c919486..500296272 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/NetStream.h @@ -8,7 +8,7 @@ namespace FEXCore::Utils { class FEX_DEFAULT_VISIBILITY NetStream : public std::iostream { public: - explicit NetStream(int socketfd); - ~NetStream() override; + explicit NetStream(int socketfd); + ~NetStream() override; }; } // namespace FEXCore::Utils diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp index 0f5b16695..588fc77d5 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp @@ -43,696 +43,378 @@ $end_info$ namespace FEX::HLE { #ifdef _M_X86_64 - __attribute__((naked)) - static void sigrestore() { - __asm volatile("syscall;" - :: "a" (0xF) - : "memory"); - } +__attribute__((naked)) static void sigrestore() { + __asm volatile("syscall;" ::"a"(0xF) : "memory"); +} #endif - constexpr static uint32_t X86_MINSIGSTKSZ = 0x2000U; +constexpr static uint32_t X86_MINSIGSTKSZ = 0x2000U; - // We can only have one delegator per process - static SignalDelegator *GlobalDelegator{}; +// We can only have one delegator per process +static SignalDelegator* GlobalDelegator {}; - struct ThreadState { - FEXCore::Core::InternalThreadState *Thread{}; +struct ThreadState { + FEXCore::Core::InternalThreadState* Thread {}; - void *AltStackPtr{}; - stack_t GuestAltStack { - .ss_sp = nullptr, - .ss_flags = SS_DISABLE, // By default the guest alt stack is disabled - .ss_size = 0, - }; - // This is the thread's current signal mask - GuestSAMask CurrentSignalMask{}; - // The mask prior to a suspend - GuestSAMask PreviousSuspendMask{}; - - uint64_t PendingSignals{}; + void* AltStackPtr {}; + stack_t GuestAltStack { + .ss_sp = nullptr, + .ss_flags = SS_DISABLE, // By default the guest alt stack is disabled + .ss_size = 0, }; + // This is the thread's current signal mask + GuestSAMask CurrentSignalMask {}; + // The mask prior to a suspend + GuestSAMask PreviousSuspendMask {}; - thread_local ThreadState ThreadData{}; + uint64_t PendingSignals {}; +}; - static void SignalHandlerThunk(int Signal, siginfo_t *Info, void *UContext) { - GlobalDelegator->HandleSignal(Signal, Info, UContext); - } +thread_local ThreadState ThreadData {}; - uint64_t SigIsMember(GuestSAMask *Set, int Signal) { - // Signal 0 isn't real, so everything is offset by one inside the set - Signal -= 1; - return (Set->Val >> Signal) & 1; - } +static void SignalHandlerThunk(int Signal, siginfo_t* Info, void* UContext) { + GlobalDelegator->HandleSignal(Signal, Info, UContext); +} - uint64_t SetSignal(GuestSAMask *Set, int Signal) { - // Signal 0 isn't real, so everything is offset by one inside the set - Signal -= 1; - return Set->Val | (1ULL << Signal); - } +uint64_t SigIsMember(GuestSAMask* Set, int Signal) { + // Signal 0 isn't real, so everything is offset by one inside the set + Signal -= 1; + return (Set->Val >> Signal) & 1; +} - /** - * @name Signal frame setup - * @{ */ +uint64_t SetSignal(GuestSAMask* Set, int Signal) { + // Signal 0 isn't real, so everything is offset by one inside the set + Signal -= 1; + return Set->Val | (1ULL << Signal); +} - // Total number of layouts that siginfo supports. - enum class SigInfoLayout { - LAYOUT_KILL, - LAYOUT_TIMER, - LAYOUT_POLL, - LAYOUT_FAULT, - LAYOUT_FAULT_RIP, - LAYOUT_CHLD, - LAYOUT_RT, - LAYOUT_SYS, - }; +/** + * @name Signal frame setup + * @{ */ - // Calculate the siginfo layout based on Signal and si_code. - static SigInfoLayout CalculateSigInfoLayout(int Signal, int si_code) { - if (si_code > SI_USER && si_code < SI_KERNEL) { - // For signals that are not considered RT. - if (Signal == SIGSEGV || - Signal == SIGBUS || - Signal == SIGTRAP) { - // Regular FAULT layout. - return SigInfoLayout::LAYOUT_FAULT; - } - else if (Signal == SIGILL || - Signal == SIGFPE) { - // Fault layout but addr refers to RIP. - return SigInfoLayout::LAYOUT_FAULT_RIP; - } - else if (Signal == SIGCHLD) { - // Child layout - return SigInfoLayout::LAYOUT_CHLD; - } - else if (Signal == SIGPOLL) { - // Poll layout - return SigInfoLayout::LAYOUT_POLL; - } - else if (Signal == SIGSYS) { - // Sys layout - return SigInfoLayout::LAYOUT_SYS; - } +// Total number of layouts that siginfo supports. +enum class SigInfoLayout { + LAYOUT_KILL, + LAYOUT_TIMER, + LAYOUT_POLL, + LAYOUT_FAULT, + LAYOUT_FAULT_RIP, + LAYOUT_CHLD, + LAYOUT_RT, + LAYOUT_SYS, +}; + +// Calculate the siginfo layout based on Signal and si_code. +static SigInfoLayout CalculateSigInfoLayout(int Signal, int si_code) { + if (si_code > SI_USER && si_code < SI_KERNEL) { + // For signals that are not considered RT. + if (Signal == SIGSEGV || Signal == SIGBUS || Signal == SIGTRAP) { + // Regular FAULT layout. + return SigInfoLayout::LAYOUT_FAULT; + } else if (Signal == SIGILL || Signal == SIGFPE) { + // Fault layout but addr refers to RIP. + return SigInfoLayout::LAYOUT_FAULT_RIP; + } else if (Signal == SIGCHLD) { + // Child layout + return SigInfoLayout::LAYOUT_CHLD; + } else if (Signal == SIGPOLL) { + // Poll layout + return SigInfoLayout::LAYOUT_POLL; + } else if (Signal == SIGSYS) { + // Sys layout + return SigInfoLayout::LAYOUT_SYS; } - else { - // Negative si_codes are kernel specific things. - if (si_code == SI_TIMER) { - return SigInfoLayout::LAYOUT_TIMER; - } - else if (si_code == SI_SIGIO) { - return SigInfoLayout::LAYOUT_POLL; - } - else if (si_code < 0) { - return SigInfoLayout::LAYOUT_RT; - } + } else { + // Negative si_codes are kernel specific things. + if (si_code == SI_TIMER) { + return SigInfoLayout::LAYOUT_TIMER; + } else if (si_code == SI_SIGIO) { + return SigInfoLayout::LAYOUT_POLL; + } else if (si_code < 0) { + return SigInfoLayout::LAYOUT_RT; } - - return SigInfoLayout::LAYOUT_KILL; } - void SignalDelegator::HandleSignal(int Signal, void *Info, void *UContext) { - // Let the host take first stab at handling the signal - auto Thread = GetTLSThread(); + return SigInfoLayout::LAYOUT_KILL; +} - if (!Thread) { - LogMan::Msg::AFmt("[{}] Thread has received a signal and hasn't registered itself with the delegate! Programming error!", FHU::Syscalls::gettid()); - } - else { - SignalHandler &Handler = HostHandlers[Signal]; - for (auto &HandlerFunc : Handler.Handlers) { - if (HandlerFunc(Thread, Signal, Info, UContext)) { - // If the host handler handled the fault then we can continue now - return; - } - } +void SignalDelegator::HandleSignal(int Signal, void* Info, void* UContext) { + // Let the host take first stab at handling the signal + auto Thread = GetTLSThread(); - if (Handler.FrontendHandler && - Handler.FrontendHandler(Thread, Signal, Info, UContext)) { + if (!Thread) { + LogMan::Msg::AFmt("[{}] Thread has received a signal and hasn't registered itself with the delegate! Programming error!", + FHU::Syscalls::gettid()); + } else { + SignalHandler& Handler = HostHandlers[Signal]; + for (auto& HandlerFunc : Handler.Handlers) { + if (HandlerFunc(Thread, Signal, Info, UContext)) { + // If the host handler handled the fault then we can continue now return; } - - // Now let the frontend handle the signal - // It's clearly a guest signal and this ends up being an OS specific issue - HandleGuestSignal(Thread, Signal, Info, UContext); } - } - void SignalDelegator::RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - SetHostSignalHandler(Signal, Func, Required); - FrontendRegisterHostSignalHandler(Signal, Func, Required); - } + if (Handler.FrontendHandler && Handler.FrontendHandler(Thread, Signal, Info, UContext)) { + return; + } - void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState *Thread, void *ucontext, uint32_t IgnoreMask) { + // Now let the frontend handle the signal + // It's clearly a guest signal and this ends up being an OS specific issue + HandleGuestSignal(Thread, Signal, Info, UContext); + } +} + +void SignalDelegator::RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + SetHostSignalHandler(Signal, Func, Required); + FrontendRegisterHostSignalHandler(Signal, Func, Required); +} + +void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState* Thread, void* ucontext, uint32_t IgnoreMask) { #ifdef _M_ARM_64 - for (size_t i = 0; i < Config.SRAGPRCount; i++) { - const uint8_t SRAIdxMap = Config.SRAGPRMapping[i]; - if (IgnoreMask & (1U << SRAIdxMap)) { - // Skip this one, it's already spilled - continue; - } - Thread->CurrentFrame->State.gregs[i] = ArchHelpers::Context::GetArmReg(ucontext, SRAIdxMap); + for (size_t i = 0; i < Config.SRAGPRCount; i++) { + const uint8_t SRAIdxMap = Config.SRAGPRMapping[i]; + if (IgnoreMask & (1U << SRAIdxMap)) { + // Skip this one, it's already spilled + continue; } + Thread->CurrentFrame->State.gregs[i] = ArchHelpers::Context::GetArmReg(ucontext, SRAIdxMap); + } - if (Config.SupportsAVX) { - // TODO: This doesn't save the upper 128-bits of the 256-bit registers. - // This needs to be implemented still. - for (size_t i = 0; i < Config.SRAFPRCount; i++) { - auto FPR = ArchHelpers::Context::GetArmFPR(ucontext, Config.SRAFPRMapping[i]); - memcpy(&Thread->CurrentFrame->State.xmm.avx.data[i][0], &FPR, sizeof(__uint128_t)); + if (Config.SupportsAVX) { + // TODO: This doesn't save the upper 128-bits of the 256-bit registers. + // This needs to be implemented still. + for (size_t i = 0; i < Config.SRAFPRCount; i++) { + auto FPR = ArchHelpers::Context::GetArmFPR(ucontext, Config.SRAFPRMapping[i]); + memcpy(&Thread->CurrentFrame->State.xmm.avx.data[i][0], &FPR, sizeof(__uint128_t)); + } + } else { + for (size_t i = 0; i < Config.SRAFPRCount; i++) { + auto FPR = ArchHelpers::Context::GetArmFPR(ucontext, Config.SRAFPRMapping[i]); + memcpy(&Thread->CurrentFrame->State.xmm.sse.data[i][0], &FPR, sizeof(__uint128_t)); + } + } +#endif +} + +static uint32_t ConvertSignalToTrapNo(int Signal, siginfo_t* HostSigInfo) { + switch (Signal) { + case SIGSEGV: + if (HostSigInfo->si_code == SEGV_MAPERR || HostSigInfo->si_code == SEGV_ACCERR) { + // Protection fault + return FEXCore::X86State::X86_TRAPNO_PF; + } + break; + } + + // Unknown mapping, fall back to old behaviour and just pass signal + return Signal; +} + +static uint32_t ConvertSignalToError(void* ucontext, int Signal, siginfo_t* HostSigInfo) { + switch (Signal) { + case SIGSEGV: + if (HostSigInfo->si_code == SEGV_MAPERR || HostSigInfo->si_code == SEGV_ACCERR) { + // Protection fault + // Always a user fault for us + return ArchHelpers::Context::GetProtectFlags(ucontext); + } + break; + } + + // Not a page fault issue + return 0; +} + +template +static void SetXStateInfo(T* xstate, bool is_avx_enabled) { + auto* fpstate = &xstate->fpstate; + + fpstate->sw_reserved.magic1 = FEXCore::x86_64::fpx_sw_bytes::FP_XSTATE_MAGIC; + fpstate->sw_reserved.extended_size = is_avx_enabled ? sizeof(T) : 0; + + fpstate->sw_reserved.xfeatures |= FEXCore::x86_64::fpx_sw_bytes::FEATURE_FP | FEXCore::x86_64::fpx_sw_bytes::FEATURE_SSE; + if (is_avx_enabled) { + fpstate->sw_reserved.xfeatures |= FEXCore::x86_64::fpx_sw_bytes::FEATURE_YMM; + } + + fpstate->sw_reserved.xstate_size = fpstate->sw_reserved.extended_size; + + if (is_avx_enabled) { + xstate->xstate_hdr.xfeatures = 0; + } +} + +ArchHelpers::Context::ContextBackup* SignalDelegator::StoreThreadState(FEXCore::Core::InternalThreadState* Thread, int Signal, void* ucontext) { + // We can end up getting a signal at any point in our host state + // Jump to a handler that saves all state so we can safely return + uint64_t OldSP = ArchHelpers::Context::GetSp(ucontext); + uintptr_t NewSP = OldSP; + + size_t StackOffset = sizeof(ArchHelpers::Context::ContextBackup); + + // We need to back up behind the host's red zone + // We do this on the guest side as well + // (does nothing on arm hosts) + NewSP -= ArchHelpers::Context::ContextBackup::RedZoneSize; + + NewSP -= StackOffset; + NewSP = FEXCore::AlignDown(NewSP, 16); + + auto Context = reinterpret_cast(NewSP); + ArchHelpers::Context::BackupContext(ucontext, Context); + + // Retain the action pointer so we can see it when we return + Context->Signal = Signal; + + // Save guest state + // We can't guarantee if registers are in context or host GPRs + // So we need to save everything + memcpy(&Context->GuestState, &Thread->CurrentFrame->State, sizeof(FEXCore::Core::CPUState)); + + // Set the new SP + ArchHelpers::Context::SetSp(ucontext, NewSP); + + Context->Flags = 0; + Context->FPStateLocation = 0; + Context->UContextLocation = 0; + Context->SigInfoLocation = 0; + Context->InSyscallInfo = 0; + + // Store fault to top status and then reset it + Context->FaultToTopAndGeneratedException = Thread->CurrentFrame->SynchronousFaultData.FaultToTopAndGeneratedException; + Thread->CurrentFrame->SynchronousFaultData.FaultToTopAndGeneratedException = false; + + return Context; +} + +void SignalDelegator::RestoreThreadState(FEXCore::Core::InternalThreadState* Thread, void* ucontext, RestoreType Type) { + const bool IsAVXEnabled = Config.SupportsAVX; + + uint64_t OldSP {}; + if (Type == RestoreType::TYPE_PAUSE) [[unlikely]] { + OldSP = ArchHelpers::Context::GetSp(ucontext); + } else { + // Some fun introspection here. + // We store a pointer to our host-stack on the guest stack. + // We need to inspect the guest state coming in, so we can get our host stack back. + uint64_t GuestSP = Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]; + + if (Is64BitMode) { + // Signal frame layout on stack needs to be as follows + // void* ReturnPointer + // ucontext_t + // siginfo_t + // FP state + // Host stack location + + GuestSP += sizeof(FEXCore::x86_64::ucontext_t); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86_64::ucontext_t)); + + GuestSP += sizeof(siginfo_t); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(siginfo_t)); + + if (IsAVXEnabled) { + GuestSP += sizeof(FEXCore::x86_64::xstate); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86_64::xstate)); + } else { + GuestSP += sizeof(FEXCore::x86_64::_libc_fpstate); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86_64::_libc_fpstate)); } } else { - for (size_t i = 0; i < Config.SRAFPRCount; i++) { - auto FPR = ArchHelpers::Context::GetArmFPR(ucontext, Config.SRAFPRMapping[i]); - memcpy(&Thread->CurrentFrame->State.xmm.sse.data[i][0], &FPR, sizeof(__uint128_t)); - } - } -#endif - } - - static uint32_t ConvertSignalToTrapNo(int Signal, siginfo_t *HostSigInfo) { - switch (Signal) { - case SIGSEGV: - if (HostSigInfo->si_code == SEGV_MAPERR || - HostSigInfo->si_code == SEGV_ACCERR) { - // Protection fault - return FEXCore::X86State::X86_TRAPNO_PF; - } - break; - } - - // Unknown mapping, fall back to old behaviour and just pass signal - return Signal; - } - - static uint32_t ConvertSignalToError(void *ucontext, int Signal, siginfo_t *HostSigInfo) { - switch (Signal) { - case SIGSEGV: - if (HostSigInfo->si_code == SEGV_MAPERR || - HostSigInfo->si_code == SEGV_ACCERR) { - // Protection fault - // Always a user fault for us - return ArchHelpers::Context::GetProtectFlags(ucontext); - } - break; - } - - // Not a page fault issue - return 0; - } - - template - static void SetXStateInfo(T* xstate, bool is_avx_enabled) { - auto* fpstate = &xstate->fpstate; - - fpstate->sw_reserved.magic1 = FEXCore::x86_64::fpx_sw_bytes::FP_XSTATE_MAGIC; - fpstate->sw_reserved.extended_size = is_avx_enabled ? sizeof(T) : 0; - - fpstate->sw_reserved.xfeatures |= FEXCore::x86_64::fpx_sw_bytes::FEATURE_FP | - FEXCore::x86_64::fpx_sw_bytes::FEATURE_SSE; - if (is_avx_enabled) { - fpstate->sw_reserved.xfeatures |= FEXCore::x86_64::fpx_sw_bytes::FEATURE_YMM; - } - - fpstate->sw_reserved.xstate_size = fpstate->sw_reserved.extended_size; - - if (is_avx_enabled) { - xstate->xstate_hdr.xfeatures = 0; - } - } - - ArchHelpers::Context::ContextBackup* SignalDelegator::StoreThreadState(FEXCore::Core::InternalThreadState *Thread, int Signal, void *ucontext) { - // We can end up getting a signal at any point in our host state - // Jump to a handler that saves all state so we can safely return - uint64_t OldSP = ArchHelpers::Context::GetSp(ucontext); - uintptr_t NewSP = OldSP; - - size_t StackOffset = sizeof(ArchHelpers::Context::ContextBackup); - - // We need to back up behind the host's red zone - // We do this on the guest side as well - // (does nothing on arm hosts) - NewSP -= ArchHelpers::Context::ContextBackup::RedZoneSize; - - NewSP -= StackOffset; - NewSP = FEXCore::AlignDown(NewSP, 16); - - auto Context = reinterpret_cast(NewSP); - ArchHelpers::Context::BackupContext(ucontext, Context); - - // Retain the action pointer so we can see it when we return - Context->Signal = Signal; - - // Save guest state - // We can't guarantee if registers are in context or host GPRs - // So we need to save everything - memcpy(&Context->GuestState, &Thread->CurrentFrame->State, sizeof(FEXCore::Core::CPUState)); - - // Set the new SP - ArchHelpers::Context::SetSp(ucontext, NewSP); - - Context->Flags = 0; - Context->FPStateLocation = 0; - Context->UContextLocation = 0; - Context->SigInfoLocation = 0; - Context->InSyscallInfo = 0; - - // Store fault to top status and then reset it - Context->FaultToTopAndGeneratedException = Thread->CurrentFrame->SynchronousFaultData.FaultToTopAndGeneratedException; - Thread->CurrentFrame->SynchronousFaultData.FaultToTopAndGeneratedException = false; - - return Context; - } - - void SignalDelegator::RestoreThreadState(FEXCore::Core::InternalThreadState *Thread, void *ucontext, RestoreType Type) { - const bool IsAVXEnabled = Config.SupportsAVX; - - uint64_t OldSP{}; - if (Type == RestoreType::TYPE_PAUSE) [[unlikely]] { - OldSP = ArchHelpers::Context::GetSp(ucontext); - } - else { - // Some fun introspection here. - // We store a pointer to our host-stack on the guest stack. - // We need to inspect the guest state coming in, so we can get our host stack back. - uint64_t GuestSP = Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]; - - if (Is64BitMode) { + if (Type == RestoreType::TYPE_NONREALTIME) { // Signal frame layout on stack needs to be as follows - // void* ReturnPointer - // ucontext_t - // siginfo_t - // FP state + // SigFrame_i32 + // FPState // Host stack location - GuestSP += sizeof(FEXCore::x86_64::ucontext_t); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86_64::ucontext_t)); - - GuestSP += sizeof(siginfo_t); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(siginfo_t)); + // Remove the 4-byte pretcode /AND/ a legacy argument that is ignored. + GuestSP += sizeof(SigFrame_i32) - 8; + GuestSP = FEXCore::AlignUp(GuestSP, alignof(SigFrame_i32)); if (IsAVXEnabled) { - GuestSP += sizeof(FEXCore::x86_64::xstate); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86_64::xstate)); + GuestSP += sizeof(FEXCore::x86::xstate); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::xstate)); } else { - GuestSP += sizeof(FEXCore::x86_64::_libc_fpstate); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86_64::_libc_fpstate)); - } - } - else { - if (Type == RestoreType::TYPE_NONREALTIME) { - // Signal frame layout on stack needs to be as follows - // SigFrame_i32 - // FPState - // Host stack location - - // Remove the 4-byte pretcode /AND/ a legacy argument that is ignored. - GuestSP += sizeof(SigFrame_i32) - 8; - GuestSP = FEXCore::AlignUp(GuestSP, alignof(SigFrame_i32)); - - if (IsAVXEnabled) { - GuestSP += sizeof(FEXCore::x86::xstate); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::xstate)); - } else { - GuestSP += sizeof(FEXCore::x86::_libc_fpstate); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::_libc_fpstate)); - } - } - else { - // Signal frame layout on stack needs to be as follows - // RTSigFrame_i32 - // FPState - // Host stack location - - // Remove the 4-byte pretcode. - GuestSP += sizeof(RTSigFrame_i32) - 4; - GuestSP = FEXCore::AlignUp(GuestSP, alignof(RTSigFrame_i32)); - - if (IsAVXEnabled) { - GuestSP += sizeof(FEXCore::x86::xstate); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::xstate)); - } else { - GuestSP += sizeof(FEXCore::x86::_libc_fpstate); - GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::_libc_fpstate)); - } - } - } - - OldSP = *reinterpret_cast(GuestSP); - } - - uintptr_t NewSP = OldSP; - auto Context = reinterpret_cast(NewSP); - - // Restore host state - ArchHelpers::Context::RestoreContext(ucontext, Context); - - // Reset the guest state - memcpy(&Thread->CurrentFrame->State, &Context->GuestState, sizeof(FEXCore::Core::CPUState)); - - if (Context->UContextLocation) { - auto Frame = Thread->CurrentFrame; - - if (Context->Flags &ArchHelpers::Context::ContextFlags::CONTEXT_FLAG_INJIT) { - // XXX: Unsupported since it needs state reconstruction - // If we are in the JIT then SRA might need to be restored to values from the context - // We can't currently support this since it might result in tearing without real state reconstruction - } - - if (Is64BitMode) { - RestoreFrame_x64(Thread, Context, Frame, ucontext); - } - else { - if (Type == RestoreType::TYPE_NONREALTIME) { - RestoreFrame_ia32(Thread, Context, Frame, ucontext); - } - else { - RestoreRTFrame_ia32(Thread, Context, Frame, ucontext); - } - } - } - } - - void SignalDelegator::RestoreFrame_x64(FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* Context, FEXCore::Core::CpuStateFrame *Frame, void *ucontext) { - const bool IsAVXEnabled = Config.SupportsAVX; - - auto *guest_uctx = reinterpret_cast(Context->UContextLocation); - [[maybe_unused]] auto *guest_siginfo = reinterpret_cast(Context->SigInfoLocation); - - // If the guest modified the RIP then we need to take special precautions here - if (Context->OriginalRIP != guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP] || - Context->FaultToTopAndGeneratedException) { - - // Restore previous `InSyscallInfo` structure. - Frame->InSyscallInfo = Context->InSyscallInfo; - - // Hack! Go back to the top of the dispatcher top - // This is only safe inside the JIT rather than anything outside of it - ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); - // Set our state register to point to our guest thread data - ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); - - Frame->State.rip = guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP]; - // XXX: Full context setting - CTX->SetFlagsFromCompactedEFLAGS(Thread, guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_EFL]); - -#define COPY_REG(x) \ - Frame->State.gregs[FEXCore::X86State::REG_##x] = guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_##x]; - COPY_REG(R8); - COPY_REG(R9); - COPY_REG(R10); - COPY_REG(R11); - COPY_REG(R12); - COPY_REG(R13); - COPY_REG(R14); - COPY_REG(R15); - COPY_REG(RDI); - COPY_REG(RSI); - COPY_REG(RBP); - COPY_REG(RBX); - COPY_REG(RDX); - COPY_REG(RAX); - COPY_REG(RCX); - COPY_REG(RSP); -#undef COPY_REG - auto *xstate = reinterpret_cast(guest_uctx->uc_mcontext.fpregs); - auto *fpstate = &xstate->fpstate; - - // Copy float registers - memcpy(Frame->State.mm, fpstate->_st, sizeof(Frame->State.mm)); - - if (IsAVXEnabled) { - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&Frame->State.xmm.avx.data[i][0], &fpstate->_xmm[i], sizeof(__uint128_t)); - } - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&Frame->State.xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], sizeof(__uint128_t)); + GuestSP += sizeof(FEXCore::x86::_libc_fpstate); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::_libc_fpstate)); } } else { - memcpy(Frame->State.xmm.sse.data, fpstate->_xmm, sizeof(Frame->State.xmm.sse.data)); + // Signal frame layout on stack needs to be as follows + // RTSigFrame_i32 + // FPState + // Host stack location + + // Remove the 4-byte pretcode. + GuestSP += sizeof(RTSigFrame_i32) - 4; + GuestSP = FEXCore::AlignUp(GuestSP, alignof(RTSigFrame_i32)); + + if (IsAVXEnabled) { + GuestSP += sizeof(FEXCore::x86::xstate); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::xstate)); + } else { + GuestSP += sizeof(FEXCore::x86::_libc_fpstate); + GuestSP = FEXCore::AlignUp(GuestSP, alignof(FEXCore::x86::_libc_fpstate)); + } } - - // FCW store default - Frame->State.FCW = fpstate->fcw; - Frame->State.AbridgedFTW = fpstate->ftw; - - // Deconstruct FSW - Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (fpstate->fsw >> 8) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (fpstate->fsw >> 9) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (fpstate->fsw >> 10) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (fpstate->fsw >> 14) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (fpstate->fsw >> 11) & 0b111; } + + OldSP = *reinterpret_cast(GuestSP); } - void SignalDelegator::RestoreFrame_ia32(FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* Context, FEXCore::Core::CpuStateFrame *Frame, void *ucontext) { - const bool IsAVXEnabled = Config.SupportsAVX; + uintptr_t NewSP = OldSP; + auto Context = reinterpret_cast(NewSP); - SigFrame_i32 *guest_uctx = reinterpret_cast(Context->UContextLocation); - // If the guest modified the RIP then we need to take special precautions here - if (Context->OriginalRIP != guest_uctx->sc.ip || - Context->FaultToTopAndGeneratedException) { - // Restore previous `InSyscallInfo` structure. - Frame->InSyscallInfo = Context->InSyscallInfo; + // Restore host state + ArchHelpers::Context::RestoreContext(ucontext, Context); - // Hack! Go back to the top of the dispatcher top - // This is only safe inside the JIT rather than anything outside of it - ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); - // Set our state register to point to our guest thread data - ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); + // Reset the guest state + memcpy(&Thread->CurrentFrame->State, &Context->GuestState, sizeof(FEXCore::Core::CPUState)); - // XXX: Full context setting - CTX->SetFlagsFromCompactedEFLAGS(Thread, guest_uctx->sc.flags); + if (Context->UContextLocation) { + auto Frame = Thread->CurrentFrame; - Frame->State.rip = guest_uctx->sc.ip; - Frame->State.cs_idx = guest_uctx->sc.cs; - Frame->State.ds_idx = guest_uctx->sc.ds; - Frame->State.es_idx = guest_uctx->sc.es; - Frame->State.fs_idx = guest_uctx->sc.fs; - Frame->State.gs_idx = guest_uctx->sc.gs; - Frame->State.ss_idx = guest_uctx->sc.ss; - - Frame->State.cs_cached = Frame->State.gdt[Frame->State.cs_idx >> 3].base; - Frame->State.ds_cached = Frame->State.gdt[Frame->State.ds_idx >> 3].base; - Frame->State.es_cached = Frame->State.gdt[Frame->State.es_idx >> 3].base; - Frame->State.fs_cached = Frame->State.gdt[Frame->State.fs_idx >> 3].base; - Frame->State.gs_cached = Frame->State.gdt[Frame->State.gs_idx >> 3].base; - Frame->State.ss_cached = Frame->State.gdt[Frame->State.ss_idx >> 3].base; - -#define COPY_REG(x, y) \ - Frame->State.gregs[FEXCore::X86State::REG_##x] = guest_uctx->sc.y; - COPY_REG(RDI, di); - COPY_REG(RSI, si); - COPY_REG(RBP, bp); - COPY_REG(RBX, bx); - COPY_REG(RDX, dx); - COPY_REG(RAX, ax); - COPY_REG(RCX, cx); - COPY_REG(RSP, sp); -#undef COPY_REG - auto *xstate = reinterpret_cast(guest_uctx->sc.fpstate); - auto *fpstate = &xstate->fpstate; - - // Copy float registers - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { - // 32-bit st register size is only 10 bytes. Not padded to 16byte like x86-64 - memcpy(&Frame->State.mm[i], &fpstate->_st[i], 10); - } - - // Extended XMM state - if (IsAVXEnabled) { - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&Frame->State.xmm.avx.data[i][0], &fpstate->_xmm[i], sizeof(__uint128_t)); - } - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&Frame->State.xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], sizeof(__uint128_t)); - } - } else { - memcpy(Frame->State.xmm.sse.data, fpstate->_xmm, sizeof(Frame->State.xmm.sse.data)); - } - - // FCW store default - Frame->State.FCW = fpstate->fcw; - Frame->State.AbridgedFTW = FEXCore::FPState::ConvertToAbridgedFTW(fpstate->ftw); - - // Deconstruct FSW - Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (fpstate->fsw >> 8) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (fpstate->fsw >> 9) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (fpstate->fsw >> 10) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (fpstate->fsw >> 14) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (fpstate->fsw >> 11) & 0b111; + if (Context->Flags & ArchHelpers::Context::ContextFlags::CONTEXT_FLAG_INJIT) { + // XXX: Unsupported since it needs state reconstruction + // If we are in the JIT then SRA might need to be restored to values from the context + // We can't currently support this since it might result in tearing without real state reconstruction } - } - void SignalDelegator::RestoreRTFrame_ia32(FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* Context, FEXCore::Core::CpuStateFrame *Frame, void *ucontext) { - const bool IsAVXEnabled = Config.SupportsAVX; - - RTSigFrame_i32 *guest_uctx = reinterpret_cast(Context->UContextLocation); - // If the guest modified the RIP then we need to take special precautions here - if (Context->OriginalRIP != guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EIP] || - Context->FaultToTopAndGeneratedException) { - - // Restore previous `InSyscallInfo` structure. - Frame->InSyscallInfo = Context->InSyscallInfo; - - // Hack! Go back to the top of the dispatcher top - // This is only safe inside the JIT rather than anything outside of it - ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); - // Set our state register to point to our guest thread data - ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); - - // XXX: Full context setting - CTX->SetFlagsFromCompactedEFLAGS(Thread, guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EFL]); - - Frame->State.rip = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EIP]; - Frame->State.cs_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_CS]; - Frame->State.ds_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_DS]; - Frame->State.es_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ES]; - Frame->State.fs_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_FS]; - Frame->State.gs_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_GS]; - Frame->State.ss_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_SS]; - - Frame->State.cs_cached = Frame->State.gdt[Frame->State.cs_idx >> 3].base; - Frame->State.ds_cached = Frame->State.gdt[Frame->State.ds_idx >> 3].base; - Frame->State.es_cached = Frame->State.gdt[Frame->State.es_idx >> 3].base; - Frame->State.fs_cached = Frame->State.gdt[Frame->State.fs_idx >> 3].base; - Frame->State.gs_cached = Frame->State.gdt[Frame->State.gs_idx >> 3].base; - Frame->State.ss_cached = Frame->State.gdt[Frame->State.ss_idx >> 3].base; - -#define COPY_REG(x) \ - Frame->State.gregs[FEXCore::X86State::REG_##x] = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_##x]; - COPY_REG(RDI); - COPY_REG(RSI); - COPY_REG(RBP); - COPY_REG(RBX); - COPY_REG(RDX); - COPY_REG(RAX); - COPY_REG(RCX); - COPY_REG(RSP); -#undef COPY_REG - auto *xstate = reinterpret_cast(guest_uctx->uc.uc_mcontext.fpregs); - auto *fpstate = &xstate->fpstate; - - // Copy float registers - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { - // 32-bit st register size is only 10 bytes. Not padded to 16byte like x86-64 - memcpy(&Frame->State.mm[i], &fpstate->_st[i], 10); - } - - // Extended XMM state - if (IsAVXEnabled) { - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&Frame->State.xmm.avx.data[i][0], &fpstate->_xmm[i], sizeof(__uint128_t)); - } - for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&Frame->State.xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], sizeof(__uint128_t)); - } - } else { - memcpy(Frame->State.xmm.sse.data, fpstate->_xmm, sizeof(Frame->State.xmm.sse.data)); - } - - // FCW store default - Frame->State.FCW = fpstate->fcw; - Frame->State.AbridgedFTW = FEXCore::FPState::ConvertToAbridgedFTW(fpstate->ftw); - - // Deconstruct FSW - Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (fpstate->fsw >> 8) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (fpstate->fsw >> 9) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (fpstate->fsw >> 10) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (fpstate->fsw >> 14) & 1; - Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (fpstate->fsw >> 11) & 0b111; - } - } - - uint64_t SignalDelegator::SetupFrame_x64( - FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame *Frame, - int Signal, siginfo_t *HostSigInfo, void *ucontext, - GuestSigAction *GuestAction, stack_t *GuestStack, - uint64_t NewGuestSP, const uint32_t eflags) { - - // Back up past the redzone, which is 128bytes - // 32-bit doesn't have a redzone - NewGuestSP -= 128; - - const bool IsAVXEnabled = Config.SupportsAVX; - - // On 64-bit the kernel sets up the siginfo_t and ucontext_t regardless of SA_SIGINFO set. - // This allows the application to /always/ get the siginfo and ucontext even if it didn't set this flag. - // - // Signal frame layout on stack needs to be as follows - // void* ReturnPointer - // ucontext_t - // siginfo_t - // FP state - // Host stack location - NewGuestSP -= sizeof(uint64_t); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(uint64_t)); - - uint64_t HostStackLocation = NewGuestSP; - - if (IsAVXEnabled) { - NewGuestSP -= sizeof(FEXCore::x86_64::xstate); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86_64::xstate)); + if (Is64BitMode) { + RestoreFrame_x64(Thread, Context, Frame, ucontext); } else { - NewGuestSP -= sizeof(FEXCore::x86_64::_libc_fpstate); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86_64::_libc_fpstate)); + if (Type == RestoreType::TYPE_NONREALTIME) { + RestoreFrame_ia32(Thread, Context, Frame, ucontext); + } else { + RestoreRTFrame_ia32(Thread, Context, Frame, ucontext); + } } + } +} - uint64_t FPStateLocation = NewGuestSP; +void SignalDelegator::RestoreFrame_x64(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context, + FEXCore::Core::CpuStateFrame* Frame, void* ucontext) { + const bool IsAVXEnabled = Config.SupportsAVX; - NewGuestSP -= sizeof(siginfo_t); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(siginfo_t)); - uint64_t SigInfoLocation = NewGuestSP; + auto* guest_uctx = reinterpret_cast(Context->UContextLocation); + [[maybe_unused]] auto* guest_siginfo = reinterpret_cast(Context->SigInfoLocation); - NewGuestSP -= sizeof(FEXCore::x86_64::ucontext_t); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86_64::ucontext_t)); - uint64_t UContextLocation = NewGuestSP; + // If the guest modified the RIP then we need to take special precautions here + if (Context->OriginalRIP != guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP] || Context->FaultToTopAndGeneratedException) { - ContextBackup->FPStateLocation = FPStateLocation; - ContextBackup->UContextLocation = UContextLocation; - ContextBackup->SigInfoLocation = SigInfoLocation; + // Restore previous `InSyscallInfo` structure. + Frame->InSyscallInfo = Context->InSyscallInfo; - FEXCore::x86_64::ucontext_t *guest_uctx = reinterpret_cast(UContextLocation); - siginfo_t *guest_siginfo = reinterpret_cast(SigInfoLocation); - // Store where the host context lives in the guest stack. - *(uint64_t*)HostStackLocation = (uint64_t)ContextBackup; + // Hack! Go back to the top of the dispatcher top + // This is only safe inside the JIT rather than anything outside of it + ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); + // Set our state register to point to our guest thread data + ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); - // We have extended float information - guest_uctx->uc_flags = FEXCore::x86_64::UC_FP_XSTATE | - FEXCore::x86_64::UC_SIGCONTEXT_SS | - FEXCore::x86_64::UC_STRICT_RESTORE_SS; + Frame->State.rip = guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP]; + // XXX: Full context setting + CTX->SetFlagsFromCompactedEFLAGS(Thread, guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_EFL]); - // Pointer to where the fpreg memory is - guest_uctx->uc_mcontext.fpregs = reinterpret_cast(FPStateLocation); - auto *xstate = reinterpret_cast(FPStateLocation); - SetXStateInfo(xstate, IsAVXEnabled); - - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP] = ContextBackup->OriginalRIP; - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_EFL] = eflags; - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CSGSFS] = 0; - - // aarch64 and x86_64 siginfo_t matches. We can just copy this over - // SI_USER could also potentially have random data in it, needs to be bit perfect - // For guest faults we don't have a real way to reconstruct state to a real guest RIP - *guest_siginfo = *HostSigInfo; - - if (ContextBackup->FaultToTopAndGeneratedException) { - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_TRAPNO] = Frame->SynchronousFaultData.TrapNo; - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_ERR] = Frame->SynchronousFaultData.err_code; - - // Overwrite si_code - guest_siginfo->si_code = Thread->CurrentFrame->SynchronousFaultData.si_code; - Signal = Frame->SynchronousFaultData.Signal; - } - else { - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_TRAPNO] = ConvertSignalToTrapNo(Signal, HostSigInfo); - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_ERR] = ConvertSignalToError(ucontext, Signal, HostSigInfo); - } - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_OLDMASK] = 0; - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CR2] = 0; - -#define COPY_REG(x) \ - guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_##x] = Frame->State.gregs[FEXCore::X86State::REG_##x]; +#define COPY_REG(x) Frame->State.gregs[FEXCore::X86State::REG_##x] = guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_##x]; COPY_REG(R8); COPY_REG(R9); COPY_REG(R10); @@ -750,273 +432,150 @@ namespace FEX::HLE { COPY_REG(RCX); COPY_REG(RSP); #undef COPY_REG - + auto* xstate = reinterpret_cast(guest_uctx->uc_mcontext.fpregs); auto* fpstate = &xstate->fpstate; // Copy float registers - memcpy(fpstate->_st, Frame->State.mm, sizeof(Frame->State.mm)); + memcpy(Frame->State.mm, fpstate->_st, sizeof(Frame->State.mm)); if (IsAVXEnabled) { for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&fpstate->_xmm[i], &Frame->State.xmm.avx.data[i][0], sizeof(__uint128_t)); + memcpy(&Frame->State.xmm.avx.data[i][0], &fpstate->_xmm[i], sizeof(__uint128_t)); } for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&xstate->ymmh.ymmh_space[i], &Frame->State.xmm.avx.data[i][2], sizeof(__uint128_t)); + memcpy(&Frame->State.xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], sizeof(__uint128_t)); } } else { - memcpy(fpstate->_xmm, Frame->State.xmm.sse.data, sizeof(Frame->State.xmm.sse.data)); + memcpy(Frame->State.xmm.sse.data, fpstate->_xmm, sizeof(Frame->State.xmm.sse.data)); } // FCW store default - fpstate->fcw = Frame->State.FCW; - fpstate->ftw = Frame->State.AbridgedFTW; + Frame->State.FCW = fpstate->fcw; + Frame->State.AbridgedFTW = fpstate->ftw; - // Reconstruct FSW - fpstate->fsw = - (Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); - - // Copy over signal stack information - guest_uctx->uc_stack.ss_flags = GuestStack->ss_flags; - guest_uctx->uc_stack.ss_sp = GuestStack->ss_sp; - guest_uctx->uc_stack.ss_size = GuestStack->ss_size; - - // Apparently RAX is always set to zero in case of badly misbehaving C applications and variadics. - Frame->State.gregs[FEXCore::X86State::REG_RAX] = 0; - Frame->State.gregs[FEXCore::X86State::REG_RDI] = Signal; - Frame->State.gregs[FEXCore::X86State::REG_RSI] = SigInfoLocation; - Frame->State.gregs[FEXCore::X86State::REG_RDX] = UContextLocation; - - // Set up the new SP for stack handling - // The host is required to provide us a restorer. - // If the guest didn't provide a restorer then the application should fail with a SIGSEGV. - // TODO: Emulate SIGSEGV when the guest doesn't provide a restorer. - NewGuestSP -= 8; - if (GuestAction->restorer) { - *(uint64_t*)NewGuestSP = (uint64_t)GuestAction->restorer; - } - else { - // XXX: Emulate SIGSEGV here - // *(uint64_t*)NewGuestSP = SignalReturn; - } - - return NewGuestSP; + // Deconstruct FSW + Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (fpstate->fsw >> 8) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (fpstate->fsw >> 9) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (fpstate->fsw >> 10) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (fpstate->fsw >> 14) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (fpstate->fsw >> 11) & 0b111; } +} - uint64_t SignalDelegator::SetupFrame_ia32( - ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame *Frame, - int Signal, siginfo_t *HostSigInfo, void *ucontext, - GuestSigAction *GuestAction, stack_t *GuestStack, - uint64_t NewGuestSP, const uint32_t eflags) { +void SignalDelegator::RestoreFrame_ia32(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context, + FEXCore::Core::CpuStateFrame* Frame, void* ucontext) { + const bool IsAVXEnabled = Config.SupportsAVX; - const bool IsAVXEnabled = Config.SupportsAVX; - const uint64_t SignalReturn = reinterpret_cast(VDSOPointers.VDSO_kernel_sigreturn); + SigFrame_i32* guest_uctx = reinterpret_cast(Context->UContextLocation); + // If the guest modified the RIP then we need to take special precautions here + if (Context->OriginalRIP != guest_uctx->sc.ip || Context->FaultToTopAndGeneratedException) { + // Restore previous `InSyscallInfo` structure. + Frame->InSyscallInfo = Context->InSyscallInfo; - NewGuestSP -= sizeof(uint64_t); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(uint64_t)); + // Hack! Go back to the top of the dispatcher top + // This is only safe inside the JIT rather than anything outside of it + ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); + // Set our state register to point to our guest thread data + ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); - uint64_t HostStackLocation = NewGuestSP; + // XXX: Full context setting + CTX->SetFlagsFromCompactedEFLAGS(Thread, guest_uctx->sc.flags); - if (IsAVXEnabled) { - NewGuestSP -= sizeof(FEXCore::x86::xstate); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::xstate)); - } else { - NewGuestSP -= sizeof(FEXCore::x86::_libc_fpstate); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::_libc_fpstate)); - } + Frame->State.rip = guest_uctx->sc.ip; + Frame->State.cs_idx = guest_uctx->sc.cs; + Frame->State.ds_idx = guest_uctx->sc.ds; + Frame->State.es_idx = guest_uctx->sc.es; + Frame->State.fs_idx = guest_uctx->sc.fs; + Frame->State.gs_idx = guest_uctx->sc.gs; + Frame->State.ss_idx = guest_uctx->sc.ss; - uint64_t FPStateLocation = NewGuestSP; + Frame->State.cs_cached = Frame->State.gdt[Frame->State.cs_idx >> 3].base; + Frame->State.ds_cached = Frame->State.gdt[Frame->State.ds_idx >> 3].base; + Frame->State.es_cached = Frame->State.gdt[Frame->State.es_idx >> 3].base; + Frame->State.fs_cached = Frame->State.gdt[Frame->State.fs_idx >> 3].base; + Frame->State.gs_cached = Frame->State.gdt[Frame->State.gs_idx >> 3].base; + Frame->State.ss_cached = Frame->State.gdt[Frame->State.ss_idx >> 3].base; - NewGuestSP -= sizeof(SigFrame_i32); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(SigFrame_i32)); - uint64_t SigFrameLocation = NewGuestSP; - - ContextBackup->FPStateLocation = FPStateLocation; - ContextBackup->UContextLocation = SigFrameLocation; - ContextBackup->SigInfoLocation = 0; - - SigFrame_i32 *guest_uctx = reinterpret_cast(SigFrameLocation); - // Store where the host context lives in the guest stack. - *(uint64_t*)HostStackLocation = (uint64_t)ContextBackup; - - // Pointer to where the fpreg memory is - guest_uctx->sc.fpstate = static_cast(FPStateLocation); - auto *xstate = reinterpret_cast(FPStateLocation); - SetXStateInfo(xstate, IsAVXEnabled); - - guest_uctx->sc.cs = Frame->State.cs_idx; - guest_uctx->sc.ds = Frame->State.ds_idx; - guest_uctx->sc.es = Frame->State.es_idx; - guest_uctx->sc.fs = Frame->State.fs_idx; - guest_uctx->sc.gs = Frame->State.gs_idx; - guest_uctx->sc.ss = Frame->State.ss_idx; - - if (ContextBackup->FaultToTopAndGeneratedException) { - guest_uctx->sc.trapno = Frame->SynchronousFaultData.TrapNo; - guest_uctx->sc.err = Frame->SynchronousFaultData.err_code; - Signal = Frame->SynchronousFaultData.Signal; - } - else { - guest_uctx->sc.trapno = ConvertSignalToTrapNo(Signal, HostSigInfo); - guest_uctx->sc.err = ConvertSignalToError(ucontext, Signal, HostSigInfo); - } - - guest_uctx->sc.ip = ContextBackup->OriginalRIP; - guest_uctx->sc.flags = eflags; - guest_uctx->sc.sp_at_signal = 0; - -#define COPY_REG(x, y) \ - guest_uctx->sc.x = Frame->State.gregs[FEXCore::X86State::REG_##y]; - COPY_REG(di, RDI); - COPY_REG(si, RSI); - COPY_REG(bp, RBP); - COPY_REG(bx, RBX); - COPY_REG(dx, RDX); - COPY_REG(ax, RAX); - COPY_REG(cx, RCX); - COPY_REG(sp, RSP); +#define COPY_REG(x, y) Frame->State.gregs[FEXCore::X86State::REG_##x] = guest_uctx->sc.y; + COPY_REG(RDI, di); + COPY_REG(RSI, si); + COPY_REG(RBP, bp); + COPY_REG(RBX, bx); + COPY_REG(RDX, dx); + COPY_REG(RAX, ax); + COPY_REG(RCX, cx); + COPY_REG(RSP, sp); #undef COPY_REG - - auto *fpstate = &xstate->fpstate; + auto* xstate = reinterpret_cast(guest_uctx->sc.fpstate); + auto* fpstate = &xstate->fpstate; // Copy float registers for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { // 32-bit st register size is only 10 bytes. Not padded to 16byte like x86-64 - memcpy(&fpstate->_st[i], &Frame->State.mm[i], 10); + memcpy(&Frame->State.mm[i], &fpstate->_st[i], 10); } // Extended XMM state - fpstate->status = FEXCore::x86::fpstate_magic::MAGIC_XFPSTATE; if (IsAVXEnabled) { - for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { - memcpy(&fpstate->_xmm[i], &Frame->State.xmm.avx.data[i][0], sizeof(__uint128_t)); + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + memcpy(&Frame->State.xmm.avx.data[i][0], &fpstate->_xmm[i], sizeof(__uint128_t)); } - for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { - memcpy(&xstate->ymmh.ymmh_space[i], &Frame->State.xmm.avx.data[i][2], sizeof(__uint128_t)); + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + memcpy(&Frame->State.xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], sizeof(__uint128_t)); } } else { - memcpy(fpstate->_xmm, Frame->State.xmm.sse.data, sizeof(Frame->State.xmm.sse.data)); + memcpy(Frame->State.xmm.sse.data, fpstate->_xmm, sizeof(Frame->State.xmm.sse.data)); } // FCW store default - fpstate->fcw = Frame->State.FCW; - // Reconstruct FSW - fpstate->fsw = - (Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); - fpstate->ftw = FEXCore::FPState::ConvertFromAbridgedFTW(fpstate->fsw, Frame->State.mm, Frame->State.AbridgedFTW); + Frame->State.FCW = fpstate->fcw; + Frame->State.AbridgedFTW = FEXCore::FPState::ConvertToAbridgedFTW(fpstate->ftw); - // Curiously non-rt signals don't support altstack. So that state doesn't exist here. - - // Copy over the signal information. - guest_uctx->Signal = Signal; - - // Retcode needs to be bit-exact for debuggers - constexpr static uint8_t retcode[] = { - 0x58, // pop eax - 0xb8, // mov - 0x77, 0x00, 0x00, 0x00, // 32-bit sigreturn - 0xcd, 0x80, // int 0x80 - }; - - memcpy(guest_uctx->retcode, &retcode, sizeof(retcode)); - - // 32-bit Guest can provide its own restorer or we need to provide our own. - // On a real host this restorer will live in VDSO. - constexpr uint32_t SA_RESTORER = 0x04000000; - const bool HasRestorer = (GuestAction->sa_flags & SA_RESTORER) == SA_RESTORER; - if (HasRestorer) { - guest_uctx->pretcode = (uint32_t)(uint64_t)GuestAction->restorer; - } - else { - guest_uctx->pretcode = SignalReturn; - LOGMAN_THROW_AA_FMT(SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB"); - } - - // Support regparm=3 - Frame->State.gregs[FEXCore::X86State::REG_RAX] = Signal; - Frame->State.gregs[FEXCore::X86State::REG_RDX] = 0; - Frame->State.gregs[FEXCore::X86State::REG_RCX] = 0; - - return NewGuestSP; + // Deconstruct FSW + Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (fpstate->fsw >> 8) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (fpstate->fsw >> 9) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (fpstate->fsw >> 10) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (fpstate->fsw >> 14) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (fpstate->fsw >> 11) & 0b111; } +} - uint64_t SignalDelegator::SetupRTFrame_ia32( - ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame *Frame, - int Signal, siginfo_t *HostSigInfo, void *ucontext, - GuestSigAction *GuestAction, stack_t *GuestStack, - uint64_t NewGuestSP, const uint32_t eflags) { +void SignalDelegator::RestoreRTFrame_ia32(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context, + FEXCore::Core::CpuStateFrame* Frame, void* ucontext) { + const bool IsAVXEnabled = Config.SupportsAVX; - const bool IsAVXEnabled = Config.SupportsAVX; - const uint64_t SignalReturn = reinterpret_cast(VDSOPointers.VDSO_kernel_rt_sigreturn); + RTSigFrame_i32* guest_uctx = reinterpret_cast(Context->UContextLocation); + // If the guest modified the RIP then we need to take special precautions here + if (Context->OriginalRIP != guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EIP] || Context->FaultToTopAndGeneratedException) { - NewGuestSP -= sizeof(uint64_t); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(uint64_t)); + // Restore previous `InSyscallInfo` structure. + Frame->InSyscallInfo = Context->InSyscallInfo; - uint64_t HostStackLocation = NewGuestSP; + // Hack! Go back to the top of the dispatcher top + // This is only safe inside the JIT rather than anything outside of it + ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); + // Set our state register to point to our guest thread data + ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); - if (IsAVXEnabled) { - NewGuestSP -= sizeof(FEXCore::x86::xstate); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::xstate)); - } else { - NewGuestSP -= sizeof(FEXCore::x86::_libc_fpstate); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::_libc_fpstate)); - } + // XXX: Full context setting + CTX->SetFlagsFromCompactedEFLAGS(Thread, guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EFL]); - uint64_t FPStateLocation = NewGuestSP; + Frame->State.rip = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EIP]; + Frame->State.cs_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_CS]; + Frame->State.ds_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_DS]; + Frame->State.es_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ES]; + Frame->State.fs_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_FS]; + Frame->State.gs_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_GS]; + Frame->State.ss_idx = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_SS]; - NewGuestSP -= sizeof(RTSigFrame_i32); - NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(RTSigFrame_i32)); + Frame->State.cs_cached = Frame->State.gdt[Frame->State.cs_idx >> 3].base; + Frame->State.ds_cached = Frame->State.gdt[Frame->State.ds_idx >> 3].base; + Frame->State.es_cached = Frame->State.gdt[Frame->State.es_idx >> 3].base; + Frame->State.fs_cached = Frame->State.gdt[Frame->State.fs_idx >> 3].base; + Frame->State.gs_cached = Frame->State.gdt[Frame->State.gs_idx >> 3].base; + Frame->State.ss_cached = Frame->State.gdt[Frame->State.ss_idx >> 3].base; - uint64_t SigFrameLocation = NewGuestSP; - RTSigFrame_i32 *guest_uctx = reinterpret_cast(SigFrameLocation); - // Store where the host context lives in the guest stack. - *(uint64_t*)HostStackLocation = (uint64_t)ContextBackup; - - ContextBackup->FPStateLocation = FPStateLocation; - ContextBackup->UContextLocation = SigFrameLocation; - ContextBackup->SigInfoLocation = 0; // Part of frame. - - // We have extended float information - guest_uctx->uc.uc_flags = FEXCore::x86::UC_FP_XSTATE; - guest_uctx->uc.uc_link = 0; - - // Pointer to where the fpreg memory is - guest_uctx->uc.uc_mcontext.fpregs = static_cast(FPStateLocation); - auto *xstate = reinterpret_cast(FPStateLocation); - SetXStateInfo(xstate, IsAVXEnabled); - - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_CS] = Frame->State.cs_idx; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_DS] = Frame->State.ds_idx; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ES] = Frame->State.es_idx; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_FS] = Frame->State.fs_idx; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_GS] = Frame->State.gs_idx; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_SS] = Frame->State.ss_idx; - - if (ContextBackup->FaultToTopAndGeneratedException) { - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_TRAPNO] = Frame->SynchronousFaultData.TrapNo; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ERR] = Frame->SynchronousFaultData.err_code; - Signal = Frame->SynchronousFaultData.Signal; - } - else { - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_TRAPNO] = ConvertSignalToTrapNo(Signal, HostSigInfo); - guest_uctx->info.si_code = HostSigInfo->si_code; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ERR] = ConvertSignalToError(ucontext, Signal, HostSigInfo); - } - - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EIP] = ContextBackup->OriginalRIP; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EFL] = eflags; - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_UESP] = Frame->State.gregs[FEXCore::X86State::REG_RSP]; - guest_uctx->uc.uc_mcontext.cr2 = 0; - -#define COPY_REG(x) \ - guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_##x] = Frame->State.gregs[FEXCore::X86State::REG_##x]; +#define COPY_REG(x) Frame->State.gregs[FEXCore::X86State::REG_##x] = guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_##x]; COPY_REG(RDI); COPY_REG(RSI); COPY_REG(RBP); @@ -1026,714 +585,1078 @@ namespace FEX::HLE { COPY_REG(RCX); COPY_REG(RSP); #undef COPY_REG - - auto *fpstate = &xstate->fpstate; + auto* xstate = reinterpret_cast(guest_uctx->uc.uc_mcontext.fpregs); + auto* fpstate = &xstate->fpstate; // Copy float registers for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { // 32-bit st register size is only 10 bytes. Not padded to 16byte like x86-64 - memcpy(&fpstate->_st[i], &Frame->State.mm[i], 10); + memcpy(&Frame->State.mm[i], &fpstate->_st[i], 10); } // Extended XMM state - fpstate->status = FEXCore::x86::fpstate_magic::MAGIC_XFPSTATE; if (IsAVXEnabled) { - for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { - memcpy(&fpstate->_xmm[i], &Frame->State.xmm.avx.data[i][0], sizeof(__uint128_t)); + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + memcpy(&Frame->State.xmm.avx.data[i][0], &fpstate->_xmm[i], sizeof(__uint128_t)); } - for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { - memcpy(&xstate->ymmh.ymmh_space[i], &Frame->State.xmm.avx.data[i][2], sizeof(__uint128_t)); + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + memcpy(&Frame->State.xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], sizeof(__uint128_t)); } } else { - memcpy(fpstate->_xmm, Frame->State.xmm.sse.data, sizeof(Frame->State.xmm.sse.data)); + memcpy(Frame->State.xmm.sse.data, fpstate->_xmm, sizeof(Frame->State.xmm.sse.data)); } // FCW store default - fpstate->fcw = Frame->State.FCW; - // Reconstruct FSW - fpstate->fsw = - (Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | - (Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); - fpstate->ftw = FEXCore::FPState::ConvertFromAbridgedFTW(fpstate->fsw, Frame->State.mm, Frame->State.AbridgedFTW); + Frame->State.FCW = fpstate->fcw; + Frame->State.AbridgedFTW = FEXCore::FPState::ConvertToAbridgedFTW(fpstate->ftw); - // Copy over signal stack information - guest_uctx->uc.uc_stack.ss_flags = GuestStack->ss_flags; - guest_uctx->uc.uc_stack.ss_sp = static_cast(reinterpret_cast(GuestStack->ss_sp)); - guest_uctx->uc.uc_stack.ss_size = GuestStack->ss_size; + // Deconstruct FSW + Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (fpstate->fsw >> 8) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (fpstate->fsw >> 9) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (fpstate->fsw >> 10) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (fpstate->fsw >> 14) & 1; + Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (fpstate->fsw >> 11) & 0b111; + } +} - // Setup siginfo - if (ContextBackup->FaultToTopAndGeneratedException) { - guest_uctx->info.si_code = Frame->SynchronousFaultData.si_code; - } - else { - guest_uctx->info.si_code = HostSigInfo->si_code; - } +uint64_t SignalDelegator::SetupFrame_x64(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* ContextBackup, + FEXCore::Core::CpuStateFrame* Frame, int Signal, siginfo_t* HostSigInfo, void* ucontext, + GuestSigAction* GuestAction, stack_t* GuestStack, uint64_t NewGuestSP, const uint32_t eflags) { - // These three elements are in every siginfo - guest_uctx->info.si_signo = HostSigInfo->si_signo; - guest_uctx->info.si_errno = HostSigInfo->si_errno; + // Back up past the redzone, which is 128bytes + // 32-bit doesn't have a redzone + NewGuestSP -= 128; - const SigInfoLayout Layout = CalculateSigInfoLayout(Signal, guest_uctx->info.si_code); + const bool IsAVXEnabled = Config.SupportsAVX; - switch (Layout) { - case SigInfoLayout::LAYOUT_KILL: - guest_uctx->info._sifields._kill.pid = HostSigInfo->si_pid; - guest_uctx->info._sifields._kill.uid = HostSigInfo->si_uid; - break; - case SigInfoLayout::LAYOUT_TIMER: - guest_uctx->info._sifields._timer.tid = HostSigInfo->si_timerid; - guest_uctx->info._sifields._timer.overrun = HostSigInfo->si_overrun; - guest_uctx->info._sifields._timer.sigval.sival_int = HostSigInfo->si_int; - break; - case SigInfoLayout::LAYOUT_POLL: - guest_uctx->info._sifields._poll.band= HostSigInfo->si_band; - guest_uctx->info._sifields._poll.fd= HostSigInfo->si_fd; - break; - case SigInfoLayout::LAYOUT_FAULT: - // Macro expansion to get the si_addr - // This is the address trying to be accessed, not the RIP - guest_uctx->info._sifields._sigfault.addr = static_cast(reinterpret_cast(HostSigInfo->si_addr)); - break; - case SigInfoLayout::LAYOUT_FAULT_RIP: - // Macro expansion to get the si_addr - // Can't really give a real result here. Pull from the context for now - guest_uctx->info._sifields._sigfault.addr = ContextBackup->OriginalRIP; - break; - case SigInfoLayout::LAYOUT_CHLD: - guest_uctx->info._sifields._sigchld.pid = HostSigInfo->si_pid; - guest_uctx->info._sifields._sigchld.uid = HostSigInfo->si_uid; - guest_uctx->info._sifields._sigchld.status = HostSigInfo->si_status; - guest_uctx->info._sifields._sigchld.utime = HostSigInfo->si_utime; - guest_uctx->info._sifields._sigchld.stime = HostSigInfo->si_stime; - break; - case SigInfoLayout::LAYOUT_RT: - guest_uctx->info._sifields._rt.pid = HostSigInfo->si_pid; - guest_uctx->info._sifields._rt.uid = HostSigInfo->si_uid; - guest_uctx->info._sifields._rt.sigval.sival_int = HostSigInfo->si_int; - break; - case SigInfoLayout::LAYOUT_SYS: - guest_uctx->info._sifields._sigsys.call_addr = static_cast(reinterpret_cast(HostSigInfo->si_call_addr)); - guest_uctx->info._sifields._sigsys.syscall = HostSigInfo->si_syscall; - // We need to lie about the architecture here. - // Otherwise we would expose incorrect information to the guest. - constexpr uint32_t AUDIT_LE = 0x4000'0000U; - constexpr uint32_t MACHINE_I386 = 3; // This matches the ELF definition. - guest_uctx->info._sifields._sigsys.arch = AUDIT_LE | MACHINE_I386; - break; - } + // On 64-bit the kernel sets up the siginfo_t and ucontext_t regardless of SA_SIGINFO set. + // This allows the application to /always/ get the siginfo and ucontext even if it didn't set this flag. + // + // Signal frame layout on stack needs to be as follows + // void* ReturnPointer + // ucontext_t + // siginfo_t + // FP state + // Host stack location + NewGuestSP -= sizeof(uint64_t); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(uint64_t)); - // Setup the guest stack context. - guest_uctx->Signal = Signal; - guest_uctx->pinfo = (uint32_t)(uint64_t)&guest_uctx->info; - guest_uctx->puc = (uint32_t)(uint64_t)&guest_uctx->uc; + uint64_t HostStackLocation = NewGuestSP; - // Retcode needs to be bit-exact for debuggers - constexpr static uint8_t rt_retcode[] = { - 0xb8, // mov - 0xad, 0x00, 0x00, 0x00, // 32-bit rt_sigreturn - 0xcd, 0x80, // int 0x80 - 0x0, // Pad - }; - - memcpy(guest_uctx->retcode, &rt_retcode, sizeof(rt_retcode)); - - // 32-bit Guest can provide its own restorer or we need to provide our own. - // On a real host this restorer will live in VDSO. - constexpr uint32_t SA_RESTORER = 0x04000000; - const bool HasRestorer = (GuestAction->sa_flags & SA_RESTORER) == SA_RESTORER; - if (HasRestorer) { - guest_uctx->pretcode = (uint32_t)(uint64_t)GuestAction->restorer; - } - else { - guest_uctx->pretcode = SignalReturn; - LOGMAN_THROW_AA_FMT(SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB"); - } - - // Support regparm=3 - Frame->State.gregs[FEXCore::X86State::REG_RAX] = Signal; - Frame->State.gregs[FEXCore::X86State::REG_RDX] = guest_uctx->pinfo; - Frame->State.gregs[FEXCore::X86State::REG_RCX] = guest_uctx->puc; - - return NewGuestSP; + if (IsAVXEnabled) { + NewGuestSP -= sizeof(FEXCore::x86_64::xstate); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86_64::xstate)); + } else { + NewGuestSP -= sizeof(FEXCore::x86_64::_libc_fpstate); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86_64::_libc_fpstate)); } - bool SignalDelegator::HandleDispatcherGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext, GuestSigAction *GuestAction, stack_t *GuestStack) { - auto ContextBackup = StoreThreadState(Thread, Signal, ucontext); + uint64_t FPStateLocation = NewGuestSP; - auto Frame = Thread->CurrentFrame; + NewGuestSP -= sizeof(siginfo_t); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(siginfo_t)); + uint64_t SigInfoLocation = NewGuestSP; + + NewGuestSP -= sizeof(FEXCore::x86_64::ucontext_t); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86_64::ucontext_t)); + uint64_t UContextLocation = NewGuestSP; + + ContextBackup->FPStateLocation = FPStateLocation; + ContextBackup->UContextLocation = UContextLocation; + ContextBackup->SigInfoLocation = SigInfoLocation; + + FEXCore::x86_64::ucontext_t* guest_uctx = reinterpret_cast(UContextLocation); + siginfo_t* guest_siginfo = reinterpret_cast(SigInfoLocation); + // Store where the host context lives in the guest stack. + *(uint64_t*)HostStackLocation = (uint64_t)ContextBackup; + + // We have extended float information + guest_uctx->uc_flags = FEXCore::x86_64::UC_FP_XSTATE | FEXCore::x86_64::UC_SIGCONTEXT_SS | FEXCore::x86_64::UC_STRICT_RESTORE_SS; + + // Pointer to where the fpreg memory is + guest_uctx->uc_mcontext.fpregs = reinterpret_cast(FPStateLocation); + auto* xstate = reinterpret_cast(FPStateLocation); + SetXStateInfo(xstate, IsAVXEnabled); + + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP] = ContextBackup->OriginalRIP; + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_EFL] = eflags; + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CSGSFS] = 0; + + // aarch64 and x86_64 siginfo_t matches. We can just copy this over + // SI_USER could also potentially have random data in it, needs to be bit perfect + // For guest faults we don't have a real way to reconstruct state to a real guest RIP + *guest_siginfo = *HostSigInfo; + + if (ContextBackup->FaultToTopAndGeneratedException) { + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_TRAPNO] = Frame->SynchronousFaultData.TrapNo; + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_ERR] = Frame->SynchronousFaultData.err_code; + + // Overwrite si_code + guest_siginfo->si_code = Thread->CurrentFrame->SynchronousFaultData.si_code; + Signal = Frame->SynchronousFaultData.Signal; + } else { + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_TRAPNO] = ConvertSignalToTrapNo(Signal, HostSigInfo); + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_ERR] = ConvertSignalToError(ucontext, Signal, HostSigInfo); + } + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_OLDMASK] = 0; + guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CR2] = 0; + +#define COPY_REG(x) guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_##x] = Frame->State.gregs[FEXCore::X86State::REG_##x]; + COPY_REG(R8); + COPY_REG(R9); + COPY_REG(R10); + COPY_REG(R11); + COPY_REG(R12); + COPY_REG(R13); + COPY_REG(R14); + COPY_REG(R15); + COPY_REG(RDI); + COPY_REG(RSI); + COPY_REG(RBP); + COPY_REG(RBX); + COPY_REG(RDX); + COPY_REG(RAX); + COPY_REG(RCX); + COPY_REG(RSP); +#undef COPY_REG + + auto* fpstate = &xstate->fpstate; + + // Copy float registers + memcpy(fpstate->_st, Frame->State.mm, sizeof(Frame->State.mm)); + + if (IsAVXEnabled) { + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + memcpy(&fpstate->_xmm[i], &Frame->State.xmm.avx.data[i][0], sizeof(__uint128_t)); + } + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { + memcpy(&xstate->ymmh.ymmh_space[i], &Frame->State.xmm.avx.data[i][2], sizeof(__uint128_t)); + } + } else { + memcpy(fpstate->_xmm, Frame->State.xmm.sse.data, sizeof(Frame->State.xmm.sse.data)); + } + + // FCW store default + fpstate->fcw = Frame->State.FCW; + fpstate->ftw = Frame->State.AbridgedFTW; + + // Reconstruct FSW + fpstate->fsw = (Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | + (Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | (Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | + (Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | (Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); + + // Copy over signal stack information + guest_uctx->uc_stack.ss_flags = GuestStack->ss_flags; + guest_uctx->uc_stack.ss_sp = GuestStack->ss_sp; + guest_uctx->uc_stack.ss_size = GuestStack->ss_size; + + // Apparently RAX is always set to zero in case of badly misbehaving C applications and variadics. + Frame->State.gregs[FEXCore::X86State::REG_RAX] = 0; + Frame->State.gregs[FEXCore::X86State::REG_RDI] = Signal; + Frame->State.gregs[FEXCore::X86State::REG_RSI] = SigInfoLocation; + Frame->State.gregs[FEXCore::X86State::REG_RDX] = UContextLocation; + + // Set up the new SP for stack handling + // The host is required to provide us a restorer. + // If the guest didn't provide a restorer then the application should fail with a SIGSEGV. + // TODO: Emulate SIGSEGV when the guest doesn't provide a restorer. + NewGuestSP -= 8; + if (GuestAction->restorer) { + *(uint64_t*)NewGuestSP = (uint64_t)GuestAction->restorer; + } else { + // XXX: Emulate SIGSEGV here + // *(uint64_t*)NewGuestSP = SignalReturn; + } + + return NewGuestSP; +} + +uint64_t SignalDelegator::SetupFrame_ia32(ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame* Frame, + int Signal, siginfo_t* HostSigInfo, void* ucontext, GuestSigAction* GuestAction, + stack_t* GuestStack, uint64_t NewGuestSP, const uint32_t eflags) { + + const bool IsAVXEnabled = Config.SupportsAVX; + const uint64_t SignalReturn = reinterpret_cast(VDSOPointers.VDSO_kernel_sigreturn); + + NewGuestSP -= sizeof(uint64_t); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(uint64_t)); + + uint64_t HostStackLocation = NewGuestSP; + + if (IsAVXEnabled) { + NewGuestSP -= sizeof(FEXCore::x86::xstate); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::xstate)); + } else { + NewGuestSP -= sizeof(FEXCore::x86::_libc_fpstate); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::_libc_fpstate)); + } + + uint64_t FPStateLocation = NewGuestSP; + + NewGuestSP -= sizeof(SigFrame_i32); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(SigFrame_i32)); + uint64_t SigFrameLocation = NewGuestSP; + + ContextBackup->FPStateLocation = FPStateLocation; + ContextBackup->UContextLocation = SigFrameLocation; + ContextBackup->SigInfoLocation = 0; + + SigFrame_i32* guest_uctx = reinterpret_cast(SigFrameLocation); + // Store where the host context lives in the guest stack. + *(uint64_t*)HostStackLocation = (uint64_t)ContextBackup; + + // Pointer to where the fpreg memory is + guest_uctx->sc.fpstate = static_cast(FPStateLocation); + auto* xstate = reinterpret_cast(FPStateLocation); + SetXStateInfo(xstate, IsAVXEnabled); + + guest_uctx->sc.cs = Frame->State.cs_idx; + guest_uctx->sc.ds = Frame->State.ds_idx; + guest_uctx->sc.es = Frame->State.es_idx; + guest_uctx->sc.fs = Frame->State.fs_idx; + guest_uctx->sc.gs = Frame->State.gs_idx; + guest_uctx->sc.ss = Frame->State.ss_idx; + + if (ContextBackup->FaultToTopAndGeneratedException) { + guest_uctx->sc.trapno = Frame->SynchronousFaultData.TrapNo; + guest_uctx->sc.err = Frame->SynchronousFaultData.err_code; + Signal = Frame->SynchronousFaultData.Signal; + } else { + guest_uctx->sc.trapno = ConvertSignalToTrapNo(Signal, HostSigInfo); + guest_uctx->sc.err = ConvertSignalToError(ucontext, Signal, HostSigInfo); + } + + guest_uctx->sc.ip = ContextBackup->OriginalRIP; + guest_uctx->sc.flags = eflags; + guest_uctx->sc.sp_at_signal = 0; + +#define COPY_REG(x, y) guest_uctx->sc.x = Frame->State.gregs[FEXCore::X86State::REG_##y]; + COPY_REG(di, RDI); + COPY_REG(si, RSI); + COPY_REG(bp, RBP); + COPY_REG(bx, RBX); + COPY_REG(dx, RDX); + COPY_REG(ax, RAX); + COPY_REG(cx, RCX); + COPY_REG(sp, RSP); +#undef COPY_REG + + auto* fpstate = &xstate->fpstate; + + // Copy float registers + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { + // 32-bit st register size is only 10 bytes. Not padded to 16byte like x86-64 + memcpy(&fpstate->_st[i], &Frame->State.mm[i], 10); + } + + // Extended XMM state + fpstate->status = FEXCore::x86::fpstate_magic::MAGIC_XFPSTATE; + if (IsAVXEnabled) { + for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { + memcpy(&fpstate->_xmm[i], &Frame->State.xmm.avx.data[i][0], sizeof(__uint128_t)); + } + for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { + memcpy(&xstate->ymmh.ymmh_space[i], &Frame->State.xmm.avx.data[i][2], sizeof(__uint128_t)); + } + } else { + memcpy(fpstate->_xmm, Frame->State.xmm.sse.data, sizeof(Frame->State.xmm.sse.data)); + } + + // FCW store default + fpstate->fcw = Frame->State.FCW; + // Reconstruct FSW + fpstate->fsw = (Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | + (Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | (Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | + (Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | (Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); + fpstate->ftw = FEXCore::FPState::ConvertFromAbridgedFTW(fpstate->fsw, Frame->State.mm, Frame->State.AbridgedFTW); + + // Curiously non-rt signals don't support altstack. So that state doesn't exist here. + + // Copy over the signal information. + guest_uctx->Signal = Signal; + + // Retcode needs to be bit-exact for debuggers + constexpr static uint8_t retcode[] = { + 0x58, // pop eax + 0xb8, // mov + 0x77, 0x00, 0x00, 0x00, // 32-bit sigreturn + 0xcd, 0x80, // int 0x80 + }; + + memcpy(guest_uctx->retcode, &retcode, sizeof(retcode)); + + // 32-bit Guest can provide its own restorer or we need to provide our own. + // On a real host this restorer will live in VDSO. + constexpr uint32_t SA_RESTORER = 0x04000000; + const bool HasRestorer = (GuestAction->sa_flags & SA_RESTORER) == SA_RESTORER; + if (HasRestorer) { + guest_uctx->pretcode = (uint32_t)(uint64_t)GuestAction->restorer; + } else { + guest_uctx->pretcode = SignalReturn; + LOGMAN_THROW_AA_FMT(SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB"); + } + + // Support regparm=3 + Frame->State.gregs[FEXCore::X86State::REG_RAX] = Signal; + Frame->State.gregs[FEXCore::X86State::REG_RDX] = 0; + Frame->State.gregs[FEXCore::X86State::REG_RCX] = 0; + + return NewGuestSP; +} + +uint64_t SignalDelegator::SetupRTFrame_ia32(ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame* Frame, + int Signal, siginfo_t* HostSigInfo, void* ucontext, GuestSigAction* GuestAction, + stack_t* GuestStack, uint64_t NewGuestSP, const uint32_t eflags) { + + const bool IsAVXEnabled = Config.SupportsAVX; + const uint64_t SignalReturn = reinterpret_cast(VDSOPointers.VDSO_kernel_rt_sigreturn); + + NewGuestSP -= sizeof(uint64_t); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(uint64_t)); + + uint64_t HostStackLocation = NewGuestSP; + + if (IsAVXEnabled) { + NewGuestSP -= sizeof(FEXCore::x86::xstate); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::xstate)); + } else { + NewGuestSP -= sizeof(FEXCore::x86::_libc_fpstate); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(FEXCore::x86::_libc_fpstate)); + } + + uint64_t FPStateLocation = NewGuestSP; + + NewGuestSP -= sizeof(RTSigFrame_i32); + NewGuestSP = FEXCore::AlignDown(NewGuestSP, alignof(RTSigFrame_i32)); + + uint64_t SigFrameLocation = NewGuestSP; + RTSigFrame_i32* guest_uctx = reinterpret_cast(SigFrameLocation); + // Store where the host context lives in the guest stack. + *(uint64_t*)HostStackLocation = (uint64_t)ContextBackup; + + ContextBackup->FPStateLocation = FPStateLocation; + ContextBackup->UContextLocation = SigFrameLocation; + ContextBackup->SigInfoLocation = 0; // Part of frame. + + // We have extended float information + guest_uctx->uc.uc_flags = FEXCore::x86::UC_FP_XSTATE; + guest_uctx->uc.uc_link = 0; + + // Pointer to where the fpreg memory is + guest_uctx->uc.uc_mcontext.fpregs = static_cast(FPStateLocation); + auto* xstate = reinterpret_cast(FPStateLocation); + SetXStateInfo(xstate, IsAVXEnabled); + + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_CS] = Frame->State.cs_idx; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_DS] = Frame->State.ds_idx; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ES] = Frame->State.es_idx; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_FS] = Frame->State.fs_idx; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_GS] = Frame->State.gs_idx; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_SS] = Frame->State.ss_idx; + + if (ContextBackup->FaultToTopAndGeneratedException) { + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_TRAPNO] = Frame->SynchronousFaultData.TrapNo; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ERR] = Frame->SynchronousFaultData.err_code; + Signal = Frame->SynchronousFaultData.Signal; + } else { + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_TRAPNO] = ConvertSignalToTrapNo(Signal, HostSigInfo); + guest_uctx->info.si_code = HostSigInfo->si_code; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_ERR] = ConvertSignalToError(ucontext, Signal, HostSigInfo); + } + + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EIP] = ContextBackup->OriginalRIP; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_EFL] = eflags; + guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_UESP] = Frame->State.gregs[FEXCore::X86State::REG_RSP]; + guest_uctx->uc.uc_mcontext.cr2 = 0; + +#define COPY_REG(x) guest_uctx->uc.uc_mcontext.gregs[FEXCore::x86::FEX_REG_##x] = Frame->State.gregs[FEXCore::X86State::REG_##x]; + COPY_REG(RDI); + COPY_REG(RSI); + COPY_REG(RBP); + COPY_REG(RBX); + COPY_REG(RDX); + COPY_REG(RAX); + COPY_REG(RCX); + COPY_REG(RSP); +#undef COPY_REG + + auto* fpstate = &xstate->fpstate; + + // Copy float registers + for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { + // 32-bit st register size is only 10 bytes. Not padded to 16byte like x86-64 + memcpy(&fpstate->_st[i], &Frame->State.mm[i], 10); + } + + // Extended XMM state + fpstate->status = FEXCore::x86::fpstate_magic::MAGIC_XFPSTATE; + if (IsAVXEnabled) { + for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { + memcpy(&fpstate->_xmm[i], &Frame->State.xmm.avx.data[i][0], sizeof(__uint128_t)); + } + for (size_t i = 0; i < std::size(Frame->State.xmm.avx.data); i++) { + memcpy(&xstate->ymmh.ymmh_space[i], &Frame->State.xmm.avx.data[i][2], sizeof(__uint128_t)); + } + } else { + memcpy(fpstate->_xmm, Frame->State.xmm.sse.data, sizeof(Frame->State.xmm.sse.data)); + } + + // FCW store default + fpstate->fcw = Frame->State.FCW; + // Reconstruct FSW + fpstate->fsw = (Frame->State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | + (Frame->State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | (Frame->State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | + (Frame->State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | (Frame->State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); + fpstate->ftw = FEXCore::FPState::ConvertFromAbridgedFTW(fpstate->fsw, Frame->State.mm, Frame->State.AbridgedFTW); + + // Copy over signal stack information + guest_uctx->uc.uc_stack.ss_flags = GuestStack->ss_flags; + guest_uctx->uc.uc_stack.ss_sp = static_cast(reinterpret_cast(GuestStack->ss_sp)); + guest_uctx->uc.uc_stack.ss_size = GuestStack->ss_size; + + // Setup siginfo + if (ContextBackup->FaultToTopAndGeneratedException) { + guest_uctx->info.si_code = Frame->SynchronousFaultData.si_code; + } else { + guest_uctx->info.si_code = HostSigInfo->si_code; + } + + // These three elements are in every siginfo + guest_uctx->info.si_signo = HostSigInfo->si_signo; + guest_uctx->info.si_errno = HostSigInfo->si_errno; + + const SigInfoLayout Layout = CalculateSigInfoLayout(Signal, guest_uctx->info.si_code); + + switch (Layout) { + case SigInfoLayout::LAYOUT_KILL: + guest_uctx->info._sifields._kill.pid = HostSigInfo->si_pid; + guest_uctx->info._sifields._kill.uid = HostSigInfo->si_uid; + break; + case SigInfoLayout::LAYOUT_TIMER: + guest_uctx->info._sifields._timer.tid = HostSigInfo->si_timerid; + guest_uctx->info._sifields._timer.overrun = HostSigInfo->si_overrun; + guest_uctx->info._sifields._timer.sigval.sival_int = HostSigInfo->si_int; + break; + case SigInfoLayout::LAYOUT_POLL: + guest_uctx->info._sifields._poll.band = HostSigInfo->si_band; + guest_uctx->info._sifields._poll.fd = HostSigInfo->si_fd; + break; + case SigInfoLayout::LAYOUT_FAULT: + // Macro expansion to get the si_addr + // This is the address trying to be accessed, not the RIP + guest_uctx->info._sifields._sigfault.addr = static_cast(reinterpret_cast(HostSigInfo->si_addr)); + break; + case SigInfoLayout::LAYOUT_FAULT_RIP: + // Macro expansion to get the si_addr + // Can't really give a real result here. Pull from the context for now + guest_uctx->info._sifields._sigfault.addr = ContextBackup->OriginalRIP; + break; + case SigInfoLayout::LAYOUT_CHLD: + guest_uctx->info._sifields._sigchld.pid = HostSigInfo->si_pid; + guest_uctx->info._sifields._sigchld.uid = HostSigInfo->si_uid; + guest_uctx->info._sifields._sigchld.status = HostSigInfo->si_status; + guest_uctx->info._sifields._sigchld.utime = HostSigInfo->si_utime; + guest_uctx->info._sifields._sigchld.stime = HostSigInfo->si_stime; + break; + case SigInfoLayout::LAYOUT_RT: + guest_uctx->info._sifields._rt.pid = HostSigInfo->si_pid; + guest_uctx->info._sifields._rt.uid = HostSigInfo->si_uid; + guest_uctx->info._sifields._rt.sigval.sival_int = HostSigInfo->si_int; + break; + case SigInfoLayout::LAYOUT_SYS: + guest_uctx->info._sifields._sigsys.call_addr = static_cast(reinterpret_cast(HostSigInfo->si_call_addr)); + guest_uctx->info._sifields._sigsys.syscall = HostSigInfo->si_syscall; + // We need to lie about the architecture here. + // Otherwise we would expose incorrect information to the guest. + constexpr uint32_t AUDIT_LE = 0x4000'0000U; + constexpr uint32_t MACHINE_I386 = 3; // This matches the ELF definition. + guest_uctx->info._sifields._sigsys.arch = AUDIT_LE | MACHINE_I386; + break; + } + + // Setup the guest stack context. + guest_uctx->Signal = Signal; + guest_uctx->pinfo = (uint32_t)(uint64_t)&guest_uctx->info; + guest_uctx->puc = (uint32_t)(uint64_t)&guest_uctx->uc; + + // Retcode needs to be bit-exact for debuggers + constexpr static uint8_t rt_retcode[] = { + 0xb8, // mov + 0xad, 0x00, 0x00, 0x00, // 32-bit rt_sigreturn + 0xcd, 0x80, // int 0x80 + 0x0, // Pad + }; + + memcpy(guest_uctx->retcode, &rt_retcode, sizeof(rt_retcode)); + + // 32-bit Guest can provide its own restorer or we need to provide our own. + // On a real host this restorer will live in VDSO. + constexpr uint32_t SA_RESTORER = 0x04000000; + const bool HasRestorer = (GuestAction->sa_flags & SA_RESTORER) == SA_RESTORER; + if (HasRestorer) { + guest_uctx->pretcode = (uint32_t)(uint64_t)GuestAction->restorer; + } else { + guest_uctx->pretcode = SignalReturn; + LOGMAN_THROW_AA_FMT(SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB"); + } + + // Support regparm=3 + Frame->State.gregs[FEXCore::X86State::REG_RAX] = Signal; + Frame->State.gregs[FEXCore::X86State::REG_RDX] = guest_uctx->pinfo; + Frame->State.gregs[FEXCore::X86State::REG_RCX] = guest_uctx->puc; + + return NewGuestSP; +} + +bool SignalDelegator::HandleDispatcherGuestSignal(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext, + GuestSigAction* GuestAction, stack_t* GuestStack) { + auto ContextBackup = StoreThreadState(Thread, Signal, ucontext); + + auto Frame = Thread->CurrentFrame; + + // Ref count our faults + // We use this to track if it is safe to clear cache + ++Thread->CurrentFrame->SignalHandlerRefCounter; + + uint64_t OldPC = ArchHelpers::Context::GetPc(ucontext); + const bool WasInJIT = CTX->IsAddressInCodeBuffer(Thread, OldPC); + + // Spill the SRA regardless of signal handler type + // We are going to be returning to the top of the dispatcher which will fill again + // Otherwise we might load garbage + if (WasInJIT) { + uint32_t IgnoreMask {}; +#ifdef _M_ARM_64 + if (Frame->InSyscallInfo != 0) { + // We are in a syscall, this means we are in a weird register state + // We need to spill SRA but only some of it, since some values have already been spilled + // Lower 16 bits tells us which registers are already spilled to the context + // So we ignore spilling those ones + IgnoreMask = Frame->InSyscallInfo & 0xFFFF; + } else { + // We must spill everything + IgnoreMask = 0; + } +#endif + + // We are in jit, SRA must be spilled + SpillSRA(Thread, ucontext, IgnoreMask); + + ContextBackup->Flags |= ArchHelpers::Context::ContextFlags::CONTEXT_FLAG_INJIT; + + // We are leaving the syscall information behind. Make sure to store the previous state. + ContextBackup->InSyscallInfo = Thread->CurrentFrame->InSyscallInfo; + Thread->CurrentFrame->InSyscallInfo = 0; + } else { + if (!IsAddressInDispatcher(OldPC)) { + // This is likely to cause issues but in some cases it isn't fatal + // This can also happen if we have put a signal on hold, then we just reenabled the signal + // So we are in the syscall handler + // Only throw a log message in this case + if constexpr (false) { + // XXX: Messages in the signal handler can cause us to crash + LogMan::Msg::EFmt("Signals in dispatcher have unsynchronized context"); + } + } + } + + uint64_t OldGuestSP = Frame->State.gregs[FEXCore::X86State::REG_RSP]; + uint64_t NewGuestSP = OldGuestSP; + + // altstack is only used if the signal handler was setup with SA_ONSTACK + if (GuestAction->sa_flags & SA_ONSTACK) { + // Additionally the altstack is only used if the enabled (SS_DISABLE flag is not set) + if (!(GuestStack->ss_flags & SS_DISABLE)) { + // If our guest is already inside of the alternative stack + // Then that means we are hitting recursive signals and we need to walk back the stack correctly + uint64_t AltStackBase = reinterpret_cast(GuestStack->ss_sp); + uint64_t AltStackEnd = AltStackBase + GuestStack->ss_size; + if (OldGuestSP >= AltStackBase && OldGuestSP <= AltStackEnd) { + // We are already in the alt stack, the rest of the code will handle adjusting this + } else { + NewGuestSP = AltStackEnd; + } + } + } + + // siginfo_t + siginfo_t* HostSigInfo = reinterpret_cast(info); + + // Backup where we think the RIP currently is + ContextBackup->OriginalRIP = CTX->RestoreRIPFromHostPC(Thread, ArchHelpers::Context::GetPc(ucontext)); + // Calculate eflags upfront. + uint32_t eflags = CTX->ReconstructCompactedEFLAGS(Thread, WasInJIT, ArchHelpers::Context::GetArmGPRs(ucontext), + ArchHelpers::Context::GetArmPState(ucontext)); + + if (Is64BitMode) { + NewGuestSP = SetupFrame_x64(Thread, ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags); + } else { + const bool SigInfoFrame = (GuestAction->sa_flags & SA_SIGINFO) == SA_SIGINFO; + if (SigInfoFrame) { + NewGuestSP = SetupRTFrame_ia32(ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags); + } else { + NewGuestSP = SetupFrame_ia32(ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags); + } + } + + Frame->State.rip = reinterpret_cast(GuestAction->sigaction_handler.sigaction); + Frame->State.gregs[FEXCore::X86State::REG_RSP] = NewGuestSP; + + // The guest starts its signal frame with a zero initialized FPU + // Set that up now. Little bit costly but it's a requirement + // This state will be restored on rt_sigreturn + memset(Frame->State.xmm.avx.data, 0, sizeof(Frame->State.xmm)); + memset(Frame->State.mm, 0, sizeof(Frame->State.mm)); + Frame->State.FCW = 0x37F; + Frame->State.AbridgedFTW = 0; + + // Set the new PC + ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); + // Set our state register to point to our guest thread data + ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); + + return true; +} + +bool SignalDelegator::HandleSIGILL(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) { + if (ArchHelpers::Context::GetPc(ucontext) == Config.SignalHandlerReturnAddress || + ArchHelpers::Context::GetPc(ucontext) == Config.SignalHandlerReturnAddressRT) { + RestoreThreadState(Thread, ucontext, + ArchHelpers::Context::GetPc(ucontext) == Config.SignalHandlerReturnAddressRT ? RestoreType::TYPE_REALTIME : + RestoreType::TYPE_NONREALTIME); + + // Ref count our faults + // We use this to track if it is safe to clear cache + --Thread->CurrentFrame->SignalHandlerRefCounter; + + if (Thread->DeferredSignalFrames.size() != 0) { + // If we have more deferred frames to process then mprotect back to PROT_NONE. + // It will have been RW coming in to this sigreturn and now we need to remove permissions + // to ensure FEX trampolines back to the SIGSEGV deferred handler. + mprotect(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096, PROT_NONE); + } + return true; + } + + if (ArchHelpers::Context::GetPc(ucontext) == Config.PauseReturnInstruction) { + RestoreThreadState(Thread, ucontext, RestoreType::TYPE_PAUSE); + + // Ref count our faults + // We use this to track if it is safe to clear cache + --Thread->CurrentFrame->SignalHandlerRefCounter; + return true; + } + + return false; +} + +bool SignalDelegator::HandleSignalPause(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) { + FEXCore::Core::SignalEvent SignalReason = Thread->SignalReason.load(); + auto Frame = Thread->CurrentFrame; + + if (SignalReason == FEXCore::Core::SignalEvent::Pause) { + // Store our thread state so we can come back to this + StoreThreadState(Thread, Signal, ucontext); + + if (CTX->IsAddressInCodeBuffer(Thread, ArchHelpers::Context::GetPc(ucontext))) { + // We are in jit, SRA must be spilled + ArchHelpers::Context::SetPc(ucontext, Config.ThreadPauseHandlerAddressSpillSRA); + } else { + // We are in non-jit, SRA is already spilled + LOGMAN_THROW_A_FMT(!IsAddressInDispatcher(ArchHelpers::Context::GetPc(ucontext)), "Signals in dispatcher have unsynchronized " + "context"); + ArchHelpers::Context::SetPc(ucontext, Config.ThreadPauseHandlerAddress); + } + + // Set our state register to point to our guest thread data + ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); // Ref count our faults // We use this to track if it is safe to clear cache ++Thread->CurrentFrame->SignalHandlerRefCounter; - uint64_t OldPC = ArchHelpers::Context::GetPc(ucontext); - const bool WasInJIT = CTX->IsAddressInCodeBuffer(Thread, OldPC); + Thread->SignalReason.store(FEXCore::Core::SignalEvent::Nothing); + return true; + } - // Spill the SRA regardless of signal handler type - // We are going to be returning to the top of the dispatcher which will fill again - // Otherwise we might load garbage - if (WasInJIT) { - uint32_t IgnoreMask{}; -#ifdef _M_ARM_64 - if (Frame->InSyscallInfo != 0) { - // We are in a syscall, this means we are in a weird register state - // We need to spill SRA but only some of it, since some values have already been spilled - // Lower 16 bits tells us which registers are already spilled to the context - // So we ignore spilling those ones - IgnoreMask = Frame->InSyscallInfo & 0xFFFF; - } - else { - // We must spill everything - IgnoreMask = 0; - } -#endif + if (SignalReason == FEXCore::Core::SignalEvent::Stop) { + // Our thread is stopping + // We don't care about anything at this point + // Set the stack to our starting location when we entered the core and get out safely + ArchHelpers::Context::SetSp(ucontext, Frame->ReturningStackLocation); - // We are in jit, SRA must be spilled - SpillSRA(Thread, ucontext, IgnoreMask); - - ContextBackup->Flags |= ArchHelpers::Context::ContextFlags::CONTEXT_FLAG_INJIT; - - // We are leaving the syscall information behind. Make sure to store the previous state. - ContextBackup->InSyscallInfo = Thread->CurrentFrame->InSyscallInfo; - Thread->CurrentFrame->InSyscallInfo = 0; - } else { - if (!IsAddressInDispatcher(OldPC)) { - // This is likely to cause issues but in some cases it isn't fatal - // This can also happen if we have put a signal on hold, then we just reenabled the signal - // So we are in the syscall handler - // Only throw a log message in this case - if constexpr (false) { - // XXX: Messages in the signal handler can cause us to crash - LogMan::Msg::EFmt("Signals in dispatcher have unsynchronized context"); - } - } - } - - uint64_t OldGuestSP = Frame->State.gregs[FEXCore::X86State::REG_RSP]; - uint64_t NewGuestSP = OldGuestSP; - - // altstack is only used if the signal handler was setup with SA_ONSTACK - if (GuestAction->sa_flags & SA_ONSTACK) { - // Additionally the altstack is only used if the enabled (SS_DISABLE flag is not set) - if (!(GuestStack->ss_flags & SS_DISABLE)) { - // If our guest is already inside of the alternative stack - // Then that means we are hitting recursive signals and we need to walk back the stack correctly - uint64_t AltStackBase = reinterpret_cast(GuestStack->ss_sp); - uint64_t AltStackEnd = AltStackBase + GuestStack->ss_size; - if (OldGuestSP >= AltStackBase && - OldGuestSP <= AltStackEnd) { - // We are already in the alt stack, the rest of the code will handle adjusting this - } - else { - NewGuestSP = AltStackEnd; - } - } - } - - // siginfo_t - siginfo_t *HostSigInfo = reinterpret_cast(info); - - // Backup where we think the RIP currently is - ContextBackup->OriginalRIP = CTX->RestoreRIPFromHostPC(Thread, ArchHelpers::Context::GetPc(ucontext)); - // Calculate eflags upfront. - uint32_t eflags = CTX->ReconstructCompactedEFLAGS(Thread, WasInJIT, ArchHelpers::Context::GetArmGPRs(ucontext), ArchHelpers::Context::GetArmPState(ucontext)); - - if (Is64BitMode) { - NewGuestSP = SetupFrame_x64(Thread, ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags); - } - else { - const bool SigInfoFrame = (GuestAction->sa_flags & SA_SIGINFO) == SA_SIGINFO; - if (SigInfoFrame) { - NewGuestSP = SetupRTFrame_ia32(ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags); - } - else { - NewGuestSP = SetupFrame_ia32(ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags); - } - } - - Frame->State.rip = reinterpret_cast(GuestAction->sigaction_handler.sigaction); - Frame->State.gregs[FEXCore::X86State::REG_RSP] = NewGuestSP; - - // The guest starts its signal frame with a zero initialized FPU - // Set that up now. Little bit costly but it's a requirement - // This state will be restored on rt_sigreturn - memset(Frame->State.xmm.avx.data, 0, sizeof(Frame->State.xmm)); - memset(Frame->State.mm, 0, sizeof(Frame->State.mm)); - Frame->State.FCW = 0x37F; - Frame->State.AbridgedFTW = 0; + // Our ref counting doesn't matter anymore + Thread->CurrentFrame->SignalHandlerRefCounter = 0; // Set the new PC - ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); - // Set our state register to point to our guest thread data - ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); + if (CTX->IsAddressInCodeBuffer(Thread, ArchHelpers::Context::GetPc(ucontext))) { + // We are in jit, SRA must be spilled + ArchHelpers::Context::SetPc(ucontext, Config.ThreadStopHandlerAddressSpillSRA); + } else { + // We are in non-jit, SRA is already spilled + LOGMAN_THROW_A_FMT(!IsAddressInDispatcher(ArchHelpers::Context::GetPc(ucontext)), "Signals in dispatcher have unsynchronized " + "context"); + ArchHelpers::Context::SetPc(ucontext, Config.ThreadStopHandlerAddress); + } + // We need to be a little bit careful here + // If we were already paused (due to GDB) and we are immediately stopping (due to gdb kill) + // Then we need to ensure we don't double decrement our idle thread counter + if (Thread->RunningEvents.ThreadSleeping) { + // If the thread was sleeping then its idle counter was decremented + // Reincrement it here to not break logic + FEX::HLE::_SyscallHandler->TM.IncrementIdleRefCount(); + } + + Thread->SignalReason.store(FEXCore::Core::SignalEvent::Nothing); return true; } - bool SignalDelegator::HandleSIGILL(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) { - if (ArchHelpers::Context::GetPc(ucontext) == Config.SignalHandlerReturnAddress || - ArchHelpers::Context::GetPc(ucontext) == Config.SignalHandlerReturnAddressRT) { - RestoreThreadState(Thread, ucontext, - ArchHelpers::Context::GetPc(ucontext) == Config.SignalHandlerReturnAddressRT ? RestoreType::TYPE_REALTIME : RestoreType::TYPE_NONREALTIME); + if (SignalReason == FEXCore::Core::SignalEvent::Return || SignalReason == FEXCore::Core::SignalEvent::ReturnRT) { + RestoreThreadState(Thread, ucontext, + SignalReason == FEXCore::Core::SignalEvent::ReturnRT ? RestoreType::TYPE_REALTIME : RestoreType::TYPE_NONREALTIME); - // Ref count our faults - // We use this to track if it is safe to clear cache - --Thread->CurrentFrame->SignalHandlerRefCounter; + // Ref count our faults + // We use this to track if it is safe to clear cache + --Thread->CurrentFrame->SignalHandlerRefCounter; - if (Thread->DeferredSignalFrames.size() != 0) { - // If we have more deferred frames to process then mprotect back to PROT_NONE. - // It will have been RW coming in to this sigreturn and now we need to remove permissions - // to ensure FEX trampolines back to the SIGSEGV deferred handler. - mprotect(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096, PROT_NONE); - } - return true; - } - - if (ArchHelpers::Context::GetPc(ucontext) == Config.PauseReturnInstruction) { - RestoreThreadState(Thread, ucontext, RestoreType::TYPE_PAUSE); - - // Ref count our faults - // We use this to track if it is safe to clear cache - --Thread->CurrentFrame->SignalHandlerRefCounter; - return true; - } - - return false; - } - - bool SignalDelegator::HandleSignalPause(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) { - FEXCore::Core::SignalEvent SignalReason = Thread->SignalReason.load(); - auto Frame = Thread->CurrentFrame; - - if (SignalReason == FEXCore::Core::SignalEvent::Pause) { - // Store our thread state so we can come back to this - StoreThreadState(Thread, Signal, ucontext); - - if (CTX->IsAddressInCodeBuffer(Thread, ArchHelpers::Context::GetPc(ucontext))) { - // We are in jit, SRA must be spilled - ArchHelpers::Context::SetPc(ucontext, Config.ThreadPauseHandlerAddressSpillSRA); - } else { - // We are in non-jit, SRA is already spilled - LOGMAN_THROW_A_FMT(!IsAddressInDispatcher(ArchHelpers::Context::GetPc(ucontext)), - "Signals in dispatcher have unsynchronized context"); - ArchHelpers::Context::SetPc(ucontext, Config.ThreadPauseHandlerAddress); - } - - // Set our state register to point to our guest thread data - ArchHelpers::Context::SetState(ucontext, reinterpret_cast(Frame)); - - // Ref count our faults - // We use this to track if it is safe to clear cache - ++Thread->CurrentFrame->SignalHandlerRefCounter; - - Thread->SignalReason.store(FEXCore::Core::SignalEvent::Nothing); - return true; - } - - if (SignalReason == FEXCore::Core::SignalEvent::Stop) { - // Our thread is stopping - // We don't care about anything at this point - // Set the stack to our starting location when we entered the core and get out safely - ArchHelpers::Context::SetSp(ucontext, Frame->ReturningStackLocation); - - // Our ref counting doesn't matter anymore - Thread->CurrentFrame->SignalHandlerRefCounter = 0; - - // Set the new PC - if (CTX->IsAddressInCodeBuffer(Thread, ArchHelpers::Context::GetPc(ucontext))) { - // We are in jit, SRA must be spilled - ArchHelpers::Context::SetPc(ucontext, Config.ThreadStopHandlerAddressSpillSRA); - } else { - // We are in non-jit, SRA is already spilled - LOGMAN_THROW_A_FMT(!IsAddressInDispatcher(ArchHelpers::Context::GetPc(ucontext)), - "Signals in dispatcher have unsynchronized context"); - ArchHelpers::Context::SetPc(ucontext, Config.ThreadStopHandlerAddress); - } - - // We need to be a little bit careful here - // If we were already paused (due to GDB) and we are immediately stopping (due to gdb kill) - // Then we need to ensure we don't double decrement our idle thread counter - if (Thread->RunningEvents.ThreadSleeping) { - // If the thread was sleeping then its idle counter was decremented - // Reincrement it here to not break logic - FEX::HLE::_SyscallHandler->TM.IncrementIdleRefCount(); - } - - Thread->SignalReason.store(FEXCore::Core::SignalEvent::Nothing); - return true; - } - - if (SignalReason == FEXCore::Core::SignalEvent::Return || - SignalReason == FEXCore::Core::SignalEvent::ReturnRT) { - RestoreThreadState(Thread, ucontext, SignalReason == FEXCore::Core::SignalEvent::ReturnRT ? RestoreType::TYPE_REALTIME : RestoreType::TYPE_NONREALTIME); - - // Ref count our faults - // We use this to track if it is safe to clear cache - --Thread->CurrentFrame->SignalHandlerRefCounter; - - Thread->SignalReason.store(FEXCore::Core::SignalEvent::Nothing); - return true; - } - return false; - } - - void SignalDelegator::SignalThread(FEXCore::Core::InternalThreadState *Thread, FEXCore::Core::SignalEvent Event) { - if (Event == FEXCore::Core::SignalEvent::Pause && - Thread->RunningEvents.Running.load() == false) { - // Skip signaling a thread if it is already paused. - return; - } - Thread->SignalReason.store(Event); - FHU::Syscalls::tgkill(Thread->ThreadManager.PID, Thread->ThreadManager.TID, SignalDelegator::SIGNAL_FOR_PAUSE); - } - - /** @} */ - - static bool IsAsyncSignal(const siginfo_t* Info, int Signal) { - if (Info->si_code <= SI_USER) { - // If the signal is not from the kernel then it is always async. - // This is because synchronous signals can be sent through tgkill,sigqueue and other methods. - // SI_USER == 0 and all negative si_code values come from the user. - return true; - } - else { - // If the signal is from the kernel then it is async only if it isn't an explicit synchronous signal. - switch (Signal) { - // These are all synchronous signals. - case SIGBUS: - case SIGFPE: - case SIGILL: - case SIGSEGV: - case SIGTRAP: - return false; - default: break; - } - } - - // Everything else is async and can be deferred. + Thread->SignalReason.store(FEXCore::Core::SignalEvent::Nothing); return true; } + return false; +} - void SignalDelegator::HandleGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *Info, void *UContext) { - ucontext_t* _context = (ucontext_t*)UContext; - auto SigInfo = *static_cast(Info); +void SignalDelegator::SignalThread(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::SignalEvent Event) { + if (Event == FEXCore::Core::SignalEvent::Pause && Thread->RunningEvents.Running.load() == false) { + // Skip signaling a thread if it is already paused. + return; + } + Thread->SignalReason.store(Event); + FHU::Syscalls::tgkill(Thread->ThreadManager.PID, Thread->ThreadManager.TID, SignalDelegator::SIGNAL_FOR_PAUSE); +} - constexpr bool SupportDeferredSignals = true; - if (SupportDeferredSignals) { - auto MustDeferSignal = (Thread->CurrentFrame->State.DeferredSignalRefCount.Load() != 0); +/** @} */ - if (Signal == SIGSEGV && - SigInfo.si_code == SEGV_ACCERR && - SigInfo.si_addr == reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress)) { - if (!MustDeferSignal) { - // We just reached the end of the outermost signal-deferring section and faulted to check for pending signals. - // Pull a signal frame off the stack. +static bool IsAsyncSignal(const siginfo_t* Info, int Signal) { + if (Info->si_code <= SI_USER) { + // If the signal is not from the kernel then it is always async. + // This is because synchronous signals can be sent through tgkill,sigqueue and other methods. + // SI_USER == 0 and all negative si_code values come from the user. + return true; + } else { + // If the signal is from the kernel then it is async only if it isn't an explicit synchronous signal. + switch (Signal) { + // These are all synchronous signals. + case SIGBUS: + case SIGFPE: + case SIGILL: + case SIGSEGV: + case SIGTRAP: return false; + default: break; + } + } - mprotect(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096, PROT_READ | PROT_WRITE); + // Everything else is async and can be deferred. + return true; +} - if (Thread->DeferredSignalFrames.empty()) { - // No signals to defer. Just set the fault page back to RW and continue execution. - // This occurs as a minor race condition between the refcount decrement and the access to the fault page. - return; - } +void SignalDelegator::HandleGuestSignal(FEXCore::Core::InternalThreadState* Thread, int Signal, void* Info, void* UContext) { + ucontext_t* _context = (ucontext_t*)UContext; + auto SigInfo = *static_cast(Info); - auto Top = Thread->DeferredSignalFrames.back(); - Signal = Top.Signal; - SigInfo = Top.Info; - Thread->DeferredSignalFrames.pop_back(); + constexpr bool SupportDeferredSignals = true; + if (SupportDeferredSignals) { + auto MustDeferSignal = (Thread->CurrentFrame->State.DeferredSignalRefCount.Load() != 0); - // Until we re-protect the page to PROT_NONE, FEX will now *permanently* defer signals and /not/ check them. - // - // In order to return /back/ to a sane state, we wait for the rt_sigreturn to happen. - // rt_sigreturn will check if there are any more deferred signals to handle - // - If there are deferred signals - // - mprotect back to PROT_NONE - // - sigreturn will trampoline out to the previous fault address check, SIGSEGV and restart - // - If there are *no* deferred signals - // - No need to mprotect, it is already RW + if (Signal == SIGSEGV && SigInfo.si_code == SEGV_ACCERR && + SigInfo.si_addr == reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress)) { + if (!MustDeferSignal) { + // We just reached the end of the outermost signal-deferring section and faulted to check for pending signals. + // Pull a signal frame off the stack. + + mprotect(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096, PROT_READ | PROT_WRITE); + + if (Thread->DeferredSignalFrames.empty()) { + // No signals to defer. Just set the fault page back to RW and continue execution. + // This occurs as a minor race condition between the refcount decrement and the access to the fault page. + return; } - else { + + auto Top = Thread->DeferredSignalFrames.back(); + Signal = Top.Signal; + SigInfo = Top.Info; + Thread->DeferredSignalFrames.pop_back(); + + // Until we re-protect the page to PROT_NONE, FEX will now *permanently* defer signals and /not/ check them. + // + // In order to return /back/ to a sane state, we wait for the rt_sigreturn to happen. + // rt_sigreturn will check if there are any more deferred signals to handle + // - If there are deferred signals + // - mprotect back to PROT_NONE + // - sigreturn will trampoline out to the previous fault address check, SIGSEGV and restart + // - If there are *no* deferred signals + // - No need to mprotect, it is already RW + } else { #ifdef _M_ARM_64 - // If RefCount != 0 then that means we hit an access with nested signal-deferring sections. - // Increment the PC past the `str zr, [x1]` to continue code execution until we reach the outermost section. - ArchHelpers::Context::SetPc(UContext, ArchHelpers::Context::GetPc(UContext) + 4); - return; + // If RefCount != 0 then that means we hit an access with nested signal-deferring sections. + // Increment the PC past the `str zr, [x1]` to continue code execution until we reach the outermost section. + ArchHelpers::Context::SetPc(UContext, ArchHelpers::Context::GetPc(UContext) + 4); + return; #else - // X86 should always be doing a refcount compare and branch since we can't guarantee instruction size. - // ARM64 just always does the access to reduce branching overhead. - ERROR_AND_DIE_FMT("X86 shouldn't hit this DeferredSignalFaultAddress"); + // X86 should always be doing a refcount compare and branch since we can't guarantee instruction size. + // ARM64 just always does the access to reduce branching overhead. + ERROR_AND_DIE_FMT("X86 shouldn't hit this DeferredSignalFaultAddress"); #endif - } } - else if (Signal == SIGSEGV && - SigInfo.si_code == SEGV_ACCERR && - FaultSafeMemcpy::IsFaultLocation(ArchHelpers::Context::GetPc(UContext))) { - // If you want to emulate EFAULT behaviour then enable this if-statement. - // Do this once we find an application that depends on this. - if constexpr (false) { - // Return from the subroutine, returning EFAULT. - ArchHelpers::Context::SetArmReg(UContext, 0, EFAULT); - ArchHelpers::Context::SetPc(UContext, ArchHelpers::Context::GetArmReg(UContext, 30)); - return; - } - else { - LogMan::Msg::AFmt("Received invalid data to syscall. Crashing now!"); - } + } else if (Signal == SIGSEGV && SigInfo.si_code == SEGV_ACCERR && FaultSafeMemcpy::IsFaultLocation(ArchHelpers::Context::GetPc(UContext))) { + // If you want to emulate EFAULT behaviour then enable this if-statement. + // Do this once we find an application that depends on this. + if constexpr (false) { + // Return from the subroutine, returning EFAULT. + ArchHelpers::Context::SetArmReg(UContext, 0, EFAULT); + ArchHelpers::Context::SetPc(UContext, ArchHelpers::Context::GetArmReg(UContext, 30)); + return; + } else { + LogMan::Msg::AFmt("Received invalid data to syscall. Crashing now!"); } - else { - if (IsAsyncSignal(&SigInfo, Signal) && MustDeferSignal) { - // If the signal is asynchronous (as determined by si_code) and FEX is in a state of needing - // to defer the signal, then add the signal to the thread's signal queue. - LOGMAN_THROW_A_FMT(Thread->DeferredSignalFrames.size() != Thread->DeferredSignalFrames.capacity(), - "Deferred signals vector hit capacity size. This will likely crash! Asserting now!"); - Thread->DeferredSignalFrames.emplace_back(FEXCore::Core::InternalThreadState::DeferredSignalState { - .Info = SigInfo, - .Signal = Signal, - }); + } else { + if (IsAsyncSignal(&SigInfo, Signal) && MustDeferSignal) { + // If the signal is asynchronous (as determined by si_code) and FEX is in a state of needing + // to defer the signal, then add the signal to the thread's signal queue. + LOGMAN_THROW_A_FMT(Thread->DeferredSignalFrames.size() != Thread->DeferredSignalFrames.capacity(), "Deferred signals vector hit " + "capacity size. This will " + "likely crash! Asserting now!"); + Thread->DeferredSignalFrames.emplace_back(FEXCore::Core::InternalThreadState::DeferredSignalState { + .Info = SigInfo, + .Signal = Signal, + }); - // Now update the faulting page permissions so it will fault on write. - mprotect(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096, PROT_NONE); + // Now update the faulting page permissions so it will fault on write. + mprotect(reinterpret_cast(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096, PROT_NONE); - // Postpone the remainder of signal handling logic until we process the SIGSEGV triggered by writing to DeferredSignalFaultAddress. - return; - } - } - } - // Let the host take first stab at handling the signal - SignalHandler &Handler = HostHandlers[Signal]; - - // Remove the pending signal - ThreadData.PendingSignals &= ~(1ULL << (Signal - 1)); - - // We have an emulation thread pointer, we can now modify its state - if (Handler.GuestAction.sigaction_handler.handler == SIG_DFL) { - if (Handler.DefaultBehaviour == DEFAULT_TERM || - Handler.DefaultBehaviour == DEFAULT_COREDUMP) { - // Let the signal fall through to the unhandled path - // This way the parent process can know it died correctly - } - } - else if (Handler.GuestAction.sigaction_handler.handler == SIG_IGN) { - return; - } - else { - if (Handler.GuestHandler && - Handler.GuestHandler(Thread, Signal, &SigInfo, UContext, &Handler.GuestAction, &ThreadData.GuestAltStack)) { - // Set up a new mask based on this signals signal mask - uint64_t NewMask = Handler.GuestAction.sa_mask.Val; - - // If NODEFER then the new signal mask includes this signal - if (!(Handler.GuestAction.sa_flags & SA_NODEFER)) { - NewMask |= (1ULL << (Signal - 1)); - } - - // Walk our required signals and stop masking them if requested - for (size_t i = 0; i < MAX_SIGNALS; ++i) { - if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) { - // Never mask our required signals - NewMask &= ~(1ULL << i); - } - } - - // Update our host signal mask so we don't hit race conditions with signals - // This allows us to maintain the expected signal mask through the guest signal handling and then all the way back again - memcpy(&_context->uc_sigmask, &NewMask, sizeof(uint64_t)); - - // We handled this signal, continue running + // Postpone the remainder of signal handling logic until we process the SIGSEGV triggered by writing to DeferredSignalFaultAddress. return; } - ERROR_AND_DIE_FMT("Unhandled guest exception"); } + } + // Let the host take first stab at handling the signal + SignalHandler& Handler = HostHandlers[Signal]; - // Unhandled crash - // Call back in to the previous handler - if (Handler.OldAction.sa_flags & SA_SIGINFO) { - Handler.OldAction.sigaction(Signal, &SigInfo, UContext); + // Remove the pending signal + ThreadData.PendingSignals &= ~(1ULL << (Signal - 1)); + + // We have an emulation thread pointer, we can now modify its state + if (Handler.GuestAction.sigaction_handler.handler == SIG_DFL) { + if (Handler.DefaultBehaviour == DEFAULT_TERM || Handler.DefaultBehaviour == DEFAULT_COREDUMP) { + // Let the signal fall through to the unhandled path + // This way the parent process can know it died correctly } - else if (Handler.OldAction.handler == SIG_IGN || - (Handler.OldAction.handler == SIG_DFL && - Handler.DefaultBehaviour == DEFAULT_IGNORE)) { - // Do nothing + } else if (Handler.GuestAction.sigaction_handler.handler == SIG_IGN) { + return; + } else { + if (Handler.GuestHandler && Handler.GuestHandler(Thread, Signal, &SigInfo, UContext, &Handler.GuestAction, &ThreadData.GuestAltStack)) { + // Set up a new mask based on this signals signal mask + uint64_t NewMask = Handler.GuestAction.sa_mask.Val; + + // If NODEFER then the new signal mask includes this signal + if (!(Handler.GuestAction.sa_flags & SA_NODEFER)) { + NewMask |= (1ULL << (Signal - 1)); + } + + // Walk our required signals and stop masking them if requested + for (size_t i = 0; i < MAX_SIGNALS; ++i) { + if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) { + // Never mask our required signals + NewMask &= ~(1ULL << i); + } + } + + // Update our host signal mask so we don't hit race conditions with signals + // This allows us to maintain the expected signal mask through the guest signal handling and then all the way back again + memcpy(&_context->uc_sigmask, &NewMask, sizeof(uint64_t)); + + // We handled this signal, continue running + return; } - else if (Handler.OldAction.handler == SIG_DFL && - (Handler.DefaultBehaviour == DEFAULT_COREDUMP || - Handler.DefaultBehaviour == DEFAULT_TERM)) { + ERROR_AND_DIE_FMT("Unhandled guest exception"); + } + + // Unhandled crash + // Call back in to the previous handler + if (Handler.OldAction.sa_flags & SA_SIGINFO) { + Handler.OldAction.sigaction(Signal, &SigInfo, UContext); + } else if (Handler.OldAction.handler == SIG_IGN || (Handler.OldAction.handler == SIG_DFL && Handler.DefaultBehaviour == DEFAULT_IGNORE)) { + // Do nothing + } else if (Handler.OldAction.handler == SIG_DFL && (Handler.DefaultBehaviour == DEFAULT_COREDUMP || Handler.DefaultBehaviour == DEFAULT_TERM)) { #ifndef FEX_DISABLE_TELEMETRY - // In the case of signals that cause coredump or terminate, save telemetry early. - // FEX is hard crashing at this point and won't hit regular shutdown routines. - // Add the signal to the crash mask. - CrashMask |= (1ULL << Signal); - if (Signal == SIGSEGV && - reinterpret_cast(SigInfo.si_addr) >= SyscallHandler::TASK_MAX_64BIT) { - // Tried accessing invalid non-canonical x86-64 address. - UnhandledNonCanonical = true; - } - SaveTelemetry(); + // In the case of signals that cause coredump or terminate, save telemetry early. + // FEX is hard crashing at this point and won't hit regular shutdown routines. + // Add the signal to the crash mask. + CrashMask |= (1ULL << Signal); + if (Signal == SIGSEGV && reinterpret_cast(SigInfo.si_addr) >= SyscallHandler::TASK_MAX_64BIT) { + // Tried accessing invalid non-canonical x86-64 address. + UnhandledNonCanonical = true; + } + SaveTelemetry(); #endif - // Reassign back to DFL and crash - signal(Signal, SIG_DFL); - if (SigInfo.si_code != SI_KERNEL) { - // If the signal wasn't sent by the kernel then we need to reraise it. - // This is necessary since returning from this signal handler now might just continue executing. - // eg: If sent from tgkill then the signal gets dropped and returns. - FHU::Syscalls::tgkill(::getpid(), FHU::Syscalls::gettid(), Signal); - } - } - else { - Handler.OldAction.handler(Signal); + // Reassign back to DFL and crash + signal(Signal, SIG_DFL); + if (SigInfo.si_code != SI_KERNEL) { + // If the signal wasn't sent by the kernel then we need to reraise it. + // This is necessary since returning from this signal handler now might just continue executing. + // eg: If sent from tgkill then the signal gets dropped and returns. + FHU::Syscalls::tgkill(::getpid(), FHU::Syscalls::gettid(), Signal); } + } else { + Handler.OldAction.handler(Signal); } +} - void SignalDelegator::SaveTelemetry() { +void SignalDelegator::SaveTelemetry() { #ifndef FEX_DISABLE_TELEMETRY - if (!ApplicationName.empty()) { - FEXCore::Telemetry::Shutdown(ApplicationName); - } + if (!ApplicationName.empty()) { + FEXCore::Telemetry::Shutdown(ApplicationName); + } #endif +} + +bool SignalDelegator::InstallHostThunk(int Signal) { + SignalHandler& SignalHandler = HostHandlers[Signal]; + // If the host thunk is already installed for this, just return + if (SignalHandler.Installed) { + return false; } - bool SignalDelegator::InstallHostThunk(int Signal) { - SignalHandler &SignalHandler = HostHandlers[Signal]; - // If the host thunk is already installed for this, just return - if (SignalHandler.Installed) { - return false; + // Default flags for us + SignalHandler.HostAction.sa_flags = SA_SIGINFO | SA_ONSTACK; + + bool Result = UpdateHostThunk(Signal); + + SignalHandler.Installed = Result; + return Result; +} + +bool SignalDelegator::UpdateHostThunk(int Signal) { + SignalHandler& SignalHandler = HostHandlers[Signal]; + + // Now install the thunk handler + SignalHandler.HostAction.sigaction = SignalHandlerThunk; + + auto CheckAndAddFlags = [](uint64_t HostFlags, uint64_t GuestFlags, uint64_t Flags) { + // If any of the flags don't match then update to the newest set + if ((HostFlags ^ GuestFlags) & Flags) { + // Remove all the flags from the host that we are testing for + HostFlags &= ~Flags; + // Copy over the guest flags being set + HostFlags |= GuestFlags & Flags; } - // Default flags for us - SignalHandler.HostAction.sa_flags = SA_SIGINFO | SA_ONSTACK; + return HostFlags; + }; - bool Result = UpdateHostThunk(Signal); - - SignalHandler.Installed = Result; - return Result; - } - - bool SignalDelegator::UpdateHostThunk(int Signal) { - SignalHandler &SignalHandler = HostHandlers[Signal]; - - // Now install the thunk handler - SignalHandler.HostAction.sigaction = SignalHandlerThunk; - - auto CheckAndAddFlags = [](uint64_t HostFlags, uint64_t GuestFlags, uint64_t Flags) { - // If any of the flags don't match then update to the newest set - if ((HostFlags ^ GuestFlags) & Flags) { - // Remove all the flags from the host that we are testing for - HostFlags &= ~Flags; - // Copy over the guest flags being set - HostFlags |= GuestFlags & Flags; - } - - return HostFlags; - }; - - // Don't allow the guest to override flags for - // SA_SIGINFO : Host always needs SA_SIGINFO - // SA_ONSTACK : Host always needs the altstack - // SA_RESETHAND : We don't support one shot handlers - // SA_RESTORER : We always need our host side restorer on x86-64, Couldn't use guest restorer anyway - SignalHandler.HostAction.sa_flags = CheckAndAddFlags( - SignalHandler.HostAction.sa_flags, - SignalHandler.GuestAction.sa_flags, - SA_NOCLDSTOP | SA_NOCLDWAIT | SA_NODEFER | SA_RESTART); + // Don't allow the guest to override flags for + // SA_SIGINFO : Host always needs SA_SIGINFO + // SA_ONSTACK : Host always needs the altstack + // SA_RESETHAND : We don't support one shot handlers + // SA_RESTORER : We always need our host side restorer on x86-64, Couldn't use guest restorer anyway + SignalHandler.HostAction.sa_flags = CheckAndAddFlags(SignalHandler.HostAction.sa_flags, SignalHandler.GuestAction.sa_flags, + SA_NOCLDSTOP | SA_NOCLDWAIT | SA_NODEFER | SA_RESTART); #ifdef _M_X86_64 #define SA_RESTORER 0x04000000 - SignalHandler.HostAction.sa_flags |= SA_RESTORER; - SignalHandler.HostAction.restorer = sigrestore; + SignalHandler.HostAction.sa_flags |= SA_RESTORER; + SignalHandler.HostAction.restorer = sigrestore; #endif - // Walk the signals we have that are required and make sure to remove it from the mask - // This'll likely be SIGILL, SIGBUS, SIG63 + // Walk the signals we have that are required and make sure to remove it from the mask + // This'll likely be SIGILL, SIGBUS, SIG63 - // If the guest has masked some signals then we need to also mask those signals - for (size_t i = 1; i < HostHandlers.size(); ++i) { - if (HostHandlers[i].Required.load(std::memory_order_relaxed)) { - SignalHandler.HostAction.sa_mask &= ~(1ULL << (i - 1)); - } - else if (SigIsMember(&SignalHandler.GuestAction.sa_mask, i)) { - SignalHandler.HostAction.sa_mask |= (1ULL << (i - 1)); - } + // If the guest has masked some signals then we need to also mask those signals + for (size_t i = 1; i < HostHandlers.size(); ++i) { + if (HostHandlers[i].Required.load(std::memory_order_relaxed)) { + SignalHandler.HostAction.sa_mask &= ~(1ULL << (i - 1)); + } else if (SigIsMember(&SignalHandler.GuestAction.sa_mask, i)) { + SignalHandler.HostAction.sa_mask |= (1ULL << (i - 1)); } - - // Check for SIG_IGN - if (SignalHandler.GuestAction.sigaction_handler.handler == SIG_IGN && - HostHandlers[Signal].Required.load(std::memory_order_relaxed) == false) { - // We are ignoring this signal on the guest - // Which means we need to ignore it on the host as well - SignalHandler.HostAction.handler = SIG_IGN; - } - - // Check for SIG_DFL - if (SignalHandler.GuestAction.sigaction_handler.handler == SIG_DFL && - HostHandlers[Signal].Required.load(std::memory_order_relaxed) == false) { - // Default handler on guest and default handler on host - // With coredump and terminate then expect fireworks, but that is what the guest wants - SignalHandler.HostAction.handler = SIG_DFL; - } - - // Only update the old action if we haven't ever been installed - const int Result = ::syscall(SYS_rt_sigaction, Signal, &SignalHandler.HostAction, SignalHandler.Installed ? nullptr : &SignalHandler.OldAction, 8); - if (Result < 0) { - // Signal 32 and 33 are consumed by glibc. We don't handle this atm - LogMan::Msg::AFmt("Failed to install host signal thunk for signal {}: {}", Signal, strerror(errno)); - return false; - } - - return true; } - void SignalDelegator::UninstallHostHandler(int Signal) { - SignalHandler &SignalHandler = HostHandlers[Signal]; - - ::syscall(SYS_rt_sigaction, Signal, &SignalHandler.OldAction, nullptr, 8); + // Check for SIG_IGN + if (SignalHandler.GuestAction.sigaction_handler.handler == SIG_IGN && HostHandlers[Signal].Required.load(std::memory_order_relaxed) == false) { + // We are ignoring this signal on the guest + // Which means we need to ignore it on the host as well + SignalHandler.HostAction.handler = SIG_IGN; } - SignalDelegator::SignalDelegator(FEXCore::Context::Context *_CTX, const std::string_view ApplicationName) - : CTX {_CTX} - , ApplicationName {ApplicationName} { - // Register this delegate - LOGMAN_THROW_AA_FMT(!GlobalDelegator, "Can't register global delegator multiple times!"); - GlobalDelegator = this; - // Signal zero isn't real - HostHandlers[0].Installed = true; + // Check for SIG_DFL + if (SignalHandler.GuestAction.sigaction_handler.handler == SIG_DFL && HostHandlers[Signal].Required.load(std::memory_order_relaxed) == false) { + // Default handler on guest and default handler on host + // With coredump and terminate then expect fireworks, but that is what the guest wants + SignalHandler.HostAction.handler = SIG_DFL; + } - // We can't capture SIGKILL or SIGSTOP - HostHandlers[SIGKILL].Installed = true; - HostHandlers[SIGSTOP].Installed = true; + // Only update the old action if we haven't ever been installed + const int Result = + ::syscall(SYS_rt_sigaction, Signal, &SignalHandler.HostAction, SignalHandler.Installed ? nullptr : &SignalHandler.OldAction, 8); + if (Result < 0) { + // Signal 32 and 33 are consumed by glibc. We don't handle this atm + LogMan::Msg::AFmt("Failed to install host signal thunk for signal {}: {}", Signal, strerror(errno)); + return false; + } - // Most signals default to termination - // These ones are slightly different - static constexpr std::array, 14> SignalDefaultBehaviours = {{ - {SIGQUIT, DEFAULT_COREDUMP}, - {SIGILL, DEFAULT_COREDUMP}, - {SIGTRAP, DEFAULT_COREDUMP}, - {SIGABRT, DEFAULT_COREDUMP}, - {SIGBUS, DEFAULT_COREDUMP}, - {SIGFPE, DEFAULT_COREDUMP}, - {SIGSEGV, DEFAULT_COREDUMP}, - {SIGCHLD, DEFAULT_IGNORE}, - {SIGCONT, DEFAULT_IGNORE}, - {SIGURG, DEFAULT_IGNORE}, - {SIGXCPU, DEFAULT_COREDUMP}, - {SIGXFSZ, DEFAULT_COREDUMP}, - {SIGSYS, DEFAULT_COREDUMP}, - {SIGWINCH, DEFAULT_IGNORE}, - }}; + return true; +} - for (const auto &[Signal, Behaviour] : SignalDefaultBehaviours) { - HostHandlers[Signal].DefaultBehaviour = Behaviour; - } +void SignalDelegator::UninstallHostHandler(int Signal) { + SignalHandler& SignalHandler = HostHandlers[Signal]; - // Register frontend SIGILL handler for forced assertion. - RegisterFrontendHostSignalHandler(SIGILL, [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool { + ::syscall(SYS_rt_sigaction, Signal, &SignalHandler.OldAction, nullptr, 8); +} + +SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::string_view ApplicationName) + : CTX {_CTX} + , ApplicationName {ApplicationName} { + // Register this delegate + LOGMAN_THROW_AA_FMT(!GlobalDelegator, "Can't register global delegator multiple times!"); + GlobalDelegator = this; + // Signal zero isn't real + HostHandlers[0].Installed = true; + + // We can't capture SIGKILL or SIGSTOP + HostHandlers[SIGKILL].Installed = true; + HostHandlers[SIGSTOP].Installed = true; + + // Most signals default to termination + // These ones are slightly different + static constexpr std::array, 14> SignalDefaultBehaviours = {{ + {SIGQUIT, DEFAULT_COREDUMP}, + {SIGILL, DEFAULT_COREDUMP}, + {SIGTRAP, DEFAULT_COREDUMP}, + {SIGABRT, DEFAULT_COREDUMP}, + {SIGBUS, DEFAULT_COREDUMP}, + {SIGFPE, DEFAULT_COREDUMP}, + {SIGSEGV, DEFAULT_COREDUMP}, + {SIGCHLD, DEFAULT_IGNORE}, + {SIGCONT, DEFAULT_IGNORE}, + {SIGURG, DEFAULT_IGNORE}, + {SIGXCPU, DEFAULT_COREDUMP}, + {SIGXFSZ, DEFAULT_COREDUMP}, + {SIGSYS, DEFAULT_COREDUMP}, + {SIGWINCH, DEFAULT_IGNORE}, + }}; + + for (const auto& [Signal, Behaviour] : SignalDefaultBehaviours) { + HostHandlers[Signal].DefaultBehaviour = Behaviour; + } + + // Register frontend SIGILL handler for forced assertion. + RegisterFrontendHostSignalHandler( + SIGILL, + [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) -> bool { ucontext_t* _context = (ucontext_t*)ucontext; - auto &mcontext = _context->uc_mcontext; - uint64_t PC{}; + auto& mcontext = _context->uc_mcontext; + uint64_t PC {}; #ifdef _M_ARM_64 PC = mcontext.pc; #else @@ -1746,420 +1669,412 @@ namespace FEX::HLE { return true; } return false; - }, true); + }, + true); - const auto PauseHandler = [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool { - return GlobalDelegator->HandleSignalPause(Thread, Signal, info, ucontext); - }; + const auto PauseHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) -> bool { + return GlobalDelegator->HandleSignalPause(Thread, Signal, info, ucontext); + }; - const auto GuestSignalHandler = [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext, GuestSigAction *GuestAction, stack_t *GuestStack) -> bool { - return GlobalDelegator->HandleDispatcherGuestSignal(Thread, Signal, info, ucontext, GuestAction, GuestStack); - }; + const auto GuestSignalHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext, + GuestSigAction* GuestAction, stack_t* GuestStack) -> bool { + return GlobalDelegator->HandleDispatcherGuestSignal(Thread, Signal, info, ucontext, GuestAction, GuestStack); + }; - const auto SigillHandler = [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool { - return GlobalDelegator->HandleSIGILL(Thread, Signal, info, ucontext); - }; + const auto SigillHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) -> bool { + return GlobalDelegator->HandleSIGILL(Thread, Signal, info, ucontext); + }; - // Register SIGILL signal handler. - RegisterHostSignalHandler(SIGILL, SigillHandler, true); + // Register SIGILL signal handler. + RegisterHostSignalHandler(SIGILL, SigillHandler, true); #ifdef _M_ARM_64 - // Register SIGBUS signal handler. - const auto SigbusHandler = [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *_info, void *ucontext) -> bool { - const auto PC = ArchHelpers::Context::GetPc(ucontext); - if (!Thread->CTX->IsAddressInCodeBuffer(Thread, PC)) { - // Wasn't a sigbus in JIT code - return false; - } - siginfo_t* info = reinterpret_cast(_info); + // Register SIGBUS signal handler. + const auto SigbusHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* _info, void* ucontext) -> bool { + const auto PC = ArchHelpers::Context::GetPc(ucontext); + if (!Thread->CTX->IsAddressInCodeBuffer(Thread, PC)) { + // Wasn't a sigbus in JIT code + return false; + } + siginfo_t* info = reinterpret_cast(_info); - if (info->si_code != BUS_ADRALN) { - // This only handles alignment problems - return false; - } + if (info->si_code != BUS_ADRALN) { + // This only handles alignment problems + return false; + } - const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, GlobalDelegator->ParanoidTSO(), PC, ArchHelpers::Context::GetArmGPRs(ucontext)); - ArchHelpers::Context::SetPc(ucontext, PC + Result.second); - return Result.first; - }; + const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, GlobalDelegator->ParanoidTSO(), PC, + ArchHelpers::Context::GetArmGPRs(ucontext)); + ArchHelpers::Context::SetPc(ucontext, PC + Result.second); + return Result.first; + }; - RegisterHostSignalHandler(SIGBUS, SigbusHandler, true); + RegisterHostSignalHandler(SIGBUS, SigbusHandler, true); #endif - // Register pause signal handler. - RegisterHostSignalHandler(SignalDelegator::SIGNAL_FOR_PAUSE, PauseHandler, true); + // Register pause signal handler. + RegisterHostSignalHandler(SignalDelegator::SIGNAL_FOR_PAUSE, PauseHandler, true); - // Guest signal handlers. - for (uint32_t Signal = 0; Signal <= SignalDelegator::MAX_SIGNALS; ++Signal) { - RegisterHostSignalHandlerForGuest(Signal, GuestSignalHandler); - } - } - - SignalDelegator::~SignalDelegator() { - for (int i = 0; i < MAX_SIGNALS; ++i) { - if (i == 0 || - i == SIGKILL || - i == SIGSTOP || - !HostHandlers[i].Installed - ) { - continue; - } - ::syscall(SYS_rt_sigaction, i, &HostHandlers[i].OldAction, nullptr, 8); - HostHandlers[i].Installed = false; - } - GlobalDelegator = nullptr; - } - - FEXCore::Core::InternalThreadState *SignalDelegator::GetTLSThread() { - return ThreadData.Thread; - } - - void SignalDelegator::RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) { - ThreadData.Thread = Thread; - - // Set up our signal alternative stack - // This is per thread rather than per signal - ThreadData.AltStackPtr = FEXCore::Allocator::mmap(nullptr, SIGSTKSZ * 16, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - stack_t altstack{}; - altstack.ss_sp = ThreadData.AltStackPtr; - altstack.ss_size = SIGSTKSZ * 16; - altstack.ss_flags = 0; - LOGMAN_THROW_AA_FMT(!!altstack.ss_sp, "Couldn't allocate stack pointer"); - - // Register the alt stack - const int Result = sigaltstack(&altstack, nullptr); - if (Result == -1) { - LogMan::Msg::EFmt("Failed to install alternative signal stack {}", strerror(errno)); - } - - // Get the current host signal mask - ::syscall(SYS_rt_sigprocmask, 0, nullptr, &ThreadData.CurrentSignalMask.Val, 8); - - if (Thread != (FEXCore::Core::InternalThreadState*)UINTPTR_MAX) { - // Reserve a small amount of deferred signal frames. Usually the stack won't be utilized beyond - // 1 or 2 signals but add a few more just in case. - Thread->DeferredSignalFrames.reserve(8); - } - } - - void SignalDelegator::UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) { - FEXCore::Allocator::munmap(ThreadData.AltStackPtr, SIGSTKSZ * 16); - - ThreadData.AltStackPtr = nullptr; - - stack_t altstack{}; - altstack.ss_flags = SS_DISABLE; - - // Uninstall the alt stack - const int Result = sigaltstack(&altstack, nullptr); - if (Result == -1) { - LogMan::Msg::EFmt("Failed to uninstall alternative signal stack {}", strerror(errno)); - } - - ThreadData.Thread = nullptr; - } - - void SignalDelegator::FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - // Linux signal handlers are per-process rather than per thread - // Multiple threads could be calling in to this - std::lock_guard lk(HostDelegatorMutex); - HostHandlers[Signal].Required = Required; - InstallHostThunk(Signal); - } - - void SignalDelegator::FrontendRegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - // Linux signal handlers are per-process rather than per thread - // Multiple threads could be calling in to this - std::lock_guard lk(HostDelegatorMutex); - HostHandlers[Signal].Required = Required; - InstallHostThunk(Signal); - } - - void SignalDelegator::RegisterHostSignalHandlerForGuest(int Signal, FEX::HLE::HostSignalDelegatorFunctionForGuest Func) { - std::lock_guard lk(HostDelegatorMutex); - HostHandlers[Signal].GuestHandler = std::move(Func); - } - - void SignalDelegator::RegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - SetFrontendHostSignalHandler(Signal, Func, Required); - FrontendRegisterFrontendHostSignalHandler(Signal, Func, Required); - } - - uint64_t SignalDelegator::RegisterGuestSignalHandler(int Signal, const GuestSigAction *Action, GuestSigAction *OldAction) { - std::lock_guard lk(GuestDelegatorMutex); - - // Invalid signal specified - if (Signal > MAX_SIGNALS) { - return -EINVAL; - } - - // If we have an old signal set then give it back - if (OldAction) { - *OldAction = HostHandlers[Signal].GuestAction; - } - - // Now assign the new action - if (Action) { - // These signal dispositions can't be changed on Linux - if (Signal == SIGKILL || Signal == SIGSTOP) { - return -EINVAL; - } - - HostHandlers[Signal].GuestAction = *Action; - // Only attempt to install a new thunk handler if we were installing a new guest action - if (!InstallHostThunk(Signal)) { - UpdateHostThunk(Signal); - } - } - - return 0; - } - - void SignalDelegator::CheckXIDHandler() { - std::lock_guard lk(GuestDelegatorMutex); - std::lock_guard lk2(HostDelegatorMutex); - - constexpr size_t SIGNAL_SETXID = 33; - - kernel_sigaction CurrentAction{}; - - // Only update the old action if we haven't ever been installed - const int Result = ::syscall(SYS_rt_sigaction, SIGNAL_SETXID, nullptr, &CurrentAction, 8); - if (Result < 0) { - LogMan::Msg::AFmt("Failed to get status of XID signal"); - return; - } - - SignalHandler &HostHandler = HostHandlers[SIGNAL_SETXID]; - if (CurrentAction.handler != HostHandler.HostAction.handler) { - // GLIBC overwrote our XID handler, reinstate our handler - const int Result = ::syscall(SYS_rt_sigaction, SIGNAL_SETXID, &HostHandler.HostAction, nullptr, 8); - if (Result < 0) { - LogMan::Msg::AFmt("Failed to reinstate our XID signal handler {}", strerror(errno)); - } - } - } - - uint64_t SignalDelegator::RegisterGuestSigAltStack(const stack_t *ss, stack_t *old_ss) { - auto Thread = GetTLSThread(); - bool UsingAltStack{}; - uint64_t AltStackBase = reinterpret_cast(ThreadData.GuestAltStack.ss_sp); - uint64_t AltStackEnd = AltStackBase + ThreadData.GuestAltStack.ss_size; - uint64_t GuestSP = Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]; - - if (!(ThreadData.GuestAltStack.ss_flags & SS_DISABLE) && - GuestSP >= AltStackBase && - GuestSP <= AltStackEnd) { - UsingAltStack = true; - } - - // If we have an old signal set then give it back - if (old_ss) { - *old_ss = ThreadData.GuestAltStack; - - if (UsingAltStack) { - // We are currently operating on the alt stack - // Let the guest know - old_ss->ss_flags |= SS_ONSTACK; - } - else { - old_ss->ss_flags |= SS_DISABLE; - } - } - - // Now assign the new action - if (ss) { - // If we tried setting the alt stack while we are using it then throw an error - if (UsingAltStack) { - return -EPERM; - } - - // We need to check for invalid flags - // The only flag that can be passed is SS_AUTODISARM and SS_DISABLE - if ((ss->ss_flags & ~SS_ONSTACK) & // SS_ONSTACK is ignored - ~(SS_AUTODISARM | SS_DISABLE)) { - // A flag remained that isn't one of the supported ones? - return -EINVAL; - } - - if (ss->ss_flags & SS_DISABLE) { - // If SS_DISABLE Is specified then the rest of the details are ignored - ThreadData.GuestAltStack = *ss; - return 0; - } - - // stack size needs to be MINSIGSTKSZ (0x2000) - if (ss->ss_size < X86_MINSIGSTKSZ) { - return -ENOMEM; - } - - ThreadData.GuestAltStack = *ss; - } - - return 0; - } - - static void CheckForPendingSignals(FEXCore::Core::InternalThreadState *Thread) { - // Do we have any pending signals that became unmasked? - uint64_t PendingSignals = ~ThreadData.CurrentSignalMask.Val & ThreadData.PendingSignals; - if (PendingSignals != 0) { - for (int i = 0; i < 64; ++i) { - if (PendingSignals & (1ULL << i)) { - FHU::Syscalls::tgkill(Thread->ThreadManager.PID, Thread->ThreadManager.TID, i + 1); - // We might not even return here which is spooky - } - } - } - } - - uint64_t SignalDelegator::GuestSigProcMask(int how, const uint64_t *set, uint64_t *oldset) { - // The order in which we handle signal mask setting is important here - // old and new can point to the same location in memory. - // Even if the pointers are to same memory location, we must store the original signal mask - // coming in to the syscall. - // 1) Store old mask - // 2) Set mask to new mask if exists - // 3) Give old mask back - auto OldSet = ThreadData.CurrentSignalMask.Val; - - if (!!set) { - uint64_t IgnoredSignalsMask = ~((1ULL << (SIGKILL - 1)) | (1ULL << (SIGSTOP - 1))); - if (how == SIG_BLOCK) { - ThreadData.CurrentSignalMask.Val |= *set & IgnoredSignalsMask; - } - else if (how == SIG_UNBLOCK) { - ThreadData.CurrentSignalMask.Val &= ~(*set & IgnoredSignalsMask); - } - else if (how == SIG_SETMASK) { - ThreadData.CurrentSignalMask.Val = *set & IgnoredSignalsMask; - } - else { - return -EINVAL; - } - - uint64_t HostMask = ThreadData.CurrentSignalMask.Val; - // Now actually set the host mask - // This will hide from the guest that we are not actually setting all of the masks it wants - for (size_t i = 0; i < MAX_SIGNALS; ++i) { - if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) { - // If it is a required host signal then we can't mask it - HostMask &= ~(1ULL << i); - } - } - - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &HostMask, nullptr, 8); - } - - if (!!oldset) { - *oldset = OldSet; - } - - CheckForPendingSignals(GetTLSThread()); - - return 0; - } - - uint64_t SignalDelegator::GuestSigPending(uint64_t *set, size_t sigsetsize) { - if (sigsetsize > sizeof(uint64_t)) { - return -EINVAL; - } - - *set = ThreadData.PendingSignals; - - sigset_t HostSet{}; - if (sigpending(&HostSet) == 0) { - uint64_t HostSignals{}; - for (size_t i = 0; i < MAX_SIGNALS; ++i) { - if (sigismember(&HostSet, i + 1)) { - HostSignals |= (1ULL << i); - } - } - - // Merge the real pending signal mask as well - *set |= HostSignals; - } - return 0; - } - - uint64_t SignalDelegator::GuestSigSuspend(uint64_t *set, size_t sigsetsize) { - if (sigsetsize > sizeof(uint64_t)) { - return -EINVAL; - } - - uint64_t IgnoredSignalsMask = ~((1ULL << (SIGKILL - 1)) | (1ULL << (SIGSTOP - 1))); - - // Backup the mask - ThreadData.PreviousSuspendMask = ThreadData.CurrentSignalMask; - // Set the new mask - ThreadData.CurrentSignalMask.Val = *set & IgnoredSignalsMask; - sigset_t HostSet{}; - - sigemptyset(&HostSet); - - for (int32_t i = 0; i < MAX_SIGNALS; ++i) { - if (*set & (1ULL << i)) { - sigaddset(&HostSet, i + 1); - } - } - - // Additionally we must always listen to SIGNAL_FOR_PAUSE - // This technically forces us in to a race but should be fine - // SIGBUS and SIGILL can't happen so we don't need to listen for them - //sigaddset(&HostSet, SIGNAL_FOR_PAUSE); - - // Spin this in a loop until we aren't sigsuspended - // This can happen in the case that the guest has sent signal that we can't block - uint64_t Result = sigsuspend(&HostSet); - - // Restore Previous signal mask we are emulating - // XXX: Might be unsafe if the signal handler adjusted the thread's signal mask - // But since we don't support the guest adjusting the mask through the context object - // then this is safe-ish - ThreadData.CurrentSignalMask = ThreadData.PreviousSuspendMask; - - CheckForPendingSignals(GetTLSThread()); - - return Result == -1 ? -errno : Result; - - } - - uint64_t SignalDelegator::GuestSigTimedWait(uint64_t *set, siginfo_t *info, const struct timespec *timeout, size_t sigsetsize) { - if (sigsetsize > sizeof(uint64_t)) { - return -EINVAL; - } - - uint64_t Result = ::syscall(SYS_rt_sigtimedwait, set, info, timeout); - - return Result == -1 ? -errno : Result; - } - - uint64_t SignalDelegator::GuestSignalFD(int fd, const uint64_t *set, size_t sigsetsize, int flags) { - if (sigsetsize > sizeof(uint64_t)) { - return -EINVAL; - } - - sigset_t HostSet{}; - sigemptyset(&HostSet); - - for (size_t i = 0; i < MAX_SIGNALS; ++i) { - if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) { - // For now skip our internal signals - continue; - } - - if (*set & (1ULL << i)) { - sigaddset(&HostSet, i + 1); - } - } - - // XXX: This is a barebones implementation just to get applications that listen for SIGCHLD to work - // In the future we need our own listern thread that forwards the result - // Thread is necessary to prevent deadlocks for a thread that has signaled on the same thread listening to the FD and blocking is enabled - uint64_t Result = signalfd(fd, &HostSet, flags); - - return Result == -1 ? -errno : Result; - } - - fextl::unique_ptr CreateSignalDelegator(FEXCore::Context::Context *CTX, const std::string_view ApplicationName) { - return fextl::make_unique(CTX, ApplicationName); + // Guest signal handlers. + for (uint32_t Signal = 0; Signal <= SignalDelegator::MAX_SIGNALS; ++Signal) { + RegisterHostSignalHandlerForGuest(Signal, GuestSignalHandler); } } + +SignalDelegator::~SignalDelegator() { + for (int i = 0; i < MAX_SIGNALS; ++i) { + if (i == 0 || i == SIGKILL || i == SIGSTOP || !HostHandlers[i].Installed) { + continue; + } + ::syscall(SYS_rt_sigaction, i, &HostHandlers[i].OldAction, nullptr, 8); + HostHandlers[i].Installed = false; + } + GlobalDelegator = nullptr; +} + +FEXCore::Core::InternalThreadState* SignalDelegator::GetTLSThread() { + return ThreadData.Thread; +} + +void SignalDelegator::RegisterTLSState(FEXCore::Core::InternalThreadState* Thread) { + ThreadData.Thread = Thread; + + // Set up our signal alternative stack + // This is per thread rather than per signal + ThreadData.AltStackPtr = FEXCore::Allocator::mmap(nullptr, SIGSTKSZ * 16, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + stack_t altstack {}; + altstack.ss_sp = ThreadData.AltStackPtr; + altstack.ss_size = SIGSTKSZ * 16; + altstack.ss_flags = 0; + LOGMAN_THROW_AA_FMT(!!altstack.ss_sp, "Couldn't allocate stack pointer"); + + // Register the alt stack + const int Result = sigaltstack(&altstack, nullptr); + if (Result == -1) { + LogMan::Msg::EFmt("Failed to install alternative signal stack {}", strerror(errno)); + } + + // Get the current host signal mask + ::syscall(SYS_rt_sigprocmask, 0, nullptr, &ThreadData.CurrentSignalMask.Val, 8); + + if (Thread != (FEXCore::Core::InternalThreadState*)UINTPTR_MAX) { + // Reserve a small amount of deferred signal frames. Usually the stack won't be utilized beyond + // 1 or 2 signals but add a few more just in case. + Thread->DeferredSignalFrames.reserve(8); + } +} + +void SignalDelegator::UninstallTLSState(FEXCore::Core::InternalThreadState* Thread) { + FEXCore::Allocator::munmap(ThreadData.AltStackPtr, SIGSTKSZ * 16); + + ThreadData.AltStackPtr = nullptr; + + stack_t altstack {}; + altstack.ss_flags = SS_DISABLE; + + // Uninstall the alt stack + const int Result = sigaltstack(&altstack, nullptr); + if (Result == -1) { + LogMan::Msg::EFmt("Failed to uninstall alternative signal stack {}", strerror(errno)); + } + + ThreadData.Thread = nullptr; +} + +void SignalDelegator::FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + // Linux signal handlers are per-process rather than per thread + // Multiple threads could be calling in to this + std::lock_guard lk(HostDelegatorMutex); + HostHandlers[Signal].Required = Required; + InstallHostThunk(Signal); +} + +void SignalDelegator::FrontendRegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + // Linux signal handlers are per-process rather than per thread + // Multiple threads could be calling in to this + std::lock_guard lk(HostDelegatorMutex); + HostHandlers[Signal].Required = Required; + InstallHostThunk(Signal); +} + +void SignalDelegator::RegisterHostSignalHandlerForGuest(int Signal, FEX::HLE::HostSignalDelegatorFunctionForGuest Func) { + std::lock_guard lk(HostDelegatorMutex); + HostHandlers[Signal].GuestHandler = std::move(Func); +} + +void SignalDelegator::RegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + SetFrontendHostSignalHandler(Signal, Func, Required); + FrontendRegisterFrontendHostSignalHandler(Signal, Func, Required); +} + +uint64_t SignalDelegator::RegisterGuestSignalHandler(int Signal, const GuestSigAction* Action, GuestSigAction* OldAction) { + std::lock_guard lk(GuestDelegatorMutex); + + // Invalid signal specified + if (Signal > MAX_SIGNALS) { + return -EINVAL; + } + + // If we have an old signal set then give it back + if (OldAction) { + *OldAction = HostHandlers[Signal].GuestAction; + } + + // Now assign the new action + if (Action) { + // These signal dispositions can't be changed on Linux + if (Signal == SIGKILL || Signal == SIGSTOP) { + return -EINVAL; + } + + HostHandlers[Signal].GuestAction = *Action; + // Only attempt to install a new thunk handler if we were installing a new guest action + if (!InstallHostThunk(Signal)) { + UpdateHostThunk(Signal); + } + } + + return 0; +} + +void SignalDelegator::CheckXIDHandler() { + std::lock_guard lk(GuestDelegatorMutex); + std::lock_guard lk2(HostDelegatorMutex); + + constexpr size_t SIGNAL_SETXID = 33; + + kernel_sigaction CurrentAction {}; + + // Only update the old action if we haven't ever been installed + const int Result = ::syscall(SYS_rt_sigaction, SIGNAL_SETXID, nullptr, &CurrentAction, 8); + if (Result < 0) { + LogMan::Msg::AFmt("Failed to get status of XID signal"); + return; + } + + SignalHandler& HostHandler = HostHandlers[SIGNAL_SETXID]; + if (CurrentAction.handler != HostHandler.HostAction.handler) { + // GLIBC overwrote our XID handler, reinstate our handler + const int Result = ::syscall(SYS_rt_sigaction, SIGNAL_SETXID, &HostHandler.HostAction, nullptr, 8); + if (Result < 0) { + LogMan::Msg::AFmt("Failed to reinstate our XID signal handler {}", strerror(errno)); + } + } +} + +uint64_t SignalDelegator::RegisterGuestSigAltStack(const stack_t* ss, stack_t* old_ss) { + auto Thread = GetTLSThread(); + bool UsingAltStack {}; + uint64_t AltStackBase = reinterpret_cast(ThreadData.GuestAltStack.ss_sp); + uint64_t AltStackEnd = AltStackBase + ThreadData.GuestAltStack.ss_size; + uint64_t GuestSP = Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]; + + if (!(ThreadData.GuestAltStack.ss_flags & SS_DISABLE) && GuestSP >= AltStackBase && GuestSP <= AltStackEnd) { + UsingAltStack = true; + } + + // If we have an old signal set then give it back + if (old_ss) { + *old_ss = ThreadData.GuestAltStack; + + if (UsingAltStack) { + // We are currently operating on the alt stack + // Let the guest know + old_ss->ss_flags |= SS_ONSTACK; + } else { + old_ss->ss_flags |= SS_DISABLE; + } + } + + // Now assign the new action + if (ss) { + // If we tried setting the alt stack while we are using it then throw an error + if (UsingAltStack) { + return -EPERM; + } + + // We need to check for invalid flags + // The only flag that can be passed is SS_AUTODISARM and SS_DISABLE + if ((ss->ss_flags & ~SS_ONSTACK) & // SS_ONSTACK is ignored + ~(SS_AUTODISARM | SS_DISABLE)) { + // A flag remained that isn't one of the supported ones? + return -EINVAL; + } + + if (ss->ss_flags & SS_DISABLE) { + // If SS_DISABLE Is specified then the rest of the details are ignored + ThreadData.GuestAltStack = *ss; + return 0; + } + + // stack size needs to be MINSIGSTKSZ (0x2000) + if (ss->ss_size < X86_MINSIGSTKSZ) { + return -ENOMEM; + } + + ThreadData.GuestAltStack = *ss; + } + + return 0; +} + +static void CheckForPendingSignals(FEXCore::Core::InternalThreadState* Thread) { + // Do we have any pending signals that became unmasked? + uint64_t PendingSignals = ~ThreadData.CurrentSignalMask.Val & ThreadData.PendingSignals; + if (PendingSignals != 0) { + for (int i = 0; i < 64; ++i) { + if (PendingSignals & (1ULL << i)) { + FHU::Syscalls::tgkill(Thread->ThreadManager.PID, Thread->ThreadManager.TID, i + 1); + // We might not even return here which is spooky + } + } + } +} + +uint64_t SignalDelegator::GuestSigProcMask(int how, const uint64_t* set, uint64_t* oldset) { + // The order in which we handle signal mask setting is important here + // old and new can point to the same location in memory. + // Even if the pointers are to same memory location, we must store the original signal mask + // coming in to the syscall. + // 1) Store old mask + // 2) Set mask to new mask if exists + // 3) Give old mask back + auto OldSet = ThreadData.CurrentSignalMask.Val; + + if (!!set) { + uint64_t IgnoredSignalsMask = ~((1ULL << (SIGKILL - 1)) | (1ULL << (SIGSTOP - 1))); + if (how == SIG_BLOCK) { + ThreadData.CurrentSignalMask.Val |= *set & IgnoredSignalsMask; + } else if (how == SIG_UNBLOCK) { + ThreadData.CurrentSignalMask.Val &= ~(*set & IgnoredSignalsMask); + } else if (how == SIG_SETMASK) { + ThreadData.CurrentSignalMask.Val = *set & IgnoredSignalsMask; + } else { + return -EINVAL; + } + + uint64_t HostMask = ThreadData.CurrentSignalMask.Val; + // Now actually set the host mask + // This will hide from the guest that we are not actually setting all of the masks it wants + for (size_t i = 0; i < MAX_SIGNALS; ++i) { + if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) { + // If it is a required host signal then we can't mask it + HostMask &= ~(1ULL << i); + } + } + + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &HostMask, nullptr, 8); + } + + if (!!oldset) { + *oldset = OldSet; + } + + CheckForPendingSignals(GetTLSThread()); + + return 0; +} + +uint64_t SignalDelegator::GuestSigPending(uint64_t* set, size_t sigsetsize) { + if (sigsetsize > sizeof(uint64_t)) { + return -EINVAL; + } + + *set = ThreadData.PendingSignals; + + sigset_t HostSet {}; + if (sigpending(&HostSet) == 0) { + uint64_t HostSignals {}; + for (size_t i = 0; i < MAX_SIGNALS; ++i) { + if (sigismember(&HostSet, i + 1)) { + HostSignals |= (1ULL << i); + } + } + + // Merge the real pending signal mask as well + *set |= HostSignals; + } + return 0; +} + +uint64_t SignalDelegator::GuestSigSuspend(uint64_t* set, size_t sigsetsize) { + if (sigsetsize > sizeof(uint64_t)) { + return -EINVAL; + } + + uint64_t IgnoredSignalsMask = ~((1ULL << (SIGKILL - 1)) | (1ULL << (SIGSTOP - 1))); + + // Backup the mask + ThreadData.PreviousSuspendMask = ThreadData.CurrentSignalMask; + // Set the new mask + ThreadData.CurrentSignalMask.Val = *set & IgnoredSignalsMask; + sigset_t HostSet {}; + + sigemptyset(&HostSet); + + for (int32_t i = 0; i < MAX_SIGNALS; ++i) { + if (*set & (1ULL << i)) { + sigaddset(&HostSet, i + 1); + } + } + + // Additionally we must always listen to SIGNAL_FOR_PAUSE + // This technically forces us in to a race but should be fine + // SIGBUS and SIGILL can't happen so we don't need to listen for them + // sigaddset(&HostSet, SIGNAL_FOR_PAUSE); + + // Spin this in a loop until we aren't sigsuspended + // This can happen in the case that the guest has sent signal that we can't block + uint64_t Result = sigsuspend(&HostSet); + + // Restore Previous signal mask we are emulating + // XXX: Might be unsafe if the signal handler adjusted the thread's signal mask + // But since we don't support the guest adjusting the mask through the context object + // then this is safe-ish + ThreadData.CurrentSignalMask = ThreadData.PreviousSuspendMask; + + CheckForPendingSignals(GetTLSThread()); + + return Result == -1 ? -errno : Result; +} + +uint64_t SignalDelegator::GuestSigTimedWait(uint64_t* set, siginfo_t* info, const struct timespec* timeout, size_t sigsetsize) { + if (sigsetsize > sizeof(uint64_t)) { + return -EINVAL; + } + + uint64_t Result = ::syscall(SYS_rt_sigtimedwait, set, info, timeout); + + return Result == -1 ? -errno : Result; +} + +uint64_t SignalDelegator::GuestSignalFD(int fd, const uint64_t* set, size_t sigsetsize, int flags) { + if (sigsetsize > sizeof(uint64_t)) { + return -EINVAL; + } + + sigset_t HostSet {}; + sigemptyset(&HostSet); + + for (size_t i = 0; i < MAX_SIGNALS; ++i) { + if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) { + // For now skip our internal signals + continue; + } + + if (*set & (1ULL << i)) { + sigaddset(&HostSet, i + 1); + } + } + + // XXX: This is a barebones implementation just to get applications that listen for SIGCHLD to work + // In the future we need our own listern thread that forwards the result + // Thread is necessary to prevent deadlocks for a thread that has signaled on the same thread listening to the FD and blocking is enabled + uint64_t Result = signalfd(fd, &HostSet, flags); + + return Result == -1 ? -errno : Result; +} + +fextl::unique_ptr CreateSignalDelegator(FEXCore::Context::Context* CTX, const std::string_view ApplicationName) { + return fextl::make_unique(CTX, ApplicationName); +} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h index b928c86d9..973a4d208 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h @@ -32,245 +32,247 @@ namespace Context { namespace Core { struct InternalThreadState; } -} +} // namespace FEXCore namespace FEX::HLE { - using HostSignalDelegatorFunction = std::function; - using HostSignalDelegatorFunctionForGuest = std::function; +using HostSignalDelegatorFunction = std::function; +using HostSignalDelegatorFunctionForGuest = + std::function; - class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::Allocator::FEXAllocOperators { - public: - constexpr static size_t MAX_SIGNALS {64}; +class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::Allocator::FEXAllocOperators { +public: + constexpr static size_t MAX_SIGNALS {64}; - // Use the last signal just so we are less likely to ever conflict with something that the guest application is using - // 64 is used internally by Valgrind - constexpr static size_t SIGNAL_FOR_PAUSE {63}; + // Use the last signal just so we are less likely to ever conflict with something that the guest application is using + // 64 is used internally by Valgrind + constexpr static size_t SIGNAL_FOR_PAUSE {63}; - // Returns true if the host handled the signal - // Arguments are the same as sigaction handler - SignalDelegator(FEXCore::Context::Context *_CTX, const std::string_view ApplicationName); - ~SignalDelegator() override; + // Returns true if the host handled the signal + // Arguments are the same as sigaction handler + SignalDelegator(FEXCore::Context::Context* _CTX, const std::string_view ApplicationName); + ~SignalDelegator() override; - // Called from the signal trampoline function. - void HandleSignal(int Signal, void *Info, void *UContext); + // Called from the signal trampoline function. + void HandleSignal(int Signal, void* Info, void* UContext); - void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread); - void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread); + void RegisterTLSState(FEXCore::Core::InternalThreadState* Thread); + void UninstallTLSState(FEXCore::Core::InternalThreadState* Thread); - /** - * @brief Registers a signal handler for the host to handle a signal - * - * It's a process level signal handler so one must be careful - */ - void RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); + /** + * @brief Registers a signal handler for the host to handle a signal + * + * It's a process level signal handler so one must be careful + */ + void RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); - /** - * @brief Registers a signal handler for the host to handle a signal specifically for guest handling - * - * It's a process level signal handler so one must be careful - */ - void RegisterHostSignalHandlerForGuest(int Signal, HostSignalDelegatorFunctionForGuest Func); - void RegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); + /** + * @brief Registers a signal handler for the host to handle a signal specifically for guest handling + * + * It's a process level signal handler so one must be careful + */ + void RegisterHostSignalHandlerForGuest(int Signal, HostSignalDelegatorFunctionForGuest Func); + void RegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); - /** - * @name These functions are all for Linux signal emulation - * @{ */ - /** - * @brief Allows the guest to register a signal handler that is run after the host attempts to resolve the handler first - */ - uint64_t RegisterGuestSignalHandler(int Signal, const GuestSigAction *Action, struct GuestSigAction *OldAction); + /** + * @name These functions are all for Linux signal emulation + * @{ */ + /** + * @brief Allows the guest to register a signal handler that is run after the host attempts to resolve the handler first + */ + uint64_t RegisterGuestSignalHandler(int Signal, const GuestSigAction* Action, struct GuestSigAction* OldAction); - uint64_t RegisterGuestSigAltStack(const stack_t *ss, stack_t *old_ss); + uint64_t RegisterGuestSigAltStack(const stack_t* ss, stack_t* old_ss); - uint64_t GuestSigProcMask(int how, const uint64_t *set, uint64_t *oldset); - uint64_t GuestSigPending(uint64_t *set, size_t sigsetsize); - uint64_t GuestSigSuspend(uint64_t *set, size_t sigsetsize); - uint64_t GuestSigTimedWait(uint64_t *set, siginfo_t *info, const struct timespec *timeout, size_t sigsetsize); - uint64_t GuestSignalFD(int fd, const uint64_t *set, size_t sigsetsize , int flags); - /** @} */ + uint64_t GuestSigProcMask(int how, const uint64_t* set, uint64_t* oldset); + uint64_t GuestSigPending(uint64_t* set, size_t sigsetsize); + uint64_t GuestSigSuspend(uint64_t* set, size_t sigsetsize); + uint64_t GuestSigTimedWait(uint64_t* set, siginfo_t* info, const struct timespec* timeout, size_t sigsetsize); + uint64_t GuestSignalFD(int fd, const uint64_t* set, size_t sigsetsize, int flags); + /** @} */ - /** - * @brief Check to ensure the XID handler is still set to the FEX handler - * - * On a new thread GLIBC will set the XID handler underneath us. - * After the first thread is created check this. - */ - void CheckXIDHandler(); + /** + * @brief Check to ensure the XID handler is still set to the FEX handler + * + * On a new thread GLIBC will set the XID handler underneath us. + * After the first thread is created check this. + */ + void CheckXIDHandler(); - void UninstallHostHandler(int Signal); - FEXCore::Context::Context *CTX; + void UninstallHostHandler(int Signal); + FEXCore::Context::Context* CTX; - void SetVDSOSigReturn() { - // Get symbols from VDSO. - VDSOPointers = FEX::VDSO::GetVDSOSymbols(); + void SetVDSOSigReturn() { + // Get symbols from VDSO. + VDSOPointers = FEX::VDSO::GetVDSOSymbols(); - // Update VDSO to generated code. - // TODO: Have the frontend generate the x86 sigreturn pointers. - CTX->GetVDSOSigReturn(&VDSOPointers); + // Update VDSO to generated code. + // TODO: Have the frontend generate the x86 sigreturn pointers. + CTX->GetVDSOSigReturn(&VDSOPointers); + } + + [[noreturn]] + void HandleSignalHandlerReturn(bool RT) { + using SignalHandlerReturnFunc = void (*)(); + + SignalHandlerReturnFunc SignalHandlerReturn {}; + if (RT) { + SignalHandlerReturn = reinterpret_cast(Config.SignalHandlerReturnAddressRT); + } else { + SignalHandlerReturn = reinterpret_cast(Config.SignalHandlerReturnAddress); } - [[noreturn]] void HandleSignalHandlerReturn(bool RT) { - using SignalHandlerReturnFunc = void(*)(); + SignalHandlerReturn(); + FEX_UNREACHABLE; + } - SignalHandlerReturnFunc SignalHandlerReturn{}; - if (RT) { - SignalHandlerReturn = reinterpret_cast(Config.SignalHandlerReturnAddressRT); - } - else { - SignalHandlerReturn = reinterpret_cast(Config.SignalHandlerReturnAddress); - } + void SignalThread(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::SignalEvent Event) override; - SignalHandlerReturn(); - FEX_UNREACHABLE; - } + FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); - void SignalThread(FEXCore::Core::InternalThreadState *Thread, FEXCore::Core::SignalEvent Event) override; + void SaveTelemetry(); +private: + FEXCore::Core::InternalThreadState* GetTLSThread(); - FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); + // Called from the thunk handler to handle the signal + void HandleGuestSignal(FEXCore::Core::InternalThreadState* Thread, int Signal, void* Info, void* UContext); - void SaveTelemetry(); - private: - FEXCore::Core::InternalThreadState *GetTLSThread(); + /** + * @brief Registers a signal handler for the host to handle a signal + * + * It's a process level signal handler so one must be careful + */ + void FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); + void FrontendRegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); - // Called from the thunk handler to handle the signal - void HandleGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *Info, void *UContext); + void SetHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + HostHandlers[Signal].Handlers.push_back(std::move(Func)); + } + void SetFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + HostHandlers[Signal].FrontendHandler = std::move(Func); + } - /** - * @brief Registers a signal handler for the host to handle a signal - * - * It's a process level signal handler so one must be careful - */ - void FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); - void FrontendRegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); + FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); + FEX_CONFIG_OPT(Core, CORE); + fextl::string const ApplicationName; + FEXCORE_TELEMETRY_INIT(CrashMask, TYPE_CRASH_MASK); + FEXCORE_TELEMETRY_INIT(UnhandledNonCanonical, TYPE_UNHANDLED_NONCANONICAL_ADDRESS); - void SetHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - HostHandlers[Signal].Handlers.push_back(std::move(Func)); - } - void SetFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - HostHandlers[Signal].FrontendHandler = std::move(Func); - } - - FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); - FEX_CONFIG_OPT(Core, CORE); - fextl::string const ApplicationName; - FEXCORE_TELEMETRY_INIT(CrashMask, TYPE_CRASH_MASK); - FEXCORE_TELEMETRY_INIT(UnhandledNonCanonical, TYPE_UNHANDLED_NONCANONICAL_ADDRESS); - - enum DefaultBehaviour { - DEFAULT_TERM, - // Core dump based signals are supposed to have a coredump appear - // For FEX's behaviour we don't really care right now - DEFAULT_COREDUMP = DEFAULT_TERM, - DEFAULT_IGNORE, - }; - - struct kernel_sigaction { - union { - void (*handler)(int); - void (*sigaction)(int, siginfo_t*, void*); - }; - - uint64_t sa_flags; - - void (*restorer)(); - uint64_t sa_mask; - }; - - struct SignalHandler { - std::atomic Installed{}; - std::atomic Required{}; - kernel_sigaction HostAction{}; - kernel_sigaction OldAction{}; - FEX::HLE::HostSignalDelegatorFunctionForGuest GuestHandler{}; - GuestSigAction GuestAction{}; - DefaultBehaviour DefaultBehaviour {DEFAULT_TERM}; - - // Callbacks - fextl::vector Handlers{}; - HostSignalDelegatorFunction FrontendHandler{}; - }; - - std::array HostHandlers{}; - bool InstallHostThunk(int Signal); - bool UpdateHostThunk(int Signal); - - FEXCore::Context::VDSOSigReturn VDSOPointers{}; - - bool IsAddressInDispatcher(uint64_t Address) const { - return Address >= Config.DispatcherBegin && Address < Config.DispatcherEnd; - } - - /* - * Signal frames on 32-bit architecture needs to match exactly how the kernel generates the frame. - * This is because large parts of the signal frame definition is part of the UAPI. - * This means that when FEX sets up the signal frame, it needs to match the UAPI stack setup. - * - * The two signal stack frame types below describe the two different 32-bit frame types. - */ - - // The 32-bit non-realtime signal frame. - // This frame type is used when the guest signal is used without the `SA_SIGINFO` flag. - struct SigFrame_i32 { - uint32_t pretcode; ///< sigreturn return branch point. - int32_t Signal; ///< The signal hit. - FEXCore::x86::sigcontext sc; ///< The signal context. - FEXCore::x86::_libc_fpstate fpstate_unused; ///< Unused fpstate. Retained for backwards compatibility. - uint32_t extramask[1]; ///< Upper 32-bits of the signal mask. Lower 32-bits is in the sigcontext. - char retcode[8]; ///< Unused but needs to be filled. GDB seemingly uses as a debug marker. - ///< FP state now follows after this. - }; - - // The 32-bit realtime signal frame. - // This frame type is used when the guest signal is used with the `SA_SIGINFO` flag. - struct RTSigFrame_i32 { - uint32_t pretcode; ///< sigreturn return branch point. - int32_t Signal; ///< The signal hit. - uint32_t pinfo; ///< Pointer to siginfo_t - uint32_t puc; ///< Pointer to ucontext_t - FEXCore::x86::siginfo_t info; - FEXCore::x86::ucontext_t uc; - char retcode[8]; ///< Unused but needs to be filled. GDB seemingly uses as a debug marker. - ///< FP state now follows after this. - }; - - void SpillSRA(FEXCore::Core::InternalThreadState *Thread, void *ucontext, uint32_t IgnoreMask); - - void RestoreFrame_x64(FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* Context, FEXCore::Core::CpuStateFrame *Frame, void *ucontext); - void RestoreFrame_ia32(FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* Context, FEXCore::Core::CpuStateFrame *Frame, void *ucontext); - void RestoreRTFrame_ia32(FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* Context, FEXCore::Core::CpuStateFrame *Frame, void *ucontext); - - ///< Setup the signal frame for x64. - uint64_t SetupFrame_x64(FEXCore::Core::InternalThreadState *Thread, ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame *Frame, - int Signal, siginfo_t *HostSigInfo, void *ucontext, - GuestSigAction *GuestAction, stack_t *GuestStack, - uint64_t NewGuestSP, const uint32_t eflags); - - ///< Setup the signal frame for a 32-bit signal without SA_SIGINFO. - uint64_t SetupFrame_ia32(ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame *Frame, - int Signal, siginfo_t *HostSigInfo, void *ucontext, - GuestSigAction *GuestAction, stack_t *GuestStack, - uint64_t NewGuestSP, const uint32_t eflags); - - ///< Setup the signal frame for a 32-bit signal with SA_SIGINFO. - uint64_t SetupRTFrame_ia32(ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame *Frame, - int Signal, siginfo_t *HostSigInfo, void *ucontext, - GuestSigAction *GuestAction, stack_t *GuestStack, - uint64_t NewGuestSP, const uint32_t eflags); - - enum class RestoreType { - TYPE_REALTIME, ///< Signal restore type is from a `realtime` signal. - TYPE_NONREALTIME, ///< Signal restore type is from a `non-realtime` signal. - TYPE_PAUSE, ///< Signal restore type is from a GDB pause event. - }; - ArchHelpers::Context::ContextBackup* StoreThreadState(FEXCore::Core::InternalThreadState *Thread, int Signal, void *ucontext); - void RestoreThreadState(FEXCore::Core::InternalThreadState *Thread, void *ucontext, RestoreType Type); - bool HandleDispatcherGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext, GuestSigAction *GuestAction, stack_t *GuestStack); - bool HandleSignalPause(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext); - bool HandleSIGILL(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext); - - std::mutex HostDelegatorMutex; - std::mutex GuestDelegatorMutex; + enum DefaultBehaviour { + DEFAULT_TERM, + // Core dump based signals are supposed to have a coredump appear + // For FEX's behaviour we don't really care right now + DEFAULT_COREDUMP = DEFAULT_TERM, + DEFAULT_IGNORE, }; - fextl::unique_ptr CreateSignalDelegator(FEXCore::Context::Context *CTX, const std::string_view ApplicationName); -} + struct kernel_sigaction { + union { + void (*handler)(int); + void (*sigaction)(int, siginfo_t*, void*); + }; + + uint64_t sa_flags; + + void (*restorer)(); + uint64_t sa_mask; + }; + + struct SignalHandler { + std::atomic Installed {}; + std::atomic Required {}; + kernel_sigaction HostAction {}; + kernel_sigaction OldAction {}; + FEX::HLE::HostSignalDelegatorFunctionForGuest GuestHandler {}; + GuestSigAction GuestAction {}; + DefaultBehaviour DefaultBehaviour {DEFAULT_TERM}; + + // Callbacks + fextl::vector Handlers {}; + HostSignalDelegatorFunction FrontendHandler {}; + }; + + std::array HostHandlers {}; + bool InstallHostThunk(int Signal); + bool UpdateHostThunk(int Signal); + + FEXCore::Context::VDSOSigReturn VDSOPointers {}; + + bool IsAddressInDispatcher(uint64_t Address) const { + return Address >= Config.DispatcherBegin && Address < Config.DispatcherEnd; + } + + /* + * Signal frames on 32-bit architecture needs to match exactly how the kernel generates the frame. + * This is because large parts of the signal frame definition is part of the UAPI. + * This means that when FEX sets up the signal frame, it needs to match the UAPI stack setup. + * + * The two signal stack frame types below describe the two different 32-bit frame types. + */ + + // The 32-bit non-realtime signal frame. + // This frame type is used when the guest signal is used without the `SA_SIGINFO` flag. + struct SigFrame_i32 { + uint32_t pretcode; ///< sigreturn return branch point. + int32_t Signal; ///< The signal hit. + FEXCore::x86::sigcontext sc; ///< The signal context. + FEXCore::x86::_libc_fpstate fpstate_unused; ///< Unused fpstate. Retained for backwards compatibility. + uint32_t extramask[1]; ///< Upper 32-bits of the signal mask. Lower 32-bits is in the sigcontext. + char retcode[8]; ///< Unused but needs to be filled. GDB seemingly uses as a debug marker. + ///< FP state now follows after this. + }; + + // The 32-bit realtime signal frame. + // This frame type is used when the guest signal is used with the `SA_SIGINFO` flag. + struct RTSigFrame_i32 { + uint32_t pretcode; ///< sigreturn return branch point. + int32_t Signal; ///< The signal hit. + uint32_t pinfo; ///< Pointer to siginfo_t + uint32_t puc; ///< Pointer to ucontext_t + FEXCore::x86::siginfo_t info; + FEXCore::x86::ucontext_t uc; + char retcode[8]; ///< Unused but needs to be filled. GDB seemingly uses as a debug marker. + ///< FP state now follows after this. + }; + + void SpillSRA(FEXCore::Core::InternalThreadState* Thread, void* ucontext, uint32_t IgnoreMask); + + void RestoreFrame_x64(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context, + FEXCore::Core::CpuStateFrame* Frame, void* ucontext); + void RestoreFrame_ia32(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context, + FEXCore::Core::CpuStateFrame* Frame, void* ucontext); + void RestoreRTFrame_ia32(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* Context, + FEXCore::Core::CpuStateFrame* Frame, void* ucontext); + + ///< Setup the signal frame for x64. + uint64_t SetupFrame_x64(FEXCore::Core::InternalThreadState* Thread, ArchHelpers::Context::ContextBackup* ContextBackup, + FEXCore::Core::CpuStateFrame* Frame, int Signal, siginfo_t* HostSigInfo, void* ucontext, + GuestSigAction* GuestAction, stack_t* GuestStack, uint64_t NewGuestSP, const uint32_t eflags); + + ///< Setup the signal frame for a 32-bit signal without SA_SIGINFO. + uint64_t SetupFrame_ia32(ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame* Frame, int Signal, + siginfo_t* HostSigInfo, void* ucontext, GuestSigAction* GuestAction, stack_t* GuestStack, uint64_t NewGuestSP, + const uint32_t eflags); + + ///< Setup the signal frame for a 32-bit signal with SA_SIGINFO. + uint64_t SetupRTFrame_ia32(ArchHelpers::Context::ContextBackup* ContextBackup, FEXCore::Core::CpuStateFrame* Frame, int Signal, + siginfo_t* HostSigInfo, void* ucontext, GuestSigAction* GuestAction, stack_t* GuestStack, uint64_t NewGuestSP, + const uint32_t eflags); + + enum class RestoreType { + TYPE_REALTIME, ///< Signal restore type is from a `realtime` signal. + TYPE_NONREALTIME, ///< Signal restore type is from a `non-realtime` signal. + TYPE_PAUSE, ///< Signal restore type is from a GDB pause event. + }; + ArchHelpers::Context::ContextBackup* StoreThreadState(FEXCore::Core::InternalThreadState* Thread, int Signal, void* ucontext); + void RestoreThreadState(FEXCore::Core::InternalThreadState* Thread, void* ucontext, RestoreType Type); + bool HandleDispatcherGuestSignal(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext, + GuestSigAction* GuestAction, stack_t* GuestStack); + bool HandleSignalPause(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext); + bool HandleSIGILL(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext); + + std::mutex HostDelegatorMutex; + std::mutex GuestDelegatorMutex; +}; + +fextl::unique_ptr CreateSignalDelegator(FEXCore::Context::Context* CTX, const std::string_view ApplicationName); +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp index 6eb9593b8..0b0f4ed2a 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp @@ -60,14 +60,11 @@ $end_info$ namespace FEX::HLE { class SignalDelegator; -SyscallHandler *_SyscallHandler{}; +SyscallHandler* _SyscallHandler {}; template -uint64_t GetDentsEmulation(int fd, T *dirp, uint32_t count) { - uint64_t Result = syscall(SYSCALL_DEF(getdents64), - static_cast(fd), - dirp, - static_cast(count)); +uint64_t GetDentsEmulation(int fd, T* dirp, uint32_t count) { + uint64_t Result = syscall(SYSCALL_DEF(getdents64), static_cast(fd), dirp, static_cast(count)); // Now copy back in to the array we were given if (Result != -1) { @@ -76,7 +73,7 @@ uint64_t GetDentsEmulation(int fd, T *dirp, uint32_t count) { if constexpr (sizeof(decltype(FEX::HLE::x64::linux_dirent_64::d_ino)) > sizeof(decltype(T::d_ino))) { uint64_t TmpOffset = 0; while (TmpOffset < Result) { - FEX::HLE::x64::linux_dirent_64 *Tmp = (FEX::HLE::x64::linux_dirent_64*)(reinterpret_cast(dirp) + TmpOffset); + FEX::HLE::x64::linux_dirent_64* Tmp = (FEX::HLE::x64::linux_dirent_64*)(reinterpret_cast(dirp) + TmpOffset); decltype(T::d_ino) Result_d_ino = Tmp->d_ino; if (Result_d_ino != Tmp->d_ino) { @@ -95,8 +92,8 @@ uint64_t GetDentsEmulation(int fd, T *dirp, uint32_t count) { // than the data returned by getdents64. // This means FEX is guaranteed to /never/ fill the full getdents buffer to the guest, but we may temporarily use it all. while (TmpOffset < Result) { - T *Outgoing = (T*)(reinterpret_cast(dirp) + Offset); - FEX::HLE::x64::linux_dirent_64 *Tmp = (FEX::HLE::x64::linux_dirent_64*)(reinterpret_cast(dirp) + TmpOffset); + T* Outgoing = (T*)(reinterpret_cast(dirp) + Offset); + FEX::HLE::x64::linux_dirent_64* Tmp = (FEX::HLE::x64::linux_dirent_64*)(reinterpret_cast(dirp) + TmpOffset); if (!Tmp->d_reclen) { break; @@ -130,11 +127,9 @@ uint64_t GetDentsEmulation(int fd, T *dirp, uint32_t count) { SYSCALL_ERRNO(); } -template -uint64_t GetDentsEmulation(int, FEX::HLE::x64::linux_dirent*, uint32_t); +template uint64_t GetDentsEmulation(int, FEX::HLE::x64::linux_dirent*, uint32_t); -template -uint64_t GetDentsEmulation(int, FEX::HLE::x32::linux_dirent_32*, uint32_t); +template uint64_t GetDentsEmulation(int, FEX::HLE::x32::linux_dirent_32*, uint32_t); static bool IsShebangFile(std::span Data) { // File isn't large enough to even contain a shebang. @@ -143,13 +138,10 @@ static bool IsShebangFile(std::span Data) { } // Handle shebang files. - if (Data[0] == '#' && - Data[1] == '!') { - fextl::string InterpreterLine { - Data.begin() + 2, // strip off "#!" prefix - std::find(Data.begin(), Data.end(), '\n') - }; - fextl::vector ShebangArguments{}; + if (Data[0] == '#' && Data[1] == '!') { + fextl::string InterpreterLine {Data.begin() + 2, // strip off "#!" prefix + std::find(Data.begin(), Data.end(), '\n')}; + fextl::vector ShebangArguments {}; // Shebang line can have a single argument fextl::istringstream InterpreterSS(InterpreterLine); @@ -162,7 +154,7 @@ static bool IsShebangFile(std::span Data) { } // Executable argument - fextl::string &ShebangProgram = ShebangArguments[0]; + fextl::string& ShebangProgram = ShebangArguments[0]; // If the filename is absolute then prepend the rootfs // If it is relative then don't append the rootfs @@ -190,7 +182,7 @@ static bool IsShebangFD(int FD) { return IsShebangFile(std::span(Header.data(), ReadSize)); } -static bool IsShebangFilename(fextl::string const &Filename) { +static bool IsShebangFilename(const fextl::string& Filename) { // Open the Filename to determine if it is a shebang file. int FD = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); if (FD == -1) { @@ -202,37 +194,33 @@ static bool IsShebangFilename(fextl::string const &Filename) { return IsShebang; } -uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* envp, ExecveAtArgs Args) { - fextl::string Filename{}; +uint64_t ExecveHandler(const char* pathname, char* const* argv, char* const* envp, ExecveAtArgs Args) { + fextl::string Filename {}; fextl::string RootFS = FEX::HLE::_SyscallHandler->RootFSPath(); - ELFLoader::ELFContainer::ELFType Type{}; + ELFLoader::ELFContainer::ELFType Type {}; // AT_EMPTY_PATH is only used if the pathname is empty. const bool IsFDExec = (Args.flags & AT_EMPTY_PATH) && strlen(pathname) == 0; const bool SupportsProcFSInterpreter = FEX::HLE::_SyscallHandler->FM.SupportsProcFSInterpreterPath(); fextl::string FDExecEnv; - bool IsShebang{}; + bool IsShebang {}; if (IsFDExec) { Type = ELFLoader::ELFContainer::GetELFType(Args.dirfd); IsShebang = IsShebangFD(Args.dirfd); - } - else - { + } else { // For absolute paths, check the rootfs first (if available) if (pathname[0] == '/') { auto Path = FEX::HLE::_SyscallHandler->FM.GetEmulatedPath(pathname, true); if (!Path.empty() && FHU::Filesystem::Exists(Path)) { Filename = Path; - } - else { + } else { Filename = pathname; } - } - else { + } else { Filename = pathname; } @@ -247,9 +235,7 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env char PidSelfPath[50]; snprintf(PidSelfPath, 50, "/proc/%i/exe", pid); - if (strcmp(pathname, "/proc/self/exe") == 0 || - strcmp(pathname, "/proc/thread-self/exe") == 0 || - strcmp(pathname, PidSelfPath) == 0) { + if (strcmp(pathname, "/proc/self/exe") == 0 || strcmp(pathname, "/proc/thread-self/exe") == 0 || strcmp(pathname, PidSelfPath) == 0) { // If the application is trying to execve `/proc/self/exe` or its variants, // then we need to redirect this path to the true application path. // This is because this path is a symlink to the executing application, which is always `FEXInterpreter` or `FEXLoader`. @@ -275,11 +261,9 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env // Kernel does its own checks for file format support for this // We can only call execve directly if we both have an interpreter installed AND were ran with the interpreter // If the user ran FEX through FEXLoader then we must go down the emulated path - uint64_t Result{}; - if (FEX::HLE::_SyscallHandler->IsInterpreterInstalled() && - FEX::HLE::_SyscallHandler->IsInterpreter() && - (Type == ELFLoader::ELFContainer::ELFType::TYPE_X86_32 || - Type == ELFLoader::ELFContainer::ELFType::TYPE_X86_64)) { + uint64_t Result {}; + if (FEX::HLE::_SyscallHandler->IsInterpreterInstalled() && FEX::HLE::_SyscallHandler->IsInterpreter() && + (Type == ELFLoader::ELFContainer::ELFType::TYPE_X86_32 || Type == ELFLoader::ELFContainer::ELFType::TYPE_X86_64)) { // If the FEX interpreter is installed then just execve the ELF file // This will stay inside of our emulated environment since binfmt_misc will capture it Result = ::syscall(SYS_execveat, Args.dirfd, Filename.c_str(), argv, envp, Args.flags); @@ -296,9 +280,9 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env // We don't have an interpreter installed or we are executing a non-ELF executable // We now need to munge the arguments - fextl::vector ExecveArgs{}; - fextl::vector EnvpArgs{}; - char *const *EnvpPtr = envp; + fextl::vector ExecveArgs {}; + fextl::vector EnvpArgs {}; + char* const* EnvpPtr = envp; const char NullString[] = ""; FEX::HLE::_SyscallHandler->GetCodeLoader()->GetExecveArguments(&ExecveArgs); if (!FEX::HLE::_SyscallHandler->IsInterpreter()) { @@ -321,10 +305,9 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env ExecveArgs.emplace_back(*OldArgv); ++OldArgv; } - } - else { + } else { // Linux kernel will stick an empty argument in to the argv list if none are provided. - ExecveArgs.emplace_back(NullString); + ExecveArgs.emplace_back(NullString); } // Emplace nullptr at the end to stop @@ -362,12 +345,11 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env // Emplace nullptr at the end to stop EnvpArgs.emplace_back(nullptr); - EnvpPtr = const_cast(EnvpArgs.data()); + EnvpPtr = const_cast(EnvpArgs.data()); } - const char *InterpreterPath = SupportsProcFSInterpreter ? "/proc/self/interpreter" : "/proc/self/exe"; - Result = ::syscall(SYS_execveat, Args.dirfd, InterpreterPath, - const_cast(ExecveArgs.data()), EnvpPtr, Args.flags); + const char* InterpreterPath = SupportsProcFSInterpreter ? "/proc/self/interpreter" : "/proc/self/exe"; + Result = ::syscall(SYS_execveat, Args.dirfd, InterpreterPath, const_cast(ExecveArgs.data()), EnvpPtr, Args.flags); SYSCALL_ERRNO(); } @@ -381,10 +363,10 @@ static bool AllFlagsSet(uint64_t Flags, uint64_t Mask) { } struct StackFrameData { - FEXCore::Core::InternalThreadState *Thread{}; - FEXCore::Context::Context *CTX{}; - FEXCore::Core::CpuStateFrame NewFrame{}; - FEX::HLE::clone3_args GuestArgs{}; + FEXCore::Core::InternalThreadState* Thread {}; + FEXCore::Context::Context* CTX {}; + FEXCore::Core::CpuStateFrame NewFrame {}; + FEX::HLE::clone3_args GuestArgs {}; }; struct StackFramePlusRet { @@ -394,7 +376,7 @@ struct StackFramePlusRet { }; [[noreturn]] -static void CloneBody(StackFrameData *Data, bool NeedsDataFree) { +static void CloneBody(StackFrameData* Data, bool NeedsDataFree) { uint64_t Result = FEX::HLE::HandleNewClone(Data->Thread, Data->CTX, &Data->NewFrame, &Data->GuestArgs); auto Stack = Data->GuestArgs.NewStack; if (NeedsDataFree) { @@ -407,12 +389,12 @@ static void CloneBody(StackFrameData *Data, bool NeedsDataFree) { [[noreturn]] static void Clone3HandlerRet() { - StackFrameData *Data = (StackFrameData*)alloca(0); + StackFrameData* Data = (StackFrameData*)alloca(0); CloneBody(Data, false); } -static int Clone2HandlerRet(void *arg) { - StackFrameData *Data = (StackFrameData*)arg; +static int Clone2HandlerRet(void* arg) { + StackFrameData* Data = (StackFrameData*)arg; CloneBody(Data, true); } @@ -428,38 +410,39 @@ static int Clone2HandlerRet(void *arg) { #define CLONE_NEWTIME 0x00000080ULL #endif -static void PrintFlags(uint64_t Flags){ -#define FLAGPRINT(x, y) if (Flags & (y)) LogMan::Msg::IFmt("\tFlag: " #x) - FLAGPRINT(CSIGNAL, 0x000000FF); - FLAGPRINT(CLONE_VM, 0x00000100); - FLAGPRINT(CLONE_FS, 0x00000200); - FLAGPRINT(CLONE_FILES, 0x00000400); - FLAGPRINT(CLONE_SIGHAND, 0x00000800); - FLAGPRINT(CLONE_PTRACE, 0x00002000); - FLAGPRINT(CLONE_VFORK, 0x00004000); - FLAGPRINT(CLONE_PARENT, 0x00008000); - FLAGPRINT(CLONE_THREAD, 0x00010000); - FLAGPRINT(CLONE_NEWNS, 0x00020000); - FLAGPRINT(CLONE_SYSVSEM, 0x00040000); - FLAGPRINT(CLONE_SETTLS, 0x00080000); - FLAGPRINT(CLONE_PARENT_SETTID, 0x00100000); +static void PrintFlags(uint64_t Flags) { +#define FLAGPRINT(x, y) \ + if (Flags & (y)) LogMan::Msg::IFmt("\tFlag: " #x) + FLAGPRINT(CSIGNAL, 0x000000FF); + FLAGPRINT(CLONE_VM, 0x00000100); + FLAGPRINT(CLONE_FS, 0x00000200); + FLAGPRINT(CLONE_FILES, 0x00000400); + FLAGPRINT(CLONE_SIGHAND, 0x00000800); + FLAGPRINT(CLONE_PTRACE, 0x00002000); + FLAGPRINT(CLONE_VFORK, 0x00004000); + FLAGPRINT(CLONE_PARENT, 0x00008000); + FLAGPRINT(CLONE_THREAD, 0x00010000); + FLAGPRINT(CLONE_NEWNS, 0x00020000); + FLAGPRINT(CLONE_SYSVSEM, 0x00040000); + FLAGPRINT(CLONE_SETTLS, 0x00080000); + FLAGPRINT(CLONE_PARENT_SETTID, 0x00100000); FLAGPRINT(CLONE_CHILD_CLEARTID, 0x00200000); - FLAGPRINT(CLONE_DETACHED, 0x00400000); - FLAGPRINT(CLONE_UNTRACED, 0x00800000); - FLAGPRINT(CLONE_CHILD_SETTID, 0x01000000); - FLAGPRINT(CLONE_NEWCGROUP, 0x02000000); - FLAGPRINT(CLONE_NEWUTS, 0x04000000); - FLAGPRINT(CLONE_NEWIPC, 0x08000000); - FLAGPRINT(CLONE_NEWUSER, 0x10000000); - FLAGPRINT(CLONE_NEWPID, 0x20000000); - FLAGPRINT(CLONE_NEWNET, 0x40000000); - FLAGPRINT(CLONE_IO, 0x80000000); - FLAGPRINT(CLONE_PIDFD, 0x00001000); + FLAGPRINT(CLONE_DETACHED, 0x00400000); + FLAGPRINT(CLONE_UNTRACED, 0x00800000); + FLAGPRINT(CLONE_CHILD_SETTID, 0x01000000); + FLAGPRINT(CLONE_NEWCGROUP, 0x02000000); + FLAGPRINT(CLONE_NEWUTS, 0x04000000); + FLAGPRINT(CLONE_NEWIPC, 0x08000000); + FLAGPRINT(CLONE_NEWUSER, 0x10000000); + FLAGPRINT(CLONE_NEWPID, 0x20000000); + FLAGPRINT(CLONE_NEWNET, 0x40000000); + FLAGPRINT(CLONE_IO, 0x80000000); + FLAGPRINT(CLONE_PIDFD, 0x00001000); #undef FLAGPRINT }; -static uint64_t Clone2Handler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args) { - StackFrameData *Data = (StackFrameData *)FEXCore::Allocator::malloc(sizeof(StackFrameData)); +static uint64_t Clone2Handler(FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args) { + StackFrameData* Data = (StackFrameData*)FEXCore::Allocator::malloc(sizeof(StackFrameData)); Data->Thread = Frame->Thread; Data->CTX = Frame->Thread->CTX; Data->GuestArgs = *args; @@ -468,43 +451,41 @@ static uint64_t Clone2Handler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clo memcpy(&Data->NewFrame, Frame, sizeof(FEXCore::Core::CpuStateFrame)); // Remove flags that will break us - constexpr uint64_t INVALID_FOR_HOST = - CLONE_SETTLS; + constexpr uint64_t INVALID_FOR_HOST = CLONE_SETTLS; uint64_t Flags = args->args.flags & ~INVALID_FOR_HOST; - uint64_t Result = ::clone( - Clone2HandlerRet, // To be called function - (void*)((uint64_t)args->NewStack + args->StackSize), // Stack - Flags, //Flags - Data, //Argument - (pid_t*)args->args.parent_tid, // parent_tid - 0, // XXX: What is correct for this? tls - (pid_t*)args->args.child_tid); // child_tid + uint64_t Result = ::clone(Clone2HandlerRet, // To be called function + (void*)((uint64_t)args->NewStack + args->StackSize), // Stack + Flags, // Flags + Data, // Argument + (pid_t*)args->args.parent_tid, // parent_tid + 0, // XXX: What is correct for this? tls + (pid_t*)args->args.child_tid); // child_tid // Only parent will get here SYSCALL_ERRNO(); } -static uint64_t Clone3Handler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args) { +static uint64_t Clone3Handler(FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args) { constexpr size_t Offset = sizeof(StackFramePlusRet); - StackFramePlusRet *Data = (StackFramePlusRet*)(reinterpret_cast(args->NewStack) + args->StackSize - Offset); + StackFramePlusRet* Data = (StackFramePlusRet*)(reinterpret_cast(args->NewStack) + args->StackSize - Offset); Data->Ret = (uint64_t)Clone3HandlerRet; Data->Data.Thread = Frame->Thread; Data->Data.CTX = Frame->Thread->CTX; Data->Data.GuestArgs = *args; - FEX::HLE::kernel_clone3_args HostArgs{}; - HostArgs.flags = args->args.flags; - HostArgs.pidfd = args->args.pidfd; - HostArgs.child_tid = args->args.child_tid; - HostArgs.parent_tid = args->args.parent_tid; + FEX::HLE::kernel_clone3_args HostArgs {}; + HostArgs.flags = args->args.flags; + HostArgs.pidfd = args->args.pidfd; + HostArgs.child_tid = args->args.child_tid; + HostArgs.parent_tid = args->args.parent_tid; HostArgs.exit_signal = args->args.exit_signal; // Host stack is always created - HostArgs.stack = reinterpret_cast(args->NewStack); - HostArgs.stack_size = args->StackSize - Offset; // Needs to be 16 byte aligned - HostArgs.tls = 0; // XXX: What is correct for this? - HostArgs.set_tid = args->args.set_tid; - HostArgs.set_tid_size= args->args.set_tid_size; - HostArgs.cgroup = args->args.cgroup; + HostArgs.stack = reinterpret_cast(args->NewStack); + HostArgs.stack_size = args->StackSize - Offset; // Needs to be 16 byte aligned + HostArgs.tls = 0; // XXX: What is correct for this? + HostArgs.set_tid = args->args.set_tid; + HostArgs.set_tid_size = args->args.set_tid_size; + HostArgs.cgroup = args->args.cgroup; // Create a copy of the parent frame memcpy(&Data->Data.NewFrame, Frame, sizeof(FEXCore::Core::CpuStateFrame)); @@ -514,7 +495,7 @@ static uint64_t Clone3Handler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clo SYSCALL_ERRNO(); }; -uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args) { +uint64_t CloneHandler(FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args) { uint64_t flags = args->args.flags; if (flags & CLONE_CLEAR_SIGHAND) { @@ -525,20 +506,11 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args return -EINVAL; } - auto HasUnhandledFlags = [](FEX::HLE::clone3_args *args) -> bool { - constexpr uint64_t UNHANDLED_FLAGS = - CLONE_NEWNS | - // CLONE_UNTRACED | - CLONE_NEWCGROUP | - CLONE_NEWUTS | - CLONE_NEWUTS | - CLONE_NEWIPC | - CLONE_NEWUSER | - CLONE_NEWPID | - CLONE_NEWNET | - CLONE_IO | - CLONE_CLEAR_SIGHAND | - CLONE_INTO_CGROUP; + auto HasUnhandledFlags = [](FEX::HLE::clone3_args* args) -> bool { + constexpr uint64_t UNHANDLED_FLAGS = CLONE_NEWNS | + // CLONE_UNTRACED | + CLONE_NEWCGROUP | CLONE_NEWUTS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWPID | + CLONE_NEWNET | CLONE_IO | CLONE_CLEAR_SIGHAND | CLONE_INTO_CGROUP; if ((args->args.flags & UNHANDLED_FLAGS) != 0) { // Basic unhandled flags @@ -558,12 +530,11 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args } if (AnyFlagsSet(args->args.flags, CLONE_THREAD)) { - if (!AllFlagsSet(args->args.flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) { + if (!AllFlagsSet(args->args.flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) { LogMan::Msg::IFmt("clone: CLONE_THREAD: Unsuported flags w/ CLONE_THREAD (Shared Resources), {:X}", args->args.flags); return false; } - } - else { + } else { if (AnyFlagsSet(args->args.flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM)) { // CLONE_VM is particularly nasty here // Memory regions at the point of clone(More similar to a fork) are shared @@ -596,11 +567,10 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args FEX::HLE::_SyscallHandler->LockBeforeFork(Frame->Thread); - uint64_t Result{}; + uint64_t Result {}; if (args->Type == TYPE_CLONE2) { Result = Clone2Handler(Frame, args); - } - else { + } else { Result = Clone3Handler(Frame, args); } @@ -612,16 +582,14 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->SignalMask, nullptr, sizeof(args->SignalMask)); } return Result; - } - else { + } else { LogMan::Msg::IFmt("Unsupported flag with CLONE_THREAD. This breaks TLS, falling down classic thread path"); PrintFlags(flags); } } constexpr uint64_t TASK_MAX = (1ULL << 48); // 48-bits until we can query the host side VA sanely. AArch64 doesn't expose this in cpuinfo - if (args->args.tls && - args->args.tls >= TASK_MAX) { + if (args->args.tls && args->args.tls >= TASK_MAX) { return -EPERM; } @@ -634,12 +602,9 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args if (!(flags & CLONE_THREAD)) { // CLONE_PARENT is ignored (Implied by CLONE_THREAD) - return FEX::HLE::ForkGuest(Thread, Frame, flags, - reinterpret_cast(args->args.stack), - args->args.stack_size, - reinterpret_cast(args->args.parent_tid), - reinterpret_cast(args->args.child_tid), - reinterpret_cast(args->args.tls)); + return FEX::HLE::ForkGuest(Thread, Frame, flags, reinterpret_cast(args->args.stack), args->args.stack_size, + reinterpret_cast(args->args.parent_tid), reinterpret_cast(args->args.child_tid), + reinterpret_cast(args->args.tls)); } else { auto NewThread = FEX::HLE::CreateNewThread(Thread->CTX, Frame, args); @@ -661,23 +626,21 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args } }; -uint64_t SyscallHandler::HandleBRK(FEXCore::Core::CpuStateFrame *Frame, void *Addr) { +uint64_t SyscallHandler::HandleBRK(FEXCore::Core::CpuStateFrame* Frame, void* Addr) { std::lock_guard lk(MMapMutex); uint64_t Result; if (Addr == nullptr) { // Just wants to get the location of the program break atm Result = DataSpace + DataSpaceSize; - } - else { + } else { // Allocating out data space uint64_t NewEnd = reinterpret_cast(Addr); if (NewEnd < DataSpace) { // Not allowed to move brk end below original start // Set the size to zero DataSpaceSize = 0; - } - else { + } else { uint64_t NewSize = NewEnd - DataSpace; uint64_t NewSizeAligned = FEXCore::AlignUp(NewSize, 4096); @@ -692,18 +655,17 @@ uint64_t SyscallHandler::HandleBRK(FEXCore::Core::CpuStateFrame *Frame, void *Ad LOGMAN_THROW_A_FMT(ok != -1, "Munmap failed"); DataSpaceMaxSize = NewSizeAligned; - } - else if (NewSize > DataSpaceMaxSize) { + } else if (NewSize > DataSpaceMaxSize) { constexpr static uint64_t SizeAlignment = 8 * 1024 * 1024; uint64_t AllocateNewSize = FEXCore::AlignUp(NewSize, SizeAlignment) - DataSpaceMaxSize; - if (!Is64BitMode() && - (DataSpace + DataSpaceMaxSize + AllocateNewSize > 0x1'0000'0000ULL)) { + if (!Is64BitMode() && (DataSpace + DataSpaceMaxSize + AllocateNewSize > 0x1'0000'0000ULL)) { // If we are 32bit and we tried going about the 32bit limit then out of memory return DataSpace + DataSpaceSize; } - uint64_t NewBRK{}; - NewBRK = (uint64_t)GuestMmap(Frame->Thread, (void*)(DataSpace + DataSpaceMaxSize), AllocateNewSize, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + uint64_t NewBRK {}; + NewBRK = (uint64_t)GuestMmap(Frame->Thread, (void*)(DataSpace + DataSpaceMaxSize), AllocateNewSize, PROT_READ | PROT_WRITE, + MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (NewBRK != ~0ULL && NewBRK != (DataSpace + DataSpaceMaxSize)) { @@ -717,8 +679,7 @@ uint64_t SyscallHandler::HandleBRK(FEXCore::Core::CpuStateFrame *Frame, void *Ad if (NewBRK == ~0ULL) { // If we couldn't allocate a new region then out of memory return DataSpace + DataSpaceSize; - } - else { + } else { // Increase our BRK size DataSpaceMaxSize += AllocateNewSize; } @@ -737,7 +698,7 @@ void SyscallHandler::DefaultProgramBreak(uint64_t Base, uint64_t Size) { DataSpaceStartingSize = Size; } -SyscallHandler::SyscallHandler(FEXCore::Context::Context *_CTX, FEX::HLE::SignalDelegator *_SignalDelegation) +SyscallHandler::SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::SignalDelegator* _SignalDelegation) : TM {_CTX, _SignalDelegation} , FM {_CTX} , CTX {_CTX} @@ -755,14 +716,14 @@ SyscallHandler::~SyscallHandler() { } uint32_t SyscallHandler::CalculateHostKernelVersion() { - struct utsname buf{}; + struct utsname buf {}; if (uname(&buf) == -1) { return 0; } - uint32_t Major{}; - uint32_t Minor{}; - uint32_t Patch{}; + uint32_t Major {}; + uint32_t Minor {}; + uint32_t Patch {}; // Parse kernel version in the form of `..[Optional Data]` const auto End = buf.release + sizeof(buf.release); @@ -778,27 +739,32 @@ uint32_t SyscallHandler::CalculateGuestKernelVersion() { return std::max(KernelVersion(5, 0), std::min(KernelVersion(6, 8), GetHostKernelVersion())); } -uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) { +uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args) { if (Args->Argument[0] >= Definitions.size()) { return -ENOSYS; } - auto &Def = Definitions[Args->Argument[0]]; - uint64_t Result{}; + auto& Def = Definitions[Args->Argument[0]]; + uint64_t Result {}; switch (Def.NumArgs) { case 0: Result = std::invoke(Def.Ptr0, Frame); break; case 1: Result = std::invoke(Def.Ptr1, Frame, Args->Argument[1]); break; case 2: Result = std::invoke(Def.Ptr2, Frame, Args->Argument[1], Args->Argument[2]); break; case 3: Result = std::invoke(Def.Ptr3, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3]); break; case 4: Result = std::invoke(Def.Ptr4, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4]); break; - case 5: Result = std::invoke(Def.Ptr5, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5]); break; - case 6: Result = std::invoke(Def.Ptr6, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Args->Argument[6]); break; + case 5: + Result = std::invoke(Def.Ptr5, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5]); + break; + case 6: + Result = std::invoke(Def.Ptr6, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], + Args->Argument[6]); + break; // for missing syscalls case 255: return std::invoke(Def.Ptr1, Frame, Args->Argument[0]); default: LOGMAN_MSG_A_FMT("Unhandled syscall: {}", Args->Argument[0]); return -1; - break; + break; } #ifdef DEBUG_STRACE Strace(Args, Result); @@ -807,40 +773,44 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXC } #ifdef DEBUG_STRACE -void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret) { - auto &Def = Definitions[Args->Argument[0]]; +void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments* Args, uint64_t Ret) { + auto& Def = Definitions[Args->Argument[0]]; switch (Def.NumArgs) { - case 0: LogMan::Msg::D(Def.StraceFmt.c_str(), Ret); break; - case 1: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Ret); break; - case 2: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Ret); break; - case 3: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret); break; - case 4: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Ret); break; - case 5: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Ret); break; - case 6: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Args->Argument[6], Ret); break; - default: break; + case 0: LogMan::Msg::D(Def.StraceFmt.c_str(), Ret); break; + case 1: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Ret); break; + case 2: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Ret); break; + case 3: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret); break; + case 4: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Ret); break; + case 5: + LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Ret); + break; + case 6: + LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], + Args->Argument[6], Ret); + break; + default: break; } } #endif -uint64_t UnimplementedSyscall(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber) { +uint64_t UnimplementedSyscall(FEXCore::Core::CpuStateFrame* Frame, uint64_t SyscallNumber) { ERROR_AND_DIE_FMT("Unhandled system call: {}", SyscallNumber); return -ENOSYS; } -uint64_t UnimplementedSyscallSafe(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber) { +uint64_t UnimplementedSyscallSafe(FEXCore::Core::CpuStateFrame* Frame, uint64_t SyscallNumber) { return -ENOSYS; } -void SyscallHandler::LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) { +void SyscallHandler::LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) { Thread->CTX->LockBeforeFork(Thread); VMATracking.Mutex.lock(); } -void SyscallHandler::UnlockAfterFork(FEXCore::Core::InternalThreadState *LiveThread, bool Child) { +void SyscallHandler::UnlockAfterFork(FEXCore::Core::InternalThreadState* LiveThread, bool Child) { if (Child) { VMATracking.Mutex.StealAndDropActiveLocks(); - } - else { + } else { VMATracking.Mutex.unlock(); } @@ -854,7 +824,8 @@ static bool isHEX(char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); } -fextl::unique_ptr SyscallHandler::GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) { +fextl::unique_ptr +SyscallHandler::GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) { ELFParser GuestELF; @@ -932,7 +903,7 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const rv->SortedLineMappings.resize(len); - for (auto &Mapping: rv->SortedLineMappings) { + for (auto& Mapping : rv->SortedLineMappings) { ::read(FD, (char*)&Mapping.FileGuestBegin, sizeof(Mapping.FileGuestBegin)); ::read(FD, (char*)&Mapping.FileGuestEnd, sizeof(Mapping.FileGuestEnd)); ::read(FD, (char*)&Mapping.LineNumber, sizeof(Mapping.LineNumber)); @@ -946,7 +917,7 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const rv->SortedSymbolMappings.resize(len); - for (auto &Mapping: rv->SortedSymbolMappings) { + for (auto& Mapping : rv->SortedSymbolMappings) { ::read(FD, (char*)&Mapping.FileGuestBegin, sizeof(Mapping.FileGuestBegin)); ::read(FD, (char*)&Mapping.FileGuestEnd, sizeof(Mapping.FileGuestEnd)); @@ -963,8 +934,8 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const close(FD); return rv; } else { - // objdump output parsing, index generation, index file serialization - DoGenerate: +// objdump output parsing, index generation, index file serialization +DoGenerate: LogMan::Msg::DFmt("GenerateMap: Generating index for '{}'", GuestSourceFile); int StreamFD = ::open(GuestSourceFile.c_str(), O_RDONLY | O_CLOEXEC); @@ -995,12 +966,12 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const bool PreviousLineWasEmpty = false; - uintptr_t LastSymbolOffset{}; - uintptr_t CurrentSymbolOffset{}; + uintptr_t LastSymbolOffset {}; + uintptr_t CurrentSymbolOffset {}; fextl::string LastSymbolName; - uintptr_t LastOffset{}; - uintptr_t CurrentOffset{}; + uintptr_t LastOffset {}; + uintptr_t CurrentOffset {}; int LastOffsetLine; auto rv = fextl::make_unique(); @@ -1042,10 +1013,12 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const for (; !isspace(Line[offs]) && offs < Line.size(); offs++) ; - if (offs == Line.size()) + if (offs == Line.size()) { continue; - if (offs != 8 && offs != 16) + } + if (offs != 8 && offs != 16) { continue; + } auto VAOffset = std::strtoul(Line.substr(0, offs).c_str(), nullptr, 16); @@ -1065,8 +1038,9 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const for (; Line[offs] != '<' && offs < Line.size(); offs++) ; - if (offs == Line.size()) + if (offs == Line.size()) { continue; + } offs++; @@ -1078,16 +1052,18 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const for (; isspace(Line[offs]) && offs < Line.size(); offs++) ; - if (offs == Line.size()) + if (offs == Line.size()) { continue; + } int start = offs; for (; Line[offs] != ':' && offs < Line.size(); offs++) ; - if (offs == Line.size()) + if (offs == Line.size()) { continue; + } if (Line[offs + 1] == '\t') { auto VAOffsetStr = Line.substr(start, offs - start); @@ -1121,10 +1097,10 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const // Index post processing - entires are sorted for faster lookups std::sort(rv->SortedLineMappings.begin(), rv->SortedLineMappings.end(), - [](const auto &lhs, const auto &rhs) { return lhs.FileGuestEnd <= rhs.FileGuestBegin; }); + [](const auto& lhs, const auto& rhs) { return lhs.FileGuestEnd <= rhs.FileGuestBegin; }); std::sort(rv->SortedSymbolMappings.begin(), rv->SortedSymbolMappings.end(), - [](const auto &lhs, const auto &rhs) { return lhs.FileGuestEnd <= rhs.FileGuestBegin; }); + [](const auto& lhs, const auto& rhs) { return lhs.FileGuestEnd <= rhs.FileGuestBegin; }); // Index serialization { @@ -1138,7 +1114,7 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const ::write(IndexStream, (const char*)&len, sizeof(len)); - for (const auto &Mapping: rv->SortedLineMappings) { + for (const auto& Mapping : rv->SortedLineMappings) { ::write(IndexStream, (const char*)&Mapping.FileGuestBegin, sizeof(Mapping.FileGuestBegin)); ::write(IndexStream, (const char*)&Mapping.FileGuestEnd, sizeof(Mapping.FileGuestEnd)); ::write(IndexStream, (const char*)&Mapping.LineNumber, sizeof(Mapping.LineNumber)); @@ -1150,7 +1126,7 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const ::write(IndexStream, (char*)&len, sizeof(len)); - for (const auto &Mapping: rv->SortedSymbolMappings) { + for (const auto& Mapping : rv->SortedSymbolMappings) { ::write(IndexStream, (const char*)&Mapping.FileGuestBegin, sizeof(Mapping.FileGuestBegin)); ::write(IndexStream, (const char*)&Mapping.FileGuestEnd, sizeof(Mapping.FileGuestEnd)); @@ -1173,8 +1149,6 @@ fextl::unique_ptr SyscallHandler::GenerateMap(const LogMan::Msg::DFmt("GenerateMap: Finished generating index", GuestIndexFile); return rv; } - - } -} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h index b8f6eff36..52a0ecd8e 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h @@ -40,44 +40,44 @@ $end_info$ #include "LinuxSyscalls/x64/SyscallsEnum.h" -#define CONCAT_(a, b) a ## b +#define CONCAT_(a, b) a##b #define CONCAT(a, b) CONCAT_(a, b) -#define SYSCALL_DEF(name) ( HLE::SYSCALL_ARCH_NAME::CONCAT(CONCAT(SYSCALL_, SYSCALL_ARCH_NAME), _##name)) +#define SYSCALL_DEF(name) (HLE::SYSCALL_ARCH_NAME::CONCAT(CONCAT(SYSCALL_, SYSCALL_ARCH_NAME), _##name)) // #define DEBUG_STRACE namespace FEX { - class CodeLoader; +class CodeLoader; } namespace FEXCore { - namespace Context { - class Context; - } - namespace Core { - struct CpuStateFrame; - } +namespace Context { + class Context; } +namespace Core { + struct CpuStateFrame; +} +} // namespace FEXCore namespace FEX::HLE { class SyscallHandler; class SignalDelegator; - void RegisterEpoll(FEX::HLE::SyscallHandler *Handler); - void RegisterFD(FEX::HLE::SyscallHandler *Handler); - void RegisterFS(FEX::HLE::SyscallHandler *Handler); - void RegisterInfo(FEX::HLE::SyscallHandler *Handler); - void RegisterIO(FEX::HLE::SyscallHandler *Handler); - void RegisterMemory(FEX::HLE::SyscallHandler *Handler); - void RegisterNuma(FEX::HLE::SyscallHandler *Handler); - void RegisterSignals(FEX::HLE::SyscallHandler *Handler); - void RegisterThread(FEX::HLE::SyscallHandler *Handler); - void RegisterTimer(FEX::HLE::SyscallHandler *Handler); - void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler); - void RegisterStubs(FEX::HLE::SyscallHandler *Handler); +void RegisterEpoll(FEX::HLE::SyscallHandler* Handler); +void RegisterFD(FEX::HLE::SyscallHandler* Handler); +void RegisterFS(FEX::HLE::SyscallHandler* Handler); +void RegisterInfo(FEX::HLE::SyscallHandler* Handler); +void RegisterIO(FEX::HLE::SyscallHandler* Handler); +void RegisterMemory(FEX::HLE::SyscallHandler* Handler); +void RegisterNuma(FEX::HLE::SyscallHandler* Handler); +void RegisterSignals(FEX::HLE::SyscallHandler* Handler); +void RegisterThread(FEX::HLE::SyscallHandler* Handler); +void RegisterTimer(FEX::HLE::SyscallHandler* Handler); +void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler); +void RegisterStubs(FEX::HLE::SyscallHandler* Handler); -uint64_t UnimplementedSyscall(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber); -uint64_t UnimplementedSyscallSafe(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber); +uint64_t UnimplementedSyscall(FEXCore::Core::CpuStateFrame* Frame, uint64_t SyscallNumber); +uint64_t UnimplementedSyscallSafe(FEXCore::Core::CpuStateFrame* Frame, uint64_t SyscallNumber); struct ExecveAtArgs { int dirfd; @@ -90,88 +90,90 @@ struct ExecveAtArgs { } }; -uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* envp, ExecveAtArgs Args); +uint64_t ExecveHandler(const char* pathname, char* const* argv, char* const* envp, ExecveAtArgs Args); class ThreadManager final { - public: - ThreadManager(FEXCore::Context::Context *CTX, FEX::HLE::SignalDelegator *SignalDelegation) - : CTX {CTX} - , SignalDelegation {SignalDelegation} {} +public: + ThreadManager(FEXCore::Context::Context* CTX, FEX::HLE::SignalDelegator* SignalDelegation) + : CTX {CTX} + , SignalDelegation {SignalDelegation} {} - ~ThreadManager(); + ~ThreadManager(); - FEXCore::Core::InternalThreadState *CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState *NewThreadState = nullptr, uint64_t ParentTID = 0); - void TrackThread(FEXCore::Core::InternalThreadState *Thread) { - std::lock_guard lk(ThreadCreationMutex); - Threads.emplace_back(Thread); + FEXCore::Core::InternalThreadState* + CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState = nullptr, uint64_t ParentTID = 0); + void TrackThread(FEXCore::Core::InternalThreadState* Thread) { + std::lock_guard lk(ThreadCreationMutex); + Threads.emplace_back(Thread); + } + + void DestroyThread(FEXCore::Core::InternalThreadState* Thread); + void StopThread(FEXCore::Core::InternalThreadState* Thread); + void RunThread(FEXCore::Core::InternalThreadState* Thread); + + void Pause(); + void Run(); + void Step(); + void Stop(bool IgnoreCurrentThread = false); + + void WaitForIdle(); + void WaitForIdleWithTimeout(); + void WaitForThreadsToRun(); + + void SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame); + + void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child); + + void IncrementIdleRefCount() { + ++IdleWaitRefCount; + } + + void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* CallingThread, uint64_t Start, uint64_t Length) { + std::lock_guard lk(ThreadCreationMutex); + + // Potential deferred since Thread might not be valid. + // Thread object isn't valid very early in frontend's initialization. + // To be more optimal the frontend should provide this code with a valid Thread object earlier. + auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), CallingThread); + + for (auto& Thread : Threads) { + CTX->InvalidateGuestCodeRange(Thread, Start, Length); } + } - void DestroyThread(FEXCore::Core::InternalThreadState *Thread); - void StopThread(FEXCore::Core::InternalThreadState *Thread); - void RunThread(FEXCore::Core::InternalThreadState *Thread); + void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* CallingThread, uint64_t Start, uint64_t Length, + FEXCore::Context::CodeRangeInvalidationFn callback) { + std::lock_guard lk(ThreadCreationMutex); - void Pause(); - void Run(); - void Step(); - void Stop(bool IgnoreCurrentThread = false); + // Potential deferred since Thread might not be valid. + // Thread object isn't valid very early in frontend's initialization. + // To be more optimal the frontend should provide this code with a valid Thread object earlier. + auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), CallingThread); - void WaitForIdle(); - void WaitForIdleWithTimeout(); - void WaitForThreadsToRun(); - - void SleepThread(FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame); - - void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child); - - void IncrementIdleRefCount() { - ++IdleWaitRefCount; + for (auto& Thread : Threads) { + CTX->InvalidateGuestCodeRange(Thread, Start, Length, callback); } + } - void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *CallingThread, uint64_t Start, uint64_t Length) { - std::lock_guard lk(ThreadCreationMutex); + const fextl::vector* GetThreads() const { + return &Threads; + } - // Potential deferred since Thread might not be valid. - // Thread object isn't valid very early in frontend's initialization. - // To be more optimal the frontend should provide this code with a valid Thread object earlier. - auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), CallingThread); +private: + FEXCore::Context::Context* CTX; + FEX::HLE::SignalDelegator* SignalDelegation; - for (auto &Thread : Threads) { - CTX->InvalidateGuestCodeRange(Thread, Start, Length); - } - } + FEXCore::ForkableUniqueMutex ThreadCreationMutex; + fextl::vector Threads; - void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState *CallingThread, uint64_t Start, uint64_t Length, FEXCore::Context::CodeRangeInvalidationFn callback) { - std::lock_guard lk(ThreadCreationMutex); + // Thread idling support. + bool Running {}; + std::mutex IdleWaitMutex; + std::condition_variable IdleWaitCV; + std::atomic IdleWaitRefCount {}; - // Potential deferred since Thread might not be valid. - // Thread object isn't valid very early in frontend's initialization. - // To be more optimal the frontend should provide this code with a valid Thread object earlier. - auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), CallingThread); - - for (auto &Thread : Threads) { - CTX->InvalidateGuestCodeRange(Thread, Start, Length, callback); - } - } - - fextl::vector const *GetThreads() const { - return &Threads; - } - - private: - FEXCore::Context::Context *CTX; - FEX::HLE::SignalDelegator *SignalDelegation; - - FEXCore::ForkableUniqueMutex ThreadCreationMutex; - fextl::vector Threads; - - // Thread idling support. - bool Running{}; - std::mutex IdleWaitMutex; - std::condition_variable IdleWaitCV; - std::atomic IdleWaitRefCount{}; - - void HandleThreadDeletion(FEXCore::Core::InternalThreadState *Thread); - void NotifyPause(); + void HandleThreadDeletion(FEXCore::Core::InternalThreadState* Thread); + void NotifyPause(); }; class SyscallHandler : public FEXCore::HLE::SyscallHandler, FEXCore::HLE::SourcecodeResolver, public FEXCore::Allocator::FEXAllocOperators { @@ -180,17 +182,17 @@ public: virtual ~SyscallHandler(); // In the case that the syscall doesn't hit the optimized path then we still need to go here - uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) final override; + uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args) final override; void DefaultProgramBreak(uint64_t Base, uint64_t Size); - using SyscallPtrArg0 = uint64_t(*)(FEXCore::Core::CpuStateFrame *Frame); - using SyscallPtrArg1 = uint64_t(*)(FEXCore::Core::CpuStateFrame *Frame, uint64_t); - using SyscallPtrArg2 = uint64_t(*)(FEXCore::Core::CpuStateFrame *Frame, uint64_t, uint64_t); - using SyscallPtrArg3 = uint64_t(*)(FEXCore::Core::CpuStateFrame *Frame, uint64_t, uint64_t, uint64_t); - using SyscallPtrArg4 = uint64_t(*)(FEXCore::Core::CpuStateFrame *Frame, uint64_t, uint64_t, uint64_t, uint64_t); - using SyscallPtrArg5 = uint64_t(*)(FEXCore::Core::CpuStateFrame *Frame, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); - using SyscallPtrArg6 = uint64_t(*)(FEXCore::Core::CpuStateFrame *Frame, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); + using SyscallPtrArg0 = uint64_t (*)(FEXCore::Core::CpuStateFrame* Frame); + using SyscallPtrArg1 = uint64_t (*)(FEXCore::Core::CpuStateFrame* Frame, uint64_t); + using SyscallPtrArg2 = uint64_t (*)(FEXCore::Core::CpuStateFrame* Frame, uint64_t, uint64_t); + using SyscallPtrArg3 = uint64_t (*)(FEXCore::Core::CpuStateFrame* Frame, uint64_t, uint64_t, uint64_t); + using SyscallPtrArg4 = uint64_t (*)(FEXCore::Core::CpuStateFrame* Frame, uint64_t, uint64_t, uint64_t, uint64_t); + using SyscallPtrArg5 = uint64_t (*)(FEXCore::Core::CpuStateFrame* Frame, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); + using SyscallPtrArg6 = uint64_t (*)(FEXCore::Core::CpuStateFrame* Frame, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); struct SyscallFunctionDefinition { uint8_t NumArgs; @@ -211,44 +213,46 @@ public: #endif }; - SyscallFunctionDefinition const *GetDefinition(uint64_t Syscall) { + const SyscallFunctionDefinition* GetDefinition(uint64_t Syscall) { return &Definitions.at(Syscall); } FEXCore::HLE::SyscallABI GetSyscallABI(uint64_t Syscall) override { - auto &Def = Definitions.at(Syscall); + auto& Def = Definitions.at(Syscall); return {Def.NumArgs, true, Def.HostSyscallNumber}; } - FEXCore::IR::SyscallFlags GetSyscallFlags(uint64_t Syscall) const override { - auto &Def = Definitions.at(Syscall); + FEXCore::IR::SyscallFlags GetSyscallFlags(uint64_t Syscall) const override { + auto& Def = Definitions.at(Syscall); return Def.Flags; } - virtual void RegisterSyscall_32(int SyscallNumber, - int32_t HostSyscallNumber, - FEXCore::IR::SyscallFlags Flags, + virtual void RegisterSyscall_32(int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, #ifdef DEBUG_STRACE - const fextl::string& TraceFormatString, + const fextl::string& TraceFormatString, #endif - void* SyscallHandler, int ArgumentCount) { + void* SyscallHandler, int ArgumentCount) { } - virtual void RegisterSyscall_64(int SyscallNumber, - int32_t HostSyscallNumber, - FEXCore::IR::SyscallFlags Flags, + virtual void RegisterSyscall_64(int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, #ifdef DEBUG_STRACE - const fextl::string& TraceFormatString, + const fextl::string& TraceFormatString, #endif - void* SyscallHandler, int ArgumentCount) { + void* SyscallHandler, int ArgumentCount) { } - uint64_t HandleBRK(FEXCore::Core::CpuStateFrame *Frame, void *Addr); + uint64_t HandleBRK(FEXCore::Core::CpuStateFrame* Frame, void* Addr); FEX::HLE::FileManager FM; - FEX::CodeLoader *GetCodeLoader() const { return LocalLoader; } - void SetCodeLoader(FEX::CodeLoader *Loader) { LocalLoader = Loader; } - FEX::HLE::SignalDelegator *GetSignalDelegator() { return SignalDelegation; } + FEX::CodeLoader* GetCodeLoader() const { + return LocalLoader; + } + void SetCodeLoader(FEX::CodeLoader* Loader) { + LocalLoader = Loader; + } + FEX::HLE::SignalDelegator* GetSignalDelegator() { + return SignalDelegation; + } FEX_CONFIG_OPT(IsInterpreter, IS_INTERPRETER); FEX_CONFIG_OPT(IsInterpreterInstalled, INTERPRETER_INSTALLED); @@ -257,8 +261,12 @@ public: FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); FEX_CONFIG_OPT(SMCChecks, SMCCHECKS); - uint32_t GetHostKernelVersion() const { return HostKernelVersion; } - uint32_t GetGuestKernelVersion() const { return GuestKernelVersion; } + uint32_t GetHostKernelVersion() const { + return HostKernelVersion; + } + uint32_t GetGuestKernelVersion() const { + return GuestKernelVersion; + } bool IsHostKernelVersionAtLeast(uint32_t Major, uint32_t Minor = 0, uint32_t Patch = 0) const { return GetHostKernelVersion() >= KernelVersion(Major, Minor, Patch); @@ -271,82 +279,97 @@ public: return (Major << 24) | (Minor << 16) | Patch; } - static uint32_t KernelMajor(uint32_t Version) { return Version >> 24; } - static uint32_t KernelMinor(uint32_t Version) { return (Version >> 16) & 0xFF; } - static uint32_t KernelPatch(uint32_t Version) { return Version & 0xFFFF; } + static uint32_t KernelMajor(uint32_t Version) { + return Version >> 24; + } + static uint32_t KernelMinor(uint32_t Version) { + return (Version >> 16) & 0xFF; + } + static uint32_t KernelPatch(uint32_t Version) { + return Version & 0xFFFF; + } - FEX::HLE::MemAllocator *Get32BitAllocator() { return Alloc32Handler.get(); } + FEX::HLE::MemAllocator* Get32BitAllocator() { + return Alloc32Handler.get(); + } // does a mmap as if done via a guest syscall - virtual void *GuestMmap(FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset) = 0; + virtual void* GuestMmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length, int prot, int flags, int fd, off_t offset) = 0; // does a guest munmap as if done via a guest syscall - virtual int GuestMunmap(FEXCore::Core::InternalThreadState *Thread, void *addr, uint64_t length) = 0; + virtual int GuestMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, uint64_t length) = 0; ///// Memory Manager tracking ///// - void TrackMmap(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size, int Prot, int Flags, int fd, off_t Offset); - void TrackMunmap(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size); - void TrackMprotect(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size, int Prot); - void TrackMremap(FEXCore::Core::InternalThreadState *Thread, uintptr_t OldAddress, size_t OldSize, size_t NewSize, int flags, uintptr_t NewAddress); - void TrackShmat(FEXCore::Core::InternalThreadState *Thread, int shmid, uintptr_t Base, int shmflg); - void TrackShmdt(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base); - void TrackMadvise(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size, int advice); + void TrackMmap(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size, int Prot, int Flags, int fd, off_t Offset); + void TrackMunmap(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size); + void TrackMprotect(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size, int Prot); + void TrackMremap(FEXCore::Core::InternalThreadState* Thread, uintptr_t OldAddress, size_t OldSize, size_t NewSize, int flags, uintptr_t NewAddress); + void TrackShmat(FEXCore::Core::InternalThreadState* Thread, int shmid, uintptr_t Base, int shmflg); + void TrackShmdt(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base); + void TrackMadvise(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size, int advice); ///// VMA (Virtual Memory Area) tracking ///// - static bool HandleSegfault(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext); - void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) override; + static bool HandleSegfault(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext); + void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) override; // AOTIRCacheEntryLookupResult also includes a shared lock guard, so the pointed AOTIRCacheEntry return can be safely used - FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestAddr) final override; + FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestAddr) final override; ///// FORK tracking ///// - void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread); - void UnlockAfterFork(FEXCore::Core::InternalThreadState *LiveThread, bool Child); + void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread); + void UnlockAfterFork(FEXCore::Core::InternalThreadState* LiveThread, bool Child); - SourcecodeResolver *GetSourcecodeResolver() override { return this; } + SourcecodeResolver* GetSourcecodeResolver() override { + return this; + } - void SleepThread(FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame) override { + void SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame) override { TM.SleepThread(CTX, Frame); } - bool NeedXIDCheck() const { return NeedToCheckXID; } - void DisableXIDCheck() { NeedToCheckXID = false; } + bool NeedXIDCheck() const { + return NeedToCheckXID; + } + void DisableXIDCheck() { + NeedToCheckXID = false; + } constexpr static uint64_t TASK_MAX_64BIT = (1ULL << 48); protected: - SyscallHandler(FEXCore::Context::Context *_CTX, FEX::HLE::SignalDelegator *_SignalDelegation); + SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::SignalDelegator* _SignalDelegation); - fextl::vector Definitions{}; + fextl::vector Definitions {}; std::mutex MMapMutex; // BRK management uint64_t DataSpace {}; uint64_t DataSpaceSize {}; uint64_t DataSpaceMaxSize {}; - uint64_t DataSpaceStartingSize{}; + uint64_t DataSpaceStartingSize {}; // (Major << 24) | (Minor << 16) | Patch - uint32_t HostKernelVersion{}; - uint32_t GuestKernelVersion{}; + uint32_t HostKernelVersion {}; + uint32_t GuestKernelVersion {}; - FEXCore::Context::Context *CTX; + FEXCore::Context::Context* CTX; private: - FEX::HLE::SignalDelegator *SignalDelegation; + FEX::HLE::SignalDelegator* SignalDelegation; std::mutex FutexMutex; std::mutex SyscallMutex; - FEX::CodeLoader *LocalLoader{}; - bool NeedToCheckXID{true}; + FEX::CodeLoader* LocalLoader {}; + bool NeedToCheckXID {true}; - #ifdef DEBUG_STRACE - void Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret); - #endif +#ifdef DEBUG_STRACE + void Strace(FEXCore::HLE::SyscallArguments* Args, uint64_t Ret); +#endif - fextl::unique_ptr Alloc32Handler{}; + fextl::unique_ptr Alloc32Handler {}; - fextl::unique_ptr GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) override; + fextl::unique_ptr + GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) override; ///// VMA (Virtual Memory Area) tracking ///// @@ -374,19 +397,19 @@ private: struct MappedResource { using ContainerType = fextl::map; - FEXCore::IR::AOTIRCacheEntry *AOTIRCacheEntry; - VMAEntry *FirstVMA; + FEXCore::IR::AOTIRCacheEntry* AOTIRCacheEntry; + VMAEntry* FirstVMA; uint64_t Length; // 0 if not fixed size ContainerType::iterator Iterator; }; union VMAProt { struct { - bool Readable: 1; - bool Writable: 1; - bool Executable: 1; + bool Readable : 1; + bool Writable : 1; + bool Executable : 1; }; - uint8_t All: 3; + uint8_t All : 3; static VMAProt fromProt(int Prot); @@ -394,17 +417,17 @@ private: }; struct VMAFlags { - bool Shared: 1; + bool Shared : 1; static VMAFlags fromFlags(int Flags); }; struct VMAEntry { - MappedResource *Resource; + MappedResource* Resource; // these are for Intrusive linked list tracking, starting from Resource->FirstVMA - VMAEntry *ResourcePrevVMA; - VMAEntry *ResourceNextVMA; + VMAEntry* ResourcePrevVMA; + VMAEntry* ResourceNextVMA; uint64_t Base; uint64_t Offset; @@ -430,32 +453,41 @@ private: VMACIterator LookupVMAUnsafe(uint64_t GuestAddr) const; // Mutex must be unique_locked before calling - void SetUnsafe(FEXCore::Context::Context *Ctx, MappedResource *MappedResource, uintptr_t Base, uintptr_t Offset, uintptr_t Length, VMAFlags Flags, VMAProt Prot); + void SetUnsafe(FEXCore::Context::Context* Ctx, MappedResource* MappedResource, uintptr_t Base, uintptr_t Offset, uintptr_t Length, + VMAFlags Flags, VMAProt Prot); // Mutex must be unique_locked before calling - void ClearUnsafe(FEXCore::Context::Context *Ctx, uintptr_t Base, uintptr_t Length, MappedResource *PreservedMappedResource = nullptr); + void ClearUnsafe(FEXCore::Context::Context* Ctx, uintptr_t Base, uintptr_t Length, MappedResource* PreservedMappedResource = nullptr); // Mutex must be unique_locked before calling void ChangeUnsafe(uintptr_t Base, uintptr_t Length, VMAProt Prot); // Mutex must be unique_locked before calling // Returns the Size fo the Shm or 0 if not found - uintptr_t ClearShmUnsafe(FEXCore::Context::Context *Ctx, uintptr_t Base); + uintptr_t ClearShmUnsafe(FEXCore::Context::Context* Ctx, uintptr_t Base); private: - bool ListRemove(VMAEntry *Mapping); - void ListReplace(VMAEntry *Mapping, VMAEntry *NewMapping); - void ListInsertAfter(VMAEntry *Mapping, VMAEntry *NewMapping); - void ListPrepend(MappedResource *Resource, VMAEntry *NewVMA); - static void ListCheckVMALinks(VMAEntry *VMA); + bool ListRemove(VMAEntry* Mapping); + void ListReplace(VMAEntry* Mapping, VMAEntry* NewMapping); + void ListInsertAfter(VMAEntry* Mapping, VMAEntry* NewMapping); + void ListPrepend(MappedResource* Resource, VMAEntry* NewVMA); + static void ListCheckVMALinks(VMAEntry* VMA); } VMATracking; }; -uint64_t HandleSyscall(SyscallHandler *Handler, FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args); +uint64_t HandleSyscall(SyscallHandler* Handler, FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args); -#define SYSCALL_ERRNO() do { if (Result == -1) return -errno; return Result; } while(0) -#define SYSCALL_ERRNO_NULL() do { if (Result == 0) return -errno; return Result; } while(0) +#define SYSCALL_ERRNO() \ + do { \ + if (Result == -1) return -errno; \ + return Result; \ + } while (0) +#define SYSCALL_ERRNO_NULL() \ + do { \ + if (Result == 0) return -errno; \ + return Result; \ + } while (0) -extern FEX::HLE::SyscallHandler *_SyscallHandler; +extern FEX::HLE::SyscallHandler* _SyscallHandler; #ifdef DEBUG_STRACE ////// @@ -465,7 +497,11 @@ extern FEX::HLE::SyscallHandler *_SyscallHandler; template struct ArgToFmtString; -#define ARG_TO_STR(tpy, str) template<> struct FEX::HLE::ArgToFmtString { inline static const char* const Format = str; }; +#define ARG_TO_STR(tpy, str) \ + template<> \ + struct FEX::HLE::ArgToFmtString { \ + inline static const char* const Format = str; \ + }; // Base types ARG_TO_STR(int, "%d") @@ -473,7 +509,7 @@ ARG_TO_STR(unsigned int, "%u") ARG_TO_STR(long, "%ld") ARG_TO_STR(unsigned long, "%lu") -//string types +// string types ARG_TO_STR(char*, "%s") ARG_TO_STR(const char*, "%s") @@ -484,9 +520,9 @@ struct ArgToFmtString { }; // Use ArgToFmtString and variadic template to create a format string from an args list -template +template fextl::string CollectArgsFmtString() { - std::array array = { ArgToFmtString::Format... }; + std::array array = {ArgToFmtString::Format...}; return fextl::fmt::format("{}", fmt::join(array, ", ")); } #else @@ -523,64 +559,88 @@ struct clone3_args { uint64_t SignalMask; uint64_t StackSize; - void *NewStack; + void* NewStack; kernel_clone3_args args; }; -uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args); +uint64_t CloneHandler(FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args); - inline static int RemapFromX86Flags(int flags) { +inline static int RemapFromX86Flags(int flags) { #ifdef _M_X86_64 - // Nothing to change here + // Nothing to change here #elif _M_ARM_64 - constexpr int X86_64_FLAG_O_DIRECT = 040000; - constexpr int X86_64_FLAG_O_LARGEFILE = 0100000; - constexpr int X86_64_FLAG_O_DIRECTORY = 0200000; - constexpr int X86_64_FLAG_O_NOFOLLOW = 0400000; + constexpr int X86_64_FLAG_O_DIRECT = 040000; + constexpr int X86_64_FLAG_O_LARGEFILE = 0100000; + constexpr int X86_64_FLAG_O_DIRECTORY = 0200000; + constexpr int X86_64_FLAG_O_NOFOLLOW = 0400000; - constexpr int AARCH64_FLAG_O_DIRECTORY = 040000; - constexpr int AARCH64_FLAG_O_NOFOLLOW = 0100000; - constexpr int AARCH64_FLAG_O_DIRECT = 0200000; - constexpr int AARCH64_FLAG_O_LARGEFILE = 0400000; + constexpr int AARCH64_FLAG_O_DIRECTORY = 040000; + constexpr int AARCH64_FLAG_O_NOFOLLOW = 0100000; + constexpr int AARCH64_FLAG_O_DIRECT = 0200000; + constexpr int AARCH64_FLAG_O_LARGEFILE = 0400000; - int new_flags{}; - if (flags & X86_64_FLAG_O_DIRECT) { flags = (flags & ~X86_64_FLAG_O_DIRECT); new_flags |= AARCH64_FLAG_O_DIRECT; } - if (flags & X86_64_FLAG_O_LARGEFILE) { flags = (flags & ~X86_64_FLAG_O_LARGEFILE); new_flags |= AARCH64_FLAG_O_LARGEFILE; } - if (flags & X86_64_FLAG_O_DIRECTORY) { flags = (flags & ~X86_64_FLAG_O_DIRECTORY); new_flags |= AARCH64_FLAG_O_DIRECTORY; } - if (flags & X86_64_FLAG_O_NOFOLLOW) { flags = (flags & ~X86_64_FLAG_O_NOFOLLOW); new_flags |= AARCH64_FLAG_O_NOFOLLOW; } - flags |= new_flags; + int new_flags {}; + if (flags & X86_64_FLAG_O_DIRECT) { + flags = (flags & ~X86_64_FLAG_O_DIRECT); + new_flags |= AARCH64_FLAG_O_DIRECT; + } + if (flags & X86_64_FLAG_O_LARGEFILE) { + flags = (flags & ~X86_64_FLAG_O_LARGEFILE); + new_flags |= AARCH64_FLAG_O_LARGEFILE; + } + if (flags & X86_64_FLAG_O_DIRECTORY) { + flags = (flags & ~X86_64_FLAG_O_DIRECTORY); + new_flags |= AARCH64_FLAG_O_DIRECTORY; + } + if (flags & X86_64_FLAG_O_NOFOLLOW) { + flags = (flags & ~X86_64_FLAG_O_NOFOLLOW); + new_flags |= AARCH64_FLAG_O_NOFOLLOW; + } + flags |= new_flags; #else #error Unknown flag remappings for this host platform #endif - return flags; - } + return flags; +} - inline static int RemapToX86Flags(int flags) { +inline static int RemapToX86Flags(int flags) { #ifdef _M_X86_64 - // Nothing to change here + // Nothing to change here #elif _M_ARM_64 - constexpr int X86_64_FLAG_O_DIRECT = 040000; - constexpr int X86_64_FLAG_O_LARGEFILE = 0100000; - constexpr int X86_64_FLAG_O_DIRECTORY = 0200000; - constexpr int X86_64_FLAG_O_NOFOLLOW = 0400000; + constexpr int X86_64_FLAG_O_DIRECT = 040000; + constexpr int X86_64_FLAG_O_LARGEFILE = 0100000; + constexpr int X86_64_FLAG_O_DIRECTORY = 0200000; + constexpr int X86_64_FLAG_O_NOFOLLOW = 0400000; - constexpr int AARCH64_FLAG_O_DIRECTORY = 040000; - constexpr int AARCH64_FLAG_O_NOFOLLOW = 0100000; - constexpr int AARCH64_FLAG_O_DIRECT = 0200000; - constexpr int AARCH64_FLAG_O_LARGEFILE = 0400000; + constexpr int AARCH64_FLAG_O_DIRECTORY = 040000; + constexpr int AARCH64_FLAG_O_NOFOLLOW = 0100000; + constexpr int AARCH64_FLAG_O_DIRECT = 0200000; + constexpr int AARCH64_FLAG_O_LARGEFILE = 0400000; - int new_flags{}; - if (flags & AARCH64_FLAG_O_DIRECT) { flags = (flags & ~AARCH64_FLAG_O_DIRECT); new_flags |= X86_64_FLAG_O_DIRECT; } - if (flags & AARCH64_FLAG_O_LARGEFILE) { flags = (flags & ~AARCH64_FLAG_O_LARGEFILE); new_flags |= X86_64_FLAG_O_LARGEFILE; } - if (flags & AARCH64_FLAG_O_DIRECTORY) { flags = (flags & ~AARCH64_FLAG_O_DIRECTORY); new_flags |= X86_64_FLAG_O_DIRECTORY; } - if (flags & AARCH64_FLAG_O_NOFOLLOW) { flags = (flags & ~AARCH64_FLAG_O_NOFOLLOW); new_flags |= X86_64_FLAG_O_NOFOLLOW; } - flags |= new_flags; + int new_flags {}; + if (flags & AARCH64_FLAG_O_DIRECT) { + flags = (flags & ~AARCH64_FLAG_O_DIRECT); + new_flags |= X86_64_FLAG_O_DIRECT; + } + if (flags & AARCH64_FLAG_O_LARGEFILE) { + flags = (flags & ~AARCH64_FLAG_O_LARGEFILE); + new_flags |= X86_64_FLAG_O_LARGEFILE; + } + if (flags & AARCH64_FLAG_O_DIRECTORY) { + flags = (flags & ~AARCH64_FLAG_O_DIRECTORY); + new_flags |= X86_64_FLAG_O_DIRECTORY; + } + if (flags & AARCH64_FLAG_O_NOFOLLOW) { + flags = (flags & ~AARCH64_FLAG_O_NOFOLLOW); + new_flags |= X86_64_FLAG_O_NOFOLLOW; + } + flags |= new_flags; #else #error Unknown flag remappings for this host platform #endif - return flags; - } + return flags; +} /** * @brief Checks raw syscall return for error @@ -615,28 +675,27 @@ static bool HasSyscallError(const void* Result) { } template -uint64_t GetDentsEmulation(int fd, T *dirp, uint32_t count); +uint64_t GetDentsEmulation(int fd, T* dirp, uint32_t count); namespace FaultSafeMemcpy { -// These are little helper functions for cases when FEX needs to copy data to or from the application in a robust fashion. -// CopyFromUser and CopyToUser are memcpy routines that expect to safely SIGSEGV when reading or writing application memory respectively. -// Returns zero if the memcpy completed, or crashes with SIGABRT and a log message if it faults. -[[nodiscard]] size_t CopyFromUser(void *Dest, const void* Src, size_t Size); -[[nodiscard]] size_t CopyToUser(void *Dest, const void* Src, size_t Size); -bool IsFaultLocation(uint64_t PC); -} + // These are little helper functions for cases when FEX needs to copy data to or from the application in a robust fashion. + // CopyFromUser and CopyToUser are memcpy routines that expect to safely SIGSEGV when reading or writing application memory respectively. + // Returns zero if the memcpy completed, or crashes with SIGABRT and a log message if it faults. + [[nodiscard]] + size_t CopyFromUser(void* Dest, const void* Src, size_t Size); + [[nodiscard]] + size_t CopyToUser(void* Dest, const void* Src, size_t Size); + bool IsFaultLocation(uint64_t PC); +} // namespace FaultSafeMemcpy -} +} // namespace FEX::HLE // Registers syscall for both 32bit and 64bit -#define REGISTER_SYSCALL_IMPL(name, lambda) \ - REGISTER_SYSCALL_IMPL_INTERNAL(name, ~0, FEXCore::IR::SyscallFlags::DEFAULT, lambda) +#define REGISTER_SYSCALL_IMPL(name, lambda) REGISTER_SYSCALL_IMPL_INTERNAL(name, ~0, FEXCore::IR::SyscallFlags::DEFAULT, lambda) -#define REGISTER_SYSCALL_IMPL_FLAGS(name, flags, lambda) \ - REGISTER_SYSCALL_IMPL_INTERNAL(name, ~0, flags, lambda) +#define REGISTER_SYSCALL_IMPL_FLAGS(name, flags, lambda) REGISTER_SYSCALL_IMPL_INTERNAL(name, ~0, flags, lambda) -#define REGISTER_SYSCALL_IMPL_PASS_FLAGS(name, flags, lambda) \ - REGISTER_SYSCALL_IMPL_INTERNAL(name, SYSCALL_DEF(name), flags, lambda) +#define REGISTER_SYSCALL_IMPL_PASS_FLAGS(name, flags, lambda) REGISTER_SYSCALL_IMPL_INTERNAL(name, SYSCALL_DEF(name), flags, lambda) #define REGISTER_SYSCALL_IMPL_INTERNAL(name, number, flags, lambda) \ do { \ diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/EPoll.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/EPoll.cpp index 8c473357f..9a67249f2 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/EPoll.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/EPoll.cpp @@ -16,13 +16,13 @@ $end_info$ #include namespace FEX::HLE { - void RegisterEpoll(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterEpoll(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_FLAGS(epoll_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int size) -> uint64_t { - uint64_t Result = epoll_create(size); - SYSCALL_ERRNO(); - }); - } + REGISTER_SYSCALL_IMPL_FLAGS(epoll_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int size) -> uint64_t { + uint64_t Result = epoll_create(size); + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp index c7a4de538..b78ff322b 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp @@ -29,89 +29,90 @@ $end_info$ #include namespace FEX::HLE { - void RegisterFD(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterFD(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_FLAGS(open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, int flags, uint32_t mode) -> uint64_t { - flags = FEX::HLE::RemapFromX86Flags(flags); - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Open(pathname, flags, mode); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, int flags, uint32_t mode) -> uint64_t { + flags = FEX::HLE::RemapFromX86Flags(flags); + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Open(pathname, flags, mode); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(close, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int fd) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Close(fd); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(close, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int fd) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Close(fd); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(chown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t { - uint64_t Result = ::chown(pathname, owner, group); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(chown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { + uint64_t Result = ::chown(pathname, owner, group); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(lchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t { - uint64_t Result = ::lchown(pathname, owner, group); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(lchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { + uint64_t Result = ::lchown(pathname, owner, group); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(access, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, int mode) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Access(pathname, mode); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(access, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, int mode) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Access(pathname, mode); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(pipe, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int pipefd[2]) -> uint64_t { - uint64_t Result = ::pipe(pipefd); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(pipe, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int pipefd[2]) -> uint64_t { + uint64_t Result = ::pipe(pipefd); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(dup3, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame* Frame, int oldfd, int newfd, int flags) -> uint64_t { - flags = FEX::HLE::RemapFromX86Flags(flags); - uint64_t Result = ::dup3(oldfd, newfd, flags); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(dup3, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int oldfd, int newfd, int flags) -> uint64_t { + flags = FEX::HLE::RemapFromX86Flags(flags); + uint64_t Result = ::dup3(oldfd, newfd, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(inotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - uint64_t Result = ::inotify_init(); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(inotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + uint64_t Result = ::inotify_init(); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(openat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int dirfs, const char *pathname, int flags, uint32_t mode) -> uint64_t { - flags = FEX::HLE::RemapFromX86Flags(flags); - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Openat(dirfs, pathname, flags, mode); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(openat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int dirfs, const char* pathname, int flags, uint32_t mode) -> uint64_t { + flags = FEX::HLE::RemapFromX86Flags(flags); + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Openat(dirfs, pathname, flags, mode); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(readlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, char *buf, size_t bufsiz) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Readlinkat(dirfd, pathname, buf, bufsiz); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(readlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, char* buf, size_t bufsiz) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Readlinkat(dirfd, pathname, buf, bufsiz); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(faccessat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, int mode) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.FAccessat(dirfd, pathname, mode); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(faccessat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, int mode) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.FAccessat(dirfd, pathname, mode); + SYSCALL_ERRNO(); + }); - if (Handler->IsHostKernelVersionAtLeast(5, 8, 0)) { - // Only exists on kernel 5.8+ - REGISTER_SYSCALL_IMPL_FLAGS(faccessat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, int mode, int flags) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.FAccessat2(dirfd, pathname, mode, flags); - SYSCALL_ERRNO(); - }); + if (Handler->IsHostKernelVersionAtLeast(5, 8, 0)) { + // Only exists on kernel 5.8+ + REGISTER_SYSCALL_IMPL_FLAGS(faccessat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, int mode, int flags) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.FAccessat2(dirfd, pathname, mode, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(openat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int dirfs, const char *pathname, struct open_how *how, size_t usize) -> uint64_t { - open_how HostHow{}; + REGISTER_SYSCALL_IMPL_FLAGS( + openat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int dirfs, const char* pathname, struct open_how* how, size_t usize) -> uint64_t { + open_how HostHow {}; size_t HostSize = std::min(sizeof(open_how), usize); memcpy(&HostHow, how, HostSize); @@ -119,41 +120,40 @@ namespace FEX::HLE { uint64_t Result = FEX::HLE::_SyscallHandler->FM.Openat2(dirfs, pathname, &HostHow, HostSize); SYSCALL_ERRNO(); }); - } - else { - REGISTER_SYSCALL_IMPL(faccessat2, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(openat2, UnimplementedSyscallSafe); - } + } else { + REGISTER_SYSCALL_IMPL(faccessat2, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(openat2, UnimplementedSyscallSafe); + } - REGISTER_SYSCALL_IMPL_FLAGS(eventfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, uint32_t count) -> uint64_t { - uint64_t Result = ::syscall(SYSCALL_DEF(eventfd2), count, 0); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(eventfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, uint32_t count) -> uint64_t { + uint64_t Result = ::syscall(SYSCALL_DEF(eventfd2), count, 0); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(pipe2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int pipefd[2], int flags) -> uint64_t { - flags = FEX::HLE::RemapFromX86Flags(flags); - uint64_t Result = ::pipe2(pipefd, flags); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(pipe2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int pipefd[2], int flags) -> uint64_t { + flags = FEX::HLE::RemapFromX86Flags(flags); + uint64_t Result = ::pipe2(pipefd, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(statx, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, int flags, uint32_t mask, struct statx *statxbuf) -> uint64_t { + REGISTER_SYSCALL_IMPL_FLAGS( + statx, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, int flags, uint32_t mask, struct statx* statxbuf) -> uint64_t { // Flags don't need remapped uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statx(dirfd, pathname, flags, mask, statxbuf); SYSCALL_ERRNO(); }); - if (Handler->IsHostKernelVersionAtLeast(5, 9, 0)) { - REGISTER_SYSCALL_IMPL_FLAGS(close_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, unsigned int first, unsigned int last, unsigned int flags) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.CloseRange(first, last, flags); - SYSCALL_ERRNO(); - }); - } - else { - REGISTER_SYSCALL_IMPL(close_range, UnimplementedSyscallSafe); - } + if (Handler->IsHostKernelVersionAtLeast(5, 9, 0)) { + REGISTER_SYSCALL_IMPL_FLAGS(close_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, unsigned int first, unsigned int last, unsigned int flags) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.CloseRange(first, last, flags); + SYSCALL_ERRNO(); + }); + } else { + REGISTER_SYSCALL_IMPL(close_range, UnimplementedSyscallSafe); } } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp index 52683a287..cbbb78d2d 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp @@ -22,115 +22,109 @@ $end_info$ #include namespace FEX::HLE { - void RegisterFS(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterFS(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_FLAGS(rename, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *oldpath, const char *newpath) -> uint64_t { - uint64_t Result = ::rename(oldpath, newpath); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(rename, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* oldpath, const char* newpath) -> uint64_t { + uint64_t Result = ::rename(oldpath, newpath); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(mkdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode) -> uint64_t { - uint64_t Result = ::mkdir(pathname, mode); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(mkdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, mode_t mode) -> uint64_t { + uint64_t Result = ::mkdir(pathname, mode); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(rmdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname) -> uint64_t { - uint64_t Result = ::rmdir(pathname); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(rmdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname) -> uint64_t { + uint64_t Result = ::rmdir(pathname); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(link, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *oldpath, const char *newpath) -> uint64_t { - uint64_t Result = ::link(oldpath, newpath); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(link, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* oldpath, const char* newpath) -> uint64_t { + uint64_t Result = ::link(oldpath, newpath); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname) -> uint64_t { - uint64_t Result = ::unlink(pathname); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname) -> uint64_t { + uint64_t Result = ::unlink(pathname); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(symlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *target, const char *linkpath) -> uint64_t { - uint64_t Result = ::symlink(target, linkpath); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(symlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* target, const char* linkpath) -> uint64_t { + uint64_t Result = ::symlink(target, linkpath); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(readlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, char *buf, size_t bufsiz) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Readlink(pathname, buf, bufsiz); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(readlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, char* buf, size_t bufsiz) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Readlink(pathname, buf, bufsiz); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(chmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode) -> uint64_t { - uint64_t Result = ::chmod(pathname, mode); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(chmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, mode_t mode) -> uint64_t { + uint64_t Result = ::chmod(pathname, mode); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(mknod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode, dev_t dev) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Mknod(pathname, mode, dev); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(mknod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, mode_t mode, dev_t dev) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Mknod(pathname, mode, dev); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(creat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode) -> uint64_t { - uint64_t Result = ::creat(pathname, mode); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(creat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, mode_t mode) -> uint64_t { + uint64_t Result = ::creat(pathname, mode); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL(setxattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name, const void *value, size_t size, int flags) -> uint64_t { + REGISTER_SYSCALL_IMPL( + setxattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, const char* name, const void* value, size_t size, int flags) -> uint64_t { uint64_t Result = FEX::HLE::_SyscallHandler->FM.Setxattr(path, name, value, size, flags); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL(lsetxattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name, const void *value, size_t size, int flags) -> uint64_t { + REGISTER_SYSCALL_IMPL( + lsetxattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, const char* name, const void* value, size_t size, int flags) -> uint64_t { uint64_t Result = FEX::HLE::_SyscallHandler->FM.LSetxattr(path, name, value, size, flags); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL(getxattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name, void *value, size_t size) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Getxattr(path, name, value, size); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL(getxattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, const char* name, void* value, size_t size) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Getxattr(path, name, value, size); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL(lgetxattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name, void *value, size_t size) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.LGetxattr(path, name, value, size); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL(lgetxattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, const char* name, void* value, size_t size) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.LGetxattr(path, name, value, size); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL(listxattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, char *list, size_t size) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Listxattr(path, list, size); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL(listxattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, char* list, size_t size) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Listxattr(path, list, size); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL(llistxattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, char *list, size_t size) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.LListxattr(path, list, size); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL(llistxattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, char* list, size_t size) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.LListxattr(path, list, size); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL(removexattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Removexattr(path, name); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL(removexattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, const char* name) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Removexattr(path, name); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL(lremovexattr, - [](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.LRemovexattr(path, name); - SYSCALL_ERRNO(); - }); - } + REGISTER_SYSCALL_IMPL(lremovexattr, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, const char* name) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.LRemovexattr(path, name); + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/IO.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/IO.cpp index 3a304f1af..58a9135ca 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/IO.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/IO.cpp @@ -16,19 +16,19 @@ $end_info$ #include namespace FEX::HLE { - void RegisterIO(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterIO(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_FLAGS(iopl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int level) -> uint64_t { - // Just claim we don't have permission - return -EPERM; - }); + REGISTER_SYSCALL_IMPL_FLAGS(iopl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int level) -> uint64_t { + // Just claim we don't have permission + return -EPERM; + }); - REGISTER_SYSCALL_IMPL_FLAGS(ioperm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, unsigned long from, unsigned long num, int turn_on) -> uint64_t { - // ioperm not available on our architecture - return -EPERM; - }); - } + REGISTER_SYSCALL_IMPL_FLAGS(ioperm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, unsigned long from, unsigned long num, int turn_on) -> uint64_t { + // ioperm not available on our architecture + return -EPERM; + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp index e91ea6bf0..d65bcefff 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp @@ -29,31 +29,28 @@ $end_info$ #include namespace FEX::HLE { - using cap_user_header_t = void*; - using cap_user_data_t = void*; +using cap_user_header_t = void*; +using cap_user_data_t = void*; - void RegisterInfo(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_FLAGS(uname, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, struct utsname *buf) -> uint64_t { - struct utsname Local{}; + REGISTER_SYSCALL_IMPL_FLAGS( + uname, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, [](FEXCore::Core::CpuStateFrame* Frame, struct utsname* buf) -> uint64_t { + struct utsname Local {}; if (::uname(&Local) == 0) { memcpy(buf->nodename, Local.nodename, sizeof(Local.nodename)); static_assert(sizeof(Local.nodename) <= sizeof(buf->nodename)); memcpy(buf->domainname, Local.domainname, sizeof(Local.domainname)); static_assert(sizeof(Local.domainname) <= sizeof(buf->domainname)); - } - else { + } else { strcpy(buf->nodename, "FEXCore"); LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); } strcpy(buf->sysname, "Linux"); uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - snprintf(buf->release, sizeof(buf->release), "%d.%d.%d", - FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), - FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + snprintf(buf->release, sizeof(buf->release), "%d.%d.%d", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), + FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; strcpy(buf->version, version); @@ -63,10 +60,10 @@ namespace FEX::HLE { return 0; }); - REGISTER_SYSCALL_IMPL_FLAGS(seccomp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, unsigned int operation, unsigned int flags, void *args) -> uint64_t { - // FEX doesn't support seccomp - return -EINVAL; - }); - } + REGISTER_SYSCALL_IMPL_FLAGS(seccomp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, unsigned int operation, unsigned int flags, void* args) -> uint64_t { + // FEX doesn't support seccomp + return -EINVAL; + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Memory.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Memory.cpp index 35e868ffa..91e48c300 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Memory.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Memory.cpp @@ -19,23 +19,23 @@ $end_info$ #include namespace FEX::HLE { - void RegisterMemory(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterMemory(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_FLAGS(brk, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, void *addr) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->HandleBRK(Frame, addr); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(brk, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, void* addr) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->HandleBRK(Frame, addr); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(madvise, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length, int32_t advice) -> uint64_t { - uint64_t Result = ::madvise(addr, length, advice); + REGISTER_SYSCALL_IMPL_FLAGS(madvise, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, void* addr, size_t length, int32_t advice) -> uint64_t { + uint64_t Result = ::madvise(addr, length, advice); - if (Result != -1) { - FEX::HLE::_SyscallHandler->TrackMadvise(Frame->Thread, (uintptr_t)addr, length, advice); - } - SYSCALL_ERRNO(); - }); - } + if (Result != -1) { + FEX::HLE::_SyscallHandler->TrackMadvise(Frame->Thread, (uintptr_t)addr, length, advice); + } + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/NotImplemented.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/NotImplemented.cpp index a808ed4e7..1fe8f1877 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/NotImplemented.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/NotImplemented.cpp @@ -13,47 +13,45 @@ $end_info$ #include #include -#define REGISTER_SYSCALL_NOT_IMPL(name) REGISTER_SYSCALL_IMPL(name, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { \ - LogMan::Msg::DFmt("Using deprecated/removed syscall: " #name); \ - return -ENOSYS; \ -}); +#define REGISTER_SYSCALL_NOT_IMPL(name) \ + REGISTER_SYSCALL_IMPL(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { \ + LogMan::Msg::DFmt("Using deprecated/removed syscall: " #name); \ + return -ENOSYS; \ + }); -#define REGISTER_SYSCALL_NO_PERM(name) REGISTER_SYSCALL_IMPL(name, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { \ - return -EPERM; \ -}); +#define REGISTER_SYSCALL_NO_PERM(name) REGISTER_SYSCALL_IMPL(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -EPERM; }); -#define REGISTER_SYSCALL_NO_ACCESS(name) REGISTER_SYSCALL_IMPL(name, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { \ - return -EACCES; \ -}); +#define REGISTER_SYSCALL_NO_ACCESS(name) \ + REGISTER_SYSCALL_IMPL(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -EACCES; }); namespace FEX::HLE { - // these are removed/not implemented in the linux kernel we present +// these are removed/not implemented in the linux kernel we present - void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_NOT_IMPL(ustat); - REGISTER_SYSCALL_NOT_IMPL(sysfs); - REGISTER_SYSCALL_NOT_IMPL(uselib); - REGISTER_SYSCALL_NOT_IMPL(create_module); - REGISTER_SYSCALL_NOT_IMPL(get_kernel_syms); - REGISTER_SYSCALL_NOT_IMPL(query_module); - REGISTER_SYSCALL_NOT_IMPL(nfsservctl); // Was removed in Linux 3.1 - REGISTER_SYSCALL_NOT_IMPL(getpmsg); - REGISTER_SYSCALL_NOT_IMPL(putpmsg); - REGISTER_SYSCALL_NOT_IMPL(afs_syscall); - REGISTER_SYSCALL_NOT_IMPL(vserver); - REGISTER_SYSCALL_NOT_IMPL(_sysctl); // Was removed in Linux 5.5 +void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_NOT_IMPL(ustat); + REGISTER_SYSCALL_NOT_IMPL(sysfs); + REGISTER_SYSCALL_NOT_IMPL(uselib); + REGISTER_SYSCALL_NOT_IMPL(create_module); + REGISTER_SYSCALL_NOT_IMPL(get_kernel_syms); + REGISTER_SYSCALL_NOT_IMPL(query_module); + REGISTER_SYSCALL_NOT_IMPL(nfsservctl); // Was removed in Linux 3.1 + REGISTER_SYSCALL_NOT_IMPL(getpmsg); + REGISTER_SYSCALL_NOT_IMPL(putpmsg); + REGISTER_SYSCALL_NOT_IMPL(afs_syscall); + REGISTER_SYSCALL_NOT_IMPL(vserver); + REGISTER_SYSCALL_NOT_IMPL(_sysctl); // Was removed in Linux 5.5 - REGISTER_SYSCALL_NO_PERM(vhangup); - REGISTER_SYSCALL_NO_PERM(reboot) - REGISTER_SYSCALL_NO_PERM(sethostname); - REGISTER_SYSCALL_NO_PERM(setdomainname); - REGISTER_SYSCALL_NO_PERM(kexec_load); - REGISTER_SYSCALL_NO_PERM(finit_module); - REGISTER_SYSCALL_NO_PERM(bpf); - REGISTER_SYSCALL_NO_PERM(lookup_dcookie); - REGISTER_SYSCALL_NO_PERM(init_module) - REGISTER_SYSCALL_NO_PERM(delete_module); - REGISTER_SYSCALL_NO_PERM(quotactl); - REGISTER_SYSCALL_NO_ACCESS(perf_event_open); - } + REGISTER_SYSCALL_NO_PERM(vhangup); + REGISTER_SYSCALL_NO_PERM(reboot) + REGISTER_SYSCALL_NO_PERM(sethostname); + REGISTER_SYSCALL_NO_PERM(setdomainname); + REGISTER_SYSCALL_NO_PERM(kexec_load); + REGISTER_SYSCALL_NO_PERM(finit_module); + REGISTER_SYSCALL_NO_PERM(bpf); + REGISTER_SYSCALL_NO_PERM(lookup_dcookie); + REGISTER_SYSCALL_NO_PERM(init_module) + REGISTER_SYSCALL_NO_PERM(delete_module); + REGISTER_SYSCALL_NO_PERM(quotactl); + REGISTER_SYSCALL_NO_ACCESS(perf_event_open); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Passthrough.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Passthrough.cpp index 243b9050a..742b6dd61 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Passthrough.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Passthrough.cpp @@ -19,900 +19,853 @@ namespace FEX::HLE { #ifdef _M_ARM_64 template requires (syscall_num != -1) -uint64_t SyscallPassthrough0(FEXCore::Core::CpuStateFrame *Frame) { - register uint64_t x0 asm ("x0"); - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough0(FEXCore::Core::CpuStateFrame* Frame) { + register uint64_t x0 asm("x0"); + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - : "memory"); + : "=r"(x0) + : "r"(x8) + : "memory"); return x0; } template requires (syscall_num != -1) -uint64_t SyscallPassthrough1(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1) { - register uint64_t x0 asm ("x0") = arg1; - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough1(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1) { + register uint64_t x0 asm("x0") = arg1; + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - , "r" (x0) - : "memory"); + : "=r"(x0) + : "r"(x8), "r"(x0) + : "memory"); return x0; } template requires (syscall_num != -1) -uint64_t SyscallPassthrough2(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2) { - register uint64_t x0 asm ("x0") = arg1; - register uint64_t x1 asm ("x1") = arg2; - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough2(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2) { + register uint64_t x0 asm("x0") = arg1; + register uint64_t x1 asm("x1") = arg2; + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - , "r" (x0) - , "r" (x1) - : "memory"); + : "=r"(x0) + : "r"(x8), "r"(x0), "r"(x1) + : "memory"); return x0; } template requires (syscall_num != -1) -uint64_t SyscallPassthrough3(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3) { - register uint64_t x0 asm ("x0") = arg1; - register uint64_t x1 asm ("x1") = arg2; - register uint64_t x2 asm ("x2") = arg3; - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough3(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3) { + register uint64_t x0 asm("x0") = arg1; + register uint64_t x1 asm("x1") = arg2; + register uint64_t x2 asm("x2") = arg3; + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - , "r" (x0) - , "r" (x1) - , "r" (x2) - : "memory"); + : "=r"(x0) + : "r"(x8), "r"(x0), "r"(x1), "r"(x2) + : "memory"); return x0; } template requires (syscall_num != -1) -uint64_t SyscallPassthrough4(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { - register uint64_t x0 asm ("x0") = arg1; - register uint64_t x1 asm ("x1") = arg2; - register uint64_t x2 asm ("x2") = arg3; - register uint64_t x3 asm ("x3") = arg4; - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough4(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { + register uint64_t x0 asm("x0") = arg1; + register uint64_t x1 asm("x1") = arg2; + register uint64_t x2 asm("x2") = arg3; + register uint64_t x3 asm("x3") = arg4; + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - , "r" (x0) - , "r" (x1) - , "r" (x2) - , "r" (x3) - : "memory"); + : "=r"(x0) + : "r"(x8), "r"(x0), "r"(x1), "r"(x2), "r"(x3) + : "memory"); return x0; } template requires (syscall_num != -1) -uint64_t SyscallPassthrough5(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { - register uint64_t x0 asm ("x0") = arg1; - register uint64_t x1 asm ("x1") = arg2; - register uint64_t x2 asm ("x2") = arg3; - register uint64_t x3 asm ("x3") = arg4; - register uint64_t x4 asm ("x4") = arg5; - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough5(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { + register uint64_t x0 asm("x0") = arg1; + register uint64_t x1 asm("x1") = arg2; + register uint64_t x2 asm("x2") = arg3; + register uint64_t x3 asm("x3") = arg4; + register uint64_t x4 asm("x4") = arg5; + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - , "r" (x0) - , "r" (x1) - , "r" (x2) - , "r" (x3) - , "r" (x4) - : "memory"); + : "=r"(x0) + : "r"(x8), "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4) + : "memory"); return x0; } template requires (syscall_num != -1) -uint64_t SyscallPassthrough6(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) { - register uint64_t x0 asm ("x0") = arg1; - register uint64_t x1 asm ("x1") = arg2; - register uint64_t x2 asm ("x2") = arg3; - register uint64_t x3 asm ("x3") = arg4; - register uint64_t x4 asm ("x4") = arg5; - register uint64_t x5 asm ("x5") = arg6; - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough6(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, + uint64_t arg6) { + register uint64_t x0 asm("x0") = arg1; + register uint64_t x1 asm("x1") = arg2; + register uint64_t x2 asm("x2") = arg3; + register uint64_t x3 asm("x3") = arg4; + register uint64_t x4 asm("x4") = arg5; + register uint64_t x5 asm("x5") = arg6; + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - , "r" (x0) - , "r" (x1) - , "r" (x2) - , "r" (x3) - , "r" (x4) - , "r" (x5) - : "memory"); + : "=r"(x0) + : "r"(x8), "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) + : "memory"); return x0; } template requires (syscall_num != -1) -uint64_t SyscallPassthrough7(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { - register uint64_t x0 asm ("x0") = arg1; - register uint64_t x1 asm ("x1") = arg2; - register uint64_t x2 asm ("x2") = arg3; - register uint64_t x3 asm ("x3") = arg4; - register uint64_t x4 asm ("x4") = arg5; - register uint64_t x5 asm ("x5") = arg6; - register uint64_t x6 asm ("x6") = arg7; - register int x8 asm ("x8") = syscall_num; +uint64_t SyscallPassthrough7(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, + uint64_t arg6, uint64_t arg7) { + register uint64_t x0 asm("x0") = arg1; + register uint64_t x1 asm("x1") = arg2; + register uint64_t x2 asm("x2") = arg3; + register uint64_t x3 asm("x3") = arg4; + register uint64_t x4 asm("x4") = arg5; + register uint64_t x5 asm("x5") = arg6; + register uint64_t x6 asm("x6") = arg7; + register int x8 asm("x8") = syscall_num; __asm volatile(R"( svc #0; )" - : "=r" (x0) - : "r" (x8) - , "r" (x0) - , "r" (x1) - , "r" (x2) - , "r" (x3) - , "r" (x4) - , "r" (x5) - , "r" (x6) - : "memory"); + : "=r"(x0) + : "r"(x8), "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5), "r"(x6) + : "memory"); return x0; } #else template requires (syscall_num != -1) -uint64_t SyscallPassthrough0(FEXCore::Core::CpuStateFrame *Frame) { +uint64_t SyscallPassthrough0(FEXCore::Core::CpuStateFrame* Frame) { uint64_t Result = ::syscall(syscall_num); SYSCALL_ERRNO(); } template requires (syscall_num != -1) -uint64_t SyscallPassthrough1(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1) { +uint64_t SyscallPassthrough1(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1) { uint64_t Result = ::syscall(syscall_num, arg1); SYSCALL_ERRNO(); } template requires (syscall_num != -1) -uint64_t SyscallPassthrough2(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2) { +uint64_t SyscallPassthrough2(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2) { uint64_t Result = ::syscall(syscall_num, arg1, arg2); SYSCALL_ERRNO(); } template requires (syscall_num != -1) -uint64_t SyscallPassthrough3(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3) { +uint64_t SyscallPassthrough3(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3) { uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3); SYSCALL_ERRNO(); } template requires (syscall_num != -1) -uint64_t SyscallPassthrough4(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { +uint64_t SyscallPassthrough4(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4); SYSCALL_ERRNO(); } template requires (syscall_num != -1) -uint64_t SyscallPassthrough5(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { +uint64_t SyscallPassthrough5(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4, arg5); SYSCALL_ERRNO(); } template requires (syscall_num != -1) -uint64_t SyscallPassthrough6(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) { +uint64_t SyscallPassthrough6(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, + uint64_t arg6) { uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4, arg5, arg6); SYSCALL_ERRNO(); } template requires (syscall_num != -1) -uint64_t SyscallPassthrough7(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { +uint64_t SyscallPassthrough7(FEXCore::Core::CpuStateFrame* Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, + uint64_t arg6, uint64_t arg7) { uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7); SYSCALL_ERRNO(); } #endif - void RegisterCommon(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_PASS_FLAGS(read, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(write, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(lseek, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_yield, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(msync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mincore, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(shmget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(shmctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(socket, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(connect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sendto, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(recvfrom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(shutdown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(bind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(listen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsockname, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpeername, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(socketpair, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(kill, SyscallFlags::DEFAULT, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(semget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgsnd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgrcv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(flock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fdatasync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(truncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(ftruncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getcwd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(chdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(umask, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(syslog, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(geteuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getegid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getppid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setreuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setregid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(capget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(capset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(personality, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_max, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_min, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(munlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(pivot_root, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(chroot, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(acct, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(umount2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapon, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapoff, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(gettid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fgetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(flistxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fremovexattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(tkill, SyscallFlags::DEFAULT, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_destroy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_submit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_cancel, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(remap_file_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fadvise64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_getoverrun, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_delete, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(tgkill, SyscallFlags::DEFAULT, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mbind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(get_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mq_unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(add_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(request_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(keyctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_set, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_get, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_add_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_rm_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(migrate_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mkdirat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mknodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchownat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(unlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(linkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(symlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(unshare, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(splice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(tee, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(timerfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(accept4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(eventfd2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(epoll_create1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_init1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_mark, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(prlimit_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(name_to_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_by_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(syncfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(setns, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getcpu, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(kcmp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(getrandom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(membarrier, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(copy_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_mprotect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_alloc, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_free, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_enter, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_register, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_tree, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsopen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsconfig, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(fspick, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - } - else { - REGISTER_SYSCALL_IMPL(io_uring_setup, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(io_uring_enter, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(io_uring_register, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(open_tree, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(move_mount, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(fsopen, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(fsconfig, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(fsmount, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(fspick, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 3, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - } - else { - REGISTER_SYSCALL_IMPL(pidfd_open, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 8, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_getfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - } - else { - REGISTER_SYSCALL_IMPL(pidfd_getfd, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 12, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - } - else { - REGISTER_SYSCALL_IMPL(mount_setattr, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(quotactl_fd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - } - else { - REGISTER_SYSCALL_IMPL(quotactl_fd, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_create_ruleset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - } - else { - REGISTER_SYSCALL_IMPL(landlock_create_ruleset, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_add_rule, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - } - else { - REGISTER_SYSCALL_IMPL(landlock_add_rule, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_restrict_self, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - } - else { - REGISTER_SYSCALL_IMPL(landlock_restrict_self, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_secret, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - } - else { - REGISTER_SYSCALL_IMPL(memfd_secret, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 15, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(process_mrelease, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - } - else { - REGISTER_SYSCALL_IMPL(process_mrelease, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 16, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_waitv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - } - else { - REGISTER_SYSCALL_IMPL(futex_waitv, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 17, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy_home_node, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - } - else { - REGISTER_SYSCALL_IMPL(set_mempolicy_home_node, UnimplementedSyscallSafe); - } - - if (Handler->IsHostKernelVersionAtLeast(6, 8, 0)) { - REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_wake, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_wait, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_requeue, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(statmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(listmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(lsm_get_self_attr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(lsm_set_self_attr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_PASS_FLAGS(lsm_list_modules, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - } - else { - REGISTER_SYSCALL_IMPL(futex_wake, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(futex_wait, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(futex_requeue, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(statmount, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(listmount, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(lsm_get_self_attr, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(lsm_set_self_attr, UnimplementedSyscallSafe); - REGISTER_SYSCALL_IMPL(lsm_list_modules, UnimplementedSyscallSafe); - } +void RegisterCommon(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; + REGISTER_SYSCALL_IMPL_PASS_FLAGS(read, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(write, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(lseek, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_yield, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(msync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mincore, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(shmget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(shmctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(socket, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(connect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sendto, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(recvfrom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(shutdown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(bind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(listen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsockname, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpeername, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(socketpair, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(kill, SyscallFlags::DEFAULT, SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(semget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgsnd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgrcv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(flock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fdatasync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(truncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(ftruncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getcwd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(chdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(umask, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(syslog, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(geteuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getegid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getppid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setreuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setregid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(capget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(capset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(personality, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_max, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_min, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(munlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(pivot_root, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(chroot, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(acct, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(umount2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapon, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapoff, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(gettid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fgetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(flistxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fremovexattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(tkill, SyscallFlags::DEFAULT, SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_destroy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_submit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_cancel, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(remap_file_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fadvise64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_getoverrun, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_delete, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(tgkill, SyscallFlags::DEFAULT, SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mbind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(get_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mq_unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(add_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(request_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(keyctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_set, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_get, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_add_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_rm_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(migrate_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mkdirat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mknodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchownat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(unlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(linkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(symlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(unshare, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(splice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(tee, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(timerfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(accept4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(eventfd2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(epoll_create1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_init1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_mark, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(prlimit_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(name_to_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_by_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(syncfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(setns, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getcpu, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(kcmp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(getrandom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(membarrier, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(copy_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_mprotect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_alloc, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_free, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_enter, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_register, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_tree, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsopen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsconfig, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(fspick, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + } else { + REGISTER_SYSCALL_IMPL(io_uring_setup, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(io_uring_enter, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(io_uring_register, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(open_tree, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(move_mount, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(fsopen, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(fsconfig, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(fsmount, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(fspick, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 3, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + } else { + REGISTER_SYSCALL_IMPL(pidfd_open, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 8, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_getfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + } else { + REGISTER_SYSCALL_IMPL(pidfd_getfd, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 12, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + } else { + REGISTER_SYSCALL_IMPL(mount_setattr, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(quotactl_fd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + } else { + REGISTER_SYSCALL_IMPL(quotactl_fd, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_create_ruleset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + } else { + REGISTER_SYSCALL_IMPL(landlock_create_ruleset, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_add_rule, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + } else { + REGISTER_SYSCALL_IMPL(landlock_add_rule, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_restrict_self, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + } else { + REGISTER_SYSCALL_IMPL(landlock_restrict_self, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_secret, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + } else { + REGISTER_SYSCALL_IMPL(memfd_secret, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 15, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(process_mrelease, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + } else { + REGISTER_SYSCALL_IMPL(process_mrelease, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 16, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_waitv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + } else { + REGISTER_SYSCALL_IMPL(futex_waitv, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 17, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy_home_node, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + } else { + REGISTER_SYSCALL_IMPL(set_mempolicy_home_node, UnimplementedSyscallSafe); } - namespace x64 { - void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; - RegisterCommon(Handler); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(ioctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pread_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwrite_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(readv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(writev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(dup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getitimer, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setitimer, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendfile, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(accept, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(recvmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setsockopt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getsockopt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(wait4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(semop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(gettimeofday, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getrlimit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getrusage, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sysinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(times, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(rt_sigqueueinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fstatfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sched_rr_get_interval, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(munlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(adjtimex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setrlimit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(settimeofday, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(readahead, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(futex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(io_getevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getdents64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(semtimedop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_getres, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_timedsend, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_timedreceive, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_notify, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_getsetattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(waitid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pselect6, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(ppoll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(set_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(get_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sync_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(vmsplice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(utimensat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fallocate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timerfd_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timerfd_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(preadv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwritev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(rt_tgsigqueueinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(recvmmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_adjtime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendmmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_vm_readv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_vm_writev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(preadv2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwritev2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(io_pgetevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) { - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pidfd_send_signal, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - } - else { - REGISTER_SYSCALL_IMPL_X64(pidfd_send_signal, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(5, 10, 0)) { - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_madvise, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - } - else { - REGISTER_SYSCALL_IMPL_X64(process_madvise, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(6, 5, 0)) { - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(cachestat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - } - else { - REGISTER_SYSCALL_IMPL_X64(cachestat, UnimplementedSyscallSafe); - } - if (Handler->IsHostKernelVersionAtLeast(6, 6, 0)) { - REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fchmodat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - } - else { - REGISTER_SYSCALL_IMPL_X64(fchmodat2, UnimplementedSyscallSafe); - } - } - } - - namespace x32 { - void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; - RegisterCommon(Handler); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getuid32, getuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getgid32, getgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(geteuid32, geteuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getegid32, getegid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough0); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setreuid32, setreuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setregid32, setregid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getgroups32, getgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setgroups32, setgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(fchown32, fchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setresuid32, setresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getresuid32, getresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setresgid32, setresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getresgid32, getresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough3); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setuid32, setuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setgid32, setgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setfsuid32, setfsuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setfsgid32, setfsgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough1); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(sendfile64, sendfile, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_gettime64, clock_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_settime64, clock_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_adjtime64, clock_adjtime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_getres_time64, clock_getres, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_nanosleep_time64, clock_nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timer_gettime64, timer_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timer_settime64, timer_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timerfd_gettime64, timerfd_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timerfd_settime64, timerfd_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(utimensat_time64, utimensat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(ppoll_time64, ppoll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(io_pgetevents_time64, io_pgetevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(mq_timedsend_time64, mq_timedsend, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(mq_timedreceive_time64, mq_timedreceive, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough5); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(semtimedop_time64, semtimedop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough4); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(futex_time64, futex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough6); - REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(sched_rr_get_interval_time64, sched_rr_get_interval, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - SyscallPassthrough2); - } + if (Handler->IsHostKernelVersionAtLeast(6, 8, 0)) { + REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_wake, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_wait, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_requeue, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(statmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(listmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(lsm_get_self_attr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(lsm_set_self_attr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_PASS_FLAGS(lsm_list_modules, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + } else { + REGISTER_SYSCALL_IMPL(futex_wake, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(futex_wait, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(futex_requeue, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(statmount, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(listmount, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(lsm_get_self_attr, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(lsm_set_self_attr, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(lsm_list_modules, UnimplementedSyscallSafe); } } + +namespace x64 { + void RegisterPassthrough(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; + RegisterCommon(Handler); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(ioctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pread_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwrite_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(readv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(writev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(dup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getitimer, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setitimer, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendfile, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(accept, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(recvmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setsockopt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getsockopt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(wait4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(semop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(gettimeofday, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getrlimit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getrusage, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sysinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(times, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(rt_sigqueueinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fstatfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sched_rr_get_interval, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(munlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(adjtimex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setrlimit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(settimeofday, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(readahead, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(futex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(io_getevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getdents64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(semtimedop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_getres, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_timedsend, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_timedreceive, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_notify, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_getsetattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(waitid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pselect6, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(ppoll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(set_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(get_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sync_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(vmsplice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(utimensat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fallocate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timerfd_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timerfd_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(preadv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwritev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(rt_tgsigqueueinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(recvmmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_adjtime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendmmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_vm_readv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_vm_writev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(preadv2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwritev2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(io_pgetevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) { + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pidfd_send_signal, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + } else { + REGISTER_SYSCALL_IMPL_X64(pidfd_send_signal, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(5, 10, 0)) { + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_madvise, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + } else { + REGISTER_SYSCALL_IMPL_X64(process_madvise, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(6, 5, 0)) { + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(cachestat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + } else { + REGISTER_SYSCALL_IMPL_X64(cachestat, UnimplementedSyscallSafe); + } + if (Handler->IsHostKernelVersionAtLeast(6, 6, 0)) { + REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fchmodat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + } else { + REGISTER_SYSCALL_IMPL_X64(fchmodat2, UnimplementedSyscallSafe); + } + } +} // namespace x64 + +namespace x32 { + void RegisterPassthrough(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; + RegisterCommon(Handler); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getuid32, getuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getgid32, getgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(geteuid32, geteuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getegid32, getegid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough0); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setreuid32, setreuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setregid32, setregid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getgroups32, getgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setgroups32, setgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(fchown32, fchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setresuid32, setresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getresuid32, getresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setresgid32, setresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getresgid32, getresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough3); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setuid32, setuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setgid32, setgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setfsuid32, setfsuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setfsgid32, setfsgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough1); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(sendfile64, sendfile, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_gettime64, clock_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_settime64, clock_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_adjtime64, clock_adjtime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_getres_time64, clock_getres, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_nanosleep_time64, clock_nanosleep, + SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timer_gettime64, timer_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timer_settime64, timer_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timerfd_gettime64, timerfd_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timerfd_settime64, timerfd_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(utimensat_time64, utimensat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(ppoll_time64, ppoll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(io_pgetevents_time64, io_pgetevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(mq_timedsend_time64, mq_timedsend, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(mq_timedreceive_time64, mq_timedreceive, + SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough5); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(semtimedop_time64, semtimedop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough4); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(futex_time64, futex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough6); + REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(sched_rr_get_interval_time64, sched_rr_get_interval, + SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + SyscallPassthrough2); + } +} // namespace x32 +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp index 988675d9d..d971f7ee7 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp @@ -19,37 +19,37 @@ $end_info$ #include namespace SignalDelegator { - struct GuestSigAction; +struct GuestSigAction; } namespace FEX::HLE { - void RegisterSignals(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL(rt_sigprocmask, [](FEXCore::Core::CpuStateFrame *Frame, int how, const uint64_t *set, uint64_t *oldset) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(how, set, oldset); - }); +void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL(rt_sigprocmask, [](FEXCore::Core::CpuStateFrame* Frame, int how, const uint64_t* set, uint64_t* oldset) -> uint64_t { + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(how, set, oldset); + }); - REGISTER_SYSCALL_IMPL(rt_sigpending, [](FEXCore::Core::CpuStateFrame *Frame, uint64_t *set, size_t sigsetsize) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(set, sigsetsize); - }); + REGISTER_SYSCALL_IMPL(rt_sigpending, [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, size_t sigsetsize) -> uint64_t { + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(set, sigsetsize); + }); - REGISTER_SYSCALL_IMPL(rt_sigsuspend, [](FEXCore::Core::CpuStateFrame *Frame, uint64_t *unewset, size_t sigsetsize) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(unewset, sigsetsize); - }); + REGISTER_SYSCALL_IMPL(rt_sigsuspend, [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* unewset, size_t sigsetsize) -> uint64_t { + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(unewset, sigsetsize); + }); - REGISTER_SYSCALL_IMPL(userfaultfd, [](FEXCore::Core::CpuStateFrame *Frame, int flags) -> uint64_t { - // Disable userfaultfd until we can properly emulate it - // This is okay because the kernel configuration allows you to disable it at compile time - return -ENOSYS; - uint64_t Result = ::syscall(SYSCALL_DEF(userfaultfd), flags); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL(userfaultfd, [](FEXCore::Core::CpuStateFrame* Frame, int flags) -> uint64_t { + // Disable userfaultfd until we can properly emulate it + // This is okay because the kernel configuration allows you to disable it at compile time + return -ENOSYS; + uint64_t Result = ::syscall(SYSCALL_DEF(userfaultfd), flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL(signalfd, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const uint64_t *mask, size_t sigsetsize) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSignalFD(fd, mask, sigsetsize, 0); - }); + REGISTER_SYSCALL_IMPL(signalfd, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const uint64_t* mask, size_t sigsetsize) -> uint64_t { + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSignalFD(fd, mask, sigsetsize, 0); + }); - REGISTER_SYSCALL_IMPL(signalfd4, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const uint64_t *mask, size_t sigsetsize, int flags) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSignalFD(fd, mask, sigsetsize, flags); - }); - } + REGISTER_SYSCALL_IMPL(signalfd4, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const uint64_t* mask, size_t sigsetsize, int flags) -> uint64_t { + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSignalFD(fd, mask, sigsetsize, flags); + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Stubs.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Stubs.cpp index c82d806cb..52868b8a4 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Stubs.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Stubs.cpp @@ -15,31 +15,34 @@ $end_info$ #include #include -#define SYSCALL_STUB(name) do { ERROR_AND_DIE_FMT("Syscall: " #name " stub!"); return -ENOSYS; } while(0) +#define SYSCALL_STUB(name) \ + do { \ + ERROR_AND_DIE_FMT("Syscall: " #name " stub!"); \ + return -ENOSYS; \ + } while (0) namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE { - void RegisterStubs(FEX::HLE::SyscallHandler *Handler) { +void RegisterStubs(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL(ptrace, [](FEXCore::Core::CpuStateFrame *Frame, int /*enum __ptrace_request*/ request, pid_t pid, void *addr, void *data) -> uint64_t { + REGISTER_SYSCALL_IMPL( + ptrace, [](FEXCore::Core::CpuStateFrame* Frame, int /*enum __ptrace_request*/ request, pid_t pid, void* addr, void* data) -> uint64_t { // We don't support this return -EPERM; }); - REGISTER_SYSCALL_IMPL(modify_ldt, [](FEXCore::Core::CpuStateFrame *Frame, int func, void *ptr, unsigned long bytecount) -> uint64_t { - SYSCALL_STUB(modify_ldt); - }); + REGISTER_SYSCALL_IMPL(modify_ldt, [](FEXCore::Core::CpuStateFrame* Frame, int func, void* ptr, unsigned long bytecount) -> uint64_t { + SYSCALL_STUB(modify_ldt); + }); - REGISTER_SYSCALL_IMPL(restart_syscall, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - SYSCALL_STUB(restart_syscall); - }); + REGISTER_SYSCALL_IMPL(restart_syscall, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { SYSCALL_STUB(restart_syscall); }); - REGISTER_SYSCALL_IMPL(rseq, [](FEXCore::Core::CpuStateFrame *Frame, struct rseq *rseq, uint32_t rseq_len, int flags, uint32_t sig) -> uint64_t { - // We don't support this - return -ENOSYS; - }); - } + REGISTER_SYSCALL_IMPL(rseq, [](FEXCore::Core::CpuStateFrame* Frame, struct rseq* rseq, uint32_t rseq_len, int flags, uint32_t sig) -> uint64_t { + // We don't support this + return -ENOSYS; + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp index ab5f22764..7c5e45196 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp @@ -42,472 +42,458 @@ ARG_TO_STR(idtype_t, "%u") namespace FEX::HLE { - struct ExecutionThreadHandler { - FEXCore::Context::Context *CTX; - FEXCore::Core::InternalThreadState *Thread; - }; +struct ExecutionThreadHandler { + FEXCore::Context::Context* CTX; + FEXCore::Core::InternalThreadState* Thread; +}; - static void *ThreadHandler(void* Data) { - ExecutionThreadHandler *Handler = reinterpret_cast(Data); - auto CTX = Handler->CTX; - auto Thread = Handler->Thread; - FEXCore::Allocator::free(Handler); - FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread); - CTX->ExecutionThread(Thread); - FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread); - FEX::HLE::_SyscallHandler->TM.DestroyThread(Thread); - return nullptr; +static void* ThreadHandler(void* Data) { + ExecutionThreadHandler* Handler = reinterpret_cast(Data); + auto CTX = Handler->CTX; + auto Thread = Handler->Thread; + FEXCore::Allocator::free(Handler); + FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread); + CTX->ExecutionThread(Thread); + FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread); + FEX::HLE::_SyscallHandler->TM.DestroyThread(Thread); + return nullptr; +} + +FEXCore::Core::InternalThreadState* +CreateNewThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args) { + uint64_t flags = args->args.flags; + FEXCore::Core::CPUState NewThreadState {}; + // Clone copies the parent thread's state + memcpy(&NewThreadState, Frame, sizeof(FEXCore::Core::CPUState)); + + NewThreadState.gregs[FEXCore::X86State::REG_RAX] = 0; + if (args->Type == TYPE_CLONE3) { + // stack pointer points to the lowest address to the stack + // set RSP to stack + size + NewThreadState.gregs[FEXCore::X86State::REG_RSP] = args->args.stack + args->args.stack_size; + } else { + NewThreadState.gregs[FEXCore::X86State::REG_RSP] = args->args.stack; } - FEXCore::Core::InternalThreadState *CreateNewThread(FEXCore::Context:: Context *CTX, FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args) { - uint64_t flags = args->args.flags; - FEXCore::Core::CPUState NewThreadState{}; + auto NewThread = FEX::HLE::_SyscallHandler->TM.CreateThread(0, 0, &NewThreadState, args->args.parent_tid); + + if (FEX::HLE::_SyscallHandler->Is64BitMode()) { + if (flags & CLONE_SETTLS) { + x64::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(args->args.tls)); + } + // Set us to start just after the syscall instruction + x64::AdjustRipForNewThread(NewThread->CurrentFrame); + } else { + if (flags & CLONE_SETTLS) { + x32::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(args->args.tls)); + } + x32::AdjustRipForNewThread(NewThread->CurrentFrame); + } + + // We need to do some post-thread creation setup. + NewThread->StartPaused = true; + + // Initialize a new thread for execution. + ExecutionThreadHandler* Arg = reinterpret_cast(FEXCore::Allocator::malloc(sizeof(ExecutionThreadHandler))); + Arg->CTX = CTX; + Arg->Thread = NewThread; + NewThread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg); + + // Wait for the thread to have started. + NewThread->ThreadWaiting.Wait(); + + if (FEX::HLE::_SyscallHandler->NeedXIDCheck()) { + // The first time an application creates a thread, GLIBC installs their SETXID signal handler. + // FEX needs to capture all signals and defer them to the guest. + // Once FEX creates its first guest thread, overwrite the GLIBC SETXID handler *again* to ensure + // FEX maintains control of the signal handler on this signal. + FEX::HLE::_SyscallHandler->GetSignalDelegator()->CheckXIDHandler(); + FEX::HLE::_SyscallHandler->DisableXIDCheck(); + } + + // Return the new threads TID + uint64_t Result = NewThread->ThreadManager.GetTID(); + + // Sets the child TID to pointer in ParentTID + if (flags & CLONE_PARENT_SETTID) { + *reinterpret_cast(args->args.parent_tid) = Result; + } + + // Sets the child TID to the pointer in ChildTID + if (flags & CLONE_CHILD_SETTID) { + NewThread->ThreadManager.set_child_tid = reinterpret_cast(args->args.child_tid); + *reinterpret_cast(args->args.child_tid) = Result; + } + + // When the thread exits, clear the child thread ID at ChildTID + // Additionally wakeup a futex at that address + // Address /may/ be changed with SET_TID_ADDRESS syscall + if (flags & CLONE_CHILD_CLEARTID) { + NewThread->ThreadManager.clear_child_tid = reinterpret_cast(args->args.child_tid); + } + + // clone3 flag + if (flags & CLONE_PIDFD) { + // Use pidfd_open to emulate this flag + const int pidfd = ::syscall(SYSCALL_DEF(pidfd_open), Result, 0); + if (Result == ~0ULL) { + LogMan::Msg::EFmt("Couldn't get pidfd of TID {}\n", Result); + } else { + *reinterpret_cast(args->args.pidfd) = pidfd; + } + } + + FEX::HLE::_SyscallHandler->TM.TrackThread(NewThread); + + return NewThread; +} + +uint64_t HandleNewClone(FEXCore::Core::InternalThreadState* Thread, FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame, + FEX::HLE::clone3_args* CloneArgs) { + auto GuestArgs = &CloneArgs->args; + uint64_t flags = GuestArgs->flags; + auto NewThread = Thread; + bool CreatedNewThreadObject {}; + + if (flags & CLONE_THREAD) { + FEXCore::Core::CPUState NewThreadState {}; // Clone copies the parent thread's state memcpy(&NewThreadState, Frame, sizeof(FEXCore::Core::CPUState)); NewThreadState.gregs[FEXCore::X86State::REG_RAX] = 0; - if (args->Type == TYPE_CLONE3) { - // stack pointer points to the lowest address to the stack - // set RSP to stack + size - NewThreadState.gregs[FEXCore::X86State::REG_RSP] = args->args.stack + args->args.stack_size; - } - else { - NewThreadState.gregs[FEXCore::X86State::REG_RSP] = args->args.stack; + if (GuestArgs->stack == 0) { + // Copies in the original thread's stack + } else { + NewThreadState.gregs[FEXCore::X86State::REG_RSP] = GuestArgs->stack; } - auto NewThread = FEX::HLE::_SyscallHandler->TM.CreateThread(0, 0, &NewThreadState, args->args.parent_tid); + // Overwrite thread + NewThread = FEX::HLE::_SyscallHandler->TM.CreateThread(0, 0, &NewThreadState, GuestArgs->parent_tid); + + // CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID, CLONE_PIDFD will be handled by kernel + // Call execution thread directly since we already are on the new thread + NewThread->StartRunning.NotifyAll(); // Clear the start running flag + CreatedNewThreadObject = true; + } else { + // If we don't have CLONE_THREAD then we are effectively a fork + // Clear all the other threads that are being tracked + // Frame->Thread is /ONLY/ safe to access when CLONE_THREAD flag is not set + // Unlock the mutexes on both sides of the fork + FEX::HLE::_SyscallHandler->UnlockAfterFork(Frame->Thread, true); + + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &CloneArgs->SignalMask, nullptr, sizeof(CloneArgs->SignalMask)); + + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RAX] = 0; + if (GuestArgs->stack == 0) { + // Copies in the original thread's stack + } else { + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = GuestArgs->stack; + } + } + + if (CloneArgs->Type == TYPE_CLONE3) { + // If we are coming from a clone3 handler then we need to adjust RSP. + Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] += CloneArgs->args.stack_size; + } + + if (FEX::HLE::_SyscallHandler->Is64BitMode()) { + if (flags & CLONE_SETTLS) { + x64::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(GuestArgs->tls)); + } + // Set us to start just after the syscall instruction + x64::AdjustRipForNewThread(NewThread->CurrentFrame); + } else { + if (flags & CLONE_SETTLS) { + x32::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(GuestArgs->tls)); + } + x32::AdjustRipForNewThread(NewThread->CurrentFrame); + } + + // Depending on clone settings, our TID and PID could have changed + Thread->ThreadManager.TID = FHU::Syscalls::gettid(); + Thread->ThreadManager.PID = ::getpid(); + FEX::HLE::_SyscallHandler->FM.UpdatePID(Thread->ThreadManager.PID); + + if (CreatedNewThreadObject) { + FEX::HLE::_SyscallHandler->TM.TrackThread(Thread); + } + + FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread); + + // Start exuting the thread directly + // Our host clone starts in a new stack space, so it can't return back to the JIT space + CTX->ExecutionThread(Thread); + + FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread); + + // The rest of the context remains as is and the thread will continue executing + return Thread->StatusCode; +} + +uint64_t ForkGuest(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack, + size_t StackSize, pid_t* parent_tid, pid_t* child_tid, void* tls) { + // Just before we fork, we lock all syscall mutexes so that both processes will end up with a locked mutex + + uint64_t Mask {~0ULL}; + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &Mask, sizeof(Mask)); + + FEX::HLE::_SyscallHandler->LockBeforeFork(Frame->Thread); + + const bool IsVFork = flags & CLONE_VFORK; + pid_t Result {}; + int VForkFDs[2]; + if (IsVFork) { + // Use pipes as a mechanism for knowing when the child process is exiting. + // FEX can't use `waitpid` for this since the child process may want to use it. + // If we use `waitpid` then the kernel won't return the same data if asked again. + pipe2(VForkFDs, O_CLOEXEC); + + // XXX: We don't currently support a real `vfork` as it causes problems. + // Currently behaves like a fork (with wait after the fact), which isn't correct. Need to find where the problem is + Result = fork(); + + if (Result == 0) { + // Close the read end of the pipe. + // Keep the write end open so the parent can poll it. + close(VForkFDs[0]); + } else { + // Close the write end of the pipe. + close(VForkFDs[1]); + } + } else { + Result = fork(); + } + const bool IsChild = Result == 0; + + if (IsChild) { + // Unlock the mutexes on both sides of the fork + FEX::HLE::_SyscallHandler->UnlockAfterFork(Frame->Thread, IsChild); + + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, nullptr, sizeof(Mask)); + + // Child + // update the internal TID + Thread->ThreadManager.TID = FHU::Syscalls::gettid(); + Thread->ThreadManager.PID = ::getpid(); + FEX::HLE::_SyscallHandler->FM.UpdatePID(Thread->ThreadManager.PID); + Thread->ThreadManager.clear_child_tid = nullptr; + + // only a single thread running so no need to remove anything from the thread array + + // Handle child setup now + if (stack != nullptr) { + // use specified stack + Frame->State.gregs[FEXCore::X86State::REG_RSP] = reinterpret_cast(stack) + StackSize; + } else { + // In the case of fork and nullptr stack then the child uses the same stack space as the parent + // Same virtual address, different addressspace + } if (FEX::HLE::_SyscallHandler->Is64BitMode()) { if (flags & CLONE_SETTLS) { - x64::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(args->args.tls)); + x64::SetThreadArea(Frame, tls); } - // Set us to start just after the syscall instruction - x64::AdjustRipForNewThread(NewThread->CurrentFrame); - } - else { + } else { + // 32bit TLS doesn't just set the fs register if (flags & CLONE_SETTLS) { - x32::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(args->args.tls)); + x32::SetThreadArea(Frame, tls); } - x32::AdjustRipForNewThread(NewThread->CurrentFrame); - } - - // We need to do some post-thread creation setup. - NewThread->StartPaused = true; - - // Initialize a new thread for execution. - ExecutionThreadHandler *Arg = reinterpret_cast(FEXCore::Allocator::malloc(sizeof(ExecutionThreadHandler))); - Arg->CTX = CTX; - Arg->Thread = NewThread; - NewThread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg); - - // Wait for the thread to have started. - NewThread->ThreadWaiting.Wait(); - - if (FEX::HLE::_SyscallHandler->NeedXIDCheck()) { - // The first time an application creates a thread, GLIBC installs their SETXID signal handler. - // FEX needs to capture all signals and defer them to the guest. - // Once FEX creates its first guest thread, overwrite the GLIBC SETXID handler *again* to ensure - // FEX maintains control of the signal handler on this signal. - FEX::HLE::_SyscallHandler->GetSignalDelegator()->CheckXIDHandler(); - FEX::HLE::_SyscallHandler->DisableXIDCheck(); - } - - // Return the new threads TID - uint64_t Result = NewThread->ThreadManager.GetTID(); - - // Sets the child TID to pointer in ParentTID - if (flags & CLONE_PARENT_SETTID) { - *reinterpret_cast(args->args.parent_tid) = Result; } // Sets the child TID to the pointer in ChildTID if (flags & CLONE_CHILD_SETTID) { - NewThread->ThreadManager.set_child_tid = reinterpret_cast(args->args.child_tid); - *reinterpret_cast(args->args.child_tid) = Result; + Thread->ThreadManager.set_child_tid = child_tid; + *child_tid = Thread->ThreadManager.TID; } // When the thread exits, clear the child thread ID at ChildTID // Additionally wakeup a futex at that address // Address /may/ be changed with SET_TID_ADDRESS syscall if (flags & CLONE_CHILD_CLEARTID) { - NewThread->ThreadManager.clear_child_tid = reinterpret_cast(args->args.child_tid); + Thread->ThreadManager.clear_child_tid = child_tid; } - // clone3 flag - if (flags & CLONE_PIDFD) { - // Use pidfd_open to emulate this flag - const int pidfd = ::syscall(SYSCALL_DEF(pidfd_open), Result, 0); - if (Result == ~0ULL) { - LogMan::Msg::EFmt("Couldn't get pidfd of TID {}\n", Result); - } - else { - *reinterpret_cast(args->args.pidfd) = pidfd; + // the rest of the context remains as is, this thread will keep executing + return 0; + } else { + if (Result != -1) { + if (flags & CLONE_PARENT_SETTID) { + *parent_tid = Result; } } - FEX::HLE::_SyscallHandler->TM.TrackThread(NewThread); + // Unlock the mutexes on both sides of the fork + FEX::HLE::_SyscallHandler->UnlockAfterFork(Frame->Thread, IsChild); - return NewThread; - } + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, nullptr, sizeof(Mask)); - uint64_t HandleNewClone(FEXCore::Core::InternalThreadState *Thread, FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *CloneArgs) { - auto GuestArgs = &CloneArgs->args; - uint64_t flags = GuestArgs->flags; - auto NewThread = Thread; - bool CreatedNewThreadObject{}; - - if (flags & CLONE_THREAD) { - FEXCore::Core::CPUState NewThreadState{}; - // Clone copies the parent thread's state - memcpy(&NewThreadState, Frame, sizeof(FEXCore::Core::CPUState)); - - NewThreadState.gregs[FEXCore::X86State::REG_RAX] = 0; - if (GuestArgs->stack == 0) { - // Copies in the original thread's stack - } - else { - NewThreadState.gregs[FEXCore::X86State::REG_RSP] = GuestArgs->stack; - } - - // Overwrite thread - NewThread = FEX::HLE::_SyscallHandler->TM.CreateThread(0, 0, &NewThreadState, GuestArgs->parent_tid); - - // CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID, CLONE_PIDFD will be handled by kernel - // Call execution thread directly since we already are on the new thread - NewThread->StartRunning.NotifyAll(); // Clear the start running flag - CreatedNewThreadObject = true; - } - else{ - // If we don't have CLONE_THREAD then we are effectively a fork - // Clear all the other threads that are being tracked - // Frame->Thread is /ONLY/ safe to access when CLONE_THREAD flag is not set - // Unlock the mutexes on both sides of the fork - FEX::HLE::_SyscallHandler->UnlockAfterFork(Frame->Thread, true); - - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &CloneArgs->SignalMask, nullptr, sizeof(CloneArgs->SignalMask)); - - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RAX] = 0; - if (GuestArgs->stack == 0) { - // Copies in the original thread's stack - } - else { - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = GuestArgs->stack; - } - } - - if (CloneArgs->Type == TYPE_CLONE3) { - // If we are coming from a clone3 handler then we need to adjust RSP. - Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] += CloneArgs->args.stack_size; - } - - if (FEX::HLE::_SyscallHandler->Is64BitMode()) { - if (flags & CLONE_SETTLS) { - x64::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(GuestArgs->tls)); - } - // Set us to start just after the syscall instruction - x64::AdjustRipForNewThread(NewThread->CurrentFrame); - } - else { - if (flags & CLONE_SETTLS) { - x32::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(GuestArgs->tls)); - } - x32::AdjustRipForNewThread(NewThread->CurrentFrame); - } - - // Depending on clone settings, our TID and PID could have changed - Thread->ThreadManager.TID = FHU::Syscalls::gettid(); - Thread->ThreadManager.PID = ::getpid(); - FEX::HLE::_SyscallHandler->FM.UpdatePID(Thread->ThreadManager.PID); - - if (CreatedNewThreadObject) { - FEX::HLE::_SyscallHandler->TM.TrackThread(Thread); - } - - FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread); - - // Start exuting the thread directly - // Our host clone starts in a new stack space, so it can't return back to the JIT space - CTX->ExecutionThread(Thread); - - FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread); - - // The rest of the context remains as is and the thread will continue executing - return Thread->StatusCode; - } - - uint64_t ForkGuest(FEXCore::Core::InternalThreadState *Thread, FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, size_t StackSize, pid_t *parent_tid, pid_t *child_tid, void *tls) { - // Just before we fork, we lock all syscall mutexes so that both processes will end up with a locked mutex - - uint64_t Mask{~0ULL}; - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &Mask, sizeof(Mask)); - - FEX::HLE::_SyscallHandler->LockBeforeFork(Frame->Thread); - - const bool IsVFork = flags & CLONE_VFORK; - pid_t Result{}; - int VForkFDs[2]; + // VFork needs the parent to wait for the child to exit. if (IsVFork) { - // Use pipes as a mechanism for knowing when the child process is exiting. - // FEX can't use `waitpid` for this since the child process may want to use it. - // If we use `waitpid` then the kernel won't return the same data if asked again. - pipe2(VForkFDs, O_CLOEXEC); + // Wait for the read end of the pipe to close. + pollfd PollFD {}; + PollFD.fd = VForkFDs[0]; + PollFD.events = POLLIN | POLLOUT | POLLRDHUP | POLLERR | POLLHUP | POLLNVAL; - // XXX: We don't currently support a real `vfork` as it causes problems. - // Currently behaves like a fork (with wait after the fact), which isn't correct. Need to find where the problem is - Result = fork(); + // Mask all signals until the child process returns. + sigset_t SignalMask {}; + sigfillset(&SignalMask); + while (ppoll(&PollFD, 1, nullptr, &SignalMask) == -1 && errno == EINTR) + ; - if (Result == 0) { - // Close the read end of the pipe. - // Keep the write end open so the parent can poll it. - close(VForkFDs[0]); - } - else { - // Close the write end of the pipe. - close(VForkFDs[1]); - } + // Close the read end now. + close(VForkFDs[0]); } - else { - Result = fork(); - } - const bool IsChild = Result == 0; - if (IsChild) { - // Unlock the mutexes on both sides of the fork - FEX::HLE::_SyscallHandler->UnlockAfterFork(Frame->Thread, IsChild); - - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, nullptr, sizeof(Mask)); - - // Child - // update the internal TID - Thread->ThreadManager.TID = FHU::Syscalls::gettid(); - Thread->ThreadManager.PID = ::getpid(); - FEX::HLE::_SyscallHandler->FM.UpdatePID(Thread->ThreadManager.PID); - Thread->ThreadManager.clear_child_tid = nullptr; - - // only a single thread running so no need to remove anything from the thread array - - // Handle child setup now - if (stack != nullptr) { - // use specified stack - Frame->State.gregs[FEXCore::X86State::REG_RSP] = reinterpret_cast(stack) + StackSize; - } else { - // In the case of fork and nullptr stack then the child uses the same stack space as the parent - // Same virtual address, different addressspace - } - - if (FEX::HLE::_SyscallHandler->Is64BitMode()) { - if (flags & CLONE_SETTLS) { - x64::SetThreadArea(Frame, tls); - } - } - else { - // 32bit TLS doesn't just set the fs register - if (flags & CLONE_SETTLS) { - x32::SetThreadArea(Frame, tls); - } - } - - // Sets the child TID to the pointer in ChildTID - if (flags & CLONE_CHILD_SETTID) { - Thread->ThreadManager.set_child_tid = child_tid; - *child_tid = Thread->ThreadManager.TID; - } - - // When the thread exits, clear the child thread ID at ChildTID - // Additionally wakeup a futex at that address - // Address /may/ be changed with SET_TID_ADDRESS syscall - if (flags & CLONE_CHILD_CLEARTID) { - Thread->ThreadManager.clear_child_tid = child_tid; - } - - // the rest of the context remains as is, this thread will keep executing - return 0; - } else { - if (Result != -1) { - if (flags & CLONE_PARENT_SETTID) { - *parent_tid = Result; - } - } - - // Unlock the mutexes on both sides of the fork - FEX::HLE::_SyscallHandler->UnlockAfterFork(Frame->Thread, IsChild); - - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, nullptr, sizeof(Mask)); - - // VFork needs the parent to wait for the child to exit. - if (IsVFork) { - // Wait for the read end of the pipe to close. - pollfd PollFD{}; - PollFD.fd = VForkFDs[0]; - PollFD.events = POLLIN | POLLOUT | POLLRDHUP | POLLERR | POLLHUP | POLLNVAL; - - // Mask all signals until the child process returns. - sigset_t SignalMask{}; - sigfillset(&SignalMask); - while (ppoll(&PollFD, 1, nullptr, &SignalMask) == -1 && errno == EINTR); - - // Close the read end now. - close(VForkFDs[0]); - } - - // Parent - SYSCALL_ERRNO(); - } + // Parent + SYSCALL_ERRNO(); } +} - void RegisterThread(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterThread(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL(rt_sigreturn, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - FEX::HLE::_SyscallHandler->GetSignalDelegator()->HandleSignalHandlerReturn(true); - FEX_UNREACHABLE; - }); + REGISTER_SYSCALL_IMPL(rt_sigreturn, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + FEX::HLE::_SyscallHandler->GetSignalDelegator()->HandleSignalHandlerReturn(true); + FEX_UNREACHABLE; + }); - REGISTER_SYSCALL_IMPL_FLAGS(fork, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - return ForkGuest(Frame->Thread, Frame, 0, 0, 0, 0, 0, 0); - }); + REGISTER_SYSCALL_IMPL_FLAGS(fork, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + return ForkGuest(Frame->Thread, Frame, 0, 0, 0, 0, 0, 0); + }); - REGISTER_SYSCALL_IMPL_FLAGS(vfork, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - return ForkGuest(Frame->Thread, Frame, CLONE_VFORK, 0, 0, 0, 0, 0); - }); + REGISTER_SYSCALL_IMPL_FLAGS(vfork, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + return ForkGuest(Frame->Thread, Frame, CLONE_VFORK, 0, 0, 0, 0, 0); + }); - REGISTER_SYSCALL_IMPL_FLAGS(getpgrp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - uint64_t Result = ::getpgrp(); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(getpgrp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + uint64_t Result = ::getpgrp(); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(clone3, SyscallFlags::DEFAULT, ([](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::kernel_clone3_args *cl_args, size_t size) -> uint64_t { - FEX::HLE::clone3_args args{}; - args.Type = TypeOfClone::TYPE_CLONE3; - memcpy(&args.args, cl_args, std::min(sizeof(FEX::HLE::kernel_clone3_args), size)); - return CloneHandler(Frame, &args); - })); + REGISTER_SYSCALL_IMPL_FLAGS(clone3, SyscallFlags::DEFAULT, + ([](FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::kernel_clone3_args* cl_args, size_t size) -> uint64_t { + FEX::HLE::clone3_args args {}; + args.Type = TypeOfClone::TYPE_CLONE3; + memcpy(&args.args, cl_args, std::min(sizeof(FEX::HLE::kernel_clone3_args), size)); + return CloneHandler(Frame, &args); + })); - REGISTER_SYSCALL_IMPL_FLAGS(exit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY | SyscallFlags::NORETURN, - [](FEXCore::Core::CpuStateFrame *Frame, int status) -> uint64_t { - auto Thread = Frame->Thread; + REGISTER_SYSCALL_IMPL_FLAGS(exit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY | SyscallFlags::NORETURN, + [](FEXCore::Core::CpuStateFrame* Frame, int status) -> uint64_t { + auto Thread = Frame->Thread; - // TLS/DTV teardown is something FEX can't control. Disable glibc checking when we leave a pthread. - // Since this thread is hard stopping, we can't track the TLS/DTV teardown in FEX's thread handling. - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable(); + // TLS/DTV teardown is something FEX can't control. Disable glibc checking when we leave a pthread. + // Since this thread is hard stopping, we can't track the TLS/DTV teardown in FEX's thread handling. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable(); - if (Thread->ThreadManager.clear_child_tid) { - std::atomic *Addr = reinterpret_cast*>(Thread->ThreadManager.clear_child_tid); - Addr->store(0); - syscall(SYSCALL_DEF(futex), - Thread->ThreadManager.clear_child_tid, - FUTEX_WAKE, - ~0ULL, - 0, - 0, - 0); - } + if (Thread->ThreadManager.clear_child_tid) { + std::atomic* Addr = reinterpret_cast*>(Thread->ThreadManager.clear_child_tid); + Addr->store(0); + syscall(SYSCALL_DEF(futex), Thread->ThreadManager.clear_child_tid, FUTEX_WAKE, ~0ULL, 0, 0, 0); + } - Thread->StatusCode = status; - FEX::HLE::_SyscallHandler->TM.StopThread(Thread); + Thread->StatusCode = status; + FEX::HLE::_SyscallHandler->TM.StopThread(Thread); - return 0; - }); + return 0; + }); - REGISTER_SYSCALL_IMPL_FLAGS(prctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) -> uint64_t { - uint64_t Result{}; + REGISTER_SYSCALL_IMPL_FLAGS(prctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) -> uint64_t { + uint64_t Result {}; #ifndef PR_GET_AUXV #define PR_GET_AUXV 0x41555856 #endif - switch (option) { - case PR_SET_SECCOMP: - case PR_GET_SECCOMP: - // FEX doesn't support seccomp - return -EINVAL; - break; - case PR_GET_AUXV: { - if (arg4 || arg5) { - return -EINVAL; - } + switch (option) { + case PR_SET_SECCOMP: + case PR_GET_SECCOMP: + // FEX doesn't support seccomp + return -EINVAL; + break; + case PR_GET_AUXV: { + if (arg4 || arg5) { + return -EINVAL; + } - void* addr = reinterpret_cast(arg2); - size_t UserSize = reinterpret_cast(arg3); + void* addr = reinterpret_cast(arg2); + size_t UserSize = reinterpret_cast(arg3); - uint64_t auxvBase=0; - uint64_t auxvSize=0; - FEX::HLE::_SyscallHandler->GetCodeLoader()->GetAuxv(auxvBase, auxvSize); - size_t MinSize = std::min(auxvSize, UserSize); + uint64_t auxvBase = 0; + uint64_t auxvSize = 0; + FEX::HLE::_SyscallHandler->GetCodeLoader()->GetAuxv(auxvBase, auxvSize); + size_t MinSize = std::min(auxvSize, UserSize); - memcpy(addr, reinterpret_cast(auxvBase), MinSize); + memcpy(addr, reinterpret_cast(auxvBase), MinSize); - // Returns the size of auxv without truncation. - return auxvSize; + // Returns the size of auxv without truncation. + return auxvSize; + } + default: Result = ::prctl(option, arg2, arg3, arg4, arg5); break; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_FLAGS(arch_prctl, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame* Frame, int code, unsigned long addr) -> uint64_t { + uint64_t Result {}; + switch (code) { + case 0x1001: // ARCH_SET_GS + if (addr >= SyscallHandler::TASK_MAX_64BIT) { + // Ignore a non-canonical address + return -EPERM; } - default: - Result = ::prctl(option, arg2, arg3, arg4, arg5); + Frame->State.gs_cached = addr; + Result = 0; break; + case 0x1002: // ARCH_SET_FS + if (addr >= SyscallHandler::TASK_MAX_64BIT) { + // Ignore a non-canonical address + return -EPERM; } - SYSCALL_ERRNO(); - }); + Frame->State.fs_cached = addr; + Result = 0; + break; + case 0x1003: // ARCH_GET_FS + *reinterpret_cast(addr) = Frame->State.fs_cached; + Result = 0; + break; + case 0x1004: // ARCH_GET_GS + *reinterpret_cast(addr) = Frame->State.gs_cached; + Result = 0; + break; + case 0x3001: // ARCH_CET_STATUS + Result = -EINVAL; // We don't support CET, return EINVAL + break; + case 0x1011: // ARCH_GET_CPUID + return 1; + break; + case 0x1012: // ARCH_SET_CPUID + return -ENODEV; // Claim we don't support faulting on CPUID + break; + default: + LogMan::Msg::EFmt("Unknown prctl: 0x{:x}", code); + Result = -EINVAL; + break; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(arch_prctl, SyscallFlags::DEFAULT, - [](FEXCore::Core::CpuStateFrame *Frame, int code, unsigned long addr) -> uint64_t { - uint64_t Result{}; - switch (code) { - case 0x1001: // ARCH_SET_GS - if (addr >= SyscallHandler::TASK_MAX_64BIT) { - // Ignore a non-canonical address - return -EPERM; - } - Frame->State.gs_cached = addr; - Result = 0; - break; - case 0x1002: // ARCH_SET_FS - if (addr >= SyscallHandler::TASK_MAX_64BIT) { - // Ignore a non-canonical address - return -EPERM; - } - Frame->State.fs_cached = addr; - Result = 0; - break; - case 0x1003: // ARCH_GET_FS - *reinterpret_cast(addr) = Frame->State.fs_cached; - Result = 0; - break; - case 0x1004: // ARCH_GET_GS - *reinterpret_cast(addr) = Frame->State.gs_cached; - Result = 0; - break; - case 0x3001: // ARCH_CET_STATUS - Result = -EINVAL; // We don't support CET, return EINVAL - break; - case 0x1011: // ARCH_GET_CPUID - return 1; - break; - case 0x1012: // ARCH_SET_CPUID - return -ENODEV; // Claim we don't support faulting on CPUID - break; - default: - LogMan::Msg::EFmt("Unknown prctl: 0x{:x}", code); - Result = -EINVAL; - break; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(set_tid_address, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int* tidptr) -> uint64_t { + auto Thread = Frame->Thread; + Thread->ThreadManager.clear_child_tid = tidptr; + return Thread->ThreadManager.GetTID(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(set_tid_address, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int *tidptr) -> uint64_t { - auto Thread = Frame->Thread; - Thread->ThreadManager.clear_child_tid = tidptr; - return Thread->ThreadManager.GetTID(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(exit_group, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY | SyscallFlags::NORETURN, + [](FEXCore::Core::CpuStateFrame* Frame, int status) -> uint64_t { + // Save telemetry if we're exiting. + FEX::HLE::_SyscallHandler->GetSignalDelegator()->SaveTelemetry(); - REGISTER_SYSCALL_IMPL_FLAGS(exit_group, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY | SyscallFlags::NORETURN, - [](FEXCore::Core::CpuStateFrame *Frame, int status) -> uint64_t { - - // Save telemetry if we're exiting. - FEX::HLE::_SyscallHandler->GetSignalDelegator()->SaveTelemetry(); - - syscall(SYSCALL_DEF(exit_group), status); - // This will never be reached - std::terminate(); - }); - } + syscall(SYSCALL_DEF(exit_group), status); + // This will never be reached + std::terminate(); + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.h index db5609d0f..6f20a7484 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.h @@ -12,10 +12,13 @@ $end_info$ namespace FEXCore::Core { struct InternalThreadState; struct CPUState; -} +} // namespace FEXCore::Core namespace FEX::HLE { - FEXCore::Core::InternalThreadState *CreateNewThread(FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args); - uint64_t HandleNewClone(FEXCore::Core::InternalThreadState *Thread, FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *GuestArgs); - uint64_t ForkGuest(FEXCore::Core::InternalThreadState *Thread, FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, size_t StackSize, pid_t *parent_tid, pid_t *child_tid, void *tls); -} +FEXCore::Core::InternalThreadState* +CreateNewThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args); +uint64_t HandleNewClone(FEXCore::Core::InternalThreadState* Thread, FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame, + FEX::HLE::clone3_args* GuestArgs); +uint64_t ForkGuest(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack, + size_t StackSize, pid_t* parent_tid, pid_t* child_tid, void* tls); +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Timer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Timer.cpp index 47e32a1ee..64bfc775f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Timer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Timer.cpp @@ -21,19 +21,19 @@ $end_info$ #include namespace FEX::HLE { - void RegisterTimer(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_FLAGS(alarm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, unsigned int seconds) -> uint64_t { - uint64_t Result = ::alarm(seconds); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_FLAGS(alarm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, unsigned int seconds) -> uint64_t { + uint64_t Result = ::alarm(seconds); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_FLAGS(pause, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - uint64_t Result = ::pause(); - SYSCALL_ERRNO(); - }); - } + REGISTER_SYSCALL_IMPL_FLAGS(pause, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + uint64_t Result = ::pause(); + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp index 148284c7a..7cd18230b 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp @@ -24,7 +24,7 @@ $end_info$ namespace FEX::HLE { /// Helpers /// -auto SyscallHandler::VMAProt::fromProt (int Prot) -> VMAProt { +auto SyscallHandler::VMAProt::fromProt(int Prot) -> VMAProt { return VMAProt { .Readable = (Prot & PROT_READ) != 0, .Writable = (Prot & PROT_WRITE) != 0, @@ -32,7 +32,7 @@ auto SyscallHandler::VMAProt::fromProt (int Prot) -> VMAProt { }; } -auto SyscallHandler::VMAProt::fromSHM (int SHMFlg) -> VMAProt { +auto SyscallHandler::VMAProt::fromSHM(int SHMFlg) -> VMAProt { return VMAProt { .Readable = true, .Writable = SHMFlg & SHM_RDONLY ? false : true, @@ -47,8 +47,8 @@ auto SyscallHandler::VMAFlags::fromFlags(int Flags) -> VMAFlags { } // SMC interactions -bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) { - const auto FaultAddress = (uintptr_t)((siginfo_t *)info)->si_addr; +bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) { + const auto FaultAddress = (uintptr_t)((siginfo_t*)info)->si_addr; { // Can't use the deferred signal lock in the SIGSEGV handler. @@ -80,8 +80,9 @@ bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState *Thread, auto FaultBaseMirrored = Offset - VMA->Offset + VMA->Base; if (VMA->Prot.Writable) { - _SyscallHandler->TM.InvalidateGuestCodeRange(Thread, FaultBaseMirrored, FEXCore::Utils::FEX_PAGE_SIZE, [](uintptr_t Start, uintptr_t Length) { - auto rv = mprotect((void *)Start, Length, PROT_READ | PROT_WRITE); + _SyscallHandler->TM.InvalidateGuestCodeRange(Thread, FaultBaseMirrored, FEXCore::Utils::FEX_PAGE_SIZE, + [](uintptr_t Start, uintptr_t Length) { + auto rv = mprotect((void*)Start, Length, PROT_READ | PROT_WRITE); LogMan::Throw::AAFmt(rv == 0, "mprotect({}, {}) failed", Start, Length); }); } else { @@ -91,7 +92,7 @@ bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState *Thread, } while ((VMA = VMA->ResourceNextVMA)); } else { _SyscallHandler->TM.InvalidateGuestCodeRange(Thread, FaultBase, FEXCore::Utils::FEX_PAGE_SIZE, [](uintptr_t Start, uintptr_t Length) { - auto rv = mprotect((void *)Start, Length, PROT_READ | PROT_WRITE); + auto rv = mprotect((void*)Start, Length, PROT_READ | PROT_WRITE); LogMan::Throw::AAFmt(rv == 0, "mprotect({}, {}) failed", Start, Length); }); } @@ -100,7 +101,7 @@ bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState *Thread, } } -void SyscallHandler::MarkGuestExecutableRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) { +void SyscallHandler::MarkGuestExecutableRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) { const auto Base = Start & FEXCore::Utils::FEX_PAGE_MASK; const auto Top = FEXCore::AlignUp(Start + Length, FEXCore::Utils::FEX_PAGE_SIZE); @@ -147,13 +148,13 @@ void SyscallHandler::MarkGuestExecutableRange(FEXCore::Core::InternalThreadState const auto MirroredBase = std::max(VMAOffsetBase, OffsetBase); const auto MirroredSize = std::min(OffsetTop, VMAOffsetTop) - MirroredBase; - auto rv = mprotect((void *)(MirroredBase - VMAOffsetBase + VMABase), MirroredSize, PROT_READ); + auto rv = mprotect((void*)(MirroredBase - VMAOffsetBase + VMABase), MirroredSize, PROT_READ); LogMan::Throw::AAFmt(rv == 0, "mprotect({}, {}) failed", MirroredBase, MirroredSize); } } while ((VMA = VMA->ResourceNextVMA)); } else if (Mapping->second.Prot.Writable) { - int rv = mprotect((void *)ProtectBase, ProtectSize, PROT_READ); + int rv = mprotect((void*)ProtectBase, ProtectSize, PROT_READ); LogMan::Throw::AAFmt(rv == 0, "mprotect({}, {}) failed", ProtectBase, ProtectSize); } @@ -163,7 +164,7 @@ void SyscallHandler::MarkGuestExecutableRange(FEXCore::Core::InternalThreadState } // Used for AOT -FEXCore::HLE::AOTIRCacheEntryLookupResult SyscallHandler::LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestAddr) { +FEXCore::HLE::AOTIRCacheEntryLookupResult SyscallHandler::LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestAddr) { auto lk = FEXCore::GuardSignalDeferringSection(VMATracking.Mutex, Thread); // Get the first mapping after GuestAddr, or end @@ -174,14 +175,12 @@ FEXCore::HLE::AOTIRCacheEntryLookupResult SyscallHandler::LookupAOTIRCacheEntry( return {nullptr, 0}; } - return { - Entry->second.Resource ? Entry->second.Resource->AOTIRCacheEntry : nullptr, - Entry->second.Base - Entry->second.Offset - }; + return {Entry->second.Resource ? Entry->second.Resource->AOTIRCacheEntry : nullptr, Entry->second.Base - Entry->second.Offset}; } // MMan Tracking -void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size, int Prot, int Flags, int fd, off_t Offset) { +void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size, int Prot, int Flags, int fd, + off_t Offset) { Size = FEXCore::AlignUp(Size, FEXCore::Utils::FEX_PAGE_SIZE); if (Flags & MAP_SHARED) { @@ -196,7 +195,7 @@ void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState *Thread, uintp static uint64_t AnonSharedId = 1; - MappedResource *Resource = nullptr; + MappedResource* Resource = nullptr; if (!(Flags & MAP_ANONYMOUS)) { struct stat64 buf; @@ -217,9 +216,9 @@ void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState *Thread, uintp } } } else if (Flags & MAP_SHARED) { - MRID mrid{SpecialDev::Anon, AnonSharedId++}; + MRID mrid {SpecialDev::Anon, AnonSharedId++}; - auto [Iter, Inserted] = VMATracking.MappedResources.emplace(mrid, MappedResource{nullptr, nullptr, 0}); + auto [Iter, Inserted] = VMATracking.MappedResources.emplace(mrid, MappedResource {nullptr, nullptr, 0}); LOGMAN_THROW_AA_FMT(Inserted == true, "VMA tracking error"); Resource = &Iter->second; Resource->Iterator = Iter; @@ -236,7 +235,7 @@ void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState *Thread, uintp } } -void SyscallHandler::TrackMunmap(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size) { +void SyscallHandler::TrackMunmap(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size) { Size = FEXCore::AlignUp(Size, FEXCore::Utils::FEX_PAGE_SIZE); { @@ -253,7 +252,7 @@ void SyscallHandler::TrackMunmap(FEXCore::Core::InternalThreadState *Thread, uin } } -void SyscallHandler::TrackMprotect(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size, int Prot) { +void SyscallHandler::TrackMprotect(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size, int Prot) { Size = FEXCore::AlignUp(Size, FEXCore::Utils::FEX_PAGE_SIZE); { @@ -267,7 +266,8 @@ void SyscallHandler::TrackMprotect(FEXCore::Core::InternalThreadState *Thread, u } } -void SyscallHandler::TrackMremap(FEXCore::Core::InternalThreadState *Thread, uintptr_t OldAddress, size_t OldSize, size_t NewSize, int flags, uintptr_t NewAddress) { +void SyscallHandler::TrackMremap(FEXCore::Core::InternalThreadState* Thread, uintptr_t OldAddress, size_t OldSize, size_t NewSize, + int flags, uintptr_t NewAddress) { OldSize = FEXCore::AlignUp(OldSize, FEXCore::Utils::FEX_PAGE_SIZE); NewSize = FEXCore::AlignUp(NewSize, FEXCore::Utils::FEX_PAGE_SIZE); @@ -319,7 +319,7 @@ void SyscallHandler::TrackMremap(FEXCore::Core::InternalThreadState *Thread, uin } } -void SyscallHandler::TrackShmat(FEXCore::Core::InternalThreadState *Thread, int shmid, uintptr_t Base, int shmflg) { +void SyscallHandler::TrackShmat(FEXCore::Core::InternalThreadState* Thread, int shmid, uintptr_t Base, int shmflg) { CTX->MarkMemoryShared(Thread); shmid_ds stat; @@ -333,7 +333,7 @@ void SyscallHandler::TrackShmat(FEXCore::Core::InternalThreadState *Thread, int auto lk = FEXCore::GuardSignalDeferringSection(VMATracking.Mutex, Thread); // TODO - MRID mrid{SpecialDev::SHM, static_cast(shmid)}; + MRID mrid {SpecialDev::SHM, static_cast(shmid)}; auto ResourceInserted = VMATracking.MappedResources.insert({mrid, {nullptr, nullptr, Length}}); auto Resource = &ResourceInserted.first->second; @@ -341,15 +341,14 @@ void SyscallHandler::TrackShmat(FEXCore::Core::InternalThreadState *Thread, int Resource->Iterator = ResourceInserted.first; } VMATracking.SetUnsafe(CTX, Resource, Base, 0, Length, VMAFlags::fromFlags(MAP_SHARED), - VMAProt::fromProt((shmflg & SHM_RDONLY) ? PROT_READ : (PROT_READ | PROT_WRITE)) - ); + VMAProt::fromProt((shmflg & SHM_RDONLY) ? PROT_READ : (PROT_READ | PROT_WRITE))); } if (SMCChecks != FEXCore::Config::CONFIG_SMC_NONE) { _SyscallHandler->TM.InvalidateGuestCodeRange(Thread, Base, Length); } } -void SyscallHandler::TrackShmdt(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base) { +void SyscallHandler::TrackShmdt(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base) { uintptr_t Length = 0; { auto lk = FEXCore::GuardSignalDeferringSection(VMATracking.Mutex, Thread); @@ -363,7 +362,7 @@ void SyscallHandler::TrackShmdt(FEXCore::Core::InternalThreadState *Thread, uint } } -void SyscallHandler::TrackMadvise(FEXCore::Core::InternalThreadState *Thread, uintptr_t Base, uintptr_t Size, int advice) { +void SyscallHandler::TrackMadvise(FEXCore::Core::InternalThreadState* Thread, uintptr_t Base, uintptr_t Size, int advice) { Size = FEXCore::AlignUp(Size, FEXCore::Utils::FEX_PAGE_SIZE); { auto lk = FEXCore::GuardSignalDeferringSection(VMATracking.Mutex, Thread); @@ -371,4 +370,4 @@ void SyscallHandler::TrackMadvise(FEXCore::Core::InternalThreadState *Thread, ui } } -} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsVMATracking.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsVMATracking.cpp index f60940ede..ab40d17d0 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsVMATracking.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsVMATracking.cpp @@ -12,7 +12,7 @@ $end_info$ namespace FEX::HLE { /// List Operations /// -inline void SyscallHandler::VMATracking::ListCheckVMALinks(VMAEntry *VMA) { +inline void SyscallHandler::VMATracking::ListCheckVMALinks(VMAEntry* VMA) { if (VMA) { LOGMAN_THROW_A_FMT(VMA->ResourceNextVMA != VMA, "VMA tracking error"); LOGMAN_THROW_A_FMT(VMA->ResourcePrevVMA != VMA, "VMA tracking error"); @@ -21,7 +21,7 @@ inline void SyscallHandler::VMATracking::ListCheckVMALinks(VMAEntry *VMA) { // Removes a VMA from corresponding MappedResource list // Returns true if list is empty -bool SyscallHandler::VMATracking::ListRemove(VMAEntry *VMA) { +bool SyscallHandler::VMATracking::ListRemove(VMAEntry* VMA) { LOGMAN_THROW_A_FMT(VMA->Resource != nullptr, "VMA tracking error"); // if it has prev, make prev to next @@ -55,7 +55,7 @@ bool SyscallHandler::VMATracking::ListRemove(VMAEntry *VMA) { // Replaces a VMA in corresponding MappedResource list // Requires NewVMA->Resource, NewVMA->ResourcePrevVMA and NewVMA->ResourceNextVMA to be already setup -void SyscallHandler::VMATracking::ListReplace(VMAEntry *VMA, VMAEntry *NewVMA) { +void SyscallHandler::VMATracking::ListReplace(VMAEntry* VMA, VMAEntry* NewVMA) { LOGMAN_THROW_A_FMT(VMA->Resource != nullptr, "VMA tracking error"); LOGMAN_THROW_A_FMT(VMA->Resource == NewVMA->Resource, "VMA tracking error"); @@ -84,7 +84,7 @@ void SyscallHandler::VMATracking::ListReplace(VMAEntry *VMA, VMAEntry *NewVMA) { // Inserts a VMA in corresponding MappedResource list // Requires NewVMA->Resource, NewVMA->ResourcePrevVMA and NewVMA->ResourceNextVMA to be already setup -void SyscallHandler::VMATracking::ListInsertAfter(VMAEntry *AfterVMA, VMAEntry *NewVMA) { +void SyscallHandler::VMATracking::ListInsertAfter(VMAEntry* AfterVMA, VMAEntry* NewVMA) { LOGMAN_THROW_A_FMT(NewVMA->Resource != nullptr, "VMA tracking error"); LOGMAN_THROW_A_FMT(AfterVMA->Resource == NewVMA->Resource, "VMA tracking error"); @@ -105,7 +105,7 @@ void SyscallHandler::VMATracking::ListInsertAfter(VMAEntry *AfterVMA, VMAEntry * // Prepends a VMA // Requires NewVMA->Resource, NewVMA->ResourcePrevVMA and NewVMA->ResourceNextVMA to be already setup -void SyscallHandler::VMATracking::ListPrepend(MappedResource *Resource, VMAEntry *NewVMA) { +void SyscallHandler::VMATracking::ListPrepend(MappedResource* Resource, VMAEntry* NewVMA) { LOGMAN_THROW_A_FMT(Resource != nullptr, "VMA tracking error"); LOGMAN_THROW_A_FMT(NewVMA->Resource == Resource, "VMA tracking error"); @@ -142,13 +142,13 @@ SyscallHandler::VMATracking::VMACIterator SyscallHandler::VMATracking::LookupVMA } // Set or Replace mappings in a range with a new mapping -void SyscallHandler::VMATracking::SetUnsafe(FEXCore::Context::Context *CTX, MappedResource *MappedResource, uintptr_t Base, +void SyscallHandler::VMATracking::SetUnsafe(FEXCore::Context::Context* CTX, MappedResource* MappedResource, uintptr_t Base, uintptr_t Offset, uintptr_t Length, VMAFlags Flags, VMAProt Prot) { ClearUnsafe(CTX, Base, Length, MappedResource); auto [Iter, Inserted] = VMAs.emplace( - Base, VMAEntry{MappedResource, nullptr, MappedResource ? MappedResource->FirstVMA : nullptr, Base, Offset, Length, Flags, Prot}); - + Base, VMAEntry {MappedResource, nullptr, MappedResource ? MappedResource->FirstVMA : nullptr, Base, Offset, Length, Flags, Prot}); + LOGMAN_THROW_A_FMT(Inserted == true, "VMA Tracking corruption"); if (MappedResource) { @@ -157,10 +157,10 @@ void SyscallHandler::VMATracking::SetUnsafe(FEXCore::Context::Context *CTX, Mapp } } -// Remove mappings in a range, possibly splitting them if needed and +// Remove mappings in a range, possibly splitting them if needed and // freeing their associated MappedResource unless it is equal to PreservedMappedResource -void SyscallHandler::VMATracking::ClearUnsafe(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, - MappedResource *PreservedMappedResource) { +void SyscallHandler::VMATracking::ClearUnsafe(FEXCore::Context::Context* CTX, uintptr_t Base, uintptr_t Length, + MappedResource* PreservedMappedResource) { const auto Top = Base + Length; // find the first Mapping at or after the Range ends, or ::end() @@ -219,8 +219,8 @@ void SyscallHandler::VMATracking::ClearUnsafe(FEXCore::Context::Context *CTX, ui auto NewOffset = OffsetDiff + Top; auto NewLength = MapTop - Top; - auto [Iter, Inserted] = VMAs.emplace( - Top, VMAEntry{Current->Resource, ReplaceAndErase ? Current->ResourcePrevVMA : Current, Current->ResourceNextVMA, Top, NewOffset, NewLength, Current->Flags, Current->Prot}); + auto [Iter, Inserted] = VMAs.emplace(Top, VMAEntry {Current->Resource, ReplaceAndErase ? Current->ResourcePrevVMA : Current, + Current->ResourceNextVMA, Top, NewOffset, NewLength, Current->Flags, Current->Prot}); LOGMAN_THROW_A_FMT(Inserted == true, "VMA tracking error"); auto TrailingPart = &Iter->second; if (Current->Resource) { @@ -284,7 +284,7 @@ void SyscallHandler::VMATracking::ChangeUnsafe(uintptr_t Base, uintptr_t Length, auto NewLength = Top - Base; auto [Iter, Inserted] = - VMAs.emplace(Base, VMAEntry{Current->Resource, Current, Current->ResourceNextVMA, Base, NewOffset, NewLength, MapFlags, NewProt}); + VMAs.emplace(Base, VMAEntry {Current->Resource, Current, Current->ResourceNextVMA, Base, NewOffset, NewLength, MapFlags, NewProt}); LOGMAN_THROW_A_FMT(Inserted == true, "VMA tracking error"); auto RestOfMapping = &Iter->second; @@ -311,7 +311,7 @@ void SyscallHandler::VMATracking::ChangeUnsafe(uintptr_t Base, uintptr_t Length, auto NewLength = MapTop - Top; auto [Iter, Inserted] = - VMAs.emplace(Top, VMAEntry{Current->Resource, Current, Current->ResourceNextVMA, Top, NewOffset, NewLength, MapFlags, MapProt}); + VMAs.emplace(Top, VMAEntry {Current->Resource, Current, Current->ResourceNextVMA, Top, NewOffset, NewLength, MapFlags, MapProt}); LOGMAN_THROW_A_FMT(Inserted == true, "VMA tracking error"); auto TrailingMapping = &Iter->second; @@ -324,7 +324,7 @@ void SyscallHandler::VMATracking::ChangeUnsafe(uintptr_t Base, uintptr_t Length, } // This matches the peculiarities algorithm used in linux ksys_shmdt (linux kernel 5.16, ipc/shm.c) -uintptr_t SyscallHandler::VMATracking::ClearShmUnsafe(FEXCore::Context::Context *CTX, uintptr_t Base) { +uintptr_t SyscallHandler::VMATracking::ClearShmUnsafe(FEXCore::Context::Context* CTX, uintptr_t Base) { // Find first VMA at or after Base // Iterate until first SHM VMA, with matching offset, get length @@ -337,7 +337,7 @@ uintptr_t SyscallHandler::VMATracking::ClearShmUnsafe(FEXCore::Context::Context LOGMAN_THROW_A_FMT(Entry->second.Base >= Base, "VMA tracking corruption"); if (Entry->second.Base - Base == Entry->second.Offset && Entry->second.Resource && Entry->second.Resource->Iterator->first.dev == SpecialDev::SHM) { - break; + break; } } @@ -364,4 +364,4 @@ uintptr_t SyscallHandler::VMATracking::ClearShmUnsafe(FEXCore::Context::Context return ShmLength; } -} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp index e6ae03a3b..4297152e4 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp @@ -6,241 +6,235 @@ #include namespace FEX::HLE { - FEXCore::Core::InternalThreadState *ThreadManager::CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID) { - auto Thread = CTX->CreateThread(InitialRIP, StackPointer, NewThreadState, ParentTID); +FEXCore::Core::InternalThreadState* +ThreadManager::CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState, uint64_t ParentTID) { + auto Thread = CTX->CreateThread(InitialRIP, StackPointer, NewThreadState, ParentTID); - ++IdleWaitRefCount; - return Thread; + ++IdleWaitRefCount; + return Thread; +} + +void ThreadManager::DestroyThread(FEXCore::Core::InternalThreadState* Thread) { + { + std::lock_guard lk(ThreadCreationMutex); + auto It = std::find(Threads.begin(), Threads.end(), Thread); + LOGMAN_THROW_A_FMT(It != Threads.end(), "Thread wasn't in Threads"); + Threads.erase(It); } - void ThreadManager::DestroyThread(FEXCore::Core::InternalThreadState *Thread) { - { - std::lock_guard lk(ThreadCreationMutex); - auto It = std::find(Threads.begin(), Threads.end(), Thread); - LOGMAN_THROW_A_FMT(It != Threads.end(), "Thread wasn't in Threads"); - Threads.erase(It); + HandleThreadDeletion(Thread); +} + +void ThreadManager::StopThread(FEXCore::Core::InternalThreadState* Thread) { + if (Thread->RunningEvents.Running.exchange(false)) { + SignalDelegation->SignalThread(Thread, FEXCore::Core::SignalEvent::Stop); + } +} + +void ThreadManager::RunThread(FEXCore::Core::InternalThreadState* Thread) { + // Tell the thread to start executing + Thread->StartRunning.NotifyAll(); +} + +void ThreadManager::HandleThreadDeletion(FEXCore::Core::InternalThreadState* Thread) { + if (Thread->ExecutionThread) { + if (Thread->ExecutionThread->joinable()) { + Thread->ExecutionThread->join(nullptr); } - HandleThreadDeletion(Thread); - } - - void ThreadManager::StopThread(FEXCore::Core::InternalThreadState *Thread) { - if (Thread->RunningEvents.Running.exchange(false)) { - SignalDelegation->SignalThread(Thread, FEXCore::Core::SignalEvent::Stop); + if (Thread->ExecutionThread->IsSelf()) { + Thread->ExecutionThread->detach(); } } - void ThreadManager::RunThread(FEXCore::Core::InternalThreadState *Thread) { - // Tell the thread to start executing + CTX->DestroyThread(Thread); + --IdleWaitRefCount; + IdleWaitCV.notify_all(); +} + +void ThreadManager::NotifyPause() { + // Tell all the threads that they should pause + std::lock_guard lk(ThreadCreationMutex); + for (auto& Thread : Threads) { + SignalDelegation->SignalThread(Thread, FEXCore::Core::SignalEvent::Pause); + } +} + +void ThreadManager::Pause() { + NotifyPause(); + WaitForIdle(); +} + +void ThreadManager::Run() { + // Spin up all the threads + std::lock_guard lk(ThreadCreationMutex); + for (auto& Thread : Threads) { + Thread->SignalReason.store(FEXCore::Core::SignalEvent::Return); + } + + for (auto& Thread : Threads) { Thread->StartRunning.NotifyAll(); } +} - void ThreadManager::HandleThreadDeletion(FEXCore::Core::InternalThreadState *Thread) { - if (Thread->ExecutionThread) { - if (Thread->ExecutionThread->joinable()) { - Thread->ExecutionThread->join(nullptr); - } +void ThreadManager::WaitForIdleWithTimeout() { + std::unique_lock lk(IdleWaitMutex); + bool WaitResult = IdleWaitCV.wait_for(lk, std::chrono::milliseconds(1500), [this] { return IdleWaitRefCount.load() == 0; }); - if (Thread->ExecutionThread->IsSelf()) { - Thread->ExecutionThread->detach(); - } - } - - CTX->DestroyThread(Thread); - --IdleWaitRefCount; - IdleWaitCV.notify_all(); - } - - void ThreadManager::NotifyPause() { - // Tell all the threads that they should pause - std::lock_guard lk(ThreadCreationMutex); - for (auto &Thread : Threads) { - SignalDelegation->SignalThread(Thread, FEXCore::Core::SignalEvent::Pause); - } - } - - void ThreadManager::Pause() { + if (!WaitResult) { + // The wait failed, this will occur if we stepped in to a syscall + // That's okay, we just need to pause the threads manually NotifyPause(); - WaitForIdle(); } - void ThreadManager::Run() { - // Spin up all the threads + // We have sent every thread a pause signal + // Now wait again because they /will/ be going to sleep + WaitForIdle(); +} + +void ThreadManager::WaitForThreadsToRun() { + size_t NumThreads {}; + { std::lock_guard lk(ThreadCreationMutex); - for (auto &Thread : Threads) { - Thread->SignalReason.store(FEXCore::Core::SignalEvent::Return); - } + NumThreads = Threads.size(); + } - for (auto &Thread : Threads) { - Thread->StartRunning.NotifyAll(); + // Spin while waiting for the threads to start up + std::unique_lock lk(IdleWaitMutex); + IdleWaitCV.wait(lk, [this, NumThreads] { return IdleWaitRefCount.load() >= NumThreads; }); + + Running = true; +} + +void ThreadManager::Step() { + LogMan::Msg::AFmt("ThreadManager::Step currently not implemented"); + { + std::lock_guard lk(ThreadCreationMutex); + // Walk the threads and tell them to clear their caches + // Useful when our block size is set to a large number and we need to step a single instruction + for (auto& Thread : Threads) { + CTX->ClearCodeCache(Thread); } } - void ThreadManager::WaitForIdleWithTimeout() { - std::unique_lock lk(IdleWaitMutex); - bool WaitResult = IdleWaitCV.wait_for(lk, std::chrono::milliseconds(1500), - [this] { - return IdleWaitRefCount.load() == 0; - }); + // TODO: Set to single step mode. + Run(); + WaitForThreadsToRun(); + WaitForIdle(); + // TODO: Set back to full running mode. +} - if (!WaitResult) { - // The wait failed, this will occur if we stepped in to a syscall - // That's okay, we just need to pause the threads manually - NotifyPause(); - } +void ThreadManager::Stop(bool IgnoreCurrentThread) { + pid_t tid = FHU::Syscalls::gettid(); + FEXCore::Core::InternalThreadState* CurrentThread {}; - // We have sent every thread a pause signal - // Now wait again because they /will/ be going to sleep - WaitForIdle(); - } - - void ThreadManager::WaitForThreadsToRun() { - size_t NumThreads{}; - { - std::lock_guard lk(ThreadCreationMutex); - NumThreads = Threads.size(); - } - - // Spin while waiting for the threads to start up - std::unique_lock lk(IdleWaitMutex); - IdleWaitCV.wait(lk, [this, NumThreads] { - return IdleWaitRefCount.load() >= NumThreads; - }); - - Running = true; - } - - void ThreadManager::Step() { - LogMan::Msg::AFmt("ThreadManager::Step currently not implemented"); - { - std::lock_guard lk(ThreadCreationMutex); - // Walk the threads and tell them to clear their caches - // Useful when our block size is set to a large number and we need to step a single instruction - for (auto &Thread : Threads) { - CTX->ClearCodeCache(Thread); - } - } - - // TODO: Set to single step mode. - Run(); - WaitForThreadsToRun(); - WaitForIdle(); - // TODO: Set back to full running mode. - } - - void ThreadManager::Stop(bool IgnoreCurrentThread) { - pid_t tid = FHU::Syscalls::gettid(); - FEXCore::Core::InternalThreadState* CurrentThread{}; - - // Tell all the threads that they should stop - { - std::lock_guard lk(ThreadCreationMutex); - for (auto &Thread : Threads) { - if (IgnoreCurrentThread && - Thread->ThreadManager.TID == tid) { - // If we are callign stop from the current thread then we can ignore sending signals to this thread - // This means that this thread is already gone - } - else if (Thread->ThreadManager.TID == tid) { - // We need to save the current thread for last to ensure all threads receive their stop signals - CurrentThread = Thread; - continue; - } - - if (Thread->RunningEvents.Running.load()) { - StopThread(Thread); - } - - // If the thread is waiting to start but immediately killed then there can be a hang - // This occurs in the case of gdb attach with immediate kill - if (Thread->RunningEvents.WaitingToStart.load()) { - Thread->RunningEvents.EarlyExit = true; - Thread->StartRunning.NotifyAll(); - } - } - } - - // Stop the current thread now if we aren't ignoring it - if (CurrentThread) { - StopThread(CurrentThread); - } - } - - void ThreadManager::SleepThread(FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame) { - auto Thread = Frame->Thread; - - --IdleWaitRefCount; - IdleWaitCV.notify_all(); - - Thread->RunningEvents.ThreadSleeping = true; - - // Go to sleep - Thread->StartRunning.Wait(); - - Thread->RunningEvents.Running = true; - ++IdleWaitRefCount; - Thread->RunningEvents.ThreadSleeping = false; - - IdleWaitCV.notify_all(); - } - - void ThreadManager::UnlockAfterFork(FEXCore::Core::InternalThreadState *LiveThread, bool Child) { - if (!Child) return; - - // This function is called after fork - // We need to cleanup some of the thread data that is dead - for (auto &DeadThread : Threads) { - if (DeadThread == LiveThread) { + // Tell all the threads that they should stop + { + std::lock_guard lk(ThreadCreationMutex); + for (auto& Thread : Threads) { + if (IgnoreCurrentThread && Thread->ThreadManager.TID == tid) { + // If we are callign stop from the current thread then we can ignore sending signals to this thread + // This means that this thread is already gone + } else if (Thread->ThreadManager.TID == tid) { + // We need to save the current thread for last to ensure all threads receive their stop signals + CurrentThread = Thread; continue; } - // Setting running to false ensures that when they are shutdown we won't send signals to kill them - DeadThread->RunningEvents.Running = false; + if (Thread->RunningEvents.Running.load()) { + StopThread(Thread); + } - // Despite what google searches may susgest, glibc actually has special code to handle forks - // with multiple active threads. - // It cleans up the stacks of dead threads and marks them as terminated. - // It also cleans up a bunch of internal mutexes. - - // FIXME: TLS is probally still alive. Investigate - - // Deconstructing the Interneal thread state should clean up most of the state. - // But if anything on the now deleted stack is holding a refrence to the heap, it will be leaked - CTX->DestroyThread(DeadThread); - - // FIXME: Make sure sure nothing gets leaked via the heap. Ideas: - // * Make sure nothing is allocated on the heap without ref in InternalThreadState - // * Surround any code that heap allocates with a per-thread mutex. - // Before forking, the the forking thread can lock all thread mutexes. + // If the thread is waiting to start but immediately killed then there can be a hang + // This occurs in the case of gdb attach with immediate kill + if (Thread->RunningEvents.WaitingToStart.load()) { + Thread->RunningEvents.EarlyExit = true; + Thread->StartRunning.NotifyAll(); + } } - - // Remove all threads but the live thread from Threads - Threads.clear(); - Threads.push_back(LiveThread); - - // Clean up dead stacks - FEXCore::Threads::Thread::CleanupAfterFork(); - - // We now only have one thread. - IdleWaitRefCount = 1; - ThreadCreationMutex.StealAndDropActiveLocks(); } - void ThreadManager::WaitForIdle() { - std::unique_lock lk(IdleWaitMutex); - IdleWaitCV.wait(lk, [this] { - return IdleWaitRefCount.load() == 0; - }); - - Running = false; - } - - ThreadManager::~ThreadManager() { - std::lock_guard lk(ThreadCreationMutex); - - for (auto &Thread : Threads) { - HandleThreadDeletion(Thread); - } - Threads.clear(); + // Stop the current thread now if we aren't ignoring it + if (CurrentThread) { + StopThread(CurrentThread); } } + +void ThreadManager::SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame) { + auto Thread = Frame->Thread; + + --IdleWaitRefCount; + IdleWaitCV.notify_all(); + + Thread->RunningEvents.ThreadSleeping = true; + + // Go to sleep + Thread->StartRunning.Wait(); + + Thread->RunningEvents.Running = true; + ++IdleWaitRefCount; + Thread->RunningEvents.ThreadSleeping = false; + + IdleWaitCV.notify_all(); +} + +void ThreadManager::UnlockAfterFork(FEXCore::Core::InternalThreadState* LiveThread, bool Child) { + if (!Child) { + return; + } + + // This function is called after fork + // We need to cleanup some of the thread data that is dead + for (auto& DeadThread : Threads) { + if (DeadThread == LiveThread) { + continue; + } + + // Setting running to false ensures that when they are shutdown we won't send signals to kill them + DeadThread->RunningEvents.Running = false; + + // Despite what google searches may susgest, glibc actually has special code to handle forks + // with multiple active threads. + // It cleans up the stacks of dead threads and marks them as terminated. + // It also cleans up a bunch of internal mutexes. + + // FIXME: TLS is probally still alive. Investigate + + // Deconstructing the Interneal thread state should clean up most of the state. + // But if anything on the now deleted stack is holding a refrence to the heap, it will be leaked + CTX->DestroyThread(DeadThread); + + // FIXME: Make sure sure nothing gets leaked via the heap. Ideas: + // * Make sure nothing is allocated on the heap without ref in InternalThreadState + // * Surround any code that heap allocates with a per-thread mutex. + // Before forking, the the forking thread can lock all thread mutexes. + } + + // Remove all threads but the live thread from Threads + Threads.clear(); + Threads.push_back(LiveThread); + + // Clean up dead stacks + FEXCore::Threads::Thread::CleanupAfterFork(); + + // We now only have one thread. + IdleWaitRefCount = 1; + ThreadCreationMutex.StealAndDropActiveLocks(); +} + +void ThreadManager::WaitForIdle() { + std::unique_lock lk(IdleWaitMutex); + IdleWaitCV.wait(lk, [this] { return IdleWaitRefCount.load() == 0; }); + + Running = false; +} + +ThreadManager::~ThreadManager() { + std::lock_guard lk(ThreadCreationMutex); + + for (auto& Thread : Threads) { + HandleThreadDeletion(Thread); + } + Threads.clear(); +} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Types.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Types.h index afacab531..352ef9e52 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Types.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Types.h @@ -60,7 +60,7 @@ struct FEX_PACKED epoll_event_x86 { epoll_event_x86() = delete; operator struct epoll_event() const { - epoll_event event{}; + epoll_event event {}; event.events = events; event.data = data; return event; @@ -78,16 +78,16 @@ static_assert(sizeof(epoll_event_x86) == 12, "Incorrect size"); // Due to the way this definition cyclic depends inside of includes, redefine it // This works around some terrible compile errors on some platforms struct fex_seminfo { - int32_t semmap; - int32_t semmni; - int32_t semmns; - int32_t semmnu; - int32_t semmsl; - int32_t semopm; - int32_t semume; - int32_t semusz; - int32_t semvmx; - int32_t semaem; + int32_t semmap; + int32_t semmni; + int32_t semmns; + int32_t semmnu; + int32_t semmsl; + int32_t semopm; + int32_t semume; + int32_t semusz; + int32_t semvmx; + int32_t semaem; }; struct FEX_PACKED GuestSAMask { @@ -97,7 +97,7 @@ struct FEX_PACKED GuestSAMask { struct FEX_PACKED GuestSigAction { union { void (*handler)(int); - void (*sigaction)(int, siginfo_t *, void*); + void (*sigaction)(int, siginfo_t*, void*); } sigaction_handler; uint64_t sa_flags; @@ -105,4 +105,4 @@ struct FEX_PACKED GuestSigAction { GuestSAMask sa_mask; }; -} +} // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp index d49f05cbf..e3c0ca4a6 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp @@ -8,107 +8,102 @@ #include namespace FEX::LinuxEmulation::Threads { - // Stack pool handling - struct StackPoolItem { - void *Ptr; - size_t Size; - }; +// Stack pool handling +struct StackPoolItem { + void* Ptr; + size_t Size; +}; - struct DeadStackPoolItem { - void *Ptr; - size_t Size; - bool ReadyToBeReaped; - }; +struct DeadStackPoolItem { + void* Ptr; + size_t Size; + bool ReadyToBeReaped; +}; - std::mutex DeadStackPoolMutex{}; - std::mutex LiveStackPoolMutex{}; +std::mutex DeadStackPoolMutex {}; +std::mutex LiveStackPoolMutex {}; - static fextl::deque DeadStackPool{}; - static fextl::deque LiveStackPool{}; +static fextl::deque DeadStackPool {}; +static fextl::deque LiveStackPool {}; - void *AllocateStackObject() { - std::lock_guard lk{DeadStackPoolMutex}; - // Keep the first item in the stack pool - void *Ptr{}; +void* AllocateStackObject() { + std::lock_guard lk {DeadStackPoolMutex}; + // Keep the first item in the stack pool + void* Ptr {}; - for (auto it = DeadStackPool.begin(); it != DeadStackPool.end();) { - auto Ready = std::atomic_ref(it->ReadyToBeReaped); - bool ReadyToBeReaped = Ready.load(); - if (Ptr == nullptr && ReadyToBeReaped) { - Ptr = it->Ptr; - it = DeadStackPool.erase(it); - continue; - } - - if (ReadyToBeReaped) { - FEXCore::Allocator::munmap(it->Ptr, it->Size); - it = DeadStackPool.erase(it); - continue; - } - - ++it; + for (auto it = DeadStackPool.begin(); it != DeadStackPool.end();) { + auto Ready = std::atomic_ref(it->ReadyToBeReaped); + bool ReadyToBeReaped = Ready.load(); + if (Ptr == nullptr && ReadyToBeReaped) { + Ptr = it->Ptr; + it = DeadStackPool.erase(it); + continue; } - if (Ptr == nullptr) { - Ptr = FEXCore::Allocator::mmap(nullptr, FEX::LinuxEmulation::Threads::STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ReadyToBeReaped) { + FEXCore::Allocator::munmap(it->Ptr, it->Size); + it = DeadStackPool.erase(it); + continue; } - return Ptr; + ++it; } - bool *AddStackToDeadPool(void *Ptr) { - std::lock_guard lk{DeadStackPoolMutex}; - auto &it = DeadStackPool.emplace_back(DeadStackPoolItem{Ptr, FEX::LinuxEmulation::Threads::STACK_SIZE, false}); - return &it.ReadyToBeReaped; + if (Ptr == nullptr) { + Ptr = FEXCore::Allocator::mmap(nullptr, FEX::LinuxEmulation::Threads::STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } - void AddStackToLivePool(void *Ptr) { - std::lock_guard lk{LiveStackPoolMutex}; - LiveStackPool.emplace_back(StackPoolItem{Ptr, FEX::LinuxEmulation::Threads::STACK_SIZE}); - } + return Ptr; +} - void RemoveStackFromLivePool(void *Ptr) { - std::lock_guard lk{LiveStackPoolMutex}; - for (auto it = LiveStackPool.begin(); it != LiveStackPool.end(); ++it) { - if (it->Ptr == Ptr) { - LiveStackPool.erase(it); - return; - } +bool* AddStackToDeadPool(void* Ptr) { + std::lock_guard lk {DeadStackPoolMutex}; + auto& it = DeadStackPool.emplace_back(DeadStackPoolItem {Ptr, FEX::LinuxEmulation::Threads::STACK_SIZE, false}); + return &it.ReadyToBeReaped; +} + +void AddStackToLivePool(void* Ptr) { + std::lock_guard lk {LiveStackPoolMutex}; + LiveStackPool.emplace_back(StackPoolItem {Ptr, FEX::LinuxEmulation::Threads::STACK_SIZE}); +} + +void RemoveStackFromLivePool(void* Ptr) { + std::lock_guard lk {LiveStackPoolMutex}; + for (auto it = LiveStackPool.begin(); it != LiveStackPool.end(); ++it) { + if (it->Ptr == Ptr) { + LiveStackPool.erase(it); + return; } } +} - [[noreturn]] - void DeallocateStackObjectAndExit(void *Ptr, int Status) { - RemoveStackFromLivePool(Ptr); - auto ReadyToBeReaped = AddStackToDeadPool(Ptr); - *ReadyToBeReaped = true; +[[noreturn]] +void DeallocateStackObjectAndExit(void* Ptr, int Status) { + RemoveStackFromLivePool(Ptr); + auto ReadyToBeReaped = AddStackToDeadPool(Ptr); + *ReadyToBeReaped = true; #ifdef _M_ARM_64 - __asm volatile( - "mov x8, %[SyscallNum];" - "mov w0, %w[Result];" - "svc #0;" - :: [SyscallNum] "i" (SYSCALL_DEF(exit)) - , [Result] "r" (Status) - : "memory", "x0", "x8"); + __asm volatile("mov x8, %[SyscallNum];" + "mov w0, %w[Result];" + "svc #0;" ::[SyscallNum] "i"(SYSCALL_DEF(exit)), + [Result] "r"(Status) + : "memory", "x0", "x8"); #else - __asm volatile( - "mov %[Result], %%edi;" - "syscall;" - :: "a" (SYSCALL_DEF(exit)) - , [Result] "r" (Status) - : "memory", "rdi"); + __asm volatile("mov %[Result], %%edi;" + "syscall;" ::"a"(SYSCALL_DEF(exit)), + [Result] "r"(Status) + : "memory", "rdi"); #endif - FEX_UNREACHABLE; - } + FEX_UNREACHABLE; +} #ifdef _M_ARM_64 - __attribute__((naked)) - void StackPivotAndCall(void *Arg, FEXCore::Threads::ThreadFunc Func, uint64_t StackPivot) { - // x0: Arg - // x1: Function to call - // x2: StackPivot - __asm volatile(R"( +__attribute__((naked)) void StackPivotAndCall(void* Arg, FEXCore::Threads::ThreadFunc Func, uint64_t StackPivot) { + // x0: Arg + // x1: Function to call + // x2: StackPivot + __asm volatile(R"( // Stack pivot. mov x3, sp; mov sp, x2; @@ -126,16 +121,15 @@ namespace FEX::LinuxEmulation::Threads { mov sp, x2; ret; - )" - ::: "memory"); - } + )" :: + : "memory"); +} #else - __attribute__((naked)) - void StackPivotAndCall(void *Arg, FEXCore::Threads::ThreadFunc Func, uint64_t StackPivot) { - // rdi: Arg - // rsi: Function to call - // rdx: StackPivot - __asm volatile(R"( +__attribute__((naked)) void StackPivotAndCall(void* Arg, FEXCore::Threads::ThreadFunc Func, uint64_t StackPivot) { + // rdi: Arg + // rsi: Function to call + // rdx: StackPivot + __asm volatile(R"( // Copy original stack in to RSP. movq %%rsp, %%rcx; @@ -153,162 +147,160 @@ namespace FEX::LinuxEmulation::Threads { ret; - )" ::: "memory"); - } + )" :: + : "memory"); +} #endif - namespace PThreads { - [[noreturn]] - void *InitializeThread(void *Ptr); +namespace PThreads { + [[noreturn]] + void* InitializeThread(void* Ptr); - class PThread final : public FEXCore::Threads::Thread { - public: - PThread(FEXCore::Threads::ThreadFunc Func, void *Arg) - : UserFunc {Func} - , UserArg {Arg} { - pthread_attr_t Attr{}; - Stack = AllocateStackObject(); - // pthreads allocates its dtv region behind our back and there is nothing we can do about it. - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - AddStackToLivePool(Stack); - pthread_attr_init(&Attr); - // Allocate a minimum size stack through pthreads, then stack pivot to FEX's allocated stack. - // This is required due to a race condition with pthread's DTV/TLS regions when a stack is reused before pthreads deletes that thread's - // DTV/TLS regions. - // This can be seen as a crash when running Steam fairly easily, but is very confusing when debugging. - // The cause of this race condition is from glibc associating a DTV/TLS region with a stack region until the kernel clears the - // `set_tid_address` address construct. If the stack is reused before the address is set to zero, then glibc won't initialize the new thread's - // DTV/TLS region, resulting in TLS usage crashing. - pthread_attr_setstacksize(&Attr, PTHREAD_STACK_MIN); - pthread_create(&Thread, &Attr, InitializeThread, this); - pthread_attr_destroy(&Attr); - } + class PThread final : public FEXCore::Threads::Thread { + public: + PThread(FEXCore::Threads::ThreadFunc Func, void* Arg) + : UserFunc {Func} + , UserArg {Arg} { + pthread_attr_t Attr {}; + Stack = AllocateStackObject(); + // pthreads allocates its dtv region behind our back and there is nothing we can do about it. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + AddStackToLivePool(Stack); + pthread_attr_init(&Attr); + // Allocate a minimum size stack through pthreads, then stack pivot to FEX's allocated stack. + // This is required due to a race condition with pthread's DTV/TLS regions when a stack is reused before pthreads deletes that thread's + // DTV/TLS regions. + // This can be seen as a crash when running Steam fairly easily, but is very confusing when debugging. + // The cause of this race condition is from glibc associating a DTV/TLS region with a stack region until the kernel clears the + // `set_tid_address` address construct. If the stack is reused before the address is set to zero, then glibc won't initialize the new thread's + // DTV/TLS region, resulting in TLS usage crashing. + pthread_attr_setstacksize(&Attr, PTHREAD_STACK_MIN); + pthread_create(&Thread, &Attr, InitializeThread, this); + pthread_attr_destroy(&Attr); + } - bool joinable() override { - pthread_attr_t Attr{}; - if (pthread_getattr_np(Thread, &Attr) == 0) { - int AttachState{}; - if (pthread_attr_getdetachstate(&Attr, &AttachState) == 0) { - if (AttachState == PTHREAD_CREATE_JOINABLE) { - return true; - } + bool joinable() override { + pthread_attr_t Attr {}; + if (pthread_getattr_np(Thread, &Attr) == 0) { + int AttachState {}; + if (pthread_attr_getdetachstate(&Attr, &AttachState) == 0) { + if (AttachState == PTHREAD_CREATE_JOINABLE) { + return true; } } - return false; } - - bool join(void **ret) override { - return pthread_join(Thread, ret) == 0; - } - - bool detach() override { - return pthread_detach(Thread) == 0; - } - - bool IsSelf() override { - auto self = pthread_self(); - return self == Thread; - } - - FEXCore::Threads::ThreadFunc GetUserFunc() const { - return UserFunc; - } - - void *GetUserArg() const { - return UserArg; - } - - void *GetPivotStack() const { - return Stack; - } - - private: - pthread_t Thread; - FEXCore::Threads::ThreadFunc UserFunc; - void *UserArg; - void *Stack{}; - }; - - [[noreturn]] - void *InitializeThread(void *Ptr) { - void *StackBase{}; - { - PThread *Thread{reinterpret_cast(Ptr)}; - StackBase = Thread->GetPivotStack(); - - // Run the user function. - // `Thread` object is dead after this function returns. - StackPivotAndCall(Thread->GetUserArg(), Thread->GetUserFunc(), reinterpret_cast(StackBase) + FEX::LinuxEmulation::Threads::STACK_SIZE); - } - - // TLS/DTV teardown is something FEX can't control. Disable glibc checking when we leave a pthread. - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable(); - - DeallocateStackObjectAndExit(StackBase, 0); - - FEX_UNREACHABLE; + return false; } - fextl::unique_ptr CreateThread_PThread( - FEXCore::Threads::ThreadFunc Func, - void* Arg) { - return fextl::make_unique(Func, Arg); + bool join(void** ret) override { + return pthread_join(Thread, ret) == 0; } - void CleanupAfterFork_PThread() { - // We don't need to pull the mutex here - // After a fork we are the only thread running - // Just need to make sure not to delete our own stack - uintptr_t StackLocation = reinterpret_cast(alloca(0)); - - auto ClearStackPool = [&](auto &StackPool) { - for (auto it = StackPool.begin(); it != StackPool.end(); ) { - auto &Item = *it; - uintptr_t ItemStack = reinterpret_cast(Item.Ptr); - if (ItemStack <= StackLocation && (ItemStack + Item.Size) > StackLocation) { - // This is our stack item, skip it - ++it; - } - else { - // Untracked stack. Clean it up - FEXCore::Allocator::munmap(Item.Ptr, Item.Size); - it = StackPool.erase(it); - } - } - }; - - // Clear both dead stacks and live stacks - ClearStackPool(DeadStackPool); - ClearStackPool(LiveStackPool); - - LogMan::Throw::AFmt((DeadStackPool.size() + LiveStackPool.size()) <= 1, - "After fork we should only have zero or one tracked stacks!"); + bool detach() override { + return pthread_detach(Thread) == 0; } + + bool IsSelf() override { + auto self = pthread_self(); + return self == Thread; + } + + FEXCore::Threads::ThreadFunc GetUserFunc() const { + return UserFunc; + } + + void* GetUserArg() const { + return UserArg; + } + + void* GetPivotStack() const { + return Stack; + } + + private: + pthread_t Thread; + FEXCore::Threads::ThreadFunc UserFunc; + void* UserArg; + void* Stack {}; }; - void SetupThreadHandlers() { - FEXCore::Threads::Pointers Ptrs = { - .CreateThread = PThreads::CreateThread_PThread, - .CleanupAfterFork = PThreads::CleanupAfterFork_PThread, + [[noreturn]] + void* InitializeThread(void* Ptr) { + void* StackBase {}; + { + PThread* Thread {reinterpret_cast(Ptr)}; + StackBase = Thread->GetPivotStack(); + + // Run the user function. + // `Thread` object is dead after this function returns. + StackPivotAndCall(Thread->GetUserArg(), Thread->GetUserFunc(), + reinterpret_cast(StackBase) + FEX::LinuxEmulation::Threads::STACK_SIZE); + } + + // TLS/DTV teardown is something FEX can't control. Disable glibc checking when we leave a pthread. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable(); + + DeallocateStackObjectAndExit(StackBase, 0); + + FEX_UNREACHABLE; + } + + fextl::unique_ptr CreateThread_PThread(FEXCore::Threads::ThreadFunc Func, void* Arg) { + return fextl::make_unique(Func, Arg); + } + + void CleanupAfterFork_PThread() { + // We don't need to pull the mutex here + // After a fork we are the only thread running + // Just need to make sure not to delete our own stack + uintptr_t StackLocation = reinterpret_cast(alloca(0)); + + auto ClearStackPool = [&](auto& StackPool) { + for (auto it = StackPool.begin(); it != StackPool.end();) { + auto& Item = *it; + uintptr_t ItemStack = reinterpret_cast(Item.Ptr); + if (ItemStack <= StackLocation && (ItemStack + Item.Size) > StackLocation) { + // This is our stack item, skip it + ++it; + } else { + // Untracked stack. Clean it up + FEXCore::Allocator::munmap(Item.Ptr, Item.Size); + it = StackPool.erase(it); + } + } }; - FEXCore::Threads::Thread::SetInternalPointers(Ptrs); + // Clear both dead stacks and live stacks + ClearStackPool(DeadStackPool); + ClearStackPool(LiveStackPool); + + LogMan::Throw::AFmt((DeadStackPool.size() + LiveStackPool.size()) <= 1, "After fork we should only have zero or one tracked stacks!"); } +}; // namespace PThreads - void Shutdown() { - std::lock_guard lk{DeadStackPoolMutex}; - std::lock_guard lk2{LiveStackPoolMutex}; - // Erase all the dead stack pools - for (auto &Item : DeadStackPool) { - FEXCore::Allocator::munmap(Item.Ptr, Item.Size); - } +void SetupThreadHandlers() { + FEXCore::Threads::Pointers Ptrs = { + .CreateThread = PThreads::CreateThread_PThread, + .CleanupAfterFork = PThreads::CleanupAfterFork_PThread, + }; - // Now clean up any that are considered to still be live - // We are in shutdown phase, everything in the process is dead - for (auto &Item : LiveStackPool) { - FEXCore::Allocator::munmap(Item.Ptr, Item.Size); - } - - DeadStackPool.clear(); - LiveStackPool.clear(); - } + FEXCore::Threads::Thread::SetInternalPointers(Ptrs); } + +void Shutdown() { + std::lock_guard lk {DeadStackPoolMutex}; + std::lock_guard lk2 {LiveStackPoolMutex}; + // Erase all the dead stack pools + for (auto& Item : DeadStackPool) { + FEXCore::Allocator::munmap(Item.Ptr, Item.Size); + } + + // Now clean up any that are considered to still be live + // We are in shutdown phase, everything in the process is dead + for (auto& Item : LiveStackPool) { + FEXCore::Allocator::munmap(Item.Ptr, Item.Size); + } + + DeadStackPool.clear(); + LiveStackPool.clear(); +} +} // namespace FEX::LinuxEmulation::Threads diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.h index 8b6bbd0f7..db4b53efa 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.h @@ -4,34 +4,34 @@ #include namespace FEX::LinuxEmulation::Threads { - /** - * @brief Size of the stack that this interface creates. - */ - constexpr size_t STACK_SIZE = 8 * 1024 * 1024; +/** + * @brief Size of the stack that this interface creates. + */ +constexpr size_t STACK_SIZE = 8 * 1024 * 1024; - /** - * @brief Allocates a stack object from the internally managed stack pool. - */ - void *AllocateStackObject(); +/** + * @brief Allocates a stack object from the internally managed stack pool. + */ +void* AllocateStackObject(); - /** - * @brief Deallocates a stack from the internally managed stack pool. - * - * Will not free the memory immediately, instead saving for reuse temporarily to solve race conditions on stack usage while stack tears down. - * - * @param Ptr The stack base from `AllocateStackObject` - * @param Status The status to pass to the exit syscall. - */ - [[noreturn]] - void DeallocateStackObjectAndExit(void *Ptr, int Status); +/** + * @brief Deallocates a stack from the internally managed stack pool. + * + * Will not free the memory immediately, instead saving for reuse temporarily to solve race conditions on stack usage while stack tears down. + * + * @param Ptr The stack base from `AllocateStackObject` + * @param Status The status to pass to the exit syscall. + */ +[[noreturn]] +void DeallocateStackObjectAndExit(void* Ptr, int Status); - /** - * @brief Registers thread creation handlers with FEXCore. - */ - void SetupThreadHandlers(); +/** + * @brief Registers thread creation handlers with FEXCore. + */ +void SetupThreadHandlers(); - /** - * @brief Cleans up any remaining stack objects in the pools. - */ - void Shutdown(); -} +/** + * @brief Cleans up any remaining stack objects in the pools. + */ +void Shutdown(); +} // namespace FEX::LinuxEmulation::Threads diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp index 569bff88a..844d4a212 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp @@ -25,12 +25,14 @@ ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { - void RegisterEpoll(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(epoll_wait, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, compat_ptr events, int maxevents, int timeout) -> uint64_t { +void RegisterEpoll(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32( + epoll_wait, + [](FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevents, int timeout) -> uint64_t { fextl::vector Events(std::max(0, maxevents)); uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevents, timeout, nullptr, 8); @@ -42,63 +44,55 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(epoll_ctl, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, int op, int fd, compat_ptr event) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + epoll_ctl, [](FEXCore::Core::CpuStateFrame* Frame, int epfd, int op, int fd, compat_ptr event) -> uint64_t { struct epoll_event Event = *event; uint64_t Result = ::syscall(SYSCALL_DEF(epoll_ctl), epfd, op, fd, &Event); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(epoll_pwait, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, compat_ptr events, int maxevent, int timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { - fextl::vector Events(std::max(0, maxevent)); + REGISTER_SYSCALL_IMPL_X32(epoll_pwait, + [](FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevent, + int timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { + fextl::vector Events(std::max(0, maxevent)); - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), - epfd, - Events.data(), - maxevent, - timeout, - sigmask, - sigsetsize); + uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevent, timeout, sigmask, sigsetsize); - if (Result != -1) { - for (size_t i = 0; i < Result; ++i) { - events[i] = Events[i]; - } - } + if (Result != -1) { + for (size_t i = 0; i < Result; ++i) { + events[i] = Events[i]; + } + } - SYSCALL_ERRNO(); - }); + SYSCALL_ERRNO(); + }); - if (Handler->IsHostKernelVersionAtLeast(5, 11, 0)) { - REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, compat_ptr events, int maxevent, compat_ptr timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { - fextl::vector Events(std::max(0, maxevent)); + if (Handler->IsHostKernelVersionAtLeast(5, 11, 0)) { + REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, + [](FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, + int maxevent, compat_ptr timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { + fextl::vector Events(std::max(0, maxevent)); - struct timespec tp64{}; - struct timespec *timed_ptr{}; - if (timeout) { - tp64 = *timeout; - timed_ptr = &tp64; - } + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout) { + tp64 = *timeout; + timed_ptr = &tp64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait2), - epfd, - Events.data(), - maxevent, - timed_ptr, - sigmask, - sigsetsize); + uint64_t Result = + ::syscall(SYSCALL_DEF(epoll_pwait2), epfd, Events.data(), maxevent, timed_ptr, sigmask, sigsetsize); - if (Result != -1) { - for (size_t i = 0; i < Result; ++i) { - events[i] = Events[i]; - } - } - - SYSCALL_ERRNO(); - }); - } - else { - REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, UnimplementedSyscallSafe); - } + if (Result != -1) { + for (size_t i = 0; i < Result; ++i) { + events[i] = Events[i]; + } + } + SYSCALL_ERRNO(); + }); + } else { + REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, UnimplementedSyscallSafe); } } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp index 6e5c2ac31..07c7955cc 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp @@ -42,257 +42,239 @@ $end_info$ ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { - // Used to ensure no bogus values are passed into readv/writev family syscalls. - // This is mainly to sanitize vector sizing. It's fine for the bogus value - // itself to pass into the syscall, since the kernel will handle it. - static constexpr int SanitizeIOCount(int count) { - return std::max(0, count); - } +// Used to ensure no bogus values are passed into readv/writev family syscalls. +// This is mainly to sanitize vector sizing. It's fine for the bogus value +// itself to pass into the syscall, since the kernel will handle it. +static constexpr int SanitizeIOCount(int count) { + return std::max(0, count); +} #ifdef _M_X86_64 - uint32_t ioctl_32(FEXCore::Core::CpuStateFrame*, int fd, uint32_t cmd, uint32_t args) { - uint32_t Result{}; - __asm volatile("int $0x80;" - : "=a" (Result) - : "a" (SYSCALL_x86_ioctl) - , "b" (fd) - , "c" (cmd) - , "d" (args) - : "memory"); - return Result; - } +uint32_t ioctl_32(FEXCore::Core::CpuStateFrame*, int fd, uint32_t cmd, uint32_t args) { + uint32_t Result {}; + __asm volatile("int $0x80;" : "=a"(Result) : "a"(SYSCALL_x86_ioctl), "b"(fd), "c"(cmd), "d"(args) : "memory"); + return Result; +} #endif - auto fcntlHandler = [](FEXCore::Core::CpuStateFrame *Frame, int fd, int cmd, uint64_t arg) -> uint64_t { - // fcntl64 struct directly matches the 64bit fcntl op - // cmd just needs to be fixed up - // These are redefined to be their non-64bit tagged value on x86-64 - constexpr int OP_GETLK64_32 = 12; - constexpr int OP_SETLK64_32 = 13; - constexpr int OP_SETLKW64_32 = 14; +auto fcntlHandler = [](FEXCore::Core::CpuStateFrame* Frame, int fd, int cmd, uint64_t arg) -> uint64_t { + // fcntl64 struct directly matches the 64bit fcntl op + // cmd just needs to be fixed up + // These are redefined to be their non-64bit tagged value on x86-64 + constexpr int OP_GETLK64_32 = 12; + constexpr int OP_SETLK64_32 = 13; + constexpr int OP_SETLKW64_32 = 14; - void *lock_arg = (void*)arg; - struct flock tmp{}; - int old_cmd = cmd; + void* lock_arg = (void*)arg; + struct flock tmp {}; + int old_cmd = cmd; + switch (old_cmd) { + case OP_GETLK64_32: { + cmd = F_GETLK; + lock_arg = (void*)&tmp; + tmp = *reinterpret_cast(arg); + break; + } + case OP_SETLK64_32: { + cmd = F_SETLK; + lock_arg = (void*)&tmp; + tmp = *reinterpret_cast(arg); + break; + } + case OP_SETLKW64_32: { + cmd = F_SETLKW; + lock_arg = (void*)&tmp; + tmp = *reinterpret_cast(arg); + break; + } + case F_OFD_SETLK: + case F_OFD_GETLK: + case F_OFD_SETLKW: { + lock_arg = (void*)&tmp; + tmp = *reinterpret_cast(arg); + break; + } + case F_GETLK: + case F_SETLK: + case F_SETLKW: { + lock_arg = (void*)&tmp; + tmp = *reinterpret_cast(arg); + break; + } + + case F_SETFL: lock_arg = reinterpret_cast(FEX::HLE::RemapFromX86Flags(arg)); break; + // Maps directly + case F_DUPFD: + case F_DUPFD_CLOEXEC: + case F_GETFD: + case F_SETFD: + case F_GETFL: break; + + default: LOGMAN_MSG_A_FMT("Unhandled fcntl64: 0x{:x}", cmd); break; + } + + uint64_t Result = ::fcntl(fd, cmd, lock_arg); + + if (Result != -1) { switch (old_cmd) { - case OP_GETLK64_32: { - cmd = F_GETLK; - lock_arg = (void*)&tmp; - tmp = *reinterpret_cast(arg); - break; - } - case OP_SETLK64_32: { - cmd = F_SETLK; - lock_arg = (void*)&tmp; - tmp = *reinterpret_cast(arg); - break; - } - case OP_SETLKW64_32: { - cmd = F_SETLKW; - lock_arg = (void*)&tmp; - tmp = *reinterpret_cast(arg); - break; - } - case F_OFD_SETLK: - case F_OFD_GETLK: - case F_OFD_SETLKW: { - lock_arg = (void*)&tmp; - tmp = *reinterpret_cast(arg); - break; - } - case F_GETLK: - case F_SETLK: - case F_SETLKW: { - lock_arg = (void*)&tmp; - tmp = *reinterpret_cast(arg); - break; - } - - case F_SETFL: - lock_arg = reinterpret_cast(FEX::HLE::RemapFromX86Flags(arg)); - break; - // Maps directly - case F_DUPFD: - case F_DUPFD_CLOEXEC: - case F_GETFD: - case F_SETFD: - case F_GETFL: - break; - - default: - LOGMAN_MSG_A_FMT("Unhandled fcntl64: 0x{:x}", cmd); - break; + case OP_GETLK64_32: { + *reinterpret_cast(arg) = tmp; + break; } + case F_OFD_GETLK: { + *reinterpret_cast(arg) = tmp; + break; + } + case F_GETLK: { + *reinterpret_cast(arg) = tmp; + break; + } break; + case F_DUPFD: + case F_DUPFD_CLOEXEC: FEX::HLE::x32::CheckAndAddFDDuplication(fd, Result); break; + case F_GETFL: { + Result = FEX::HLE::RemapToX86Flags(Result); + break; + } + default: break; + } + } + SYSCALL_ERRNO(); +}; - uint64_t Result = ::fcntl(fd, cmd, lock_arg); +auto selectHandler = [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* readfds, fd_set32* writefds, fd_set32* exceptfds, + struct timeval32* timeout) -> uint64_t { + struct timeval tp64 {}; + if (timeout) { + tp64 = *timeout; + } - if (Result != -1) { - switch (old_cmd) { - case OP_GETLK64_32: { - *reinterpret_cast(arg) = tmp; - break; + fd_set Host_readfds; + fd_set Host_writefds; + fd_set Host_exceptfds; + FD_ZERO(&Host_readfds); + FD_ZERO(&Host_writefds); + FD_ZERO(&Host_exceptfds); + + // Round up to the full 32bit word + uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; + + if (readfds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = readfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_readfds); } - case F_OFD_GETLK: { - *reinterpret_cast(arg) = tmp; - break; - } - case F_GETLK: { - *reinterpret_cast(arg) = tmp; - break; - } - break; - case F_DUPFD: - case F_DUPFD_CLOEXEC: - FEX::HLE::x32::CheckAndAddFDDuplication(fd, Result); - break; - case F_GETFL: { - Result = FEX::HLE::RemapToX86Flags(Result); - break; - } - default: break; } } + } + + if (writefds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = writefds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_writefds); + } + } + } + } + + if (exceptfds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = exceptfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_exceptfds); + } + } + } + } + + uint64_t Result = ::select(nfds, readfds ? &Host_readfds : nullptr, writefds ? &Host_writefds : nullptr, + exceptfds ? &Host_exceptfds : nullptr, timeout ? &tp64 : nullptr); + if (readfds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_readfds)) { + readfds[i / 32] |= 1 << (i & 31); + } else { + readfds[i / 32] &= ~(1 << (i & 31)); + } + } + } + + if (writefds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_writefds)) { + writefds[i / 32] |= 1 << (i & 31); + } else { + writefds[i / 32] &= ~(1 << (i & 31)); + } + } + } + + if (exceptfds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_exceptfds)) { + exceptfds[i / 32] |= 1 << (i & 31); + } else { + exceptfds[i / 32] &= ~(1 << (i & 31)); + } + } + } + + if (timeout) { + *timeout = tp64; + } + SYSCALL_ERRNO(); +}; + +void RegisterFD(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(poll, [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, int timeout) -> uint64_t { + uint64_t Result = ::poll(fds, nfds, timeout); SYSCALL_ERRNO(); - }; + }); - auto selectHandler = [](FEXCore::Core::CpuStateFrame *Frame, int nfds, fd_set32 *readfds, fd_set32 *writefds, fd_set32 *exceptfds, struct timeval32 *timeout) -> uint64_t { - struct timeval tp64{}; - if (timeout) { - tp64 = *timeout; - } + REGISTER_SYSCALL_IMPL_X32(ppoll, + [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, timespec32* timeout_ts, + const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { + // sigsetsize is unused here since it is currently a constant and not exposed through glibc + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout_ts) { + struct timespec32 timeout {}; + if (FaultSafeMemcpy::CopyFromUser(&timeout, timeout_ts, sizeof(timeout)) == EFAULT) { + return -EFAULT; + } - fd_set Host_readfds; - fd_set Host_writefds; - fd_set Host_exceptfds; - FD_ZERO(&Host_readfds); - FD_ZERO(&Host_writefds); - FD_ZERO(&Host_exceptfds); + tp64 = timeout; + timed_ptr = &tp64; + } - // Round up to the full 32bit word - uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; + uint64_t Result = ::syscall(SYSCALL_DEF(ppoll), fds, nfds, timed_ptr, sigmask, sigsetsize); - if (readfds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = readfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_readfds); - } - } - } - } + if (timeout_ts) { + struct timespec32 timeout {}; + timeout = tp64; - if (writefds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = writefds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_writefds); - } - } - } - } + if (FaultSafeMemcpy::CopyToUser(timeout_ts, &timeout, sizeof(timeout)) == EFAULT) { + // Write to user memory failed, this can occur if the timeout is defined in read-only memory. + // This is okay to happen, kernel continues happily. + } + } - if (exceptfds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = exceptfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_exceptfds); - } - } - } - } + SYSCALL_ERRNO(); + }); - uint64_t Result = ::select(nfds, - readfds ? &Host_readfds : nullptr, - writefds ? &Host_writefds : nullptr, - exceptfds ? &Host_exceptfds : nullptr, - timeout ? &tp64 : nullptr); - if (readfds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_readfds)) { - readfds[i/32] |= 1 << (i & 31); - } else { - readfds[i/32] &= ~(1 << (i & 31)); - } - } - } - - if (writefds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_writefds)) { - writefds[i/32] |= 1 << (i & 31); - } else { - writefds[i/32] &= ~(1 << (i & 31)); - } - } - } - - if (exceptfds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_exceptfds)) { - exceptfds[i/32] |= 1 << (i & 31); - } else { - exceptfds[i/32] &= ~(1 << (i & 31)); - } - } - } - - if (timeout) { - *timeout = tp64; - } - SYSCALL_ERRNO(); - }; - - void RegisterFD(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(poll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, int timeout) -> uint64_t { - uint64_t Result = ::poll(fds, nfds, timeout); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(ppoll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, timespec32 *timeout_ts, const uint64_t *sigmask, size_t sigsetsize) -> uint64_t { - // sigsetsize is unused here since it is currently a constant and not exposed through glibc - struct timespec tp64{}; - struct timespec *timed_ptr{}; - if (timeout_ts) { - struct timespec32 timeout{}; - if (FaultSafeMemcpy::CopyFromUser(&timeout, timeout_ts, sizeof(timeout)) == EFAULT) { - return -EFAULT; - } - - tp64 = timeout; - timed_ptr = &tp64; - } - - uint64_t Result = ::syscall(SYSCALL_DEF(ppoll), - fds, - nfds, - timed_ptr, - sigmask, - sigsetsize); - - if (timeout_ts) { - struct timespec32 timeout{}; - timeout = tp64; - - if (FaultSafeMemcpy::CopyToUser(timeout_ts, &timeout, sizeof(timeout)) == EFAULT) { - // Write to user memory failed, this can occur if the timeout is defined in read-only memory. - // This is okay to happen, kernel continues happily. - } - } - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(_llseek, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t fd, uint32_t offset_high, uint32_t offset_low, loff_t *result, uint32_t whence) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + _llseek, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t fd, uint32_t offset_high, uint32_t offset_low, loff_t* result, uint32_t whence) -> uint64_t { uint64_t Offset = offset_high; Offset <<= 32; Offset |= offset_low; @@ -303,574 +285,558 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(readv, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const struct iovec32 *iov, int iovcnt) -> uint64_t { - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - uint64_t Result = ::readv(fd, Host_iovec.data(), iovcnt); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(readv, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, int iovcnt) -> uint64_t { + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + uint64_t Result = ::readv(fd, Host_iovec.data(), iovcnt); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(writev, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const struct iovec32 *iov, int iovcnt) -> uint64_t { - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - uint64_t Result = ::writev(fd, Host_iovec.data(), iovcnt); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(writev, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, int iovcnt) -> uint64_t { + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + uint64_t Result = ::writev(fd, Host_iovec.data(), iovcnt); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(chown32, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t { - uint64_t Result = ::chown(pathname, owner, group); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(chown32, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { + uint64_t Result = ::chown(pathname, owner, group); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(lchown32, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t { - uint64_t Result = ::lchown(pathname, owner, group); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(lchown32, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { + uint64_t Result = ::lchown(pathname, owner, group); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(oldstat, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, oldstat32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); - if (Result != -1) { - if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { - return -EOVERFLOW; - } - if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { - return -EOVERFLOW; - } - - *buf = host_stat; + REGISTER_SYSCALL_IMPL_X32(oldstat, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, oldstat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); + if (Result != -1) { + if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { + return -EOVERFLOW; } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(oldfstat, [](FEXCore::Core::CpuStateFrame *Frame, int fd, oldstat32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = ::fstat(fd, &host_stat); - if (Result != -1) { - if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { - return -EOVERFLOW; - } - if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { - return -EOVERFLOW; - } - - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(oldlstat, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, oldstat32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); - if (Result != -1) { - if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { - return -EOVERFLOW; - } - if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { - return -EOVERFLOW; - } - - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(stat, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, stat32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstat, [](FEXCore::Core::CpuStateFrame *Frame, int fd, stat32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = ::fstat(fd, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(lstat, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, stat32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(stat64, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, stat64_32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(lstat64, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, stat64_32 *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); - - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstat64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, stat64_32 *buf) -> uint64_t { - struct stat64 host_stat; - uint64_t Result = ::fstat64(fd, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(statfs, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, statfs32_32 *buf) -> uint64_t { - struct statfs host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstatfs, [](FEXCore::Core::CpuStateFrame *Frame, int fd, statfs32_32 *buf) -> uint64_t { - struct statfs host_stat; - uint64_t Result = ::fstatfs(fd, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstatfs64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, size_t sz, struct statfs64_32 *buf) -> uint64_t { - LOGMAN_THROW_AA_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); - - struct statfs64 host_stat; - uint64_t Result = ::fstatfs64(fd, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(statfs64, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, size_t sz, struct statfs64_32 *buf) -> uint64_t { - LOGMAN_THROW_AA_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); - - struct statfs host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); - if (Result != -1) { - *buf = host_stat; + if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { + return -EOVERFLOW; } - SYSCALL_ERRNO(); - }); + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); - // x86 32-bit fcntl syscall has a historical quirk that it uses the same handler as fcntl64 - // This is in direct opposition to all other 32-bit architectures that use the compat_fcntl handler - // This quirk goes back to the start of the Linux 2.6.12-rc2 git history. Seeing history before - // that point to see when this quirk happened would be difficult - // - // For more reference, the compat_fcntl handler blocks a few commands: - // - F_GETLK64 - // - F_SETLK64 - // - F_SETLKW64 - // - F_OFD_GETLK - // - F_OFD_SETLK - // - F_OFD_SETLKW - - REGISTER_SYSCALL_IMPL_X32(fcntl, fcntlHandler); - REGISTER_SYSCALL_IMPL_X32(fcntl64, fcntlHandler); - - REGISTER_SYSCALL_IMPL_X32(dup, [](FEXCore::Core::CpuStateFrame *Frame, int oldfd) -> uint64_t { - uint64_t Result = ::dup(oldfd); - if (Result != -1) { - CheckAndAddFDDuplication(oldfd, Result); + REGISTER_SYSCALL_IMPL_X32(oldfstat, [](FEXCore::Core::CpuStateFrame* Frame, int fd, oldstat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = ::fstat(fd, &host_stat); + if (Result != -1) { + if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { + return -EOVERFLOW; } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(dup2, [](FEXCore::Core::CpuStateFrame *Frame, int oldfd, int newfd) -> uint64_t { - uint64_t Result = ::dup2(oldfd, newfd); - if (Result != -1) { - CheckAndAddFDDuplication(oldfd, newfd); + if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { + return -EOVERFLOW; } - SYSCALL_ERRNO(); - }); - REGISTER_SYSCALL_IMPL_X32(preadv, [](FEXCore::Core::CpuStateFrame *Frame, - int fd, - const struct iovec32 *iov, - uint32_t iovcnt, - uint32_t pos_low, - uint32_t pos_high) -> uint64_t { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(oldlstat, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, oldstat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); + if (Result != -1) { + if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { + return -EOVERFLOW; + } + if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { + return -EOVERFLOW; + } + + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(stat, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, stat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(fstat, [](FEXCore::Core::CpuStateFrame* Frame, int fd, stat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = ::fstat(fd, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(lstat, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, stat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(stat64, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, stat64_32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(lstat64, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, stat64_32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); + + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(fstat64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, stat64_32* buf) -> uint64_t { + struct stat64 host_stat; + uint64_t Result = ::fstat64(fd, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(statfs, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, statfs32_32* buf) -> uint64_t { + struct statfs host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(fstatfs, [](FEXCore::Core::CpuStateFrame* Frame, int fd, statfs32_32* buf) -> uint64_t { + struct statfs host_stat; + uint64_t Result = ::fstatfs(fd, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(fstatfs64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, size_t sz, struct statfs64_32* buf) -> uint64_t { + LOGMAN_THROW_AA_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); + + struct statfs64 host_stat; + uint64_t Result = ::fstatfs64(fd, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(statfs64, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, size_t sz, struct statfs64_32* buf) -> uint64_t { + LOGMAN_THROW_AA_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); + + struct statfs host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + + SYSCALL_ERRNO(); + }); + + // x86 32-bit fcntl syscall has a historical quirk that it uses the same handler as fcntl64 + // This is in direct opposition to all other 32-bit architectures that use the compat_fcntl handler + // This quirk goes back to the start of the Linux 2.6.12-rc2 git history. Seeing history before + // that point to see when this quirk happened would be difficult + // + // For more reference, the compat_fcntl handler blocks a few commands: + // - F_GETLK64 + // - F_SETLK64 + // - F_SETLKW64 + // - F_OFD_GETLK + // - F_OFD_SETLK + // - F_OFD_SETLKW + + REGISTER_SYSCALL_IMPL_X32(fcntl, fcntlHandler); + REGISTER_SYSCALL_IMPL_X32(fcntl64, fcntlHandler); + + REGISTER_SYSCALL_IMPL_X32(dup, [](FEXCore::Core::CpuStateFrame* Frame, int oldfd) -> uint64_t { + uint64_t Result = ::dup(oldfd); + if (Result != -1) { + CheckAndAddFDDuplication(oldfd, Result); + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(dup2, [](FEXCore::Core::CpuStateFrame* Frame, int oldfd, int newfd) -> uint64_t { + uint64_t Result = ::dup2(oldfd, newfd); + if (Result != -1) { + CheckAndAddFDDuplication(oldfd, newfd); + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32( + preadv, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high) -> uint64_t { fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); uint64_t Result = ::syscall(SYSCALL_DEF(preadv), fd, Host_iovec.data(), iovcnt, pos_low, pos_high); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(pwritev, [](FEXCore::Core::CpuStateFrame *Frame, - int fd, - const struct iovec32 *iov, - uint32_t iovcnt, - uint32_t pos_low, - uint32_t pos_high) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + pwritev, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high) -> uint64_t { fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); uint64_t Result = ::syscall(SYSCALL_DEF(pwritev), fd, Host_iovec.data(), iovcnt, pos_low, pos_high); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(process_vm_readv, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, const struct iovec32 *local_iov, unsigned long liovcnt, const struct iovec32 *remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { - fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); - fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); + REGISTER_SYSCALL_IMPL_X32(process_vm_readv, + [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, const struct iovec32* local_iov, unsigned long liovcnt, + const struct iovec32* remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { + fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); + fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); - uint64_t Result = ::process_vm_readv(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); - SYSCALL_ERRNO(); - }); + uint64_t Result = + ::process_vm_readv(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(process_vm_writev, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, const struct iovec32 *local_iov, unsigned long liovcnt, const struct iovec32 *remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { - fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); - fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); + REGISTER_SYSCALL_IMPL_X32(process_vm_writev, + [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, const struct iovec32* local_iov, unsigned long liovcnt, + const struct iovec32* remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { + fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); + fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); - uint64_t Result = ::process_vm_writev(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); - SYSCALL_ERRNO(); - }); + uint64_t Result = + ::process_vm_writev(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(preadv2, [](FEXCore::Core::CpuStateFrame *Frame, - int fd, - const struct iovec32 *iov, - uint32_t iovcnt, - uint32_t pos_low, - uint32_t pos_high, - int flags) -> uint64_t { - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + REGISTER_SYSCALL_IMPL_X32(preadv2, + [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, + uint32_t pos_high, int flags) -> uint64_t { + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - uint64_t Result = ::syscall(SYSCALL_DEF(preadv2), fd, Host_iovec.data(), iovcnt, pos_low, pos_high, flags); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(preadv2), fd, Host_iovec.data(), iovcnt, pos_low, pos_high, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(pwritev2, [](FEXCore::Core::CpuStateFrame *Frame, - int fd, - const struct iovec32 *iov, - uint32_t iovcnt, - uint32_t pos_low, - uint32_t pos_high, - int flags) -> uint64_t { - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + REGISTER_SYSCALL_IMPL_X32(pwritev2, + [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, + uint32_t pos_high, int flags) -> uint64_t { + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - uint64_t Result = ::syscall(SYSCALL_DEF(pwritev2), fd, Host_iovec.data(),iovcnt, pos_low, pos_high, flags); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(pwritev2), fd, Host_iovec.data(), iovcnt, pos_low, pos_high, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(fstatat_64, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, stat64_32 *buf, int flag) -> uint64_t { - struct stat64 host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.NewFSStatAt64(dirfd, pathname, &host_stat, flag); - if (Result != -1) { - *buf = host_stat; + REGISTER_SYSCALL_IMPL_X32(fstatat_64, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, stat64_32* buf, int flag) -> uint64_t { + struct stat64 host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.NewFSStatAt64(dirfd, pathname, &host_stat, flag); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(ioctl, ioctl32); + + REGISTER_SYSCALL_IMPL_X32(getdents, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* dirp, uint32_t count) -> uint64_t { + return GetDentsEmulation(fd, reinterpret_cast(dirp), count); + }); + + REGISTER_SYSCALL_IMPL_X32(getdents64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* dirp, uint32_t count) -> uint64_t { + uint64_t Result = ::syscall(SYSCALL_DEF(getdents64), static_cast(fd), dirp, static_cast(count)); + if (Result != -1) { + // Walk each offset + // if we are passing the full d_off to the 32bit application then it seems to break things? + for (size_t i = 0, num = 0; i < Result; ++num) { + linux_dirent_64* Incoming = (linux_dirent_64*)(reinterpret_cast(dirp) + i); + Incoming->d_off = num; + i += Incoming->d_reclen; } - SYSCALL_ERRNO(); - }); + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(ioctl, ioctl32); + REGISTER_SYSCALL_IMPL_X32(select, [](FEXCore::Core::CpuStateFrame* Frame, compat_select_args* arg) -> uint64_t { + return selectHandler(Frame, arg->nfds, arg->readfds, arg->writefds, arg->exceptfds, arg->timeout); + }); - REGISTER_SYSCALL_IMPL_X32(getdents, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *dirp, uint32_t count) -> uint64_t { - return GetDentsEmulation(fd, reinterpret_cast(dirp), count); - }); + REGISTER_SYSCALL_IMPL_X32(_newselect, selectHandler); - REGISTER_SYSCALL_IMPL_X32(getdents64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *dirp, uint32_t count) -> uint64_t { - uint64_t Result = ::syscall(SYSCALL_DEF(getdents64), - static_cast(fd), - dirp, - static_cast(count)); - if (Result != -1) { - // Walk each offset - // if we are passing the full d_off to the 32bit application then it seems to break things? - for (size_t i = 0, num = 0; i < Result; ++num) { - linux_dirent_64 *Incoming = (linux_dirent_64*)(reinterpret_cast(dirp) + i); - Incoming->d_off = num; - i += Incoming->d_reclen; - } - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(pselect6, + [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* readfds, fd_set32* writefds, fd_set32* exceptfds, + timespec32* timeout, compat_ptr sigmaskpack) -> uint64_t { + struct timespec tp64 {}; + if (timeout) { + tp64 = *timeout; + } - REGISTER_SYSCALL_IMPL_X32(select, [](FEXCore::Core::CpuStateFrame *Frame, compat_select_args *arg) -> uint64_t { - return selectHandler(Frame, arg->nfds, arg->readfds, arg->writefds, arg->exceptfds, arg->timeout); - }); + fd_set Host_readfds; + fd_set Host_writefds; + fd_set Host_exceptfds; + sigset_t HostSet {}; - REGISTER_SYSCALL_IMPL_X32(_newselect, selectHandler); + FD_ZERO(&Host_readfds); + FD_ZERO(&Host_writefds); + FD_ZERO(&Host_exceptfds); + sigemptyset(&HostSet); - REGISTER_SYSCALL_IMPL_X32(pselect6, [](FEXCore::Core::CpuStateFrame *Frame, int nfds, fd_set32 *readfds, fd_set32 *writefds, fd_set32 *exceptfds, timespec32 *timeout, compat_ptr sigmaskpack) -> uint64_t { - struct timespec tp64{}; - if (timeout) { - tp64 = *timeout; - } + // Round up to the full 32bit word + uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; - fd_set Host_readfds; - fd_set Host_writefds; - fd_set Host_exceptfds; - sigset_t HostSet{}; + if (readfds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = readfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_readfds); + } + } + } + } - FD_ZERO(&Host_readfds); - FD_ZERO(&Host_writefds); - FD_ZERO(&Host_exceptfds); - sigemptyset(&HostSet); + if (writefds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = writefds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_writefds); + } + } + } + } - // Round up to the full 32bit word - uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; + if (exceptfds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = exceptfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_exceptfds); + } + } + } + } - if (readfds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = readfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_readfds); - } - } - } - } + if (sigmaskpack && sigmaskpack->sigset) { + uint64_t* sigmask = sigmaskpack->sigset; + size_t sigsetsize = sigmaskpack->size; + for (int32_t i = 0; i < (sigsetsize * 8); ++i) { + if (*sigmask & (1ULL << i)) { + sigaddset(&HostSet, i + 1); + } + } + } - if (writefds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = writefds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_writefds); - } - } - } - } + uint64_t Result = ::pselect(nfds, readfds ? &Host_readfds : nullptr, writefds ? &Host_writefds : nullptr, + exceptfds ? &Host_exceptfds : nullptr, timeout ? &tp64 : nullptr, &HostSet); - if (exceptfds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = exceptfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_exceptfds); - } - } - } - } + if (readfds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_readfds)) { + readfds[i / 32] |= 1 << (i & 31); + } else { + readfds[i / 32] &= ~(1 << (i & 31)); + } + } + } - if (sigmaskpack && sigmaskpack->sigset) { - uint64_t *sigmask = sigmaskpack->sigset; - size_t sigsetsize = sigmaskpack->size; - for (int32_t i = 0; i < (sigsetsize * 8); ++i) { - if (*sigmask & (1ULL << i)) { - sigaddset(&HostSet, i + 1); - } - } - } + if (writefds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_writefds)) { + writefds[i / 32] |= 1 << (i & 31); + } else { + writefds[i / 32] &= ~(1 << (i & 31)); + } + } + } - uint64_t Result = ::pselect(nfds, - readfds ? &Host_readfds : nullptr, - writefds ? &Host_writefds : nullptr, - exceptfds ? &Host_exceptfds : nullptr, - timeout ? &tp64 : nullptr, - &HostSet); + if (exceptfds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_exceptfds)) { + exceptfds[i / 32] |= 1 << (i & 31); + } else { + exceptfds[i / 32] &= ~(1 << (i & 31)); + } + } + } - if (readfds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_readfds)) { - readfds[i/32] |= 1 << (i & 31); - } else { - readfds[i/32] &= ~(1 << (i & 31)); - } - } - } + if (timeout) { + *timeout = tp64; + } + SYSCALL_ERRNO(); + }); - if (writefds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_writefds)) { - writefds[i/32] |= 1 << (i & 31); - } else { - writefds[i/32] &= ~(1 << (i & 31)); - } - } - } + REGISTER_SYSCALL_IMPL_X32(fadvise64_64, + [](FEXCore::Core::CpuStateFrame* Frame, int32_t fd, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, + uint32_t len_high, int advice) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + uint64_t Len = len_high; + Len <<= 32; + Len |= len_low; + uint64_t Result = ::posix_fadvise64(fd, Offset, Len, advice); + SYSCALL_ERRNO(); + }); - if (exceptfds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_exceptfds)) { - exceptfds[i/32] |= 1 << (i & 31); - } else { - exceptfds[i/32] &= ~(1 << (i & 31)); - } - } - } + REGISTER_SYSCALL_IMPL_X32(timerfd_settime, + [](FEXCore::Core::CpuStateFrame* Frame, int fd, int flags, const FEX::HLE::x32::old_itimerspec32* new_value, + FEX::HLE::x32::old_itimerspec32* old_value) -> uint64_t { + struct itimerspec new_value_host {}; + struct itimerspec old_value_host {}; + struct itimerspec* old_value_host_p {}; - if (timeout) { - *timeout = tp64; - } - SYSCALL_ERRNO(); - }); + new_value_host = *new_value; + if (old_value) { + old_value_host_p = &old_value_host; + } - REGISTER_SYSCALL_IMPL_X32(fadvise64_64, [](FEXCore::Core::CpuStateFrame *Frame, int32_t fd, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, uint32_t len_high, int advice) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - uint64_t Len = len_high; - Len <<= 32; - Len |= len_low; - uint64_t Result = ::posix_fadvise64(fd, Offset, Len, advice); - SYSCALL_ERRNO(); - }); + // Flags don't need remapped + uint64_t Result = ::timerfd_settime(fd, flags, &new_value_host, old_value_host_p); - REGISTER_SYSCALL_IMPL_X32(timerfd_settime, [](FEXCore::Core::CpuStateFrame *Frame, - int fd, - int flags, - const FEX::HLE::x32::old_itimerspec32 *new_value, - FEX::HLE::x32::old_itimerspec32 *old_value) -> uint64_t { - struct itimerspec new_value_host{}; - struct itimerspec old_value_host{}; - struct itimerspec *old_value_host_p{}; + if (Result != -1 && old_value) { + *old_value = old_value_host; + } + SYSCALL_ERRNO(); + }); - new_value_host = *new_value; - if (old_value) { - old_value_host_p = &old_value_host; - } + REGISTER_SYSCALL_IMPL_X32(timerfd_gettime, [](FEXCore::Core::CpuStateFrame* Frame, int fd, FEX::HLE::x32::old_itimerspec32* curr_value) -> uint64_t { + struct itimerspec Host {}; - // Flags don't need remapped - uint64_t Result = ::timerfd_settime(fd, flags, &new_value_host, old_value_host_p); + uint64_t Result = ::timerfd_gettime(fd, &Host); - if (Result != -1 && old_value) { - *old_value = old_value_host; - } - SYSCALL_ERRNO(); - }); + if (Result != -1) { + *curr_value = Host; + } - REGISTER_SYSCALL_IMPL_X32(timerfd_gettime, [](FEXCore::Core::CpuStateFrame *Frame, int fd, FEX::HLE::x32::old_itimerspec32 *curr_value) -> uint64_t { - struct itimerspec Host{}; + SYSCALL_ERRNO(); + }); - uint64_t Result = ::timerfd_gettime(fd, &Host); + REGISTER_SYSCALL_IMPL_X32(pselect6_time64, + [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* readfds, fd_set32* writefds, fd_set32* exceptfds, + struct timespec* timeout, compat_ptr sigmaskpack) -> uint64_t { + fd_set Host_readfds; + fd_set Host_writefds; + fd_set Host_exceptfds; + sigset_t HostSet {}; - if (Result != -1) { - *curr_value = Host; - } + FD_ZERO(&Host_readfds); + FD_ZERO(&Host_writefds); + FD_ZERO(&Host_exceptfds); + sigemptyset(&HostSet); - SYSCALL_ERRNO(); - }); + // Round up to the full 32bit word + uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; - REGISTER_SYSCALL_IMPL_X32(pselect6_time64, [](FEXCore::Core::CpuStateFrame *Frame, int nfds, fd_set32 *readfds, fd_set32 *writefds, fd_set32 *exceptfds, struct timespec *timeout, compat_ptr sigmaskpack) -> uint64_t { - fd_set Host_readfds; - fd_set Host_writefds; - fd_set Host_exceptfds; - sigset_t HostSet{}; + if (readfds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = readfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_readfds); + } + } + } + } - FD_ZERO(&Host_readfds); - FD_ZERO(&Host_writefds); - FD_ZERO(&Host_exceptfds); - sigemptyset(&HostSet); + if (writefds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = writefds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_writefds); + } + } + } + } - // Round up to the full 32bit word - uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; + if (exceptfds) { + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = exceptfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_exceptfds); + } + } + } + } - if (readfds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = readfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_readfds); - } - } - } - } + if (sigmaskpack && sigmaskpack->sigset) { + uint64_t* sigmask = sigmaskpack->sigset; + size_t sigsetsize = sigmaskpack->size; + for (int32_t i = 0; i < (sigsetsize * 8); ++i) { + if (*sigmask & (1ULL << i)) { + sigaddset(&HostSet, i + 1); + } + } + } - if (writefds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = writefds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_writefds); - } - } - } - } + uint64_t Result = ::pselect(nfds, readfds ? &Host_readfds : nullptr, writefds ? &Host_writefds : nullptr, + exceptfds ? &Host_exceptfds : nullptr, timeout, &HostSet); - if (exceptfds) { - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = exceptfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_exceptfds); - } - } - } - } + if (readfds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_readfds)) { + readfds[i / 32] |= 1 << (i & 31); + } else { + readfds[i / 32] &= ~(1 << (i & 31)); + } + } + } - if (sigmaskpack && sigmaskpack->sigset) { - uint64_t *sigmask = sigmaskpack->sigset; - size_t sigsetsize = sigmaskpack->size; - for (int32_t i = 0; i < (sigsetsize * 8); ++i) { - if (*sigmask & (1ULL << i)) { - sigaddset(&HostSet, i + 1); - } - } - } + if (writefds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_writefds)) { + writefds[i / 32] |= 1 << (i & 31); + } else { + writefds[i / 32] &= ~(1 << (i & 31)); + } + } + } - uint64_t Result = ::pselect(nfds, - readfds ? &Host_readfds : nullptr, - writefds ? &Host_writefds : nullptr, - exceptfds ? &Host_exceptfds : nullptr, - timeout, - &HostSet); + if (exceptfds) { + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_exceptfds)) { + exceptfds[i / 32] |= 1 << (i & 31); + } else { + exceptfds[i / 32] &= ~(1 << (i & 31)); + } + } + } - if (readfds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_readfds)) { - readfds[i/32] |= 1 << (i & 31); - } else { - readfds[i/32] &= ~(1 << (i & 31)); - } - } - } + SYSCALL_ERRNO(); + }); - if (writefds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_writefds)) { - writefds[i/32] |= 1 << (i & 31); - } else { - writefds[i/32] &= ~(1 << (i & 31)); - } - } - } + REGISTER_SYSCALL_IMPL_X32(sendfile, [](FEXCore::Core::CpuStateFrame* Frame, int out_fd, int in_fd, compat_off_t* offset, size_t count) -> uint64_t { + off_t Local {}; + off_t* Local_p {}; + if (offset) { + Local_p = &Local; + Local = *offset; + } + uint64_t Result = ::sendfile(out_fd, in_fd, Local_p, count); + SYSCALL_ERRNO(); + }); - if (exceptfds) { - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_exceptfds)) { - exceptfds[i/32] |= 1 << (i & 31); - } else { - exceptfds[i/32] &= ~(1 << (i & 31)); - } - } - } - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(sendfile, [](FEXCore::Core::CpuStateFrame *Frame, int out_fd, int in_fd, compat_off_t *offset, size_t count) -> uint64_t { - off_t Local{}; - off_t *Local_p{}; - if (offset) { - Local_p = &Local; - Local = *offset; - } - uint64_t Result = ::sendfile(out_fd, in_fd, Local_p, count); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(pread_64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + pread_64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { uint64_t Offset = offset_high; Offset <<= 32; Offset |= offset_low; @@ -879,7 +845,8 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(pwrite_64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + pwrite_64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { uint64_t Offset = offset_high; Offset <<= 32; Offset |= offset_low; @@ -888,7 +855,8 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(readahead, [](FEXCore::Core::CpuStateFrame *Frame, int fd, uint32_t offset_low, uint64_t offset_high, size_t count) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + readahead, [](FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint64_t offset_high, size_t count) -> uint64_t { uint64_t Offset = offset_high; Offset <<= 32; Offset |= offset_low; @@ -897,49 +865,42 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(sync_file_range, [](FEXCore::Core::CpuStateFrame *Frame, - int fd, - uint32_t offset_low, - uint32_t offset_high, - uint32_t len_low, - uint32_t len_high, - unsigned int flags) -> uint64_t { - // Flags don't need remapped - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; + REGISTER_SYSCALL_IMPL_X32(sync_file_range, + [](FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, + uint32_t len_high, unsigned int flags) -> uint64_t { + // Flags don't need remapped + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; - uint64_t Len = len_high; - Len <<= 32; - Len |= len_low; + uint64_t Len = len_high; + Len <<= 32; + Len |= len_low; - uint64_t Result = ::syscall(SYSCALL_DEF(sync_file_range), fd, Offset, Len, flags); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(sync_file_range), fd, Offset, Len, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(fallocate, [](FEXCore::Core::CpuStateFrame *Frame, - int fd, - int mode, - uint32_t offset_low, - uint32_t offset_high, - uint32_t len_low, - uint32_t len_high) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; + REGISTER_SYSCALL_IMPL_X32(fallocate, + [](FEXCore::Core::CpuStateFrame* Frame, int fd, int mode, uint32_t offset_low, uint32_t offset_high, + uint32_t len_low, uint32_t len_high) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; - uint64_t Len = len_high; - Len <<= 32; - Len |= len_low; + uint64_t Len = len_high; + Len <<= 32; + Len |= len_low; - uint64_t Result = ::fallocate(fd, mode, Offset, Len); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::fallocate(fd, mode, Offset, Len); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(vmsplice, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const struct iovec32 *iov, unsigned long nr_segs, unsigned int flags) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + vmsplice, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, unsigned long nr_segs, unsigned int flags) -> uint64_t { fextl::vector Host_iovec(iov, iov + nr_segs); uint64_t Result = ::vmsplice(fd, Host_iovec.data(), nr_segs, flags); SYSCALL_ERRNO(); }); - } } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp index dab1539b7..78dbb1e77 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp @@ -15,13 +15,14 @@ $end_info$ #include namespace FEX::HLE::x32 { - void RegisterFS(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(umount, [](FEXCore::Core::CpuStateFrame *Frame, const char *target) -> uint64_t { - uint64_t Result = ::umount(target); - SYSCALL_ERRNO(); - }); +void RegisterFS(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(umount, [](FEXCore::Core::CpuStateFrame* Frame, const char* target) -> uint64_t { + uint64_t Result = ::umount(target); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(truncate64, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + truncate64, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, uint32_t offset_low, uint32_t offset_high) -> uint64_t { uint64_t Offset = offset_high; Offset <<= 32; Offset |= offset_low; @@ -29,16 +30,17 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(ftruncate64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, uint32_t offset_low, uint32_t offset_high) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - uint64_t Result = ::ftruncate(fd, Offset); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(ftruncate64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + uint64_t Result = ::ftruncate(fd, Offset); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(sigprocmask, [](FEXCore::Core::CpuStateFrame *Frame, int how, const uint64_t *set, uint64_t *oldset, size_t sigsetsize) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + sigprocmask, [](FEXCore::Core::CpuStateFrame* Frame, int how, const uint64_t* set, uint64_t* oldset, size_t sigsetsize) -> uint64_t { return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(how, set, oldset); }); - } } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp index 000a9d2cb..8357e9382 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp @@ -16,29 +16,33 @@ $end_info$ #include namespace FEX::HLE::x32 { - void RegisterIO(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(io_getevents, [](FEXCore::Core::CpuStateFrame *Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec32 *timeout) -> uint64_t { - struct timespec* timeout_ptr{}; - struct timespec tp64{}; - if (timeout) { - tp64 = *timeout; - timeout_ptr = &tp64; - } +void RegisterIO(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(io_getevents, + [](FEXCore::Core::CpuStateFrame* Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event* events, + struct timespec32* timeout) -> uint64_t { + struct timespec* timeout_ptr {}; + struct timespec tp64 {}; + if (timeout) { + tp64 = *timeout; + timeout_ptr = &tp64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(io_getevents), ctx_id, min_nr, nr, events, timeout_ptr); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(io_getevents), ctx_id, min_nr, nr, events, timeout_ptr); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(io_pgetevents, [](FEXCore::Core::CpuStateFrame *Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec32 *timeout, const struct io_sigset *usig) -> uint64_t { - struct timespec* timeout_ptr{}; - struct timespec tp64{}; - if (timeout) { - tp64 = *timeout; - timeout_ptr = &tp64; - } + REGISTER_SYSCALL_IMPL_X32(io_pgetevents, + [](FEXCore::Core::CpuStateFrame* Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event* events, + struct timespec32* timeout, const struct io_sigset* usig) -> uint64_t { + struct timespec* timeout_ptr {}; + struct timespec tp64 {}; + if (timeout) { + tp64 = *timeout; + timeout_ptr = &tp64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(io_pgetevents), ctx_id, min_nr, nr, events, timeout_ptr, usig); - SYSCALL_ERRNO(); - }); - } + uint64_t Result = ::syscall(SYSCALL_DEF(io_pgetevents), ctx_id, min_nr, nr, events, timeout_ptr, usig); + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp index 353f2945e..92a1648b7 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp @@ -21,156 +21,151 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } ARG_TO_STR(FEX::HLE::x32::compat_ptr>, "%lx") ARG_TO_STR(FEX::HLE::x32::compat_ptr>, "%lx") namespace FEX::HLE::x32 { - struct sysinfo32 { - int32_t uptime; - uint32_t loads[3]; - uint32_t totalram; - uint32_t freeram; - uint32_t sharedram; - uint32_t bufferram; - uint32_t totalswap; - uint32_t freeswap; - uint16_t procs; - uint32_t totalhigh; - uint32_t freehigh; - uint32_t mem_unit; - char _pad[8]; - }; +struct sysinfo32 { + int32_t uptime; + uint32_t loads[3]; + uint32_t totalram; + uint32_t freeram; + uint32_t sharedram; + uint32_t bufferram; + uint32_t totalswap; + uint32_t freeswap; + uint16_t procs; + uint32_t totalhigh; + uint32_t freehigh; + uint32_t mem_unit; + char _pad[8]; +}; - static_assert(sizeof(sysinfo32) == 64, "Needs to be 64bytes"); +static_assert(sizeof(sysinfo32) == 64, "Needs to be 64bytes"); - void RegisterInfo(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(oldolduname, [](FEXCore::Core::CpuStateFrame *Frame, struct oldold_utsname *buf) -> uint64_t { - struct utsname Local{}; +void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(oldolduname, [](FEXCore::Core::CpuStateFrame* Frame, struct oldold_utsname* buf) -> uint64_t { + struct utsname Local {}; - memset(buf, 0, sizeof(*buf)); - if (::uname(&Local) == 0) { - memcpy(buf->nodename, Local.nodename, __OLD_UTS_LEN); - } - else { - strncpy(buf->nodename, "FEXCore", __OLD_UTS_LEN); - LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); - } - strncpy(buf->sysname, "Linux", __OLD_UTS_LEN); - uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - snprintf(buf->release, __OLD_UTS_LEN, "%d.%d.%d", - FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), - FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + memset(buf, 0, sizeof(*buf)); + if (::uname(&Local) == 0) { + memcpy(buf->nodename, Local.nodename, __OLD_UTS_LEN); + } else { + strncpy(buf->nodename, "FEXCore", __OLD_UTS_LEN); + LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); + } + strncpy(buf->sysname, "Linux", __OLD_UTS_LEN); + uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); + snprintf(buf->release, __OLD_UTS_LEN, "%d.%d.%d", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), + FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); - const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; - strncpy(buf->version, version, __OLD_UTS_LEN); - // Tell the guest that we are a 64bit kernel - strncpy(buf->machine, "x86_64", __OLD_UTS_LEN); - return 0; - }); + const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; + strncpy(buf->version, version, __OLD_UTS_LEN); + // Tell the guest that we are a 64bit kernel + strncpy(buf->machine, "x86_64", __OLD_UTS_LEN); + return 0; + }); - REGISTER_SYSCALL_IMPL_X32(olduname, [](FEXCore::Core::CpuStateFrame *Frame, struct old_utsname *buf) -> uint64_t { - struct utsname Local{}; + REGISTER_SYSCALL_IMPL_X32(olduname, [](FEXCore::Core::CpuStateFrame* Frame, struct old_utsname* buf) -> uint64_t { + struct utsname Local {}; - memset(buf, 0, sizeof(*buf)); - if (::uname(&Local) == 0) { - memcpy(buf->nodename, Local.nodename, __NEW_UTS_LEN); - } - else { - strncpy(buf->nodename, "FEXCore", __NEW_UTS_LEN); - LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); - } - strncpy(buf->sysname, "Linux", __NEW_UTS_LEN); - uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - snprintf(buf->release, __NEW_UTS_LEN, "%d.%d.%d", - FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), - FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + memset(buf, 0, sizeof(*buf)); + if (::uname(&Local) == 0) { + memcpy(buf->nodename, Local.nodename, __NEW_UTS_LEN); + } else { + strncpy(buf->nodename, "FEXCore", __NEW_UTS_LEN); + LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); + } + strncpy(buf->sysname, "Linux", __NEW_UTS_LEN); + uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); + snprintf(buf->release, __NEW_UTS_LEN, "%d.%d.%d", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), + FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); - const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; - strncpy(buf->version, version, __NEW_UTS_LEN); - // Tell the guest that we are a 64bit kernel - strncpy(buf->machine, "x86_64", __NEW_UTS_LEN); - return 0; - }); + const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; + strncpy(buf->version, version, __NEW_UTS_LEN); + // Tell the guest that we are a 64bit kernel + strncpy(buf->machine, "x86_64", __NEW_UTS_LEN); + return 0; + }); - REGISTER_SYSCALL_IMPL_X32(getrlimit, [](FEXCore::Core::CpuStateFrame *Frame, int resource, compat_ptr> rlim) -> uint64_t { - struct rlimit rlim64{}; + REGISTER_SYSCALL_IMPL_X32( + getrlimit, [](FEXCore::Core::CpuStateFrame* Frame, int resource, compat_ptr> rlim) -> uint64_t { + struct rlimit rlim64 {}; uint64_t Result = ::getrlimit(resource, &rlim64); *rlim = rlim64; SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(ugetrlimit, [](FEXCore::Core::CpuStateFrame *Frame, int resource, compat_ptr> rlim) -> uint64_t { - struct rlimit rlim64{}; + REGISTER_SYSCALL_IMPL_X32( + ugetrlimit, [](FEXCore::Core::CpuStateFrame* Frame, int resource, compat_ptr> rlim) -> uint64_t { + struct rlimit rlim64 {}; uint64_t Result = ::getrlimit(resource, &rlim64); *rlim = rlim64; SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(setrlimit, [](FEXCore::Core::CpuStateFrame *Frame, int resource, const compat_ptr> rlim) -> uint64_t { - struct rlimit rlim64{}; + REGISTER_SYSCALL_IMPL_X32( + setrlimit, [](FEXCore::Core::CpuStateFrame* Frame, int resource, const compat_ptr> rlim) -> uint64_t { + struct rlimit rlim64 {}; rlim64 = *rlim; uint64_t Result = ::setrlimit(resource, &rlim64); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(sysinfo, [](FEXCore::Core::CpuStateFrame *Frame, struct sysinfo32 *info) -> uint64_t { - struct sysinfo Host{}; - uint64_t Result = ::sysinfo(&Host); - if (Result != -1) { -#define Copy(x) info->x = static_castx)>(std::min(Host.x, static_cast(std::numeric_limitsx)>::max()))); - Copy(uptime); - Copy(procs); + REGISTER_SYSCALL_IMPL_X32(sysinfo, [](FEXCore::Core::CpuStateFrame* Frame, struct sysinfo32* info) -> uint64_t { + struct sysinfo Host {}; + uint64_t Result = ::sysinfo(&Host); + if (Result != -1) { +#define Copy(x) \ + info->x = static_castx)>(std::min(Host.x, static_cast(std::numeric_limitsx)>::max()))); + Copy(uptime); + Copy(procs); #define CopyShift(x) info->x = static_castx)>(Host.x >> ShiftAmount); - info->loads[0] = std::min(Host.loads[0], static_cast(std::numeric_limits::max())); - info->loads[1] = std::min(Host.loads[1], static_cast(std::numeric_limits::max())); - info->loads[2] = std::min(Host.loads[2], static_cast(std::numeric_limits::max())); + info->loads[0] = std::min(Host.loads[0], static_cast(std::numeric_limits::max())); + info->loads[1] = std::min(Host.loads[1], static_cast(std::numeric_limits::max())); + info->loads[2] = std::min(Host.loads[2], static_cast(std::numeric_limits::max())); - // If any result can't fit in to a uint32_t then we need to shift the mem_unit and all the members - // Set the mem_unit to the pagesize - uint32_t ShiftAmount{}; - if ((Host.totalram >> 32) != 0 || - (Host.totalswap >> 32) != 0) { + // If any result can't fit in to a uint32_t then we need to shift the mem_unit and all the members + // Set the mem_unit to the pagesize + uint32_t ShiftAmount {}; + if ((Host.totalram >> 32) != 0 || (Host.totalswap >> 32) != 0) { - while (Host.mem_unit < 4096) { - Host.mem_unit <<= 1; - ++ShiftAmount; - } + while (Host.mem_unit < 4096) { + Host.mem_unit <<= 1; + ++ShiftAmount; } - - CopyShift(totalram); - CopyShift(sharedram); - CopyShift(bufferram); - CopyShift(totalswap); - CopyShift(freeswap); - CopyShift(totalhigh); - CopyShift(freehigh); - Copy(mem_unit); } - SYSCALL_ERRNO(); - }); - REGISTER_SYSCALL_IMPL_X32(getrusage, [](FEXCore::Core::CpuStateFrame *Frame, int who, rusage_32 *usage) -> uint64_t { - struct rusage usage64 = *usage; - uint64_t Result = ::getrusage(who, &usage64); - *usage = usage64; - SYSCALL_ERRNO(); - }); + CopyShift(totalram); + CopyShift(sharedram); + CopyShift(bufferram); + CopyShift(totalswap); + CopyShift(freeswap); + CopyShift(totalhigh); + CopyShift(freehigh); + Copy(mem_unit); + } + SYSCALL_ERRNO(); + }); - if (Handler->IsHostKernelVersionAtLeast(6, 8, 0)) { - REGISTER_SYSCALL_IMPL_X32(map_shadow_stack, - [](FEXCore::Core::CpuStateFrame *Frame, uint64_t addr, uint64_t size, uint32_t flags) -> uint64_t { - // Claim that shadow stack isn't supported. - return -EOPNOTSUPP; - }); - } - else { - REGISTER_SYSCALL_IMPL_X32(map_shadow_stack, UnimplementedSyscallSafe); - } + REGISTER_SYSCALL_IMPL_X32(getrusage, [](FEXCore::Core::CpuStateFrame* Frame, int who, rusage_32* usage) -> uint64_t { + struct rusage usage64 = *usage; + uint64_t Result = ::getrusage(who, &usage64); + *usage = usage64; + SYSCALL_ERRNO(); + }); + + if (Handler->IsHostKernelVersionAtLeast(6, 8, 0)) { + REGISTER_SYSCALL_IMPL_X32(map_shadow_stack, [](FEXCore::Core::CpuStateFrame* Frame, uint64_t addr, uint64_t size, uint32_t flags) -> uint64_t { + // Claim that shadow stack isn't supported. + return -EOPNOTSUPP; + }); + } else { + REGISTER_SYSCALL_IMPL_X32(map_shadow_stack, UnimplementedSyscallSafe); } } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/HelperDefines.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/HelperDefines.h index d61a99e34..7e1a1f4fa 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/HelperDefines.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/HelperDefines.h @@ -10,12 +10,16 @@ #ifndef _BASIC_META // Meta typedef variable in unnamed and matches upstream // Use this for the super basic ioctl passthrough path -#define _BASIC_META(x) __attribute__((annotate("fex-match"))) __attribute__((annotate("ioctl-alias-x86_32-_"#x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x]; +#define _BASIC_META(x) \ + __attribute__((annotate("fex-match"))) \ + __attribute__((annotate("ioctl-alias-x86_32-_" #x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x]; #endif #ifndef _BASIC_META_VAR // This is similar to _BASIC_META except that it allows you to pass variadic arguments to the original ioctl definition -#define _BASIC_META_VAR(x, args...) __attribute__((annotate("fex-match"))) __attribute__((annotate("ioctl-alias-x86_32-_"#x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x(args)]; +#define _BASIC_META_VAR(x, args...) \ + __attribute__((annotate("fex-match"))) \ + __attribute__((annotate("ioctl-alias-x86_32-_" #x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x(args)]; #endif #ifndef _CUSTOM_META @@ -25,7 +29,7 @@ // Allows you to effectively pass in the original ioctl definition with custom type replacing the upstream type #define _CUSTOM_META(name, ioctl_num) \ typedef uint8_t _meta_##name[name]; \ - __attribute__((annotate("ioctl-alias-x86_32-_meta_"#name))) typedef uint8_t _##name[ioctl_num]; \ + __attribute__((annotate("ioctl-alias-x86_32-_meta_" #name))) typedef uint8_t _##name[ioctl_num]; \ constexpr static uint32_t FEX_##name = ioctl_num; #endif @@ -34,6 +38,6 @@ // Required to have an ioctl covering a range which some ioctls do #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) \ typedef uint8_t _meta_##name[ioctl_num + offset]; \ - __attribute__((annotate("ioctl-alias-x86_32-_meta_"#name))) typedef uint8_t _##name[ioctl_num + offset]; \ + __attribute__((annotate("ioctl-alias-x86_32-_meta_" #name))) typedef uint8_t _##name[ioctl_num + offset]; \ constexpr static uint32_t FEX_##name = ioctl_num + offset; #endif diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/asound.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/asound.h index 5f9aa803f..5941d2c66 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/asound.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/asound.h @@ -9,17 +9,17 @@ namespace FEX::HLE::x32 { namespace asound { #ifndef SNDRV_TIMER_IOCTL_TREAD_OLD -#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) #endif #ifndef SNDRV_PCM_IOCTL_USER_PVERSION -#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) +#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) #endif #ifndef SNDRV_TIMER_IOCTL_TREAD64 -#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) +#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) #endif #include "LinuxSyscalls/x32/Ioctl/asound.inl" -} -} +} // namespace asound +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/drm.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/drm.h index cca77efc5..80c329c28 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/drm.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/drm.h @@ -32,1387 +32,1235 @@ extern "C" { namespace FEX::HLE::x32 { namespace DRM { -struct -FEX_ANNOTATE("alias-x86_32-drm_version") -FEX_ANNOTATE("fex-match") -fex_drm_version { - int version_major; /**< Major version */ - int version_minor; /**< Minor version */ - int version_patchlevel; /**< Patch level */ - uint32_t name_len; /**< Length of name buffer */ - compat_ptr name; /**< Name of driver */ - uint32_t date_len; /**< Length of date buffer */ - compat_ptr date; /**< User-space buffer to hold date */ - uint32_t desc_len; /**< Length of desc buffer */ - compat_ptr desc; /**< User-space buffer to hold desc */ + struct FEX_ANNOTATE("alias-x86_32-drm_version") FEX_ANNOTATE("fex-match") fex_drm_version { + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel; /**< Patch level */ + uint32_t name_len; /**< Length of name buffer */ + compat_ptr name; /**< Name of driver */ + uint32_t date_len; /**< Length of date buffer */ + compat_ptr date; /**< User-space buffer to hold date */ + uint32_t desc_len; /**< Length of desc buffer */ + compat_ptr desc; /**< User-space buffer to hold desc */ - fex_drm_version() = delete; + fex_drm_version() = delete; - operator drm_version() const { - drm_version val{}; - val.version_major = version_major; - val.version_minor = version_minor; - val.version_patchlevel = version_patchlevel; - val.name_len = name_len; - val.name = name; - val.date_len = date_len; - val.date = date; - val.desc_len = desc_len; - val.desc = desc; - return val; - } - - fex_drm_version(struct drm_version val) - : name {val.name} - , date {val.date} - , desc {val.desc} { - version_major = val.version_major; - version_minor = val.version_minor; - version_patchlevel = val.version_patchlevel; - name_len = val.name_len; - name = val.name; - date_len = val.date_len; - date = val.date; - desc_len = val.desc_len; - desc = val.desc; - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_unique") -FEX_ANNOTATE("fex-match") -fex_drm_unique { - compat_size_t unique_len; - compat_ptr unique; - - fex_drm_unique() = delete; - - operator drm_unique() const { - drm_unique val{}; - val.unique_len = unique_len; - val.unique = unique; - return val; - } - - fex_drm_unique(struct drm_unique val) - : unique {val.unique} { - unique_len = val.unique_len; - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_map") -FEX_ANNOTATE("fex-match") -fex_drm_map { - uint32_t offset; - uint32_t size; - enum drm_map_type type; - enum drm_map_flags flags; - compat_ptr handle; - int32_t mtrr; - - fex_drm_map() = delete; - - operator drm_map() const { - drm_map val{}; - CPYT(offset); - CPYT(size); - CPYT(type); - CPYT(flags); - CPYT(handle); - CPYT(mtrr); - return val; - } - - fex_drm_map(struct drm_map val) - : handle { val.handle } { - CPYT(offset); - CPYT(size); - CPYT(type); - CPYT(flags); - CPYT(mtrr); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_client") -FEX_ANNOTATE("fex-match") -fex_drm_client { - int32_t idx; - int32_t auth; - uint32_t pid; - uint32_t uid; - uint32_t magic; - uint32_t iocs; - - fex_drm_client() = delete; - - operator drm_client() const { - drm_client val{}; - CPYT(idx); - CPYT(auth); - CPYT(pid); - CPYT(uid); - CPYT(magic); - CPYT(iocs); - return val; - } - - fex_drm_client(struct drm_client val) { - CPYF(idx); - CPYF(auth); - CPYF(pid); - CPYF(uid); - CPYF(magic); - CPYF(iocs); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_stats") -FEX_ANNOTATE("fex-match") -fex_drm_stats { - uint32_t count; - struct { - uint32_t value; - enum drm_stat_type type; - } data[15]; - - fex_drm_stats() = delete; - - operator drm_stats() const { - drm_stats val{}; - CPYT(count); - for (size_t i = 0; i < 15; ++i) { - CPYT(data[i].value); - CPYT(data[i].type); + operator drm_version() const { + drm_version val {}; + val.version_major = version_major; + val.version_minor = version_minor; + val.version_patchlevel = version_patchlevel; + val.name_len = name_len; + val.name = name; + val.date_len = date_len; + val.date = date; + val.desc_len = desc_len; + val.desc = desc; + return val; } - return val; - } - fex_drm_stats(struct drm_stats val) { - CPYF(count); - for (size_t i = 0; i < 15; ++i) { - CPYF(data[i].value); - CPYF(data[i].type); + fex_drm_version(struct drm_version val) + : name {val.name} + , date {val.date} + , desc {val.desc} { + version_major = val.version_major; + version_minor = val.version_minor; + version_patchlevel = val.version_patchlevel; + name_len = val.name_len; + name = val.name; + date_len = val.date_len; + date = val.date; + desc_len = val.desc_len; + desc = val.desc; } - } -}; + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_buf_desc") -FEX_ANNOTATE("fex-match") -fex_drm_buf_desc { - int32_t count; - int32_t size; - int32_t low_mark; - int32_t high_mark; - enum { - _DRM_PAGE_ALIGN = 0x01, - _DRM_AGP_BUFFER = 0x02, - _DRM_SG_BUFFER = 0x04, - _DRM_FB_BUFFER = 0x08, - _DRM_PCI_BUFFER_RO = 0x10 - } flags; - uint32_t agp_start; + struct FEX_ANNOTATE("alias-x86_32-drm_unique") FEX_ANNOTATE("fex-match") fex_drm_unique { + compat_size_t unique_len; + compat_ptr unique; - fex_drm_buf_desc() = delete; + fex_drm_unique() = delete; - operator drm_buf_desc() const { - drm_buf_desc val{}; - CPYT(count); - CPYT(size); - CPYT(low_mark); - CPYT(high_mark); - CPYT(agp_start); - return val; - } + operator drm_unique() const { + drm_unique val {}; + val.unique_len = unique_len; + val.unique = unique; + return val; + } - fex_drm_buf_desc(struct drm_buf_desc val) { - CPYF(count); - CPYF(size); - CPYF(low_mark); - CPYF(high_mark); - CPYF(agp_start); - } -}; + fex_drm_unique(struct drm_unique val) + : unique {val.unique} { + unique_len = val.unique_len; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_buf_info") -FEX_ANNOTATE("fex-match") -fex_drm_buf_info { - int32_t count; - compat_ptr list; + struct FEX_ANNOTATE("alias-x86_32-drm_map") FEX_ANNOTATE("fex-match") fex_drm_map { + uint32_t offset; + uint32_t size; + enum drm_map_type type; + enum drm_map_flags flags; + compat_ptr handle; + int32_t mtrr; - fex_drm_buf_info() = delete; + fex_drm_map() = delete; - operator drm_buf_info() const { - drm_buf_info val{}; - CPYT(count); - CPYT(list); - return val; - } + operator drm_map() const { + drm_map val {}; + CPYT(offset); + CPYT(size); + CPYT(type); + CPYT(flags); + CPYT(handle); + CPYT(mtrr); + return val; + } - fex_drm_buf_info(struct drm_buf_info val) - : list { val.list } { - CPYF(count); - } -}; + fex_drm_map(struct drm_map val) + : handle {val.handle} { + CPYT(offset); + CPYT(size); + CPYT(type); + CPYT(flags); + CPYT(mtrr); + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_buf_pub") -FEX_ANNOTATE("fex-match") -fex_drm_buf_pub { - int32_t idx; - int32_t total; - int32_t used; - compat_ptr address; + struct FEX_ANNOTATE("alias-x86_32-drm_client") FEX_ANNOTATE("fex-match") fex_drm_client { + int32_t idx; + int32_t auth; + uint32_t pid; + uint32_t uid; + uint32_t magic; + uint32_t iocs; - fex_drm_buf_pub() = delete; + fex_drm_client() = delete; - operator drm_buf_pub() const { - drm_buf_pub val{}; - CPYT(idx); - CPYT(total); - CPYT(used); - CPYT(address); - return val; - } + operator drm_client() const { + drm_client val {}; + CPYT(idx); + CPYT(auth); + CPYT(pid); + CPYT(uid); + CPYT(magic); + CPYT(iocs); + return val; + } - fex_drm_buf_pub(struct drm_buf_pub val) - : address { val.address } { - CPYF(idx); - CPYF(total); - CPYF(used); - } -}; + fex_drm_client(struct drm_client val) { + CPYF(idx); + CPYF(auth); + CPYF(pid); + CPYF(uid); + CPYF(magic); + CPYF(iocs); + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_buf_map") -FEX_ANNOTATE("fex-match") -fex_drm_buf_map { - int32_t count; + struct FEX_ANNOTATE("alias-x86_32-drm_stats") FEX_ANNOTATE("fex-match") fex_drm_stats { + uint32_t count; + struct { + uint32_t value; + enum drm_stat_type type; + } data[15]; + + fex_drm_stats() = delete; + + operator drm_stats() const { + drm_stats val {}; + CPYT(count); + for (size_t i = 0; i < 15; ++i) { + CPYT(data[i].value); + CPYT(data[i].type); + } + return val; + } + + fex_drm_stats(struct drm_stats val) { + CPYF(count); + for (size_t i = 0; i < 15; ++i) { + CPYF(data[i].value); + CPYF(data[i].type); + } + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_buf_desc") FEX_ANNOTATE("fex-match") fex_drm_buf_desc { + int32_t count; + int32_t size; + int32_t low_mark; + int32_t high_mark; + enum { _DRM_PAGE_ALIGN = 0x01, _DRM_AGP_BUFFER = 0x02, _DRM_SG_BUFFER = 0x04, _DRM_FB_BUFFER = 0x08, _DRM_PCI_BUFFER_RO = 0x10 } flags; + uint32_t agp_start; + + fex_drm_buf_desc() = delete; + + operator drm_buf_desc() const { + drm_buf_desc val {}; + CPYT(count); + CPYT(size); + CPYT(low_mark); + CPYT(high_mark); + CPYT(agp_start); + return val; + } + + fex_drm_buf_desc(struct drm_buf_desc val) { + CPYF(count); + CPYF(size); + CPYF(low_mark); + CPYF(high_mark); + CPYF(agp_start); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_buf_info") FEX_ANNOTATE("fex-match") fex_drm_buf_info { + int32_t count; + compat_ptr list; + + fex_drm_buf_info() = delete; + + operator drm_buf_info() const { + drm_buf_info val {}; + CPYT(count); + CPYT(list); + return val; + } + + fex_drm_buf_info(struct drm_buf_info val) + : list {val.list} { + CPYF(count); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_buf_pub") FEX_ANNOTATE("fex-match") fex_drm_buf_pub { + int32_t idx; + int32_t total; + int32_t used; + compat_ptr address; + + fex_drm_buf_pub() = delete; + + operator drm_buf_pub() const { + drm_buf_pub val {}; + CPYT(idx); + CPYT(total); + CPYT(used); + CPYT(address); + return val; + } + + fex_drm_buf_pub(struct drm_buf_pub val) + : address {val.address} { + CPYF(idx); + CPYF(total); + CPYF(used); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_buf_map") FEX_ANNOTATE("fex-match") fex_drm_buf_map { + int32_t count; #ifdef __cplusplus - compat_ptr virt; + compat_ptr virt; #else - compat_ptr virtual; + compat_ptr virtual; #endif - compat_ptr list; + compat_ptr list; - fex_drm_buf_map() = delete; + fex_drm_buf_map() = delete; - operator drm_buf_map() const { - drm_buf_map val{}; - CPYT(count); + operator drm_buf_map() const { + drm_buf_map val {}; + CPYT(count); #ifdef __cplusplus - CPYT(virt); + CPYT(virt); #else - CPYT(virtual); + CPYT(virtual); #endif - CPYT(list); - return val; - } + CPYT(list); + return val; + } - fex_drm_buf_map(struct drm_buf_map val) + fex_drm_buf_map(struct drm_buf_map val) #ifdef __cplusplus - : virt { val.virt } + : virt {val.virt} #else - : virtual { val.virtual } + : virtual {val.virtual} #endif - , list { val.list } - { - CPYF(count); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_buf_free") -FEX_ANNOTATE("fex-match") -fex_drm_buf_free { - int32_t count; - compat_ptr list; - - fex_drm_buf_free() = delete; - - operator drm_buf_free() const { - drm_buf_free val{}; - CPYT(count); - CPYT(list); - return val; - } - - fex_drm_buf_free(struct drm_buf_free val) - : list { val.list } { - CPYF(count); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_ctx_priv_map") -FEX_ANNOTATE("fex-match") -fex_drm_ctx_priv_map { - uint32_t ctx_id; - compat_ptr handle; - - fex_drm_ctx_priv_map() = delete; - - operator drm_ctx_priv_map() const { - drm_ctx_priv_map val{}; - CPYT(ctx_id); - CPYT(handle); - return val; - } - - fex_drm_ctx_priv_map(struct drm_ctx_priv_map val) - : handle { val.handle } { - CPYF(ctx_id); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_ctx_res") -FEX_ANNOTATE("fex-match") -fex_drm_ctx_res { - int32_t count; - compat_ptr contexts; - - fex_drm_ctx_res() = delete; - - operator drm_ctx_res() const { - drm_ctx_res val{}; - CPYT(count); - return val; - } - - fex_drm_ctx_res(struct drm_ctx_res val) - : contexts { val.contexts } { - CPYF(count); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_dma") -FEX_ANNOTATE("fex-match") -fex_drm_dma { - int32_t context; - int32_t send_count; - compat_ptr send_indices; - compat_ptr send_sizes; - enum drm_dma_flags flags; - int32_t request_count; - int32_t request_size; - compat_ptr request_indices; - compat_ptr request_sizes; - int32_t granted_count; - - fex_drm_dma() = delete; - - operator drm_dma() const { - drm_dma val{}; - CPYT(context); - CPYT(send_count); - CPYT(send_indices); - CPYT(send_sizes); - CPYT(flags); - CPYT(request_count); - CPYT(request_size); - CPYT(request_indices); - CPYT(request_sizes); - CPYT(granted_count); - return val; - } - - fex_drm_dma(struct drm_dma val) - : send_indices { val.send_indices } - , send_sizes { val.send_sizes } - , request_indices { val.request_indices } - , request_sizes { val.request_sizes } { - CPYF(context); - CPYF(send_count); - CPYF(flags); - CPYF(request_count); - CPYF(request_size); - CPYF(granted_count); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_scatter_gather") -FEX_ANNOTATE("fex-match") -fex_drm_scatter_gather { - uint32_t size; - uint32_t handle; - - fex_drm_scatter_gather() = delete; - - operator drm_scatter_gather() const { - drm_scatter_gather val{}; - CPYT(size); - CPYT(handle); - return val; - } - - fex_drm_scatter_gather(struct drm_scatter_gather val) { - CPYF(size); - CPYF(handle); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_wait_vblank_request") -FEX_ANNOTATE("fex-match") -fex_drm_wait_vblank_request { - enum drm_vblank_seq_type type; - uint32_t sequence; - uint32_t signal; - - fex_drm_wait_vblank_request() = delete; - - operator drm_wait_vblank_request() const { - drm_wait_vblank_request val{}; - CPYT(type); - CPYT(sequence); - CPYT(signal); - return val; - } - - fex_drm_wait_vblank_request(struct drm_wait_vblank_request val) { - CPYF(type); - CPYF(sequence); - CPYF(signal); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_wait_vblank_reply") -FEX_ANNOTATE("fex-match") -fex_drm_wait_vblank_reply { - enum drm_vblank_seq_type type; - uint32_t sequence; - int32_t tval_sec; - int32_t tval_usec; - - fex_drm_wait_vblank_reply() = delete; - - operator drm_wait_vblank_reply() const { - drm_wait_vblank_reply val{}; - CPYT(type); - CPYT(sequence); - CPYT(tval_sec); - CPYT(tval_usec); - return val; - } - - fex_drm_wait_vblank_reply(struct drm_wait_vblank_reply val) { - CPYF(type); - CPYF(sequence); - CPYF(tval_sec); - CPYF(tval_usec); - } -}; - -union -FEX_ANNOTATE("alias-x86_32-drm_wait_vblank") -FEX_ANNOTATE("fex-match") -fex_drm_wait_vblank { - fex_drm_wait_vblank_request request; - fex_drm_wait_vblank_reply reply; - - fex_drm_wait_vblank() = delete; -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_update_draw") -FEX_ANNOTATE("fex-match") -FEX_PACKED -fex_drm_update_draw { - drm_drawable_t handle; - uint32_t type; - uint32_t num; - compat_uint64_t data; - - fex_drm_update_draw() = delete; - - operator drm_update_draw() const { - drm_update_draw val{}; - CPYT(handle); - CPYT(type); - CPYT(num); - CPYT(data); - return val; - } - - fex_drm_update_draw(struct drm_update_draw val) { - CPYF(handle); - CPYF(type); - CPYF(num); - CPYF(data); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_mode_get_plane_res") -FEX_ANNOTATE("fex-match") -FEX_PACKED -fex_drm_mode_get_plane_res { - compat_uint64_t plane_id_ptr; - uint32_t count_planes; - fex_drm_mode_get_plane_res() = delete; - - operator drm_mode_get_plane_res() const { - drm_mode_get_plane_res val{}; - CPYT(plane_id_ptr); - CPYT(count_planes); - return val; - } - - fex_drm_mode_get_plane_res(struct drm_mode_get_plane_res val) { - CPYF(plane_id_ptr); - CPYF(count_planes); - } -}; - -struct -FEX_ANNOTATE("alias-x86_32-drm_mode_fb_cmd2") -FEX_ANNOTATE("fex-match") -FEX_PACKED -fex_drm_mode_fb_cmd2 { - uint32_t fb_id; - uint32_t width; - uint32_t height; - uint32_t pixel_format; - uint32_t flags; - - uint32_t handles[4]; - uint32_t pitches[4]; - uint32_t offsets[4]; - compat_uint64_t modifier[4]; - fex_drm_mode_fb_cmd2() = delete; - - operator drm_mode_fb_cmd2() const { - drm_mode_fb_cmd2 val{}; - CPYT(fb_id); - CPYT(width); - CPYT(height); - CPYT(pixel_format); - CPYT(flags); - for (int i = 0; i < 4; ++i) { - CPYT(handles[i]); - CPYT(pitches[i]); - CPYT(offsets[i]); - CPYT(modifier[i]); + , list {val.list} { + CPYF(count); } - return val; - } + }; - fex_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 val) { - CPYF(fb_id); - CPYF(width); - CPYF(height); - CPYF(pixel_format); - CPYF(flags); - for (int i = 0; i < 4; ++i) { - CPYF(handles[i]); - CPYF(pitches[i]); - CPYF(offsets[i]); - CPYF(modifier[i]); + struct FEX_ANNOTATE("alias-x86_32-drm_buf_free") FEX_ANNOTATE("fex-match") fex_drm_buf_free { + int32_t count; + compat_ptr list; + + fex_drm_buf_free() = delete; + + operator drm_buf_free() const { + drm_buf_free val {}; + CPYT(count); + CPYT(list); + return val; } - } -}; -struct -FEX_ANNOTATE("alias-x86_32-drm_mode_obj_get_properties") -FEX_ANNOTATE("fex-match") -FEX_PACKED -fex_drm_mode_obj_get_properties { - compat_uint64_t props_ptr; - compat_uint64_t prop_values_ptr; - uint32_t count_props; - uint32_t obj_id; - uint32_t obj_type; + fex_drm_buf_free(struct drm_buf_free val) + : list {val.list} { + CPYF(count); + } + }; - fex_drm_mode_obj_get_properties() = delete; + struct FEX_ANNOTATE("alias-x86_32-drm_ctx_priv_map") FEX_ANNOTATE("fex-match") fex_drm_ctx_priv_map { + uint32_t ctx_id; + compat_ptr handle; - operator drm_mode_obj_get_properties() const { - drm_mode_obj_get_properties val{}; - val.props_ptr = props_ptr; - val.prop_values_ptr = prop_values_ptr; - val.count_props = count_props; - val.obj_id = obj_id; - val.obj_type = obj_type; - return val; - } + fex_drm_ctx_priv_map() = delete; - fex_drm_mode_obj_get_properties(struct drm_mode_obj_get_properties val) { - props_ptr = val.props_ptr; - prop_values_ptr = val.prop_values_ptr; - count_props = val.count_props; - obj_type = val.obj_type; - } -}; + operator drm_ctx_priv_map() const { + drm_ctx_priv_map val {}; + CPYT(ctx_id); + CPYT(handle); + return val; + } -struct -FEX_ANNOTATE("alias-x86_32-drm_mode_obj_set_property") -FEX_ANNOTATE("fex-match") -FEX_PACKED -fex_drm_mode_obj_set_property { - compat_uint64_t value; - uint32_t prop_id; - uint32_t obj_id; - uint32_t obj_type; + fex_drm_ctx_priv_map(struct drm_ctx_priv_map val) + : handle {val.handle} { + CPYF(ctx_id); + } + }; - fex_drm_mode_obj_set_property() = delete; + struct FEX_ANNOTATE("alias-x86_32-drm_ctx_res") FEX_ANNOTATE("fex-match") fex_drm_ctx_res { + int32_t count; + compat_ptr contexts; - operator drm_mode_obj_set_property() const { - drm_mode_obj_set_property val{}; - val.value = value; - val.prop_id = prop_id; - val.obj_id = obj_id; - val.obj_type = obj_type; - return val; - } + fex_drm_ctx_res() = delete; - fex_drm_mode_obj_set_property(struct drm_mode_obj_set_property val) { - value = val.value; - prop_id = val.prop_id; - obj_id = val.obj_id; - obj_type = val.obj_type; - } -}; + operator drm_ctx_res() const { + drm_ctx_res val {}; + CPYT(count); + return val; + } -} + fex_drm_ctx_res(struct drm_ctx_res val) + : contexts {val.contexts} { + CPYF(count); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_dma") FEX_ANNOTATE("fex-match") fex_drm_dma { + int32_t context; + int32_t send_count; + compat_ptr send_indices; + compat_ptr send_sizes; + enum drm_dma_flags flags; + int32_t request_count; + int32_t request_size; + compat_ptr request_indices; + compat_ptr request_sizes; + int32_t granted_count; + + fex_drm_dma() = delete; + + operator drm_dma() const { + drm_dma val {}; + CPYT(context); + CPYT(send_count); + CPYT(send_indices); + CPYT(send_sizes); + CPYT(flags); + CPYT(request_count); + CPYT(request_size); + CPYT(request_indices); + CPYT(request_sizes); + CPYT(granted_count); + return val; + } + + fex_drm_dma(struct drm_dma val) + : send_indices {val.send_indices} + , send_sizes {val.send_sizes} + , request_indices {val.request_indices} + , request_sizes {val.request_sizes} { + CPYF(context); + CPYF(send_count); + CPYF(flags); + CPYF(request_count); + CPYF(request_size); + CPYF(granted_count); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_scatter_gather") FEX_ANNOTATE("fex-match") fex_drm_scatter_gather { + uint32_t size; + uint32_t handle; + + fex_drm_scatter_gather() = delete; + + operator drm_scatter_gather() const { + drm_scatter_gather val {}; + CPYT(size); + CPYT(handle); + return val; + } + + fex_drm_scatter_gather(struct drm_scatter_gather val) { + CPYF(size); + CPYF(handle); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_wait_vblank_request") FEX_ANNOTATE("fex-match") fex_drm_wait_vblank_request { + enum drm_vblank_seq_type type; + uint32_t sequence; + uint32_t signal; + + fex_drm_wait_vblank_request() = delete; + + operator drm_wait_vblank_request() const { + drm_wait_vblank_request val {}; + CPYT(type); + CPYT(sequence); + CPYT(signal); + return val; + } + + fex_drm_wait_vblank_request(struct drm_wait_vblank_request val) { + CPYF(type); + CPYF(sequence); + CPYF(signal); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_wait_vblank_reply") FEX_ANNOTATE("fex-match") fex_drm_wait_vblank_reply { + enum drm_vblank_seq_type type; + uint32_t sequence; + int32_t tval_sec; + int32_t tval_usec; + + fex_drm_wait_vblank_reply() = delete; + + operator drm_wait_vblank_reply() const { + drm_wait_vblank_reply val {}; + CPYT(type); + CPYT(sequence); + CPYT(tval_sec); + CPYT(tval_usec); + return val; + } + + fex_drm_wait_vblank_reply(struct drm_wait_vblank_reply val) { + CPYF(type); + CPYF(sequence); + CPYF(tval_sec); + CPYF(tval_usec); + } + }; + + union FEX_ANNOTATE("alias-x86_32-drm_wait_vblank") FEX_ANNOTATE("fex-match") fex_drm_wait_vblank { + fex_drm_wait_vblank_request request; + fex_drm_wait_vblank_reply reply; + + fex_drm_wait_vblank() = delete; + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_update_draw") FEX_ANNOTATE("fex-match") FEX_PACKED fex_drm_update_draw { + drm_drawable_t handle; + uint32_t type; + uint32_t num; + compat_uint64_t data; + + fex_drm_update_draw() = delete; + + operator drm_update_draw() const { + drm_update_draw val {}; + CPYT(handle); + CPYT(type); + CPYT(num); + CPYT(data); + return val; + } + + fex_drm_update_draw(struct drm_update_draw val) { + CPYF(handle); + CPYF(type); + CPYF(num); + CPYF(data); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_mode_get_plane_res") FEX_ANNOTATE("fex-match") FEX_PACKED fex_drm_mode_get_plane_res { + compat_uint64_t plane_id_ptr; + uint32_t count_planes; + fex_drm_mode_get_plane_res() = delete; + + operator drm_mode_get_plane_res() const { + drm_mode_get_plane_res val {}; + CPYT(plane_id_ptr); + CPYT(count_planes); + return val; + } + + fex_drm_mode_get_plane_res(struct drm_mode_get_plane_res val) { + CPYF(plane_id_ptr); + CPYF(count_planes); + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_mode_fb_cmd2") FEX_ANNOTATE("fex-match") FEX_PACKED fex_drm_mode_fb_cmd2 { + uint32_t fb_id; + uint32_t width; + uint32_t height; + uint32_t pixel_format; + uint32_t flags; + + uint32_t handles[4]; + uint32_t pitches[4]; + uint32_t offsets[4]; + compat_uint64_t modifier[4]; + fex_drm_mode_fb_cmd2() = delete; + + operator drm_mode_fb_cmd2() const { + drm_mode_fb_cmd2 val {}; + CPYT(fb_id); + CPYT(width); + CPYT(height); + CPYT(pixel_format); + CPYT(flags); + for (int i = 0; i < 4; ++i) { + CPYT(handles[i]); + CPYT(pitches[i]); + CPYT(offsets[i]); + CPYT(modifier[i]); + } + return val; + } + + fex_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 val) { + CPYF(fb_id); + CPYF(width); + CPYF(height); + CPYF(pixel_format); + CPYF(flags); + for (int i = 0; i < 4; ++i) { + CPYF(handles[i]); + CPYF(pitches[i]); + CPYF(offsets[i]); + CPYF(modifier[i]); + } + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_mode_obj_get_properties") FEX_ANNOTATE("fex-match") FEX_PACKED fex_drm_mode_obj_get_properties { + compat_uint64_t props_ptr; + compat_uint64_t prop_values_ptr; + uint32_t count_props; + uint32_t obj_id; + uint32_t obj_type; + + fex_drm_mode_obj_get_properties() = delete; + + operator drm_mode_obj_get_properties() const { + drm_mode_obj_get_properties val {}; + val.props_ptr = props_ptr; + val.prop_values_ptr = prop_values_ptr; + val.count_props = count_props; + val.obj_id = obj_id; + val.obj_type = obj_type; + return val; + } + + fex_drm_mode_obj_get_properties(struct drm_mode_obj_get_properties val) { + props_ptr = val.props_ptr; + prop_values_ptr = val.prop_values_ptr; + count_props = val.count_props; + obj_type = val.obj_type; + } + }; + + struct FEX_ANNOTATE("alias-x86_32-drm_mode_obj_set_property") FEX_ANNOTATE("fex-match") FEX_PACKED fex_drm_mode_obj_set_property { + compat_uint64_t value; + uint32_t prop_id; + uint32_t obj_id; + uint32_t obj_type; + + fex_drm_mode_obj_set_property() = delete; + + operator drm_mode_obj_set_property() const { + drm_mode_obj_set_property val {}; + val.value = value; + val.prop_id = prop_id; + val.obj_id = obj_id; + val.obj_type = obj_type; + return val; + } + + fex_drm_mode_obj_set_property(struct drm_mode_obj_set_property val) { + value = val.value; + prop_id = val.prop_id; + obj_id = val.obj_id; + obj_type = val.obj_type; + } + }; + +} // namespace DRM namespace AMDGPU { -struct -FEX_ANNOTATE("alias-x86_32-drm_amdgpu_gem_metadata") -FEX_ANNOTATE("fex-match") -fex_drm_amdgpu_gem_metadata { - __u32 handle; - __u32 op; - struct { - compat_uint64_t flags; - compat_uint64_t tiling_info; - __u32 data_size_bytes; - __u32 data[64]; - } data; + struct FEX_ANNOTATE("alias-x86_32-drm_amdgpu_gem_metadata") FEX_ANNOTATE("fex-match") fex_drm_amdgpu_gem_metadata { + __u32 handle; + __u32 op; + struct { + compat_uint64_t flags; + compat_uint64_t tiling_info; + __u32 data_size_bytes; + __u32 data[64]; + } data; - fex_drm_amdgpu_gem_metadata() = delete; - operator drm_amdgpu_gem_metadata() const { - drm_amdgpu_gem_metadata val{}; - val.handle = handle; - val.op = op; - val.data.flags = data.flags; - val.data.tiling_info = data.tiling_info; - val.data.data_size_bytes = data.data_size_bytes; - memcpy(val.data.data, data.data, sizeof(data.data)); - return val; - } + fex_drm_amdgpu_gem_metadata() = delete; + operator drm_amdgpu_gem_metadata() const { + drm_amdgpu_gem_metadata val {}; + val.handle = handle; + val.op = op; + val.data.flags = data.flags; + val.data.tiling_info = data.tiling_info; + val.data.data_size_bytes = data.data_size_bytes; + memcpy(val.data.data, data.data, sizeof(data.data)); + return val; + } - fex_drm_amdgpu_gem_metadata(struct drm_amdgpu_gem_metadata val) { - handle = val.handle; - op = val.op; - data.flags = val.data.flags; - data.tiling_info = val.data.tiling_info; - data.data_size_bytes = val.data.data_size_bytes; - memcpy(data.data, val.data.data, sizeof(data.data)); - } -}; -} + fex_drm_amdgpu_gem_metadata(struct drm_amdgpu_gem_metadata val) { + handle = val.handle; + op = val.op; + data.flags = val.data.flags; + data.tiling_info = val.data.tiling_info; + data.data_size_bytes = val.data.data_size_bytes; + memcpy(data.data, val.data.data, sizeof(data.data)); + } + }; +} // namespace AMDGPU namespace RADEON { -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_gem_create") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_gem_create { - compat_uint64_t size; - compat_uint64_t alignment; - __u32 handle; - __u32 initial_domain; - __u32 flags; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_gem_create") FEX_ANNOTATE("fex-match") fex_drm_radeon_gem_create { + compat_uint64_t size; + compat_uint64_t alignment; + __u32 handle; + __u32 initial_domain; + __u32 flags; - fex_drm_radeon_gem_create() = delete; + fex_drm_radeon_gem_create() = delete; - operator drm_radeon_gem_create() const { - drm_radeon_gem_create val{}; - val.size = size; - val.alignment = alignment; - val.handle = handle; - val.initial_domain = initial_domain; - val.flags = flags; - return val; - } + operator drm_radeon_gem_create() const { + drm_radeon_gem_create val {}; + val.size = size; + val.alignment = alignment; + val.handle = handle; + val.initial_domain = initial_domain; + val.flags = flags; + return val; + } - fex_drm_radeon_gem_create(struct drm_radeon_gem_create val) { - size = val.size; - alignment = val.alignment; - handle = val.handle; - initial_domain = val.initial_domain; - flags = val.flags; - } -}; + fex_drm_radeon_gem_create(struct drm_radeon_gem_create val) { + size = val.size; + alignment = val.alignment; + handle = val.handle; + initial_domain = val.initial_domain; + flags = val.flags; + } + }; -struct -FEX_PACKED -FEX_ANNOTATE("alias-x86_32-drm_radeon_init") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_init_t { - enum { - } func; + struct FEX_PACKED FEX_ANNOTATE("alias-x86_32-drm_radeon_init") FEX_ANNOTATE("fex-match") fex_drm_radeon_init_t { + enum {} func; - compat_ulong_t sarea_priv_offset; - int32_t is_pci; - int32_t cp_mode; - int32_t gart_size; - int32_t ring_size; - int32_t usec_timeout; + compat_ulong_t sarea_priv_offset; + int32_t is_pci; + int32_t cp_mode; + int32_t gart_size; + int32_t ring_size; + int32_t usec_timeout; - uint32_t fb_bpp; - uint32_t front_offset, front_pitch; - uint32_t back_offset, back_pitch; - uint32_t depth_bpp; - uint32_t depth_offset, depth_pitch; + uint32_t fb_bpp; + uint32_t front_offset, front_pitch; + uint32_t back_offset, back_pitch; + uint32_t depth_bpp; + uint32_t depth_offset, depth_pitch; - compat_ulong_t fb_offset; - compat_ulong_t mmio_offset; - compat_ulong_t ring_offset; - compat_ulong_t ring_rptr_offset; - compat_ulong_t buffers_offset; - compat_ulong_t gart_textures_offset; + compat_ulong_t fb_offset; + compat_ulong_t mmio_offset; + compat_ulong_t ring_offset; + compat_ulong_t ring_rptr_offset; + compat_ulong_t buffers_offset; + compat_ulong_t gart_textures_offset; - fex_drm_radeon_init_t() = delete; + fex_drm_radeon_init_t() = delete; - operator drm_radeon_init_t() const { - drm_radeon_init_t val{}; - val.sarea_priv_offset = sarea_priv_offset; - val.is_pci = is_pci; - val.cp_mode = cp_mode; - val.gart_size = gart_size; - val.ring_size = ring_size; - val.usec_timeout = usec_timeout; - val.fb_bpp = fb_bpp; - val.front_offset = front_offset; - val.front_pitch = front_pitch; - val.back_offset = back_offset; - val.back_pitch = back_pitch; - val.depth_bpp = depth_bpp; - val.depth_offset = depth_offset; - val.depth_pitch = depth_pitch; - val.fb_offset = fb_offset; - val.mmio_offset = mmio_offset; - val.ring_offset = ring_offset; - val.ring_rptr_offset = ring_rptr_offset; - val.buffers_offset = buffers_offset; - val.gart_textures_offset = gart_textures_offset; - return val; - } + operator drm_radeon_init_t() const { + drm_radeon_init_t val {}; + val.sarea_priv_offset = sarea_priv_offset; + val.is_pci = is_pci; + val.cp_mode = cp_mode; + val.gart_size = gart_size; + val.ring_size = ring_size; + val.usec_timeout = usec_timeout; + val.fb_bpp = fb_bpp; + val.front_offset = front_offset; + val.front_pitch = front_pitch; + val.back_offset = back_offset; + val.back_pitch = back_pitch; + val.depth_bpp = depth_bpp; + val.depth_offset = depth_offset; + val.depth_pitch = depth_pitch; + val.fb_offset = fb_offset; + val.mmio_offset = mmio_offset; + val.ring_offset = ring_offset; + val.ring_rptr_offset = ring_rptr_offset; + val.buffers_offset = buffers_offset; + val.gart_textures_offset = gart_textures_offset; + return val; + } - fex_drm_radeon_init_t(drm_radeon_init_t val) { - sarea_priv_offset = val.sarea_priv_offset; - is_pci = val.is_pci; - cp_mode = val.cp_mode; - gart_size = val.gart_size; - ring_size = val.ring_size; - usec_timeout = val.usec_timeout; - fb_bpp = val.fb_bpp; - front_offset = val.front_offset; - front_pitch = val.front_pitch; - back_offset = val.back_offset; - back_pitch = val.back_pitch; - depth_bpp = val.depth_bpp; - depth_offset = val.depth_offset; - depth_pitch = val.depth_pitch; - fb_offset = val.fb_offset; - mmio_offset = val.mmio_offset; - ring_offset = val.ring_offset; - ring_rptr_offset = val.ring_rptr_offset; - buffers_offset = val.buffers_offset; - gart_textures_offset = val.gart_textures_offset; - } -}; + fex_drm_radeon_init_t(drm_radeon_init_t val) { + sarea_priv_offset = val.sarea_priv_offset; + is_pci = val.is_pci; + cp_mode = val.cp_mode; + gart_size = val.gart_size; + ring_size = val.ring_size; + usec_timeout = val.usec_timeout; + fb_bpp = val.fb_bpp; + front_offset = val.front_offset; + front_pitch = val.front_pitch; + back_offset = val.back_offset; + back_pitch = val.back_pitch; + depth_bpp = val.depth_bpp; + depth_offset = val.depth_offset; + depth_pitch = val.depth_pitch; + fb_offset = val.fb_offset; + mmio_offset = val.mmio_offset; + ring_offset = val.ring_offset; + ring_rptr_offset = val.ring_rptr_offset; + buffers_offset = val.buffers_offset; + gart_textures_offset = val.gart_textures_offset; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_clear") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_clear_t { - uint32_t flags; - uint32_t clear_color; - uint32_t clear_depth; - uint32_t color_mask; - uint32_t depth_mask; - compat_ptr depth_boxes; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_clear") FEX_ANNOTATE("fex-match") fex_drm_radeon_clear_t { + uint32_t flags; + uint32_t clear_color; + uint32_t clear_depth; + uint32_t color_mask; + uint32_t depth_mask; + compat_ptr depth_boxes; - fex_drm_radeon_clear_t() = delete; + fex_drm_radeon_clear_t() = delete; - operator drm_radeon_clear_t() const { - drm_radeon_clear_t val{}; - val.flags = flags; - val.clear_color = clear_color; - val.clear_depth = clear_depth; - val.color_mask = color_mask; - val.depth_mask = depth_mask; - val.depth_boxes = depth_boxes; - return val; - } + operator drm_radeon_clear_t() const { + drm_radeon_clear_t val {}; + val.flags = flags; + val.clear_color = clear_color; + val.clear_depth = clear_depth; + val.color_mask = color_mask; + val.depth_mask = depth_mask; + val.depth_boxes = depth_boxes; + return val; + } - fex_drm_radeon_clear_t(drm_radeon_clear_t val) - : depth_boxes {val.depth_boxes} { - flags = val.flags; - clear_color = val.clear_color; - clear_depth = val.clear_depth; - color_mask = val.color_mask; - depth_mask = val.depth_mask; - } -}; + fex_drm_radeon_clear_t(drm_radeon_clear_t val) + : depth_boxes {val.depth_boxes} { + flags = val.flags; + clear_color = val.clear_color; + clear_depth = val.clear_depth; + color_mask = val.color_mask; + depth_mask = val.depth_mask; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_stipple") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_stipple_t { - compat_ptr mask; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_stipple") FEX_ANNOTATE("fex-match") fex_drm_radeon_stipple_t { + compat_ptr mask; - fex_drm_radeon_stipple_t() = delete; + fex_drm_radeon_stipple_t() = delete; - operator drm_radeon_stipple_t() const { - drm_radeon_stipple_t val{}; - val.mask = mask; - return val; - } + operator drm_radeon_stipple_t() const { + drm_radeon_stipple_t val {}; + val.mask = mask; + return val; + } - fex_drm_radeon_stipple_t(drm_radeon_stipple_t val) - : mask {val.mask} { - } -}; + fex_drm_radeon_stipple_t(drm_radeon_stipple_t val) + : mask {val.mask} {} + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_texture") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_texture_t { - uint32_t offset; - int32_t pitch; - int32_t format; - int32_t width; - int32_t height; - compat_ptr image; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_texture") FEX_ANNOTATE("fex-match") fex_drm_radeon_texture_t { + uint32_t offset; + int32_t pitch; + int32_t format; + int32_t width; + int32_t height; + compat_ptr image; - fex_drm_radeon_texture_t() = delete; + fex_drm_radeon_texture_t() = delete; - operator drm_radeon_texture_t() const { - drm_radeon_texture_t val{}; - val.offset = offset; - val.pitch = pitch; - val.format = format; - val.width = width; - val.height = height; - val.image = image; - return val; - } + operator drm_radeon_texture_t() const { + drm_radeon_texture_t val {}; + val.offset = offset; + val.pitch = pitch; + val.format = format; + val.width = width; + val.height = height; + val.image = image; + return val; + } - fex_drm_radeon_texture_t(drm_radeon_texture_t val) - : image {val.image} { - offset = val.offset; - pitch = val.pitch; - format = val.format; - width = val.width; - height = val.height; - } -}; + fex_drm_radeon_texture_t(drm_radeon_texture_t val) + : image {val.image} { + offset = val.offset; + pitch = val.pitch; + format = val.format; + width = val.width; + height = val.height; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_vertex2") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_vertex2_t { - int32_t idx; - int32_t discard; - int32_t nr_states; - compat_ptr state; - int32_t nr_prims; - compat_ptr prim; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_vertex2") FEX_ANNOTATE("fex-match") fex_drm_radeon_vertex2_t { + int32_t idx; + int32_t discard; + int32_t nr_states; + compat_ptr state; + int32_t nr_prims; + compat_ptr prim; - fex_drm_radeon_vertex2_t() = delete; + fex_drm_radeon_vertex2_t() = delete; - operator drm_radeon_vertex2_t() const { - drm_radeon_vertex2_t val; - val.idx = idx; - val.discard = discard; - val.nr_states = nr_states; - val.state = state; - val.nr_prims = nr_prims; - val.prim = prim; - return val; - } + operator drm_radeon_vertex2_t() const { + drm_radeon_vertex2_t val; + val.idx = idx; + val.discard = discard; + val.nr_states = nr_states; + val.state = state; + val.nr_prims = nr_prims; + val.prim = prim; + return val; + } - fex_drm_radeon_vertex2_t(drm_radeon_vertex2_t val) - : state {val.state} - , prim {val.prim} { - idx = val.idx; - discard = val.discard; - nr_states = val.nr_states; - nr_prims = val.nr_prims; - } -}; + fex_drm_radeon_vertex2_t(drm_radeon_vertex2_t val) + : state {val.state} + , prim {val.prim} { + idx = val.idx; + discard = val.discard; + nr_states = val.nr_states; + nr_prims = val.nr_prims; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_cmd_buffer") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_cmd_buffer_t { - int32_t bufsz; - compat_ptr buf; - int32_t nbox; - compat_ptr boxes; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_cmd_buffer") FEX_ANNOTATE("fex-match") fex_drm_radeon_cmd_buffer_t { + int32_t bufsz; + compat_ptr buf; + int32_t nbox; + compat_ptr boxes; - fex_drm_radeon_cmd_buffer_t() = delete; + fex_drm_radeon_cmd_buffer_t() = delete; - operator drm_radeon_cmd_buffer_t() const { - drm_radeon_cmd_buffer_t val; - val.bufsz = bufsz; - val.buf = buf; - val.nbox = nbox; - val.boxes = boxes; - return val; - } + operator drm_radeon_cmd_buffer_t() const { + drm_radeon_cmd_buffer_t val; + val.bufsz = bufsz; + val.buf = buf; + val.nbox = nbox; + val.boxes = boxes; + return val; + } - fex_drm_radeon_cmd_buffer_t(drm_radeon_cmd_buffer_t val) - : buf {val.buf} - , boxes {val.boxes} { - val.bufsz = bufsz; - val.nbox = nbox; - } -}; + fex_drm_radeon_cmd_buffer_t(drm_radeon_cmd_buffer_t val) + : buf {val.buf} + , boxes {val.boxes} { + val.bufsz = bufsz; + val.nbox = nbox; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_getparam") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_getparam_t { - int32_t param; - compat_ptr value; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_getparam") FEX_ANNOTATE("fex-match") fex_drm_radeon_getparam_t { + int32_t param; + compat_ptr value; - fex_drm_radeon_getparam_t() = delete; + fex_drm_radeon_getparam_t() = delete; - operator drm_radeon_getparam_t() const { - drm_radeon_getparam_t val; - val.param = param; - val.value = value; - return val; - } + operator drm_radeon_getparam_t() const { + drm_radeon_getparam_t val; + val.param = param; + val.value = value; + return val; + } - fex_drm_radeon_getparam_t(drm_radeon_getparam_t val) - : value {val.value} { - val.param = param; - } -}; + fex_drm_radeon_getparam_t(drm_radeon_getparam_t val) + : value {val.value} { + val.param = param; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_mem_alloc") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_mem_alloc_t { - int32_t region; - int32_t alignment; - int32_t size; - compat_ptr region_offset; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_mem_alloc") FEX_ANNOTATE("fex-match") fex_drm_radeon_mem_alloc_t { + int32_t region; + int32_t alignment; + int32_t size; + compat_ptr region_offset; - fex_drm_radeon_mem_alloc_t() = delete; + fex_drm_radeon_mem_alloc_t() = delete; - operator drm_radeon_mem_alloc_t() const { - drm_radeon_mem_alloc_t val; - val.region = region; - val.alignment = alignment; - val.size = size; - val.region_offset = region_offset; - return val; - } + operator drm_radeon_mem_alloc_t() const { + drm_radeon_mem_alloc_t val; + val.region = region; + val.alignment = alignment; + val.size = size; + val.region_offset = region_offset; + return val; + } - fex_drm_radeon_mem_alloc_t(drm_radeon_mem_alloc_t val) - : region_offset {val.region_offset} { - val.region = region; - val.alignment = alignment; - val.size = size; - } -}; + fex_drm_radeon_mem_alloc_t(drm_radeon_mem_alloc_t val) + : region_offset {val.region_offset} { + val.region = region; + val.alignment = alignment; + val.size = size; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_irq_emit") -FEX_ANNOTATE("fex-match") -fex_drm_radeon_irq_emit_t { - compat_ptr irq_seq; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_irq_emit") FEX_ANNOTATE("fex-match") fex_drm_radeon_irq_emit_t { + compat_ptr irq_seq; - fex_drm_radeon_irq_emit_t() = delete; + fex_drm_radeon_irq_emit_t() = delete; - operator drm_radeon_irq_emit_t() const { - drm_radeon_irq_emit_t val; - val.irq_seq = irq_seq; - return val; - } + operator drm_radeon_irq_emit_t() const { + drm_radeon_irq_emit_t val; + val.irq_seq = irq_seq; + return val; + } - fex_drm_radeon_irq_emit_t(drm_radeon_irq_emit_t val) - : irq_seq {val.irq_seq} { - } -}; + fex_drm_radeon_irq_emit_t(drm_radeon_irq_emit_t val) + : irq_seq {val.irq_seq} {} + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_radeon_setparam") -FEX_ANNOTATE("fex-match") -FEX_PACKED -fex_drm_radeon_setparam_t { - uint32_t param; - compat_int64_t value; + struct FEX_ANNOTATE("alias-x86_32-drm_radeon_setparam") FEX_ANNOTATE("fex-match") FEX_PACKED fex_drm_radeon_setparam_t { + uint32_t param; + compat_int64_t value; - fex_drm_radeon_setparam_t() = delete; + fex_drm_radeon_setparam_t() = delete; - operator drm_radeon_setparam_t() const { - drm_radeon_setparam_t val; - val.param = param; - val.value = value; - return val; - } + operator drm_radeon_setparam_t() const { + drm_radeon_setparam_t val; + val.param = param; + val.value = value; + return val; + } - fex_drm_radeon_setparam_t(drm_radeon_setparam_t val) { - param = val.param; - value = val.value; - } -}; + fex_drm_radeon_setparam_t(drm_radeon_setparam_t val) { + param = val.param; + value = val.value; + } + }; -} +} // namespace RADEON namespace MSM { -struct -FEX_ANNOTATE("alias-x86_32-drm_msm_timespec") -FEX_ANNOTATE("fex-match") -fex_drm_msm_timespec { - compat_int64_t tv_sec; - compat_int64_t tv_nsec; + struct FEX_ANNOTATE("alias-x86_32-drm_msm_timespec") FEX_ANNOTATE("fex-match") fex_drm_msm_timespec { + compat_int64_t tv_sec; + compat_int64_t tv_nsec; - fex_drm_msm_timespec() = delete; - operator drm_msm_timespec() const { - drm_msm_timespec val{}; - val.tv_sec = tv_sec; - val.tv_nsec = tv_nsec; - return val; - } + fex_drm_msm_timespec() = delete; + operator drm_msm_timespec() const { + drm_msm_timespec val {}; + val.tv_sec = tv_sec; + val.tv_nsec = tv_nsec; + return val; + } - fex_drm_msm_timespec(struct drm_msm_timespec val) { - tv_sec = val.tv_sec; - tv_nsec = val.tv_nsec; - } -}; + fex_drm_msm_timespec(struct drm_msm_timespec val) { + tv_sec = val.tv_sec; + tv_nsec = val.tv_nsec; + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_msm_wait_fence") -FEX_ANNOTATE("fex-match") -FEX_PACKED -fex_drm_msm_wait_fence { - uint32_t fence; - uint32_t flags; - struct fex_drm_msm_timespec timeout; - uint32_t queueid; + struct FEX_ANNOTATE("alias-x86_32-drm_msm_wait_fence") FEX_ANNOTATE("fex-match") FEX_PACKED fex_drm_msm_wait_fence { + uint32_t fence; + uint32_t flags; + struct fex_drm_msm_timespec timeout; + uint32_t queueid; - fex_drm_msm_wait_fence() = delete; + fex_drm_msm_wait_fence() = delete; - operator drm_msm_wait_fence() const { - drm_msm_wait_fence val{}; - val.fence = fence; - val.flags = flags; - val.timeout = timeout; - val.queueid = queueid; - return val; - } + operator drm_msm_wait_fence() const { + drm_msm_wait_fence val {}; + val.fence = fence; + val.flags = flags; + val.timeout = timeout; + val.queueid = queueid; + return val; + } - fex_drm_msm_wait_fence(struct drm_msm_wait_fence val) - : timeout {val.timeout} { - fence = val.fence; - flags = val.flags; - queueid = val.queueid; - } -}; + fex_drm_msm_wait_fence(struct drm_msm_wait_fence val) + : timeout {val.timeout} { + fence = val.fence; + flags = val.flags; + queueid = val.queueid; + } + }; -} +} // namespace MSM namespace I915 { -struct -FEX_ANNOTATE("alias-x86_32-drm_i915_batchbuffer") -FEX_ANNOTATE("fex-match") -fex_drm_i915_batchbuffer_t { - int32_t start; - int32_t used; - int32_t DR1; - int32_t DR4; - int32_t num_cliprects; - compat_ptr cliprects; + struct FEX_ANNOTATE("alias-x86_32-drm_i915_batchbuffer") FEX_ANNOTATE("fex-match") fex_drm_i915_batchbuffer_t { + int32_t start; + int32_t used; + int32_t DR1; + int32_t DR4; + int32_t num_cliprects; + compat_ptr cliprects; - fex_drm_i915_batchbuffer_t() = delete; + fex_drm_i915_batchbuffer_t() = delete; - operator drm_i915_batchbuffer_t() const { - drm_i915_batchbuffer_t val{}; - CPYT(start); - CPYT(used); - CPYT(DR1); - CPYT(DR4); - CPYT(num_cliprects); - CPYT(cliprects); - return val; - } + operator drm_i915_batchbuffer_t() const { + drm_i915_batchbuffer_t val {}; + CPYT(start); + CPYT(used); + CPYT(DR1); + CPYT(DR4); + CPYT(num_cliprects); + CPYT(cliprects); + return val; + } - fex_drm_i915_batchbuffer_t(drm_i915_batchbuffer_t val) - : cliprects { val.cliprects } { - CPYF(start); - CPYF(used); - CPYF(DR1); - CPYF(DR4); - CPYF(num_cliprects); - } -}; + fex_drm_i915_batchbuffer_t(drm_i915_batchbuffer_t val) + : cliprects {val.cliprects} { + CPYF(start); + CPYF(used); + CPYF(DR1); + CPYF(DR4); + CPYF(num_cliprects); + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_i915_irq_emit") -FEX_ANNOTATE("fex-match") -fex_drm_i915_irq_emit_t { - compat_ptr irq_seq; + struct FEX_ANNOTATE("alias-x86_32-drm_i915_irq_emit") FEX_ANNOTATE("fex-match") fex_drm_i915_irq_emit_t { + compat_ptr irq_seq; - fex_drm_i915_irq_emit_t() = delete; + fex_drm_i915_irq_emit_t() = delete; - operator drm_i915_irq_emit_t() const { - drm_i915_irq_emit_t val{}; - CPYT(irq_seq); - return val; - } + operator drm_i915_irq_emit_t() const { + drm_i915_irq_emit_t val {}; + CPYT(irq_seq); + return val; + } - fex_drm_i915_irq_emit_t(drm_i915_irq_emit_t val) - : irq_seq { val.irq_seq } { - } -}; + fex_drm_i915_irq_emit_t(drm_i915_irq_emit_t val) + : irq_seq {val.irq_seq} {} + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_i915_getparam") -FEX_ANNOTATE("fex-match") -fex_drm_i915_getparam_t -{ - int32_t param; - compat_ptr value; - fex_drm_i915_getparam_t() = delete; + struct FEX_ANNOTATE("alias-x86_32-drm_i915_getparam") FEX_ANNOTATE("fex-match") fex_drm_i915_getparam_t { + int32_t param; + compat_ptr value; + fex_drm_i915_getparam_t() = delete; - operator drm_i915_getparam_t() const { - drm_i915_getparam_t val{}; - CPYT(param); - CPYT(value); - return val; - } + operator drm_i915_getparam_t() const { + drm_i915_getparam_t val {}; + CPYT(param); + CPYT(value); + return val; + } - fex_drm_i915_getparam_t(drm_i915_getparam_t val) - : value { val.value } { - CPYF(param); - } -}; + fex_drm_i915_getparam_t(drm_i915_getparam_t val) + : value {val.value} { + CPYF(param); + } + }; -struct -FEX_ANNOTATE("alias-x86_32-drm_i915_mem_alloc") -FEX_ANNOTATE("fex-match") -fex_drm_i915_mem_alloc_t -{ - int32_t region; - int32_t alignment; - int32_t size; - compat_ptr region_offset; - fex_drm_i915_mem_alloc_t() = delete; + struct FEX_ANNOTATE("alias-x86_32-drm_i915_mem_alloc") FEX_ANNOTATE("fex-match") fex_drm_i915_mem_alloc_t { + int32_t region; + int32_t alignment; + int32_t size; + compat_ptr region_offset; + fex_drm_i915_mem_alloc_t() = delete; - operator drm_i915_mem_alloc_t() const { - drm_i915_mem_alloc_t val{}; - CPYT(region); - CPYT(alignment); - CPYT(size); - CPYT(region_offset); - return val; - } + operator drm_i915_mem_alloc_t() const { + drm_i915_mem_alloc_t val {}; + CPYT(region); + CPYT(alignment); + CPYT(size); + CPYT(region_offset); + return val; + } - fex_drm_i915_mem_alloc_t(drm_i915_mem_alloc_t val) - : region_offset { val.region_offset } { - CPYT(region); - CPYT(alignment); - CPYT(size); - } -}; + fex_drm_i915_mem_alloc_t(drm_i915_mem_alloc_t val) + : region_offset {val.region_offset} { + CPYT(region); + CPYT(alignment); + CPYT(size); + } + }; -struct -FEX_ANNOTATE("alias-x86_32-_drm_i915_cmdbuffer") -FEX_ANNOTATE("fex-match") -fex_drm_i915_cmdbuffer_t -{ - compat_ptr buf; - int32_t sz; - int32_t DR1; - int32_t DR4; - int32_t num_cliprects; - compat_ptr cliprects; + struct FEX_ANNOTATE("alias-x86_32-_drm_i915_cmdbuffer") FEX_ANNOTATE("fex-match") fex_drm_i915_cmdbuffer_t { + compat_ptr buf; + int32_t sz; + int32_t DR1; + int32_t DR4; + int32_t num_cliprects; + compat_ptr cliprects; - fex_drm_i915_cmdbuffer_t() = delete; + fex_drm_i915_cmdbuffer_t() = delete; - operator drm_i915_cmdbuffer_t() const { - drm_i915_cmdbuffer_t val{}; - CPYT(buf); - CPYT(sz); - CPYT(DR1); - CPYT(DR4); - CPYT(num_cliprects); - CPYT(cliprects); - return val; - } + operator drm_i915_cmdbuffer_t() const { + drm_i915_cmdbuffer_t val {}; + CPYT(buf); + CPYT(sz); + CPYT(DR1); + CPYT(DR4); + CPYT(num_cliprects); + CPYT(cliprects); + return val; + } - fex_drm_i915_cmdbuffer_t(drm_i915_cmdbuffer_t val) - : buf { val.buf } - , cliprects { val.cliprects } { - CPYT(sz); - CPYT(DR1); - CPYT(DR4); - CPYT(num_cliprects); - } -}; + fex_drm_i915_cmdbuffer_t(drm_i915_cmdbuffer_t val) + : buf {val.buf} + , cliprects {val.cliprects} { + CPYT(sz); + CPYT(DR1); + CPYT(DR4); + CPYT(num_cliprects); + } + }; // I915 defines if they don't exist // Older DRM doesn't have this #ifndef DRM_IOCTL_I915_GEM_MMAP_OFFSET -struct drm_i915_gem_mmap_offset { - uint32_t handle; - uint32_t pad; - compat_uint64_t offset; - compat_uint64_t flags; - compat_uint64_t extensions; -}; + struct drm_i915_gem_mmap_offset { + uint32_t handle; + uint32_t pad; + compat_uint64_t offset; + compat_uint64_t flags; + compat_uint64_t extensions; + }; -#define DRM_IOCTL_I915_GEM_MMAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, FEX::HLE::x32::I915::drm_i915_gem_mmap_offset) +#define DRM_IOCTL_I915_GEM_MMAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, FEX::HLE::x32::I915::drm_i915_gem_mmap_offset) #endif -} +} // namespace I915 namespace VC4 { -struct -FEX_ANNOTATE("alias-x86_32-drm_vc4_perfmon_get_values") -FEX_ANNOTATE("fex-match") -fex_drm_vc4_perfmon_get_values { - uint32_t id; - compat_uint64_t values_ptr; + struct FEX_ANNOTATE("alias-x86_32-drm_vc4_perfmon_get_values") FEX_ANNOTATE("fex-match") fex_drm_vc4_perfmon_get_values { + uint32_t id; + compat_uint64_t values_ptr; - fex_drm_vc4_perfmon_get_values() = delete; + fex_drm_vc4_perfmon_get_values() = delete; - operator drm_vc4_perfmon_get_values() const { - drm_vc4_perfmon_get_values val{}; - val.id = id; - val.values_ptr = values_ptr; - return val; - } - fex_drm_vc4_perfmon_get_values(drm_vc4_perfmon_get_values val) { - id = val.id; - values_ptr = val.values_ptr; - } -}; + operator drm_vc4_perfmon_get_values() const { + drm_vc4_perfmon_get_values val {}; + val.id = id; + val.values_ptr = values_ptr; + return val; + } + fex_drm_vc4_perfmon_get_values(drm_vc4_perfmon_get_values val) { + id = val.id; + values_ptr = val.values_ptr; + } + }; -} +} // namespace VC4 namespace V3D { -struct -FEX_ANNOTATE("alias-x86_32-drm_v3d_submit_csd") -FEX_ANNOTATE("fex-match") -fex_drm_v3d_submit_csd { - uint32_t cfg[7]; - uint32_t coef[4]; + struct FEX_ANNOTATE("alias-x86_32-drm_v3d_submit_csd") FEX_ANNOTATE("fex-match") fex_drm_v3d_submit_csd { + uint32_t cfg[7]; + uint32_t coef[4]; - compat_uint64_t bo_handles; + compat_uint64_t bo_handles; - uint32_t bo_handle_count; + uint32_t bo_handle_count; - uint32_t in_sync; + uint32_t in_sync; - uint32_t out_sync; + uint32_t out_sync; - /** - * @name This member were added in Linux 5.15 - * Commit: 26a4dc29b74a137f45665089f6d3d633fcc9b662 - * - * As far as I can tell this is an ABI break, Probably safe since this likely would have been padded to 8 bytes. - * Still pretty sketchy. - * @{ */ + /** + * @name This member were added in Linux 5.15 + * Commit: 26a4dc29b74a137f45665089f6d3d633fcc9b662 + * + * As far as I can tell this is an ABI break, Probably safe since this likely would have been padded to 8 bytes. + * Still pretty sketchy. + * @{ */ - uint32_t perfmon_id; - /** @} */ + uint32_t perfmon_id; + /** @} */ - /** - * @name These members were added in Linux 5.17 - * Commit: bb3425efdcd99f2b4e608e850226f7107b2f993e - * This added additional members to `drm_v3d_submit_cl` and `drm_v3d_submit_tfu` as well. - * - * As far as I can tell this is an ABI break for the `submit_tfu` and `submit_csd` structs. - * `submit_cl` is safe because it it already had a flags member. - * - * We just need to eat the fact that if the userspace isn't compiled against Linux 5.17 headers - * that copying this member may cause faults that we can't capture currently. - * @{ */ + /** + * @name These members were added in Linux 5.17 + * Commit: bb3425efdcd99f2b4e608e850226f7107b2f993e + * This added additional members to `drm_v3d_submit_cl` and `drm_v3d_submit_tfu` as well. + * + * As far as I can tell this is an ABI break for the `submit_tfu` and `submit_csd` structs. + * `submit_cl` is safe because it it already had a flags member. + * + * We just need to eat the fact that if the userspace isn't compiled against Linux 5.17 headers + * that copying this member may cause faults that we can't capture currently. + * @{ */ - compat_uint64_t extensions; + compat_uint64_t extensions; - uint32_t flags; + uint32_t flags; - uint32_t pad; - /** @} */ + uint32_t pad; + /** @} */ - fex_drm_v3d_submit_csd() = default; + fex_drm_v3d_submit_csd() = default; - operator drm_v3d_submit_csd() const { - drm_v3d_submit_csd val{}; - memcpy(val.cfg, cfg, sizeof(cfg)); - memcpy(val.coef, coef, sizeof(coef)); - val.bo_handles = bo_handles; - val.bo_handle_count = bo_handle_count; - val.in_sync = in_sync; - val.out_sync = out_sync; - val.perfmon_id = perfmon_id; - val.extensions = extensions; - val.flags = flags; - val.pad = pad; - return val; - } + operator drm_v3d_submit_csd() const { + drm_v3d_submit_csd val {}; + memcpy(val.cfg, cfg, sizeof(cfg)); + memcpy(val.coef, coef, sizeof(coef)); + val.bo_handles = bo_handles; + val.bo_handle_count = bo_handle_count; + val.in_sync = in_sync; + val.out_sync = out_sync; + val.perfmon_id = perfmon_id; + val.extensions = extensions; + val.flags = flags; + val.pad = pad; + return val; + } - static void SafeConvertToGuest(fex_drm_v3d_submit_csd *Result, drm_v3d_submit_csd Src, size_t IoctlSize) { - // We need to be more careful since this API changes over time - fex_drm_v3d_submit_csd Tmp = Src; - memcpy(Result, &Tmp, IoctlSize); - } + static void SafeConvertToGuest(fex_drm_v3d_submit_csd* Result, drm_v3d_submit_csd Src, size_t IoctlSize) { + // We need to be more careful since this API changes over time + fex_drm_v3d_submit_csd Tmp = Src; + memcpy(Result, &Tmp, IoctlSize); + } - static - drm_v3d_submit_csd SafeConvertToHost(fex_drm_v3d_submit_csd *Src, size_t IoctlSize) { - // We need to be more careful since this API changes over time - drm_v3d_submit_csd Result{}; + static drm_v3d_submit_csd SafeConvertToHost(fex_drm_v3d_submit_csd* Src, size_t IoctlSize) { + // We need to be more careful since this API changes over time + drm_v3d_submit_csd Result {}; - // Copy the incoming variable over with memcpy - // This way if it is smaller than expected we will zero the remaining struct - fex_drm_v3d_submit_csd Tmp{}; - memcpy(&Tmp, Src, std::min(IoctlSize, sizeof(fex_drm_v3d_submit_csd))); + // Copy the incoming variable over with memcpy + // This way if it is smaller than expected we will zero the remaining struct + fex_drm_v3d_submit_csd Tmp {}; + memcpy(&Tmp, Src, std::min(IoctlSize, sizeof(fex_drm_v3d_submit_csd))); - memcpy(Result.cfg, Tmp.cfg, sizeof(cfg)); - memcpy(Result.coef, Tmp.coef, sizeof(coef)); - Result.bo_handles = Tmp.bo_handles; - Result.bo_handle_count = Tmp.bo_handle_count; - Result.in_sync = Tmp.in_sync; - Result.out_sync = Tmp.out_sync; - Result.perfmon_id = Tmp.perfmon_id; - Result.extensions = Tmp.extensions; - Result.flags = Tmp.flags; - Result.pad = Tmp.pad; + memcpy(Result.cfg, Tmp.cfg, sizeof(cfg)); + memcpy(Result.coef, Tmp.coef, sizeof(coef)); + Result.bo_handles = Tmp.bo_handles; + Result.bo_handle_count = Tmp.bo_handle_count; + Result.in_sync = Tmp.in_sync; + Result.out_sync = Tmp.out_sync; + Result.perfmon_id = Tmp.perfmon_id; + Result.extensions = Tmp.extensions; + Result.flags = Tmp.flags; + Result.pad = Tmp.pad; - return Result; - } + return Result; + } - fex_drm_v3d_submit_csd(drm_v3d_submit_csd val) { - memcpy(cfg, val.cfg, sizeof(cfg)); - memcpy(coef, val.coef, sizeof(coef)); - bo_handles = val.bo_handles; - bo_handle_count = val.bo_handle_count; - in_sync = val.in_sync; - out_sync = val.out_sync; - perfmon_id = val.perfmon_id; - extensions = val.extensions; - flags = val.flags; - pad = val.pad; - } -}; + fex_drm_v3d_submit_csd(drm_v3d_submit_csd val) { + memcpy(cfg, val.cfg, sizeof(cfg)); + memcpy(coef, val.coef, sizeof(coef)); + bo_handles = val.bo_handles; + bo_handle_count = val.bo_handle_count; + in_sync = val.in_sync; + out_sync = val.out_sync; + perfmon_id = val.perfmon_id; + extensions = val.extensions; + flags = val.flags; + pad = val.pad; + } + }; -} +} // namespace V3D #include "LinuxSyscalls/x32/Ioctl/drm.inl" #include "LinuxSyscalls/x32/Ioctl/amdgpu_drm.inl" @@ -1426,6 +1274,6 @@ fex_drm_v3d_submit_csd { #include "LinuxSyscalls/x32/Ioctl/v3d_drm.inl" #include "LinuxSyscalls/x32/Ioctl/pvr_drm.inl" #include "LinuxSyscalls/x32/Ioctl/xe_drm.inl" -} +} // namespace FEX::HLE::x32 #undef CPYT #undef CPYF diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/ext_fs.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/ext_fs.h index e095d8fbb..3a04e2cef 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/ext_fs.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/ext_fs.h @@ -14,4 +14,4 @@ namespace FEX::HLE::x32 { namespace ext_fs { #include "LinuxSyscalls/x32/Ioctl/ext_fs.inl" } -} +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/f2fs.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/f2fs.h index f0373c8d3..032400435 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/f2fs.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/f2fs.h @@ -6,16 +6,16 @@ namespace FEX::HLE::x32 { namespace f2fs { -// There is no userspace definitions for these -// Must define everything ourselves -constexpr uint32_t F2FS_IOCTL_MAGIC = 0xf5; + // There is no userspace definitions for these + // Must define everything ourselves + constexpr uint32_t F2FS_IOCTL_MAGIC = 0xf5; #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) -#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) -#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) -#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4) -#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) -#define F2FS_IOC_GARBAGE_COLLECT _IOW(F2FS_IOCTL_MAGIC, 6, uint32_t) -#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7) +#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) +#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) +#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4) +#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) +#define F2FS_IOC_GARBAGE_COLLECT _IOW(F2FS_IOCTL_MAGIC, 6, uint32_t) +#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7) //#define F2FS_IOC_DEFRAGMENT _IOWR(F2FS_IOCTL_MAGIC, 8, \ // struct f2fs_defragment) //#define F2FS_IOC_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \ @@ -24,19 +24,16 @@ constexpr uint32_t F2FS_IOCTL_MAGIC = 0xf5; // struct f2fs_flush_device) //#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ // struct f2fs_gc_range) -#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, uint32_t) -#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, uint32_t) -#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, uint32_t) -#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15) -#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, uint64_t) -#define F2FS_IOC_GET_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 17, uint64_t) -#define F2FS_IOC_RELEASE_COMPRESS_BLOCKS \ - _IOR(F2FS_IOCTL_MAGIC, 18, uint64_t) -#define F2FS_IOC_RESERVE_COMPRESS_BLOCKS \ - _IOR(F2FS_IOCTL_MAGIC, 19, uint64_t) +#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, uint32_t) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, uint32_t) +#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, uint32_t) +#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15) +#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, uint64_t) +#define F2FS_IOC_GET_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 17, uint64_t) +#define F2FS_IOC_RELEASE_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 18, uint64_t) +#define F2FS_IOC_RESERVE_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 19, uint64_t) //#define F2FS_IOC_SEC_TRIM_FILE _IOW(F2FS_IOCTL_MAGIC, 20, \ // struct f2fs_sectrim_range) #include "LinuxSyscalls/x32/Ioctl/f2fs.inl" -} -} - +} // namespace f2fs +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/input.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/input.h index 355195403..a567a6047 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/input.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/input.h @@ -9,5 +9,4 @@ namespace FEX::HLE::x32 { namespace input { #include "LinuxSyscalls/x32/Ioctl/input.inl" } -} - +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/joystick.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/joystick.h index 28198cfc0..d5130ad76 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/joystick.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/joystick.h @@ -12,4 +12,4 @@ namespace FEX::HLE::x32 { namespace joystick { #include "LinuxSyscalls/x32/Ioctl/joystick.inl" } -} +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/msdos_fs.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/msdos_fs.h index d2fc213fb..56311fc89 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/msdos_fs.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/msdos_fs.h @@ -12,4 +12,4 @@ namespace FEX::HLE::x32 { namespace msdos_fs { #include "LinuxSyscalls/x32/Ioctl/msdos_fs.inl" } -} +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/sockios.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/sockios.h index 7fd99e151..d219fe61d 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/sockios.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/sockios.h @@ -8,9 +8,8 @@ namespace FEX::HLE::x32 { namespace sockios { #ifndef SIOCGSKNS -#define SIOCGSKNS 0x894C +#define SIOCGSKNS 0x894C #endif #include "LinuxSyscalls/x32/Ioctl/sockios.inl" -} -} - +} // namespace sockios +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/streams.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/streams.h index 568708719..29fb0b38a 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/streams.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/streams.h @@ -7,9 +7,9 @@ namespace FEX::HLE::x32 { namespace streams { #ifndef TIOCGPTPEER -#define TIOCGPTPEER _IO('T', 0x41) +#define TIOCGPTPEER _IO('T', 0x41) #endif #include "LinuxSyscalls/x32/Ioctl/streams.inl" -} +} // namespace streams -} +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/usbdev.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/usbdev.h index e3bf22f9c..c0ba86322 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/usbdev.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/usbdev.h @@ -8,21 +8,20 @@ namespace FEX::HLE::x32 { namespace usbdev { #ifndef USBDEVFS_GET_SPEED -#define USBDEVFS_GET_SPEED _IO('U', 31) +#define USBDEVFS_GET_SPEED _IO('U', 31) #endif #ifndef USBDEVFS_CONNINFO_EX -#define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) +#define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) #endif #ifndef USBDEVFS_FORBID_SUSPEND -#define USBDEVFS_FORBID_SUSPEND _IO('U', 33) +#define USBDEVFS_FORBID_SUSPEND _IO('U', 33) #endif #ifndef USBDEVFS_ALLOW_SUSPEND -#define USBDEVFS_ALLOW_SUSPEND _IO('U', 34) +#define USBDEVFS_ALLOW_SUSPEND _IO('U', 34) #endif #ifndef USBDEVFS_WAIT_FOR_RESUME -#define USBDEVFS_WAIT_FOR_RESUME _IO('U', 35) +#define USBDEVFS_WAIT_FOR_RESUME _IO('U', 35) #endif #include "LinuxSyscalls/x32/Ioctl/usbdev.inl" -} -} - +} // namespace usbdev +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/wireless.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/wireless.h index ae18d5f80..402e5fcff 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/wireless.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Ioctl/wireless.h @@ -10,4 +10,4 @@ namespace wireless { #include "LinuxSyscalls/x32/Ioctl/wireless.inl" } -} +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.cpp index 389c005f6..10feb3653 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.cpp @@ -26,378 +26,378 @@ #include namespace FEX::HLE::x32 { - static void UnhandledIoctl(const char *Type, int fd, uint32_t cmd, uint32_t args) { - LogMan::Msg::EFmt("@@@@@@@@@@@@@@@@@@@@@@@@@"); - LogMan::Msg::EFmt("Unhandled {} ioctl({}, 0x{:08x}, 0x{:08x})", Type, fd, cmd, args); - LogMan::Msg::EFmt("\tDir : 0x{:x}", _IOC_DIR(cmd)); - LogMan::Msg::EFmt("\tType : 0x{:x}", _IOC_TYPE(cmd)); - LogMan::Msg::EFmt("\tNR : 0x{:x}", _IOC_NR(cmd)); - LogMan::Msg::EFmt("\tSIZE : 0x{:x}", _IOC_SIZE(cmd)); - LogMan::Msg::AFmt("@@@@@@@@@@@@@@@@@@@@@@@@@"); - } +static void UnhandledIoctl(const char* Type, int fd, uint32_t cmd, uint32_t args) { + LogMan::Msg::EFmt("@@@@@@@@@@@@@@@@@@@@@@@@@"); + LogMan::Msg::EFmt("Unhandled {} ioctl({}, 0x{:08x}, 0x{:08x})", Type, fd, cmd, args); + LogMan::Msg::EFmt("\tDir : 0x{:x}", _IOC_DIR(cmd)); + LogMan::Msg::EFmt("\tType : 0x{:x}", _IOC_TYPE(cmd)); + LogMan::Msg::EFmt("\tNR : 0x{:x}", _IOC_NR(cmd)); + LogMan::Msg::EFmt("\tSIZE : 0x{:x}", _IOC_SIZE(cmd)); + LogMan::Msg::AFmt("@@@@@@@@@@@@@@@@@@@@@@@@@"); +} - namespace BasicHandler { - uint64_t BasicHandler(int fd, uint32_t cmd, uint32_t args) { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); +namespace BasicHandler { + uint64_t BasicHandler(int fd, uint32_t cmd, uint32_t args) { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + } +} // namespace BasicHandler + +namespace DRM { + uint32_t AddAndRunHandler(int fd, uint32_t cmd, uint32_t args); + void AssignDeviceTypeToFD(int fd, const drm_version& Version); + + template + class LRUCacheFDCache { + public: + LRUCacheFDCache() { + // Set the last element to our handler + // This element will always be the last one + LRUCache[LRUSize] = std::make_pair(0, AddAndRunHandler); } - } - namespace DRM { - uint32_t AddAndRunHandler(int fd, uint32_t cmd, uint32_t args); - void AssignDeviceTypeToFD(int fd, drm_version const &Version); + using HandlerType = uint32_t (*)(int fd, uint32_t cmd, uint32_t args); + void SetFDHandler(uint32_t FD, HandlerType Handler) { + FDToHandler[FD] = Handler; + } - template - class LRUCacheFDCache { - public: - LRUCacheFDCache() { - // Set the last element to our handler - // This element will always be the last one - LRUCache[LRUSize] = std::make_pair(0, AddAndRunHandler); + void DuplicateFD(int fd, int NewFD) { + auto it = FDToHandler.find(fd); + if (it != FDToHandler.end()) { + FDToHandler[NewFD] = it->second; + } + } + + HandlerType FindHandler(uint32_t FD) { + HandlerType Handler {}; + for (size_t i = 0; i < LRUSize; ++i) { + auto& it = LRUCache[i]; + if (it.first == FD) { + if (i == 0) { + // If we are the first in the queue then just return it + return it.second; + } + Handler = it.second; + break; + } } - using HandlerType = uint32_t(*)(int fd, uint32_t cmd, uint32_t args); - void SetFDHandler(uint32_t FD, HandlerType Handler) { - FDToHandler[FD] = Handler; + if (Handler) { + AddToFront(FD, Handler); + return Handler; } + return LRUCache[LRUSize].second; + } - void DuplicateFD(int fd, int NewFD) { + uint32_t AddAndRunMapHandler(int fd, uint32_t cmd, uint32_t args) { + // Couldn't find in cache, check map + { auto it = FDToHandler.find(fd); if (it != FDToHandler.end()) { - FDToHandler[NewFD] = it->second; + // Found, add to the cache + AddToFront(fd, it->second); + return it->second(fd, cmd, args); } } - HandlerType FindHandler(uint32_t FD) { - HandlerType Handler{}; - for (size_t i = 0; i < LRUSize; ++i) { - auto &it = LRUCache[i]; - if (it.first == FD) { - if (i == 0) { - // If we are the first in the queue then just return it - return it.second; - } - Handler = it.second; - break; - } - } + // Wasn't found in map, query it + drm_version Host_Version {}; + Host_Version.name = reinterpret_cast(alloca(128)); + Host_Version.name_len = 128; + uint64_t Result = ioctl(fd, DRM_IOCTL_VERSION, &Host_Version); - if (Handler) { - AddToFront(FD, Handler); - return Handler; - } - return LRUCache[LRUSize].second; + // Add it to the map and double check that it was added + // Next time around when the ioctl is used then it will be added to cache + if (Result != -1) { + AssignDeviceTypeToFD(fd, Host_Version); } - uint32_t AddAndRunMapHandler(int fd, uint32_t cmd, uint32_t args) { - // Couldn't find in cache, check map - { - auto it = FDToHandler.find(fd); - if (it != FDToHandler.end()) { - // Found, add to the cache - AddToFront(fd, it->second); - return it->second(fd, cmd, args); - } - } + auto it = FDToHandler.find(fd); - // Wasn't found in map, query it - drm_version Host_Version{}; - Host_Version.name = reinterpret_cast(alloca(128)); - Host_Version.name_len = 128; - uint64_t Result = ioctl(fd, DRM_IOCTL_VERSION, &Host_Version); - - // Add it to the map and double check that it was added - // Next time around when the ioctl is used then it will be added to cache - if (Result != -1) { - AssignDeviceTypeToFD(fd, Host_Version); - } - - auto it = FDToHandler.find(fd); - - if (it == FDToHandler.end()) { - // We don't understand this DRM ioctl - return -EPERM; - } - Result = it->second(fd, cmd, args); - SYSCALL_ERRNO(); + if (it == FDToHandler.end()) { + // We don't understand this DRM ioctl + return -EPERM; } - - private: - void AddToFront(uint32_t FD, HandlerType Handler) { - // Push the element to the front if we found one - // First copy all the other elements back one - // Ensuring the final element isn't written over - memmove(&LRUCache[1], &LRUCache[0], (LRUSize - 1) * sizeof(LRUCache[0])); - // Now set the first element to the one we just found - LRUCache[0] = std::make_pair(FD, Handler); - } - // With four elements total (3 + 1) then this is a single cacheline in size - std::pair LRUCache[LRUSize + 1]; - fextl::map FDToHandler; - }; - - static LRUCacheFDCache<3> FDToHandler; - - uint32_t AddAndRunHandler(int fd, uint32_t cmd, uint32_t args) { - return FDToHandler.AddAndRunMapHandler(fd, cmd, args); + Result = it->second(fd, cmd, args); + SYSCALL_ERRNO(); } - void CheckAndAddFDDuplication(int fd, int NewFD) { - FDToHandler.DuplicateFD(fd, NewFD); + private: + void AddToFront(uint32_t FD, HandlerType Handler) { + // Push the element to the front if we found one + // First copy all the other elements back one + // Ensuring the final element isn't written over + memmove(&LRUCache[1], &LRUCache[0], (LRUSize - 1) * sizeof(LRUCache[0])); + // Now set the first element to the one we just found + LRUCache[0] = std::make_pair(FD, Handler); } + // With four elements total (3 + 1) then this is a single cacheline in size + std::pair LRUCache[LRUSize + 1]; + fextl::map FDToHandler; + }; - uint32_t AMDGPU_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { - case _IOC_NR(FEX_DRM_IOCTL_AMDGPU_GEM_METADATA): { - AMDGPU::fex_drm_amdgpu_gem_metadata *val = reinterpret_cast(args); - drm_amdgpu_gem_metadata Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_AMDGPU_GEM_METADATA, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } + static LRUCacheFDCache<3> FDToHandler; + + uint32_t AddAndRunHandler(int fd, uint32_t cmd, uint32_t args) { + return FDToHandler.AddAndRunMapHandler(fd, cmd, args); + } + + void CheckAndAddFDDuplication(int fd, int NewFD) { + FDToHandler.DuplicateFD(fd, NewFD); + } + + uint32_t AMDGPU_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { + case _IOC_NR(FEX_DRM_IOCTL_AMDGPU_GEM_METADATA): { + AMDGPU::fex_drm_amdgpu_gem_metadata* val = reinterpret_cast(args); + drm_amdgpu_gem_metadata Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_AMDGPU_GEM_METADATA, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) - // DRM + // DRM #include "LinuxSyscalls/x32/Ioctl/amdgpu_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("AMDGPU", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("AMDGPU", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t RADEON_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { - case _IOC_NR(FEX_DRM_IOCTL_RADEON_CP_INIT): { - RADEON::fex_drm_radeon_init_t *val = reinterpret_cast(args); - drm_radeon_init_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_CP_INIT, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_CLEAR): { - RADEON::fex_drm_radeon_clear_t *val = reinterpret_cast(args); - drm_radeon_clear_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_CLEAR, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_STIPPLE): { - RADEON::fex_drm_radeon_stipple_t *val = reinterpret_cast(args); - drm_radeon_stipple_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_STIPPLE, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_TEXTURE): { - RADEON::fex_drm_radeon_texture_t *val = reinterpret_cast(args); - drm_radeon_texture_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_TEXTURE, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_VERTEX2): { - RADEON::fex_drm_radeon_vertex2_t *val = reinterpret_cast(args); - drm_radeon_vertex2_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_VERTEX2, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_CMDBUF): { - RADEON::fex_drm_radeon_cmd_buffer_t *val = reinterpret_cast(args); - drm_radeon_cmd_buffer_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_CMDBUF, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_GETPARAM): { - RADEON::fex_drm_radeon_getparam_t *val = reinterpret_cast(args); - drm_radeon_getparam_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_GETPARAM, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_ALLOC): { - RADEON::fex_drm_radeon_mem_alloc_t *val = reinterpret_cast(args); - drm_radeon_mem_alloc_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_ALLOC, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_IRQ_EMIT): { - RADEON::fex_drm_radeon_irq_emit_t *val = reinterpret_cast(args); - drm_radeon_irq_emit_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_IRQ_EMIT, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_SETPARAM): { - RADEON::fex_drm_radeon_setparam_t *val = reinterpret_cast(args); - drm_radeon_setparam_t Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_SETPARAM, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } - case _IOC_NR(FEX_DRM_IOCTL_RADEON_GEM_CREATE): { - RADEON::fex_drm_radeon_gem_create *val = reinterpret_cast(args); - drm_radeon_gem_create Host_val = *val; - uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } + uint32_t RADEON_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { + case _IOC_NR(FEX_DRM_IOCTL_RADEON_CP_INIT): { + RADEON::fex_drm_radeon_init_t* val = reinterpret_cast(args); + drm_radeon_init_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_CP_INIT, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_CLEAR): { + RADEON::fex_drm_radeon_clear_t* val = reinterpret_cast(args); + drm_radeon_clear_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_CLEAR, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_STIPPLE): { + RADEON::fex_drm_radeon_stipple_t* val = reinterpret_cast(args); + drm_radeon_stipple_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_STIPPLE, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_TEXTURE): { + RADEON::fex_drm_radeon_texture_t* val = reinterpret_cast(args); + drm_radeon_texture_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_TEXTURE, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_VERTEX2): { + RADEON::fex_drm_radeon_vertex2_t* val = reinterpret_cast(args); + drm_radeon_vertex2_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_VERTEX2, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_CMDBUF): { + RADEON::fex_drm_radeon_cmd_buffer_t* val = reinterpret_cast(args); + drm_radeon_cmd_buffer_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_CMDBUF, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_GETPARAM): { + RADEON::fex_drm_radeon_getparam_t* val = reinterpret_cast(args); + drm_radeon_getparam_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_GETPARAM, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_ALLOC): { + RADEON::fex_drm_radeon_mem_alloc_t* val = reinterpret_cast(args); + drm_radeon_mem_alloc_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_ALLOC, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_IRQ_EMIT): { + RADEON::fex_drm_radeon_irq_emit_t* val = reinterpret_cast(args); + drm_radeon_irq_emit_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_IRQ_EMIT, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_SETPARAM): { + RADEON::fex_drm_radeon_setparam_t* val = reinterpret_cast(args); + drm_radeon_setparam_t Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_SETPARAM, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } + case _IOC_NR(FEX_DRM_IOCTL_RADEON_GEM_CREATE): { + RADEON::fex_drm_radeon_gem_create* val = reinterpret_cast(args); + drm_radeon_gem_create Host_val = *val; + uint64_t Result = ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) - // DRM + // DRM #include "LinuxSyscalls/x32/Ioctl/radeon_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("RADEON", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("RADEON", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t MSM_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { - case _IOC_NR(FEX_DRM_IOCTL_MSM_WAIT_FENCE): { - MSM::fex_drm_msm_wait_fence *val = reinterpret_cast(args); - drm_msm_wait_fence Host_val = *val; - uint64_t Result = ::ioctl(fd, DRM_IOCTL_MSM_WAIT_FENCE, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } + uint32_t MSM_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { + case _IOC_NR(FEX_DRM_IOCTL_MSM_WAIT_FENCE): { + MSM::fex_drm_msm_wait_fence* val = reinterpret_cast(args); + drm_msm_wait_fence Host_val = *val; + uint64_t Result = ::ioctl(fd, DRM_IOCTL_MSM_WAIT_FENCE, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) - // DRM + // DRM #include "LinuxSyscalls/x32/Ioctl/msm_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("MSM", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("MSM", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t Nouveau_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { + uint32_t Nouveau_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) // DRM #include "LinuxSyscalls/x32/Ioctl/nouveau_drm.inl" - // Let's hope NVIF is arch agnostic. - case DRM_COMMAND_BASE + DRM_NOUVEAU_NVIF: - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("Nouveau", fd, cmd, args); - return -EPERM; - break; - } + // Let's hope NVIF is arch agnostic. + case DRM_COMMAND_BASE + DRM_NOUVEAU_NVIF: { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; + } + default: + UnhandledIoctl("Nouveau", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t I915_Handler(int fd, uint32_t cmd, uint32_t args) { -#define SIMPLE(enum, type) case _IOC_NR(FEX_##enum): { \ - I915::fex_##type *guest = reinterpret_cast(args); \ - type host = *guest; \ - uint64_t Result = ::ioctl(fd, enum, &host); \ - if (Result != -1) { \ - *guest = host; \ - } \ - SYSCALL_ERRNO(); \ - break; \ - } + uint32_t I915_Handler(int fd, uint32_t cmd, uint32_t args) { +#define SIMPLE(enum, type) \ + case _IOC_NR(FEX_##enum): { \ + I915::fex_##type* guest = reinterpret_cast(args); \ + type host = *guest; \ + uint64_t Result = ::ioctl(fd, enum, &host); \ + if (Result != -1) { \ + *guest = host; \ + } \ + SYSCALL_ERRNO(); \ + break; \ + } - switch (_IOC_NR(cmd)) { - SIMPLE(DRM_IOCTL_I915_BATCHBUFFER, drm_i915_batchbuffer_t) - SIMPLE(DRM_IOCTL_I915_IRQ_EMIT, drm_i915_irq_emit_t) - SIMPLE(DRM_IOCTL_I915_GETPARAM, drm_i915_getparam_t) - SIMPLE(DRM_IOCTL_I915_ALLOC, drm_i915_mem_alloc_t) - SIMPLE(DRM_IOCTL_I915_CMDBUFFER, drm_i915_cmdbuffer_t) + switch (_IOC_NR(cmd)) { + SIMPLE(DRM_IOCTL_I915_BATCHBUFFER, drm_i915_batchbuffer_t) + SIMPLE(DRM_IOCTL_I915_IRQ_EMIT, drm_i915_irq_emit_t) + SIMPLE(DRM_IOCTL_I915_GETPARAM, drm_i915_getparam_t) + SIMPLE(DRM_IOCTL_I915_ALLOC, drm_i915_mem_alloc_t) + SIMPLE(DRM_IOCTL_I915_CMDBUFFER, drm_i915_cmdbuffer_t) #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): @@ -405,342 +405,333 @@ namespace FEX::HLE::x32 { #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) // DRM #include "LinuxSyscalls/x32/Ioctl/i915_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("I915", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("I915", fd, cmd, args); + return -EPERM; + break; + } #undef SIMPLE #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t Panfrost_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { + uint32_t Panfrost_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) // DRM #include "LinuxSyscalls/x32/Ioctl/panfrost_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("Panfrost", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("Panfrost", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t Lima_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { + uint32_t Lima_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) // DRM #include "LinuxSyscalls/x32/Ioctl/lima_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("Lima", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("Lima", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t VC4_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { - case _IOC_NR(FEX_DRM_IOCTL_VC4_PERFMON_GET_VALUES): { - FEX::HLE::x32::VC4::fex_drm_vc4_perfmon_get_values *val = reinterpret_cast(args); - drm_vc4_perfmon_get_values Host_val = *val; - uint64_t Result = ::ioctl(fd, DRM_IOCTL_VC4_PERFMON_GET_VALUES, &Host_val); - if (Result != -1) { - *val = Host_val; - } - SYSCALL_ERRNO(); - break; - } + uint32_t VC4_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { + case _IOC_NR(FEX_DRM_IOCTL_VC4_PERFMON_GET_VALUES): { + FEX::HLE::x32::VC4::fex_drm_vc4_perfmon_get_values* val = reinterpret_cast(args); + drm_vc4_perfmon_get_values Host_val = *val; + uint64_t Result = ::ioctl(fd, DRM_IOCTL_VC4_PERFMON_GET_VALUES, &Host_val); + if (Result != -1) { + *val = Host_val; + } + SYSCALL_ERRNO(); + break; + } #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) - // DRM + // DRM #include "LinuxSyscalls/x32/Ioctl/vc4_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("VC4", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("VC4", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t V3D_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { - case _IOC_NR(FEX_DRM_IOCTL_V3D_SUBMIT_CSD): { - FEX::HLE::x32::V3D::fex_drm_v3d_submit_csd *val = reinterpret_cast(args); - drm_v3d_submit_csd Host_val = FEX::HLE::x32::V3D::fex_drm_v3d_submit_csd::SafeConvertToHost(val, _IOC_SIZE(cmd)); - uint64_t Result = ::ioctl(fd, DRM_IOCTL_V3D_SUBMIT_CSD, &Host_val); - if (Result != -1) { - FEX::HLE::x32::V3D::fex_drm_v3d_submit_csd::SafeConvertToGuest(val, Host_val, _IOC_SIZE(cmd)); - } - SYSCALL_ERRNO(); - break; - } + uint32_t V3D_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { + case _IOC_NR(FEX_DRM_IOCTL_V3D_SUBMIT_CSD): { + FEX::HLE::x32::V3D::fex_drm_v3d_submit_csd* val = reinterpret_cast(args); + drm_v3d_submit_csd Host_val = FEX::HLE::x32::V3D::fex_drm_v3d_submit_csd::SafeConvertToHost(val, _IOC_SIZE(cmd)); + uint64_t Result = ::ioctl(fd, DRM_IOCTL_V3D_SUBMIT_CSD, &Host_val); + if (Result != -1) { + FEX::HLE::x32::V3D::fex_drm_v3d_submit_csd::SafeConvertToGuest(val, Host_val, _IOC_SIZE(cmd)); + } + SYSCALL_ERRNO(); + break; + } #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) - // DRM + // DRM #include "LinuxSyscalls/x32/Ioctl/v3d_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("V3D", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("V3D", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t Virtio_Handler(int fd, uint32_t cmd, uint32_t args) { - switch (_IOC_NR(cmd)) { + uint32_t Virtio_Handler(int fd, uint32_t cmd, uint32_t args) { + switch (_IOC_NR(cmd)) { #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) // DRM #include "LinuxSyscalls/x32/Ioctl/virtio_drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - default: - UnhandledIoctl("Virtio", fd, cmd, args); - return -EPERM; - break; + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + break; } + default: + UnhandledIoctl("Virtio", fd, cmd, args); + return -EPERM; + break; + } #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; + } - uint32_t Default_Handler(int fd, uint32_t cmd, uint32_t args) { - // Default handler assumes everything is correct and doesn't need to do any work. - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - } + uint32_t Default_Handler(int fd, uint32_t cmd, uint32_t args) { + // Default handler assumes everything is correct and doesn't need to do any work. + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); + } - void AssignDeviceTypeToFD(int fd, drm_version const &Version) { - if (Version.name) { - if (strncmp(Version.name, "amdgpu", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, AMDGPU_Handler); - } - else if (strncmp(Version.name, "radeon", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, RADEON_Handler); - } - else if (strncmp(Version.name, "msm", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, MSM_Handler); - } - else if (strncmp(Version.name, "nouveau", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, Nouveau_Handler); - } - else if (strncmp(Version.name, "i915", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, I915_Handler); - } - else if (strncmp(Version.name, "panfrost", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, Panfrost_Handler); - } - else if (strncmp(Version.name, "lima", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, Lima_Handler); - } - else if (strncmp(Version.name, "vc4", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, VC4_Handler); - } - else if (strncmp(Version.name, "v3d", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, V3D_Handler); - } - else if (strncmp(Version.name, "virtio_gpu", Version.name_len) == 0) { - FDToHandler.SetFDHandler(fd, Virtio_Handler); - } - else { - LogMan::Msg::IFmt("Unknown DRM device: '{}'. Using default passthrough", Version.name); - FDToHandler.SetFDHandler(fd, Default_Handler); - } + void AssignDeviceTypeToFD(int fd, const drm_version& Version) { + if (Version.name) { + if (strncmp(Version.name, "amdgpu", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, AMDGPU_Handler); + } else if (strncmp(Version.name, "radeon", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, RADEON_Handler); + } else if (strncmp(Version.name, "msm", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, MSM_Handler); + } else if (strncmp(Version.name, "nouveau", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, Nouveau_Handler); + } else if (strncmp(Version.name, "i915", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, I915_Handler); + } else if (strncmp(Version.name, "panfrost", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, Panfrost_Handler); + } else if (strncmp(Version.name, "lima", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, Lima_Handler); + } else if (strncmp(Version.name, "vc4", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, VC4_Handler); + } else if (strncmp(Version.name, "v3d", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, V3D_Handler); + } else if (strncmp(Version.name, "virtio_gpu", Version.name_len) == 0) { + FDToHandler.SetFDHandler(fd, Virtio_Handler); + } else { + LogMan::Msg::IFmt("Unknown DRM device: '{}'. Using default passthrough", Version.name); + FDToHandler.SetFDHandler(fd, Default_Handler); } } + } - uint32_t Handler(int fd, uint32_t cmd, uint32_t args) { -#define SIMPLE(enum, type) case _IOC_NR(FEX_##enum): { \ - DRM::fex_##type *guest = reinterpret_cast(args); \ - type host = *guest; \ - uint64_t Result = ::ioctl(fd, enum, &host); \ - if (Result != -1) { \ - *guest = host; \ - } \ - SYSCALL_ERRNO(); \ - break; \ - } + uint32_t Handler(int fd, uint32_t cmd, uint32_t args) { +#define SIMPLE(enum, type) \ + case _IOC_NR(FEX_##enum): { \ + DRM::fex_##type* guest = reinterpret_cast(args); \ + type host = *guest; \ + uint64_t Result = ::ioctl(fd, enum, &host); \ + if (Result != -1) { \ + *guest = host; \ + } \ + SYSCALL_ERRNO(); \ + break; \ + } - switch (_IOC_NR(cmd)) { - case _IOC_NR(FEX_DRM_IOCTL_VERSION): { - fex_drm_version *version = reinterpret_cast(args); - drm_version Host_Version = *version; - uint64_t Result = ::ioctl(fd, DRM_IOCTL_VERSION, &Host_Version); - if (Result != -1) { - *version = Host_Version; - AssignDeviceTypeToFD(fd, Host_Version); - } - SYSCALL_ERRNO(); - break; - } + switch (_IOC_NR(cmd)) { + case _IOC_NR(FEX_DRM_IOCTL_VERSION): { + fex_drm_version* version = reinterpret_cast(args); + drm_version Host_Version = *version; + uint64_t Result = ::ioctl(fd, DRM_IOCTL_VERSION, &Host_Version); + if (Result != -1) { + *version = Host_Version; + AssignDeviceTypeToFD(fd, Host_Version); + } + SYSCALL_ERRNO(); + break; + } - SIMPLE(DRM_IOCTL_GET_UNIQUE, drm_unique) - SIMPLE(DRM_IOCTL_GET_CLIENT, drm_client) - SIMPLE(DRM_IOCTL_GET_STATS, drm_stats) - SIMPLE(DRM_IOCTL_SET_UNIQUE, drm_unique) + SIMPLE(DRM_IOCTL_GET_UNIQUE, drm_unique) + SIMPLE(DRM_IOCTL_GET_CLIENT, drm_client) + SIMPLE(DRM_IOCTL_GET_STATS, drm_stats) + SIMPLE(DRM_IOCTL_SET_UNIQUE, drm_unique) - SIMPLE(DRM_IOCTL_ADD_MAP, drm_map) - SIMPLE(DRM_IOCTL_ADD_BUFS, drm_buf_desc) - SIMPLE(DRM_IOCTL_MARK_BUFS, drm_buf_desc) - SIMPLE(DRM_IOCTL_INFO_BUFS, drm_buf_info) - SIMPLE(DRM_IOCTL_MAP_BUFS, drm_buf_map) - SIMPLE(DRM_IOCTL_FREE_BUFS, drm_buf_free) - SIMPLE(DRM_IOCTL_RM_MAP, drm_map) - SIMPLE(DRM_IOCTL_SET_SAREA_CTX, drm_ctx_priv_map) - SIMPLE(DRM_IOCTL_GET_SAREA_CTX, drm_ctx_priv_map) + SIMPLE(DRM_IOCTL_ADD_MAP, drm_map) + SIMPLE(DRM_IOCTL_ADD_BUFS, drm_buf_desc) + SIMPLE(DRM_IOCTL_MARK_BUFS, drm_buf_desc) + SIMPLE(DRM_IOCTL_INFO_BUFS, drm_buf_info) + SIMPLE(DRM_IOCTL_MAP_BUFS, drm_buf_map) + SIMPLE(DRM_IOCTL_FREE_BUFS, drm_buf_free) + SIMPLE(DRM_IOCTL_RM_MAP, drm_map) + SIMPLE(DRM_IOCTL_SET_SAREA_CTX, drm_ctx_priv_map) + SIMPLE(DRM_IOCTL_GET_SAREA_CTX, drm_ctx_priv_map) - SIMPLE(DRM_IOCTL_RES_CTX, drm_ctx_res) - SIMPLE(DRM_IOCTL_DMA, drm_dma) - SIMPLE(DRM_IOCTL_SG_ALLOC, drm_scatter_gather) - SIMPLE(DRM_IOCTL_SG_FREE, drm_scatter_gather) - SIMPLE(DRM_IOCTL_UPDATE_DRAW, drm_update_draw) - SIMPLE(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_get_plane_res) - SIMPLE(DRM_IOCTL_MODE_ADDFB2, drm_mode_fb_cmd2) - SIMPLE(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties) - SIMPLE(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property) - SIMPLE(DRM_IOCTL_MODE_GETFB2, drm_mode_fb_cmd2) + SIMPLE(DRM_IOCTL_RES_CTX, drm_ctx_res) + SIMPLE(DRM_IOCTL_DMA, drm_dma) + SIMPLE(DRM_IOCTL_SG_ALLOC, drm_scatter_gather) + SIMPLE(DRM_IOCTL_SG_FREE, drm_scatter_gather) + SIMPLE(DRM_IOCTL_UPDATE_DRAW, drm_update_draw) + SIMPLE(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_get_plane_res) + SIMPLE(DRM_IOCTL_MODE_ADDFB2, drm_mode_fb_cmd2) + SIMPLE(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties) + SIMPLE(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property) + SIMPLE(DRM_IOCTL_MODE_GETFB2, drm_mode_fb_cmd2) - case _IOC_NR(FEX_DRM_IOCTL_WAIT_VBLANK): { - fex_drm_wait_vblank *guest = reinterpret_cast(args); - drm_wait_vblank Host{}; - Host.request = guest->request; - uint64_t Result = ::ioctl(fd, FEX_DRM_IOCTL_WAIT_VBLANK, &Host); - if (Result != -1) { - guest->reply = Host.reply; - } - SYSCALL_ERRNO(); - break; - } - // Passthrough + case _IOC_NR(FEX_DRM_IOCTL_WAIT_VBLANK): { + fex_drm_wait_vblank* guest = reinterpret_cast(args); + drm_wait_vblank Host {}; + Host.request = guest->request; + uint64_t Result = ::ioctl(fd, FEX_DRM_IOCTL_WAIT_VBLANK, &Host); + if (Result != -1) { + guest->reply = Host.reply; + } + SYSCALL_ERRNO(); + break; + } + // Passthrough #define _BASIC_META(x) case _IOC_NR(x): #define _BASIC_META_VAR(x, args...) case _IOC_NR(x): #define _CUSTOM_META(name, ioctl_num) #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) - // DRM + // DRM #include "LinuxSyscalls/x32/Ioctl/drm.inl" - { - uint64_t Result = ::ioctl(fd, cmd, args); - SYSCALL_ERRNO(); - break; - } - - case DRM_COMMAND_BASE ... (DRM_COMMAND_END - 1): { - // This is the space of the DRM device commands - auto it = FDToHandler.FindHandler(fd); - return it(fd, cmd, args); + { + uint64_t Result = ::ioctl(fd, cmd, args); + SYSCALL_ERRNO(); break; - } - default: - UnhandledIoctl("DRM", fd, cmd, args); - return -EPERM; - break; } + + case DRM_COMMAND_BASE ...(DRM_COMMAND_END - 1): { + // This is the space of the DRM device commands + auto it = FDToHandler.FindHandler(fd); + return it(fd, cmd, args); + break; + } + default: + UnhandledIoctl("DRM", fd, cmd, args); + return -EPERM; + break; + } #undef SIMPLE #undef _BASIC_META #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - return -EPERM; - } + return -EPERM; } +} // namespace DRM - struct IoctlHandler { - uint32_t Command; - std::function Handler; - }; +struct IoctlHandler { + uint32_t Command; + std::function Handler; +}; - static fextl::vector> Handlers; +static fextl::vector> Handlers; - void InitializeStaticIoctlHandlers() { - using namespace DRM; - using namespace sockios; +void InitializeStaticIoctlHandlers() { + using namespace DRM; + using namespace sockios; - const fextl::vector LocalHandlers = {{ -#define _BASIC_META(x) IoctlHandler{_IOC_TYPE(x), FEX::HLE::x32::BasicHandler::BasicHandler}, -#define _BASIC_META_VAR(x, args...) IoctlHandler{_IOC_TYPE(x(args)), FEX::HLE::x32::BasicHandler::BasicHandler}, -#define _CUSTOM_META(name, ioctl_num) IoctlHandler{_IOC_TYPE(FEX_##name), FEX::HLE::x32::BasicHandler::BasicHandler}, -#define _CUSTOM_META_OFFSET(name, ioctl_num, offset) IoctlHandler{_IOC_TYPE(FEX_##name), FEX::HLE::x32::BasicHandler::BasicHandler}, + const fextl::vector LocalHandlers = {{ +#define _BASIC_META(x) IoctlHandler {_IOC_TYPE(x), FEX::HLE::x32::BasicHandler::BasicHandler}, +#define _BASIC_META_VAR(x, args...) IoctlHandler {_IOC_TYPE(x(args)), FEX::HLE::x32::BasicHandler::BasicHandler}, +#define _CUSTOM_META(name, ioctl_num) IoctlHandler {_IOC_TYPE(FEX_##name), FEX::HLE::x32::BasicHandler::BasicHandler}, +#define _CUSTOM_META_OFFSET(name, ioctl_num, offset) IoctlHandler {_IOC_TYPE(FEX_##name), FEX::HLE::x32::BasicHandler::BasicHandler}, - // Asound + // Asound #include "LinuxSyscalls/x32/Ioctl/asound.inl" - // Streams + // Streams #include "LinuxSyscalls/x32/Ioctl/streams.inl" - // USB Dev + // USB Dev #include "LinuxSyscalls/x32/Ioctl/usbdev.inl" - // Input + // Input #include "LinuxSyscalls/x32/Ioctl/input.inl" - // SOCKIOS + // SOCKIOS #include "LinuxSyscalls/x32/Ioctl/sockios.inl" - // Joystick + // Joystick #include "LinuxSyscalls/x32/Ioctl/joystick.inl" - // Wireless + // Wireless #include "LinuxSyscalls/x32/Ioctl/wireless.inl" #undef _BASIC_META @@ -748,11 +739,11 @@ namespace FEX::HLE::x32 { #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET -#define _BASIC_META(x) IoctlHandler{_IOC_TYPE(x), FEX::HLE::x32::DRM::Handler}, -#define _BASIC_META_VAR(x, args...) IoctlHandler{_IOC_TYPE(x(args)), FEX::HLE::x32::DRM::Handler}, -#define _CUSTOM_META(name, ioctl_num) IoctlHandler{_IOC_TYPE(FEX_##name), FEX::HLE::x32::DRM::Handler}, -#define _CUSTOM_META_OFFSET(name, ioctl_num, offset) IoctlHandler{_IOC_TYPE(FEX_##name), FEX::HLE::x32::DRM::Handler}, - // DRM +#define _BASIC_META(x) IoctlHandler {_IOC_TYPE(x), FEX::HLE::x32::DRM::Handler}, +#define _BASIC_META_VAR(x, args...) IoctlHandler {_IOC_TYPE(x(args)), FEX::HLE::x32::DRM::Handler}, +#define _CUSTOM_META(name, ioctl_num) IoctlHandler {_IOC_TYPE(FEX_##name), FEX::HLE::x32::DRM::Handler}, +#define _CUSTOM_META_OFFSET(name, ioctl_num, offset) IoctlHandler {_IOC_TYPE(FEX_##name), FEX::HLE::x32::DRM::Handler}, + // DRM #include "LinuxSyscalls/x32/Ioctl/drm.inl" #include "LinuxSyscalls/x32/Ioctl/amdgpu_drm.inl" @@ -772,21 +763,20 @@ namespace FEX::HLE::x32 { #undef _BASIC_META_VAR #undef _CUSTOM_META #undef _CUSTOM_META_OFFSET - }}; + }}; - Handlers.assign(1U << _IOC_TYPEBITS, FEX::HLE::x32::BasicHandler::BasicHandler); + Handlers.assign(1U << _IOC_TYPEBITS, FEX::HLE::x32::BasicHandler::BasicHandler); - for (auto &Arg : LocalHandlers) { - Handlers[Arg.Command] = Arg.Handler; - } - } - - uint32_t ioctl32(FEXCore::Core::CpuStateFrame *Frame, int fd, uint32_t request, uint32_t args) { - return Handlers[_IOC_TYPE(request)](fd, request, args); - } - - void CheckAndAddFDDuplication(int fd, int NewFD) { - DRM::CheckAndAddFDDuplication(fd, NewFD); + for (auto& Arg : LocalHandlers) { + Handlers[Arg.Command] = Arg.Handler; } } +uint32_t ioctl32(FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t request, uint32_t args) { + return Handlers[_IOC_TYPE(request)](fd, request, args); +} + +void CheckAndAddFDDuplication(int fd, int NewFD) { + DRM::CheckAndAddFDDuplication(fd, NewFD); +} +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.h index 6349e5bc5..ef5a80f6b 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IoctlEmulation.h @@ -3,12 +3,11 @@ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { - void InitializeStaticIoctlHandlers(); - uint32_t ioctl32(FEXCore::Core::CpuStateFrame *Frame, int fd, uint32_t request, uint32_t args); - void CheckAndAddFDDuplication(int fd, int NewFD); -} - +void InitializeStaticIoctlHandlers(); +uint32_t ioctl32(FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t request, uint32_t args); +void CheckAndAddFDDuplication(int fd, int NewFD); +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp index 842371662..6cf1c27bb 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp @@ -21,79 +21,81 @@ $end_info$ namespace FEX::HLE::x32 { - void *x32SyscallHandler::GuestMmap(FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - LOGMAN_THROW_AA_FMT((length >> 32) == 0, "values must fit to 32 bits"); +void* x32SyscallHandler::GuestMmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + LOGMAN_THROW_AA_FMT((length >> 32) == 0, "values must fit to 32 bits"); - auto Result = (uint64_t)GetAllocator()->Mmap((void*)addr, length, prot, flags, fd, offset); + auto Result = (uint64_t)GetAllocator()->Mmap((void*)addr, length, prot, flags, fd, offset); - LOGMAN_THROW_AA_FMT((Result >> 32) == 0|| (Result >> 32) == 0xFFFFFFFF, "values must fit to 32 bits"); + LOGMAN_THROW_AA_FMT((Result >> 32) == 0 || (Result >> 32) == 0xFFFFFFFF, "values must fit to 32 bits"); - if (!FEX::HLE::HasSyscallError(Result)) { - FEX::HLE::_SyscallHandler->TrackMmap(Thread, Result, length, prot, flags, fd, offset); - return (void *)Result; - } else { - errno = -Result; - return MAP_FAILED; - } + if (!FEX::HLE::HasSyscallError(Result)) { + FEX::HLE::_SyscallHandler->TrackMmap(Thread, Result, length, prot, flags, fd, offset); + return (void*)Result; + } else { + errno = -Result; + return MAP_FAILED; } +} - int x32SyscallHandler::GuestMunmap(FEXCore::Core::InternalThreadState *Thread, void *addr, uint64_t length) { - LOGMAN_THROW_AA_FMT((uintptr_t(addr) >> 32) == 0, "values must fit to 32 bits"); - LOGMAN_THROW_AA_FMT((length >> 32) == 0, "values must fit to 32 bits"); +int x32SyscallHandler::GuestMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, uint64_t length) { + LOGMAN_THROW_AA_FMT((uintptr_t(addr) >> 32) == 0, "values must fit to 32 bits"); + LOGMAN_THROW_AA_FMT((length >> 32) == 0, "values must fit to 32 bits"); - auto Result = GetAllocator()->Munmap(addr, length); + auto Result = GetAllocator()->Munmap(addr, length); - if (Result == 0) { - FEX::HLE::_SyscallHandler->TrackMunmap(Thread, (uintptr_t)addr, length); - return Result; - } else { - errno = -Result; - return -1; - } + if (Result == 0) { + FEX::HLE::_SyscallHandler->TrackMunmap(Thread, (uintptr_t)addr, length); + return Result; + } else { + errno = -Result; + return -1; } +} - void RegisterMemory(FEX::HLE::SyscallHandler *Handler) { - struct old_mmap_struct { - uint32_t addr; - uint32_t len; - uint32_t prot; - uint32_t flags; - uint32_t fd; - uint32_t offset; - }; - REGISTER_SYSCALL_IMPL_X32(mmap, [](FEXCore::Core::CpuStateFrame *Frame, old_mmap_struct const* arg) -> uint64_t { - uint64_t Result = (uint64_t)static_cast(FEX::HLE::_SyscallHandler)-> - GuestMmap(Frame->Thread, reinterpret_cast(arg->addr), arg->len, arg->prot, arg->flags, arg->fd, arg->offset); +void RegisterMemory(FEX::HLE::SyscallHandler* Handler) { + struct old_mmap_struct { + uint32_t addr; + uint32_t len; + uint32_t prot; + uint32_t flags; + uint32_t fd; + uint32_t offset; + }; + REGISTER_SYSCALL_IMPL_X32(mmap, [](FEXCore::Core::CpuStateFrame* Frame, const old_mmap_struct* arg) -> uint64_t { + uint64_t Result = (uint64_t) static_cast(FEX::HLE::_SyscallHandler) + ->GuestMmap(Frame->Thread, reinterpret_cast(arg->addr), arg->len, arg->prot, arg->flags, arg->fd, arg->offset); - SYSCALL_ERRNO(); - }); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(mmap2, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t addr, uint32_t length, int prot, int flags, int fd, uint32_t pgoffset) -> uint64_t { - uint64_t Result = (uint64_t)static_cast(FEX::HLE::_SyscallHandler)-> - GuestMmap(Frame->Thread, reinterpret_cast(addr), length, prot,flags, fd, (uint64_t)pgoffset * 0x1000); - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(munmap, [](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length) -> uint64_t { - uint64_t Result = (uint64_t)static_cast(FEX::HLE::_SyscallHandler)-> - GuestMunmap(Frame->Thread, addr, length); - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(mprotect, [](FEXCore::Core::CpuStateFrame *Frame, void *addr, uint32_t len, int prot) -> uint64_t { - uint64_t Result = ::mprotect(addr, len, prot); - if (Result != -1) { - FEX::HLE::_SyscallHandler->TrackMprotect(Frame->Thread, (uintptr_t)addr, len, prot); - } + REGISTER_SYSCALL_IMPL_X32( + mmap2, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t addr, uint32_t length, int prot, int flags, int fd, uint32_t pgoffset) -> uint64_t { + uint64_t Result = (uint64_t) static_cast(FEX::HLE::_SyscallHandler) + ->GuestMmap(Frame->Thread, reinterpret_cast(addr), length, prot, flags, fd, (uint64_t)pgoffset * 0x1000); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(mremap, [](FEXCore::Core::CpuStateFrame *Frame, void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) -> uint64_t { - uint64_t Result = reinterpret_cast(static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()-> - Mremap(old_address, old_size, new_size, flags, new_address)); + REGISTER_SYSCALL_IMPL_X32(munmap, [](FEXCore::Core::CpuStateFrame* Frame, void* addr, size_t length) -> uint64_t { + uint64_t Result = + (uint64_t) static_cast(FEX::HLE::_SyscallHandler)->GuestMunmap(Frame->Thread, addr, length); + + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32(mprotect, [](FEXCore::Core::CpuStateFrame* Frame, void* addr, uint32_t len, int prot) -> uint64_t { + uint64_t Result = ::mprotect(addr, len, prot); + if (Result != -1) { + FEX::HLE::_SyscallHandler->TrackMprotect(Frame->Thread, (uintptr_t)addr, len, prot); + } + + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32( + mremap, [](FEXCore::Core::CpuStateFrame* Frame, void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) -> uint64_t { + uint64_t Result = reinterpret_cast( + static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()->Mremap(old_address, old_size, new_size, flags, new_address)); if (!FEX::HLE::HasSyscallError(Result)) { FEX::HLE::_SyscallHandler->TrackMremap(Frame->Thread, (uintptr_t)old_address, old_size, new_size, flags, Result); @@ -102,42 +104,41 @@ namespace FEX::HLE::x32 { return Result; }); - REGISTER_SYSCALL_IMPL_X32(mlockall, [](FEXCore::Core::CpuStateFrame *Frame, int flags) -> uint64_t { - uint64_t Result = ::syscall(SYSCALL_DEF(mlock2), reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000, flags); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(mlockall, [](FEXCore::Core::CpuStateFrame* Frame, int flags) -> uint64_t { + uint64_t Result = ::syscall(SYSCALL_DEF(mlock2), reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000, flags); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(munlockall, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - uint64_t Result = ::munlock(reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(munlockall, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + uint64_t Result = ::munlock(reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(shmat, [](FEXCore::Core::CpuStateFrame *Frame, int shmid, const void *shmaddr, int shmflg) -> uint64_t { - // also implemented in ipc:OP_SHMAT - uint32_t ResultAddr{}; - uint64_t Result = static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()-> - Shmat(shmid, reinterpret_cast(shmaddr), shmflg, &ResultAddr); - - if (!FEX::HLE::HasSyscallError(Result)) { - FEX::HLE::_SyscallHandler->TrackShmat(Frame->Thread, shmid, ResultAddr, shmflg); - return ResultAddr; - } - else { - return Result; - } - }); - - REGISTER_SYSCALL_IMPL_X32(shmdt, [](FEXCore::Core::CpuStateFrame *Frame, const void *shmaddr) -> uint64_t { - // also implemented in ipc:OP_SHMDT - uint64_t Result = static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()-> - Shmdt(shmaddr); - - if (!FEX::HLE::HasSyscallError(Result)) { - FEX::HLE::_SyscallHandler->TrackShmdt(Frame->Thread, (uintptr_t)shmaddr); - } + REGISTER_SYSCALL_IMPL_X32(shmat, [](FEXCore::Core::CpuStateFrame* Frame, int shmid, const void* shmaddr, int shmflg) -> uint64_t { + // also implemented in ipc:OP_SHMAT + uint32_t ResultAddr {}; + uint64_t Result = static_cast(FEX::HLE::_SyscallHandler) + ->GetAllocator() + ->Shmat(shmid, reinterpret_cast(shmaddr), shmflg, &ResultAddr); + if (!FEX::HLE::HasSyscallError(Result)) { + FEX::HLE::_SyscallHandler->TrackShmat(Frame->Thread, shmid, ResultAddr, shmflg); + return ResultAddr; + } else { return Result; - }); - } + } + }); + REGISTER_SYSCALL_IMPL_X32(shmdt, [](FEXCore::Core::CpuStateFrame* Frame, const void* shmaddr) -> uint64_t { + // also implemented in ipc:OP_SHMDT + uint64_t Result = static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()->Shmdt(shmaddr); + + if (!FEX::HLE::HasSyscallError(Result)) { + FEX::HLE::_SyscallHandler->TrackShmdt(Frame->Thread, (uintptr_t)shmaddr); + } + + return Result; + }); } + +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Msg.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Msg.cpp index 13c4d994b..86bf6cdb0 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Msg.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Msg.cpp @@ -20,34 +20,39 @@ ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") namespace FEX::HLE::x32 { - void RegisterMsg(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(mq_timedsend, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec32 *abs_timeout) -> uint64_t { - struct timespec tp64{}; - struct timespec *timed_ptr{}; - if (abs_timeout) { - tp64 = *abs_timeout; - timed_ptr = &tp64; - } +void RegisterMsg(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(mq_timedsend, + [](FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::mqd_t mqdes, const char* msg_ptr, size_t msg_len, + unsigned int msg_prio, const struct timespec32* abs_timeout) -> uint64_t { + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (abs_timeout) { + tp64 = *abs_timeout; + timed_ptr = &tp64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedsend), mqdes, msg_ptr, msg_len, msg_prio, timed_ptr); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedsend), mqdes, msg_ptr, msg_len, msg_prio, timed_ptr); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(mq_timedreceive, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec32 *abs_timeout) -> uint64_t { - struct timespec tp64{}; - struct timespec *timed_ptr{}; - if (abs_timeout) { - tp64 = *abs_timeout; - timed_ptr = &tp64; - } + REGISTER_SYSCALL_IMPL_X32(mq_timedreceive, + [](FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::mqd_t mqdes, char* msg_ptr, size_t msg_len, + unsigned int* msg_prio, const struct timespec32* abs_timeout) -> uint64_t { + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (abs_timeout) { + tp64 = *abs_timeout; + timed_ptr = &tp64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedreceive), mqdes, msg_ptr, msg_len, msg_prio, timed_ptr); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedreceive), mqdes, msg_ptr, msg_len, msg_prio, timed_ptr); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(mq_open, [](FEXCore::Core::CpuStateFrame *Frame, const char *name, int oflag, mode_t mode, compat_ptr attr) -> uint64_t { - mq_attr HostAttr{}; - mq_attr *HostAttr_p{}; + REGISTER_SYSCALL_IMPL_X32( + mq_open, [](FEXCore::Core::CpuStateFrame* Frame, const char* name, int oflag, mode_t mode, compat_ptr attr) -> uint64_t { + mq_attr HostAttr {}; + mq_attr* HostAttr_p {}; if ((oflag & O_CREAT) && attr) { // attr is optional unless O_CREAT is set // Then attr can be valid or nullptr @@ -58,35 +63,38 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(mq_notify, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, const compat_ptr sevp) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + mq_notify, [](FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::mqd_t mqdes, const compat_ptr sevp) -> uint64_t { sigevent Host = *sevp; uint64_t Result = ::syscall(SYSCALL_DEF(mq_notify), mqdes, &Host); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(mq_getsetattr, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, compat_ptr newattr, compat_ptr oldattr) -> uint64_t { - mq_attr HostNew{}; - mq_attr *HostNew_p{}; + REGISTER_SYSCALL_IMPL_X32(mq_getsetattr, + [](FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::mqd_t mqdes, compat_ptr newattr, + compat_ptr oldattr) -> uint64_t { + mq_attr HostNew {}; + mq_attr* HostNew_p {}; - mq_attr HostOld{}; - mq_attr *HostOld_p{}; + mq_attr HostOld {}; + mq_attr* HostOld_p {}; - if (newattr) { - HostNew = *newattr; - HostNew_p = &HostNew; - } + if (newattr) { + HostNew = *newattr; + HostNew_p = &HostNew; + } - if (oldattr) { - HostOld_p = &HostOld; - } + if (oldattr) { + HostOld_p = &HostOld; + } - uint64_t Result = ::syscall(SYSCALL_DEF(mq_getsetattr), mqdes, HostNew_p, HostOld_p); + uint64_t Result = ::syscall(SYSCALL_DEF(mq_getsetattr), mqdes, HostNew_p, HostOld_p); - if (Result != 1 && oldattr) { - *oldattr = HostOld; - } + if (Result != 1 && oldattr) { + *oldattr = HostOld; + } - SYSCALL_ERRNO(); - }); - } + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp index e7f35d72e..71c810c47 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp @@ -12,32 +12,32 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { -#define REGISTER_SYSCALL_NOT_IMPL_X32(name) REGISTER_SYSCALL_IMPL_X32(name, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { \ - LogMan::Msg::DFmt("Using deprecated/removed syscall: " #name); \ - return -ENOSYS; \ -}); -#define REGISTER_SYSCALL_NO_PERM_X32(name) REGISTER_SYSCALL_IMPL_X32(name, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { \ - return -EPERM; \ -}); +#define REGISTER_SYSCALL_NOT_IMPL_X32(name) \ + REGISTER_SYSCALL_IMPL_X32(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { \ + LogMan::Msg::DFmt("Using deprecated/removed syscall: " #name); \ + return -ENOSYS; \ + }); +#define REGISTER_SYSCALL_NO_PERM_X32(name) \ + REGISTER_SYSCALL_IMPL_X32(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -EPERM; }); - // these are removed/not implemented in the linux kernel we present - void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_NOT_IMPL_X32(break); - REGISTER_SYSCALL_NOT_IMPL_X32(stty); - REGISTER_SYSCALL_NOT_IMPL_X32(gtty); - REGISTER_SYSCALL_NOT_IMPL_X32(prof); - REGISTER_SYSCALL_NOT_IMPL_X32(ftime); - REGISTER_SYSCALL_NOT_IMPL_X32(mpx); - REGISTER_SYSCALL_NOT_IMPL_X32(lock); - REGISTER_SYSCALL_NOT_IMPL_X32(ulimit); - REGISTER_SYSCALL_NOT_IMPL_X32(profil); - REGISTER_SYSCALL_NOT_IMPL_X32(idle); +// these are removed/not implemented in the linux kernel we present +void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_NOT_IMPL_X32(break); + REGISTER_SYSCALL_NOT_IMPL_X32(stty); + REGISTER_SYSCALL_NOT_IMPL_X32(gtty); + REGISTER_SYSCALL_NOT_IMPL_X32(prof); + REGISTER_SYSCALL_NOT_IMPL_X32(ftime); + REGISTER_SYSCALL_NOT_IMPL_X32(mpx); + REGISTER_SYSCALL_NOT_IMPL_X32(lock); + REGISTER_SYSCALL_NOT_IMPL_X32(ulimit); + REGISTER_SYSCALL_NOT_IMPL_X32(profil); + REGISTER_SYSCALL_NOT_IMPL_X32(idle); - REGISTER_SYSCALL_NO_PERM_X32(stime); - REGISTER_SYSCALL_NO_PERM_X32(bdflush); - } + REGISTER_SYSCALL_NO_PERM_X32(stime); + REGISTER_SYSCALL_NO_PERM_X32(bdflush); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp index 9a990b5d3..d5fe13724 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp @@ -16,18 +16,18 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { - void RegisterSched(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(sched_rr_get_interval, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, struct timespec32 *tp) -> uint64_t { - struct timespec tp64{}; - uint64_t Result = ::sched_rr_get_interval(pid, tp ? &tp64 : nullptr); - if (tp) { - *tp = tp64; - } - SYSCALL_ERRNO(); - }); - } +void RegisterSched(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(sched_rr_get_interval, [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, struct timespec32* tp) -> uint64_t { + struct timespec tp64 {}; + uint64_t Result = ::sched_rr_get_interval(pid, tp ? &tp64 : nullptr); + if (tp) { + *tp = tp64; + } + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp index 31b0cabc3..ae0c5236a 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp @@ -26,437 +26,404 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { - // Define the IPC ops - enum IPCOp { - OP_SEMOP = 1, - OP_SEMGET = 2, - OP_SEMCTL = 3, - OP_SEMTIMEDOP = 4, - OP_MSGSND = 11, - OP_MSGRCV = 12, - OP_MSGGET = 13, - OP_MSGCTL = 14, - OP_SHMAT = 21, - OP_SHMDT = 22, - OP_SHMGET = 23, - OP_SHMCTL = 24, - }; +// Define the IPC ops +enum IPCOp { + OP_SEMOP = 1, + OP_SEMGET = 2, + OP_SEMCTL = 3, + OP_SEMTIMEDOP = 4, + OP_MSGSND = 11, + OP_MSGRCV = 12, + OP_MSGGET = 13, + OP_MSGCTL = 14, + OP_SHMAT = 21, + OP_SHMDT = 22, + OP_SHMGET = 23, + OP_SHMCTL = 24, +}; - struct msgbuf_32 { - compat_long_t mtype; - char mtext[1]; - }; +struct msgbuf_32 { + compat_long_t mtype; + char mtext[1]; +}; - union semun_32 { - int32_t val; // Value for SETVAL - compat_ptr buf32; // struct semid_ds* - Buffer ptr for IPC_STAT, IPC_SET - compat_ptr buf64; // struct semid_ds* - Buffer ptr for IPC_STAT, IPC_SET - uint32_t array; // uint16_t array for GETALL, SETALL - compat_ptr __buf; // struct seminfo * - Buffer for IPC_INFO - }; +union semun_32 { + int32_t val; // Value for SETVAL + compat_ptr buf32; // struct semid_ds* - Buffer ptr for IPC_STAT, IPC_SET + compat_ptr buf64; // struct semid_ds* - Buffer ptr for IPC_STAT, IPC_SET + uint32_t array; // uint16_t array for GETALL, SETALL + compat_ptr __buf; // struct seminfo * - Buffer for IPC_INFO +}; - union msgun_32 { - int32_t val; // Value for SETVAL - compat_ptr buf32; // struct msgid_ds* - Buffer ptr for IPC_STAT, IPC_SET - compat_ptr buf64; // struct msgid_ds* - Buffer ptr for IPC_STAT, IPC_SET - uint32_t array; // uint16_t array for GETALL, SETALL - compat_ptr __buf; // struct msginfo * - Buffer for IPC_INFO - }; +union msgun_32 { + int32_t val; // Value for SETVAL + compat_ptr buf32; // struct msgid_ds* - Buffer ptr for IPC_STAT, IPC_SET + compat_ptr buf64; // struct msgid_ds* - Buffer ptr for IPC_STAT, IPC_SET + uint32_t array; // uint16_t array for GETALL, SETALL + compat_ptr __buf; // struct msginfo * - Buffer for IPC_INFO +}; - union shmun_32 { - int32_t val; // Value for SETVAL - compat_ptr buf32; // struct shmid_ds* - Buffer ptr for IPC_STAT, IPC_SET - compat_ptr buf64; // struct shmid_ds* - Buffer ptr for IPC_STAT, IPC_SET - uint32_t array; // uint16_t array for GETALL, SETALL - compat_ptr __buf32; // struct shminfo * - Buffer for IPC_INFO - compat_ptr __buf64; // struct shminfo * - Buffer for IPC_INFO +union shmun_32 { + int32_t val; // Value for SETVAL + compat_ptr buf32; // struct shmid_ds* - Buffer ptr for IPC_STAT, IPC_SET + compat_ptr buf64; // struct shmid_ds* - Buffer ptr for IPC_STAT, IPC_SET + uint32_t array; // uint16_t array for GETALL, SETALL + compat_ptr __buf32; // struct shminfo * - Buffer for IPC_INFO + compat_ptr __buf64; // struct shminfo * - Buffer for IPC_INFO - compat_ptr __buf_info_32; // struct shm_info * - Buffer for SHM_INFO - }; + compat_ptr __buf_info_32; // struct shm_info * - Buffer for SHM_INFO +}; - union semun { - int val; /* value for SETVAL */ - struct semid_ds_32 *buf; /* buffer for IPC_STAT & IPC_SET */ - unsigned short *array; /* array for GETALL & SETALL */ - struct fex_seminfo *__buf; /* buffer for IPC_INFO */ - void *__pad; - }; +union semun { + int val; /* value for SETVAL */ + struct semid_ds_32* buf; /* buffer for IPC_STAT & IPC_SET */ + unsigned short* array; /* array for GETALL & SETALL */ + struct fex_seminfo* __buf; /* buffer for IPC_INFO */ + void* __pad; +}; - uint64_t _ipc(FEXCore::Core::CpuStateFrame *Frame, uint32_t call, uint32_t first, uint32_t second, uint32_t third, uint32_t ptr, uint32_t fifth) { - uint64_t Result{}; +uint64_t _ipc(FEXCore::Core::CpuStateFrame* Frame, uint32_t call, uint32_t first, uint32_t second, uint32_t third, uint32_t ptr, uint32_t fifth) { + uint64_t Result {}; - switch (static_cast(call)) { - case OP_SEMOP: { - Result = ::syscall(SYSCALL_DEF(semop), first, reinterpret_cast(ptr), second); - break; + switch (static_cast(call)) { + case OP_SEMOP: { + Result = ::syscall(SYSCALL_DEF(semop), first, reinterpret_cast(ptr), second); + break; + } + case OP_SEMGET: { + Result = ::syscall(SYSCALL_DEF(semget), first, second, third); + break; + } + case OP_SEMCTL: { + uint32_t semid = first; + uint32_t semnum = second; + // Upper 16bits used for a different flag? + int32_t cmd = third & 0xFF; + compat_ptr semun(ptr); + bool IPC64 = third & 0x100; + switch (cmd) { + case IPC_SET: { + struct semid64_ds buf {}; + if (IPC64) { + buf = *semun->buf64; + } else { + buf = *semun->buf32; } - case OP_SEMGET: { - Result = ::syscall(SYSCALL_DEF(semget), first, second, third); - break; - } - case OP_SEMCTL: { - uint32_t semid = first; - uint32_t semnum = second; - // Upper 16bits used for a different flag? - int32_t cmd = third & 0xFF; - compat_ptr semun(ptr); - bool IPC64 = third & 0x100; - switch (cmd) { - case IPC_SET: { - struct semid64_ds buf{}; - if (IPC64) { - buf = *semun->buf64; - } - else { - buf = *semun->buf32; - } - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - if (IPC64) { - *semun->buf64 = buf; - } - else { - *semun->buf32 = buf; - } - } - break; - } - case SEM_STAT: - case SEM_STAT_ANY: - case IPC_STAT: { - struct semid64_ds buf{}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - if (IPC64) { - *semun->buf64 = buf; - } - else { - *semun->buf32 = buf; - } - } - break; - } - case SEM_INFO: - case IPC_INFO: { - struct fex_seminfo si{}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); - if (Result != -1) { - memcpy(semun->__buf, &si, sizeof(si)); - } - break; - } - case GETALL: - case SETALL: { - // ptr is just a int32_t* in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->array); - break; - } - case SETVAL: { - // ptr is just a int32_t in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->val); - break; - } - case IPC_RMID: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETVAL: - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); - return -EINVAL; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { + if (IPC64) { + *semun->buf64 = buf; + } else { + *semun->buf32 = buf; } - break; } - case OP_SEMTIMEDOP: { - timespec32 *timeout = reinterpret_cast(fifth); - struct timespec tp64{}; - struct timespec *timed_ptr{}; - if (timeout) { - tp64 = *timeout; - timed_ptr = &tp64; + break; + } + case SEM_STAT: + case SEM_STAT_ANY: + case IPC_STAT: { + struct semid64_ds buf {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { + if (IPC64) { + *semun->buf64 = buf; + } else { + *semun->buf32 = buf; } - - Result = ::syscall(SYSCALL_DEF(semtimedop), first, reinterpret_cast(ptr), second, timed_ptr); - break; } - case OP_MSGSND: { - // Requires a temporary buffer - fextl::vector Tmp(second + sizeof(size_t)); - struct msgbuf *TmpMsg = reinterpret_cast(&Tmp.at(0)); - msgbuf_32 *src = reinterpret_cast(ptr); - TmpMsg->mtype = src->mtype; - memcpy(TmpMsg->mtext, src->mtext, second); - - Result = ::syscall(SYSCALL_DEF(msgsnd), first, TmpMsg, second, third); - break; + break; + } + case SEM_INFO: + case IPC_INFO: { + struct fex_seminfo si {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); + if (Result != -1) { + memcpy(semun->__buf, &si, sizeof(si)); } - case OP_MSGRCV: { - fextl::vector Tmp(second + sizeof(size_t)); - struct msgbuf *TmpMsg = reinterpret_cast(&Tmp.at(0)); + break; + } + case GETALL: + case SETALL: { + // ptr is just a int32_t* in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->array); + break; + } + case SETVAL: { + // ptr is just a int32_t in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->val); + break; + } + case IPC_RMID: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETVAL: Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd); break; + default: LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); return -EINVAL; + } + break; + } + case OP_SEMTIMEDOP: { + timespec32* timeout = reinterpret_cast(fifth); + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout) { + tp64 = *timeout; + timed_ptr = &tp64; + } - if (call >> 16) { - Result = ::syscall(SYSCALL_DEF(msgrcv), first, TmpMsg, second, fifth, third); - if (Result != -1) { - msgbuf_32 *src = reinterpret_cast(ptr); - src->mtype = TmpMsg->mtype; - memcpy(src->mtext, TmpMsg->mtext, Result); - } + Result = ::syscall(SYSCALL_DEF(semtimedop), first, reinterpret_cast(ptr), second, timed_ptr); + break; + } + case OP_MSGSND: { + // Requires a temporary buffer + fextl::vector Tmp(second + sizeof(size_t)); + struct msgbuf* TmpMsg = reinterpret_cast(&Tmp.at(0)); + msgbuf_32* src = reinterpret_cast(ptr); + TmpMsg->mtype = src->mtype; + memcpy(TmpMsg->mtext, src->mtext, second); + Result = ::syscall(SYSCALL_DEF(msgsnd), first, TmpMsg, second, third); + break; + } + case OP_MSGRCV: { + fextl::vector Tmp(second + sizeof(size_t)); + struct msgbuf* TmpMsg = reinterpret_cast(&Tmp.at(0)); + + if (call >> 16) { + Result = ::syscall(SYSCALL_DEF(msgrcv), first, TmpMsg, second, fifth, third); + if (Result != -1) { + msgbuf_32* src = reinterpret_cast(ptr); + src->mtype = TmpMsg->mtype; + memcpy(src->mtext, TmpMsg->mtext, Result); + } + + } else { + struct compat_ipc_kludge { + compat_uptr_t msgp; + compat_long_t msgtyp; + }; + compat_ipc_kludge* ipck = reinterpret_cast(ptr); + Result = ::syscall(SYSCALL_DEF(msgrcv), first, TmpMsg, second, ipck->msgtyp, third); + if (Result != -1) { + msgbuf_32* src = reinterpret_cast(ipck->msgp); + ipck->msgtyp = TmpMsg->mtype; + memcpy(src->mtext, TmpMsg->mtext, Result); + } + } + + break; + } + case OP_MSGGET: { + Result = ::syscall(SYSCALL_DEF(msgget), first, second); + break; + } + case OP_MSGCTL: { + uint32_t msqid = first; + int32_t cmd = second & 0xFF; + msgun_32 msgun {}; + msgun.val = ptr; + bool IPC64 = second & 0x100; + switch (cmd) { + case IPC_SET: { + struct msqid64_ds buf {}; + if (IPC64) { + buf = *msgun.buf64; + } else { + buf = *msgun.buf32; + } + Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, &buf); + break; + } + case MSG_STAT: + case MSG_STAT_ANY: + case IPC_STAT: { + struct msqid64_ds buf {}; + Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, &buf); + if (Result != -1) { + if (IPC64) { + *msgun.buf64 = buf; + } else { + *msgun.buf32 = buf; } - else { - struct compat_ipc_kludge { - compat_uptr_t msgp; - compat_long_t msgtyp; - }; - compat_ipc_kludge *ipck = reinterpret_cast(ptr); - Result = ::syscall(SYSCALL_DEF(msgrcv), first, TmpMsg, second, ipck->msgtyp, third); - if (Result != -1) { - msgbuf_32 *src = reinterpret_cast(ipck->msgp); - ipck->msgtyp = TmpMsg->mtype; - memcpy(src->mtext, TmpMsg->mtext, Result); - } - } + } + break; + } + case MSG_INFO: + case IPC_INFO: { + struct msginfo mi {}; + Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, reinterpret_cast(&mi)); + if (Result != -1) { + memcpy(msgun.__buf, &mi, sizeof(mi)); + } + break; + } + case IPC_RMID: Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, nullptr); break; + default: LOGMAN_MSG_A_FMT("Unhandled msgctl cmd: {}", cmd); return -EINVAL; + } + break; + } + case OP_SHMAT: { + // also implemented in memory:shmat + Result = static_cast(FEX::HLE::_SyscallHandler) + ->GetAllocator() + ->Shmat(first, reinterpret_cast(ptr), second, reinterpret_cast(third)); + if (!FEX::HLE::HasSyscallError(Result)) { + FEX::HLE::_SyscallHandler->TrackShmat(Frame->Thread, first, *reinterpret_cast(third), second); + } + break; + } + case OP_SHMDT: { + // also implemented in memory:shmdt + Result = static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()->Shmdt(reinterpret_cast(ptr)); + if (!FEX::HLE::HasSyscallError(Result)) { + FEX::HLE::_SyscallHandler->TrackShmdt(Frame->Thread, ptr); + } + break; + } + case OP_SHMGET: { + Result = ::shmget(first, second, third); + break; + } + case OP_SHMCTL: { + int32_t shmid = first; + int32_t shmcmd = second; + int32_t cmd = shmcmd & 0xFF; + bool IPC64 = shmcmd & 0x100; + shmun_32 shmun {}; + shmun.val = reinterpret_cast(ptr); - break; + switch (cmd) { + case IPC_SET: { + struct shmid64_ds buf {}; + if (IPC64) { + buf = *shmun.buf64; + } else { + buf = *shmun.buf32; } - case OP_MSGGET: { - Result = ::syscall(SYSCALL_DEF(msgget), first, second); - break; - } - case OP_MSGCTL: { - uint32_t msqid = first; - int32_t cmd = second & 0xFF; - msgun_32 msgun{}; - msgun.val = ptr; - bool IPC64 = second & 0x100; - switch (cmd) { - case IPC_SET: { - struct msqid64_ds buf{}; - if (IPC64) { - buf = *msgun.buf64; - } - else { - buf = *msgun.buf32; - } - Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, &buf); - break; - } - case MSG_STAT: - case MSG_STAT_ANY: - case IPC_STAT: { - struct msqid64_ds buf{}; - Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, &buf); - if (Result != -1) { - if (IPC64) { - *msgun.buf64 = buf; - } - else { - *msgun.buf32 = buf; - } - } - break; - } - case MSG_INFO: - case IPC_INFO: { - struct msginfo mi{}; - Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, reinterpret_cast(&mi)); - if (Result != -1) { - memcpy(msgun.__buf, &mi, sizeof(mi)); - } - break; - } - case IPC_RMID: - Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, nullptr); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled msgctl cmd: {}", cmd); - return -EINVAL; + Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, &buf); + // IPC_SET sets the internal data structure that the kernel uses + // No need to writeback + break; + } + case SHM_STAT: + case SHM_STAT_ANY: + case IPC_STAT: { + struct shmid64_ds buf {}; + Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, &buf); + if (Result != -1) { + if (IPC64) { + *shmun.buf64 = buf; + } else { + *shmun.buf32 = buf; } - break; } - case OP_SHMAT: { - // also implemented in memory:shmat - Result = static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()-> - Shmat(first, reinterpret_cast(ptr), second, reinterpret_cast(third)); - if (!FEX::HLE::HasSyscallError(Result)) { - FEX::HLE::_SyscallHandler->TrackShmat(Frame->Thread, first, *reinterpret_cast(third), second); + break; + } + case IPC_INFO: { + struct shminfo si {}; + Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, reinterpret_cast(&si)); + if (Result != -1) { + if (IPC64) { + *shmun.__buf64 = si; + } else { + *shmun.__buf32 = si; } - break; } - case OP_SHMDT: { - // also implemented in memory:shmdt - Result = static_cast(FEX::HLE::_SyscallHandler)->GetAllocator()-> - Shmdt(reinterpret_cast(ptr)); - if (!FEX::HLE::HasSyscallError(Result)) { - FEX::HLE::_SyscallHandler->TrackShmdt(Frame->Thread, ptr); - } - break; + break; + } + case SHM_INFO: { + struct shm_info si {}; + Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, reinterpret_cast(&si)); + if (Result != -1) { + // SHM_INFO doesn't follow IPC64 behaviour + *shmun.__buf_info_32 = si; } - case OP_SHMGET: { - Result = ::shmget(first, second, third); - break; - } - case OP_SHMCTL: { - int32_t shmid = first; - int32_t shmcmd = second; - int32_t cmd = shmcmd & 0xFF; - bool IPC64 = shmcmd & 0x100; - shmun_32 shmun{}; - shmun.val = reinterpret_cast(ptr); + break; + } + case SHM_LOCK: Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, nullptr); break; + case SHM_UNLOCK: Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, nullptr); break; + case IPC_RMID: Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, nullptr); break; - switch (cmd) { - case IPC_SET: { - struct shmid64_ds buf{}; - if (IPC64) { - buf = *shmun.buf64; - } - else { - buf = *shmun.buf32; - } - Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, &buf); - // IPC_SET sets the internal data structure that the kernel uses - // No need to writeback - break; - } - case SHM_STAT: - case SHM_STAT_ANY: - case IPC_STAT: { - struct shmid64_ds buf{}; - Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, &buf); - if (Result != -1) { - if (IPC64) { - *shmun.buf64 = buf; - } - else { - *shmun.buf32 = buf; - } - } - break; - } - case IPC_INFO: { - struct shminfo si{}; - Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, reinterpret_cast(&si)); - if (Result != -1) { - if (IPC64) { - *shmun.__buf64 = si; - } - else { - *shmun.__buf32 = si; - } - } - break; - } - case SHM_INFO: { - struct shm_info si{}; - Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, reinterpret_cast(&si)); - if (Result != -1) { - // SHM_INFO doesn't follow IPC64 behaviour - *shmun.__buf_info_32 = si; - } - break; - } - case SHM_LOCK: - Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, nullptr); - break; - case SHM_UNLOCK: - Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, nullptr); - break; - case IPC_RMID: - Result = ::syscall(SYSCALL_DEF(shmctl), shmid, cmd, nullptr); - break; + default: LOGMAN_MSG_A_FMT("Unhandled shmctl cmd: {}", cmd); return -EINVAL; + } + break; + } - default: - LOGMAN_MSG_A_FMT("Unhandled shmctl cmd: {}", cmd); - return -EINVAL; - } - break; + default: return -ENOSYS; + } + SYSCALL_ERRNO(); +} +void RegisterSemaphore(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(ipc, _ipc); + + REGISTER_SYSCALL_IMPL_X32(semctl, [](FEXCore::Core::CpuStateFrame* Frame, int semid, int semnum, int cmd, semun_32* semun) -> uint64_t { + uint64_t Result {}; + bool IPC64 = cmd & 0x100; + + switch (cmd) { + case IPC_SET: { + struct semid64_ds buf {}; + if (IPC64) { + buf = *semun->buf64; + } else { + buf = *semun->buf32; } - - default: return -ENOSYS; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { + if (IPC64) { + *semun->buf64 = buf; + } else { + *semun->buf32 = buf; + } + } + break; + } + case SEM_STAT: + case SEM_STAT_ANY: + case IPC_STAT: { + struct semid64_ds buf {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { + if (IPC64) { + *semun->buf64 = buf; + } else { + *semun->buf32 = buf; + } + } + break; + } + case SEM_INFO: + case IPC_INFO: { + struct fex_seminfo si {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); + if (Result != -1) { + memcpy(semun->__buf, &si, sizeof(si)); + } + break; + } + case GETALL: + case SETALL: { + // ptr is just a int32_t* in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->array); + break; + } + case SETVAL: { + // ptr is just a int32_t in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->val); + break; + } + case IPC_RMID: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETVAL: Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun); break; + default: LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); return -EINVAL; } SYSCALL_ERRNO(); - } - void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(ipc, _ipc); - - REGISTER_SYSCALL_IMPL_X32(semctl, [](FEXCore::Core::CpuStateFrame *Frame, int semid, int semnum, int cmd, semun_32 *semun) -> uint64_t { - uint64_t Result{}; - bool IPC64 = cmd & 0x100; - - switch (cmd) { - case IPC_SET: { - struct semid64_ds buf{}; - if (IPC64) { - buf = *semun->buf64; - } - else { - buf = *semun->buf32; - } - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - if (IPC64) { - *semun->buf64 = buf; - } - else { - *semun->buf32 = buf; - } - } - break; - } - case SEM_STAT: - case SEM_STAT_ANY: - case IPC_STAT: { - struct semid64_ds buf{}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - if (IPC64) { - *semun->buf64 = buf; - } - else { - *semun->buf32 = buf; - } - } - break; - } - case SEM_INFO: - case IPC_INFO: { - struct fex_seminfo si{}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); - if (Result != -1) { - memcpy(semun->__buf, &si, sizeof(si)); - } - break; - } - case GETALL: - case SETALL: { - // ptr is just a int32_t* in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->array); - break; - } - case SETVAL: { - // ptr is just a int32_t in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->val); - break; - } - case IPC_RMID: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETVAL: - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); - return -EINVAL; - } - SYSCALL_ERRNO(); - }); - - } + }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp index d16b09434..456b1f697 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp @@ -22,112 +22,110 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") namespace FEX::HLE::x32 { - void CopySigInfo(FEXCore::x86::siginfo_t *Info, siginfo_t const &Host) { - // Copy the basic things first - Info->si_signo = Host.si_signo; - Info->si_errno = Host.si_errno; - Info->si_code = Host.si_code; +void CopySigInfo(FEXCore::x86::siginfo_t* Info, const siginfo_t& Host) { + // Copy the basic things first + Info->si_signo = Host.si_signo; + Info->si_errno = Host.si_errno; + Info->si_code = Host.si_code; - // Check si_code to determine how we need to interpret this - if (Info->si_code == SI_TIMER) { - // SI_TIMER means pid, uid, value - Info->_sifields._timer.tid = Host.si_timerid; + // Check si_code to determine how we need to interpret this + if (Info->si_code == SI_TIMER) { + // SI_TIMER means pid, uid, value + Info->_sifields._timer.tid = Host.si_timerid; + Info->_sifields._timer.overrun = Host.si_overrun; + Info->_sifields._timer.sigval.sival_int = Host.si_value.sival_int; + } else { + // Now we need to copy over the more complex things + switch (Info->si_signo) { + case SIGSEGV: + case SIGBUS: + // This is the address trying to be accessed, not the RIP + Info->_sifields._sigfault.addr = static_cast(reinterpret_cast(Host.si_addr)); + break; + case SIGFPE: + case SIGILL: + // Can't really give a real result here. This is the RIP causing a sigill or sigfpe + // Claim at RIP 0 for now + Info->_sifields._sigfault.addr = 0; + break; + case SIGCHLD: + Info->_sifields._sigchld.pid = Host.si_pid; + Info->_sifields._sigchld.uid = Host.si_uid; + Info->_sifields._sigchld.status = Host.si_status; + Info->_sifields._sigchld.utime = Host.si_utime; + Info->_sifields._sigchld.stime = Host.si_stime; + break; + case SIGALRM: + case SIGVTALRM: + Info->_sifields._timer.tid = Host.si_timerid; Info->_sifields._timer.overrun = Host.si_overrun; - Info->_sifields._timer.sigval.sival_int = Host.si_value.sival_int; - } - else { - // Now we need to copy over the more complex things - switch (Info->si_signo) { - case SIGSEGV: - case SIGBUS: - // This is the address trying to be accessed, not the RIP - Info->_sifields._sigfault.addr = static_cast(reinterpret_cast(Host.si_addr)); - break; - case SIGFPE: - case SIGILL: - // Can't really give a real result here. This is the RIP causing a sigill or sigfpe - // Claim at RIP 0 for now - Info->_sifields._sigfault.addr = 0; - break; - case SIGCHLD: - Info->_sifields._sigchld.pid = Host.si_pid; - Info->_sifields._sigchld.uid = Host.si_uid; - Info->_sifields._sigchld.status = Host.si_status; - Info->_sifields._sigchld.utime = Host.si_utime; - Info->_sifields._sigchld.stime = Host.si_stime; - break; - case SIGALRM: - case SIGVTALRM: - Info->_sifields._timer.tid = Host.si_timerid; - Info->_sifields._timer.overrun = Host.si_overrun; - Info->_sifields._timer.sigval.sival_int = Host.si_int; - break; - default: - LogMan::Msg::EFmt("Unhandled siginfo_t for sigtimedwait: {}", Info->si_signo); - break; - } + Info->_sifields._timer.sigval.sival_int = Host.si_int; + break; + default: LogMan::Msg::EFmt("Unhandled siginfo_t for sigtimedwait: {}", Info->si_signo); break; } } +} - void RegisterSignals(FEX::HLE::SyscallHandler *Handler) { +void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { - // Only gets the lower 32-bits of the signal mask - REGISTER_SYSCALL_IMPL_X32(sgetmask, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - uint64_t Set{}; - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(0, nullptr, &Set); - return Set & ~0U; - }); + // Only gets the lower 32-bits of the signal mask + REGISTER_SYSCALL_IMPL_X32(sgetmask, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + uint64_t Set {}; + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(0, nullptr, &Set); + return Set & ~0U; + }); - // Only controls the lower 32-bits of the signal mask - // Blocks the upper 32-bits - REGISTER_SYSCALL_IMPL_X32(ssetmask, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t New) -> uint64_t { - uint64_t Set{}; - uint64_t NewSet = (~0ULL << 32) | New; - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(SIG_SETMASK, &NewSet, &Set); - return Set & ~0U; - }); + // Only controls the lower 32-bits of the signal mask + // Blocks the upper 32-bits + REGISTER_SYSCALL_IMPL_X32(ssetmask, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t New) -> uint64_t { + uint64_t Set {}; + uint64_t NewSet = (~0ULL << 32) | New; + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(SIG_SETMASK, &NewSet, &Set); + return Set & ~0U; + }); - // Only masks the lower 32-bits of the signal mask - // The upper 32-bits are still active (unmasked) and can signal the program - REGISTER_SYSCALL_IMPL_X32(sigsuspend, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t Mask) -> uint64_t { - uint64_t Mask64 = Mask; - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(&Mask64, 8); - }); + // Only masks the lower 32-bits of the signal mask + // The upper 32-bits are still active (unmasked) and can signal the program + REGISTER_SYSCALL_IMPL_X32(sigsuspend, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t Mask) -> uint64_t { + uint64_t Mask64 = Mask; + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(&Mask64, 8); + }); - REGISTER_SYSCALL_IMPL_X32(sigpending, [](FEXCore::Core::CpuStateFrame *Frame, compat_old_sigset_t *set) -> uint64_t { - uint64_t HostSet{}; - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(&HostSet, 8); - if (Result == 0) { - // This old interface only returns the lower signals - *set = HostSet & ~0U; - } - return Result; - }); + REGISTER_SYSCALL_IMPL_X32(sigpending, [](FEXCore::Core::CpuStateFrame* Frame, compat_old_sigset_t* set) -> uint64_t { + uint64_t HostSet {}; + uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(&HostSet, 8); + if (Result == 0) { + // This old interface only returns the lower signals + *set = HostSet & ~0U; + } + return Result; + }); - REGISTER_SYSCALL_IMPL_X32(signal, [](FEXCore::Core::CpuStateFrame *Frame, int signum, uint32_t handler) -> uint64_t { - GuestSigAction newact{}; - GuestSigAction oldact{}; - newact.sigaction_handler.handler = reinterpret_cast(handler); - FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, &newact, &oldact); - return static_cast(reinterpret_cast(oldact.sigaction_handler.handler)); - }); + REGISTER_SYSCALL_IMPL_X32(signal, [](FEXCore::Core::CpuStateFrame* Frame, int signum, uint32_t handler) -> uint64_t { + GuestSigAction newact {}; + GuestSigAction oldact {}; + newact.sigaction_handler.handler = reinterpret_cast(handler); + FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, &newact, &oldact); + return static_cast(reinterpret_cast(oldact.sigaction_handler.handler)); + }); - REGISTER_SYSCALL_IMPL_X32(sigaction, [](FEXCore::Core::CpuStateFrame *Frame, int signum, const OldGuestSigAction_32 *act, OldGuestSigAction_32 *oldact) -> uint64_t { - GuestSigAction *act64_p{}; - GuestSigAction *old64_p{}; + REGISTER_SYSCALL_IMPL_X32( + sigaction, [](FEXCore::Core::CpuStateFrame* Frame, int signum, const OldGuestSigAction_32* act, OldGuestSigAction_32* oldact) -> uint64_t { + GuestSigAction* act64_p {}; + GuestSigAction* old64_p {}; - GuestSigAction act64{}; + GuestSigAction act64 {}; if (act) { act64 = *act; act64_p = &act64; } - GuestSigAction old64{}; + GuestSigAction old64 {}; if (oldact) { old64_p = &old64; @@ -141,20 +139,22 @@ namespace FEX::HLE::x32 { return Result; }); - REGISTER_SYSCALL_IMPL_X32(rt_sigaction, [](FEXCore::Core::CpuStateFrame *Frame, int signum, const GuestSigAction_32 *act, GuestSigAction_32 *oldact, size_t sigsetsize) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + rt_sigaction, + [](FEXCore::Core::CpuStateFrame* Frame, int signum, const GuestSigAction_32* act, GuestSigAction_32* oldact, size_t sigsetsize) -> uint64_t { if (sigsetsize != 8) { return -EINVAL; } - GuestSigAction *act64_p{}; - GuestSigAction *old64_p{}; + GuestSigAction* act64_p {}; + GuestSigAction* old64_p {}; - GuestSigAction act64{}; + GuestSigAction act64 {}; if (act) { act64 = *act; act64_p = &act64; } - GuestSigAction old64{}; + GuestSigAction old64 {}; if (oldact) { old64_p = &old64; @@ -168,38 +168,46 @@ namespace FEX::HLE::x32 { return Result; }); - REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait, [](FEXCore::Core::CpuStateFrame *Frame, uint64_t *set, compat_ptr info, const struct timespec32* timeout, size_t sigsetsize) -> uint64_t { - struct timespec* timeout_ptr{}; - struct timespec tp64{}; - if (timeout) { - tp64 = *timeout; - timeout_ptr = &tp64; - } + REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait, + [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, compat_ptr info, + const struct timespec32* timeout, size_t sigsetsize) -> uint64_t { + struct timespec* timeout_ptr {}; + struct timespec tp64 {}; + if (timeout) { + tp64 = *timeout; + timeout_ptr = &tp64; + } - siginfo_t HostInfo{}; - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout_ptr, sigsetsize); - if (Result != -1) { - // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t - CopySigInfo(info, HostInfo); - } - return Result; - }); + siginfo_t HostInfo {}; + uint64_t Result = + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout_ptr, sigsetsize); + if (Result != -1) { + // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t + CopySigInfo(info, HostInfo); + } + return Result; + }); - REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait_time64, [](FEXCore::Core::CpuStateFrame *Frame, uint64_t *set, compat_ptr info, const struct timespec* timeout, size_t sigsetsize) -> uint64_t { - siginfo_t HostInfo{}; - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout, sigsetsize); - if (Result != -1) { - // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t - CopySigInfo(info, HostInfo); - } - return Result; - }); + REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait_time64, + [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, compat_ptr info, + const struct timespec* timeout, size_t sigsetsize) -> uint64_t { + siginfo_t HostInfo {}; + uint64_t Result = + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout, sigsetsize); + if (Result != -1) { + // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t + CopySigInfo(info, HostInfo); + } + return Result; + }); - if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) { - REGISTER_SYSCALL_IMPL_X32(pidfd_send_signal, [](FEXCore::Core::CpuStateFrame *Frame, int pidfd, int sig, compat_ptr info, unsigned int flags) -> uint64_t { - siginfo_t *InfoHost_ptr{}; - siginfo_t InfoHost{}; + if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) { + REGISTER_SYSCALL_IMPL_X32( + pidfd_send_signal, + [](FEXCore::Core::CpuStateFrame* Frame, int pidfd, int sig, compat_ptr info, unsigned int flags) -> uint64_t { + siginfo_t* InfoHost_ptr {}; + siginfo_t InfoHost {}; if (info) { InfoHost = *info; InfoHost_ptr = &InfoHost; @@ -208,14 +216,14 @@ namespace FEX::HLE::x32 { uint64_t Result = ::syscall(SYSCALL_DEF(pidfd_send_signal), pidfd, sig, InfoHost_ptr, flags); SYSCALL_ERRNO(); }); - } - else { - REGISTER_SYSCALL_IMPL_X32(pidfd_send_signal, UnimplementedSyscallSafe); - } + } else { + REGISTER_SYSCALL_IMPL_X32(pidfd_send_signal, UnimplementedSyscallSafe); + } - REGISTER_SYSCALL_IMPL_X32(rt_sigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int sig, compat_ptr info) -> uint64_t { - siginfo_t info64{}; - siginfo_t *info64_p{}; + REGISTER_SYSCALL_IMPL_X32( + rt_sigqueueinfo, [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, int sig, compat_ptr info) -> uint64_t { + siginfo_t info64 {}; + siginfo_t* info64_p {}; if (info) { info64_p = &info64; @@ -225,9 +233,10 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(rt_tgsigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t tgid, pid_t tid, int sig, compat_ptr info) -> uint64_t { - siginfo_t info64{}; - siginfo_t *info64_p{}; + REGISTER_SYSCALL_IMPL_X32( + rt_tgsigqueueinfo, [](FEXCore::Core::CpuStateFrame* Frame, pid_t tgid, pid_t tid, int sig, compat_ptr info) -> uint64_t { + siginfo_t info64 {}; + siginfo_t* info64_p {}; if (info) { info64_p = &info64; @@ -236,5 +245,5 @@ namespace FEX::HLE::x32 { uint64_t Result = ::syscall(SYSCALL_DEF(rt_tgsigqueueinfo), tgid, tid, sig, info64_p); SYSCALL_ERRNO(); }); - } } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp index a4e2d1a8d..222bffa4d 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp @@ -26,7 +26,7 @@ ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { @@ -111,183 +111,116 @@ namespace FEX::HLE::x32 { #define SO_PEERPIDFD 77 #endif - enum SockOp { - OP_SOCKET = 1, - OP_BIND = 2, - OP_CONNECT = 3, - OP_LISTEN = 4, - OP_ACCEPT = 5, - OP_GETSOCKNAME = 6, - OP_GETPEERNAME = 7, - OP_SOCKETPAIR = 8, - OP_SEND = 9, - OP_RECV = 10, - OP_SENDTO = 11, - OP_RECVFROM = 12, - OP_SHUTDOWN = 13, - OP_SETSOCKOPT = 14, - OP_GETSOCKOPT = 15, - OP_SENDMSG = 16, - OP_RECVMSG = 17, - OP_ACCEPT4 = 18, - OP_RECVMMSG = 19, - OP_SENDMMSG = 20, - }; +enum SockOp { + OP_SOCKET = 1, + OP_BIND = 2, + OP_CONNECT = 3, + OP_LISTEN = 4, + OP_ACCEPT = 5, + OP_GETSOCKNAME = 6, + OP_GETPEERNAME = 7, + OP_SOCKETPAIR = 8, + OP_SEND = 9, + OP_RECV = 10, + OP_SENDTO = 11, + OP_RECVFROM = 12, + OP_SHUTDOWN = 13, + OP_SETSOCKOPT = 14, + OP_GETSOCKOPT = 15, + OP_SENDMSG = 16, + OP_RECVMSG = 17, + OP_ACCEPT4 = 18, + OP_RECVMMSG = 19, + OP_SENDMMSG = 20, +}; - static uint64_t SendMsg(int sockfd, const struct msghdr32 *msg, int flags) { - struct msghdr HostHeader{}; - fextl::vector Host_iovec(msg->msg_iovlen); - for (size_t i = 0; i < msg->msg_iovlen; ++i) { - Host_iovec[i] = msg->msg_iov[i]; - } +static uint64_t SendMsg(int sockfd, const struct msghdr32* msg, int flags) { + struct msghdr HostHeader {}; + fextl::vector Host_iovec(msg->msg_iovlen); + for (size_t i = 0; i < msg->msg_iovlen; ++i) { + Host_iovec[i] = msg->msg_iov[i]; + } - HostHeader.msg_name = msg->msg_name; - HostHeader.msg_namelen = msg->msg_namelen; + HostHeader.msg_name = msg->msg_name; + HostHeader.msg_namelen = msg->msg_namelen; - HostHeader.msg_iov = Host_iovec.data(); - HostHeader.msg_iovlen = msg->msg_iovlen; + HostHeader.msg_iov = Host_iovec.data(); + HostHeader.msg_iovlen = msg->msg_iovlen; - HostHeader.msg_control = alloca(msg->msg_controllen * 2); - HostHeader.msg_controllen = msg->msg_controllen; + HostHeader.msg_control = alloca(msg->msg_controllen * 2); + HostHeader.msg_controllen = msg->msg_controllen; - HostHeader.msg_flags = msg->msg_flags; - if (HostHeader.msg_controllen) { - void *CurrentGuestPtr = msg->msg_control; - struct cmsghdr *CurrentHost = reinterpret_cast(HostHeader.msg_control); + HostHeader.msg_flags = msg->msg_flags; + if (HostHeader.msg_controllen) { + void* CurrentGuestPtr = msg->msg_control; + struct cmsghdr* CurrentHost = reinterpret_cast(HostHeader.msg_control); - for (cmsghdr32 *msghdr_guest = reinterpret_cast(CurrentGuestPtr); - CurrentGuestPtr != 0; - msghdr_guest = reinterpret_cast(CurrentGuestPtr)) { + for (cmsghdr32* msghdr_guest = reinterpret_cast(CurrentGuestPtr); CurrentGuestPtr != 0; + msghdr_guest = reinterpret_cast(CurrentGuestPtr)) { - CurrentHost->cmsg_level = msghdr_guest->cmsg_level; - CurrentHost->cmsg_type = msghdr_guest->cmsg_type; + CurrentHost->cmsg_level = msghdr_guest->cmsg_level; + CurrentHost->cmsg_type = msghdr_guest->cmsg_type; - if (msghdr_guest->cmsg_len) { - size_t SizeIncrease = (CMSG_LEN(0) - sizeof(cmsghdr32)); - CurrentHost->cmsg_len = msghdr_guest->cmsg_len + SizeIncrease; - HostHeader.msg_controllen += SizeIncrease; - memcpy(CMSG_DATA(CurrentHost), msghdr_guest->cmsg_data, msghdr_guest->cmsg_len - sizeof(cmsghdr32)); - } + if (msghdr_guest->cmsg_len) { + size_t SizeIncrease = (CMSG_LEN(0) - sizeof(cmsghdr32)); + CurrentHost->cmsg_len = msghdr_guest->cmsg_len + SizeIncrease; + HostHeader.msg_controllen += SizeIncrease; + memcpy(CMSG_DATA(CurrentHost), msghdr_guest->cmsg_data, msghdr_guest->cmsg_len - sizeof(cmsghdr32)); + } - // Go to next host - CurrentHost = CMSG_NXTHDR(&HostHeader, CurrentHost); + // Go to next host + CurrentHost = CMSG_NXTHDR(&HostHeader, CurrentHost); - // Go to next msg - if (msghdr_guest->cmsg_len < sizeof(cmsghdr32)) { + // Go to next msg + if (msghdr_guest->cmsg_len < sizeof(cmsghdr32)) { + CurrentGuestPtr = nullptr; + } else { + CurrentGuestPtr = reinterpret_cast(reinterpret_cast(CurrentGuestPtr) + msghdr_guest->cmsg_len); + CurrentGuestPtr = reinterpret_cast((reinterpret_cast(CurrentGuestPtr) + 3) & ~3ULL); + if (CurrentGuestPtr >= reinterpret_cast(reinterpret_cast(static_cast(msg->msg_control)) + msg->msg_controllen)) { CurrentGuestPtr = nullptr; } - else { - CurrentGuestPtr = reinterpret_cast(reinterpret_cast(CurrentGuestPtr) + msghdr_guest->cmsg_len); - CurrentGuestPtr = reinterpret_cast((reinterpret_cast(CurrentGuestPtr) + 3) & ~3ULL); - if (CurrentGuestPtr >= reinterpret_cast(reinterpret_cast(static_cast(msg->msg_control)) + msg->msg_controllen)) { - CurrentGuestPtr = nullptr; - } - } } } - - uint64_t Result = ::sendmsg(sockfd, &HostHeader, flags); - SYSCALL_ERRNO(); } - static uint64_t RecvMsg(int sockfd, struct msghdr32 *msg, int flags) { - struct msghdr HostHeader{}; - fextl::vector Host_iovec(msg->msg_iovlen); + uint64_t Result = ::sendmsg(sockfd, &HostHeader, flags); + SYSCALL_ERRNO(); +} + +static uint64_t RecvMsg(int sockfd, struct msghdr32* msg, int flags) { + struct msghdr HostHeader {}; + fextl::vector Host_iovec(msg->msg_iovlen); + for (size_t i = 0; i < msg->msg_iovlen; ++i) { + Host_iovec[i] = msg->msg_iov[i]; + } + + HostHeader.msg_name = msg->msg_name; + HostHeader.msg_namelen = msg->msg_namelen; + + HostHeader.msg_iov = Host_iovec.data(); + HostHeader.msg_iovlen = msg->msg_iovlen; + + HostHeader.msg_control = alloca(msg->msg_controllen * 2); + HostHeader.msg_controllen = msg->msg_controllen * 2; + + HostHeader.msg_flags = msg->msg_flags; + + uint64_t Result = ::recvmsg(sockfd, &HostHeader, flags); + if (Result != -1) { for (size_t i = 0; i < msg->msg_iovlen; ++i) { - Host_iovec[i] = msg->msg_iov[i]; + msg->msg_iov[i] = Host_iovec[i]; } - HostHeader.msg_name = msg->msg_name; - HostHeader.msg_namelen = msg->msg_namelen; - - HostHeader.msg_iov = Host_iovec.data(); - HostHeader.msg_iovlen = msg->msg_iovlen; - - HostHeader.msg_control = alloca(msg->msg_controllen*2); - HostHeader.msg_controllen = msg->msg_controllen*2; - - HostHeader.msg_flags = msg->msg_flags; - - uint64_t Result = ::recvmsg(sockfd, &HostHeader, flags); - if (Result != -1) { - for (size_t i = 0; i < msg->msg_iovlen; ++i) { - msg->msg_iov[i] = Host_iovec[i]; - } - - msg->msg_namelen = HostHeader.msg_namelen; - msg->msg_controllen = HostHeader.msg_controllen; - msg->msg_flags = HostHeader.msg_flags; - if (HostHeader.msg_controllen) { - // Host and guest cmsg data structures aren't compatible. - // Copy them over now - void *CurrentGuestPtr = msg->msg_control; - for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&HostHeader); - cmsg != nullptr; - cmsg = CMSG_NXTHDR(&HostHeader, cmsg)) { - cmsghdr32 *CurrentGuest = reinterpret_cast(CurrentGuestPtr); - - // Copy over the header first - // cmsg_len needs to be adjusted by the size of the header between host and guest - // Host is 16 bytes, guest is 12 bytes - CurrentGuest->cmsg_level = cmsg->cmsg_level; - CurrentGuest->cmsg_type = cmsg->cmsg_type; - - // Now copy over the data - if (cmsg->cmsg_len) { - size_t SizeIncrease = (CMSG_LEN(0) - sizeof(cmsghdr32)); - CurrentGuest->cmsg_len = cmsg->cmsg_len - SizeIncrease; - - // Controllen size also changes - msg->msg_controllen -= SizeIncrease; - - memcpy(CurrentGuest->cmsg_data, CMSG_DATA(cmsg), cmsg->cmsg_len - sizeof(struct cmsghdr)); - CurrentGuestPtr = reinterpret_cast(reinterpret_cast(CurrentGuestPtr) + CurrentGuest->cmsg_len); - CurrentGuestPtr = reinterpret_cast((reinterpret_cast(CurrentGuestPtr) + 3) & ~3ULL); - - } - } - } - } - SYSCALL_ERRNO(); - } - - void ConvertHeaderToHost(fextl::vector &iovec, struct msghdr *Host, const struct msghdr32 *Guest) { - size_t CurrentIOVecSize = iovec.size(); - iovec.resize(CurrentIOVecSize + Guest->msg_iovlen); - for (size_t i = 0; i < Guest->msg_iovlen; ++i) { - iovec[CurrentIOVecSize + i] = Guest->msg_iov[i]; - } - - Host->msg_name = Guest->msg_name; - Host->msg_namelen = Guest->msg_namelen; - - Host->msg_iov = &iovec[CurrentIOVecSize]; - Host->msg_iovlen = Guest->msg_iovlen; - - // XXX: This could result in a stack overflow - Host->msg_control = alloca(Guest->msg_controllen*2); - Host->msg_controllen = Guest->msg_controllen*2; - - Host->msg_flags = Guest->msg_flags; - } - - void ConvertHeaderToGuest(struct msghdr32 *Guest, struct msghdr *Host) { - for (size_t i = 0; i < Guest->msg_iovlen; ++i) { - Guest->msg_iov[i] = Host->msg_iov[i]; - } - - Guest->msg_namelen = Host->msg_namelen; - Guest->msg_controllen = Host->msg_controllen; - Guest->msg_flags = Host->msg_flags; - - if (Host->msg_controllen) { + msg->msg_namelen = HostHeader.msg_namelen; + msg->msg_controllen = HostHeader.msg_controllen; + msg->msg_flags = HostHeader.msg_flags; + if (HostHeader.msg_controllen) { // Host and guest cmsg data structures aren't compatible. // Copy them over now - void *CurrentGuestPtr = Guest->msg_control; - for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(Host); - cmsg != nullptr; - cmsg = CMSG_NXTHDR(Host, cmsg)) { - cmsghdr32 *CurrentGuest = reinterpret_cast(CurrentGuestPtr); + void* CurrentGuestPtr = msg->msg_control; + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&HostHeader); cmsg != nullptr; cmsg = CMSG_NXTHDR(&HostHeader, cmsg)) { + cmsghdr32* CurrentGuest = reinterpret_cast(CurrentGuestPtr); // Copy over the header first // cmsg_len needs to be adjusted by the size of the header between host and guest @@ -301,7 +234,7 @@ namespace FEX::HLE::x32 { CurrentGuest->cmsg_len = cmsg->cmsg_len - SizeIncrease; // Controllen size also changes - Guest->msg_controllen -= SizeIncrease; + msg->msg_controllen -= SizeIncrease; memcpy(CurrentGuest->cmsg_data, CMSG_DATA(cmsg), cmsg->cmsg_len - sizeof(struct cmsghdr)); CurrentGuestPtr = reinterpret_cast(reinterpret_cast(CurrentGuestPtr) + CurrentGuest->cmsg_len); @@ -310,558 +243,547 @@ namespace FEX::HLE::x32 { } } } + SYSCALL_ERRNO(); +} - static uint64_t RecvMMsg(int sockfd, compat_ptr msgvec, uint32_t vlen, int flags, struct timespec *timeout_ts) { - fextl::vector Host_iovec; - fextl::vector HostMHeader(vlen); - for (size_t i = 0; i < vlen; ++i) { - ConvertHeaderToHost(Host_iovec, &HostMHeader[i].msg_hdr, &msgvec[i].msg_hdr); - HostMHeader[i].msg_len = msgvec[i].msg_len; - } - uint64_t Result = ::recvmmsg(sockfd, HostMHeader.data(), vlen, flags, timeout_ts); - if (Result != -1) { - for (size_t i = 0; i < Result; ++i) { - ConvertHeaderToGuest(&msgvec[i].msg_hdr, &HostMHeader[i].msg_hdr); - msgvec[i].msg_len = HostMHeader[i].msg_len; - } - } - SYSCALL_ERRNO(); +void ConvertHeaderToHost(fextl::vector& iovec, struct msghdr* Host, const struct msghdr32* Guest) { + size_t CurrentIOVecSize = iovec.size(); + iovec.resize(CurrentIOVecSize + Guest->msg_iovlen); + for (size_t i = 0; i < Guest->msg_iovlen; ++i) { + iovec[CurrentIOVecSize + i] = Guest->msg_iov[i]; } - static uint64_t SendMMsg(int sockfd, compat_ptr msgvec, uint32_t vlen, int flags) { - fextl::vector Host_iovec; - fextl::vector HostMmsg(vlen); + Host->msg_name = Guest->msg_name; + Host->msg_namelen = Guest->msg_namelen; - // Walk the iovec and convert them - // Calculate controllen at the same time - size_t Controllen_size{}; - for (size_t i = 0; i < vlen; ++i) { - msghdr32 &guest = msgvec[i].msg_hdr; + Host->msg_iov = &iovec[CurrentIOVecSize]; + Host->msg_iovlen = Guest->msg_iovlen; - Controllen_size += guest.msg_controllen * 2; - for (size_t j = 0; j < guest.msg_iovlen; ++j) { - iovec guest_iov = guest.msg_iov[j]; - Host_iovec.emplace_back(guest_iov); + // XXX: This could result in a stack overflow + Host->msg_control = alloca(Guest->msg_controllen * 2); + Host->msg_controllen = Guest->msg_controllen * 2; + + Host->msg_flags = Guest->msg_flags; +} + +void ConvertHeaderToGuest(struct msghdr32* Guest, struct msghdr* Host) { + for (size_t i = 0; i < Guest->msg_iovlen; ++i) { + Guest->msg_iov[i] = Host->msg_iov[i]; + } + + Guest->msg_namelen = Host->msg_namelen; + Guest->msg_controllen = Host->msg_controllen; + Guest->msg_flags = Host->msg_flags; + + if (Host->msg_controllen) { + // Host and guest cmsg data structures aren't compatible. + // Copy them over now + void* CurrentGuestPtr = Guest->msg_control; + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(Host); cmsg != nullptr; cmsg = CMSG_NXTHDR(Host, cmsg)) { + cmsghdr32* CurrentGuest = reinterpret_cast(CurrentGuestPtr); + + // Copy over the header first + // cmsg_len needs to be adjusted by the size of the header between host and guest + // Host is 16 bytes, guest is 12 bytes + CurrentGuest->cmsg_level = cmsg->cmsg_level; + CurrentGuest->cmsg_type = cmsg->cmsg_type; + + // Now copy over the data + if (cmsg->cmsg_len) { + size_t SizeIncrease = (CMSG_LEN(0) - sizeof(cmsghdr32)); + CurrentGuest->cmsg_len = cmsg->cmsg_len - SizeIncrease; + + // Controllen size also changes + Guest->msg_controllen -= SizeIncrease; + + memcpy(CurrentGuest->cmsg_data, CMSG_DATA(cmsg), cmsg->cmsg_len - sizeof(struct cmsghdr)); + CurrentGuestPtr = reinterpret_cast(reinterpret_cast(CurrentGuestPtr) + CurrentGuest->cmsg_len); + CurrentGuestPtr = reinterpret_cast((reinterpret_cast(CurrentGuestPtr) + 3) & ~3ULL); } } + } +} - fextl::vector Controllen(Controllen_size); +static uint64_t RecvMMsg(int sockfd, compat_ptr msgvec, uint32_t vlen, int flags, struct timespec* timeout_ts) { + fextl::vector Host_iovec; + fextl::vector HostMHeader(vlen); + for (size_t i = 0; i < vlen; ++i) { + ConvertHeaderToHost(Host_iovec, &HostMHeader[i].msg_hdr, &msgvec[i].msg_hdr); + HostMHeader[i].msg_len = msgvec[i].msg_len; + } + uint64_t Result = ::recvmmsg(sockfd, HostMHeader.data(), vlen, flags, timeout_ts); + if (Result != -1) { + for (size_t i = 0; i < Result; ++i) { + ConvertHeaderToGuest(&msgvec[i].msg_hdr, &HostMHeader[i].msg_hdr); + msgvec[i].msg_len = HostMHeader[i].msg_len; + } + } + SYSCALL_ERRNO(); +} - size_t current_iov{}; - size_t current_controllen_offset{}; - for (size_t i = 0; i < vlen; ++i) { - msghdr32 &guest = msgvec[i].msg_hdr; - struct msghdr &msg = HostMmsg[i].msg_hdr; - msg.msg_name = guest.msg_name; - msg.msg_namelen = guest.msg_namelen; +static uint64_t SendMMsg(int sockfd, compat_ptr msgvec, uint32_t vlen, int flags) { + fextl::vector Host_iovec; + fextl::vector HostMmsg(vlen); - msg.msg_iov = &Host_iovec.at(current_iov); - msg.msg_iovlen = guest.msg_iovlen; - current_iov += msg.msg_iovlen; + // Walk the iovec and convert them + // Calculate controllen at the same time + size_t Controllen_size {}; + for (size_t i = 0; i < vlen; ++i) { + msghdr32& guest = msgvec[i].msg_hdr; - if (guest.msg_controllen) { - msg.msg_control = &Controllen.at(current_controllen_offset); - current_controllen_offset += guest.msg_controllen * 2; - } - msg.msg_controllen = guest.msg_controllen; + Controllen_size += guest.msg_controllen * 2; + for (size_t j = 0; j < guest.msg_iovlen; ++j) { + iovec guest_iov = guest.msg_iov[j]; + Host_iovec.emplace_back(guest_iov); + } + } - msg.msg_flags = guest.msg_flags; + fextl::vector Controllen(Controllen_size); - if (msg.msg_controllen) { - void *CurrentGuestPtr = guest.msg_control; - struct cmsghdr *CurrentHost = reinterpret_cast(msg.msg_control); + size_t current_iov {}; + size_t current_controllen_offset {}; + for (size_t i = 0; i < vlen; ++i) { + msghdr32& guest = msgvec[i].msg_hdr; + struct msghdr& msg = HostMmsg[i].msg_hdr; + msg.msg_name = guest.msg_name; + msg.msg_namelen = guest.msg_namelen; - for (cmsghdr32 *msghdr_guest = reinterpret_cast(CurrentGuestPtr); - CurrentGuestPtr != 0; - msghdr_guest = reinterpret_cast(CurrentGuestPtr)) { + msg.msg_iov = &Host_iovec.at(current_iov); + msg.msg_iovlen = guest.msg_iovlen; + current_iov += msg.msg_iovlen; - CurrentHost->cmsg_level = msghdr_guest->cmsg_level; - CurrentHost->cmsg_type = msghdr_guest->cmsg_type; + if (guest.msg_controllen) { + msg.msg_control = &Controllen.at(current_controllen_offset); + current_controllen_offset += guest.msg_controllen * 2; + } + msg.msg_controllen = guest.msg_controllen; - if (msghdr_guest->cmsg_len) { - size_t SizeIncrease = (CMSG_LEN(0) - sizeof(cmsghdr32)); - CurrentHost->cmsg_len = msghdr_guest->cmsg_len + SizeIncrease; - msg.msg_controllen += SizeIncrease; - memcpy(CMSG_DATA(CurrentHost), msghdr_guest->cmsg_data, msghdr_guest->cmsg_len - sizeof(cmsghdr32)); - } + msg.msg_flags = guest.msg_flags; - // Go to next host - CurrentHost = CMSG_NXTHDR(&msg, CurrentHost); + if (msg.msg_controllen) { + void* CurrentGuestPtr = guest.msg_control; + struct cmsghdr* CurrentHost = reinterpret_cast(msg.msg_control); - // Go to next msg - if (msghdr_guest->cmsg_len < sizeof(cmsghdr32)) { + for (cmsghdr32* msghdr_guest = reinterpret_cast(CurrentGuestPtr); CurrentGuestPtr != 0; + msghdr_guest = reinterpret_cast(CurrentGuestPtr)) { + + CurrentHost->cmsg_level = msghdr_guest->cmsg_level; + CurrentHost->cmsg_type = msghdr_guest->cmsg_type; + + if (msghdr_guest->cmsg_len) { + size_t SizeIncrease = (CMSG_LEN(0) - sizeof(cmsghdr32)); + CurrentHost->cmsg_len = msghdr_guest->cmsg_len + SizeIncrease; + msg.msg_controllen += SizeIncrease; + memcpy(CMSG_DATA(CurrentHost), msghdr_guest->cmsg_data, msghdr_guest->cmsg_len - sizeof(cmsghdr32)); + } + + // Go to next host + CurrentHost = CMSG_NXTHDR(&msg, CurrentHost); + + // Go to next msg + if (msghdr_guest->cmsg_len < sizeof(cmsghdr32)) { + CurrentGuestPtr = nullptr; + } else { + CurrentGuestPtr = reinterpret_cast(reinterpret_cast(CurrentGuestPtr) + msghdr_guest->cmsg_len); + CurrentGuestPtr = reinterpret_cast((reinterpret_cast(CurrentGuestPtr) + 3) & ~3ULL); + if (CurrentGuestPtr >= reinterpret_cast(reinterpret_cast(static_cast(guest.msg_control)) + guest.msg_controllen)) { CurrentGuestPtr = nullptr; } - else { - CurrentGuestPtr = reinterpret_cast(reinterpret_cast(CurrentGuestPtr) + msghdr_guest->cmsg_len); - CurrentGuestPtr = reinterpret_cast((reinterpret_cast(CurrentGuestPtr) + 3) & ~3ULL); - if (CurrentGuestPtr >= reinterpret_cast(reinterpret_cast(static_cast(guest.msg_control)) + guest.msg_controllen)) { - CurrentGuestPtr = nullptr; - } - } } } - - HostMmsg[i].msg_len = msgvec[i].msg_len; } - uint64_t Result = ::sendmmsg(sockfd, HostMmsg.data(), vlen, flags); - - if (Result != -1) { - // Update guest msglen - for (size_t i = 0; i < Result; ++i) { - msgvec[i].msg_len = HostMmsg[i].msg_len; - } - } - SYSCALL_ERRNO(); + HostMmsg[i].msg_len = msgvec[i].msg_len; } - static uint64_t SetSockOpt(int sockfd, int level, int optname, compat_ptr optval, int optlen) { - uint64_t Result{}; + uint64_t Result = ::sendmmsg(sockfd, HostMmsg.data(), vlen, flags); - if (level == SOL_SOCKET) { - switch (optname) { - case SO_ATTACH_FILTER: - case SO_ATTACH_REUSEPORT_CBPF: { - struct sock_fprog32 { - uint16_t len; - uint32_t filter; - }; - struct sock_fprog64 { - uint16_t len; - uint64_t filter; - }; + if (Result != -1) { + // Update guest msglen + for (size_t i = 0; i < Result; ++i) { + msgvec[i].msg_len = HostMmsg[i].msg_len; + } + } + SYSCALL_ERRNO(); +} - if (optlen != sizeof(sock_fprog32)) { - return -EINVAL; - } +static uint64_t SetSockOpt(int sockfd, int level, int optname, compat_ptr optval, int optlen) { + uint64_t Result {}; - sock_fprog32 *prog = reinterpret_cast(optval.Ptr); - sock_fprog64 prog64{}; - prog64.len = prog->len; - prog64.filter = prog->filter; + if (level == SOL_SOCKET) { + switch (optname) { + case SO_ATTACH_FILTER: + case SO_ATTACH_REUSEPORT_CBPF: { + struct sock_fprog32 { + uint16_t len; + uint32_t filter; + }; + struct sock_fprog64 { + uint16_t len; + uint64_t filter; + }; - Result = ::syscall(SYSCALL_DEF(setsockopt), - sockfd, - level, - optname, - &prog64, - sizeof(sock_fprog64) - ); - break; - } - case SO_RCVTIMEO_OLD: { - // _OLD uses old_timeval32. Needs to be converted - struct timeval tv64 = *reinterpret_cast(optval.Ptr); - Result = ::syscall(SYSCALL_DEF(setsockopt), - sockfd, - level, - SO_RCVTIMEO_NEW, - &tv64, - sizeof(tv64) - ); - break; - } - case SO_SNDTIMEO_OLD: { - // _OLD uses old_timeval32. Needs to be converted - struct timeval tv64 = *reinterpret_cast(optval.Ptr); - Result = ::syscall(SYSCALL_DEF(setsockopt), - sockfd, - level, - SO_SNDTIMEO_NEW, - &tv64, - sizeof(tv64) - ); - break; - } - // Each optname as a reminder which setting has been manually checked - case SO_DEBUG: - case SO_REUSEADDR: - case SO_TYPE: - case SO_ERROR: - case SO_DONTROUTE: - case SO_BROADCAST: - case SO_SNDBUF: - case SO_RCVBUF: - case SO_SNDBUFFORCE: - case SO_RCVBUFFORCE: - case SO_KEEPALIVE: - case SO_OOBINLINE: - case SO_NO_CHECK: - case SO_PRIORITY: - case SO_LINGER: - case SO_BSDCOMPAT: - case SO_REUSEPORT: - /** - * @name These end up differing between {x86,arm} and {powerpc, alpha, sparc, mips, parisc} - * @{ */ - case SO_PASSCRED: - case SO_PEERCRED: - case SO_RCVLOWAT: - case SO_SNDLOWAT: - /** @} */ - case SO_SECURITY_AUTHENTICATION: - case SO_SECURITY_ENCRYPTION_TRANSPORT: - case SO_SECURITY_ENCRYPTION_NETWORK: - case SO_DETACH_FILTER: - case SO_PEERNAME: - case SO_TIMESTAMP_OLD: // Returns int32_t boolean - case SO_ACCEPTCONN: - case SO_PEERSEC: - // Gap 32, 33 - case SO_PASSSEC: - case SO_TIMESTAMPNS_OLD: // Returns int32_t boolean - case SO_MARK: - case SO_TIMESTAMPING_OLD: // Returns so_timestamping - case SO_PROTOCOL: - case SO_DOMAIN: - case SO_RXQ_OVFL: - case SO_WIFI_STATUS: - case SO_PEEK_OFF: - case SO_NOFCS: - case SO_LOCK_FILTER: - case SO_SELECT_ERR_QUEUE: - case SO_BUSY_POLL: - case SO_MAX_PACING_RATE: - case SO_BPF_EXTENSIONS: - case SO_INCOMING_CPU: - case SO_ATTACH_BPF: - case SO_ATTACH_REUSEPORT_EBPF: - case SO_CNX_ADVICE: - // Gap 54 (SCM_TIMESTAMPING_OPT_STATS) - case SO_MEMINFO: - case SO_INCOMING_NAPI_ID: - case SO_COOKIE: // Cookie always returns 64-bit even on 32-bit - // Gap 58 (SCM_TIMESTAMPING_PKTINFO) - case SO_PEERGROUPS: - case SO_ZEROCOPY: - case SO_TXTIME: - case SO_BINDTOIFINDEX: - case SO_TIMESTAMP_NEW: - case SO_TIMESTAMPNS_NEW: - case SO_TIMESTAMPING_NEW: - case SO_RCVTIMEO_NEW: - case SO_SNDTIMEO_NEW: - case SO_DETACH_REUSEPORT_BPF: - case SO_PREFER_BUSY_POLL: - case SO_BUSY_POLL_BUDGET: - case SO_NETNS_COOKIE: // Cookie always returns 64-bit even on 32-bit - case SO_BUF_LOCK: - case SO_RESERVE_MEM: - case SO_TXREHASH: - case SO_RCVMARK: - case SO_PASSPIDFD: - case SO_PEERPIDFD: - default: - Result = ::syscall(SYSCALL_DEF(setsockopt), - sockfd, - level, - optname, - reinterpret_cast(optval.Ptr), - optlen - ); - break; + if (optlen != sizeof(sock_fprog32)) { + return -EINVAL; } - } - else { - Result = ::syscall(SYSCALL_DEF(setsockopt), - sockfd, - level, - optname, - reinterpret_cast(optval.Ptr), - optlen - ); - } - SYSCALL_ERRNO(); + sock_fprog32* prog = reinterpret_cast(optval.Ptr); + sock_fprog64 prog64 {}; + prog64.len = prog->len; + prog64.filter = prog->filter; + + Result = ::syscall(SYSCALL_DEF(setsockopt), sockfd, level, optname, &prog64, sizeof(sock_fprog64)); + break; + } + case SO_RCVTIMEO_OLD: { + // _OLD uses old_timeval32. Needs to be converted + struct timeval tv64 = *reinterpret_cast(optval.Ptr); + Result = ::syscall(SYSCALL_DEF(setsockopt), sockfd, level, SO_RCVTIMEO_NEW, &tv64, sizeof(tv64)); + break; + } + case SO_SNDTIMEO_OLD: { + // _OLD uses old_timeval32. Needs to be converted + struct timeval tv64 = *reinterpret_cast(optval.Ptr); + Result = ::syscall(SYSCALL_DEF(setsockopt), sockfd, level, SO_SNDTIMEO_NEW, &tv64, sizeof(tv64)); + break; + } + // Each optname as a reminder which setting has been manually checked + case SO_DEBUG: + case SO_REUSEADDR: + case SO_TYPE: + case SO_ERROR: + case SO_DONTROUTE: + case SO_BROADCAST: + case SO_SNDBUF: + case SO_RCVBUF: + case SO_SNDBUFFORCE: + case SO_RCVBUFFORCE: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case SO_NO_CHECK: + case SO_PRIORITY: + case SO_LINGER: + case SO_BSDCOMPAT: + case SO_REUSEPORT: + /** + * @name These end up differing between {x86,arm} and {powerpc, alpha, sparc, mips, parisc} + * @{ */ + case SO_PASSCRED: + case SO_PEERCRED: + case SO_RCVLOWAT: + case SO_SNDLOWAT: + /** @} */ + case SO_SECURITY_AUTHENTICATION: + case SO_SECURITY_ENCRYPTION_TRANSPORT: + case SO_SECURITY_ENCRYPTION_NETWORK: + case SO_DETACH_FILTER: + case SO_PEERNAME: + case SO_TIMESTAMP_OLD: // Returns int32_t boolean + case SO_ACCEPTCONN: + case SO_PEERSEC: + // Gap 32, 33 + case SO_PASSSEC: + case SO_TIMESTAMPNS_OLD: // Returns int32_t boolean + case SO_MARK: + case SO_TIMESTAMPING_OLD: // Returns so_timestamping + case SO_PROTOCOL: + case SO_DOMAIN: + case SO_RXQ_OVFL: + case SO_WIFI_STATUS: + case SO_PEEK_OFF: + case SO_NOFCS: + case SO_LOCK_FILTER: + case SO_SELECT_ERR_QUEUE: + case SO_BUSY_POLL: + case SO_MAX_PACING_RATE: + case SO_BPF_EXTENSIONS: + case SO_INCOMING_CPU: + case SO_ATTACH_BPF: + case SO_ATTACH_REUSEPORT_EBPF: + case SO_CNX_ADVICE: + // Gap 54 (SCM_TIMESTAMPING_OPT_STATS) + case SO_MEMINFO: + case SO_INCOMING_NAPI_ID: + case SO_COOKIE: // Cookie always returns 64-bit even on 32-bit + // Gap 58 (SCM_TIMESTAMPING_PKTINFO) + case SO_PEERGROUPS: + case SO_ZEROCOPY: + case SO_TXTIME: + case SO_BINDTOIFINDEX: + case SO_TIMESTAMP_NEW: + case SO_TIMESTAMPNS_NEW: + case SO_TIMESTAMPING_NEW: + case SO_RCVTIMEO_NEW: + case SO_SNDTIMEO_NEW: + case SO_DETACH_REUSEPORT_BPF: + case SO_PREFER_BUSY_POLL: + case SO_BUSY_POLL_BUDGET: + case SO_NETNS_COOKIE: // Cookie always returns 64-bit even on 32-bit + case SO_BUF_LOCK: + case SO_RESERVE_MEM: + case SO_TXREHASH: + case SO_RCVMARK: + case SO_PASSPIDFD: + case SO_PEERPIDFD: + default: Result = ::syscall(SYSCALL_DEF(setsockopt), sockfd, level, optname, reinterpret_cast(optval.Ptr), optlen); break; + } + } else { + Result = ::syscall(SYSCALL_DEF(setsockopt), sockfd, level, optname, reinterpret_cast(optval.Ptr), optlen); } - static uint64_t GetSockOpt(int sockfd, int level, int optname, compat_ptr optval, compat_ptr optlen) { - uint64_t Result{}; - if (level == SOL_SOCKET) { - switch (optname) { - case SO_RCVTIMEO_OLD: { - // _OLD uses old_timeval32. Needs to be converted - struct timeval tv64{}; - Result = ::syscall(SYSCALL_DEF(getsockopt), - sockfd, - level, - SO_RCVTIMEO_NEW, - &tv64, - sizeof(tv64) - ); - *reinterpret_cast(optval.Ptr) = tv64; - break; - } - case SO_SNDTIMEO_OLD: { - // _OLD uses old_timeval32. Needs to be converted - struct timeval tv64{}; - Result = ::syscall(SYSCALL_DEF(getsockopt), - sockfd, - level, - SO_SNDTIMEO_NEW, - &tv64, - sizeof(tv64) - ); - *reinterpret_cast(optval.Ptr) = tv64; - break; - } - // Each optname as a reminder which setting has been manually checked - case SO_DEBUG: - case SO_REUSEADDR: - case SO_TYPE: - case SO_ERROR: - case SO_DONTROUTE: - case SO_BROADCAST: - case SO_SNDBUF: - case SO_RCVBUF: - case SO_SNDBUFFORCE: - case SO_RCVBUFFORCE: - case SO_KEEPALIVE: - case SO_OOBINLINE: - case SO_NO_CHECK: - case SO_PRIORITY: - case SO_LINGER: - case SO_BSDCOMPAT: - case SO_REUSEPORT: - /** - * @name These end up differing between {x86,arm} and {powerpc, alpha, sparc, mips, parisc} - * @{ */ - case SO_PASSCRED: - case SO_PEERCRED: - case SO_RCVLOWAT: - case SO_SNDLOWAT: - /** @} */ - case SO_SECURITY_AUTHENTICATION: - case SO_SECURITY_ENCRYPTION_TRANSPORT: - case SO_SECURITY_ENCRYPTION_NETWORK: - case SO_ATTACH_FILTER: // Renamed to SO_GET_FILTER on get. Same between 32-bit and 64-bit - case SO_DETACH_FILTER: - case SO_PEERNAME: - case SO_TIMESTAMP_OLD: // Returns int32_t boolean - case SO_ACCEPTCONN: - case SO_PEERSEC: - // Gap 32, 33 - case SO_PASSSEC: - case SO_TIMESTAMPNS_OLD: // Returns int32_t boolean - case SO_MARK: - case SO_TIMESTAMPING_OLD: // Returns so_timestamping - case SO_PROTOCOL: - case SO_DOMAIN: - case SO_RXQ_OVFL: - case SO_WIFI_STATUS: - case SO_PEEK_OFF: - case SO_NOFCS: - case SO_LOCK_FILTER: - case SO_SELECT_ERR_QUEUE: - case SO_BUSY_POLL: - case SO_MAX_PACING_RATE: - case SO_BPF_EXTENSIONS: - case SO_INCOMING_CPU: - case SO_ATTACH_BPF: - case SO_ATTACH_REUSEPORT_CBPF: // Doesn't do anything in get - case SO_ATTACH_REUSEPORT_EBPF: - case SO_CNX_ADVICE: - // Gap 54 (SCM_TIMESTAMPING_OPT_STATS) - case SO_MEMINFO: - case SO_INCOMING_NAPI_ID: - case SO_COOKIE: // Cookie always returns 64-bit even on 32-bit - // Gap 58 (SCM_TIMESTAMPING_PKTINFO) - case SO_PEERGROUPS: - case SO_ZEROCOPY: - case SO_TXTIME: - case SO_BINDTOIFINDEX: - case SO_TIMESTAMP_NEW: - case SO_TIMESTAMPNS_NEW: - case SO_TIMESTAMPING_NEW: - case SO_RCVTIMEO_NEW: - case SO_SNDTIMEO_NEW: - case SO_DETACH_REUSEPORT_BPF: - case SO_PREFER_BUSY_POLL: - case SO_BUSY_POLL_BUDGET: - case SO_NETNS_COOKIE: // Cookie always returns 64-bit even on 32-bit - case SO_BUF_LOCK: - case SO_RESERVE_MEM: - default: - Result = ::syscall(SYSCALL_DEF(getsockopt), sockfd, level, optname, optval, optlen); - break; - } + SYSCALL_ERRNO(); +} + +static uint64_t GetSockOpt(int sockfd, int level, int optname, compat_ptr optval, compat_ptr optlen) { + uint64_t Result {}; + if (level == SOL_SOCKET) { + switch (optname) { + case SO_RCVTIMEO_OLD: { + // _OLD uses old_timeval32. Needs to be converted + struct timeval tv64 {}; + Result = ::syscall(SYSCALL_DEF(getsockopt), sockfd, level, SO_RCVTIMEO_NEW, &tv64, sizeof(tv64)); + *reinterpret_cast(optval.Ptr) = tv64; + break; } - else { - Result = ::syscall(SYSCALL_DEF(getsockopt), sockfd, level, optname, optval, optlen); + case SO_SNDTIMEO_OLD: { + // _OLD uses old_timeval32. Needs to be converted + struct timeval tv64 {}; + Result = ::syscall(SYSCALL_DEF(getsockopt), sockfd, level, SO_SNDTIMEO_NEW, &tv64, sizeof(tv64)); + *reinterpret_cast(optval.Ptr) = tv64; + break; } - SYSCALL_ERRNO(); + // Each optname as a reminder which setting has been manually checked + case SO_DEBUG: + case SO_REUSEADDR: + case SO_TYPE: + case SO_ERROR: + case SO_DONTROUTE: + case SO_BROADCAST: + case SO_SNDBUF: + case SO_RCVBUF: + case SO_SNDBUFFORCE: + case SO_RCVBUFFORCE: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case SO_NO_CHECK: + case SO_PRIORITY: + case SO_LINGER: + case SO_BSDCOMPAT: + case SO_REUSEPORT: + /** + * @name These end up differing between {x86,arm} and {powerpc, alpha, sparc, mips, parisc} + * @{ */ + case SO_PASSCRED: + case SO_PEERCRED: + case SO_RCVLOWAT: + case SO_SNDLOWAT: + /** @} */ + case SO_SECURITY_AUTHENTICATION: + case SO_SECURITY_ENCRYPTION_TRANSPORT: + case SO_SECURITY_ENCRYPTION_NETWORK: + case SO_ATTACH_FILTER: // Renamed to SO_GET_FILTER on get. Same between 32-bit and 64-bit + case SO_DETACH_FILTER: + case SO_PEERNAME: + case SO_TIMESTAMP_OLD: // Returns int32_t boolean + case SO_ACCEPTCONN: + case SO_PEERSEC: + // Gap 32, 33 + case SO_PASSSEC: + case SO_TIMESTAMPNS_OLD: // Returns int32_t boolean + case SO_MARK: + case SO_TIMESTAMPING_OLD: // Returns so_timestamping + case SO_PROTOCOL: + case SO_DOMAIN: + case SO_RXQ_OVFL: + case SO_WIFI_STATUS: + case SO_PEEK_OFF: + case SO_NOFCS: + case SO_LOCK_FILTER: + case SO_SELECT_ERR_QUEUE: + case SO_BUSY_POLL: + case SO_MAX_PACING_RATE: + case SO_BPF_EXTENSIONS: + case SO_INCOMING_CPU: + case SO_ATTACH_BPF: + case SO_ATTACH_REUSEPORT_CBPF: // Doesn't do anything in get + case SO_ATTACH_REUSEPORT_EBPF: + case SO_CNX_ADVICE: + // Gap 54 (SCM_TIMESTAMPING_OPT_STATS) + case SO_MEMINFO: + case SO_INCOMING_NAPI_ID: + case SO_COOKIE: // Cookie always returns 64-bit even on 32-bit + // Gap 58 (SCM_TIMESTAMPING_PKTINFO) + case SO_PEERGROUPS: + case SO_ZEROCOPY: + case SO_TXTIME: + case SO_BINDTOIFINDEX: + case SO_TIMESTAMP_NEW: + case SO_TIMESTAMPNS_NEW: + case SO_TIMESTAMPING_NEW: + case SO_RCVTIMEO_NEW: + case SO_SNDTIMEO_NEW: + case SO_DETACH_REUSEPORT_BPF: + case SO_PREFER_BUSY_POLL: + case SO_BUSY_POLL_BUDGET: + case SO_NETNS_COOKIE: // Cookie always returns 64-bit even on 32-bit + case SO_BUF_LOCK: + case SO_RESERVE_MEM: + default: Result = ::syscall(SYSCALL_DEF(getsockopt), sockfd, level, optname, optval, optlen); break; + } + } else { + Result = ::syscall(SYSCALL_DEF(getsockopt), sockfd, level, optname, optval, optlen); } + SYSCALL_ERRNO(); +} - void RegisterSocket(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(socketcall, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t call, uint32_t *Arguments) -> uint64_t { - uint64_t Result{}; +void RegisterSocket(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(socketcall, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t call, uint32_t* Arguments) -> uint64_t { + uint64_t Result {}; - switch (call) { - case OP_SOCKET: { - Result = ::socket(Arguments[0], Arguments[1], Arguments[2]); - break; - } - case OP_BIND: { - Result = ::bind(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; - } - case OP_CONNECT: { - Result = ::connect(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; - } - case OP_LISTEN: { - Result = ::listen(Arguments[0], Arguments[1]); - break; - } - case OP_ACCEPT: { - Result = ::accept(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); - break; - } - case OP_GETSOCKNAME: { - Result = ::getsockname(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); - break; - } - case OP_GETPEERNAME: { - Result = ::getpeername(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); - break; - } - case OP_SOCKETPAIR: { - Result = ::socketpair(Arguments[0], Arguments[1], Arguments[2], reinterpret_cast(Arguments[3])); - break; - } - case OP_SEND: { - Result = ::send(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); - break; - } - case OP_RECV: { - Result = ::recv(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); - break; - } - case OP_SENDTO: { - Result = ::sendto( - Arguments[0], - reinterpret_cast(Arguments[1]), - Arguments[2], - Arguments[3], - reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5]) - ); - break; - } - case OP_RECVFROM: { - Result = ::recvfrom( - Arguments[0], - reinterpret_cast(Arguments[1]), - Arguments[2], - Arguments[3], - reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5]) - ); - break; - } - case OP_SHUTDOWN: { - Result = ::shutdown(Arguments[0], Arguments[1]); - break; - } - case OP_SETSOCKOPT: { - return SetSockOpt( - Arguments[0], - Arguments[1], - Arguments[2], - Arguments[3], - reinterpret_cast(Arguments[4]) - ); - break; - } - case OP_GETSOCKOPT: { - return GetSockOpt( - Arguments[0], - Arguments[1], - Arguments[2], - reinterpret_cast(Arguments[3]), - reinterpret_cast(Arguments[4]) - ); - break; - } - case OP_SENDMSG: { - return SendMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; - } - case OP_RECVMSG: { - return RecvMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; - } - case OP_ACCEPT4: { - return ::accept4(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2]), Arguments[3]); - break; - } - case OP_RECVMMSG: { - timespec32 *timeout_ts = reinterpret_cast(Arguments[4]); - struct timespec tp64{}; - struct timespec *timed_ptr{}; - if (timeout_ts) { - tp64 = *timeout_ts; - timed_ptr = &tp64; - } - - uint64_t Result = RecvMMsg(Arguments[0], Arguments[1], Arguments[2], Arguments[3], timed_ptr); - - if (timeout_ts) { - *timeout_ts = tp64; - } - - return Result; - break; - } - case OP_SENDMMSG: { - return SendMMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); - break; - } - default: - LOGMAN_MSG_A_FMT("Unsupported socketcall op: {}", call); - break; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(sendmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, const struct msghdr32 *msg, int flags) -> uint64_t { - return SendMsg(sockfd, msg, flags); - }); - - REGISTER_SYSCALL_IMPL_X32(sendmmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, compat_ptr msgvec, uint32_t vlen, int flags) -> uint64_t { - return SendMMsg(sockfd, msgvec, vlen, flags); - }); - - REGISTER_SYSCALL_IMPL_X32(recvmmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, compat_ptr msgvec, uint32_t vlen, int flags, timespec32 *timeout_ts) -> uint64_t { - struct timespec tp64{}; - struct timespec *timed_ptr{}; + switch (call) { + case OP_SOCKET: { + Result = ::socket(Arguments[0], Arguments[1], Arguments[2]); + break; + } + case OP_BIND: { + Result = ::bind(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_CONNECT: { + Result = ::connect(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_LISTEN: { + Result = ::listen(Arguments[0], Arguments[1]); + break; + } + case OP_ACCEPT: { + Result = ::accept(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); + break; + } + case OP_GETSOCKNAME: { + Result = ::getsockname(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); + break; + } + case OP_GETPEERNAME: { + Result = ::getpeername(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); + break; + } + case OP_SOCKETPAIR: { + Result = ::socketpair(Arguments[0], Arguments[1], Arguments[2], reinterpret_cast(Arguments[3])); + break; + } + case OP_SEND: { + Result = ::send(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); + break; + } + case OP_RECV: { + Result = ::recv(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); + break; + } + case OP_SENDTO: { + Result = ::sendto(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3], + reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5])); + break; + } + case OP_RECVFROM: { + Result = ::recvfrom(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3], + reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5])); + break; + } + case OP_SHUTDOWN: { + Result = ::shutdown(Arguments[0], Arguments[1]); + break; + } + case OP_SETSOCKOPT: { + return SetSockOpt(Arguments[0], Arguments[1], Arguments[2], Arguments[3], reinterpret_cast(Arguments[4])); + break; + } + case OP_GETSOCKOPT: { + return GetSockOpt(Arguments[0], Arguments[1], Arguments[2], reinterpret_cast(Arguments[3]), + reinterpret_cast(Arguments[4])); + break; + } + case OP_SENDMSG: { + return SendMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_RECVMSG: { + return RecvMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_ACCEPT4: { + return ::accept4(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2]), Arguments[3]); + break; + } + case OP_RECVMMSG: { + timespec32* timeout_ts = reinterpret_cast(Arguments[4]); + struct timespec tp64 {}; + struct timespec* timed_ptr {}; if (timeout_ts) { tp64 = *timeout_ts; timed_ptr = &tp64; } - uint64_t Result = RecvMMsg(sockfd, msgvec, vlen, flags, timed_ptr); + uint64_t Result = RecvMMsg(Arguments[0], Arguments[1], Arguments[2], Arguments[3], timed_ptr); if (timeout_ts) { *timeout_ts = tp64; } return Result; - }); + break; + } + case OP_SENDMMSG: { + return SendMMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); + break; + } + default: LOGMAN_MSG_A_FMT("Unsupported socketcall op: {}", call); break; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(recvmmsg_time64, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, compat_ptr msgvec, uint32_t vlen, int flags, struct timespec *timeout_ts) -> uint64_t { - return RecvMMsg(sockfd, msgvec, vlen, flags, timeout_ts); - }); + REGISTER_SYSCALL_IMPL_X32(sendmsg, [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, const struct msghdr32* msg, int flags) -> uint64_t { + return SendMsg(sockfd, msg, flags); + }); - REGISTER_SYSCALL_IMPL_X32(recvmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct msghdr32 *msg, int flags) -> uint64_t { - return RecvMsg(sockfd, msg, flags); - }); + REGISTER_SYSCALL_IMPL_X32(sendmmsg, + [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, compat_ptr msgvec, uint32_t vlen, + int flags) -> uint64_t { return SendMMsg(sockfd, msgvec, vlen, flags); }); - REGISTER_SYSCALL_IMPL_X32(setsockopt, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, int level, int optname, compat_ptr optval, socklen_t optlen) -> uint64_t { - return SetSockOpt(sockfd, level, optname, optval, optlen); - }); + REGISTER_SYSCALL_IMPL_X32(recvmmsg, + [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, compat_ptr msgvec, uint32_t vlen, int flags, + timespec32* timeout_ts) -> uint64_t { + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout_ts) { + tp64 = *timeout_ts; + timed_ptr = &tp64; + } - REGISTER_SYSCALL_IMPL_X32(getsockopt, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, int level, int optname, compat_ptr optval, compat_ptr optlen) -> uint64_t { - return GetSockOpt(sockfd, level, optname, optval, optlen); - }); - } + uint64_t Result = RecvMMsg(sockfd, msgvec, vlen, flags, timed_ptr); + + if (timeout_ts) { + *timeout_ts = tp64; + } + + return Result; + }); + + REGISTER_SYSCALL_IMPL_X32(recvmmsg_time64, + [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, compat_ptr msgvec, uint32_t vlen, int flags, + struct timespec* timeout_ts) -> uint64_t { return RecvMMsg(sockfd, msgvec, vlen, flags, timeout_ts); }); + + REGISTER_SYSCALL_IMPL_X32(recvmsg, [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, struct msghdr32* msg, int flags) -> uint64_t { + return RecvMsg(sockfd, msg, flags); + }); + + REGISTER_SYSCALL_IMPL_X32(setsockopt, + [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, int level, int optname, compat_ptr optval, + socklen_t optlen) -> uint64_t { return SetSockOpt(sockfd, level, optname, optval, optlen); }); + + REGISTER_SYSCALL_IMPL_X32(getsockopt, + [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, int level, int optname, compat_ptr optval, + compat_ptr optlen) -> uint64_t { return GetSockOpt(sockfd, level, optname, optval, optlen); }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp index f276211db..a07274b21 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp @@ -14,24 +14,22 @@ $end_info$ #include #include -#define SYSCALL_STUB(name) do { ERROR_AND_DIE_FMT("Syscall: " #name " stub!"); return -ENOSYS; } while(0) +#define SYSCALL_STUB(name) \ + do { \ + ERROR_AND_DIE_FMT("Syscall: " #name " stub!"); \ + return -ENOSYS; \ + } while (0) namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { - void RegisterStubs(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(readdir, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - SYSCALL_STUB(readdir); - }); +void RegisterStubs(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(readdir, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { SYSCALL_STUB(readdir); }); - REGISTER_SYSCALL_IMPL_X32(vm86old, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - return -ENOSYS; - }); + REGISTER_SYSCALL_IMPL_X32(vm86old, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -ENOSYS; }); - REGISTER_SYSCALL_IMPL_X32(vm86, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - return -ENOSYS; - }); - } + REGISTER_SYSCALL_IMPL_X32(vm86, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -ENOSYS; }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.cpp index 5f6eaa1a4..2f9da3a77 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.cpp @@ -24,89 +24,92 @@ $end_info$ #include namespace FEX::HLE::x32 { - void RegisterEpoll(FEX::HLE::SyscallHandler *Handler); - void RegisterFD(FEX::HLE::SyscallHandler *Handler); - void RegisterFS(FEX::HLE::SyscallHandler *Handler); - void RegisterInfo(FEX::HLE::SyscallHandler *Handler); - void RegisterIO(FEX::HLE::SyscallHandler *Handler); - void RegisterMemory(FEX::HLE::SyscallHandler *Handler); - void RegisterMsg(FEX::HLE::SyscallHandler *Handler); - void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler); - void RegisterSched(FEX::HLE::SyscallHandler *Handler); - void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler); - void RegisterSignals(FEX::HLE::SyscallHandler *Handler); - void RegisterSocket(FEX::HLE::SyscallHandler *Handler); - void RegisterStubs(FEX::HLE::SyscallHandler *Handler); - void RegisterThread(FEX::HLE::SyscallHandler *Handler); - void RegisterTime(FEX::HLE::SyscallHandler *Handler); - void RegisterTimer(FEX::HLE::SyscallHandler *Handler); - void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler); +void RegisterEpoll(FEX::HLE::SyscallHandler* Handler); +void RegisterFD(FEX::HLE::SyscallHandler* Handler); +void RegisterFS(FEX::HLE::SyscallHandler* Handler); +void RegisterInfo(FEX::HLE::SyscallHandler* Handler); +void RegisterIO(FEX::HLE::SyscallHandler* Handler); +void RegisterMemory(FEX::HLE::SyscallHandler* Handler); +void RegisterMsg(FEX::HLE::SyscallHandler* Handler); +void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler); +void RegisterSched(FEX::HLE::SyscallHandler* Handler); +void RegisterSemaphore(FEX::HLE::SyscallHandler* Handler); +void RegisterSignals(FEX::HLE::SyscallHandler* Handler); +void RegisterSocket(FEX::HLE::SyscallHandler* Handler); +void RegisterStubs(FEX::HLE::SyscallHandler* Handler); +void RegisterThread(FEX::HLE::SyscallHandler* Handler); +void RegisterTime(FEX::HLE::SyscallHandler* Handler); +void RegisterTimer(FEX::HLE::SyscallHandler* Handler); +void RegisterPassthrough(FEX::HLE::SyscallHandler* Handler); - x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr Allocator) - : SyscallHandler{ctx, _SignalDelegation}, AllocHandler{std::move(Allocator)} { - OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX32; - RegisterSyscallHandlers(); - } +x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, + fextl::unique_ptr Allocator) + : SyscallHandler {ctx, _SignalDelegation} + , AllocHandler {std::move(Allocator)} { + OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX32; + RegisterSyscallHandlers(); +} - void x32SyscallHandler::RegisterSyscallHandlers() { - auto cvt = [](auto in) { - union { - decltype(in) val; - void *raw; - } raw; - raw.val = in; - return raw.raw; - }; +void x32SyscallHandler::RegisterSyscallHandlers() { + auto cvt = [](auto in) { + union { + decltype(in) val; + void* raw; + } raw; + raw.val = in; + return raw.raw; + }; - Definitions.resize(FEX::HLE::x32::SYSCALL_x86_MAX, SyscallFunctionDefinition { - .NumArgs = 255, - .Ptr = cvt(&UnimplementedSyscall), - }); + Definitions.resize(FEX::HLE::x32::SYSCALL_x86_MAX, SyscallFunctionDefinition { + .NumArgs = 255, + .Ptr = cvt(&UnimplementedSyscall), + }); - FEX::HLE::RegisterEpoll(this); - FEX::HLE::RegisterFD(this); - FEX::HLE::RegisterFS(this); - FEX::HLE::RegisterInfo(this); - FEX::HLE::RegisterIO(this); - FEX::HLE::RegisterMemory(this); - FEX::HLE::RegisterSignals(this); - FEX::HLE::RegisterThread(this); - FEX::HLE::RegisterTimer(this); - FEX::HLE::RegisterNotImplemented(this); - FEX::HLE::RegisterStubs(this); + FEX::HLE::RegisterEpoll(this); + FEX::HLE::RegisterFD(this); + FEX::HLE::RegisterFS(this); + FEX::HLE::RegisterInfo(this); + FEX::HLE::RegisterIO(this); + FEX::HLE::RegisterMemory(this); + FEX::HLE::RegisterSignals(this); + FEX::HLE::RegisterThread(this); + FEX::HLE::RegisterTimer(this); + FEX::HLE::RegisterNotImplemented(this); + FEX::HLE::RegisterStubs(this); - // 32bit specific - FEX::HLE::x32::RegisterEpoll(this); - FEX::HLE::x32::RegisterFD(this); - FEX::HLE::x32::RegisterFS(this); - FEX::HLE::x32::RegisterInfo(this); - FEX::HLE::x32::RegisterIO(this); - FEX::HLE::x32::RegisterMemory(this); - FEX::HLE::x32::RegisterMsg(this); - FEX::HLE::x32::RegisterNotImplemented(this); - FEX::HLE::x32::RegisterSched(this); - FEX::HLE::x32::RegisterSemaphore(this); - FEX::HLE::x32::RegisterSignals(this); - FEX::HLE::x32::RegisterSocket(this); - FEX::HLE::x32::RegisterStubs(this); - FEX::HLE::x32::RegisterThread(this); - FEX::HLE::x32::RegisterTime(this); - FEX::HLE::x32::RegisterTimer(this); - FEX::HLE::x32::RegisterPassthrough(this); + // 32bit specific + FEX::HLE::x32::RegisterEpoll(this); + FEX::HLE::x32::RegisterFD(this); + FEX::HLE::x32::RegisterFS(this); + FEX::HLE::x32::RegisterInfo(this); + FEX::HLE::x32::RegisterIO(this); + FEX::HLE::x32::RegisterMemory(this); + FEX::HLE::x32::RegisterMsg(this); + FEX::HLE::x32::RegisterNotImplemented(this); + FEX::HLE::x32::RegisterSched(this); + FEX::HLE::x32::RegisterSemaphore(this); + FEX::HLE::x32::RegisterSignals(this); + FEX::HLE::x32::RegisterSocket(this); + FEX::HLE::x32::RegisterStubs(this); + FEX::HLE::x32::RegisterThread(this); + FEX::HLE::x32::RegisterTime(this); + FEX::HLE::x32::RegisterTimer(this); + FEX::HLE::x32::RegisterPassthrough(this); - FEX::HLE::x32::InitializeStaticIoctlHandlers(); + FEX::HLE::x32::InitializeStaticIoctlHandlers(); #if PRINT_MISSING_SYSCALLS - for (auto &Syscall: SyscallNames) { - if (Definitions[Syscall.first].Ptr == cvt(&UnimplementedSyscall)) { - LogMan::Msg::DFmt("Unimplemented syscall: {}: {}", Syscall.first, Syscall.second); - } + for (auto& Syscall : SyscallNames) { + if (Definitions[Syscall.first].Ptr == cvt(&UnimplementedSyscall)) { + LogMan::Msg::DFmt("Unimplemented syscall: {}: {}", Syscall.first, Syscall.second); } + } #endif - } - - fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr Allocator) { - return fextl::make_unique(ctx, _SignalDelegation, std::move(Allocator)); - } - } + +fextl::unique_ptr +CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, fextl::unique_ptr Allocator) { + return fextl::make_unique(ctx, _SignalDelegation, std::move(Allocator)); +} + +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.h index 334417272..e83d11244 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Syscalls.h @@ -18,13 +18,13 @@ $end_info$ #include namespace FEXCore { - namespace Context { - class Context; - } - namespace Core { - struct CpuStateFrame; - } +namespace Context { + class Context; } +namespace Core { + struct CpuStateFrame; +} +} // namespace FEXCore namespace FEX::HLE { class SignalDelegator; @@ -35,25 +35,25 @@ namespace FEX::HLE::x32 { class x32SyscallHandler final : public FEX::HLE::SyscallHandler { public: - x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr Allocator); + x32SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, fextl::unique_ptr Allocator); - FEX::HLE::MemAllocator *GetAllocator() { return AllocHandler.get(); } - void *GuestMmap(FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset) override; - int GuestMunmap(FEXCore::Core::InternalThreadState *Thread, void *addr, uint64_t length) override; + FEX::HLE::MemAllocator* GetAllocator() { + return AllocHandler.get(); + } + void* GuestMmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length, int prot, int flags, int fd, off_t offset) override; + int GuestMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, uint64_t length) override; - void RegisterSyscall_32(int SyscallNumber, - int32_t HostSyscallNumber, - FEXCore::IR::SyscallFlags Flags, + void RegisterSyscall_32(int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, #ifdef DEBUG_STRACE - const fextl::string& TraceFormatString, + const fextl::string& TraceFormatString, #endif - void* SyscallHandler, int ArgumentCount) override { - auto &Def = Definitions.at(SyscallNumber); + void* SyscallHandler, int ArgumentCount) override { + auto& Def = Definitions.at(SyscallNumber); #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED auto cvt = [](auto in) { union { decltype(in) val; - void *raw; + void* raw; } raw; raw.val = in; return raw.raw; @@ -71,12 +71,11 @@ public: private: void RegisterSyscallHandlers(); - fextl::unique_ptr AllocHandler{}; + fextl::unique_ptr AllocHandler {}; }; -fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, - FEX::HLE::SignalDelegator *_SignalDelegation, - fextl::unique_ptr Allocator); +fextl::unique_ptr +CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, fextl::unique_ptr Allocator); ////// // REGISTER_SYSCALL_IMPL implementation // Given a syscall name + a lambda, and it will generate an strace string, extract number of arguments @@ -86,33 +85,31 @@ fextl::unique_ptr CreateHandler(FEXCore::Context::Cont // RegisterSyscall base // Deduces return, args... from the function passed // Does not work with lambas, because they are objects with operator (), not functions -template -void RegisterSyscall(SyscallHandler *Handler, int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, const char *Name, R(*fn)(FEXCore::Core::CpuStateFrame *Frame, Args...)) { +template +void RegisterSyscall(SyscallHandler* Handler, int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, + const char* Name, R (*fn)(FEXCore::Core::CpuStateFrame* Frame, Args...)) { #ifdef DEBUG_STRACE auto TraceFormatString = fextl::string(Name) + "(" + CollectArgsFmtString() + ") = %ld"; #endif - Handler->RegisterSyscall_32(SyscallNumber, - HostSyscallNumber, - Flags, + Handler->RegisterSyscall_32(SyscallNumber, HostSyscallNumber, Flags, #ifdef DEBUG_STRACE - TraceFormatString, + TraceFormatString, #endif - reinterpret_cast(fn), sizeof...(Args)); + reinterpret_cast(fn), sizeof...(Args)); } // Generic RegisterSyscall for lambdas // Non-capturing lambdas can be cast to function pointers, but this does not happen on argument matching // This is some glue logic that will cast a lambda and call the base RegisterSyscall implementation template -void RegisterSyscall(SyscallHandler *_Handler, int num, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, const char *name, F f){ +void RegisterSyscall(SyscallHandler* _Handler, int num, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, const char* name, F f) { RegisterSyscall(_Handler, num, HostSyscallNumber, Flags, name, +f); } -} +} // namespace FEX::HLE::x32 // Registers syscall for 32bit only -#define REGISTER_SYSCALL_IMPL_X32(name, lambda) \ - REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, ~0, FEXCore::IR::SyscallFlags::DEFAULT, lambda) +#define REGISTER_SYSCALL_IMPL_X32(name, lambda) REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, ~0, FEXCore::IR::SyscallFlags::DEFAULT, lambda) #define REGISTER_SYSCALL_IMPL_X32_PASS(name, lambda) \ REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, SYSCALL_DEF(name), FEXCore::IR::SyscallFlags::DEFAULT, lambda) @@ -120,11 +117,9 @@ void RegisterSyscall(SyscallHandler *_Handler, int num, int32_t HostSyscallNumbe #define REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(name, hostname, lambda) \ REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, SYSCALL_DEF(hostname), FEXCore::IR::SyscallFlags::DEFAULT, lambda) -#define REGISTER_SYSCALL_IMPL_X32_FLAGS(name, flags, lambda) \ - REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, ~0, flags, lambda) +#define REGISTER_SYSCALL_IMPL_X32_FLAGS(name, flags, lambda) REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, ~0, flags, lambda) -#define REGISTER_SYSCALL_IMPL_X32_PASS_FLAGS(name, flags, lambda) \ - REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, SYSCALL_DEF(name), flags, lambda) +#define REGISTER_SYSCALL_IMPL_X32_PASS_FLAGS(name, flags, lambda) REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, SYSCALL_DEF(name), flags, lambda) #define REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(name, hostname, flags, lambda) \ REGISTER_SYSCALL_IMPL_X32_INTERNAL(name, SYSCALL_DEF(hostname), flags, lambda) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h index ed7d9a1f7..e252b73ae 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h @@ -480,4 +480,3 @@ enum Syscalls_x86 { SYSCALL_x86_lsm_list_modules = 461, SYSCALL_x86_MAX = 512, }; - diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp index e41fbbe0d..4d6a481dc 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp @@ -35,152 +35,150 @@ ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%x") ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%x") namespace FEX::HLE::x32 { - // The kernel only gives 32-bit userspace 3 TLS segments - // Depending on if the host kernel is 32-bit or 64-bit then the TLS index assigned is different - // - // Host kernel x86_64, valid TLS enries: 12,13,14 - // Host kernel x86, valid TLS enries: 6,7,8 - // Since we are claiming to be a 64-bit kernel, use the 64-bit range - // - // 6/12 = glibc - // 7/13 = wine fs - // 8/14 = etc - constexpr uint32_t TLS_NextEntry = 12; - constexpr uint32_t TLS_MaxEntry = TLS_NextEntry+3; +// The kernel only gives 32-bit userspace 3 TLS segments +// Depending on if the host kernel is 32-bit or 64-bit then the TLS index assigned is different +// +// Host kernel x86_64, valid TLS enries: 12,13,14 +// Host kernel x86, valid TLS enries: 6,7,8 +// Since we are claiming to be a 64-bit kernel, use the 64-bit range +// +// 6/12 = glibc +// 7/13 = wine fs +// 8/14 = etc +constexpr uint32_t TLS_NextEntry = 12; +constexpr uint32_t TLS_MaxEntry = TLS_NextEntry + 3; + +uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame* Frame, void* tls) { + struct x32::user_desc* u_info = reinterpret_cast(tls); + if (u_info->entry_number == -1) { + for (uint32_t i = TLS_NextEntry; i < TLS_MaxEntry; ++i) { + auto GDT = &Frame->State.gdt[i]; + if (GDT->base == 0) { + // If the base is zero then it isn't present with our setup + u_info->entry_number = i; + break; + } + } - uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame *Frame, void *tls) { - struct x32::user_desc* u_info = reinterpret_cast(tls); if (u_info->entry_number == -1) { - for (uint32_t i = TLS_NextEntry; i < TLS_MaxEntry; ++i) { - auto GDT = &Frame->State.gdt[i]; - if (GDT->base == 0) { - // If the base is zero then it isn't present with our setup - u_info->entry_number = i; - break; - } - } - - if (u_info->entry_number == -1) { - // Couldn't find a slot. Return empty handed - return -ESRCH; - } + // Couldn't find a slot. Return empty handed + return -ESRCH; } - - // Now we need to update the thread's GDT to handle this change - auto GDT = &Frame->State.gdt[u_info->entry_number]; - GDT->base = u_info->base_addr; - - // With the segment register optimization we need to check all of the segment registers and update. - const auto GetEntry = [](auto value) { - return value >> 3; - }; - if (GetEntry(Frame->State.cs_idx) == u_info->entry_number) { - Frame->State.cs_cached = GDT->base; - } - if (GetEntry(Frame->State.ds_idx) == u_info->entry_number) { - Frame->State.ds_cached = GDT->base; - } - if (GetEntry(Frame->State.es_idx) == u_info->entry_number) { - Frame->State.es_cached = GDT->base; - } - if (GetEntry(Frame->State.fs_idx) == u_info->entry_number) { - Frame->State.fs_cached = GDT->base; - } - if (GetEntry(Frame->State.gs_idx) == u_info->entry_number) { - Frame->State.gs_cached = GDT->base; - } - if (GetEntry(Frame->State.ss_idx) == u_info->entry_number) { - Frame->State.ss_cached = GDT->base; - } - return 0; } - void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame *Frame) { - Frame->State.rip += 2; + // Now we need to update the thread's GDT to handle this change + auto GDT = &Frame->State.gdt[u_info->entry_number]; + GDT->base = u_info->base_addr; + + // With the segment register optimization we need to check all of the segment registers and update. + const auto GetEntry = [](auto value) { + return value >> 3; + }; + if (GetEntry(Frame->State.cs_idx) == u_info->entry_number) { + Frame->State.cs_cached = GDT->base; } + if (GetEntry(Frame->State.ds_idx) == u_info->entry_number) { + Frame->State.ds_cached = GDT->base; + } + if (GetEntry(Frame->State.es_idx) == u_info->entry_number) { + Frame->State.es_cached = GDT->base; + } + if (GetEntry(Frame->State.fs_idx) == u_info->entry_number) { + Frame->State.fs_cached = GDT->base; + } + if (GetEntry(Frame->State.gs_idx) == u_info->entry_number) { + Frame->State.gs_cached = GDT->base; + } + if (GetEntry(Frame->State.ss_idx) == u_info->entry_number) { + Frame->State.ss_cached = GDT->base; + } + return 0; +} - void RegisterThread(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(sigreturn, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { - FEX::HLE::_SyscallHandler->GetSignalDelegator()->HandleSignalHandlerReturn(false); - FEX_UNREACHABLE; - }); +void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame* Frame) { + Frame->State.rip += 2; +} - REGISTER_SYSCALL_IMPL_X32(clone, ([](FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, void *tls, pid_t *child_tid) -> uint64_t { - FEX::HLE::clone3_args args { - .Type = TypeOfClone::TYPE_CLONE2, - .args = { - .flags = flags & ~CSIGNAL, // This no longer contains CSIGNAL - .pidfd = reinterpret_cast(parent_tid), // For clone, pidfd is duplicated here - .child_tid = reinterpret_cast(child_tid), - .parent_tid = reinterpret_cast(parent_tid), - .exit_signal = flags & CSIGNAL, - .stack = reinterpret_cast(stack), - .stack_size = 0, // This syscall isn't able to see the stack size - .tls = reinterpret_cast(tls), - .set_tid = 0, // This syscall isn't able to select TIDs - .set_tid_size = 0, - .cgroup = 0, // This syscall can't select cgroups - } - }; +void RegisterThread(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(sigreturn, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + FEX::HLE::_SyscallHandler->GetSignalDelegator()->HandleSignalHandlerReturn(false); + FEX_UNREACHABLE; + }); + + REGISTER_SYSCALL_IMPL_X32( + clone, ([](FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack, pid_t* parent_tid, void* tls, pid_t* child_tid) -> uint64_t { + FEX::HLE::clone3_args args {.Type = TypeOfClone::TYPE_CLONE2, + .args = { + .flags = flags & ~CSIGNAL, // This no longer contains CSIGNAL + .pidfd = reinterpret_cast(parent_tid), // For clone, pidfd is duplicated here + .child_tid = reinterpret_cast(child_tid), + .parent_tid = reinterpret_cast(parent_tid), + .exit_signal = flags & CSIGNAL, + .stack = reinterpret_cast(stack), + .stack_size = 0, // This syscall isn't able to see the stack size + .tls = reinterpret_cast(tls), + .set_tid = 0, // This syscall isn't able to select TIDs + .set_tid_size = 0, + .cgroup = 0, // This syscall can't select cgroups + }}; return CloneHandler(Frame, &args); })); - REGISTER_SYSCALL_IMPL_X32(waitpid, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int32_t *status, int32_t options) -> uint64_t { - uint64_t Result = ::waitpid(pid, status, options); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(waitpid, [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, int32_t* status, int32_t options) -> uint64_t { + uint64_t Result = ::waitpid(pid, status, options); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(nice, [](FEXCore::Core::CpuStateFrame *Frame, int inc) -> uint64_t { - uint64_t Result = ::nice(inc); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(nice, [](FEXCore::Core::CpuStateFrame* Frame, int inc) -> uint64_t { + uint64_t Result = ::nice(inc); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(set_thread_area, [](FEXCore::Core::CpuStateFrame *Frame, struct user_desc *u_info) -> uint64_t { - return SetThreadArea(Frame, u_info); - }); + REGISTER_SYSCALL_IMPL_X32( + set_thread_area, [](FEXCore::Core::CpuStateFrame* Frame, struct user_desc* u_info) -> uint64_t { return SetThreadArea(Frame, u_info); }); - REGISTER_SYSCALL_IMPL_X32(get_thread_area, [](FEXCore::Core::CpuStateFrame *Frame, struct user_desc *u_info) -> uint64_t { - // Index to fetch comes from the user_desc - uint32_t Entry = u_info->entry_number; - if (Entry < TLS_NextEntry || Entry > TLS_MaxEntry) { - return -EINVAL; - } + REGISTER_SYSCALL_IMPL_X32(get_thread_area, [](FEXCore::Core::CpuStateFrame* Frame, struct user_desc* u_info) -> uint64_t { + // Index to fetch comes from the user_desc + uint32_t Entry = u_info->entry_number; + if (Entry < TLS_NextEntry || Entry > TLS_MaxEntry) { + return -EINVAL; + } - const auto &GDT = &Frame->State.gdt[Entry]; + const auto& GDT = &Frame->State.gdt[Entry]; - memset(u_info, 0, sizeof(*u_info)); + memset(u_info, 0, sizeof(*u_info)); - // FEX only stores base instead of the full GDT - u_info->base_addr = GDT->base; + // FEX only stores base instead of the full GDT + u_info->base_addr = GDT->base; - // Fill the rest of the structure with expected data (even if wrong at the moment) - if (u_info->base_addr) { - u_info->limit = 0xF'FFFF; - u_info->seg_32bit = 1; - u_info->limit_in_pages = 1; - u_info->useable = 1; - } - else { - u_info->read_exec_only = 1; - u_info->seg_not_present = 1; - } - return 0; - }); + // Fill the rest of the structure with expected data (even if wrong at the moment) + if (u_info->base_addr) { + u_info->limit = 0xF'FFFF; + u_info->seg_32bit = 1; + u_info->limit_in_pages = 1; + u_info->useable = 1; + } else { + u_info->read_exec_only = 1; + u_info->seg_not_present = 1; + } + return 0; + }); - REGISTER_SYSCALL_IMPL_X32(set_robust_list, [](FEXCore::Core::CpuStateFrame *Frame, struct robust_list_head *head, size_t len) -> uint64_t { - if (len != 12) { - // Return invalid if the passed in length doesn't match what's expected. - return -EINVAL; - } + REGISTER_SYSCALL_IMPL_X32(set_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, struct robust_list_head* head, size_t len) -> uint64_t { + if (len != 12) { + // Return invalid if the passed in length doesn't match what's expected. + return -EINVAL; + } - auto Thread = Frame->Thread; - // Retain the robust list head but don't give it to the kernel - // The kernel would break if it tried parsing a 32bit robust list from a 64bit process - Thread->ThreadManager.robust_list_head = reinterpret_cast(head); - return 0; - }); + auto Thread = Frame->Thread; + // Retain the robust list head but don't give it to the kernel + // The kernel would break if it tried parsing a 32bit robust list from a 64bit process + Thread->ThreadManager.robust_list_head = reinterpret_cast(head); + return 0; + }); - REGISTER_SYSCALL_IMPL_X32(get_robust_list, [](FEXCore::Core::CpuStateFrame *Frame, int pid, struct robust_list_head **head, uint32_t *len_ptr) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + get_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, int pid, struct robust_list_head** head, uint32_t* len_ptr) -> uint64_t { auto Thread = Frame->Thread; // Give the robust list back to the application // Steam specifically checks to make sure the robust list is set @@ -189,37 +187,29 @@ namespace FEX::HLE::x32 { return 0; }); - REGISTER_SYSCALL_IMPL_X32(futex, [](FEXCore::Core::CpuStateFrame *Frame, int *uaddr, int futex_op, int val, const timespec32 *timeout, int *uaddr2, uint32_t val3) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + futex, [](FEXCore::Core::CpuStateFrame* Frame, int* uaddr, int futex_op, int val, const timespec32* timeout, int* uaddr2, uint32_t val3) -> uint64_t { void* timeout_ptr = (void*)timeout; - struct timespec tp64{}; + struct timespec tp64 {}; int cmd = futex_op & FUTEX_CMD_MASK; - if (timeout && - (cmd == FUTEX_WAIT || - cmd == FUTEX_LOCK_PI || - cmd == FUTEX_WAIT_BITSET || - cmd == FUTEX_WAIT_REQUEUE_PI)) { + if (timeout && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || cmd == FUTEX_WAIT_BITSET || cmd == FUTEX_WAIT_REQUEUE_PI)) { // timeout argument is only handled as timespec in these cases // Otherwise just an integer tp64 = *timeout; timeout_ptr = &tp64; } - uint64_t Result = syscall(SYSCALL_DEF(futex), - uaddr, - futex_op, - val, - timeout_ptr, - uaddr2, - val3); + uint64_t Result = syscall(SYSCALL_DEF(futex), uaddr, futex_op, val, timeout_ptr, uaddr2, val3); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(sigaltstack, [](FEXCore::Core::CpuStateFrame *Frame, const compat_ptr ss, compat_ptr old_ss) -> uint64_t { - stack_t ss64{}; - stack_t old64{}; + REGISTER_SYSCALL_IMPL_X32( + sigaltstack, [](FEXCore::Core::CpuStateFrame* Frame, const compat_ptr ss, compat_ptr old_ss) -> uint64_t { + stack_t ss64 {}; + stack_t old64 {}; - stack_t *ss64_ptr{}; - stack_t *old64_ptr{}; + stack_t* ss64_ptr {}; + stack_t* old64_ptr {}; if (ss) { ss64 = *ss; @@ -238,36 +228,37 @@ namespace FEX::HLE::x32 { return Result; }); - // launch a new process under fex - // currently does not propagate argv[0] correctly - REGISTER_SYSCALL_IMPL_X32(execve, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uint32_t *argv, uint32_t *envp) -> uint64_t { - fextl::vector Args; - fextl::vector Envp; + // launch a new process under fex + // currently does not propagate argv[0] correctly + REGISTER_SYSCALL_IMPL_X32(execve, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uint32_t* argv, uint32_t* envp) -> uint64_t { + fextl::vector Args; + fextl::vector Envp; - if (argv) { - for (int i = 0; argv[i]; i++) { - Args.push_back(reinterpret_cast(static_cast(argv[i]))); - } - - Args.push_back(nullptr); + if (argv) { + for (int i = 0; argv[i]; i++) { + Args.push_back(reinterpret_cast(static_cast(argv[i]))); } - if (envp) { - for (int i = 0; envp[i]; i++) { - Envp.push_back(reinterpret_cast(static_cast(envp[i]))); - } - Envp.push_back(nullptr); + Args.push_back(nullptr); + } + + if (envp) { + for (int i = 0; envp[i]; i++) { + Envp.push_back(reinterpret_cast(static_cast(envp[i]))); } + Envp.push_back(nullptr); + } - auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; - auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; + auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; + auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; - FEX::HLE::ExecveAtArgs AtArgs = FEX::HLE::ExecveAtArgs::Empty(); + FEX::HLE::ExecveAtArgs AtArgs = FEX::HLE::ExecveAtArgs::Empty(); - return FEX::HLE::ExecveHandler(pathname, ArgsPtr, EnvpPtr, AtArgs); - }); + return FEX::HLE::ExecveHandler(pathname, ArgsPtr, EnvpPtr, AtArgs); + }); - REGISTER_SYSCALL_IMPL_X32(execveat, ([](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, uint32_t *argv, uint32_t *envp, int flags) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + execveat, ([](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, uint32_t* argv, uint32_t* envp, int flags) -> uint64_t { fextl::vector Args; fextl::vector Envp; @@ -296,50 +287,52 @@ namespace FEX::HLE::x32 { return FEX::HLE::ExecveHandler(pathname, ArgsPtr, EnvpPtr, AtArgs); })); - REGISTER_SYSCALL_IMPL_X32(wait4, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int *wstatus, int options, struct rusage_32 *rusage) -> uint64_t { - struct rusage usage64{}; - struct rusage *usage64_p{}; + REGISTER_SYSCALL_IMPL_X32(wait4, [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, int* wstatus, int options, struct rusage_32* rusage) -> uint64_t { + struct rusage usage64 {}; + struct rusage* usage64_p {}; - if (rusage) { - usage64 = *rusage; - usage64_p = &usage64; - } - uint64_t Result = ::wait4(pid, wstatus, options, usage64_p); - if (rusage) { - *rusage = usage64; - } - SYSCALL_ERRNO(); - }); + if (rusage) { + usage64 = *rusage; + usage64_p = &usage64; + } + uint64_t Result = ::wait4(pid, wstatus, options, usage64_p); + if (rusage) { + *rusage = usage64; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(waitid, [](FEXCore::Core::CpuStateFrame *Frame, int which, pid_t upid, compat_ptr info, int options, struct rusage_32 *rusage) -> uint64_t { - struct rusage usage64{}; - struct rusage *usage64_p{}; + REGISTER_SYSCALL_IMPL_X32(waitid, + [](FEXCore::Core::CpuStateFrame* Frame, int which, pid_t upid, compat_ptr info, + int options, struct rusage_32* rusage) -> uint64_t { + struct rusage usage64 {}; + struct rusage* usage64_p {}; - siginfo_t info64{}; - siginfo_t *info64_p{}; + siginfo_t info64 {}; + siginfo_t* info64_p {}; - if (rusage) { - usage64 = *rusage; - usage64_p = &usage64; - } + if (rusage) { + usage64 = *rusage; + usage64_p = &usage64; + } - if (info) { - info64_p = &info64; - } + if (info) { + info64_p = &info64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(waitid), which, upid, info64_p, options, usage64_p); + uint64_t Result = ::syscall(SYSCALL_DEF(waitid), which, upid, info64_p, options, usage64_p); - if (Result != -1) { - if (rusage) { - *rusage = usage64; - } + if (Result != -1) { + if (rusage) { + *rusage = usage64; + } - if (info) { - *info = info64; - } - } + if (info) { + *info = info64; + } + } - SYSCALL_ERRNO(); - }); - } + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.h index 302aa405c..51d4d384f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.h @@ -13,19 +13,19 @@ struct CpuStateFrame; } namespace FEX::HLE::x32 { - // We must define this ourselves since it doesn't exist on non-x86 platforms - struct user_desc { - uint32_t entry_number; - uint32_t base_addr; - uint32_t limit; - uint32_t seg_32bit : 1; - uint32_t contents : 2; - uint32_t read_exec_only : 1; - uint32_t limit_in_pages : 1; - uint32_t seg_not_present : 1; - uint32_t useable : 1; - }; +// We must define this ourselves since it doesn't exist on non-x86 platforms +struct user_desc { + uint32_t entry_number; + uint32_t base_addr; + uint32_t limit; + uint32_t seg_32bit : 1; + uint32_t contents : 2; + uint32_t read_exec_only : 1; + uint32_t limit_in_pages : 1; + uint32_t seg_not_present : 1; + uint32_t useable : 1; +}; - uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame *Frame, void *tls); - void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame *Frame); -} +uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame* Frame, void* tls); +void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame* Frame); +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp index aac498308..607128f73 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp @@ -25,118 +25,119 @@ ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") struct timespec; namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x32 { - void RegisterTime(FEX::HLE::SyscallHandler *Handler) { +void RegisterTime(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(time, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::x32::old_time32_t *tloc) -> uint64_t { - time_t Host{}; - uint64_t Result = ::time(&Host); + REGISTER_SYSCALL_IMPL_X32(time, [](FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::x32::old_time32_t* tloc) -> uint64_t { + time_t Host {}; + uint64_t Result = ::time(&Host); - if (tloc) { - // On 32-bit this truncates - *tloc = (FEX::HLE::x32::old_time32_t)Host; - } + if (tloc) { + // On 32-bit this truncates + *tloc = (FEX::HLE::x32::old_time32_t)Host; + } - SYSCALL_ERRNO(); - }); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(times, [](FEXCore::Core::CpuStateFrame *Frame, struct FEX::HLE::x32::compat_tms *buf) -> uint64_t { - struct tms Host{}; - uint64_t Result = ::times(&Host); - if (buf) { - *buf = Host; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(times, [](FEXCore::Core::CpuStateFrame* Frame, struct FEX::HLE::x32::compat_tms* buf) -> uint64_t { + struct tms Host {}; + uint64_t Result = ::times(&Host); + if (buf) { + *buf = Host; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(utime, [](FEXCore::Core::CpuStateFrame *Frame, char* filename, const FEX::HLE::x32::old_utimbuf32* times) -> uint64_t { - struct utimbuf Host{}; - struct utimbuf *Host_p{}; - if (times) { - Host = *times; - Host_p = &Host; - } - uint64_t Result = ::utime(filename, Host_p); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(utime, [](FEXCore::Core::CpuStateFrame* Frame, char* filename, const FEX::HLE::x32::old_utimbuf32* times) -> uint64_t { + struct utimbuf Host {}; + struct utimbuf* Host_p {}; + if (times) { + Host = *times; + Host_p = &Host; + } + uint64_t Result = ::utime(filename, Host_p); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(gettimeofday, [](FEXCore::Core::CpuStateFrame *Frame, timeval32 *tv, struct timezone *tz) -> uint64_t { - struct timeval tv64{}; - struct timeval *tv_ptr{}; - if (tv) { - tv_ptr = &tv64; - } + REGISTER_SYSCALL_IMPL_X32(gettimeofday, [](FEXCore::Core::CpuStateFrame* Frame, timeval32* tv, struct timezone* tz) -> uint64_t { + struct timeval tv64 {}; + struct timeval* tv_ptr {}; + if (tv) { + tv_ptr = &tv64; + } - uint64_t Result = ::gettimeofday(tv_ptr, tz); + uint64_t Result = ::gettimeofday(tv_ptr, tz); - if (tv) { - *tv = tv64; - } - SYSCALL_ERRNO(); - }); + if (tv) { + *tv = tv64; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(settimeofday, [](FEXCore::Core::CpuStateFrame *Frame, const timeval32 *tv, const struct timezone *tz) -> uint64_t { - struct timeval tv64{}; - struct timeval *tv_ptr{}; - if (tv) { - tv64 = *tv; - tv_ptr = &tv64; - } + REGISTER_SYSCALL_IMPL_X32(settimeofday, [](FEXCore::Core::CpuStateFrame* Frame, const timeval32* tv, const struct timezone* tz) -> uint64_t { + struct timeval tv64 {}; + struct timeval* tv_ptr {}; + if (tv) { + tv64 = *tv; + tv_ptr = &tv64; + } - const uint64_t Result = ::settimeofday(tv_ptr, tz); - SYSCALL_ERRNO(); - }); + const uint64_t Result = ::settimeofday(tv_ptr, tz); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(nanosleep, [](FEXCore::Core::CpuStateFrame *Frame, const timespec32 *req, timespec32 *rem) -> uint64_t { - struct timespec rem64{}; - struct timespec *rem64_ptr{}; + REGISTER_SYSCALL_IMPL_X32(nanosleep, [](FEXCore::Core::CpuStateFrame* Frame, const timespec32* req, timespec32* rem) -> uint64_t { + struct timespec rem64 {}; + struct timespec* rem64_ptr {}; - if (rem) { - rem64 = *rem; - rem64_ptr = &rem64; - } + if (rem) { + rem64 = *rem; + rem64_ptr = &rem64; + } - uint64_t Result = 0; - if (req) { - const struct timespec req64 = *req; - Result = ::nanosleep(&req64, rem64_ptr); - } else { - Result = ::nanosleep(nullptr, rem64_ptr); - } + uint64_t Result = 0; + if (req) { + const struct timespec req64 = *req; + Result = ::nanosleep(&req64, rem64_ptr); + } else { + Result = ::nanosleep(nullptr, rem64_ptr); + } - if (rem) { - *rem = rem64; - } - SYSCALL_ERRNO(); - }); + if (rem) { + *rem = rem64; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(clock_gettime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, timespec32 *tp) -> uint64_t { - struct timespec tp64{}; - uint64_t Result = ::clock_gettime(clk_id, &tp64); - if (tp) { - *tp = tp64; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(clock_gettime, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, timespec32* tp) -> uint64_t { + struct timespec tp64 {}; + uint64_t Result = ::clock_gettime(clk_id, &tp64); + if (tp) { + *tp = tp64; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(clock_getres, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, timespec32 *tp) -> uint64_t { - struct timespec tp64{}; - uint64_t Result = ::clock_getres(clk_id, &tp64); - if (tp) { - *tp = tp64; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(clock_getres, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, timespec32* tp) -> uint64_t { + struct timespec tp64 {}; + uint64_t Result = ::clock_getres(clk_id, &tp64); + if (tp) { + *tp = tp64; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(clock_nanosleep, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, int flags, const timespec32 *request, timespec32 *remain) -> uint64_t { - struct timespec req64{}; - struct timespec *req64_ptr{}; + REGISTER_SYSCALL_IMPL_X32( + clock_nanosleep, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, int flags, const timespec32* request, timespec32* remain) -> uint64_t { + struct timespec req64 {}; + struct timespec* req64_ptr {}; - struct timespec rem64{}; - struct timespec *rem64_ptr{}; + struct timespec rem64 {}; + struct timespec* rem64_ptr {}; if (request) { req64 = *request; @@ -151,43 +152,43 @@ namespace FEX::HLE::x32 { // Can't use glibc helper here since it does additional validation and data munging that breaks games. uint64_t Result = ::syscall(SYSCALL_DEF(clock_nanosleep), clockid, flags, req64_ptr, rem64_ptr); - if (remain && - (flags & TIMER_ABSTIME) == 0) { + if (remain && (flags & TIMER_ABSTIME) == 0) { // Remain is completely ignored if TIMER_ABSTIME is set. *remain = rem64; } SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(clock_settime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, const timespec32 *tp) -> uint64_t { - if (!tp) { - // clock_settime is required to pass a timespec. - return -EFAULT; - } + REGISTER_SYSCALL_IMPL_X32(clock_settime, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, const timespec32* tp) -> uint64_t { + if (!tp) { + // clock_settime is required to pass a timespec. + return -EFAULT; + } - uint64_t Result = 0; - const struct timespec tp64 = *tp; - Result = ::clock_settime(clockid, &tp64); - SYSCALL_ERRNO(); - }); + uint64_t Result = 0; + const struct timespec tp64 = *tp; + Result = ::clock_settime(clockid, &tp64); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(futimesat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, const timeval32 times[2]) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32(futimesat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const timeval32 times[2]) -> uint64_t { + uint64_t Result = 0; + if (times) { + struct timeval times64[2] {}; + times64[0] = times[0]; + times64[1] = times[1]; + Result = ::syscall(SYSCALL_DEF(futimesat), dirfd, pathname, times64); + } else { + Result = ::syscall(SYSCALL_DEF(futimesat), dirfd, pathname, nullptr); + } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X32( + utimensat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const compat_ptr times, int flags) -> uint64_t { uint64_t Result = 0; if (times) { - struct timeval times64[2]{}; - times64[0] = times[0]; - times64[1] = times[1]; - Result = ::syscall(SYSCALL_DEF(futimesat), dirfd, pathname, times64); - } else { - Result = ::syscall(SYSCALL_DEF(futimesat), dirfd, pathname, nullptr); - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(utimensat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, const compat_ptr times, int flags) -> uint64_t { - uint64_t Result = 0; - if (times) { - timespec times64[2]{}; + timespec times64[2] {}; times64[0] = times[0]; times64[1] = times[1]; Result = ::syscall(SYSCALL_DEF(utimensat), dirfd, pathname, times64, flags); @@ -197,37 +198,38 @@ namespace FEX::HLE::x32 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(utimes, [](FEXCore::Core::CpuStateFrame *Frame, const char *filename, const timeval32 times[2]) -> uint64_t { - uint64_t Result = 0; - if (times) { - struct timeval times64[2]{}; - times64[0] = times[0]; - times64[1] = times[1]; - Result = ::utimes(filename, times64); - } else { - Result = ::utimes(filename, nullptr); - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(utimes, [](FEXCore::Core::CpuStateFrame* Frame, const char* filename, const timeval32 times[2]) -> uint64_t { + uint64_t Result = 0; + if (times) { + struct timeval times64[2] {}; + times64[0] = times[0]; + times64[1] = times[1]; + Result = ::utimes(filename, times64); + } else { + Result = ::utimes(filename, nullptr); + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(adjtimex, [](FEXCore::Core::CpuStateFrame *Frame, compat_ptr buf) -> uint64_t { - struct timex Host{}; - Host = *buf; - uint64_t Result = ::adjtimex(&Host); - if (Result != -1) { - *buf = Host; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(adjtimex, [](FEXCore::Core::CpuStateFrame* Frame, compat_ptr buf) -> uint64_t { + struct timex Host {}; + Host = *buf; + uint64_t Result = ::adjtimex(&Host); + if (Result != -1) { + *buf = Host; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(clock_adjtime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, compat_ptr buf) -> uint64_t { - struct timex Host{}; - Host = *buf; - uint64_t Result = ::clock_adjtime(clk_id, &Host); - if (Result != -1) { - *buf = Host; - } - SYSCALL_ERRNO(); - }); - } + REGISTER_SYSCALL_IMPL_X32(clock_adjtime, + [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, compat_ptr buf) -> uint64_t { + struct timex Host {}; + Host = *buf; + uint64_t Result = ::clock_adjtime(clk_id, &Host); + if (Result != -1) { + *buf = Host; + } + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp index 642ae43aa..3a5d46621 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp @@ -18,82 +18,83 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") namespace FEX::HLE::x32 { - void RegisterTimer(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X32(timer_settime, [](FEXCore::Core::CpuStateFrame *Frame, - kernel_timer_t timerid, - int flags, - const FEX::HLE::x32::old_itimerspec32 *new_value, - FEX::HLE::x32::old_itimerspec32 *old_value) -> uint64_t { - itimerspec new_value_host{}; - itimerspec old_value_host{}; - itimerspec *old_value_host_p{}; +void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(timer_settime, + [](FEXCore::Core::CpuStateFrame* Frame, kernel_timer_t timerid, int flags, + const FEX::HLE::x32::old_itimerspec32* new_value, FEX::HLE::x32::old_itimerspec32* old_value) -> uint64_t { + itimerspec new_value_host {}; + itimerspec old_value_host {}; + itimerspec* old_value_host_p {}; - new_value_host = *new_value; - if (old_value) { - old_value_host_p = &old_value_host; - } - uint64_t Result = ::syscall(SYSCALL_DEF(timer_settime), timerid, flags, &new_value_host, old_value_host_p); - if (Result != -1 && old_value) { - *old_value = old_value_host; - } - SYSCALL_ERRNO(); - }); + new_value_host = *new_value; + if (old_value) { + old_value_host_p = &old_value_host; + } + uint64_t Result = ::syscall(SYSCALL_DEF(timer_settime), timerid, flags, &new_value_host, old_value_host_p); + if (Result != -1 && old_value) { + *old_value = old_value_host; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(timer_gettime, [](FEXCore::Core::CpuStateFrame *Frame, - kernel_timer_t timerid, - FEX::HLE::x32::old_itimerspec32 *curr_value) -> uint64_t { - itimerspec curr_value_host{}; + REGISTER_SYSCALL_IMPL_X32( + timer_gettime, [](FEXCore::Core::CpuStateFrame* Frame, kernel_timer_t timerid, FEX::HLE::x32::old_itimerspec32* curr_value) -> uint64_t { + itimerspec curr_value_host {}; uint64_t Result = ::syscall(SYSCALL_DEF(timer_gettime), timerid, curr_value_host); *curr_value = curr_value_host; SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X32(getitimer, [](FEXCore::Core::CpuStateFrame *Frame, int which, FEX::HLE::x32::itimerval32 *curr_value) -> uint64_t { - itimerval val{}; - itimerval *val_p{}; - if (curr_value) { - val_p = &val; - } - uint64_t Result = ::getitimer(which, val_p); - if (curr_value) { - *curr_value = val; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(getitimer, [](FEXCore::Core::CpuStateFrame* Frame, int which, FEX::HLE::x32::itimerval32* curr_value) -> uint64_t { + itimerval val {}; + itimerval* val_p {}; + if (curr_value) { + val_p = &val; + } + uint64_t Result = ::getitimer(which, val_p); + if (curr_value) { + *curr_value = val; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(setitimer, [](FEXCore::Core::CpuStateFrame *Frame, int which, const FEX::HLE::x32::itimerval32 *new_value, FEX::HLE::x32::itimerval32 *old_value) -> uint64_t { - itimerval val{}; - itimerval old{}; - itimerval *val_p{}; - itimerval *old_p{}; + REGISTER_SYSCALL_IMPL_X32(setitimer, + [](FEXCore::Core::CpuStateFrame* Frame, int which, const FEX::HLE::x32::itimerval32* new_value, + FEX::HLE::x32::itimerval32* old_value) -> uint64_t { + itimerval val {}; + itimerval old {}; + itimerval* val_p {}; + itimerval* old_p {}; - if (new_value) { - val = *new_value; - val_p = &val; - } + if (new_value) { + val = *new_value; + val_p = &val; + } - if (old_value) { - old_p = &old; - } + if (old_value) { + old_p = &old; + } - uint64_t Result = ::setitimer(which, val_p, old_p); + uint64_t Result = ::setitimer(which, val_p, old_p); - if (old_value) { - *old_value = old; - } - SYSCALL_ERRNO(); - }); + if (old_value) { + *old_value = old; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X32(timer_create, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, compat_ptr sevp, kernel_timer_t *timerid) -> uint64_t { + REGISTER_SYSCALL_IMPL_X32( + timer_create, + [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, compat_ptr sevp, kernel_timer_t* timerid) -> uint64_t { sigevent Host = *sevp; uint64_t Result = ::syscall(SYSCALL_DEF(timer_create), clockid, &Host, timerid); SYSCALL_ERRNO(); }); - } } +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Types.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Types.h index 90ca0a278..063ebffb8 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Types.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Types.h @@ -64,29 +64,28 @@ template class compat_ptr { public: compat_ptr() = delete; - compat_ptr(uint32_t In) : Ptr {In} {} - compat_ptr(T *In) : Ptr {static_cast(reinterpret_cast(In))} {} + compat_ptr(uint32_t In) + : Ptr {In} {} + compat_ptr(T* In) + : Ptr {static_cast(reinterpret_cast(In))} {} - template::value, T2>> + template::value, T2>> T2& operator*() const { return *Interpret(); } - T *operator->() { + T* operator->() { return Interpret(); } // In the case of non-void type, we can index the pointer - template::value, T2>> - T2 &operator[](size_t idx) const { + template::value, T2>> + T2& operator[](size_t idx) const { return *reinterpret_cast(Ptr + sizeof(T2) * idx); } // In the case of void type, we need to trivially convert - template::value, T2>> + template::value, T2>> operator T2*() const { return reinterpret_cast(Ptr); } @@ -120,17 +119,14 @@ static_assert(sizeof(compat_ptr) == 4, "Incorrect size"); * Provides conversation operators for the host version * @{ */ -struct -FEX_ANNOTATE("alias-x86_32-timespec") -FEX_ANNOTATE("fex-match") -timespec32 { +struct FEX_ANNOTATE("alias-x86_32-timespec") FEX_ANNOTATE("fex-match") timespec32 { int32_t tv_sec; int32_t tv_nsec; timespec32() = default; operator timespec() const { - timespec spec{}; + timespec spec {}; spec.tv_sec = tv_sec; spec.tv_nsec = tv_nsec; return spec; @@ -153,17 +149,14 @@ static_assert(sizeof(timespec32) == 8, "Incorrect size"); * Provides conversation operators for the host version * @{ */ -struct -FEX_ANNOTATE("alias-x86_32-timeval") -FEX_ANNOTATE("fex-match") -timeval32 { +struct FEX_ANNOTATE("alias-x86_32-timeval") FEX_ANNOTATE("fex-match") timeval32 { int32_t tv_sec; int32_t tv_usec; timeval32() = delete; operator timeval() const { - timeval spec{}; + timeval spec {}; spec.tv_sec = tv_sec; spec.tv_usec = tv_usec; return spec; @@ -186,26 +179,22 @@ static_assert(sizeof(timeval32) == 8, "Incorrect size"); * Provides conversation operators for the host version * @{ */ -struct -FEX_ANNOTATE("alias-x86_32-itimerval") -FEX_ANNOTATE("fex-match") -itimerval32 { +struct FEX_ANNOTATE("alias-x86_32-itimerval") FEX_ANNOTATE("fex-match") itimerval32 { FEX::HLE::x32::timeval32 it_interval; FEX::HLE::x32::timeval32 it_value; itimerval32() = delete; operator itimerval() const { - itimerval spec{}; + itimerval spec {}; spec.it_interval = it_interval; spec.it_value = it_value; return spec; } itimerval32(struct itimerval spec) - : it_interval { spec.it_interval } - , it_value { spec.it_value } { - } + : it_interval {spec.it_interval} + , it_value {spec.it_value} {} }; /** @} */ @@ -219,17 +208,14 @@ static_assert(sizeof(itimerval32) == 16, "Incorrect size"); * Provides conversation operators for the host version * @{ */ -struct -FEX_ANNOTATE("alias-x86_32-iovec") -FEX_ANNOTATE("fex-match") -iovec32 { +struct FEX_ANNOTATE("alias-x86_32-iovec") FEX_ANNOTATE("fex-match") iovec32 { uint32_t iov_base; uint32_t iov_len; iovec32() = delete; operator iovec() const { - iovec vec{}; + iovec vec {}; vec.iov_base = reinterpret_cast(iov_base); vec.iov_len = iov_len; return vec; @@ -245,23 +231,17 @@ static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(iovec32) == 8, "Incorrect size"); /** @} */ -struct -FEX_ANNOTATE("alias-x86_32-cmsghdr") -FEX_ANNOTATE("fex-match") -cmsghdr32 { +struct FEX_ANNOTATE("alias-x86_32-cmsghdr") FEX_ANNOTATE("fex-match") cmsghdr32 { uint32_t cmsg_len; int32_t cmsg_level; int32_t cmsg_type; - char cmsg_data[]; + char cmsg_data[]; }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(cmsghdr32) == 12, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-msghdr") -FEX_ANNOTATE("fex-match") -msghdr32 { +struct FEX_ANNOTATE("alias-x86_32-msghdr") FEX_ANNOTATE("fex-match") msghdr32 { compat_ptr msg_name; socklen_t msg_namelen; @@ -276,10 +256,7 @@ msghdr32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(msghdr32) == 28, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-mmsghdr") -FEX_ANNOTATE("fex-match") -mmsghdr_32 { +struct FEX_ANNOTATE("alias-x86_32-mmsghdr") FEX_ANNOTATE("fex-match") mmsghdr_32 { msghdr32 msg_hdr; uint32_t msg_len; }; @@ -287,10 +264,7 @@ mmsghdr_32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(mmsghdr_32) == 32, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-stack_t") -FEX_ANNOTATE("fex-match") -stack_t32 { +struct FEX_ANNOTATE("alias-x86_32-stack_t") FEX_ANNOTATE("fex-match") stack_t32 { compat_ptr ss_sp; int32_t ss_flags; compat_size_t ss_size; @@ -298,17 +272,17 @@ stack_t32 { stack_t32() = delete; operator stack_t() const { - stack_t ss{}; - ss.ss_sp = ss_sp; + stack_t ss {}; + ss.ss_sp = ss_sp; ss.ss_flags = ss_flags; - ss.ss_size = ss_size; + ss.ss_size = ss_size; return ss; } stack_t32(stack_t ss) : ss_sp {ss.ss_sp} { ss_flags = ss.ss_flags; - ss_size = ss.ss_size; + ss_size = ss.ss_size; } }; @@ -316,10 +290,9 @@ static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(stack_t32) == 12, "Incorrect size"); struct -// This does not match the glibc implementation of stat -// Matches the definition of `struct compat_stat` in `arch/x86/include/asm/compat.h` -FEX_ANNOTATE("fex-match") -oldstat32 { + // This does not match the glibc implementation of stat + // Matches the definition of `struct compat_stat` in `arch/x86/include/asm/compat.h` + FEX_ANNOTATE("fex-match") oldstat32 { uint16_t st_dev; uint16_t st_ino; uint16_t st_mode; @@ -337,13 +310,12 @@ oldstat32 { oldstat32() = delete; oldstat32(struct stat host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x const uint32_t MINORBITS = 20; const uint32_t MINORMASK = (1U << MINORBITS) - 1; auto EncodeOld = [](dev_t dev) -> uint16_t { // This is a bit weird - return ((dev >> MINORBITS) << 8) | - (dev & MINORMASK); + return ((dev >> MINORBITS) << 8) | (dev & MINORMASK); }; st_dev = EncodeOld(host.st_dev); @@ -360,17 +332,16 @@ oldstat32 { st_atime_ = host.st_atim.tv_sec; st_mtime_ = host.st_mtime; st_ctime_ = host.st_ctime; - #undef COPY +#undef COPY } }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(oldstat32) == 32, "Incorrect size"); struct -// This does not match the glibc implementation of stat -// Matches the definition of `struct compat_stat` in `arch/x86/include/asm/compat.h` -FEX_ANNOTATE("fex-match") -stat32 { + // This does not match the glibc implementation of stat + // Matches the definition of `struct compat_stat` in `arch/x86/include/asm/compat.h` + FEX_ANNOTATE("fex-match") stat32 { compat_dev_t st_dev; uint16_t __pad1; compat_ino_t st_ino; @@ -384,7 +355,7 @@ stat32 { uint16_t __pad2; uint32_t st_size; uint32_t st_blksize; - uint32_t st_blocks; /* Number 512-byte blocks allocated. */ + uint32_t st_blocks; /* Number 512-byte blocks allocated. */ uint32_t st_atime_; uint32_t fex_st_atime_nsec; uint32_t st_mtime_; @@ -397,7 +368,7 @@ stat32 { stat32() = delete; stat32(struct stat host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x COPY(st_dev); COPY(st_ino); COPY(st_mode); @@ -419,20 +390,18 @@ stat32 { st_ctime_ = host.st_ctime; fex_st_ctime_nsec = host.st_ctim.tv_nsec; - #undef COPY +#undef COPY } }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(stat32) == 64, "Incorrect size"); struct -// This does not match the glibc implementation of stat -// Matches the definition of `struct stat64` in `x86_64-linux-gnu/asm/stat.h` -FEX_ANNOTATE("fex-match") -FEX_PACKED -stat64_32 { + // This does not match the glibc implementation of stat + // Matches the definition of `struct stat64` in `x86_64-linux-gnu/asm/stat.h` + FEX_ANNOTATE("fex-match") FEX_PACKED stat64_32 { compat_uint64_t st_dev; - uint8_t __pad0[4]; + uint8_t __pad0[4]; uint32_t __st_ino; uint32_t st_mode; @@ -442,10 +411,10 @@ stat64_32 { uint32_t st_gid; compat_uint64_t st_rdev; - uint8_t __pad3[4]; + uint8_t __pad3[4]; compat_int64_t st_size; uint32_t st_blksize; - compat_uint64_t st_blocks; /* Number 512-byte blocks allocated. */ + compat_uint64_t st_blocks; /* Number 512-byte blocks allocated. */ uint32_t st_atime_; uint32_t fex_st_atime_nsec; uint32_t st_mtime_; @@ -457,7 +426,7 @@ stat64_32 { stat64_32() = delete; stat64_32(struct stat host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x COPY(st_dev); COPY(st_ino); COPY(st_nlink); @@ -481,12 +450,12 @@ stat64_32 { st_ctime_ = host.st_ctime; fex_st_ctime_nsec = host.st_ctim.tv_nsec; - #undef COPY +#undef COPY } #ifndef stat64 stat64_32(struct stat64 host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x COPY(st_dev); COPY(st_ino); COPY(st_nlink); @@ -510,19 +479,14 @@ stat64_32 { st_ctime_ = host.st_ctime; fex_st_ctime_nsec = host.st_ctim.tv_nsec; - #undef COPY +#undef COPY } #endif }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(stat64_32) == 96, "Incorrect size"); -struct -FEX_PACKED -FEX_ALIGNED(4) -FEX_ANNOTATE("alias-x86_32-statfs64") -FEX_ANNOTATE("fex-match") -statfs64_32 { +struct FEX_PACKED FEX_ALIGNED(4) FEX_ANNOTATE("alias-x86_32-statfs64") FEX_ANNOTATE("fex-match") statfs64_32 { uint32_t f_type; uint32_t f_bsize; compat_uint64_t f_blocks; @@ -539,7 +503,7 @@ statfs64_32 { statfs64_32() = delete; statfs64_32(struct statfs host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x COPY(f_type); COPY(f_bsize); COPY(f_blocks); @@ -552,12 +516,12 @@ statfs64_32 { COPY(f_flags); memcpy(&f_fsid, &host.f_fsid, sizeof(f_fsid)); - #undef COPY +#undef COPY } #ifndef statfs64 statfs64_32(struct statfs64 host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x COPY(f_type); COPY(f_bsize); COPY(f_blocks); @@ -570,17 +534,14 @@ statfs64_32 { COPY(f_flags); memcpy(&f_fsid, &host.f_fsid, sizeof(f_fsid)); - #undef COPY +#undef COPY } #endif }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(statfs64_32) == 84, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-statfs") -FEX_ANNOTATE("fex-match") -statfs32_32 { +struct FEX_ANNOTATE("alias-x86_32-statfs") FEX_ANNOTATE("fex-match") statfs32_32 { int32_t f_type; int32_t f_bsize; int32_t f_blocks; @@ -597,7 +558,7 @@ statfs32_32 { statfs32_32() = delete; statfs32_32(struct statfs host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x COPY(f_type); COPY(f_bsize); COPY(f_blocks); @@ -610,12 +571,12 @@ statfs32_32 { COPY(f_flags); memcpy(&f_fsid, &host.f_fsid, sizeof(f_fsid)); - #undef COPY +#undef COPY } #ifndef statfs64 statfs32_32(struct statfs64 host) { - #define COPY(x) x = host.x +#define COPY(x) x = host.x COPY(f_type); COPY(f_bsize); COPY(f_blocks); @@ -628,17 +589,14 @@ statfs32_32 { COPY(f_flags); memcpy(&f_fsid, &host.f_fsid, sizeof(f_fsid)); - #undef COPY +#undef COPY } #endif }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(statfs32_32) == 64, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-flock") -FEX_ANNOTATE("fex-match") -flock_32 { +struct FEX_ANNOTATE("alias-x86_32-flock") FEX_ANNOTATE("fex-match") flock_32 { int16_t l_type; int16_t l_whence; int32_t l_start; @@ -648,20 +606,20 @@ flock_32 { flock_32() = delete; flock_32(struct flock host) { - l_type = host.l_type; + l_type = host.l_type; l_whence = host.l_whence; - l_start = host.l_start; - l_len = host.l_len; - l_pid = host.l_pid; + l_start = host.l_start; + l_len = host.l_len; + l_pid = host.l_pid; } operator struct flock() const { - struct flock res{}; - res.l_type = l_type; + struct flock res {}; + res.l_type = l_type; res.l_whence = l_whence; - res.l_start = l_start; - res.l_len = l_len; - res.l_pid = l_pid; + res.l_start = l_start; + res.l_len = l_len; + res.l_pid = l_pid; return res; } }; @@ -672,10 +630,7 @@ static_assert(sizeof(flock_32) == 16, "Incorrect size"); // glibc doesn't pack flock64 while the kernel does // This does not match glibc flock64 definition // Matches the definition of `struct compat_flock64` in `arch/x86/include/asm/compat.h` -struct -FEX_ANNOTATE("fex-match") -FEX_PACKED -flock64_32 { +struct FEX_ANNOTATE("fex-match") FEX_PACKED flock64_32 { int16_t l_type; int16_t l_whence; compat_loff_t l_start; @@ -685,20 +640,20 @@ flock64_32 { flock64_32() = delete; flock64_32(struct flock host) { - l_type = host.l_type; + l_type = host.l_type; l_whence = host.l_whence; - l_start = host.l_start; - l_len = host.l_len; - l_pid = host.l_pid; + l_start = host.l_start; + l_len = host.l_len; + l_pid = host.l_pid; } operator struct flock() const { - struct flock res{}; - res.l_type = l_type; + struct flock res {}; + res.l_type = l_type; res.l_whence = l_whence; - res.l_start = l_start; - res.l_len = l_len; - res.l_pid = l_pid; + res.l_start = l_start; + res.l_len = l_len; + res.l_pid = l_pid; return res; } }; @@ -707,11 +662,9 @@ static_assert(sizeof(flock64_32) == 24, "Incorrect size"); // There is no public definition of this struct // Matches the definition of `struct linux_dirent` in fs/readdir.c -struct -FEX_ANNOTATE("fex-match") -linux_dirent { +struct FEX_ANNOTATE("fex-match") linux_dirent { compat_uint64_t d_ino; - compat_int64_t d_off; + compat_int64_t d_off; uint16_t d_reclen; uint8_t _pad[6]; char d_name[]; @@ -721,9 +674,7 @@ static_assert(sizeof(linux_dirent) == 24, "Incorrect size"); // There is no public definition of this struct // Matches the definition of `struct compat_linux_dirent` in fs/readdir.c -struct -FEX_ANNOTATE("fex-match") -linux_dirent_32 { +struct FEX_ANNOTATE("fex-match") linux_dirent_32 { compat_ulong_t d_ino; compat_ulong_t d_off; uint16_t d_reclen; @@ -735,13 +686,11 @@ static_assert(sizeof(linux_dirent_32) == 12, "Incorrect size"); // There is no public definition of this struct // Matches the definition of `struct linux_dirent64` in include/linux/dirent.h -struct -FEX_ANNOTATE("fex-match") -linux_dirent_64 { +struct FEX_ANNOTATE("fex-match") linux_dirent_64 { compat_uint64_t d_ino; compat_uint64_t d_off; uint16_t d_reclen; - uint8_t d_type; + uint8_t d_type; uint8_t _pad[5]; char d_name[]; }; @@ -750,9 +699,7 @@ static_assert(sizeof(linux_dirent_64) == 24, "Incorrect size"); // There is no public definition of this struct // Matches `struct compat_sigset_argpack` -struct -FEX_ANNOTATE("fex-match") -sigset_argpack32 { +struct FEX_ANNOTATE("fex-match") sigset_argpack32 { compat_ptr sigset; compat_size_t size; }; @@ -760,10 +707,7 @@ sigset_argpack32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(sigset_argpack32) == 8, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-rusage") -FEX_ANNOTATE("fex-match") -rusage_32 { +struct FEX_ANNOTATE("alias-x86_32-rusage") FEX_ANNOTATE("fex-match") rusage_32 { timeval32 ru_utime; timeval32 ru_stime; union { @@ -825,27 +769,27 @@ rusage_32 { rusage_32() = delete; rusage_32(struct rusage usage) - : ru_utime { usage.ru_utime } - , ru_stime { usage.ru_stime } { + : ru_utime {usage.ru_utime} + , ru_stime {usage.ru_stime} { // These only truncate - ru_maxrss = usage.ru_maxrss; - ru_ixrss = usage.ru_ixrss; - ru_idrss = usage.ru_idrss; - ru_isrss = usage.ru_isrss; - ru_minflt = usage.ru_minflt; - ru_majflt = usage.ru_majflt; - ru_nswap = usage.ru_nswap; - ru_inblock = usage.ru_inblock; - ru_oublock = usage.ru_oublock; - ru_msgsnd = usage.ru_msgsnd; - ru_msgrcv = usage.ru_msgrcv; + ru_maxrss = usage.ru_maxrss; + ru_ixrss = usage.ru_ixrss; + ru_idrss = usage.ru_idrss; + ru_isrss = usage.ru_isrss; + ru_minflt = usage.ru_minflt; + ru_majflt = usage.ru_majflt; + ru_nswap = usage.ru_nswap; + ru_inblock = usage.ru_inblock; + ru_oublock = usage.ru_oublock; + ru_msgsnd = usage.ru_msgsnd; + ru_msgrcv = usage.ru_msgrcv; ru_nsignals = usage.ru_nsignals; - ru_nvcsw = usage.ru_nvcsw; - ru_nivcsw = usage.ru_nivcsw; + ru_nvcsw = usage.ru_nvcsw; + ru_nivcsw = usage.ru_nivcsw; } operator struct rusage() const { - struct rusage usage{}; + struct rusage usage {}; usage.ru_utime = ru_utime; usage.ru_stime = ru_stime; usage.ru_maxrss = ru_maxrss; @@ -869,10 +813,7 @@ rusage_32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(rusage_32) == 72, "Incorrect size"); -struct -FEX_PACKED -FEX_ANNOTATE("fex-match") -OldGuestSigAction_32 { +struct FEX_PACKED FEX_ANNOTATE("fex-match") OldGuestSigAction_32 { FEX::HLE::x32::compat_ptr handler_32; uint32_t sa_mask; uint32_t sa_flags; @@ -881,7 +822,7 @@ OldGuestSigAction_32 { OldGuestSigAction_32() = delete; operator FEX::HLE::GuestSigAction() const { - FEX::HLE::GuestSigAction action{}; + FEX::HLE::GuestSigAction action {}; action.sigaction_handler.handler = reinterpret_cast(handler_32.Ptr); action.sa_flags = sa_flags; @@ -904,10 +845,7 @@ static_assert(sizeof(OldGuestSigAction_32) == 16, "Incorrect size"); // This definition isn't public // This is for rt_sigaction // Matches the definition for `struct compat_sigaction` in `include/linux/compat.h` -struct -FEX_PACKED -FEX_ANNOTATE("fex-match") -GuestSigAction_32 { +struct FEX_PACKED FEX_ANNOTATE("fex-match") GuestSigAction_32 { FEX::HLE::x32::compat_ptr handler_32; uint32_t sa_flags; @@ -917,7 +855,7 @@ GuestSigAction_32 { GuestSigAction_32() = delete; operator FEX::HLE::GuestSigAction() const { - FEX::HLE::GuestSigAction action{}; + FEX::HLE::GuestSigAction action {}; action.sigaction_handler.handler = reinterpret_cast(handler_32.Ptr); action.sa_flags = sa_flags; @@ -937,10 +875,7 @@ GuestSigAction_32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(GuestSigAction_32) == 20, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-tms") -FEX_ANNOTATE("fex-match") -compat_tms { +struct FEX_ANNOTATE("alias-x86_32-tms") FEX_ANNOTATE("fex-match") compat_tms { compat_clock_t tms_utime; compat_clock_t tms_stime; compat_clock_t tms_cutime; @@ -948,7 +883,7 @@ compat_tms { compat_tms() = delete; operator tms() const { - tms val{}; + tms val {}; val.tms_utime = tms_utime; val.tms_stime = tms_stime; val.tms_cutime = tms_cutime; @@ -966,16 +901,13 @@ compat_tms { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(compat_tms) == 16, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-utimbuf") -FEX_ANNOTATE("fex-match") -old_utimbuf32 { +struct FEX_ANNOTATE("alias-x86_32-utimbuf") FEX_ANNOTATE("fex-match") old_utimbuf32 { old_time32_t actime; old_time32_t modtime; old_utimbuf32() = delete; operator utimbuf() const { - utimbuf val{}; + utimbuf val {}; val.actime = actime; val.modtime = modtime; return val; @@ -990,42 +922,35 @@ old_utimbuf32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(old_utimbuf32) == 8, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-itimerspec") -FEX_ANNOTATE("fex-match") -old_itimerspec32 { +struct FEX_ANNOTATE("alias-x86_32-itimerspec") FEX_ANNOTATE("fex-match") old_itimerspec32 { timespec32 it_interval; timespec32 it_value; old_itimerspec32() = delete; operator itimerspec() const { - itimerspec val{}; + itimerspec val {}; val.it_interval = it_interval; val.it_value = it_value; return val; } old_itimerspec32(struct itimerspec val) - : it_interval { val.it_interval } - , it_value { val.it_value } { - } + : it_interval {val.it_interval} + , it_value {val.it_value} {} }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(old_itimerspec32) == 16, "Incorrect size"); template -struct -FEX_ANNOTATE("alias-x86_32-rlimit") -FEX_ANNOTATE("fex-match") -rlimit32 { +struct FEX_ANNOTATE("alias-x86_32-rlimit") FEX_ANNOTATE("fex-match") rlimit32 { uint32_t rlim_cur; uint32_t rlim_max; rlimit32() = delete; operator rlimit() const { static_assert(Signed == false, "Signed variant doesn't exist"); - rlimit val{}; + rlimit val {}; val.rlim_cur = rlim_cur; val.rlim_max = rlim_max; @@ -1044,15 +969,13 @@ rlimit32 { constexpr uint32_t Limit = Signed ? 0x7FFF'FFFF : 0xFFFF'FFFF; if (val.rlim_cur > Limit) { rlim_cur = Limit; - } - else { + } else { rlim_cur = val.rlim_cur; } if (val.rlim_max > Limit) { rlim_max = Limit; - } - else { + } else { rlim_max = val.rlim_max; } } @@ -1061,10 +984,7 @@ rlimit32 { static_assert(std::is_trivial>::value, "Needs to be trivial"); static_assert(sizeof(rlimit32) == 8, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-timex") -FEX_ANNOTATE("fex-match") -timex32 { +struct FEX_ANNOTATE("alias-x86_32-timex") FEX_ANNOTATE("fex-match") timex32 { uint32_t modes; compat_long_t offset; compat_long_t freq; @@ -1088,75 +1008,80 @@ timex32 { int32_t tai; // Padding - int32_t :32; int32_t :32; int32_t :32; int32_t :32; - int32_t :32; int32_t :32; int32_t :32; int32_t :32; - int32_t :32; int32_t :32; int32_t :32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; + int32_t : 32; timex32() = delete; operator timex() const { - timex val{}; - val.modes = modes; - val.offset = offset; - val.freq = freq; - val.maxerror = maxerror; - val.esterror = esterror; - val.status = status; - val.constant = constant; + timex val {}; + val.modes = modes; + val.offset = offset; + val.freq = freq; + val.maxerror = maxerror; + val.esterror = esterror; + val.status = status; + val.constant = constant; val.precision = precision; val.tolerance = tolerance; - val.time = time; - val.tick = tick; - val.ppsfreq = ppsfreq; - val.jitter = jitter; - val.shift = shift; - val.stabil = stabil; - val.jitcnt = jitcnt; - val.calcnt = calcnt; - val.errcnt = errcnt; - val.stbcnt = stbcnt; - val.tai = tai; + val.time = time; + val.tick = tick; + val.ppsfreq = ppsfreq; + val.jitter = jitter; + val.shift = shift; + val.stabil = stabil; + val.jitcnt = jitcnt; + val.calcnt = calcnt; + val.errcnt = errcnt; + val.stbcnt = stbcnt; + val.tai = tai; return val; } timex32(struct timex val) - : time { val.time } { - modes = val.modes; - offset = val.offset; - freq = val.freq; - maxerror = val.maxerror; - esterror = val.esterror; - status = val.status; - constant = val.constant; + : time {val.time} { + modes = val.modes; + offset = val.offset; + freq = val.freq; + maxerror = val.maxerror; + esterror = val.esterror; + status = val.status; + constant = val.constant; precision = val.precision; tolerance = val.tolerance; - tick = val.tick; - ppsfreq = val.ppsfreq; - jitter = val.jitter; - shift = val.shift; - stabil = val.stabil; - jitcnt = val.jitcnt; - calcnt = val.calcnt; - errcnt = val.errcnt; - stbcnt = val.stbcnt; - tai = val.tai; + tick = val.tick; + ppsfreq = val.ppsfreq; + jitter = val.jitter; + shift = val.shift; + stabil = val.stabil; + jitcnt = val.jitcnt; + calcnt = val.calcnt; + errcnt = val.errcnt; + stbcnt = val.stbcnt; + tai = val.tai; } }; static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(timex32) == 128, "Incorrect size"); -union -FEX_ANNOTATE("alias-x86_32-sigval") -FEX_ANNOTATE("fex-match") -sigval32 { +union FEX_ANNOTATE("alias-x86_32-sigval") FEX_ANNOTATE("fex-match") sigval32 { int sival_int; compat_ptr sival_ptr; sigval32() = delete; operator sigval() const { - sigval val{}; + sigval val {}; val.sival_ptr = sival_ptr; return val; } @@ -1172,9 +1097,7 @@ static_assert(sizeof(sigval32) == 4, "Incorrect size"); constexpr size_t FEX_SIGEV_MAX_SIZE = 64; constexpr size_t FEX_SIGEV_PAD_SIZE = (FEX_SIGEV_MAX_SIZE - (sizeof(int32_t) * 2 + sizeof(sigval32))) / sizeof(int32_t); -struct -FEX_ANNOTATE("fex-match") -sigevent32 { +struct FEX_ANNOTATE("fex-match") sigevent32 { FEX::HLE::x32::sigval32 sigev_value; int sigev_signo; int sigev_notify; @@ -1191,35 +1114,33 @@ sigevent32 { // For older build environments #ifndef sigev_notify_thread_id -#define sigev_notify_thread_id _sigev_un._tid +#define sigev_notify_thread_id _sigev_un._tid #endif operator sigevent() const { - sigevent val{}; - val.sigev_value = sigev_value; - val.sigev_signo = sigev_signo; + sigevent val {}; + val.sigev_value = sigev_value; + val.sigev_signo = sigev_signo; val.sigev_notify = sigev_notify; if (sigev_notify == SIGEV_THREAD_ID) { val.sigev_notify_thread_id = _sigev_un._tid; - } - else if (sigev_notify == SIGEV_THREAD) { - val.sigev_notify_function = reinterpret_cast(_sigev_un._sigev_thread._function); + } else if (sigev_notify == SIGEV_THREAD) { + val.sigev_notify_function = reinterpret_cast(_sigev_un._sigev_thread._function); val.sigev_notify_attributes = reinterpret_cast(_sigev_un._sigev_thread._attribute); } return val; } sigevent32(sigevent val) - : sigev_value { val.sigev_value } { - sigev_signo = val.sigev_signo; + : sigev_value {val.sigev_value} { + sigev_signo = val.sigev_signo; sigev_notify = val.sigev_notify; if (sigev_notify == SIGEV_THREAD_ID) { _sigev_un._tid = val.sigev_notify_thread_id; - } - else if (sigev_notify == SIGEV_THREAD) { - _sigev_un._sigev_thread._function = static_cast(reinterpret_cast(val.sigev_notify_function)); + } else if (sigev_notify == SIGEV_THREAD) { + _sigev_un._sigev_thread._function = static_cast(reinterpret_cast(val.sigev_notify_function)); _sigev_un._sigev_thread._attribute = static_cast(reinterpret_cast(val.sigev_notify_attributes)); } } @@ -1228,10 +1149,7 @@ sigevent32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(sigval32) == 4, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-mq_attr") -FEX_ANNOTATE("fex-match") -mq_attr32 { +struct FEX_ANNOTATE("alias-x86_32-mq_attr") FEX_ANNOTATE("fex-match") mq_attr32 { compat_long_t mq_flags; compat_long_t mq_maxmsg; compat_long_t mq_msgsize; @@ -1240,17 +1158,17 @@ mq_attr32 { mq_attr32() = delete; operator mq_attr() const { - struct mq_attr val{}; - val.mq_flags = mq_flags; - val.mq_maxmsg = mq_maxmsg; + struct mq_attr val {}; + val.mq_flags = mq_flags; + val.mq_maxmsg = mq_maxmsg; val.mq_msgsize = mq_msgsize; val.mq_curmsgs = mq_curmsgs; return val; } mq_attr32(struct mq_attr val) { - mq_flags = val.mq_flags; - mq_maxmsg = val.mq_maxmsg; + mq_flags = val.mq_flags; + mq_maxmsg = val.mq_maxmsg; mq_msgsize = val.mq_msgsize; mq_curmsgs = val.mq_curmsgs; } @@ -1259,35 +1177,28 @@ mq_attr32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(mq_attr32) == 32, "Incorrect size"); -union -FEX_ANNOTATE("alias-x86_32-epoll_data_t") -FEX_ANNOTATE("fex-match") -epoll_data32 { +union FEX_ANNOTATE("alias-x86_32-epoll_data_t") FEX_ANNOTATE("fex-match") epoll_data32 { compat_ptr ptr; int fd; uint32_t u32; compat_uint64_t u64; }; -struct -FEX_PACKED -FEX_ANNOTATE("alias-x86_32-epoll_event") -FEX_ANNOTATE("fex-match") -epoll_event32 { +struct FEX_PACKED FEX_ANNOTATE("alias-x86_32-epoll_event") FEX_ANNOTATE("fex-match") epoll_event32 { uint32_t events; epoll_data32 data; epoll_event32() = delete; operator struct epoll_event() const { - epoll_event event{}; + epoll_event event {}; event.events = events; event.data.u64 = data.u64; return event; } epoll_event32(struct epoll_event event) - : data { event.data.u64 }{ + : data {event.data.u64} { events = event.events; } }; @@ -1308,23 +1219,23 @@ struct ipc_perm_32 { operator struct ipc64_perm() const { struct ipc64_perm perm; perm.key = key; - perm.uid = uid; - perm.gid = gid; - perm.cuid = cuid; - perm.cgid = cgid; - perm.mode = mode; + perm.uid = uid; + perm.gid = gid; + perm.cuid = cuid; + perm.cgid = cgid; + perm.mode = mode; perm.seq = seq; return perm; } ipc_perm_32(struct ipc64_perm perm) { - key = perm.key; - uid = perm.uid; - gid = perm.gid; + key = perm.key; + uid = perm.uid; + gid = perm.gid; cuid = perm.cuid; cgid = perm.cgid; mode = perm.mode; - seq = perm.seq; + seq = perm.seq; } }; @@ -1348,23 +1259,23 @@ struct ipc_perm_64 { operator struct ipc64_perm() const { struct ipc64_perm perm; perm.key = key; - perm.uid = uid; - perm.gid = gid; - perm.cuid = cuid; - perm.cgid = cgid; - perm.mode = mode; + perm.uid = uid; + perm.gid = gid; + perm.cuid = cuid; + perm.cgid = cgid; + perm.mode = mode; perm.seq = seq; return perm; } ipc_perm_64(struct ipc64_perm perm) { - key = perm.key; - uid = perm.uid; - gid = perm.gid; + key = perm.key; + uid = perm.uid; + gid = perm.gid; cuid = perm.cuid; cgid = perm.cgid; mode = perm.mode; - seq = perm.seq; + seq = perm.seq; } }; @@ -1487,7 +1398,7 @@ struct semid_ds_32 { semid_ds_32() = delete; operator struct semid64_ds() const { - struct semid64_ds buf{}; + struct semid64_ds buf {}; buf.sem_perm = sem_perm; buf.sem_otime = sem_otime; @@ -1522,7 +1433,7 @@ struct semid_ds_64 { semid_ds_64() = delete; operator struct semid64_ds() const { - struct semid64_ds buf{}; + struct semid64_ds buf {}; buf.sem_perm = sem_perm; buf.sem_otime = sem_otime_high; @@ -1568,7 +1479,7 @@ struct msqid_ds_32 { msqid_ds_32() = delete; operator struct msqid64_ds() const { - struct msqid64_ds val{}; + struct msqid64_ds val {}; // msg_first and msg_last are unused and untouched val.msg_perm = msg_perm; val.msg_stime = msg_stime; @@ -1591,23 +1502,20 @@ struct msqid_ds_32 { msg_ctime = buf.msg_ctime; if (buf.msg_cbytes > std::numeric_limits::max()) { msg_cbytes = std::numeric_limits::max(); - } - else { + } else { msg_cbytes = buf.msg_cbytes; } msg_lcbytes = buf.msg_cbytes; if (buf.msg_qnum > std::numeric_limits::max()) { msg_qnum = std::numeric_limits::max(); - } - else { + } else { msg_qnum = buf.msg_qnum; } if (buf.msg_cbytes > std::numeric_limits::max()) { msg_cbytes = std::numeric_limits::max(); - } - else { + } else { msg_cbytes = buf.msg_cbytes; } msg_lqbytes = buf.msg_qbytes; @@ -1635,7 +1543,7 @@ struct msqid_ds_64 { msqid_ds_64() = delete; operator struct msqid64_ds() const { - struct msqid64_ds val{}; + struct msqid64_ds val {}; val.msg_perm = msg_perm; val.msg_stime = msg_stime_high; val.msg_stime <<= 32; @@ -1676,9 +1584,7 @@ struct msqid_ds_64 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(msqid_ds_64) == 88, "Incorrect size"); -struct -FEX_ANNOTATE("fex-match") -shminfo_32 { +struct FEX_ANNOTATE("fex-match") shminfo_32 { uint32_t shmmax; uint32_t shmmin; uint32_t shmmni; @@ -1709,10 +1615,7 @@ shminfo_32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(shminfo_32) == 20, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-shminfo64") -FEX_ANNOTATE("fex-match") -shminfo_64 { +struct FEX_ANNOTATE("alias-x86_32-shminfo64") FEX_ANNOTATE("fex-match") shminfo_64 { compat_ulong_t shmmax; compat_ulong_t shmmin; compat_ulong_t shmmni; @@ -1747,10 +1650,7 @@ shminfo_64 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(shminfo_64) == 36, "Incorrect size"); -struct -FEX_ANNOTATE("alias-x86_32-shm_info") -FEX_ANNOTATE("fex-match") -shm_info_32 { +struct FEX_ANNOTATE("alias-x86_32-shm_info") FEX_ANNOTATE("fex-match") shm_info_32 { int used_ids; uint32_t shm_tot; uint32_t shm_rss; @@ -1773,9 +1673,7 @@ shm_info_32 { static_assert(std::is_trivial::value, "Needs to be trivial"); static_assert(sizeof(shm_info_32) == 24, "Incorrect size"); -struct -FEX_ANNOTATE("fex-match") -compat_select_args { +struct FEX_ANNOTATE("fex-match") compat_select_args { int nfds; compat_ptr readfds; compat_ptr writefds; @@ -1788,4 +1686,4 @@ compat_select_args { static_assert(std::is_trivial_v, "Needs to be trivial"); static_assert(sizeof(compat_select_args) == 20, "Incorrect size"); -} +} // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/EPoll.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/EPoll.cpp index 86f3b4065..c2075a3b9 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/EPoll.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/EPoll.cpp @@ -22,12 +22,13 @@ $end_info$ struct timespec; namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x64 { - void RegisterEpoll(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X64(epoll_wait, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, FEX::HLE::epoll_event_x86 *events, int maxevents, int timeout) -> uint64_t { +void RegisterEpoll(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X64( + epoll_wait, [](FEXCore::Core::CpuStateFrame* Frame, int epfd, FEX::HLE::epoll_event_x86* events, int maxevents, int timeout) -> uint64_t { fextl::vector Events(std::max(0, maxevents)); uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevents, timeout, nullptr, 8); @@ -39,63 +40,55 @@ namespace FEX::HLE::x64 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X64(epoll_ctl, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, int op, int fd, FEX::HLE::epoll_event_x86 *event) -> uint64_t { - struct epoll_event Event; - struct epoll_event *EventPtr{}; - if (event) { - Event = *event; - EventPtr = &Event; - } - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_ctl), epfd, op, fd, EventPtr); - if (Result != -1 && event) { - *event = Event; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X64(epoll_pwait, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, FEX::HLE::epoll_event_x86 *events, int maxevent, int timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { - fextl::vector Events(std::max(0, maxevent)); - - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), - epfd, - Events.data(), - maxevent, - timeout, - sigmask, - sigsetsize); - - if (Result != -1) { - for (size_t i = 0; i < Result; ++i) { - events[i] = Events[i]; - } - } - - SYSCALL_ERRNO(); - }); - - if (Handler->IsHostKernelVersionAtLeast(5, 11, 0)) { - REGISTER_SYSCALL_IMPL_X64(epoll_pwait2, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, FEX::HLE::epoll_event_x86 *events, int maxevent, timespec *timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { - fextl::vector Events(std::max(0, maxevent)); - - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait2), - epfd, - Events.data(), - maxevent, - timeout, - sigmask, - sigsetsize); - - if (Result != -1) { - for (size_t i = 0; i < Result; ++i) { - events[i] = Events[i]; - } - } - - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X64(epoll_ctl, [](FEXCore::Core::CpuStateFrame* Frame, int epfd, int op, int fd, FEX::HLE::epoll_event_x86* event) -> uint64_t { + struct epoll_event Event; + struct epoll_event* EventPtr {}; + if (event) { + Event = *event; + EventPtr = &Event; } - else { - REGISTER_SYSCALL_IMPL_X64(epoll_pwait2, UnimplementedSyscallSafe); + uint64_t Result = ::syscall(SYSCALL_DEF(epoll_ctl), epfd, op, fd, EventPtr); + if (Result != -1 && event) { + *event = Event; } + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X64(epoll_pwait, + [](FEXCore::Core::CpuStateFrame* Frame, int epfd, FEX::HLE::epoll_event_x86* events, int maxevent, int timeout, + const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { + fextl::vector Events(std::max(0, maxevent)); + + uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevent, timeout, sigmask, sigsetsize); + + if (Result != -1) { + for (size_t i = 0; i < Result; ++i) { + events[i] = Events[i]; + } + } + + SYSCALL_ERRNO(); + }); + + if (Handler->IsHostKernelVersionAtLeast(5, 11, 0)) { + REGISTER_SYSCALL_IMPL_X64(epoll_pwait2, + [](FEXCore::Core::CpuStateFrame* Frame, int epfd, FEX::HLE::epoll_event_x86* events, int maxevent, + timespec* timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { + fextl::vector Events(std::max(0, maxevent)); + + uint64_t Result = + ::syscall(SYSCALL_DEF(epoll_pwait2), epfd, Events.data(), maxevent, timeout, sigmask, sigsetsize); + + if (Result != -1) { + for (size_t i = 0; i < Result; ++i) { + events[i] = Events[i]; + } + } + + SYSCALL_ERRNO(); + }); + } else { + REGISTER_SYSCALL_IMPL_X64(epoll_pwait2, UnimplementedSyscallSafe); } } +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp index df7ca3803..7710c04ff 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp @@ -28,69 +28,68 @@ $end_info$ #include namespace FEX::HLE::x64 { - void RegisterFD(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X64(poll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, int timeout) -> uint64_t { - uint64_t Result = ::poll(fds, nfds, timeout); - SYSCALL_ERRNO(); - }); +void RegisterFD(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X64(poll, [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, int timeout) -> uint64_t { + uint64_t Result = ::poll(fds, nfds, timeout); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(select, [](FEXCore::Core::CpuStateFrame *Frame, int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) -> uint64_t { + REGISTER_SYSCALL_IMPL_X64( + select, [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout) -> uint64_t { uint64_t Result = ::select(nfds, readfds, writefds, exceptfds, timeout); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X64(fcntl, [](FEXCore::Core::CpuStateFrame *Frame, int fd, int cmd, uint64_t arg) -> uint64_t { - uint64_t Result{}; - switch (cmd) { - case F_GETFL: - Result = ::fcntl(fd, cmd, arg); - if (Result != -1) { - Result = FEX::HLE::RemapToX86Flags(Result); - } - break; - case F_SETFL: - Result = ::fcntl(fd, cmd, FEX::HLE::RemapFromX86Flags(arg)); - break; - default: - Result = ::fcntl(fd, cmd, arg); - break; + REGISTER_SYSCALL_IMPL_X64(fcntl, [](FEXCore::Core::CpuStateFrame* Frame, int fd, int cmd, uint64_t arg) -> uint64_t { + uint64_t Result {}; + switch (cmd) { + case F_GETFL: + Result = ::fcntl(fd, cmd, arg); + if (Result != -1) { + Result = FEX::HLE::RemapToX86Flags(Result); } - SYSCALL_ERRNO(); - }); + break; + case F_SETFL: Result = ::fcntl(fd, cmd, FEX::HLE::RemapFromX86Flags(arg)); break; + default: Result = ::fcntl(fd, cmd, arg); break; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(futimesat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, const struct timeval times[2]) -> uint64_t { + REGISTER_SYSCALL_IMPL_X64( + futimesat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const struct timeval times[2]) -> uint64_t { uint64_t Result = ::syscall(SYSCALL_DEF(futimesat), dirfd, pathname, times); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X64(stat, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, FEX::HLE::x64::guest_stat *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X64(stat, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, FEX::HLE::x64::guest_stat* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(fstat, [](FEXCore::Core::CpuStateFrame *Frame, int fd, FEX::HLE::x64::guest_stat *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = ::fstat(fd, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X64(fstat, [](FEXCore::Core::CpuStateFrame* Frame, int fd, FEX::HLE::x64::guest_stat* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = ::fstat(fd, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(lstat, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, FEX::HLE::x64::guest_stat *buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); - if (Result != -1) { - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X64(lstat, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, FEX::HLE::x64::guest_stat* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); + if (Result != -1) { + *buf = host_stat; + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(newfstatat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, FEX::HLE::x64::guest_stat *buf, int flag) -> uint64_t { + REGISTER_SYSCALL_IMPL_X64( + newfstatat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, FEX::HLE::x64::guest_stat* buf, int flag) -> uint64_t { struct stat host_stat; uint64_t Result = FEX::HLE::_SyscallHandler->FM.NewFSStatAt(dirfd, pathname, &host_stat, flag); if (Result != -1) { @@ -99,18 +98,18 @@ namespace FEX::HLE::x64 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X64(getdents, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *dirp, uint32_t count) -> uint64_t { - return GetDentsEmulation(fd, reinterpret_cast(dirp), count); - }); + REGISTER_SYSCALL_IMPL_X64(getdents, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* dirp, uint32_t count) -> uint64_t { + return GetDentsEmulation(fd, reinterpret_cast(dirp), count); + }); - REGISTER_SYSCALL_IMPL_X64(dup2, [](FEXCore::Core::CpuStateFrame *Frame, int oldfd, int newfd) -> uint64_t { - uint64_t Result = ::dup2(oldfd, newfd); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X64(dup2, [](FEXCore::Core::CpuStateFrame* Frame, int oldfd, int newfd) -> uint64_t { + uint64_t Result = ::dup2(oldfd, newfd); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(statfs, [](FEXCore::Core::CpuStateFrame *Frame, const char *path, struct statfs *buf) -> uint64_t { - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, buf); - SYSCALL_ERRNO(); - }); - } + REGISTER_SYSCALL_IMPL_X64(statfs, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, struct statfs* buf) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, buf); + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Info.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Info.cpp index 9af8b2534..57632063b 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Info.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Info.cpp @@ -15,18 +15,17 @@ $end_info$ #include namespace FEX::HLE::x64 { - void RegisterInfo(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - if (Handler->IsHostKernelVersionAtLeast(6, 6, 0)) { - REGISTER_SYSCALL_IMPL_X64_FLAGS(map_shadow_stack, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, uint64_t addr, uint64_t size, uint32_t flags) -> uint64_t { - // Claim that shadow stack isn't supported. - return -EOPNOTSUPP; - }); - } - else { - REGISTER_SYSCALL_IMPL_X64(map_shadow_stack, UnimplementedSyscallSafe); - } + if (Handler->IsHostKernelVersionAtLeast(6, 6, 0)) { + REGISTER_SYSCALL_IMPL_X64_FLAGS(map_shadow_stack, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, uint64_t addr, uint64_t size, uint32_t flags) -> uint64_t { + // Claim that shadow stack isn't supported. + return -EOPNOTSUPP; + }); + } else { + REGISTER_SYSCALL_IMPL_X64(map_shadow_stack, UnimplementedSyscallSafe); } } +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/HelperDefines.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/HelperDefines.h index 0a1915400..d95088455 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/HelperDefines.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/HelperDefines.h @@ -10,12 +10,16 @@ #ifndef _BASIC_META // Meta typedef variable in unnamed and matches upstream // Use this for the super basic ioctl passthrough path -#define _BASIC_META(x) __attribute__((annotate("fex-match"))) __attribute__((annotate("ioctl-alias-x86_64-_"#x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x]; +#define _BASIC_META(x) \ + __attribute__((annotate("fex-match"))) \ + __attribute__((annotate("ioctl-alias-x86_64-_" #x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x]; #endif #ifndef _BASIC_META_VAR // This is similar to _BASIC_META except that it allows you to pass variadic arguments to the original ioctl definition -#define _BASIC_META_VAR(x, args...) __attribute__((annotate("fex-match"))) __attribute__((annotate("ioctl-alias-x86_64-_"#x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x(args)]; +#define _BASIC_META_VAR(x, args...) \ + __attribute__((annotate("fex-match"))) \ + __attribute__((annotate("ioctl-alias-x86_64-_" #x STRINGY1(__LINE__)))) typedef uint8_t STRINGY(_##x, __LINE__)[x(args)]; #endif #ifndef _CUSTOM_META @@ -25,7 +29,7 @@ // Allows you to effectively pass in the original ioctl definition with custom type replacing the upstream type #define _CUSTOM_META(name, ioctl_num) \ typedef uint8_t _meta_##name[name]; \ - __attribute__((annotate("ioctl-alias-x86_64-_meta_"#name))) typedef uint8_t _##name[ioctl_num]; \ + __attribute__((annotate("ioctl-alias-x86_64-_meta_" #name))) typedef uint8_t _##name[ioctl_num]; \ constexpr static uint32_t FEX_##name = ioctl_num; #endif @@ -45,6 +49,6 @@ // Required to have an ioctl covering a range which some ioctls do #define _CUSTOM_META_OFFSET(name, ioctl_num, offset) \ typedef uint8_t _meta_##name[ioctl_num + offset]; \ - __attribute__((annotate("ioctl-alias-x86_64-_meta_"#name))) typedef uint8_t _##name[ioctl_num + offset]; \ + __attribute__((annotate("ioctl-alias-x86_64-_meta_" #name))) typedef uint8_t _##name[ioctl_num + offset]; \ constexpr static uint32_t FEX_##name = ioctl_num + offset; #endif diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/asound.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/asound.h index ec6e3d92f..51ce8da46 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/asound.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/asound.h @@ -9,13 +9,13 @@ namespace FEX::HLE::x64 { namespace asound { #ifndef SNDRV_TIMER_IOCTL_TREAD_OLD -#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) #endif #ifndef SNDRV_TIMER_IOCTL_TREAD64 -#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) +#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) #endif #include "LinuxSyscalls/x64/Ioctl/asound.inl" -} -} +} // namespace asound +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/drm.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/drm.h index 416c9a040..ae8b0fab6 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/drm.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/drm.h @@ -29,6 +29,6 @@ namespace FEX::HLE::x64 { #include "LinuxSyscalls/x64/Ioctl/amdgpu_drm.inl" #include "LinuxSyscalls/x64/Ioctl/msm_drm.inl" -} +} // namespace FEX::HLE::x64 #undef CPYT #undef CPYF diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/ext_fs.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/ext_fs.h index 8a0dfcefa..e17b7bbad 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/ext_fs.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/ext_fs.h @@ -14,4 +14,4 @@ namespace FEX::HLE::x64 { namespace ext_fs { #include "LinuxSyscalls/x64/Ioctl/ext_fs.inl" } -} +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/f2fs.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/f2fs.h index 1474154ee..d9f6f6f13 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/f2fs.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/f2fs.h @@ -6,16 +6,16 @@ namespace FEX::HLE::x64 { namespace f2fs { -// There is no userspace definitions for these -// Must define everything ourselves -constexpr uint32_t F2FS_IOCTL_MAGIC = 0xf5; + // There is no userspace definitions for these + // Must define everything ourselves + constexpr uint32_t F2FS_IOCTL_MAGIC = 0xf5; #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) -#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) -#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) -#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4) -#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) -#define F2FS_IOC_GARBAGE_COLLECT _IOW(F2FS_IOCTL_MAGIC, 6, uint32_t) -#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7) +#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) +#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) +#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4) +#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) +#define F2FS_IOC_GARBAGE_COLLECT _IOW(F2FS_IOCTL_MAGIC, 6, uint32_t) +#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7) //#define F2FS_IOC_DEFRAGMENT _IOWR(F2FS_IOCTL_MAGIC, 8, \ // struct f2fs_defragment) //#define F2FS_IOC_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \ @@ -24,19 +24,16 @@ constexpr uint32_t F2FS_IOCTL_MAGIC = 0xf5; // struct f2fs_flush_device) //#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ // struct f2fs_gc_range) -#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, uint32_t) -#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, uint32_t) -#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, uint32_t) -#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15) -#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, uint64_t) -#define F2FS_IOC_GET_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 17, uint64_t) -#define F2FS_IOC_RELEASE_COMPRESS_BLOCKS \ - _IOR(F2FS_IOCTL_MAGIC, 18, uint64_t) -#define F2FS_IOC_RESERVE_COMPRESS_BLOCKS \ - _IOR(F2FS_IOCTL_MAGIC, 19, uint64_t) +#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, uint32_t) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, uint32_t) +#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, uint32_t) +#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15) +#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, uint64_t) +#define F2FS_IOC_GET_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 17, uint64_t) +#define F2FS_IOC_RELEASE_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 18, uint64_t) +#define F2FS_IOC_RESERVE_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 19, uint64_t) //#define F2FS_IOC_SEC_TRIM_FILE _IOW(F2FS_IOCTL_MAGIC, 20, \ // struct f2fs_sectrim_range) #include "LinuxSyscalls/x64/Ioctl/f2fs.inl" -} -} - +} // namespace f2fs +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/input.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/input.h index d52904a73..8f6936e71 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/input.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/input.h @@ -9,4 +9,4 @@ namespace FEX::HLE::x64 { namespace input { #include "LinuxSyscalls/x64/Ioctl/input.inl" } -} +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/joystick.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/joystick.h index 6946c75d9..ba9f0b2c7 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/joystick.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/joystick.h @@ -12,4 +12,4 @@ namespace FEX::HLE::x64 { namespace joystick { #include "LinuxSyscalls/x64/Ioctl/joystick.inl" } -} +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/msdos_fs.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/msdos_fs.h index d97a71e14..226adcb5f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/msdos_fs.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/msdos_fs.h @@ -12,4 +12,4 @@ namespace FEX::HLE::x64 { namespace msdos_fs { #include "LinuxSyscalls/x64/Ioctl/msdos_fs.inl" } -} +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/sockios.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/sockios.h index 88f0a5d3e..e3ed93931 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/sockios.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/sockios.h @@ -10,5 +10,4 @@ namespace FEX::HLE::x64 { namespace sockios { #include "LinuxSyscalls/x64/Ioctl/sockios.inl" } -} - +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/wireless.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/wireless.h index b43e7b869..6a0fd4550 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/wireless.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Ioctl/wireless.h @@ -10,4 +10,4 @@ namespace wireless { #include "LinuxSyscalls/x64/Ioctl/wireless.inl" } -} +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Memory.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Memory.cpp index 1dbe51d66..58eef80b0 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Memory.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Memory.cpp @@ -23,68 +23,70 @@ $end_info$ namespace FEX::HLE::x64 { - void *x64SyscallHandler::GuestMmap(FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - uint64_t Result{}; +void* x64SyscallHandler::GuestMmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + uint64_t Result {}; - bool Map32Bit = flags & FEX::HLE::X86_64_MAP_32BIT; - if (Map32Bit) { - Result = (uint64_t)Get32BitAllocator()->Mmap(addr, length, prot,flags, fd, offset); - if (FEX::HLE::HasSyscallError(Result)) { - errno = -Result; - Result = -1; - } - } else { - Result = reinterpret_cast(::mmap(reinterpret_cast(addr), length, prot, flags, fd, offset)); + bool Map32Bit = flags & FEX::HLE::X86_64_MAP_32BIT; + if (Map32Bit) { + Result = (uint64_t)Get32BitAllocator()->Mmap(addr, length, prot, flags, fd, offset); + if (FEX::HLE::HasSyscallError(Result)) { + errno = -Result; + Result = -1; } - - if (Result != -1) { - FEX::HLE::_SyscallHandler->TrackMmap(Thread, (uintptr_t)Result, length, prot, flags, fd, offset); - } - - return reinterpret_cast(Result); + } else { + Result = reinterpret_cast(::mmap(reinterpret_cast(addr), length, prot, flags, fd, offset)); } - int x64SyscallHandler::GuestMunmap(FEXCore::Core::InternalThreadState *Thread, void *addr, uint64_t length) { - uint64_t Result{}; - if (reinterpret_cast(addr) < 0x1'0000'0000ULL) { - Result = Get32BitAllocator()->Munmap(addr, length); - - if (FEX::HLE::HasSyscallError(Result)) { - errno = -Result; - Result = -1; - } - } else { - Result = ::munmap(addr, length); - } - - if (Result != -1) { - FEX::HLE::_SyscallHandler->TrackMunmap(Thread, reinterpret_cast(addr), length); - } - - return Result; + if (Result != -1) { + FEX::HLE::_SyscallHandler->TrackMmap(Thread, (uintptr_t)Result, length, prot, flags, fd, offset); } - void RegisterMemory(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; + return reinterpret_cast(Result); +} - REGISTER_SYSCALL_IMPL_X64_FLAGS(mmap, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length, int prot, int flags, int fd, off_t offset) -> uint64_t { - uint64_t Result = (uint64_t) static_cast(FEX::HLE::_SyscallHandler)-> - GuestMmap(Frame->Thread, addr, length, prot, flags, fd, offset); +int x64SyscallHandler::GuestMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, uint64_t length) { + uint64_t Result {}; + if (reinterpret_cast(addr) < 0x1'0000'0000ULL) { + Result = Get32BitAllocator()->Munmap(addr, length); - SYSCALL_ERRNO(); - }); + if (FEX::HLE::HasSyscallError(Result)) { + errno = -Result; + Result = -1; + } + } else { + Result = ::munmap(addr, length); + } - REGISTER_SYSCALL_IMPL_X64_FLAGS(munmap, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length) -> uint64_t { - uint64_t Result = static_cast(FEX::HLE::_SyscallHandler)-> - GuestMunmap(Frame->Thread, addr, length); + if (Result != -1) { + FEX::HLE::_SyscallHandler->TrackMunmap(Thread, reinterpret_cast(addr), length); + } + + return Result; +} + +void RegisterMemory(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; + + REGISTER_SYSCALL_IMPL_X64_FLAGS( + mmap, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, void* addr, size_t length, int prot, int flags, int fd, off_t offset) -> uint64_t { + uint64_t Result = (uint64_t) static_cast(FEX::HLE::_SyscallHandler) + ->GuestMmap(Frame->Thread, addr, length, prot, flags, fd, offset); SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X64_FLAGS(mremap, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) -> uint64_t { + REGISTER_SYSCALL_IMPL_X64_FLAGS( + munmap, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, void* addr, size_t length) -> uint64_t { + uint64_t Result = static_cast(FEX::HLE::_SyscallHandler)->GuestMunmap(Frame->Thread, addr, length); + + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL_X64_FLAGS( + mremap, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) -> uint64_t { uint64_t Result = reinterpret_cast(::mremap(old_address, old_size, new_size, flags, new_address)); if (Result != -1) { @@ -93,34 +95,34 @@ namespace FEX::HLE::x64 { SYSCALL_ERRNO(); }); - REGISTER_SYSCALL_IMPL_X64_FLAGS(mprotect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t len, int prot) -> uint64_t { - uint64_t Result = ::mprotect(addr, len, prot); + REGISTER_SYSCALL_IMPL_X64_FLAGS(mprotect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, void* addr, size_t len, int prot) -> uint64_t { + uint64_t Result = ::mprotect(addr, len, prot); - if (Result != -1) { - FEX::HLE::_SyscallHandler->TrackMprotect(Frame->Thread, (uintptr_t)addr, len, prot); - } - SYSCALL_ERRNO(); - }); + if (Result != -1) { + FEX::HLE::_SyscallHandler->TrackMprotect(Frame->Thread, (uintptr_t)addr, len, prot); + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64_FLAGS(shmat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, int shmid, const void *shmaddr, int shmflg) -> uint64_t { - uint64_t Result = reinterpret_cast(shmat(shmid, shmaddr, shmflg)); + REGISTER_SYSCALL_IMPL_X64_FLAGS(shmat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, int shmid, const void* shmaddr, int shmflg) -> uint64_t { + uint64_t Result = reinterpret_cast(shmat(shmid, shmaddr, shmflg)); - if (Result != -1) { - FEX::HLE::_SyscallHandler->TrackShmat(Frame->Thread, shmid, Result, shmflg); - } - SYSCALL_ERRNO(); - }); + if (Result != -1) { + FEX::HLE::_SyscallHandler->TrackShmat(Frame->Thread, shmid, Result, shmflg); + } + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64_FLAGS(shmdt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, - [](FEXCore::Core::CpuStateFrame *Frame, const void *shmaddr) -> uint64_t { - uint64_t Result = ::shmdt(shmaddr); + REGISTER_SYSCALL_IMPL_X64_FLAGS(shmdt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, const void* shmaddr) -> uint64_t { + uint64_t Result = ::shmdt(shmaddr); - if (Result != -1) { - FEX::HLE::_SyscallHandler->TrackShmdt(Frame->Thread, (uintptr_t)shmaddr); - } - SYSCALL_ERRNO(); - }); - } + if (Result != -1) { + FEX::HLE::_SyscallHandler->TrackShmdt(Frame->Thread, (uintptr_t)shmaddr); + } + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/NotImplemented.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/NotImplemented.cpp index 4e7e80d74..b9d30b535 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/NotImplemented.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/NotImplemented.cpp @@ -13,26 +13,26 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } namespace FEX::HLE::x64 { -#define REGISTER_SYSCALL_NOT_IMPL_X64(name) REGISTER_SYSCALL_IMPL_X64(name, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { \ - LogMan::Msg::DFmt("Using deprecated/removed syscall: " #name); \ - return -ENOSYS; \ -}); -#define REGISTER_SYSCALL_NO_PERM_X64(name) REGISTER_SYSCALL_IMPL_X64(name, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t { \ - return -EPERM; \ -}); +#define REGISTER_SYSCALL_NOT_IMPL_X64(name) \ + REGISTER_SYSCALL_IMPL_X64(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { \ + LogMan::Msg::DFmt("Using deprecated/removed syscall: " #name); \ + return -ENOSYS; \ + }); +#define REGISTER_SYSCALL_NO_PERM_X64(name) \ + REGISTER_SYSCALL_IMPL_X64(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -EPERM; }); - // these are removed/not implemented in the linux kernel we present - void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_NOT_IMPL_X64(tuxcall); - REGISTER_SYSCALL_NOT_IMPL_X64(security); - REGISTER_SYSCALL_NOT_IMPL_X64(set_thread_area); - REGISTER_SYSCALL_NOT_IMPL_X64(get_thread_area); - REGISTER_SYSCALL_NOT_IMPL_X64(epoll_ctl_old); - REGISTER_SYSCALL_NOT_IMPL_X64(epoll_wait_old); - REGISTER_SYSCALL_NO_PERM_X64(kexec_file_load); - } +// these are removed/not implemented in the linux kernel we present +void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_NOT_IMPL_X64(tuxcall); + REGISTER_SYSCALL_NOT_IMPL_X64(security); + REGISTER_SYSCALL_NOT_IMPL_X64(set_thread_area); + REGISTER_SYSCALL_NOT_IMPL_X64(get_thread_area); + REGISTER_SYSCALL_NOT_IMPL_X64(epoll_ctl_old); + REGISTER_SYSCALL_NOT_IMPL_X64(epoll_wait_old); + REGISTER_SYSCALL_NO_PERM_X64(kexec_file_load); } +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Semaphore.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Semaphore.cpp index 3acacb4a5..7465d0f22 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Semaphore.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Semaphore.cpp @@ -16,67 +16,63 @@ $end_info$ #include namespace FEXCore::Core { - struct CpuStateFrame; +struct CpuStateFrame; } ARG_TO_STR(FEX::HLE::x64::semun, "%lx") namespace FEX::HLE::x64 { - void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X64(semctl, [](FEXCore::Core::CpuStateFrame *Frame, int semid, int semnum, int cmd, FEX::HLE::x64::semun semun) -> uint64_t { - uint64_t Result{}; - switch (cmd) { - case IPC_SET: { - struct semid64_ds buf{}; - buf = *semun.buf; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - *semun.buf = buf; - } - break; - } - case SEM_STAT: - case SEM_STAT_ANY: - case IPC_STAT: { - struct semid64_ds buf{}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - *semun.buf = buf; - } - break; - } - case SEM_INFO: - case IPC_INFO: { - struct fex_seminfo si{}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); - if (Result != -1) { - memcpy(semun.__buf, &si, sizeof(si)); - } - break; - } - case GETALL: - case SETALL: { - // ptr is just a int32_t* in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun.array); - break; - } - case SETVAL: { - // ptr is just a int32_t in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun.val); - break; - } - case IPC_RMID: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETVAL: - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun); - break; - default: - LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); - return -EINVAL; +void RegisterSemaphore(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X64(semctl, [](FEXCore::Core::CpuStateFrame* Frame, int semid, int semnum, int cmd, FEX::HLE::x64::semun semun) -> uint64_t { + uint64_t Result {}; + switch (cmd) { + case IPC_SET: { + struct semid64_ds buf {}; + buf = *semun.buf; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { + *semun.buf = buf; } - SYSCALL_ERRNO(); - }); - } + break; + } + case SEM_STAT: + case SEM_STAT_ANY: + case IPC_STAT: { + struct semid64_ds buf {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { + *semun.buf = buf; + } + break; + } + case SEM_INFO: + case IPC_INFO: { + struct fex_seminfo si {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); + if (Result != -1) { + memcpy(semun.__buf, &si, sizeof(si)); + } + break; + } + case GETALL: + case SETALL: { + // ptr is just a int32_t* in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun.array); + break; + } + case SETVAL: { + // ptr is just a int32_t in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun.val); + break; + } + case IPC_RMID: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETVAL: Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun); break; + default: LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); return -EINVAL; + } + SYSCALL_ERRNO(); + }); } +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Signals.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Signals.cpp index 85400a700..30737c7e3 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Signals.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Signals.cpp @@ -19,8 +19,9 @@ $end_info$ #include namespace FEX::HLE::x64 { - void RegisterSignals(FEX::HLE::SyscallHandler *Handler) { - REGISTER_SYSCALL_IMPL_X64(rt_sigaction, [](FEXCore::Core::CpuStateFrame *Frame, int signum, const GuestSigAction *act, GuestSigAction *oldact, size_t sigsetsize) -> uint64_t { +void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X64( + rt_sigaction, [](FEXCore::Core::CpuStateFrame* Frame, int signum, const GuestSigAction* act, GuestSigAction* oldact, size_t sigsetsize) -> uint64_t { if (sigsetsize != 8) { return -EINVAL; } @@ -28,9 +29,10 @@ namespace FEX::HLE::x64 { return FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, act, oldact); }); - REGISTER_SYSCALL_IMPL_X64(rt_sigtimedwait, [](FEXCore::Core::CpuStateFrame *Frame, uint64_t *set, siginfo_t *info, const struct timespec* timeout, size_t sigsetsize) -> uint64_t { + REGISTER_SYSCALL_IMPL_X64( + rt_sigtimedwait, + [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, siginfo_t* info, const struct timespec* timeout, size_t sigsetsize) -> uint64_t { return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, info, timeout, sigsetsize); }); - } } - +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.cpp index 64f58588c..7d71a8a3e 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.cpp @@ -12,92 +12,92 @@ $end_info$ #include namespace FEX::HLE::x64 { - void RegisterEpoll(FEX::HLE::SyscallHandler *Handler); - void RegisterFD(FEX::HLE::SyscallHandler *Handler); - void RegisterInfo(FEX::HLE::SyscallHandler *Handler); - void RegisterMemory(FEX::HLE::SyscallHandler *Handler); - void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler); - void RegisterSignals(FEX::HLE::SyscallHandler *Handler); - void RegisterThread(FEX::HLE::SyscallHandler *Handler); - void RegisterTime(FEX::HLE::SyscallHandler *Handler); - void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler); - void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler); +void RegisterEpoll(FEX::HLE::SyscallHandler* Handler); +void RegisterFD(FEX::HLE::SyscallHandler* Handler); +void RegisterInfo(FEX::HLE::SyscallHandler* Handler); +void RegisterMemory(FEX::HLE::SyscallHandler* Handler); +void RegisterSemaphore(FEX::HLE::SyscallHandler* Handler); +void RegisterSignals(FEX::HLE::SyscallHandler* Handler); +void RegisterThread(FEX::HLE::SyscallHandler* Handler); +void RegisterTime(FEX::HLE::SyscallHandler* Handler); +void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler); +void RegisterPassthrough(FEX::HLE::SyscallHandler* Handler); - x64SyscallHandler::x64SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) - : SyscallHandler {ctx, _SignalDelegation} { - OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX64; +x64SyscallHandler::x64SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation) + : SyscallHandler {ctx, _SignalDelegation} { + OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX64; - RegisterSyscallHandlers(); - } + RegisterSyscallHandlers(); +} - void x64SyscallHandler::RegisterSyscallHandlers() { - auto cvt = [](auto in) { - union { - decltype(in) val; - void *raw; - } raw; - raw.val = in; - return raw.raw; - }; +void x64SyscallHandler::RegisterSyscallHandlers() { + auto cvt = [](auto in) { + union { + decltype(in) val; + void* raw; + } raw; + raw.val = in; + return raw.raw; + }; - Definitions.resize(FEX::HLE::x64::SYSCALL_x64_MAX, SyscallFunctionDefinition { - .NumArgs = 255, - .Ptr = cvt(&UnimplementedSyscall), - }); + Definitions.resize(FEX::HLE::x64::SYSCALL_x64_MAX, SyscallFunctionDefinition { + .NumArgs = 255, + .Ptr = cvt(&UnimplementedSyscall), + }); - FEX::HLE::RegisterEpoll(this); - FEX::HLE::RegisterFD(this); - FEX::HLE::RegisterFS(this); - FEX::HLE::RegisterInfo(this); - FEX::HLE::RegisterIO(this); - FEX::HLE::RegisterMemory(this); - FEX::HLE::RegisterSignals(this); - FEX::HLE::RegisterThread(this); - FEX::HLE::RegisterTimer(this); - FEX::HLE::RegisterNotImplemented(this); - FEX::HLE::RegisterStubs(this); + FEX::HLE::RegisterEpoll(this); + FEX::HLE::RegisterFD(this); + FEX::HLE::RegisterFS(this); + FEX::HLE::RegisterInfo(this); + FEX::HLE::RegisterIO(this); + FEX::HLE::RegisterMemory(this); + FEX::HLE::RegisterSignals(this); + FEX::HLE::RegisterThread(this); + FEX::HLE::RegisterTimer(this); + FEX::HLE::RegisterNotImplemented(this); + FEX::HLE::RegisterStubs(this); - // 64bit specific - FEX::HLE::x64::RegisterEpoll(this); - FEX::HLE::x64::RegisterFD(this); - FEX::HLE::x64::RegisterInfo(this); - FEX::HLE::x64::RegisterMemory(this); - FEX::HLE::x64::RegisterSemaphore(this); - FEX::HLE::x64::RegisterSignals(this); - FEX::HLE::x64::RegisterThread(this); - FEX::HLE::x64::RegisterTime(this); - FEX::HLE::x64::RegisterNotImplemented(this); - FEX::HLE::x64::RegisterPassthrough(this); + // 64bit specific + FEX::HLE::x64::RegisterEpoll(this); + FEX::HLE::x64::RegisterFD(this); + FEX::HLE::x64::RegisterInfo(this); + FEX::HLE::x64::RegisterMemory(this); + FEX::HLE::x64::RegisterSemaphore(this); + FEX::HLE::x64::RegisterSignals(this); + FEX::HLE::x64::RegisterThread(this); + FEX::HLE::x64::RegisterTime(this); + FEX::HLE::x64::RegisterNotImplemented(this); + FEX::HLE::x64::RegisterPassthrough(this); - // x86-64 has a gap of syscalls in the range of [335, 424) where there aren't any - // These are defined that these must return -ENOSYS - // This allows x86-64 to start using the common syscall numbers - // Fill the gap to ensure that FEX doesn't assert - constexpr int SYSCALL_GAP_BEGIN = 335; - constexpr int SYSCALL_GAP_END = 424; - for (int SyscallNumber = SYSCALL_GAP_BEGIN; SyscallNumber < SYSCALL_GAP_END; ++SyscallNumber) { - auto &Def = Definitions.at(SyscallNumber); - Def.Ptr = cvt(&UnimplementedSyscallSafe); - Def.NumArgs = 0; - Def.Flags = FEXCore::IR::SyscallFlags::DEFAULT; - // This will allow our syscall optimization code to make this code more optimal - // Unlikely to hit a hot path though - Def.HostSyscallNumber = SYSCALL_DEF(MAX); + // x86-64 has a gap of syscalls in the range of [335, 424) where there aren't any + // These are defined that these must return -ENOSYS + // This allows x86-64 to start using the common syscall numbers + // Fill the gap to ensure that FEX doesn't assert + constexpr int SYSCALL_GAP_BEGIN = 335; + constexpr int SYSCALL_GAP_END = 424; + for (int SyscallNumber = SYSCALL_GAP_BEGIN; SyscallNumber < SYSCALL_GAP_END; ++SyscallNumber) { + auto& Def = Definitions.at(SyscallNumber); + Def.Ptr = cvt(&UnimplementedSyscallSafe); + Def.NumArgs = 0; + Def.Flags = FEXCore::IR::SyscallFlags::DEFAULT; + // This will allow our syscall optimization code to make this code more optimal + // Unlikely to hit a hot path though + Def.HostSyscallNumber = SYSCALL_DEF(MAX); #ifdef DEBUG_STRACE - Def.StraceFmt = "Invalid"; + Def.StraceFmt = "Invalid"; #endif - } + } #if PRINT_MISSING_SYSCALLS - for (auto &Syscall: SyscallNames) { - if (Definitions[Syscall.first].Ptr == cvt(&UnimplementedSyscall)) { - LogMan::Msg::DFmt("Unimplemented syscall: {}", Syscall.second); - } + for (auto& Syscall : SyscallNames) { + if (Definitions[Syscall.first].Ptr == cvt(&UnimplementedSyscall)) { + LogMan::Msg::DFmt("Unimplemented syscall: {}", Syscall.second); } + } #endif - } - - fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) { - return fextl::make_unique(ctx, _SignalDelegation); - } } + +fextl::unique_ptr CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation) { + return fextl::make_unique(ctx, _SignalDelegation); +} +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.h index 1f341a35e..117c8f006 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.h @@ -23,7 +23,7 @@ $end_info$ namespace FEX::HLE { class SignalDelegator; class SyscallHandler; -} +} // namespace FEX::HLE namespace FEXCore::Core { struct InternalThreadState; @@ -31,26 +31,24 @@ struct InternalThreadState; namespace FEX::HLE::x64 { class x64SyscallHandler final : public FEX::HLE::SyscallHandler { - public: - x64SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation); +public: + x64SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation); - void *GuestMmap(FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset) override; - int GuestMunmap(FEXCore::Core::InternalThreadState *Thread, void *addr, uint64_t length) override; + void* GuestMmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length, int prot, int flags, int fd, off_t offset) override; + int GuestMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, uint64_t length) override; - void RegisterSyscall_64(int SyscallNumber, - int32_t HostSyscallNumber, - FEXCore::IR::SyscallFlags Flags, + void RegisterSyscall_64(int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, #ifdef DEBUG_STRACE - const fextl::string& TraceFormatString, + const fextl::string& TraceFormatString, #endif - void* SyscallHandler, int ArgumentCount) override { - auto &Def = Definitions.at(SyscallNumber); + void* SyscallHandler, int ArgumentCount) override { + auto& Def = Definitions.at(SyscallNumber); #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED auto cvt = [](auto in) { union { decltype(in) val; - void *raw; + void* raw; } raw; raw.val = in; return raw.raw; @@ -66,11 +64,11 @@ class x64SyscallHandler final : public FEX::HLE::SyscallHandler { #endif } - private: - void RegisterSyscallHandlers(); +private: + void RegisterSyscallHandlers(); }; -fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation); +fextl::unique_ptr CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation); ////// // REGISTER_SYSCALL_IMPL implementation @@ -81,42 +79,38 @@ fextl::unique_ptr CreateHandler(FEXCore::Context::Cont // RegisterSyscall base // Deduces return, args... from the function passed // Does not work with lambas, because they are objects with operator (), not functions -template -void RegisterSyscall(SyscallHandler *Handler, int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, const char *Name, R(*fn)(FEXCore::Core::CpuStateFrame *Frame, Args...)) { +template +void RegisterSyscall(SyscallHandler* Handler, int SyscallNumber, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, + const char* Name, R (*fn)(FEXCore::Core::CpuStateFrame* Frame, Args...)) { #ifdef DEBUG_STRACE auto TraceFormatString = fextl::string(Name) + "(" + CollectArgsFmtString() + ") = %ld"; #endif - Handler->RegisterSyscall_64(SyscallNumber, - HostSyscallNumber, - Flags, + Handler->RegisterSyscall_64(SyscallNumber, HostSyscallNumber, Flags, #ifdef DEBUG_STRACE - TraceFormatString, + TraceFormatString, #endif - reinterpret_cast(fn), sizeof...(Args)); + reinterpret_cast(fn), sizeof...(Args)); } // Generic RegisterSyscall for lambdas // Non-capturing lambdas can be cast to function pointers, but this does not happen on argument matching // This is some glue logic that will cast a lambda and call the base RegisterSyscall implementation template -void RegisterSyscall(SyscallHandler *_Handler, int num, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, const char *name, F f){ +void RegisterSyscall(SyscallHandler* _Handler, int num, int32_t HostSyscallNumber, FEXCore::IR::SyscallFlags Flags, const char* name, F f) { RegisterSyscall(_Handler, num, HostSyscallNumber, Flags, name, +f); } -} +} // namespace FEX::HLE::x64 // Registers syscall for 64bit only -#define REGISTER_SYSCALL_IMPL_X64(name, lambda) \ - REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, ~0, FEXCore::IR::SyscallFlags::DEFAULT, lambda) +#define REGISTER_SYSCALL_IMPL_X64(name, lambda) REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, ~0, FEXCore::IR::SyscallFlags::DEFAULT, lambda) #define REGISTER_SYSCALL_IMPL_X64_PASS(name, lambda) \ REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, SYSCALL_DEF(name), FEXCore::IR::SyscallFlags::DEFAULT, lambda) -#define REGISTER_SYSCALL_IMPL_X64_FLAGS(name, flags, lambda) \ - REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, ~0, flags, lambda) +#define REGISTER_SYSCALL_IMPL_X64_FLAGS(name, flags, lambda) REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, ~0, flags, lambda) -#define REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(name, flags, lambda) \ - REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, SYSCALL_DEF(name), flags, lambda) +#define REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(name, flags, lambda) REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, SYSCALL_DEF(name), flags, lambda) #define REGISTER_SYSCALL_IMPL_X64_INTERNAL(name, number, flags, lambda) \ do { \ diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h index 65548a5d2..ea692f990 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h @@ -489,4 +489,4 @@ enum Syscalls_x64 { SYSCALL_x64_futex_time64 = ~0, SYSCALL_x64_sched_rr_get_interval_time64 = ~0, }; -} +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp index a650a36cc..de35d3f79 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp @@ -24,76 +24,79 @@ $end_info$ #include namespace FEX::HLE::x64 { - uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame *Frame, void *tls) { - Frame->State.fs_cached = reinterpret_cast(tls); - return 0; - } +uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame* Frame, void* tls) { + Frame->State.fs_cached = reinterpret_cast(tls); + return 0; +} - void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame *Frame) { - Frame->State.rip += 2; - } +void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame* Frame) { + Frame->State.rip += 2; +} - void RegisterThread(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; +void RegisterThread(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_X64_FLAGS(clone, SyscallFlags::DEFAULT, - ([](FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls) -> uint64_t { + REGISTER_SYSCALL_IMPL_X64_FLAGS( + clone, SyscallFlags::DEFAULT, + ([](FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack, pid_t* parent_tid, pid_t* child_tid, void* tls) -> uint64_t { FEX::HLE::clone3_args args { .Type = TypeOfClone::TYPE_CLONE2, - .args = { - .flags = flags, // CSIGNAL is contained in here - .pidfd = 0, // For clone, pidfd is duplicated here - .child_tid = reinterpret_cast(child_tid), - .parent_tid = reinterpret_cast(parent_tid), - .exit_signal = flags & CSIGNAL, - .stack = reinterpret_cast(stack), - .stack_size = 0, // This syscall isn't able to see the stack size - .tls = reinterpret_cast(tls), - .set_tid = 0, // This syscall isn't able to select TIDs - .set_tid_size = 0, - .cgroup = 0, // This syscall can't select cgroups - }, + .args = + { + .flags = flags, // CSIGNAL is contained in here + .pidfd = 0, // For clone, pidfd is duplicated here + .child_tid = reinterpret_cast(child_tid), + .parent_tid = reinterpret_cast(parent_tid), + .exit_signal = flags & CSIGNAL, + .stack = reinterpret_cast(stack), + .stack_size = 0, // This syscall isn't able to see the stack size + .tls = reinterpret_cast(tls), + .set_tid = 0, // This syscall isn't able to select TIDs + .set_tid_size = 0, + .cgroup = 0, // This syscall can't select cgroups + }, }; return CloneHandler(Frame, &args); })); - REGISTER_SYSCALL_IMPL_X64(sigaltstack, [](FEXCore::Core::CpuStateFrame *Frame, const stack_t *ss, stack_t *old_ss) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack(ss, old_ss); - }); + REGISTER_SYSCALL_IMPL_X64(sigaltstack, [](FEXCore::Core::CpuStateFrame* Frame, const stack_t* ss, stack_t* old_ss) -> uint64_t { + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack(ss, old_ss); + }); - // launch a new process under fex - // currently does not propagate argv[0] correctly - REGISTER_SYSCALL_IMPL_X64_FLAGS(execve, SyscallFlags::DEFAULT, - [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, char *const argv[], char *const envp[]) -> uint64_t { - fextl::vector Args; - fextl::vector Envp; + // launch a new process under fex + // currently does not propagate argv[0] correctly + REGISTER_SYSCALL_IMPL_X64_FLAGS(execve, SyscallFlags::DEFAULT, + [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, char* const argv[], char* const envp[]) -> uint64_t { + fextl::vector Args; + fextl::vector Envp; - if (argv) { - for (int i = 0; argv[i]; i++) { - Args.push_back(argv[i]); - } + if (argv) { + for (int i = 0; argv[i]; i++) { + Args.push_back(argv[i]); + } - Args.push_back(nullptr); - } + Args.push_back(nullptr); + } - if (envp) { - for (int i = 0; envp[i]; i++) { - Envp.push_back(envp[i]); - } + if (envp) { + for (int i = 0; envp[i]; i++) { + Envp.push_back(envp[i]); + } - Envp.push_back(nullptr); - } + Envp.push_back(nullptr); + } - auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; - auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; + auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; + auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; - FEX::HLE::ExecveAtArgs AtArgs = FEX::HLE::ExecveAtArgs::Empty(); + FEX::HLE::ExecveAtArgs AtArgs = FEX::HLE::ExecveAtArgs::Empty(); - return FEX::HLE::ExecveHandler(pathname, ArgsPtr, EnvpPtr, AtArgs); - }); + return FEX::HLE::ExecveHandler(pathname, ArgsPtr, EnvpPtr, AtArgs); + }); - REGISTER_SYSCALL_IMPL_X64_FLAGS(execveat, SyscallFlags::DEFAULT, - ([](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, char *const argv[], char *const envp[], int flags) -> uint64_t { + REGISTER_SYSCALL_IMPL_X64_FLAGS( + execveat, SyscallFlags::DEFAULT, + ([](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, char* const argv[], char* const envp[], int flags) -> uint64_t { fextl::vector Args; fextl::vector Envp; @@ -122,5 +125,5 @@ namespace FEX::HLE::x64 { auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; return FEX::HLE::ExecveHandler(pathname, ArgsPtr, EnvpPtr, AtArgs); })); - } } +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.h index 64032f90e..7bb595584 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.h @@ -13,6 +13,6 @@ struct CpuStateFrame; } namespace FEX::HLE::x64 { - uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame *Frame, void *tls); - void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame *Frame); -} +uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame* Frame, void* tls); +void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame* Frame); +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Time.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Time.cpp index 0a76700de..4a9e81951 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Time.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Time.cpp @@ -20,22 +20,22 @@ $end_info$ #include namespace FEX::HLE::x64 { - void RegisterTime(FEX::HLE::SyscallHandler *Handler) { - using namespace FEXCore::IR; - REGISTER_SYSCALL_IMPL_X64_FLAGS(time, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, [](FEXCore::Core::CpuStateFrame *Frame, time_t *tloc) -> uint64_t { - uint64_t Result = ::time(tloc); - SYSCALL_ERRNO(); - }); +void RegisterTime(FEX::HLE::SyscallHandler* Handler) { + using namespace FEXCore::IR; + REGISTER_SYSCALL_IMPL_X64_FLAGS(time, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, time_t* tloc) -> uint64_t { + uint64_t Result = ::time(tloc); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(utime, [](FEXCore::Core::CpuStateFrame *Frame, char* filename, const struct utimbuf* times) -> uint64_t { - uint64_t Result = ::utime(filename, times); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X64(utime, [](FEXCore::Core::CpuStateFrame* Frame, char* filename, const struct utimbuf* times) -> uint64_t { + uint64_t Result = ::utime(filename, times); + SYSCALL_ERRNO(); + }); - REGISTER_SYSCALL_IMPL_X64(utimes, [](FEXCore::Core::CpuStateFrame *Frame, const char *filename, const struct timeval times[2]) -> uint64_t { - uint64_t Result = ::utimes(filename, times); - SYSCALL_ERRNO(); - }); - } + REGISTER_SYSCALL_IMPL_X64(utimes, [](FEXCore::Core::CpuStateFrame* Frame, const char* filename, const struct timeval times[2]) -> uint64_t { + uint64_t Result = ::utimes(filename, times); + SYSCALL_ERRNO(); + }); } - +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Types.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Types.h index 6917158c1..6544eeeb2 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Types.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Types.h @@ -23,122 +23,116 @@ using kernel_old_time_t = int64_t; using kernel_ulong_t = uint64_t; using __time_t = time_t; - struct ipc_perm_64 { - uint32_t key; - uint32_t uid; - uint32_t gid; - uint32_t cuid; - uint32_t cgid; - uint16_t mode; - uint16_t _pad1; - uint16_t seq; - uint16_t _pad2; - kernel_ulong_t _pad[2]; +struct ipc_perm_64 { + uint32_t key; + uint32_t uid; + uint32_t gid; + uint32_t cuid; + uint32_t cgid; + uint16_t mode; + uint16_t _pad1; + uint16_t seq; + uint16_t _pad2; + kernel_ulong_t _pad[2]; - ipc_perm_64() = delete; + ipc_perm_64() = delete; - operator struct ipc64_perm() const { - struct ipc64_perm perm; - perm.key = key; - perm.uid = uid; - perm.gid = gid; - perm.cuid = cuid; - perm.cgid = cgid; - perm.mode = mode; - perm.seq = seq; - return perm; - } + operator struct ipc64_perm() const { + struct ipc64_perm perm; + perm.key = key; + perm.uid = uid; + perm.gid = gid; + perm.cuid = cuid; + perm.cgid = cgid; + perm.mode = mode; + perm.seq = seq; + return perm; + } - ipc_perm_64(struct ipc64_perm perm) { - key = perm.key; - uid = perm.uid; - gid = perm.gid; - cuid = perm.cuid; - cgid = perm.cgid; - mode = perm.mode; - seq = perm.seq; - } - }; + ipc_perm_64(struct ipc64_perm perm) { + key = perm.key; + uid = perm.uid; + gid = perm.gid; + cuid = perm.cuid; + cgid = perm.cgid; + mode = perm.mode; + seq = perm.seq; + } +}; - static_assert(std::is_trivial::value, "Needs to be trivial"); - static_assert(sizeof(ipc_perm_64) == 48, "Incorrect size"); +static_assert(std::is_trivial::value, "Needs to be trivial"); +static_assert(sizeof(ipc_perm_64) == 48, "Incorrect size"); - // Matches the definition x86/include/uapi/asm/sembuf.h - struct - FEX_ANNOTATE("alias-x86_64-semid64_ds") - FEX_ANNOTATE("fex-match") - semid_ds_64 { - FEX::HLE::x64::ipc_perm_64 sem_perm; - time_t sem_otime; - uint64_t __unused1; - time_t sem_ctime; - uint64_t __unused2; - uint64_t sem_nsems; - uint64_t __unused3; - uint64_t __unused4; +// Matches the definition x86/include/uapi/asm/sembuf.h +struct FEX_ANNOTATE("alias-x86_64-semid64_ds") FEX_ANNOTATE("fex-match") semid_ds_64 { + FEX::HLE::x64::ipc_perm_64 sem_perm; + time_t sem_otime; + uint64_t __unused1; + time_t sem_ctime; + uint64_t __unused2; + uint64_t sem_nsems; + uint64_t __unused3; + uint64_t __unused4; - semid_ds_64() = delete; + semid_ds_64() = delete; - operator struct semid64_ds() const { - struct semid64_ds buf{}; - buf.sem_perm = sem_perm; + operator struct semid64_ds() const { + struct semid64_ds buf {}; + buf.sem_perm = sem_perm; - buf.sem_otime = sem_otime; - buf.sem_ctime = sem_ctime; - buf.sem_nsems = sem_nsems; - return buf; - } + buf.sem_otime = sem_otime; + buf.sem_ctime = sem_ctime; + buf.sem_nsems = sem_nsems; + return buf; + } - semid_ds_64(struct semid64_ds buf) - : sem_perm {buf.sem_perm} { - sem_otime = buf.sem_otime; - sem_ctime = buf.sem_ctime; - sem_nsems = buf.sem_nsems; - } - }; + semid_ds_64(struct semid64_ds buf) + : sem_perm {buf.sem_perm} { + sem_otime = buf.sem_otime; + sem_ctime = buf.sem_ctime; + sem_nsems = buf.sem_nsems; + } +}; - static_assert(std::is_trivial::value, "Needs to be trivial"); - static_assert(sizeof(FEX::HLE::x64::semid_ds_64) == 104, "Incorrect size"); +static_assert(std::is_trivial::value, "Needs to be trivial"); +static_assert(sizeof(FEX::HLE::x64::semid_ds_64) == 104, "Incorrect size"); - union semun { - int val; - FEX::HLE::x64::semid_ds_64 *buf; - unsigned short *array; - struct fex_seminfo *__buf; - void *__pad; - }; +union semun { + int val; + FEX::HLE::x64::semid_ds_64* buf; + unsigned short* array; + struct fex_seminfo* __buf; + void* __pad; +}; - static_assert(std::is_trivial::value, "Needs to be trivial"); - static_assert(sizeof(FEX::HLE::x64::semun) == 8, "Incorrect size"); +static_assert(std::is_trivial::value, "Needs to be trivial"); +static_assert(sizeof(FEX::HLE::x64::semun) == 8, "Incorrect size"); - struct - FEX_ANNOTATE("fex-match") - FEX_PACKED - guest_stat { - uint64_t st_dev; - uint64_t st_ino; - uint64_t st_nlink; +struct FEX_ANNOTATE("fex-match") FEX_PACKED guest_stat { + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_nlink; - unsigned int st_mode; - unsigned int st_uid; - unsigned int st_gid; - unsigned int __pad0; - uint64_t st_rdev; - int64_t st_size; - int64_t st_blksize; - int64_t st_blocks; /* Number 512-byte blocks allocated. */ + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad0; + uint64_t st_rdev; + int64_t st_size; + int64_t st_blksize; + int64_t st_blocks; /* Number 512-byte blocks allocated. */ - uint64_t st_atime_; - uint64_t fex_st_atime_nsec; - uint64_t st_mtime_; - uint64_t fex_st_mtime_nsec; - uint64_t st_ctime_; - uint64_t fex_st_ctime_nsec; - int64_t unused[3]; + uint64_t st_atime_; + uint64_t fex_st_atime_nsec; + uint64_t st_mtime_; + uint64_t fex_st_mtime_nsec; + uint64_t st_ctime_; + uint64_t fex_st_ctime_nsec; + int64_t unused[3]; - guest_stat() = delete; - operator struct stat() const { - struct stat val{}; + guest_stat() = delete; + operator struct stat() const { + struct stat val {}; #define COPY(x) val.x = x COPY(st_dev); COPY(st_ino); @@ -160,12 +154,12 @@ using __time_t = time_t; val.st_mtim.tv_nsec = fex_st_mtime_nsec; val.st_ctim.tv_sec = st_ctime_; - val.st_ctim.tv_nsec= fex_st_ctime_nsec; + val.st_ctim.tv_nsec = fex_st_ctime_nsec; #undef COPY - return val; - } + return val; + } - guest_stat(struct stat val) { + guest_stat(struct stat val) { #define COPY(x) x = val.x COPY(st_dev); COPY(st_ino); @@ -189,43 +183,38 @@ using __time_t = time_t; st_ctime_ = val.st_ctime; fex_st_ctime_nsec = val.st_ctim.tv_nsec; #undef COPY - } - }; + } +}; - // Original definition in `arch/x86/include/uapi/asm/stat.h` for future excavation - static_assert(std::is_trivial::value, "Needs to be trivial"); - static_assert(sizeof(FEX::HLE::x64::guest_stat) == 144, "Incorrect size"); +// Original definition in `arch/x86/include/uapi/asm/stat.h` for future excavation +static_assert(std::is_trivial::value, "Needs to be trivial"); +static_assert(sizeof(FEX::HLE::x64::guest_stat) == 144, "Incorrect size"); - // There is no public definition of this struct - // Matches the definition of `struct linux_dirent` in fs/readdir.c - struct - FEX_ANNOTATE("fex-match") - linux_dirent { - uint64_t d_ino; - uint64_t d_off; - uint16_t d_reclen; - char d_name[1]; - /* Has hidden null character and d_type */ - }; - static_assert(std::is_trivial::value, "Needs to be trivial"); - static_assert(offsetof(linux_dirent, d_ino) == 0, "Incorrect offset"); - static_assert(offsetof(linux_dirent, d_off) == 8, "Incorrect offset"); - static_assert(offsetof(linux_dirent, d_reclen) == 16, "Incorrect offset"); - static_assert(offsetof(linux_dirent, d_name) == 18, "Incorrect offset"); - static_assert(sizeof(linux_dirent) == 24, "Incorrect size"); +// There is no public definition of this struct +// Matches the definition of `struct linux_dirent` in fs/readdir.c +struct FEX_ANNOTATE("fex-match") linux_dirent { + uint64_t d_ino; + uint64_t d_off; + uint16_t d_reclen; + char d_name[1]; + /* Has hidden null character and d_type */ +}; +static_assert(std::is_trivial::value, "Needs to be trivial"); +static_assert(offsetof(linux_dirent, d_ino) == 0, "Incorrect offset"); +static_assert(offsetof(linux_dirent, d_off) == 8, "Incorrect offset"); +static_assert(offsetof(linux_dirent, d_reclen) == 16, "Incorrect offset"); +static_assert(offsetof(linux_dirent, d_name) == 18, "Incorrect offset"); +static_assert(sizeof(linux_dirent) == 24, "Incorrect size"); - // There is no public definition of this struct - // Matches the definition of `struct linux_dirent64` in include/linux/dirent.h - struct - FEX_ANNOTATE("fex-match") - FEX_PACKED - linux_dirent_64 { - uint64_t d_ino; - uint64_t d_off; - uint16_t d_reclen; - uint8_t d_type; - char d_name[]; - }; - static_assert(std::is_trivial::value, "Needs to be trivial"); - static_assert(sizeof(linux_dirent_64) == 19, "Incorrect size"); -} +// There is no public definition of this struct +// Matches the definition of `struct linux_dirent64` in include/linux/dirent.h +struct FEX_ANNOTATE("fex-match") FEX_PACKED linux_dirent_64 { + uint64_t d_ino; + uint64_t d_off; + uint16_t d_reclen; + uint8_t d_type; + char d_name[]; +}; +static_assert(std::is_trivial::value, "Needs to be trivial"); +static_assert(sizeof(linux_dirent_64) == 19, "Incorrect size"); +} // namespace FEX::HLE::x64 diff --git a/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp b/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp index 75f05c82a..a29f161bb 100644 --- a/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp +++ b/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp @@ -19,586 +19,586 @@ #include namespace FEX::VDSO { - FEXCore::Context::VDSOSigReturn VDSOPointers{}; - namespace VDSOHandlers { - using TimeType = decltype(::time)*; - using GetTimeOfDayType = decltype(::gettimeofday)*; - using ClockGetTimeType = decltype(::clock_gettime)*; - using ClockGetResType = decltype(::clock_getres)*; - using GetCPUType = decltype(FHU::Syscalls::getcpu)*; +FEXCore::Context::VDSOSigReturn VDSOPointers {}; +namespace VDSOHandlers { + using TimeType = decltype(::time)*; + using GetTimeOfDayType = decltype(::gettimeofday)*; + using ClockGetTimeType = decltype(::clock_gettime)*; + using ClockGetResType = decltype(::clock_getres)*; + using GetCPUType = decltype(FHU::Syscalls::getcpu)*; - TimeType TimePtr; - GetTimeOfDayType GetTimeOfDayPtr; - ClockGetTimeType ClockGetTimePtr; - ClockGetResType ClockGetResPtr; - GetCPUType GetCPUPtr; + TimeType TimePtr; + GetTimeOfDayType GetTimeOfDayPtr; + ClockGetTimeType ClockGetTimePtr; + ClockGetResType ClockGetResPtr; + GetCPUType GetCPUPtr; +} // namespace VDSOHandlers + +using HandlerPtr = void (*)(void*); +namespace x64 { + static uint64_t SyscallRet(uint64_t Result) { + if (Result == -1) { + return -errno; + } + return Result; } + // glibc handlers + namespace glibc { + static void time(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + time_t* a_0; + uint64_t rv; + }* args = reinterpret_cast(ArgsRV); - using HandlerPtr = void(*)(void*); - namespace x64 { - static uint64_t SyscallRet(uint64_t Result) { + uint64_t Result = ::time(args->a_0); + args->rv = SyscallRet(Result); + } + + static void gettimeofday(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + struct timeval* tv; + struct timezone* tz; + int rv; + }* args = reinterpret_cast(ArgsRV); + + int Result = ::gettimeofday(args->tv, args->tz); + args->rv = SyscallRet(Result); + } + + static void clock_gettime(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + struct timespec* tp; + int rv; + }* args = reinterpret_cast(ArgsRV); + + int Result = ::clock_gettime(args->clk_id, args->tp); + args->rv = SyscallRet(Result); + } + + static void clock_getres(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + struct timespec* tp; + int rv; + }* args = reinterpret_cast(ArgsRV); + + int Result = ::clock_getres(args->clk_id, args->tp); + args->rv = SyscallRet(Result); + } + + static void getcpu(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + uint32_t* cpu; + uint32_t* node; + int rv; + }* args = reinterpret_cast(ArgsRV); + + int Result = FHU::Syscalls::getcpu(args->cpu, args->node); + args->rv = SyscallRet(Result); + } + } // namespace glibc + + namespace VDSO { + // VDSO handlers + static void time(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + time_t* a_0; + uint64_t rv; + }* args = reinterpret_cast(ArgsRV); + + args->rv = VDSOHandlers::TimePtr(args->a_0); + } + + static void gettimeofday(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + struct timeval* tv; + struct timezone* tz; + int rv; + }* args = reinterpret_cast(ArgsRV); + + args->rv = VDSOHandlers::GetTimeOfDayPtr(args->tv, args->tz); + } + + static void clock_gettime(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + struct timespec* tp; + int rv; + }* args = reinterpret_cast(ArgsRV); + + args->rv = VDSOHandlers::ClockGetTimePtr(args->clk_id, args->tp); + } + + static void clock_getres(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + struct timespec* tp; + int rv; + }* args = reinterpret_cast(ArgsRV); + + args->rv = VDSOHandlers::ClockGetResPtr(args->clk_id, args->tp); + } + + static void getcpu(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + uint32_t* cpu; + uint32_t* node; + int rv; + }* args = reinterpret_cast(ArgsRV); + + args->rv = VDSOHandlers::GetCPUPtr(args->cpu, args->node); + } + } // namespace VDSO + + HandlerPtr Handler_time = FEX::VDSO::x64::glibc::time; + HandlerPtr Handler_gettimeofday = FEX::VDSO::x64::glibc::gettimeofday; + HandlerPtr Handler_clock_gettime = FEX::VDSO::x64::glibc::clock_gettime; + HandlerPtr Handler_clock_getres = FEX::VDSO::x64::glibc::clock_getres; + HandlerPtr Handler_getcpu = FEX::VDSO::x64::glibc::getcpu; +} // namespace x64 +namespace x32 { + namespace glibc { + static int SyscallRet(int Result) { if (Result == -1) { return -errno; } return Result; } + // glibc handlers - namespace glibc { - static void time(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - time_t *a_0; - uint64_t rv; - } *args = reinterpret_cast(ArgsRV); + static void time(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + HLE::x32::compat_ptr a_0; + int rv; + }* args = reinterpret_cast(ArgsRV); - uint64_t Result = ::time(args->a_0); - args->rv = SyscallRet(Result); - } - - static void gettimeofday(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - struct timeval *tv; - struct timezone *tz; - int rv; - } *args = reinterpret_cast(ArgsRV); - - int Result = ::gettimeofday(args->tv, args->tz); - args->rv = SyscallRet(Result); - } - - static void clock_gettime(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - struct timespec *tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - int Result = ::clock_gettime(args->clk_id, args->tp); - args->rv = SyscallRet(Result); - } - - static void clock_getres(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - struct timespec *tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - int Result = ::clock_getres(args->clk_id, args->tp); - args->rv = SyscallRet(Result); - } - - static void getcpu(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - uint32_t *cpu; - uint32_t *node; - int rv; - } *args = reinterpret_cast(ArgsRV); - - int Result = FHU::Syscalls::getcpu(args->cpu, args->node); - args->rv = SyscallRet(Result); + time_t Host {}; + int Result = ::time(&Host); + args->rv = SyscallRet(Result); + if (Result != -1 && args->a_0) { + *args->a_0 = Host; } } - namespace VDSO { - // VDSO handlers - static void time(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - time_t *a_0; - uint64_t rv; - } *args = reinterpret_cast(ArgsRV); + static void gettimeofday(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + HLE::x32::compat_ptr tv; + HLE::x32::compat_ptr tz; + int rv; + }* args = reinterpret_cast(ArgsRV); - args->rv = VDSOHandlers::TimePtr(args->a_0); + struct timeval tv64 {}; + struct timeval* tv_ptr {}; + if (args->tv) { + tv_ptr = &tv64; } - static void gettimeofday(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - struct timeval *tv; - struct timezone *tz; - int rv; - } *args = reinterpret_cast(ArgsRV); + int Result = ::gettimeofday(tv_ptr, args->tz); + args->rv = SyscallRet(Result); - args->rv = VDSOHandlers::GetTimeOfDayPtr(args->tv, args->tz); - } - - static void clock_gettime(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - struct timespec *tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - args->rv = VDSOHandlers::ClockGetTimePtr(args->clk_id, args->tp); - } - - static void clock_getres(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - struct timespec *tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - args->rv = VDSOHandlers::ClockGetResPtr(args->clk_id, args->tp); - } - - static void getcpu(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - uint32_t *cpu; - uint32_t *node; - int rv; - } *args = reinterpret_cast(ArgsRV); - - args->rv = VDSOHandlers::GetCPUPtr(args->cpu, args->node); + if (Result != -1 && args->tv) { + *args->tv = tv64; } } - HandlerPtr Handler_time = FEX::VDSO::x64::glibc::time; - HandlerPtr Handler_gettimeofday = FEX::VDSO::x64::glibc::gettimeofday; - HandlerPtr Handler_clock_gettime = FEX::VDSO::x64::glibc::clock_gettime; - HandlerPtr Handler_clock_getres = FEX::VDSO::x64::glibc::clock_getres; - HandlerPtr Handler_getcpu = FEX::VDSO::x64::glibc::getcpu; - } - namespace x32 { - namespace glibc { - static int SyscallRet(int Result) { - if (Result == -1) { - return -errno; - } - return Result; - } + static void clock_gettime(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + HLE::x32::compat_ptr tp; + int rv; + }* args = reinterpret_cast(ArgsRV); - // glibc handlers - static void time(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - HLE::x32::compat_ptr a_0; - int rv; - } *args = reinterpret_cast(ArgsRV); + struct timespec tp64 {}; + int Result = ::clock_gettime(args->clk_id, &tp64); + args->rv = SyscallRet(Result); - time_t Host{}; - int Result = ::time(&Host); - args->rv = SyscallRet(Result); - if (Result != -1 && args->a_0) { - *args->a_0 = Host; - } - } - - static void gettimeofday(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - HLE::x32::compat_ptr tv; - HLE::x32::compat_ptr tz; - int rv; - } *args = reinterpret_cast(ArgsRV); - - struct timeval tv64{}; - struct timeval *tv_ptr{}; - if (args->tv) { - tv_ptr = &tv64; - } - - int Result = ::gettimeofday(tv_ptr, args->tz); - args->rv = SyscallRet(Result); - - if (Result != -1 && args->tv) { - *args->tv = tv64; - } - } - - static void clock_gettime(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - HLE::x32::compat_ptr tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - struct timespec tp64{}; - int Result = ::clock_gettime(args->clk_id, &tp64); - args->rv = SyscallRet(Result); - - if (Result != -1 && args->tp) { - *args->tp = tp64; - } - } - - static void clock_gettime64(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - HLE::x32::compat_ptr tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - int Result = ::clock_gettime(args->clk_id, args->tp); - args->rv = SyscallRet(Result); - } - - static void clock_getres(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - HLE::x32::compat_ptr tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - struct timespec tp64{}; - - int Result = ::clock_getres(args->clk_id, &tp64); - args->rv = SyscallRet(Result); - - if (Result != -1 && args->tp) { - *args->tp = tp64; - } - } - - static void getcpu(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - HLE::x32::compat_ptr cpu; - HLE::x32::compat_ptr node; - int rv; - } *args = reinterpret_cast(ArgsRV); - - int Result = ::getcpu(args->cpu, args->node); - args->rv = SyscallRet(Result); + if (Result != -1 && args->tp) { + *args->tp = tp64; } } - namespace VDSO { - static bool SyscallErr(uint64_t Result) { - return Result >= -4095; - } + static void clock_gettime64(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + HLE::x32::compat_ptr tp; + int rv; + }* args = reinterpret_cast(ArgsRV); - // VDSO handlers - static void time(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - HLE::x32::compat_ptr a_0; - int rv; - } *args = reinterpret_cast(ArgsRV); + int Result = ::clock_gettime(args->clk_id, args->tp); + args->rv = SyscallRet(Result); + } - time_t Host{}; - uint64_t Result = VDSOHandlers::TimePtr(&Host); - args->rv = Result; - if (!SyscallErr(Result) && args->a_0) { - *args->a_0 = Host; - } - } + static void clock_getres(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + HLE::x32::compat_ptr tp; + int rv; + }* args = reinterpret_cast(ArgsRV); - static void gettimeofday(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - HLE::x32::compat_ptr tv; - HLE::x32::compat_ptr tz; - int rv; - } *args = reinterpret_cast(ArgsRV); + struct timespec tp64 {}; - struct timeval tv64{}; - struct timeval *tv_ptr{}; - if (args->tv) { - tv_ptr = &tv64; - } + int Result = ::clock_getres(args->clk_id, &tp64); + args->rv = SyscallRet(Result); - uint64_t Result = VDSOHandlers::GetTimeOfDayPtr(tv_ptr, args->tz); - args->rv = Result; - - if (!SyscallErr(Result) && args->tv) { - *args->tv = tv64; - } - } - - static void clock_gettime(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - HLE::x32::compat_ptr tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - struct timespec tp64{}; - uint64_t Result = VDSOHandlers::ClockGetTimePtr(args->clk_id, &tp64); - args->rv = Result; - - if (!SyscallErr(Result) && args->tp) { - *args->tp = tp64; - } - } - - static void clock_gettime64(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - HLE::x32::compat_ptr tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - args->rv = VDSOHandlers::ClockGetTimePtr(args->clk_id, args->tp); - } - - static void clock_getres(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - clockid_t clk_id; - HLE::x32::compat_ptr tp; - int rv; - } *args = reinterpret_cast(ArgsRV); - - struct timespec tp64{}; - - uint64_t Result = VDSOHandlers::ClockGetResPtr(args->clk_id, &tp64); - args->rv = Result; - - if (!SyscallErr(Result) && args->tp) { - *args->tp = tp64; - } - } - - static void getcpu(void* ArgsRV) { - struct __attribute__((packed)) ArgsRV_t { - HLE::x32::compat_ptr cpu; - HLE::x32::compat_ptr node; - int rv; - } *args = reinterpret_cast(ArgsRV); - - args->rv = VDSOHandlers::GetCPUPtr(args->cpu, args->node); + if (Result != -1 && args->tp) { + *args->tp = tp64; } } - HandlerPtr Handler_time = FEX::VDSO::x32::glibc::time; - HandlerPtr Handler_gettimeofday = FEX::VDSO::x32::glibc::gettimeofday; - HandlerPtr Handler_clock_gettime = FEX::VDSO::x32::glibc::clock_gettime; - HandlerPtr Handler_clock_gettime64 = FEX::VDSO::x32::glibc::clock_gettime64; - HandlerPtr Handler_clock_getres = FEX::VDSO::x32::glibc::clock_getres; - HandlerPtr Handler_getcpu = FEX::VDSO::x32::glibc::getcpu; + static void getcpu(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + HLE::x32::compat_ptr cpu; + HLE::x32::compat_ptr node; + int rv; + }* args = reinterpret_cast(ArgsRV); + + int Result = ::getcpu(args->cpu, args->node); + args->rv = SyscallRet(Result); + } + } // namespace glibc + + namespace VDSO { + static bool SyscallErr(uint64_t Result) { + return Result >= -4095; + } + + // VDSO handlers + static void time(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + HLE::x32::compat_ptr a_0; + int rv; + }* args = reinterpret_cast(ArgsRV); + + time_t Host {}; + uint64_t Result = VDSOHandlers::TimePtr(&Host); + args->rv = Result; + if (!SyscallErr(Result) && args->a_0) { + *args->a_0 = Host; + } + } + + static void gettimeofday(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + HLE::x32::compat_ptr tv; + HLE::x32::compat_ptr tz; + int rv; + }* args = reinterpret_cast(ArgsRV); + + struct timeval tv64 {}; + struct timeval* tv_ptr {}; + if (args->tv) { + tv_ptr = &tv64; + } + + uint64_t Result = VDSOHandlers::GetTimeOfDayPtr(tv_ptr, args->tz); + args->rv = Result; + + if (!SyscallErr(Result) && args->tv) { + *args->tv = tv64; + } + } + + static void clock_gettime(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + HLE::x32::compat_ptr tp; + int rv; + }* args = reinterpret_cast(ArgsRV); + + struct timespec tp64 {}; + uint64_t Result = VDSOHandlers::ClockGetTimePtr(args->clk_id, &tp64); + args->rv = Result; + + if (!SyscallErr(Result) && args->tp) { + *args->tp = tp64; + } + } + + static void clock_gettime64(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + HLE::x32::compat_ptr tp; + int rv; + }* args = reinterpret_cast(ArgsRV); + + args->rv = VDSOHandlers::ClockGetTimePtr(args->clk_id, args->tp); + } + + static void clock_getres(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + clockid_t clk_id; + HLE::x32::compat_ptr tp; + int rv; + }* args = reinterpret_cast(ArgsRV); + + struct timespec tp64 {}; + + uint64_t Result = VDSOHandlers::ClockGetResPtr(args->clk_id, &tp64); + args->rv = Result; + + if (!SyscallErr(Result) && args->tp) { + *args->tp = tp64; + } + } + + static void getcpu(void* ArgsRV) { + struct __attribute__((packed)) ArgsRV_t { + HLE::x32::compat_ptr cpu; + HLE::x32::compat_ptr node; + int rv; + }* args = reinterpret_cast(ArgsRV); + + args->rv = VDSOHandlers::GetCPUPtr(args->cpu, args->node); + } + } // namespace VDSO + + HandlerPtr Handler_time = FEX::VDSO::x32::glibc::time; + HandlerPtr Handler_gettimeofday = FEX::VDSO::x32::glibc::gettimeofday; + HandlerPtr Handler_clock_gettime = FEX::VDSO::x32::glibc::clock_gettime; + HandlerPtr Handler_clock_gettime64 = FEX::VDSO::x32::glibc::clock_gettime64; + HandlerPtr Handler_clock_getres = FEX::VDSO::x32::glibc::clock_getres; + HandlerPtr Handler_getcpu = FEX::VDSO::x32::glibc::getcpu; +} // namespace x32 + +void LoadHostVDSO() { + // dlopen does allocations that FEX can't track. + // Ensure we don't run afoul of the glibc fault allocator. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + void* vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!vdso) { + vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); } - void LoadHostVDSO() { - // dlopen does allocations that FEX can't track. - // Ensure we don't run afoul of the glibc fault allocator. - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - void *vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); - if (!vdso) { - vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); - } - - if (!vdso) { - // We couldn't load VDSO, fallback to C implementations. Which will still be faster than emulated libc versions. - LogMan::Msg::IFmt("linux-vdso implementation falling back to libc. Consider enabling VDSO in your kernel."); - return; - } - - auto SymbolPtr = dlsym(vdso, "__kernel_time"); - if (!SymbolPtr) { - SymbolPtr = dlsym(vdso, "__vdso_time"); - } - if (SymbolPtr) { - VDSOHandlers::TimePtr = reinterpret_cast(SymbolPtr); - x64::Handler_time = x64::VDSO::time; - x32::Handler_time = x32::VDSO::time; - } - - SymbolPtr = dlsym(vdso, "__kernel_gettimeofday"); - if (!SymbolPtr) { - SymbolPtr = dlsym(vdso, "__vdso_gettimeofday"); - } - - if (SymbolPtr) { - VDSOHandlers::GetTimeOfDayPtr = reinterpret_cast(SymbolPtr); - x64::Handler_gettimeofday = x64::VDSO::gettimeofday; - x32::Handler_gettimeofday = x32::VDSO::gettimeofday; - } - - SymbolPtr = dlsym(vdso, "__kernel_clock_gettime"); - if (!SymbolPtr) { - SymbolPtr = dlsym(vdso, "__vdso_clock_gettime"); - } - - if (SymbolPtr) { - VDSOHandlers::ClockGetTimePtr = reinterpret_cast(SymbolPtr); - x64::Handler_clock_gettime = x64::VDSO::clock_gettime; - x32::Handler_clock_gettime = x32::VDSO::clock_gettime; - x32::Handler_clock_gettime64 = x32::VDSO::clock_gettime64; - } - - SymbolPtr = dlsym(vdso, "__kernel_clock_getres"); - if (!SymbolPtr) { - SymbolPtr = dlsym(vdso, "__vdso_clock_getres"); - } - - if (SymbolPtr) { - VDSOHandlers::ClockGetResPtr = reinterpret_cast(SymbolPtr); - x64::Handler_clock_getres = x64::VDSO::clock_getres; - x32::Handler_clock_getres = x32::VDSO::clock_getres; - } - - SymbolPtr = dlsym(vdso, "__kernel_getcpu"); - if (!SymbolPtr) { - SymbolPtr = dlsym(vdso, "__vdso_getcpu"); - } - - if (SymbolPtr) { - VDSOHandlers::GetCPUPtr = reinterpret_cast(SymbolPtr); - x64::Handler_getcpu = x64::VDSO::getcpu; - x32::Handler_getcpu = x32::VDSO::getcpu; - } - dlclose(vdso); + if (!vdso) { + // We couldn't load VDSO, fallback to C implementations. Which will still be faster than emulated libc versions. + LogMan::Msg::IFmt("linux-vdso implementation falling back to libc. Consider enabling VDSO in your kernel."); + return; } - static fextl::vector VDSODefinitions = { - { - // sha256(libVDSO:time) - { 0x37, 0x63, 0x46, 0xb0, 0x79, 0x06, 0x5f, 0x9d, 0x00, 0xb6, 0x8d, 0xfd, 0x9e, 0x4a, 0x62, 0xcd, 0x1e, 0x6c, 0xcc, 0x22, 0xcd, 0xb2, 0xc0, 0x17, 0x7d, 0x42, 0x6a, 0x40, 0xd1, 0xeb, 0xfa, 0xe0 }, - nullptr, - }, - { - // sha256(libVDSO:gettimeofday) - { 0x77, 0x2a, 0xde, 0x1c, 0x13, 0x2d, 0xe9, 0x48, 0xaf, 0xe0, 0xba, 0xcc, 0x6a, 0x89, 0xff, 0xca, 0x4a, 0xdc, 0xd5, 0x63, 0x2c, 0xc5, 0x62, 0x8b, 0x5d, 0xde, 0x0b, 0x15, 0x35, 0xc6, 0xc7, 0x14 }, - nullptr, - }, - { - // sha256(libVDSO:clock_gettime) - { 0x3c, 0x96, 0x9b, 0x2d, 0xc3, 0xad, 0x2b, 0x3b, 0x9c, 0x4e, 0x4d, 0xca, 0x1c, 0xe8, 0x18, 0x4a, 0x12, 0x8a, 0xe4, 0xc1, 0x56, 0x92, 0x73, 0xce, 0x65, 0x85, 0x5f, 0x65, 0x7e, 0x94, 0x26, 0xbe }, - nullptr, - }, + auto SymbolPtr = dlsym(vdso, "__kernel_time"); + if (!SymbolPtr) { + SymbolPtr = dlsym(vdso, "__vdso_time"); + } + if (SymbolPtr) { + VDSOHandlers::TimePtr = reinterpret_cast(SymbolPtr); + x64::Handler_time = x64::VDSO::time; + x32::Handler_time = x32::VDSO::time; + } - { - // sha256(libVDSO:clock_gettime64) - { 0xba, 0xe9, 0x6d, 0x30, 0xc0, 0x68, 0xc6, 0xd7, 0x59, 0x04, 0xf7, 0x10, 0x06, 0x72, 0x88, 0xfd, 0x4c, 0x57, 0x0f, 0x31, 0xa5, 0xea, 0xa9, 0xb9, 0xd3, 0x8d, 0x03, 0x81, 0x50, 0x16, 0x22, 0x71 }, - nullptr, - }, + SymbolPtr = dlsym(vdso, "__kernel_gettimeofday"); + if (!SymbolPtr) { + SymbolPtr = dlsym(vdso, "__vdso_gettimeofday"); + } - { - // sha256(libVDSO:clock_getres) - { 0xe4, 0xa1, 0xf6, 0x23, 0x35, 0xae, 0xb7, 0xb6, 0xb0, 0x37, 0xc5, 0xc3, 0xa3, 0xfd, 0xbf, 0xa2, 0xa1, 0xc8, 0x95, 0x78, 0xe5, 0x76, 0x86, 0xdb, 0x3e, 0x6c, 0x54, 0xd5, 0x02, 0x60, 0xd8, 0x6d }, - nullptr, - }, - { - // sha256(libVDSO:getcpu) - { 0x39, 0x83, 0x39, 0x36, 0x0f, 0x68, 0xd6, 0xfc, 0xc2, 0x3a, 0x97, 0x11, 0x85, 0x09, 0xc7, 0x25, 0xbb, 0x50, 0x49, 0x55, 0x6b, 0x0c, 0x9f, 0x50, 0x37, 0xf5, 0x9d, 0xb0, 0x38, 0x58, 0x57, 0x12 }, - nullptr, - }, - }; + if (SymbolPtr) { + VDSOHandlers::GetTimeOfDayPtr = reinterpret_cast(SymbolPtr); + x64::Handler_gettimeofday = x64::VDSO::gettimeofday; + x32::Handler_gettimeofday = x32::VDSO::gettimeofday; + } - void LoadGuestVDSOSymbols(bool Is64Bit, char *VDSOBase) { - // We need to load symbols we care about. - if (Is64Bit) { - // We don't care about any 64-bit symbols right now. - return; + SymbolPtr = dlsym(vdso, "__kernel_clock_gettime"); + if (!SymbolPtr) { + SymbolPtr = dlsym(vdso, "__vdso_clock_gettime"); + } + + if (SymbolPtr) { + VDSOHandlers::ClockGetTimePtr = reinterpret_cast(SymbolPtr); + x64::Handler_clock_gettime = x64::VDSO::clock_gettime; + x32::Handler_clock_gettime = x32::VDSO::clock_gettime; + x32::Handler_clock_gettime64 = x32::VDSO::clock_gettime64; + } + + SymbolPtr = dlsym(vdso, "__kernel_clock_getres"); + if (!SymbolPtr) { + SymbolPtr = dlsym(vdso, "__vdso_clock_getres"); + } + + if (SymbolPtr) { + VDSOHandlers::ClockGetResPtr = reinterpret_cast(SymbolPtr); + x64::Handler_clock_getres = x64::VDSO::clock_getres; + x32::Handler_clock_getres = x32::VDSO::clock_getres; + } + + SymbolPtr = dlsym(vdso, "__kernel_getcpu"); + if (!SymbolPtr) { + SymbolPtr = dlsym(vdso, "__vdso_getcpu"); + } + + if (SymbolPtr) { + VDSOHandlers::GetCPUPtr = reinterpret_cast(SymbolPtr); + x64::Handler_getcpu = x64::VDSO::getcpu; + x32::Handler_getcpu = x32::VDSO::getcpu; + } + dlclose(vdso); +} + +static fextl::vector VDSODefinitions = { + { + // sha256(libVDSO:time) + {0x37, 0x63, 0x46, 0xb0, 0x79, 0x06, 0x5f, 0x9d, 0x00, 0xb6, 0x8d, 0xfd, 0x9e, 0x4a, 0x62, 0xcd, + 0x1e, 0x6c, 0xcc, 0x22, 0xcd, 0xb2, 0xc0, 0x17, 0x7d, 0x42, 0x6a, 0x40, 0xd1, 0xeb, 0xfa, 0xe0}, + nullptr, + }, + { + // sha256(libVDSO:gettimeofday) + {0x77, 0x2a, 0xde, 0x1c, 0x13, 0x2d, 0xe9, 0x48, 0xaf, 0xe0, 0xba, 0xcc, 0x6a, 0x89, 0xff, 0xca, + 0x4a, 0xdc, 0xd5, 0x63, 0x2c, 0xc5, 0x62, 0x8b, 0x5d, 0xde, 0x0b, 0x15, 0x35, 0xc6, 0xc7, 0x14}, + nullptr, + }, + { + // sha256(libVDSO:clock_gettime) + {0x3c, 0x96, 0x9b, 0x2d, 0xc3, 0xad, 0x2b, 0x3b, 0x9c, 0x4e, 0x4d, 0xca, 0x1c, 0xe8, 0x18, 0x4a, + 0x12, 0x8a, 0xe4, 0xc1, 0x56, 0x92, 0x73, 0xce, 0x65, 0x85, 0x5f, 0x65, 0x7e, 0x94, 0x26, 0xbe}, + nullptr, + }, + + { + // sha256(libVDSO:clock_gettime64) + {0xba, 0xe9, 0x6d, 0x30, 0xc0, 0x68, 0xc6, 0xd7, 0x59, 0x04, 0xf7, 0x10, 0x06, 0x72, 0x88, 0xfd, + 0x4c, 0x57, 0x0f, 0x31, 0xa5, 0xea, 0xa9, 0xb9, 0xd3, 0x8d, 0x03, 0x81, 0x50, 0x16, 0x22, 0x71}, + nullptr, + }, + + { + // sha256(libVDSO:clock_getres) + {0xe4, 0xa1, 0xf6, 0x23, 0x35, 0xae, 0xb7, 0xb6, 0xb0, 0x37, 0xc5, 0xc3, 0xa3, 0xfd, 0xbf, 0xa2, + 0xa1, 0xc8, 0x95, 0x78, 0xe5, 0x76, 0x86, 0xdb, 0x3e, 0x6c, 0x54, 0xd5, 0x02, 0x60, 0xd8, 0x6d}, + nullptr, + }, + { + // sha256(libVDSO:getcpu) + {0x39, 0x83, 0x39, 0x36, 0x0f, 0x68, 0xd6, 0xfc, 0xc2, 0x3a, 0x97, 0x11, 0x85, 0x09, 0xc7, 0x25, + 0xbb, 0x50, 0x49, 0x55, 0x6b, 0x0c, 0x9f, 0x50, 0x37, 0xf5, 0x9d, 0xb0, 0x38, 0x58, 0x57, 0x12}, + nullptr, + }, +}; + +void LoadGuestVDSOSymbols(bool Is64Bit, char* VDSOBase) { + // We need to load symbols we care about. + if (Is64Bit) { + // We don't care about any 64-bit symbols right now. + return; + } + + // 32-bit symbol loading. + const Elf32_Ehdr* Header = reinterpret_cast(VDSOBase); + + // First walk the section headers to find the symbol table. + const Elf32_Shdr* RawShdrs = reinterpret_cast(VDSOBase + Header->e_shoff); + + const Elf32_Shdr* StrHeader = &RawShdrs[Header->e_shstrndx]; + const char* SHStrings = VDSOBase + StrHeader->sh_offset; + + const Elf32_Shdr* SymTableHeader {}; + const Elf32_Shdr* StringTableHeader {}; + + for (size_t i = 0; i < Header->e_shnum; ++i) { + const auto& Header = RawShdrs[i]; + if (Header.sh_type == SHT_SYMTAB && strcmp(&SHStrings[Header.sh_name], ".symtab") == 0) { + SymTableHeader = &Header; + StringTableHeader = &RawShdrs[SymTableHeader->sh_link]; + break; } + } - // 32-bit symbol loading. - const Elf32_Ehdr *Header = reinterpret_cast(VDSOBase); + if (!SymTableHeader) { + // Couldn't find symbol table + return; + } - // First walk the section headers to find the symbol table. - const Elf32_Shdr *RawShdrs = - reinterpret_cast(VDSOBase + Header->e_shoff); + const char* StrTab = VDSOBase + StringTableHeader->sh_offset; + size_t NumSymbols = SymTableHeader->sh_size / SymTableHeader->sh_entsize; - const Elf32_Shdr *StrHeader = &RawShdrs[Header->e_shstrndx]; - char const *SHStrings = VDSOBase + StrHeader->sh_offset; - - const Elf32_Shdr *SymTableHeader{}; - const Elf32_Shdr *StringTableHeader{}; - - for (size_t i = 0; i < Header->e_shnum; ++i) { - const auto &Header = RawShdrs[i]; - if (Header.sh_type == SHT_SYMTAB && strcmp(&SHStrings[Header.sh_name], ".symtab") == 0) { - SymTableHeader = &Header; - StringTableHeader = &RawShdrs[SymTableHeader->sh_link]; - break; - } - } - - if (!SymTableHeader) { - // Couldn't find symbol table - return; - } - - char const *StrTab = VDSOBase + StringTableHeader->sh_offset; - size_t NumSymbols = SymTableHeader->sh_size / SymTableHeader->sh_entsize; - - for (size_t i = 0; i < NumSymbols; ++i) { - uint64_t offset = SymTableHeader->sh_offset + i * SymTableHeader->sh_entsize; - Elf32_Sym const *Symbol = - reinterpret_cast(VDSOBase + offset); - if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && - Symbol->st_value != 0) { - char const * Name = &StrTab[Symbol->st_name]; - if (Name[0] != '\0') { - if (strcmp(Name, "__kernel_sigreturn") == 0) { - VDSOPointers.VDSO_kernel_sigreturn = VDSOBase + Symbol->st_value; - } - else if (strcmp(Name, "__kernel_rt_sigreturn") == 0) { - VDSOPointers.VDSO_kernel_rt_sigreturn = VDSOBase + Symbol->st_value; - } + for (size_t i = 0; i < NumSymbols; ++i) { + uint64_t offset = SymTableHeader->sh_offset + i * SymTableHeader->sh_entsize; + const Elf32_Sym* Symbol = reinterpret_cast(VDSOBase + offset); + if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN && Symbol->st_value != 0) { + const char* Name = &StrTab[Symbol->st_name]; + if (Name[0] != '\0') { + if (strcmp(Name, "__kernel_sigreturn") == 0) { + VDSOPointers.VDSO_kernel_sigreturn = VDSOBase + Symbol->st_value; + } else if (strcmp(Name, "__kernel_rt_sigreturn") == 0) { + VDSOPointers.VDSO_kernel_rt_sigreturn = VDSOBase + Symbol->st_value; } } } } +} - void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler *const Handler) { - void* VDSOBase{}; - FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBS); - FEX_CONFIG_OPT(ThunkGuestLibs32, THUNKGUESTLIBS32); +void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler) { + void* VDSOBase {}; + FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBS); + FEX_CONFIG_OPT(ThunkGuestLibs32, THUNKGUESTLIBS32); - fextl::string ThunkGuestPath{}; - if (Is64Bit) { - ThunkGuestPath = fextl::fmt::format("{}/libVDSO-guest.so", ThunkGuestLibs()); + fextl::string ThunkGuestPath {}; + if (Is64Bit) { + ThunkGuestPath = fextl::fmt::format("{}/libVDSO-guest.so", ThunkGuestLibs()); - // Set the Thunk definition pointers for x86-64 - VDSODefinitions[0].ThunkFunction = FEX::VDSO::x64::Handler_time; - VDSODefinitions[1].ThunkFunction = FEX::VDSO::x64::Handler_gettimeofday; - VDSODefinitions[2].ThunkFunction = FEX::VDSO::x64::Handler_clock_gettime; - VDSODefinitions[3].ThunkFunction = FEX::VDSO::x64::Handler_clock_gettime; - VDSODefinitions[4].ThunkFunction = FEX::VDSO::x64::Handler_clock_getres; - VDSODefinitions[5].ThunkFunction = FEX::VDSO::x64::Handler_getcpu; - } - else { - ThunkGuestPath = fextl::fmt::format("{}/libVDSO-guest.so", ThunkGuestLibs32()); + // Set the Thunk definition pointers for x86-64 + VDSODefinitions[0].ThunkFunction = FEX::VDSO::x64::Handler_time; + VDSODefinitions[1].ThunkFunction = FEX::VDSO::x64::Handler_gettimeofday; + VDSODefinitions[2].ThunkFunction = FEX::VDSO::x64::Handler_clock_gettime; + VDSODefinitions[3].ThunkFunction = FEX::VDSO::x64::Handler_clock_gettime; + VDSODefinitions[4].ThunkFunction = FEX::VDSO::x64::Handler_clock_getres; + VDSODefinitions[5].ThunkFunction = FEX::VDSO::x64::Handler_getcpu; + } else { + ThunkGuestPath = fextl::fmt::format("{}/libVDSO-guest.so", ThunkGuestLibs32()); - // Set the Thunk definition pointers for x86 - VDSODefinitions[0].ThunkFunction = FEX::VDSO::x32::Handler_time; - VDSODefinitions[1].ThunkFunction = FEX::VDSO::x32::Handler_gettimeofday; - VDSODefinitions[2].ThunkFunction = FEX::VDSO::x32::Handler_clock_gettime; - VDSODefinitions[3].ThunkFunction = FEX::VDSO::x32::Handler_clock_gettime64; - VDSODefinitions[4].ThunkFunction = FEX::VDSO::x32::Handler_clock_getres; - VDSODefinitions[5].ThunkFunction = FEX::VDSO::x32::Handler_getcpu; - } - - // Load VDSO if we can - int VDSOFD = ::open(ThunkGuestPath.c_str(), O_RDONLY); - - if (VDSOFD != -1) { - // Get file size - size_t VDSOSize = lseek(VDSOFD, 0, SEEK_END); - - if (VDSOSize >= 4) { - // Reset to beginning - lseek(VDSOFD, 0, SEEK_SET); - VDSOSize = FEXCore::AlignUp(VDSOSize, 4096); - - // Map the VDSO file to memory - VDSOBase = Handler->GuestMmap(nullptr, nullptr, VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0); - - // Since we found our VDSO thunk library, find our host VDSO function implementations. - LoadHostVDSO(); - - } - close(VDSOFD); - LoadGuestVDSOSymbols(Is64Bit, reinterpret_cast(VDSOBase)); - } - - return VDSOBase; + // Set the Thunk definition pointers for x86 + VDSODefinitions[0].ThunkFunction = FEX::VDSO::x32::Handler_time; + VDSODefinitions[1].ThunkFunction = FEX::VDSO::x32::Handler_gettimeofday; + VDSODefinitions[2].ThunkFunction = FEX::VDSO::x32::Handler_clock_gettime; + VDSODefinitions[3].ThunkFunction = FEX::VDSO::x32::Handler_clock_gettime64; + VDSODefinitions[4].ThunkFunction = FEX::VDSO::x32::Handler_clock_getres; + VDSODefinitions[5].ThunkFunction = FEX::VDSO::x32::Handler_getcpu; } - uint64_t GetVSyscallEntry(const void* VDSOBase) { - if (!VDSOBase) { - return 0; + // Load VDSO if we can + int VDSOFD = ::open(ThunkGuestPath.c_str(), O_RDONLY); + + if (VDSOFD != -1) { + // Get file size + size_t VDSOSize = lseek(VDSOFD, 0, SEEK_END); + + if (VDSOSize >= 4) { + // Reset to beginning + lseek(VDSOFD, 0, SEEK_SET); + VDSOSize = FEXCore::AlignUp(VDSOSize, 4096); + + // Map the VDSO file to memory + VDSOBase = Handler->GuestMmap(nullptr, nullptr, VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0); + + // Since we found our VDSO thunk library, find our host VDSO function implementations. + LoadHostVDSO(); } + close(VDSOFD); + LoadGuestVDSOSymbols(Is64Bit, reinterpret_cast(VDSOBase)); + } - // Extract the vsyscall location from the VDSO header. - auto Header = reinterpret_cast(VDSOBase); - - if (Header->e_entry) { - return reinterpret_cast(VDSOBase) + Header->e_entry; - } + return VDSOBase; +} +uint64_t GetVSyscallEntry(const void* VDSOBase) { + if (!VDSOBase) { return 0; } - fextl::vector const& GetVDSOThunkDefinitions() { - return VDSODefinitions; + // Extract the vsyscall location from the VDSO header. + auto Header = reinterpret_cast(VDSOBase); + + if (Header->e_entry) { + return reinterpret_cast(VDSOBase) + Header->e_entry; } - FEXCore::Context::VDSOSigReturn const& GetVDSOSymbols() { - return VDSOPointers; - } + return 0; } + +const fextl::vector& GetVDSOThunkDefinitions() { + return VDSODefinitions; +} + +const FEXCore::Context::VDSOSigReturn& GetVDSOSymbols() { + return VDSOPointers; +} +} // namespace FEX::VDSO diff --git a/Source/Tools/LinuxEmulation/VDSO_Emulation.h b/Source/Tools/LinuxEmulation/VDSO_Emulation.h index 68d730f7c..69fd43868 100644 --- a/Source/Tools/LinuxEmulation/VDSO_Emulation.h +++ b/Source/Tools/LinuxEmulation/VDSO_Emulation.h @@ -10,11 +10,11 @@ struct VDSOSigReturn; } namespace FEX::VDSO { - using MapperFn = std::function; - void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler *const Handler); +using MapperFn = std::function; +void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler); - uint64_t GetVSyscallEntry(const void* VDSOBase); +uint64_t GetVSyscallEntry(const void* VDSOBase); - fextl::vector const& GetVDSOThunkDefinitions(); - FEXCore::Context::VDSOSigReturn const& GetVDSOSymbols(); -} +const fextl::vector& GetVDSOThunkDefinitions(); +const FEXCore::Context::VDSOSigReturn& GetVDSOSymbols(); +} // namespace FEX::VDSO diff --git a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp index d7b89b064..2fa359572 100644 --- a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp +++ b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp @@ -43,11 +43,11 @@ $end_info$ #include #include -void MsgHandler(LogMan::DebugLevels Level, char const *Message) { +void MsgHandler(LogMan::DebugLevels Level, const char* Message) { fextl::fmt::print("[{}] {}\n", LogMan::DebugLevelStr(Level), Message); } -void AssertHandler(char const *Message) { +void AssertHandler(const char* Message) { fextl::fmt::print("[ASSERT] {}\n", Message); // make sure buffers are flushed @@ -71,7 +71,7 @@ public: void Load() override { fextl::unordered_map EnvMap; - for (auto &Option : Env) { + for (auto& Option : Env) { std::string_view Key = Option.first; std::string_view Value_View = Option.second; std::optional Value; @@ -81,21 +81,21 @@ public: if (Value) { EnvMap.insert_or_assign(Key, *Value); - } - else { + } else { EnvMap.insert_or_assign(Key, Value_View); } } auto GetVar = [&](const std::string_view id) -> std::optional { const auto it = EnvMap.find(id); - if (it == EnvMap.end()) + if (it == EnvMap.end()) { return std::nullopt; + } return it->second; }; - for (auto &it : EnvConfigLookup) { + for (auto& it : EnvConfigLookup) { if (auto Value = GetVar(it.first); Value) { Set(it.second, *Value); } @@ -105,85 +105,85 @@ public: private: fextl::vector> Env; }; -} +} // namespace namespace LongJumpHandler { - static jmp_buf LongJump{}; - static bool DidFault{}; +static jmp_buf LongJump {}; +static bool DidFault {}; #ifndef _WIN32 - void RegisterLongJumpHandler(FEX::HLE::SignalDelegator *Handler) { - Handler->RegisterFrontendHostSignalHandler(SIGSEGV, [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) { - constexpr uint8_t HLT = 0xF4; - if (reinterpret_cast(Thread->CurrentFrame->State.rip)[0] != HLT) { - DidFault = true; - return false; - } - - longjmp(LongJumpHandler::LongJump, 1); +void RegisterLongJumpHandler(FEX::HLE::SignalDelegator* Handler) { + Handler->RegisterFrontendHostSignalHandler( + SIGSEGV, + [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) { + constexpr uint8_t HLT = 0xF4; + if (reinterpret_cast(Thread->CurrentFrame->State.rip)[0] != HLT) { + DidFault = true; return false; - }, true); - } -#else - FEX::DummyHandlers::DummySignalDelegator *Handler; - - static void LongJumpHandler() { - longjmp(LongJump, 1); - } - - LONG WINAPI - VectoredExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) { - auto Thread = Handler->GetBackingTLSThread(); - PCONTEXT Context; - Context = ExceptionInfo->ContextRecord; - - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { - case STATUS_DATATYPE_MISALIGNMENT: { - const auto PC = FEX::ArchHelpers::Context::GetPc(Context); - if (!Thread->CTX->IsAddressInCodeBuffer(Thread, PC)) { - // Wasn't a sigbus in JIT code - return EXCEPTION_CONTINUE_SEARCH; - } - - const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(true, PC, FEX::ArchHelpers::Context::GetArmGPRs(Context)); - FEX::ArchHelpers::Context::SetPc(Context, PC + Result.second); - return Result.first ? - EXCEPTION_CONTINUE_EXECUTION : - EXCEPTION_CONTINUE_SEARCH; - } - case STATUS_ACCESS_VIOLATION: { - constexpr uint8_t HLT = 0xF4; - if (reinterpret_cast(Thread->CurrentFrame->State.rip)[0] != HLT) { - DidFault = true; - return EXCEPTION_CONTINUE_SEARCH; - } - - FEX::ArchHelpers::Context::SetPc(Context, reinterpret_cast(LongJumpHandler)); - return EXCEPTION_CONTINUE_EXECUTION; - } - default: break; } - printf("!Fault!\n"); - printf("\tExceptionCode: 0x%lx\n", ExceptionInfo->ExceptionRecord->ExceptionCode); - printf("\tExceptionFlags: 0x%lx\n", ExceptionInfo->ExceptionRecord->ExceptionFlags); - printf("\tExceptionRecord: 0x%p\n", ExceptionInfo->ExceptionRecord->ExceptionRecord); - printf("\tExceptionAddress: 0x%p\n", ExceptionInfo->ExceptionRecord->ExceptionAddress); - printf("\tNumberParameters: 0x%lx\n", ExceptionInfo->ExceptionRecord->NumberParameters); + longjmp(LongJumpHandler::LongJump, 1); + return false; + }, + true); +} +#else +FEX::DummyHandlers::DummySignalDelegator* Handler; - return EXCEPTION_CONTINUE_SEARCH; - } - - void RegisterLongJumpHandler(FEX::DummyHandlers::DummySignalDelegator *Handler) { - // Install VEH handler. - AddVectoredExceptionHandler(0, VectoredExceptionHandler); - - LongJumpHandler::Handler = Handler; - } -#endif +static void LongJumpHandler() { + longjmp(LongJump, 1); } -int main(int argc, char **argv, char **const envp) { +LONG WINAPI VectoredExceptionHandler(struct _EXCEPTION_POINTERS* ExceptionInfo) { + auto Thread = Handler->GetBackingTLSThread(); + PCONTEXT Context; + Context = ExceptionInfo->ContextRecord; + + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { + case STATUS_DATATYPE_MISALIGNMENT: { + const auto PC = FEX::ArchHelpers::Context::GetPc(Context); + if (!Thread->CTX->IsAddressInCodeBuffer(Thread, PC)) { + // Wasn't a sigbus in JIT code + return EXCEPTION_CONTINUE_SEARCH; + } + + const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(true, PC, FEX::ArchHelpers::Context::GetArmGPRs(Context)); + FEX::ArchHelpers::Context::SetPc(Context, PC + Result.second); + return Result.first ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; + } + case STATUS_ACCESS_VIOLATION: { + constexpr uint8_t HLT = 0xF4; + if (reinterpret_cast(Thread->CurrentFrame->State.rip)[0] != HLT) { + DidFault = true; + return EXCEPTION_CONTINUE_SEARCH; + } + + FEX::ArchHelpers::Context::SetPc(Context, reinterpret_cast(LongJumpHandler)); + return EXCEPTION_CONTINUE_EXECUTION; + } + default: break; + } + + printf("!Fault!\n"); + printf("\tExceptionCode: 0x%lx\n", ExceptionInfo->ExceptionRecord->ExceptionCode); + printf("\tExceptionFlags: 0x%lx\n", ExceptionInfo->ExceptionRecord->ExceptionFlags); + printf("\tExceptionRecord: 0x%p\n", ExceptionInfo->ExceptionRecord->ExceptionRecord); + printf("\tExceptionAddress: 0x%p\n", ExceptionInfo->ExceptionRecord->ExceptionAddress); + printf("\tNumberParameters: 0x%lx\n", ExceptionInfo->ExceptionRecord->NumberParameters); + + return EXCEPTION_CONTINUE_SEARCH; +} + +void RegisterLongJumpHandler(FEX::DummyHandlers::DummySignalDelegator* Handler) { + // Install VEH handler. + AddVectoredExceptionHandler(0, VectoredExceptionHandler); + + LongJumpHandler::Handler = Handler; +} +#endif +} // namespace LongJumpHandler + +int main(int argc, char** argv, char** const envp) { #ifndef _WIN32 auto SBRKPointer = FEXCore::Allocator::DisableSBRKAllocations(); #endif @@ -216,7 +216,7 @@ int main(int argc, char **argv, char **const envp) { return -1; } - FEX::HarnessHelper::HarnessCodeLoader Loader{Filename, ConfigFile}; + FEX::HarnessHelper::HarnessCodeLoader Loader {Filename, ConfigFile}; // Adds in environment options from the test harness config FEXCore::Config::AddLayer(fextl::make_unique(Loader.GetEnvironmentOptions())); @@ -263,20 +263,14 @@ int main(int argc, char **argv, char **const envp) { SupportsAVX = HostFeatures.SupportsAVX; SupportsAVX2 = HostFeatures.SupportsAVX2; - bool TestUnsupported = - (!HostFeatures.Supports3DNow && Loader.Requires3DNow()) || - (!HostFeatures.SupportsSSE4A && Loader.RequiresSSE4A()) || - (!SupportsAVX && Loader.RequiresAVX()) || - (!SupportsAVX2 && Loader.RequiresAVX2()) || - (!HostFeatures.SupportsRAND && Loader.RequiresRAND()) || - (!HostFeatures.SupportsSHA && Loader.RequiresSHA()) || - (!HostFeatures.SupportsCLZERO && Loader.RequiresCLZERO()) || - (!HostFeatures.SupportsBMI1 && Loader.RequiresBMI1()) || - (!HostFeatures.SupportsBMI2 && Loader.RequiresBMI2()) || - (!HostFeatures.SupportsCLWB && Loader.RequiresCLWB()); + bool TestUnsupported = (!HostFeatures.Supports3DNow && Loader.Requires3DNow()) || (!HostFeatures.SupportsSSE4A && Loader.RequiresSSE4A()) || + (!SupportsAVX && Loader.RequiresAVX()) || (!SupportsAVX2 && Loader.RequiresAVX2()) || + (!HostFeatures.SupportsRAND && Loader.RequiresRAND()) || (!HostFeatures.SupportsSHA && Loader.RequiresSHA()) || + (!HostFeatures.SupportsCLZERO && Loader.RequiresCLZERO()) || (!HostFeatures.SupportsBMI1 && Loader.RequiresBMI1()) || + (!HostFeatures.SupportsBMI2 && Loader.RequiresBMI2()) || (!HostFeatures.SupportsCLWB && Loader.RequiresCLWB()); #ifdef _WIN32 - TestUnsupported |= Loader.RequiresLinux(); + TestUnsupported |= Loader.RequiresLinux(); #endif if (TestUnsupported) { @@ -285,8 +279,8 @@ int main(int argc, char **argv, char **const envp) { if (Core != FEXCore::Config::CONFIG_CUSTOM) { #ifndef _WIN32 - auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get()) - : FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator)); + auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get()) : + FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator)); #else auto SyscallHandler = FEX::WindowsHandlers::CreateSyscallHandler(); @@ -363,4 +357,3 @@ int main(int argc, char **argv, char **const envp) { return Passed ? 0 : -1; } - diff --git a/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.cpp b/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.cpp index c70280f4b..0e9b88cca 100644 --- a/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.cpp +++ b/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.cpp @@ -29,14 +29,17 @@ using namespace Xbyak; #ifdef _M_X86_64 -static inline int modify_ldt(int func, void *ldt) { return ::syscall(SYS_modify_ldt, func, ldt, sizeof(struct user_desc)); } +static inline int modify_ldt(int func, void* ldt) { + return ::syscall(SYS_modify_ldt, func, ldt, sizeof(struct user_desc)); +} class x86HostRunner final : public Xbyak::CodeGenerator { public: using AsmDispatch = void (*)(uintptr_t InitialRip, uintptr_t InitialStack); AsmDispatch DispatchPtr; - x86HostRunner() : CodeGenerator(4096) { + x86HostRunner() + : CodeGenerator(4096) { Setup32BitCodeSegment(); DispatchPtr = getCurr(); @@ -88,10 +91,10 @@ public: GetCodeSegmentEntryLocation = getCurr(); hlt(); - Label Gate{}; + Label Gate {}; // Patch gate entry point // mov(dword[rip + Gate], edi) - jmp(qword [rip + Gate], LabelType::T_FAR); + jmp(qword[rip + Gate], LabelType::T_FAR); L(Gate); dd(0x1'0000); // This is a 32-bit offset from the start of the gate. We start at 0x1'0000 + 0 @@ -113,14 +116,14 @@ public: ready(); } - bool HandleSIGSEGV(FEXCore::Core::CPUState *OutState, int Signal, void *info, void *ucontext) { - ucontext_t *_context = (ucontext_t *)ucontext; - mcontext_t *_mcontext = &_context->uc_mcontext; + bool HandleSIGSEGV(FEXCore::Core::CPUState* OutState, int Signal, void* info, void* ucontext) { + ucontext_t* _context = (ucontext_t*)ucontext; + mcontext_t* _mcontext = &_context->uc_mcontext; // Check our current instruction that we just executed to ensure it was an HLT - uint8_t *Inst{}; + uint8_t* Inst {}; - Inst = reinterpret_cast(_mcontext->gregs[REG_RIP]); + Inst = reinterpret_cast(_mcontext->gregs[REG_RIP]); if (!Is64BitMode()) { if (_mcontext->gregs[REG_RIP] == GetCodeSegmentEntryLocation) { // Backup the CSGSFS register @@ -161,8 +164,7 @@ public: const auto* reserved = &xstate->fpstate.sw_reserved; if (reserved->HasExtendedContext() && reserved->HasYMMH()) { for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) { - memcpy(&OutState->xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], - sizeof(xstate->ymmh.ymmh_space[0])); + memcpy(&OutState->xmm.avx.data[i][2], &xstate->ymmh.ymmh_space[i], sizeof(xstate->ymmh.ymmh_space[0])); } } @@ -189,8 +191,8 @@ public: private: FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); - int CodeSegmentEntry{}; - int GlobalCodeSegmentEntry{}; + int CodeSegmentEntry {}; + int GlobalCodeSegmentEntry {}; uint64_t GetCodeSegmentEntryLocation; uint64_t ReturningStackLocation; @@ -265,22 +267,21 @@ private: } }; -void RunAsHost(fextl::unique_ptr &SignalDelegation, uintptr_t InitialRip, uintptr_t StackPointer, - FEXCore::Core::CPUState *OutputState) { +void RunAsHost(fextl::unique_ptr& SignalDelegation, uintptr_t InitialRip, uintptr_t StackPointer, + FEXCore::Core::CPUState* OutputState) { x86HostRunner runner; SignalDelegation->RegisterHostSignalHandler( SIGSEGV, - [&runner, OutputState](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool { + [&runner, OutputState](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) -> bool { return runner.HandleSIGSEGV(OutputState, Signal, info, ucontext); }, - true - ); + true); runner.DispatchPtr(InitialRip, StackPointer); } #else -void RunAsHost(fextl::unique_ptr &SignalDelegation, uintptr_t InitialRip, uintptr_t StackPointer, - FEXCore::Core::CPUState *OutputState) { +void RunAsHost(fextl::unique_ptr& SignalDelegation, uintptr_t InitialRip, uintptr_t StackPointer, + FEXCore::Core::CPUState* OutputState) { LOGMAN_MSG_A_FMT("RunAsHost doesn't exist for this host"); } #endif diff --git a/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.h b/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.h index 08181ad9f..98e5c8eed 100644 --- a/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.h +++ b/Source/Tools/TestHarnessRunner/TestHarnessRunner/HostRunner.h @@ -4,18 +4,19 @@ #include namespace FEXCore::CPU { - class CPUBackend; +class CPUBackend; } -namespace FEXCore::Context{ - class Context; +namespace FEXCore::Context { +class Context; } namespace FEXCore::Core { - struct InternalThreadState; - struct CPUState; -} +struct InternalThreadState; +struct CPUState; +} // namespace FEXCore::Core namespace FEX::HLE { - class SignalDelegator; +class SignalDelegator; } -void RunAsHost(fextl::unique_ptr &SignalDelegation, uintptr_t InitialRip, uintptr_t StackPointer, FEXCore::Core::CPUState *OutputState); +void RunAsHost(fextl::unique_ptr& SignalDelegation, uintptr_t InitialRip, uintptr_t StackPointer, + FEXCore::Core::CPUState* OutputState); diff --git a/Source/Tools/pidof/pidof.cpp b/Source/Tools/pidof/pidof.cpp index 568c84c91..62226329c 100644 --- a/Source/Tools/pidof/pidof.cpp +++ b/Source/Tools/pidof/pidof.cpp @@ -11,38 +11,28 @@ namespace Config { -bool SingleShot{}; -bool SkipZombie{true}; -bool DoNotDisplay{}; +bool SingleShot {}; +bool SkipZombie {true}; +bool DoNotDisplay {}; std::string Separator {" "}; std::unordered_set OmitPids; std::unordered_set Programs; -void LoadOptions(int argc, char **argv) { - optparse::OptionParser Parser{}; +void LoadOptions(int argc, char** argv) { + optparse::OptionParser Parser {}; - Parser.add_option("-s") - .help("Single shot - Only returns one pid") - .action("store_true") - .set_default(SingleShot); + Parser.add_option("-s").help("Single shot - Only returns one pid").action("store_true").set_default(SingleShot); Parser.add_option("-q") .help("Do not display matched PIDs to stdout. Simply exit with status of true or false if a PID was found") .action("store_true") .set_default(DoNotDisplay); - Parser.add_option("-z") - .help("Try to detect zombie processes - Usually zombie processes are skipped") - .action("store_false") - .set_default(SkipZombie); + Parser.add_option("-z").help("Try to detect zombie processes - Usually zombie processes are skipped").action("store_false").set_default(SkipZombie); - Parser.add_option("-d") - .help("Use a different separator if more than one pid is show - Default is space") - .set_default(Separator); + Parser.add_option("-d").help("Use a different separator if more than one pid is show - Default is space").set_default(Separator); - Parser.add_option("-o") - .help("Ignore processes with matched pids") - .action("append"); + Parser.add_option("-o").help("Ignore processes with matched pids").action("append"); optparse::Values Options = Parser.parse_args(argc, argv); @@ -51,25 +41,27 @@ void LoadOptions(int argc, char **argv) { SkipZombie = Options.get("z"); Separator = Options["d"]; - for (const auto &Omit: Options.all("o")) { - std::istringstream ss{Omit}; + for (const auto& Omit : Options.all("o")) { + std::istringstream ss {Omit}; std::string sub; while (std::getline(ss, sub, ',')) { int64_t pid; auto ConvResult = std::from_chars(sub.data(), sub.data() + sub.size(), pid, 10); // Invalid pid, skip. - if (ConvResult.ec == std::errc::invalid_argument) continue; + if (ConvResult.ec == std::errc::invalid_argument) { + continue; + } OmitPids.emplace(pid); } } - for (const auto &Program : Parser.args()) { + for (const auto& Program : Parser.args()) { Programs.emplace(Program); } } -} +} // namespace Config struct PIDInfo { int64_t pid; @@ -80,20 +72,24 @@ struct PIDInfo { std::vector PIDs; -int main(int argc, char **argv) { +int main(int argc, char** argv) { Config::LoadOptions(argc, argv); // Iterate over all pids, storing the data for investigating afterwards. - for (const auto &Entry : std::filesystem::directory_iterator("/proc/")) { + for (const auto& Entry : std::filesystem::directory_iterator("/proc/")) { // If not a directory then skip. - if (!Entry.is_directory()) continue; + if (!Entry.is_directory()) { + continue; + } auto CMDLinePath = Entry.path() / "cmdline"; auto StatusPath = Entry.path() / "status"; auto ExePath = Entry.path() / "exe"; // If cmdline doesn't exist then skip. - if (!std::filesystem::exists(CMDLinePath)) continue; + if (!std::filesystem::exists(CMDLinePath)) { + continue; + } auto Filename = Entry.path().filename().string(); int64_t pid; @@ -101,25 +97,33 @@ int main(int argc, char **argv) { // If the filename couldn't be converted to a PID then skip. // Happens with folders like `self` and a few other folders in this directory. - if (ConvResult.ec == std::errc::invalid_argument) continue; + if (ConvResult.ec == std::errc::invalid_argument) { + continue; + } std::ostringstream CMDLineData; { std::ifstream fs(CMDLinePath, std::ios_base::in | std::ios_base::binary); - if (!fs.is_open()) continue; + if (!fs.is_open()) { + continue; + } CMDLineData << fs.rdbuf(); // If cmdline was empty then skip. - if (CMDLineData.str().empty()) continue; + if (CMDLineData.str().empty()) { + continue; + } } std::error_code ec; std::string exe_link = std::filesystem::read_symlink(ExePath, ec); // Couldn't read exe path? skip. - if (ec) continue; + if (ec) { + continue; + } // Read state char State; @@ -127,12 +131,16 @@ int main(int argc, char **argv) { { std::ifstream fs(StatusPath, std::ios_base::in | std::ios_base::binary); - if (!fs.is_open()) continue; + if (!fs.is_open()) { + continue; + } std::string Line; while (std::getline(fs, Line)) { - if (fs.eof()) break; + if (fs.eof()) { + break; + } if (Line.find("State") == Line.npos) { continue; @@ -145,44 +153,52 @@ int main(int argc, char **argv) { } PIDs.emplace_back(PIDInfo { - .pid = pid, - .cmdline = CMDLineData.str(), - .exe_link = exe_link, - .State = State, + .pid = pid, + .cmdline = CMDLineData.str(), + .exe_link = exe_link, + .State = State, }); } std::unordered_set MatchedPIDs; - for (const auto &pid : PIDs) { - if (pid.State == 'Z' && Config::SkipZombie) continue; - if (Config::OmitPids.contains(pid.pid)) continue; + for (const auto& pid : PIDs) { + if (pid.State == 'Z' && Config::SkipZombie) { + continue; + } + if (Config::OmitPids.contains(pid.pid)) { + continue; + } std::vector Args; - const char *arg = pid.cmdline.data(); + const char* arg = pid.cmdline.data(); while (arg[0]) { Args.emplace_back(arg); arg += strlen(arg) + 1; } - auto IsFEX = [](auto &Path) { - if (Path.ends_with("FEXInterpreter")) return true; - if (Path.ends_with("FEXLoader")) return true; + auto IsFEX = [](auto& Path) { + if (Path.ends_with("FEXInterpreter")) { + return true; + } + if (Path.ends_with("FEXLoader")) { + return true; + } return false; }; bool IsFEXBin = IsFEX(pid.exe_link) || IsFEX(Args[0]); - if (!IsFEXBin) continue; + if (!IsFEXBin) { + continue; + } auto Arg1 = Args[1]; auto Arg1Program = std::filesystem::path(Arg1).filename(); bool Matched = false; - for (const auto &CompareProgram : Config::Programs) { + for (const auto& CompareProgram : Config::Programs) { auto CompareProgramFilename = std::filesystem::path(CompareProgram).filename(); - if (CompareProgram == Arg1Program || - CompareProgram == Arg1 || - CompareProgramFilename == Arg1Program) { + if (CompareProgram == Arg1Program || CompareProgram == Arg1 || CompareProgramFilename == Arg1Program) { MatchedPIDs.emplace(pid.pid); Matched = true; break; @@ -196,12 +212,11 @@ int main(int argc, char **argv) { if (!MatchedPIDs.empty() && !Config::DoNotDisplay) { bool first = true; - for (const auto &MatchedPID : MatchedPIDs) { + for (const auto& MatchedPID : MatchedPIDs) { if (first) { fmt::print("{}", MatchedPID); first = false; - } - else { + } else { fmt::print("{}{}", Config::Separator, MatchedPID); } } diff --git a/Source/Windows/Common/CPUFeatures.cpp b/Source/Windows/Common/CPUFeatures.cpp index a83db1961..ec1d13b08 100644 --- a/Source/Windows/Common/CPUFeatures.cpp +++ b/Source/Windows/Common/CPUFeatures.cpp @@ -4,16 +4,14 @@ #include "CPUFeatures.h" namespace FEX::Windows { -CPUFeatures::CPUFeatures(FEXCore::Context::Context &CTX) { +CPUFeatures::CPUFeatures(FEXCore::Context::Context& CTX) { CpuInfo.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; // Baseline FEX feature-set - CpuInfo.ProcessorFeatureBits = CPU_FEATURE_VME | CPU_FEATURE_TSC | CPU_FEATURE_CMOV | CPU_FEATURE_PGE | - CPU_FEATURE_PSE | CPU_FEATURE_MTRR | CPU_FEATURE_CX8 | CPU_FEATURE_MMX | - CPU_FEATURE_X86 | CPU_FEATURE_PAT | CPU_FEATURE_FXSR | CPU_FEATURE_SEP | - CPU_FEATURE_SSE | CPU_FEATURE_3DNOW | CPU_FEATURE_SSE2 | CPU_FEATURE_SSE3 | - CPU_FEATURE_CX128 | CPU_FEATURE_NX | CPU_FEATURE_SSSE3 | CPU_FEATURE_SSE41 | - CPU_FEATURE_PAE | CPU_FEATURE_DAZ; + CpuInfo.ProcessorFeatureBits = CPU_FEATURE_VME | CPU_FEATURE_TSC | CPU_FEATURE_CMOV | CPU_FEATURE_PGE | CPU_FEATURE_PSE | CPU_FEATURE_MTRR | + CPU_FEATURE_CX8 | CPU_FEATURE_MMX | CPU_FEATURE_X86 | CPU_FEATURE_PAT | CPU_FEATURE_FXSR | CPU_FEATURE_SEP | + CPU_FEATURE_SSE | CPU_FEATURE_3DNOW | CPU_FEATURE_SSE2 | CPU_FEATURE_SSE3 | CPU_FEATURE_CX128 | + CPU_FEATURE_NX | CPU_FEATURE_SSSE3 | CPU_FEATURE_SSE41 | CPU_FEATURE_PAE | CPU_FEATURE_DAZ; // Features that require specific host CPU support const auto CPUIDResult01 = CTX.RunCPUIDFunction(0x01, 0); @@ -34,69 +32,44 @@ CPUFeatures::CPUFeatures(FEXCore::Context::Context &CTX) { const auto FamilyIdentifier = CPUIDResult01.eax; CpuInfo.ProcessorLevel = ((FamilyIdentifier >> 8) & 0xf) + ((FamilyIdentifier >> 20) & 0xff); // Family - CpuInfo.ProcessorRevision = (FamilyIdentifier & 0xf0000) >> 4; // Extended Model - CpuInfo.ProcessorRevision |= (FamilyIdentifier & 0xf0) << 4; // Model - CpuInfo.ProcessorRevision |= FamilyIdentifier & 0xf; // Stepping + CpuInfo.ProcessorRevision = (FamilyIdentifier & 0xf0000) >> 4; // Extended Model + CpuInfo.ProcessorRevision |= (FamilyIdentifier & 0xf0) << 4; // Model + CpuInfo.ProcessorRevision |= FamilyIdentifier & 0xf; // Stepping } bool CPUFeatures::IsFeaturePresent(uint32_t Feature) { switch (Feature) { - case PF_FLOATING_POINT_PRECISION_ERRATA: - return FALSE; - case PF_FLOATING_POINT_EMULATED: - return FALSE; - case PF_COMPARE_EXCHANGE_DOUBLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_CX8); - case PF_MMX_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_MMX); - case PF_XMMI_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE); - case PF_3DNOW_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_3DNOW); - case PF_RDTSC_INSTRUCTION_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_TSC); - case PF_PAE_ENABLED: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_PAE); - case PF_XMMI64_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE2); - case PF_SSE3_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE3); - case PF_SSSE3_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSSE3); - case PF_XSAVE_ENABLED: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_XSAVE); - case PF_COMPARE_EXCHANGE128: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_CX128); - case PF_SSE_DAZ_MODE_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_DAZ); - case PF_NX_ENABLED: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_NX); - case PF_SECOND_LEVEL_ADDRESS_TRANSLATION: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_2NDLEV); - case PF_VIRT_FIRMWARE_ENABLED: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_VIRT); - case PF_RDWRFSGSBASE_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_RDFS); - case PF_FASTFAIL_AVAILABLE: - return TRUE; - case PF_SSE4_1_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE41); - case PF_SSE4_2_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE42); - case PF_AVX_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX); - case PF_AVX2_INSTRUCTIONS_AVAILABLE: - return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX2); - default: - LogMan::Msg::DFmt("Unknown CPU feature: {:X}", Feature); - return false; + case PF_FLOATING_POINT_PRECISION_ERRATA: return FALSE; + case PF_FLOATING_POINT_EMULATED: return FALSE; + case PF_COMPARE_EXCHANGE_DOUBLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_CX8); + case PF_MMX_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_MMX); + case PF_XMMI_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE); + case PF_3DNOW_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_3DNOW); + case PF_RDTSC_INSTRUCTION_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_TSC); + case PF_PAE_ENABLED: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_PAE); + case PF_XMMI64_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE2); + case PF_SSE3_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE3); + case PF_SSSE3_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSSE3); + case PF_XSAVE_ENABLED: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_XSAVE); + case PF_COMPARE_EXCHANGE128: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_CX128); + case PF_SSE_DAZ_MODE_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_DAZ); + case PF_NX_ENABLED: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_NX); + case PF_SECOND_LEVEL_ADDRESS_TRANSLATION: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_2NDLEV); + case PF_VIRT_FIRMWARE_ENABLED: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_VIRT); + case PF_RDWRFSGSBASE_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_RDFS); + case PF_FASTFAIL_AVAILABLE: return TRUE; + case PF_SSE4_1_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE41); + case PF_SSE4_2_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE42); + case PF_AVX_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX); + case PF_AVX2_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX2); + default: LogMan::Msg::DFmt("Unknown CPU feature: {:X}", Feature); return false; } } -void CPUFeatures::UpdateInformation(SYSTEM_CPU_INFORMATION *Info) { +void CPUFeatures::UpdateInformation(SYSTEM_CPU_INFORMATION* Info) { Info->ProcessorArchitecture = CpuInfo.ProcessorArchitecture; Info->ProcessorLevel = CpuInfo.ProcessorLevel; Info->ProcessorRevision = CpuInfo.ProcessorRevision; Info->ProcessorFeatureBits = CpuInfo.ProcessorFeatureBits; } -} +} // namespace FEX::Windows diff --git a/Source/Windows/Common/CPUFeatures.h b/Source/Windows/Common/CPUFeatures.h index 5e64c425a..7da8084a0 100644 --- a/Source/Windows/Common/CPUFeatures.h +++ b/Source/Windows/Common/CPUFeatures.h @@ -5,7 +5,7 @@ #include namespace FEXCore::Context { - class Context; +class Context; } /** @@ -14,19 +14,19 @@ namespace FEXCore::Context { namespace FEX::Windows { class CPUFeatures { public: - CPUFeatures(FEXCore::Context::Context &CTX); + CPUFeatures(FEXCore::Context::Context& CTX); /** - * @brief If the given PF_* feature is supported + * @brief If the given PF_* feature is supported */ bool IsFeaturePresent(uint32_t Feature); /** * @brief Fills in `Info` according to the detected CPU features */ - void UpdateInformation(SYSTEM_CPU_INFORMATION *Info); + void UpdateInformation(SYSTEM_CPU_INFORMATION* Info); private: - SYSTEM_CPU_INFORMATION CpuInfo{}; + SYSTEM_CPU_INFORMATION CpuInfo {}; }; -} +} // namespace FEX::Windows diff --git a/Source/Windows/Common/IntervalList.h b/Source/Windows/Common/IntervalList.h index 6c2b772a4..69e729651 100644 --- a/Source/Windows/Common/IntervalList.h +++ b/Source/Windows/Common/IntervalList.h @@ -17,7 +17,9 @@ public: Interval() = default; - Interval(SizeType Offset, SizeType End) : Offset{Offset}, End{End} {} + Interval(SizeType Offset, SizeType End) + : Offset {Offset} + , End {End} {} }; private: @@ -25,7 +27,7 @@ private: public: struct QueryResult { - bool Enclosed; ///< If the given offset was enclosed by an interval + bool Enclosed; ///< If the given offset was enclosed by an interval DifferenceType Size; ///< Size of the interval starting from the query offset, or distance to the next interval if /// `Enclosed` is false (if there is no next interval, size is 0) }; @@ -39,9 +41,8 @@ public: return; } - auto [FirstIt, EndIt] = std::equal_range(Intervals.begin(), Intervals.end(), Entry, [](const auto &LHS, const auto &RHS) { - return LHS.End <= RHS.Offset; - }); + auto [FirstIt, EndIt] = + std::equal_range(Intervals.begin(), Intervals.end(), Entry, [](const auto& LHS, const auto& RHS) { return LHS.End <= RHS.Offset; }); if (FirstIt == EndIt) { // No overlaps @@ -70,9 +71,8 @@ public: return; } - auto [FirstIt, EndIt] = std::equal_range(Intervals.begin(), Intervals.end(), Entry, [](const auto &LHS, const auto &RHS) { - return LHS.End <= RHS.Offset; - }); + auto [FirstIt, EndIt] = + std::equal_range(Intervals.begin(), Intervals.end(), Entry, [](const auto& LHS, const auto& RHS) { return LHS.End <= RHS.Offset; }); if (FirstIt == EndIt) { // No intersecting intervals present, nothing more to do @@ -81,7 +81,7 @@ public: if (FirstIt->Offset < Entry.Offset && FirstIt->End > Entry.End) { // The interval to be removed is fully enclosed by an existing interval - + // Break the single interval into two smaller intervals on either side on the interval being removed const auto FirstPredecessorIt = Intervals.insert(FirstIt, *FirstIt); FirstIt = std::next(FirstPredecessorIt); @@ -122,7 +122,7 @@ public: } QueryResult Query(SizeType Offset) { - const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Offset, [](const auto &LHS, const auto &RHS) { + const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Offset, [](const auto& LHS, const auto& RHS) { return LHS < RHS.End; }); // Lowest offset interval that (maybe) overlaps with the query offset @@ -136,7 +136,7 @@ public: } bool Intersect(Interval Entry) { - const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Entry, [](const auto &LHS, const auto &RHS) { + const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Entry, [](const auto& LHS, const auto& RHS) { return LHS.Offset < RHS.End; }); // Lowest offset interval that (maybe) overlaps with the query offset diff --git a/Source/Windows/Common/InvalidationTracker.cpp b/Source/Windows/Common/InvalidationTracker.cpp index 0ad1da30b..85074c26d 100644 --- a/Source/Windows/Common/InvalidationTracker.cpp +++ b/Source/Windows/Common/InvalidationTracker.cpp @@ -9,7 +9,8 @@ #include namespace FEX::Windows { -void InvalidationTracker::HandleMemoryProtectionNotification(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, uint64_t Size, ULONG Prot) { +void InvalidationTracker::HandleMemoryProtectionNotification(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, uint64_t Size, + ULONG Prot) { const auto AlignedBase = Address & FEXCore::Utils::FEX_PAGE_MASK; const auto AlignedSize = (Address - AlignedBase + Size + FEXCore::Utils::FEX_PAGE_SIZE - 1) & FEXCore::Utils::FEX_PAGE_MASK; @@ -27,14 +28,14 @@ void InvalidationTracker::HandleMemoryProtectionNotification(FEXCore::Core::Inte } } -void InvalidationTracker::InvalidateContainingSection(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, bool Free) { +void InvalidationTracker::InvalidateContainingSection(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, bool Free) { MEMORY_BASIC_INFORMATION Info; - if (NtQueryVirtualMemory(NtCurrentProcess(), reinterpret_cast(Address), MemoryBasicInformation, &Info, sizeof(Info), nullptr)) + if (NtQueryVirtualMemory(NtCurrentProcess(), reinterpret_cast(Address), MemoryBasicInformation, &Info, sizeof(Info), nullptr)) { return; + } const auto SectionBase = reinterpret_cast(Info.AllocationBase); - const auto SectionSize = reinterpret_cast(Info.BaseAddress) + Info.RegionSize - - reinterpret_cast(Info.AllocationBase); + const auto SectionSize = reinterpret_cast(Info.BaseAddress) + Info.RegionSize - reinterpret_cast(Info.AllocationBase); Thread->CTX->InvalidateGuestCodeRange(Thread, SectionBase, SectionSize); if (Free) { @@ -43,7 +44,7 @@ void InvalidationTracker::InvalidateContainingSection(FEXCore::Core::InternalThr } } -void InvalidationTracker::InvalidateAlignedInterval(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, uint64_t Size, bool Free) { +void InvalidationTracker::InvalidateAlignedInterval(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, uint64_t Size, bool Free) { const auto AlignedBase = Address & FEXCore::Utils::FEX_PAGE_MASK; const auto AlignedSize = (Address - AlignedBase + Size + FEXCore::Utils::FEX_PAGE_SIZE - 1) & FEXCore::Utils::FEX_PAGE_MASK; Thread->CTX->InvalidateGuestCodeRange(Thread, AlignedBase, AlignedSize); @@ -61,7 +62,7 @@ void InvalidationTracker::ReprotectRWXIntervals(uint64_t Address, uint64_t Size) do { const auto Query = RWXIntervals.Query(Address); if (Query.Enclosed) { - void *TmpAddress = reinterpret_cast(Address); + void* TmpAddress = reinterpret_cast(Address); SIZE_T TmpSize = static_cast(std::min(End, Address + Query.Size) - Address); ULONG TmpProt; NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_EXECUTE_READ, &TmpProt); @@ -74,16 +75,17 @@ void InvalidationTracker::ReprotectRWXIntervals(uint64_t Address, uint64_t Size) } while (Address < End); } -bool InvalidationTracker::HandleRWXAccessViolation(FEXCore::Core::InternalThreadState *Thread, uint64_t FaultAddress) { +bool InvalidationTracker::HandleRWXAccessViolation(FEXCore::Core::InternalThreadState* Thread, uint64_t FaultAddress) { const bool NeedsInvalidate = [&](uint64_t Address) { std::unique_lock Lock(RWXIntervalsLock); const bool Enclosed = RWXIntervals.Query(Address).Enclosed; // Invalidate just the single faulting page - if (!Enclosed) + if (!Enclosed) { return false; + } ULONG TmpProt; - void *TmpAddress = reinterpret_cast(Address); + void* TmpAddress = reinterpret_cast(Address); SIZE_T TmpSize = 1; NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_EXECUTE_READWRITE, &TmpProt); return true; @@ -96,4 +98,4 @@ bool InvalidationTracker::HandleRWXAccessViolation(FEXCore::Core::InternalThread } return false; } -} +} // namespace FEX::Windows diff --git a/Source/Windows/Common/InvalidationTracker.h b/Source/Windows/Common/InvalidationTracker.h index 86aa8afce..4851730b6 100644 --- a/Source/Windows/Common/InvalidationTracker.h +++ b/Source/Windows/Common/InvalidationTracker.h @@ -6,7 +6,7 @@ #include namespace FEXCore::Core { - struct InternalThreadState; +struct InternalThreadState; } namespace FEX::Windows { @@ -15,14 +15,14 @@ namespace FEX::Windows { */ class InvalidationTracker { public: - void HandleMemoryProtectionNotification(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, uint64_t Size, ULONG Prot); - void InvalidateContainingSection(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, bool Free); - void InvalidateAlignedInterval(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, uint64_t Size, bool Free); + void HandleMemoryProtectionNotification(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, uint64_t Size, ULONG Prot); + void InvalidateContainingSection(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, bool Free); + void InvalidateAlignedInterval(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, uint64_t Size, bool Free); void ReprotectRWXIntervals(uint64_t Address, uint64_t Size); - bool HandleRWXAccessViolation(FEXCore::Core::InternalThreadState *Thread, uint64_t FaultAddress); + bool HandleRWXAccessViolation(FEXCore::Core::InternalThreadState* Thread, uint64_t FaultAddress); private: IntervalList RWXIntervals; std::mutex RWXIntervalsLock; }; -} +} // namespace FEX::Windows diff --git a/Source/Windows/WOW64/BTInterface.h b/Source/Windows/WOW64/BTInterface.h index 7ff7f019f..80d1c8fc5 100644 --- a/Source/Windows/WOW64/BTInterface.h +++ b/Source/Windows/WOW64/BTInterface.h @@ -9,18 +9,18 @@ extern "C" { void STDMETHODCALLTYPE BTCpuProcessInit(); NTSTATUS STDMETHODCALLTYPE BTCpuThreadInit(); NTSTATUS STDMETHODCALLTYPE BTCpuThreadTerm(HANDLE Thread); -void STDMETHODCALLTYPE *BTCpuGetBopCode(); -void STDMETHODCALLTYPE *__wine_get_unix_opcode(); -NTSTATUS STDMETHODCALLTYPE BTCpuGetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context); -NTSTATUS STDMETHODCALLTYPE BTCpuSetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context); +void STDMETHODCALLTYPE* BTCpuGetBopCode(); +void STDMETHODCALLTYPE* __wine_get_unix_opcode(); +NTSTATUS STDMETHODCALLTYPE BTCpuGetContext(HANDLE Thread, HANDLE Process, void* Unknown, WOW64_CONTEXT* Context); +NTSTATUS STDMETHODCALLTYPE BTCpuSetContext(HANDLE Thread, HANDLE Process, void* Unknown, WOW64_CONTEXT* Context); void STDMETHODCALLTYPE BTCpuSimulate(); -NTSTATUS STDMETHODCALLTYPE BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count); -NTSTATUS STDMETHODCALLTYPE BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs); -void STDMETHODCALLTYPE BTCpuFlushInstructionCache2(const void *Address, SIZE_T Size); -void STDMETHODCALLTYPE BTCpuNotifyMemoryAlloc(void *Address, SIZE_T Size, ULONG Type, ULONG Prot); -void STDMETHODCALLTYPE BTCpuNotifyMemoryProtect(void *Address, SIZE_T Size, ULONG NewProt); -void STDMETHODCALLTYPE BTCpuNotifyMemoryFree(void *Address, SIZE_T Size, ULONG FreeType); -void STDMETHODCALLTYPE BTCpuNotifyUnmapViewOfSection(void *Address, ULONG Flags); +NTSTATUS STDMETHODCALLTYPE BTCpuSuspendLocalThread(HANDLE Thread, ULONG* Count); +NTSTATUS STDMETHODCALLTYPE BTCpuResetToConsistentState(EXCEPTION_POINTERS* Ptrs); +void STDMETHODCALLTYPE BTCpuFlushInstructionCache2(const void* Address, SIZE_T Size); +void STDMETHODCALLTYPE BTCpuNotifyMemoryAlloc(void* Address, SIZE_T Size, ULONG Type, ULONG Prot); +void STDMETHODCALLTYPE BTCpuNotifyMemoryProtect(void* Address, SIZE_T Size, ULONG NewProt); +void STDMETHODCALLTYPE BTCpuNotifyMemoryFree(void* Address, SIZE_T Size, ULONG FreeType); +void STDMETHODCALLTYPE BTCpuNotifyUnmapViewOfSection(void* Address, ULONG Flags); BOOLEAN STDMETHODCALLTYPE BTCpuIsProcessorFeaturePresent(UINT Feature); -BOOLEAN STDMETHODCALLTYPE BTCpuUpdateProcessorInformation(SYSTEM_CPU_INFORMATION *Info); +BOOLEAN STDMETHODCALLTYPE BTCpuUpdateProcessorInformation(SYSTEM_CPU_INFORMATION* Info); } diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index c9ba14dad..a48a59e93 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -44,16 +44,16 @@ $end_info$ #include namespace ControlBits { - // When this is unset, a thread can be safely interrupted and have its context recovered - // IMPORTANT: This can only safely be written by the owning thread - static constexpr uint32_t IN_JIT{1U << 0}; +// When this is unset, a thread can be safely interrupted and have its context recovered +// IMPORTANT: This can only safely be written by the owning thread +static constexpr uint32_t IN_JIT {1U << 0}; - // JIT entry polls this bit until it is unset, at which point CONTROL_IN_JIT will be set - static constexpr uint32_t PAUSED{1U << 1}; +// JIT entry polls this bit until it is unset, at which point CONTROL_IN_JIT will be set +static constexpr uint32_t PAUSED {1U << 1}; - // When this is set, the CPU context stored in the CPU area has not yet been flushed to the FEX TLS - static constexpr uint32_t WOW_CPU_AREA_DIRTY{1U << 2}; -}; +// When this is set, the CPU context stored in the CPU area has not yet been flushed to the FEX TLS +static constexpr uint32_t WOW_CPU_AREA_DIRTY {1U << 2}; +}; // namespace ControlBits struct TLS { enum class Slot : size_t { @@ -62,299 +62,295 @@ struct TLS { THREAD_STATE = WOW64_TLS_MAX_NUMBER - 2, }; - _TEB *TEB; + _TEB* TEB; - explicit TLS(_TEB *TEB) : TEB(TEB) {} + explicit TLS(_TEB* TEB) + : TEB(TEB) {} - std::atomic &ControlWord() const { + std::atomic& ControlWord() const { // TODO: Change this when libc++ gains std::atomic_ref support - return reinterpret_cast &>(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::CONTROL_WORD)]); + return reinterpret_cast&>(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::CONTROL_WORD)]); } - CONTEXT *&EntryContext() const { - return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::ENTRY_CONTEXT)]); + CONTEXT*& EntryContext() const { + return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::ENTRY_CONTEXT)]); } - FEXCore::Core::InternalThreadState *&ThreadState() const { - return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::THREAD_STATE)]); + FEXCore::Core::InternalThreadState*& ThreadState() const { + return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::THREAD_STATE)]); } }; class WowSyscallHandler; namespace { - namespace BridgeInstrs { - // These directly jumped to by the guest to make system calls - uint16_t Syscall{0x2ecd}; - uint16_t UnixCall{0x2ecd}; - } +namespace BridgeInstrs { + // These directly jumped to by the guest to make system calls + uint16_t Syscall {0x2ecd}; + uint16_t UnixCall {0x2ecd}; +} // namespace BridgeInstrs - fextl::unique_ptr CTX; - fextl::unique_ptr SignalDelegator; - fextl::unique_ptr SyscallHandler; +fextl::unique_ptr CTX; +fextl::unique_ptr SignalDelegator; +fextl::unique_ptr SyscallHandler; - FEX::Windows::InvalidationTracker InvalidationTracker; - std::optional CPUFeatures; +FEX::Windows::InvalidationTracker InvalidationTracker; +std::optional CPUFeatures; - std::mutex ThreadSuspendLock; - std::unordered_set InitializedWOWThreads; // Set of TIDs, `ThreadSuspendLock` must be locked when accessing +std::mutex ThreadSuspendLock; +std::unordered_set InitializedWOWThreads; // Set of TIDs, `ThreadSuspendLock` must be locked when accessing - std::pair GetThreadTLS(HANDLE Thread) { - THREAD_BASIC_INFORMATION Info; - const NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); - return {Err, TLS{reinterpret_cast<_TEB *>(Info.TebBaseAddress)}}; - } - - TLS GetTLS() { - return TLS{NtCurrentTeb()}; - } - - uint64_t GetWowTEB(void *TEB) { - static constexpr size_t WowTEBOffsetMemberOffset{0x180c}; - return static_cast(*reinterpret_cast(reinterpret_cast(TEB) + WowTEBOffsetMemberOffset) - + reinterpret_cast(TEB)); - } - - bool IsAddressInJit(uint64_t Address) { - auto Thread = GetTLS().ThreadState(); - return Thread->CTX->IsAddressInCodeBuffer(Thread, Address); - } +std::pair GetThreadTLS(HANDLE Thread) { + THREAD_BASIC_INFORMATION Info; + const NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); + return {Err, TLS {reinterpret_cast<_TEB*>(Info.TebBaseAddress)}}; } +TLS GetTLS() { + return TLS {NtCurrentTeb()}; +} + +uint64_t GetWowTEB(void* TEB) { + static constexpr size_t WowTEBOffsetMemberOffset {0x180c}; + return static_cast( + *reinterpret_cast(reinterpret_cast(TEB) + WowTEBOffsetMemberOffset) + reinterpret_cast(TEB)); +} + +bool IsAddressInJit(uint64_t Address) { + auto Thread = GetTLS().ThreadState(); + return Thread->CTX->IsAddressInCodeBuffer(Thread, Address); +} +} // namespace + namespace Context { - void LoadStateFromWowContext(FEXCore::Core::InternalThreadState *Thread, uint64_t WowTEB, WOW64_CONTEXT *Context) { - auto &State = Thread->CurrentFrame->State; +void LoadStateFromWowContext(FEXCore::Core::InternalThreadState* Thread, uint64_t WowTEB, WOW64_CONTEXT* Context) { + auto& State = Thread->CurrentFrame->State; - // General register state + // General register state - State.gregs[FEXCore::X86State::REG_RAX] = Context->Eax; - State.gregs[FEXCore::X86State::REG_RBX] = Context->Ebx; - State.gregs[FEXCore::X86State::REG_RCX] = Context->Ecx; - State.gregs[FEXCore::X86State::REG_RDX] = Context->Edx; - State.gregs[FEXCore::X86State::REG_RSI] = Context->Esi; - State.gregs[FEXCore::X86State::REG_RDI] = Context->Edi; - State.gregs[FEXCore::X86State::REG_RBP] = Context->Ebp; - State.gregs[FEXCore::X86State::REG_RSP] = Context->Esp; + State.gregs[FEXCore::X86State::REG_RAX] = Context->Eax; + State.gregs[FEXCore::X86State::REG_RBX] = Context->Ebx; + State.gregs[FEXCore::X86State::REG_RCX] = Context->Ecx; + State.gregs[FEXCore::X86State::REG_RDX] = Context->Edx; + State.gregs[FEXCore::X86State::REG_RSI] = Context->Esi; + State.gregs[FEXCore::X86State::REG_RDI] = Context->Edi; + State.gregs[FEXCore::X86State::REG_RBP] = Context->Ebp; + State.gregs[FEXCore::X86State::REG_RSP] = Context->Esp; - State.rip = Context->Eip; - CTX->SetFlagsFromCompactedEFLAGS(Thread, Context->EFlags); + State.rip = Context->Eip; + CTX->SetFlagsFromCompactedEFLAGS(Thread, Context->EFlags); - State.es_idx = Context->SegEs & 0xffff; - State.cs_idx = Context->SegCs & 0xffff; - State.ss_idx = Context->SegSs & 0xffff; - State.ds_idx = Context->SegDs & 0xffff; - State.fs_idx = Context->SegFs & 0xffff; - State.gs_idx = Context->SegGs & 0xffff; + State.es_idx = Context->SegEs & 0xffff; + State.cs_idx = Context->SegCs & 0xffff; + State.ss_idx = Context->SegSs & 0xffff; + State.ds_idx = Context->SegDs & 0xffff; + State.fs_idx = Context->SegFs & 0xffff; + State.gs_idx = Context->SegGs & 0xffff; - // The TEB is the only populated GDT entry by default - State.gdt[(Context->SegFs & 0xffff) >> 3].base = WowTEB; - State.fs_cached = WowTEB; - State.es_cached = 0; - State.cs_cached = 0; - State.ss_cached = 0; - State.ds_cached = 0; + // The TEB is the only populated GDT entry by default + State.gdt[(Context->SegFs & 0xffff) >> 3].base = WowTEB; + State.fs_cached = WowTEB; + State.es_cached = 0; + State.cs_cached = 0; + State.ss_cached = 0; + State.ds_cached = 0; - // Floating-point register state - const auto *XSave = reinterpret_cast(Context->ExtendedRegisters); + // Floating-point register state + const auto* XSave = reinterpret_cast(Context->ExtendedRegisters); - memcpy(State.xmm.sse.data, XSave->XmmRegisters, sizeof(State.xmm.sse.data)); - memcpy(State.mm, XSave->FloatRegisters, sizeof(State.mm)); + memcpy(State.xmm.sse.data, XSave->XmmRegisters, sizeof(State.xmm.sse.data)); + memcpy(State.mm, XSave->FloatRegisters, sizeof(State.mm)); - State.FCW = XSave->ControlWord; - State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (XSave->StatusWord >> 8) & 1; - State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (XSave->StatusWord >> 9) & 1; - State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (XSave->StatusWord >> 10) & 1; - State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (XSave->StatusWord >> 14) & 1; - State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (XSave->StatusWord >> 11) & 0b111; - State.AbridgedFTW = XSave->TagWord; + State.FCW = XSave->ControlWord; + State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (XSave->StatusWord >> 8) & 1; + State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (XSave->StatusWord >> 9) & 1; + State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (XSave->StatusWord >> 10) & 1; + State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (XSave->StatusWord >> 14) & 1; + State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (XSave->StatusWord >> 11) & 0b111; + State.AbridgedFTW = XSave->TagWord; +} + +void StoreWowContextFromState(FEXCore::Core::InternalThreadState* Thread, WOW64_CONTEXT* Context) { + auto& State = Thread->CurrentFrame->State; + + // General register state + + Context->Eax = State.gregs[FEXCore::X86State::REG_RAX]; + Context->Ebx = State.gregs[FEXCore::X86State::REG_RBX]; + Context->Ecx = State.gregs[FEXCore::X86State::REG_RCX]; + Context->Edx = State.gregs[FEXCore::X86State::REG_RDX]; + Context->Esi = State.gregs[FEXCore::X86State::REG_RSI]; + Context->Edi = State.gregs[FEXCore::X86State::REG_RDI]; + Context->Ebp = State.gregs[FEXCore::X86State::REG_RBP]; + Context->Esp = State.gregs[FEXCore::X86State::REG_RSP]; + + Context->Eip = State.rip; + Context->EFlags = CTX->ReconstructCompactedEFLAGS(Thread, false, nullptr, 0); + + Context->SegEs = State.es_idx; + Context->SegCs = State.cs_idx; + Context->SegSs = State.ss_idx; + Context->SegDs = State.ds_idx; + Context->SegFs = State.fs_idx; + Context->SegGs = State.gs_idx; + + // Floating-point register state + + auto* XSave = reinterpret_cast(Context->ExtendedRegisters); + + memcpy(XSave->XmmRegisters, State.xmm.sse.data, sizeof(State.xmm.sse.data)); + memcpy(XSave->FloatRegisters, State.mm, sizeof(State.mm)); + + XSave->ControlWord = State.FCW; + XSave->StatusWord = (State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | (State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | + (State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | (State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | + (State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); + XSave->TagWord = State.AbridgedFTW; + + Context->FloatSave.ControlWord = XSave->ControlWord; + Context->FloatSave.StatusWord = XSave->StatusWord; + Context->FloatSave.TagWord = FEXCore::FPState::ConvertFromAbridgedFTW(XSave->StatusWord, State.mm, XSave->TagWord); + Context->FloatSave.ErrorOffset = XSave->ErrorOffset; + Context->FloatSave.ErrorSelector = XSave->ErrorSelector | (XSave->ErrorOpcode << 16); + Context->FloatSave.DataOffset = XSave->DataOffset; + Context->FloatSave.DataSelector = XSave->DataSelector; + Context->FloatSave.Cr0NpxState = XSave->StatusWord | 0xffff0000; +} + +NTSTATUS FlushThreadStateContext(HANDLE Thread) { + const auto [Err, TLS] = GetThreadTLS(Thread); + if (Err) { + return Err; } - void StoreWowContextFromState(FEXCore::Core::InternalThreadState *Thread, WOW64_CONTEXT *Context) { - auto &State = Thread->CurrentFrame->State; + WOW64_CONTEXT TmpWowContext {.ContextFlags = WOW64_CONTEXT_FULL | WOW64_CONTEXT_EXTENDED_REGISTERS}; - // General register state + Context::StoreWowContextFromState(TLS.ThreadState(), &TmpWowContext); + return RtlWow64SetThreadContext(Thread, &TmpWowContext); +} - Context->Eax = State.gregs[FEXCore::X86State::REG_RAX]; - Context->Ebx = State.gregs[FEXCore::X86State::REG_RBX]; - Context->Ecx = State.gregs[FEXCore::X86State::REG_RCX]; - Context->Edx = State.gregs[FEXCore::X86State::REG_RDX]; - Context->Esi = State.gregs[FEXCore::X86State::REG_RSI]; - Context->Edi = State.gregs[FEXCore::X86State::REG_RDI]; - Context->Ebp = State.gregs[FEXCore::X86State::REG_RBP]; - Context->Esp = State.gregs[FEXCore::X86State::REG_RSP]; +void ReconstructThreadState(CONTEXT* Context) { + const auto& Config = SignalDelegator->GetConfig(); + auto* Thread = GetTLS().ThreadState(); + auto& State = Thread->CurrentFrame->State; - Context->Eip = State.rip; - Context->EFlags = CTX->ReconstructCompactedEFLAGS(Thread, false, nullptr, 0); + State.rip = CTX->RestoreRIPFromHostPC(Thread, Context->Pc); - Context->SegEs = State.es_idx; - Context->SegCs = State.cs_idx; - Context->SegSs = State.ss_idx; - Context->SegDs = State.ds_idx; - Context->SegFs = State.fs_idx; - Context->SegGs = State.gs_idx; - - // Floating-point register state - - auto *XSave = reinterpret_cast(Context->ExtendedRegisters); - - memcpy(XSave->XmmRegisters, State.xmm.sse.data, sizeof(State.xmm.sse.data)); - memcpy(XSave->FloatRegisters, State.mm, sizeof(State.mm)); - - XSave->ControlWord = State.FCW; - XSave->StatusWord = - (State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | - (State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | - (State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | - (State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | - (State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); - XSave->TagWord = State.AbridgedFTW; - - Context->FloatSave.ControlWord = XSave->ControlWord; - Context->FloatSave.StatusWord = XSave->StatusWord; - Context->FloatSave.TagWord = FEXCore::FPState::ConvertFromAbridgedFTW(XSave->StatusWord, State.mm, XSave->TagWord); - Context->FloatSave.ErrorOffset = XSave->ErrorOffset; - Context->FloatSave.ErrorSelector = XSave->ErrorSelector | (XSave->ErrorOpcode << 16); - Context->FloatSave.DataOffset = XSave->DataOffset; - Context->FloatSave.DataSelector = XSave->DataSelector; - Context->FloatSave.Cr0NpxState = XSave->StatusWord | 0xffff0000; + // Spill all SRA GPRs + for (size_t i = 0; i < Config.SRAGPRCount; i++) { + State.gregs[i] = Context->X[Config.SRAGPRMapping[i]]; } - NTSTATUS FlushThreadStateContext(HANDLE Thread) { - const auto [Err, TLS] = GetThreadTLS(Thread); - if (Err) { - return Err; - } - - WOW64_CONTEXT TmpWowContext{ - .ContextFlags = WOW64_CONTEXT_FULL | WOW64_CONTEXT_EXTENDED_REGISTERS - }; - - Context::StoreWowContextFromState(TLS.ThreadState(), &TmpWowContext); - return RtlWow64SetThreadContext(Thread, &TmpWowContext); - } - - void ReconstructThreadState(CONTEXT *Context) { - const auto &Config = SignalDelegator->GetConfig(); - auto *Thread = GetTLS().ThreadState(); - auto &State = Thread->CurrentFrame->State; - - State.rip = CTX->RestoreRIPFromHostPC(Thread, Context->Pc); - - // Spill all SRA GPRs - for (size_t i = 0; i < Config.SRAGPRCount; i++) { - State.gregs[i] = Context->X[Config.SRAGPRMapping[i]]; - } - - // Spill all SRA FPRs - for (size_t i = 0; i < Config.SRAFPRCount; i++) { - memcpy(State.xmm.sse.data[i], &Context->V[Config.SRAFPRMapping[i]], sizeof(__uint128_t)); - } - } - - WOW64_CONTEXT ReconstructWowContext(CONTEXT *Context) { - ReconstructThreadState(Context); - - WOW64_CONTEXT WowContext{ - .ContextFlags = WOW64_CONTEXT_ALL, - }; - - auto *XSave = reinterpret_cast(WowContext.ExtendedRegisters); - XSave->ControlWord = 0x27f; - XSave->MxCsr = 0x1f80; - - Context::StoreWowContextFromState(GetTLS().ThreadState(), &WowContext); - return WowContext; - } - - bool HandleUnalignedAccess(CONTEXT *Context) { - auto Thread = GetTLS().ThreadState(); - if (!Thread->CTX->IsAddressInCodeBuffer(Thread, Context->Pc)) { - return false; - } - - FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); - const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, ParanoidTSO(), Context->Pc, &Context->X0); - if (!Result.first) { - return false; - } - - Context->Pc += Result.second; - return true; - } - - void LockJITContext() { - uint32_t Expected = GetTLS().ControlWord().load(), New; - - // Spin until PAUSED is unset, setting IN_JIT when that occurs - do { - Expected = Expected & ~ControlBits::PAUSED; - New = (Expected | ControlBits::IN_JIT) & ~ControlBits::WOW_CPU_AREA_DIRTY; - } while (!GetTLS().ControlWord().compare_exchange_weak(Expected, New, std::memory_order::relaxed)); - std::atomic_signal_fence(std::memory_order::seq_cst); - - // If the CPU area is dirty, flush it to the JIT context before reentry - if (Expected & ControlBits::WOW_CPU_AREA_DIRTY) { - WOW64_CONTEXT *WowContext; - RtlWow64GetCurrentCpuArea(nullptr, reinterpret_cast(&WowContext), nullptr); - Context::LoadStateFromWowContext(GetTLS().ThreadState(), GetWowTEB(NtCurrentTeb()), WowContext); - } - } - - void UnlockJITContext() { - std::atomic_signal_fence(std::memory_order::seq_cst); - GetTLS().ControlWord().fetch_and(~ControlBits::IN_JIT, std::memory_order::relaxed); - } - - bool HandleSuspendInterrupt(CONTEXT *Context, uint64_t FaultAddress) { - if (FaultAddress != reinterpret_cast(&GetTLS().ThreadState()->InterruptFaultPage)) { - return false; - } - - void *TmpAddress = reinterpret_cast(FaultAddress); - SIZE_T TmpSize = FEXCore::Utils::FEX_PAGE_SIZE; - ULONG TmpProt; - NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_READWRITE, &TmpProt); - - // Since interrupts only happen at the start of blocks, the reconstructed state should be entirely accurate - ReconstructThreadState(Context); - - // Yield to the suspender - UnlockJITContext(); - LockJITContext(); - - // Adjust context to return to the dispatcher, reloading SRA from thread state - const auto &Config = SignalDelegator->GetConfig(); - Context->Pc = Config.AbsoluteLoopTopAddressFillSRA; - return true; + // Spill all SRA FPRs + for (size_t i = 0; i < Config.SRAFPRCount; i++) { + memcpy(State.xmm.sse.data[i], &Context->V[Config.SRAFPRMapping[i]], sizeof(__uint128_t)); } } +WOW64_CONTEXT ReconstructWowContext(CONTEXT* Context) { + ReconstructThreadState(Context); + + WOW64_CONTEXT WowContext { + .ContextFlags = WOW64_CONTEXT_ALL, + }; + + auto* XSave = reinterpret_cast(WowContext.ExtendedRegisters); + XSave->ControlWord = 0x27f; + XSave->MxCsr = 0x1f80; + + Context::StoreWowContextFromState(GetTLS().ThreadState(), &WowContext); + return WowContext; +} + +bool HandleUnalignedAccess(CONTEXT* Context) { + auto Thread = GetTLS().ThreadState(); + if (!Thread->CTX->IsAddressInCodeBuffer(Thread, Context->Pc)) { + return false; + } + + FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); + const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, ParanoidTSO(), Context->Pc, &Context->X0); + if (!Result.first) { + return false; + } + + Context->Pc += Result.second; + return true; +} + +void LockJITContext() { + uint32_t Expected = GetTLS().ControlWord().load(), New; + + // Spin until PAUSED is unset, setting IN_JIT when that occurs + do { + Expected = Expected & ~ControlBits::PAUSED; + New = (Expected | ControlBits::IN_JIT) & ~ControlBits::WOW_CPU_AREA_DIRTY; + } while (!GetTLS().ControlWord().compare_exchange_weak(Expected, New, std::memory_order::relaxed)); + std::atomic_signal_fence(std::memory_order::seq_cst); + + // If the CPU area is dirty, flush it to the JIT context before reentry + if (Expected & ControlBits::WOW_CPU_AREA_DIRTY) { + WOW64_CONTEXT* WowContext; + RtlWow64GetCurrentCpuArea(nullptr, reinterpret_cast(&WowContext), nullptr); + Context::LoadStateFromWowContext(GetTLS().ThreadState(), GetWowTEB(NtCurrentTeb()), WowContext); + } +} + +void UnlockJITContext() { + std::atomic_signal_fence(std::memory_order::seq_cst); + GetTLS().ControlWord().fetch_and(~ControlBits::IN_JIT, std::memory_order::relaxed); +} + +bool HandleSuspendInterrupt(CONTEXT* Context, uint64_t FaultAddress) { + if (FaultAddress != reinterpret_cast(&GetTLS().ThreadState()->InterruptFaultPage)) { + return false; + } + + void* TmpAddress = reinterpret_cast(FaultAddress); + SIZE_T TmpSize = FEXCore::Utils::FEX_PAGE_SIZE; + ULONG TmpProt; + NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_READWRITE, &TmpProt); + + // Since interrupts only happen at the start of blocks, the reconstructed state should be entirely accurate + ReconstructThreadState(Context); + + // Yield to the suspender + UnlockJITContext(); + LockJITContext(); + + // Adjust context to return to the dispatcher, reloading SRA from thread state + const auto& Config = SignalDelegator->GetConfig(); + Context->Pc = Config.AbsoluteLoopTopAddressFillSRA; + return true; +} +} // namespace Context + namespace Logging { - void MsgHandler(LogMan::DebugLevels Level, char const *Message) { - const auto Output = fextl::fmt::format("[{}][{:X}] {}\n", LogMan::DebugLevelStr(Level), GetCurrentThreadId(), Message); - __wine_dbg_output(Output.c_str()); - } - - void AssertHandler(char const *Message) { - const auto Output = fextl::fmt::format("[ASSERT] {}\n", Message); - __wine_dbg_output(Output.c_str()); - } - - void Init() { - LogMan::Throw::InstallHandler(AssertHandler); - LogMan::Msg::InstallHandler(MsgHandler); - } +void MsgHandler(LogMan::DebugLevels Level, const char* Message) { + const auto Output = fextl::fmt::format("[{}][{:X}] {}\n", LogMan::DebugLevelStr(Level), GetCurrentThreadId(), Message); + __wine_dbg_output(Output.c_str()); } +void AssertHandler(const char* Message) { + const auto Output = fextl::fmt::format("[ASSERT] {}\n", Message); + __wine_dbg_output(Output.c_str()); +} + +void Init() { + LogMan::Throw::InstallHandler(AssertHandler); + LogMan::Msg::InstallHandler(MsgHandler); +} +} // namespace Logging + class WowSyscallHandler : public FEXCore::HLE::SyscallHandler, public FEXCore::Allocator::FEXAllocOperators { public: WowSyscallHandler() { OSABI = FEXCore::HLE::SyscallOSABI::OS_WIN32; } - uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) override { - const uint64_t ReturnRIP = *(uint32_t *)(Frame->State.gregs[FEXCore::X86State::REG_RSP]); // Return address from the stack - uint64_t ReturnRSP = Frame->State.gregs[FEXCore::X86State::REG_RSP] + 4; // Stack pointer after popping return address + uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args) override { + const uint64_t ReturnRIP = *(uint32_t*)(Frame->State.gregs[FEXCore::X86State::REG_RSP]); // Return address from the stack + uint64_t ReturnRSP = Frame->State.gregs[FEXCore::X86State::REG_RSP] + 4; // Stack pointer after popping return address uint64_t ReturnRAX = 0; if (Frame->State.rip == (uint64_t)&BridgeInstrs::UnixCall) { @@ -362,7 +358,7 @@ public: unixlib_handle_t Handle; UINT32 ID; ULONG32 Args; - } *StackArgs = reinterpret_cast(ReturnRSP); + }* StackArgs = reinterpret_cast(ReturnRSP); ReturnRSP += sizeof(StackLayout); @@ -374,14 +370,11 @@ public: Context::UnlockJITContext(); Wow64ProcessPendingCrossProcessItems(); - ReturnRAX = static_cast(Wow64SystemServiceEx(static_cast(EntryRAX), - reinterpret_cast(ReturnRSP + 4))); + ReturnRAX = static_cast(Wow64SystemServiceEx(static_cast(EntryRAX), reinterpret_cast(ReturnRSP + 4))); Context::LockJITContext(); - } // If a new context has been set, use it directly and don't return to the syscall caller - if (Frame->State.rip == (uint64_t)&BridgeInstrs::Syscall || - Frame->State.rip == (uint64_t)&BridgeInstrs::UnixCall) { + if (Frame->State.rip == (uint64_t)&BridgeInstrs::Syscall || Frame->State.rip == (uint64_t)&BridgeInstrs::UnixCall) { Frame->State.gregs[FEXCore::X86State::REG_RAX] = ReturnRAX; Frame->State.gregs[FEXCore::X86State::REG_RSP] = ReturnRSP; Frame->State.rip = ReturnRIP; @@ -392,14 +385,14 @@ public: } FEXCore::HLE::SyscallABI GetSyscallABI(uint64_t Syscall) override { - return { .NumArgs = 0, .HasReturn = false, .HostSyscallNumber = -1 }; + return {.NumArgs = 0, .HasReturn = false, .HostSyscallNumber = -1}; } - FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestAddr) override { + FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestAddr) override { return {0, 0}; } - void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) override { + void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) override { InvalidationTracker.ReprotectRWXIntervals(Start, Length); } }; @@ -461,15 +454,15 @@ NTSTATUS BTCpuThreadTerm(HANDLE Thread) { return STATUS_SUCCESS; } -void *BTCpuGetBopCode() { +void* BTCpuGetBopCode() { return &BridgeInstrs::Syscall; } -void *__wine_get_unix_opcode() { +void* __wine_get_unix_opcode() { return &BridgeInstrs::UnixCall; } -NTSTATUS BTCpuGetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context) { +NTSTATUS BTCpuGetContext(HANDLE Thread, HANDLE Process, void* Unknown, WOW64_CONTEXT* Context) { auto [Err, TLS] = GetThreadTLS(Thread); if (Err) { return Err; @@ -484,7 +477,7 @@ NTSTATUS BTCpuGetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CON return RtlWow64GetThreadContext(Thread, Context); } -NTSTATUS BTCpuSetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context) { +NTSTATUS BTCpuSetContext(HANDLE Thread, HANDLE Process, void* Unknown, WOW64_CONTEXT* Context) { auto [Err, TLS] = GetThreadTLS(Thread); if (Err) { return Err; @@ -521,7 +514,7 @@ void BTCpuSimulate() { // APC handling calls BTCpuSimulate from syscalls and then use NtContinue to return to the previous context, // to avoid the saved context being clobbered in this case only save the entry context highest in the stack - if (!GetTLS().EntryContext() || GetTLS().EntryContext()->Sp <= entry_context.Sp) { + if (!GetTLS().EntryContext() || GetTLS().EntryContext()->Sp <= entry_context.Sp) { GetTLS().EntryContext() = &entry_context; } @@ -530,7 +523,7 @@ void BTCpuSimulate() { Context::UnlockJITContext(); } -NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { +NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG* Count) { THREAD_BASIC_INFORMATION Info; if (NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); Err) { return Err; @@ -541,8 +534,7 @@ NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { LogMan::Msg::DFmt("Suspending self"); // Mark the CPU area as dirty, to force the JIT context to be restored from it on entry as it may be changed using // SetThreadContext (which doesn't use the BTCpu API) - if (!(GetTLS().ControlWord().fetch_or(ControlBits::WOW_CPU_AREA_DIRTY, std::memory_order::relaxed) & - ControlBits::WOW_CPU_AREA_DIRTY)) { + if (!(GetTLS().ControlWord().fetch_or(ControlBits::WOW_CPU_AREA_DIRTY, std::memory_order::relaxed) & ControlBits::WOW_CPU_AREA_DIRTY)) { if (NTSTATUS Err = Context::FlushThreadStateContext(Thread); Err) { return Err; } @@ -561,8 +553,9 @@ NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { std::scoped_lock Lock(ThreadSuspendLock); // If the thread hasn't yet been initialized, suspend it without special handling as it wont yet have entered the JIT - if (!InitializedWOWThreads.contains(ThreadTID)) + if (!InitializedWOWThreads.contains(ThreadTID)) { return NtSuspendThread(Thread, Count); + } // If CONTROL_IN_JIT is unset at this point, then it can never be set (and thus the JIT cannot be reentered) as // CONTROL_PAUSED has been set, as such, while this may redundantly request interrupts in rare cases it will never @@ -571,13 +564,14 @@ NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { LogMan::Msg::DFmt("Thread {:X} is in JIT, polling for interrupt", ThreadTID); ULONG TmpProt; - void *TmpAddress = &TLS.ThreadState()->InterruptFaultPage; + void* TmpAddress = &TLS.ThreadState()->InterruptFaultPage; SIZE_T TmpSize = FEXCore::Utils::FEX_PAGE_SIZE; NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_READONLY, &TmpProt); } // Spin until the JIT is interrupted - while (TLS.ControlWord().load() & ControlBits::IN_JIT); + while (TLS.ControlWord().load() & ControlBits::IN_JIT) + ; // The JIT has now been interrupted and the context stored in the thread's CPU area is up-to-date if (Err = NtSuspendThread(Thread, Count); Err) { @@ -585,7 +579,7 @@ NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { return Err; } - CONTEXT TmpContext{ + CONTEXT TmpContext { .ContextFlags = CONTEXT_INTEGER, }; @@ -610,9 +604,9 @@ NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { return Err; } -NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { - auto *Context = Ptrs->ContextRecord; - const auto *Exception = Ptrs->ExceptionRecord; +NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS* Ptrs) { + auto* Context = Ptrs->ContextRecord; + const auto* Exception = Ptrs->ExceptionRecord; if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Context::HandleUnalignedAccess(Context)) { LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", Context->Pc); NtContinue(Context, FALSE); @@ -650,21 +644,21 @@ NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { return STATUS_SUCCESS; } -void BTCpuFlushInstructionCache2(const void *Address, SIZE_T Size) { +void BTCpuFlushInstructionCache2(const void* Address, SIZE_T Size) { InvalidationTracker.InvalidateAlignedInterval(GetTLS().ThreadState(), reinterpret_cast(Address), static_cast(Size), false); } -void BTCpuNotifyMemoryAlloc(void *Address, SIZE_T Size, ULONG Type, ULONG Prot) { - InvalidationTracker.HandleMemoryProtectionNotification(GetTLS().ThreadState(), reinterpret_cast(Address), static_cast(Size), - Prot); +void BTCpuNotifyMemoryAlloc(void* Address, SIZE_T Size, ULONG Type, ULONG Prot) { + InvalidationTracker.HandleMemoryProtectionNotification(GetTLS().ThreadState(), reinterpret_cast(Address), + static_cast(Size), Prot); } -void BTCpuNotifyMemoryProtect(void *Address, SIZE_T Size, ULONG NewProt) { - InvalidationTracker.HandleMemoryProtectionNotification(GetTLS().ThreadState(), reinterpret_cast(Address), static_cast(Size), - NewProt); +void BTCpuNotifyMemoryProtect(void* Address, SIZE_T Size, ULONG NewProt) { + InvalidationTracker.HandleMemoryProtectionNotification(GetTLS().ThreadState(), reinterpret_cast(Address), + static_cast(Size), NewProt); } -void BTCpuNotifyMemoryFree(void *Address, SIZE_T Size, ULONG FreeType) { +void BTCpuNotifyMemoryFree(void* Address, SIZE_T Size, ULONG FreeType) { if (!Size) { InvalidationTracker.InvalidateContainingSection(GetTLS().ThreadState(), reinterpret_cast(Address), true); } else if (FreeType & MEM_DECOMMIT) { @@ -672,7 +666,7 @@ void BTCpuNotifyMemoryFree(void *Address, SIZE_T Size, ULONG FreeType) { } } -void BTCpuNotifyUnmapViewOfSection(void *Address, ULONG Flags) { +void BTCpuNotifyUnmapViewOfSection(void* Address, ULONG Flags) { InvalidationTracker.InvalidateContainingSection(GetTLS().ThreadState(), reinterpret_cast(Address), true); } @@ -680,7 +674,7 @@ BOOLEAN WINAPI BTCpuIsProcessorFeaturePresent(UINT Feature) { return CPUFeatures->IsFeaturePresent(Feature) ? TRUE : FALSE; } -BOOLEAN BTCpuUpdateProcessorInformation(SYSTEM_CPU_INFORMATION *Info) { +BOOLEAN BTCpuUpdateProcessorInformation(SYSTEM_CPU_INFORMATION* Info) { CPUFeatures->UpdateInformation(Info); return TRUE; } diff --git a/Source/Windows/include/wine/debug.h b/Source/Windows/include/wine/debug.h index 70a4868e0..ece6c1a95 100644 --- a/Source/Windows/include/wine/debug.h +++ b/Source/Windows/include/wine/debug.h @@ -9,7 +9,7 @@ extern "C" { #endif -int __cdecl __wine_dbg_output( const char *str ); +int __cdecl __wine_dbg_output(const char* str); #ifdef __cplusplus } diff --git a/Source/Windows/include/wine/unixlib.h b/Source/Windows/include/wine/unixlib.h index bca7ae3a8..937ccb117 100644 --- a/Source/Windows/include/wine/unixlib.h +++ b/Source/Windows/include/wine/unixlib.h @@ -11,7 +11,7 @@ extern "C" { typedef UINT64 unixlib_handle_t; -NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ); +NTSTATUS WINAPI __wine_unix_call(unixlib_handle_t handle, unsigned int code, void* args); #ifdef __cplusplus } diff --git a/Source/Windows/include/winternl.h b/Source/Windows/include/winternl.h index 72fbb257a..27efe6fe1 100644 --- a/Source/Windows/include/winternl.h +++ b/Source/Windows/include/winternl.h @@ -9,98 +9,97 @@ extern "C" { #endif -#define NtCurrentProcess() ((HANDLE)~(ULONG_PTR)0) +#define NtCurrentProcess() ((HANDLE) ~(ULONG_PTR)0) -#define WOW64_TLS_MAX_NUMBER 19 +#define WOW64_TLS_MAX_NUMBER 19 -typedef struct _THREAD_BASIC_INFORMATION -{ - NTSTATUS ExitStatus; - PVOID TebBaseAddress; - CLIENT_ID ClientId; - ULONG_PTR AffinityMask; - LONG Priority; - LONG BasePriority; +typedef struct _THREAD_BASIC_INFORMATION { + NTSTATUS ExitStatus; + PVOID TebBaseAddress; + CLIENT_ID ClientId; + ULONG_PTR AffinityMask; + LONG Priority; + LONG BasePriority; } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; /* System Information Class 0x01 */ typedef struct _SYSTEM_CPU_INFORMATION { - USHORT ProcessorArchitecture; - USHORT ProcessorLevel; - USHORT ProcessorRevision; - USHORT MaximumProcessors; - ULONG ProcessorFeatureBits; + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + USHORT MaximumProcessors; + ULONG ProcessorFeatureBits; } SYSTEM_CPU_INFORMATION, *PSYSTEM_CPU_INFORMATION; /* definitions of bits in the Feature set for the x86 processors */ -#define CPU_FEATURE_VME 0x00000005 /* Virtual 86 Mode Extensions */ -#define CPU_FEATURE_TSC 0x00000002 /* Time Stamp Counter available */ -#define CPU_FEATURE_CMOV 0x00000008 /* Conditional Move instruction*/ -#define CPU_FEATURE_PGE 0x00000014 /* Page table Entry Global bit */ -#define CPU_FEATURE_PSE 0x00000024 /* Page Size Extension */ -#define CPU_FEATURE_MTRR 0x00000040 /* Memory Type Range Registers */ -#define CPU_FEATURE_CX8 0x00000080 /* Compare and eXchange 8 byte instr. */ -#define CPU_FEATURE_MMX 0x00000100 /* Multi Media eXtensions */ -#define CPU_FEATURE_X86 0x00000200 /* seems to be always ON, on the '86 */ -#define CPU_FEATURE_PAT 0x00000400 /* Page Attribute Table */ -#define CPU_FEATURE_FXSR 0x00000800 /* FXSAVE and FXSTORE instructions */ -#define CPU_FEATURE_SEP 0x00001000 /* SYSENTER and SYSEXIT instructions */ -#define CPU_FEATURE_SSE 0x00002000 /* SSE extensions (ext. MMX) */ -#define CPU_FEATURE_3DNOW 0x00004000 /* 3DNOW instructions available */ -#define CPU_FEATURE_SSE2 0x00010000 /* SSE2 extensions (XMMI64) */ -#define CPU_FEATURE_DS 0x00020000 /* Debug Store */ -#define CPU_FEATURE_HTT 0x00040000 /* Hyper Threading Technology */ -#define CPU_FEATURE_SSE3 0x00080000 /* SSE3 extensions */ -#define CPU_FEATURE_CX128 0x00100000 /* cmpxchg16b instruction */ -#define CPU_FEATURE_XSAVE 0x00800000 /* XSAVE instructions */ -#define CPU_FEATURE_2NDLEV 0x04000000 /* Second-level address translation */ -#define CPU_FEATURE_VIRT 0x08000000 /* Virtualization support */ -#define CPU_FEATURE_RDFS 0x10000000 /* RDFSBASE etc. instructions */ -#define CPU_FEATURE_NX 0x20000000 /* Data execution prevention */ +#define CPU_FEATURE_VME 0x00000005 /* Virtual 86 Mode Extensions */ +#define CPU_FEATURE_TSC 0x00000002 /* Time Stamp Counter available */ +#define CPU_FEATURE_CMOV 0x00000008 /* Conditional Move instruction*/ +#define CPU_FEATURE_PGE 0x00000014 /* Page table Entry Global bit */ +#define CPU_FEATURE_PSE 0x00000024 /* Page Size Extension */ +#define CPU_FEATURE_MTRR 0x00000040 /* Memory Type Range Registers */ +#define CPU_FEATURE_CX8 0x00000080 /* Compare and eXchange 8 byte instr. */ +#define CPU_FEATURE_MMX 0x00000100 /* Multi Media eXtensions */ +#define CPU_FEATURE_X86 0x00000200 /* seems to be always ON, on the '86 */ +#define CPU_FEATURE_PAT 0x00000400 /* Page Attribute Table */ +#define CPU_FEATURE_FXSR 0x00000800 /* FXSAVE and FXSTORE instructions */ +#define CPU_FEATURE_SEP 0x00001000 /* SYSENTER and SYSEXIT instructions */ +#define CPU_FEATURE_SSE 0x00002000 /* SSE extensions (ext. MMX) */ +#define CPU_FEATURE_3DNOW 0x00004000 /* 3DNOW instructions available */ +#define CPU_FEATURE_SSE2 0x00010000 /* SSE2 extensions (XMMI64) */ +#define CPU_FEATURE_DS 0x00020000 /* Debug Store */ +#define CPU_FEATURE_HTT 0x00040000 /* Hyper Threading Technology */ +#define CPU_FEATURE_SSE3 0x00080000 /* SSE3 extensions */ +#define CPU_FEATURE_CX128 0x00100000 /* cmpxchg16b instruction */ +#define CPU_FEATURE_XSAVE 0x00800000 /* XSAVE instructions */ +#define CPU_FEATURE_2NDLEV 0x04000000 /* Second-level address translation */ +#define CPU_FEATURE_VIRT 0x08000000 /* Virtualization support */ +#define CPU_FEATURE_RDFS 0x10000000 /* RDFSBASE etc. instructions */ +#define CPU_FEATURE_NX 0x20000000 /* Data execution prevention */ /* FIXME: following values are made up, actual flags are unknown */ -#define CPU_FEATURE_SSSE3 0x00008000 /* SSSE3 instructions */ -#define CPU_FEATURE_SSE41 0x01000000 /* SSE41 instructions */ -#define CPU_FEATURE_SSE42 0x02000000 /* SSE42 instructions */ -#define CPU_FEATURE_AVX 0x40000000 /* AVX instructions */ -#define CPU_FEATURE_AVX2 0x80000000 /* AVX2 instructions */ -#define CPU_FEATURE_PAE 0x00200000 -#define CPU_FEATURE_DAZ 0x00400000 +#define CPU_FEATURE_SSSE3 0x00008000 /* SSSE3 instructions */ +#define CPU_FEATURE_SSE41 0x01000000 /* SSE41 instructions */ +#define CPU_FEATURE_SSE42 0x02000000 /* SSE42 instructions */ +#define CPU_FEATURE_AVX 0x40000000 /* AVX instructions */ +#define CPU_FEATURE_AVX2 0x80000000 /* AVX2 instructions */ +#define CPU_FEATURE_PAE 0x00200000 +#define CPU_FEATURE_DAZ 0x00400000 typedef enum _MEMORY_INFORMATION_CLASS { - MemoryBasicInformation, - MemoryWorkingSetInformation, - MemoryMappedFilenameInformation, - MemoryRegionInformation, - MemoryWorkingSetExInformation, - MemorySharedCommitInformation, - MemoryImageInformation, - MemoryRegionInformationEx, - MemoryPrivilegedBasicInformation, - MemoryEnclaveImageInformation, - MemoryBasicInformationCapped, - MemoryPhysicalContiguityInformation, - MemoryBadInformation, - MemoryBadInformationAllProcesses, + MemoryBasicInformation, + MemoryWorkingSetInformation, + MemoryMappedFilenameInformation, + MemoryRegionInformation, + MemoryWorkingSetExInformation, + MemorySharedCommitInformation, + MemoryImageInformation, + MemoryRegionInformationEx, + MemoryPrivilegedBasicInformation, + MemoryEnclaveImageInformation, + MemoryBasicInformationCapped, + MemoryPhysicalContiguityInformation, + MemoryBadInformation, + MemoryBadInformationAllProcesses, #ifdef __WINESRC__ - MemoryWineUnixFuncs = 1000, - MemoryWineUnixWow64Funcs, + MemoryWineUnixFuncs = 1000, + MemoryWineUnixWow64Funcs, #endif } MEMORY_INFORMATION_CLASS; -NTSTATUS WINAPI Wow64SystemServiceEx(UINT,UINT*); +NTSTATUS WINAPI Wow64SystemServiceEx(UINT, UINT*); void WINAPI Wow64ProcessPendingCrossProcessItems(void); -NTSTATUS WINAPI RtlWow64SetThreadContext(HANDLE,const WOW64_CONTEXT*); -NTSTATUS WINAPI RtlWow64GetThreadContext(HANDLE,WOW64_CONTEXT*); -NTSTATUS WINAPI RtlWow64GetCurrentCpuArea(USHORT*,void**,void**); +NTSTATUS WINAPI RtlWow64SetThreadContext(HANDLE, const WOW64_CONTEXT*); +NTSTATUS WINAPI RtlWow64GetThreadContext(HANDLE, WOW64_CONTEXT*); +NTSTATUS WINAPI RtlWow64GetCurrentCpuArea(USHORT*, void**, void**); -NTSTATUS WINAPI NtSuspendThread(HANDLE,PULONG); -NTSTATUS WINAPI NtGetContextThread(HANDLE,CONTEXT*); -NTSTATUS WINAPI NtContinue(PCONTEXT,BOOLEAN); -NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE,LPCVOID,MEMORY_INFORMATION_CLASS,PVOID,SIZE_T,SIZE_T*); -NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG,ULONG*); +NTSTATUS WINAPI NtSuspendThread(HANDLE, PULONG); +NTSTATUS WINAPI NtGetContextThread(HANDLE, CONTEXT*); +NTSTATUS WINAPI NtContinue(PCONTEXT, BOOLEAN); +NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE, LPCVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, SIZE_T*); +NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE, PVOID*, SIZE_T*, ULONG, ULONG*); #ifdef __cplusplus } diff --git a/ThunkLibs/Generator/analysis.cpp b/ThunkLibs/Generator/analysis.cpp index fa730a765..ee610a69c 100644 --- a/ThunkLibs/Generator/analysis.cpp +++ b/ThunkLibs/Generator/analysis.cpp @@ -7,619 +7,613 @@ #include struct NamespaceAnnotations { - std::optional version; - std::optional load_host_endpoint_via; - bool generate_guest_symtable = false; - bool indirect_guest_calls = false; + std::optional version; + std::optional load_host_endpoint_via; + bool generate_guest_symtable = false; + bool indirect_guest_calls = false; }; static NamespaceAnnotations GetNamespaceAnnotations(clang::ASTContext& context, clang::CXXRecordDecl* decl) { - if (!decl->hasDefinition()) { - return {}; + if (!decl->hasDefinition()) { + return {}; + } + + ErrorReporter report_error {context}; + NamespaceAnnotations ret; + + for (const clang::CXXBaseSpecifier& base : decl->bases()) { + auto annotation = base.getType().getAsString(); + if (annotation == "fexgen::generate_guest_symtable") { + ret.generate_guest_symtable = true; + } else if (annotation == "fexgen::indirect_guest_calls") { + ret.indirect_guest_calls = true; + } else { + throw report_error(base.getSourceRange().getBegin(), "Unknown namespace annotation"); } + } - ErrorReporter report_error { context }; - NamespaceAnnotations ret; - - for (const clang::CXXBaseSpecifier& base : decl->bases()) { - auto annotation = base.getType().getAsString(); - if (annotation == "fexgen::generate_guest_symtable") { - ret.generate_guest_symtable = true; - } else if (annotation == "fexgen::indirect_guest_calls") { - ret.indirect_guest_calls = true; - } else { - throw report_error(base.getSourceRange().getBegin(), "Unknown namespace annotation"); - } + for (const clang::FieldDecl* field : decl->fields()) { + auto name = field->getNameAsString(); + if (name == "load_host_endpoint_via") { + auto loader_function_expr = field->getInClassInitializer()->IgnoreCasts(); + auto loader_function_str = llvm::dyn_cast_or_null(loader_function_expr); + if (loader_function_expr && !loader_function_str) { + throw report_error(loader_function_expr->getBeginLoc(), "Must initialize load_host_endpoint_via with a string"); + } + if (loader_function_str) { + ret.load_host_endpoint_via = loader_function_str->getString(); + } + } else if (name == "version") { + auto initializer = field->getInClassInitializer()->IgnoreCasts(); + auto version_literal = llvm::dyn_cast_or_null(initializer); + if (!initializer || !version_literal) { + throw report_error(field->getBeginLoc(), "No version given (expected integral typed member, e.g. \"int version = 5;\")"); + } + ret.version = version_literal->getValue().getZExtValue(); + } else { + throw report_error(field->getBeginLoc(), "Unknown namespace annotation"); } + } - for (const clang::FieldDecl* field : decl->fields()) { - auto name = field->getNameAsString(); - if (name == "load_host_endpoint_via") { - auto loader_function_expr = field->getInClassInitializer()->IgnoreCasts(); - auto loader_function_str = llvm::dyn_cast_or_null(loader_function_expr); - if (loader_function_expr && !loader_function_str) { - throw report_error(loader_function_expr->getBeginLoc(), - "Must initialize load_host_endpoint_via with a string"); - } - if (loader_function_str) { - ret.load_host_endpoint_via = loader_function_str->getString(); - } - } else if (name == "version") { - auto initializer = field->getInClassInitializer()->IgnoreCasts(); - auto version_literal = llvm::dyn_cast_or_null(initializer); - if (!initializer || !version_literal) { - throw report_error(field->getBeginLoc(), "No version given (expected integral typed member, e.g. \"int version = 5;\")"); - } - ret.version = version_literal->getValue().getZExtValue(); - } else { - throw report_error(field->getBeginLoc(), "Unknown namespace annotation"); - } - } - - return ret; + return ret; } enum class CallbackStrategy { - Default, - Stub, + Default, + Stub, }; struct Annotations { - bool custom_host_impl = false; - bool custom_guest_entrypoint = false; + bool custom_host_impl = false; + bool custom_guest_entrypoint = false; - bool returns_guest_pointer = false; + bool returns_guest_pointer = false; - std::optional uniform_va_type; + std::optional uniform_va_type; - CallbackStrategy callback_strategy = CallbackStrategy::Default; + CallbackStrategy callback_strategy = CallbackStrategy::Default; }; static Annotations GetAnnotations(clang::ASTContext& context, clang::CXXRecordDecl* decl) { - ErrorReporter report_error { context }; - Annotations ret; + ErrorReporter report_error {context}; + Annotations ret; - for (const auto& base : decl->bases()) { - auto annotation = base.getType().getAsString(); - if (annotation == "fexgen::returns_guest_pointer") { - ret.returns_guest_pointer = true; - } else if (annotation == "fexgen::custom_host_impl") { - ret.custom_host_impl = true; - } else if (annotation == "fexgen::callback_stub") { - ret.callback_strategy = CallbackStrategy::Stub; - } else if (annotation == "fexgen::custom_guest_entrypoint") { - ret.custom_guest_entrypoint = true; - } else { - throw report_error(base.getSourceRange().getBegin(), "Unknown annotation"); - } + for (const auto& base : decl->bases()) { + auto annotation = base.getType().getAsString(); + if (annotation == "fexgen::returns_guest_pointer") { + ret.returns_guest_pointer = true; + } else if (annotation == "fexgen::custom_host_impl") { + ret.custom_host_impl = true; + } else if (annotation == "fexgen::callback_stub") { + ret.callback_strategy = CallbackStrategy::Stub; + } else if (annotation == "fexgen::custom_guest_entrypoint") { + ret.custom_guest_entrypoint = true; + } else { + throw report_error(base.getSourceRange().getBegin(), "Unknown annotation"); } + } - for (const auto& child_decl : decl->getPrimaryContext()->decls()) { - if (auto field = llvm::dyn_cast_or_null(child_decl)) { - throw report_error(field->getBeginLoc(), "Unknown field annotation"); - } else if (auto type_alias = llvm::dyn_cast_or_null(child_decl)) { - auto name = type_alias->getNameAsString(); - if (name == "uniform_va_type") { - ret.uniform_va_type = type_alias->getUnderlyingType(); - } else { - throw report_error(type_alias->getBeginLoc(), "Unknown type alias annotation"); - } - } + for (const auto& child_decl : decl->getPrimaryContext()->decls()) { + if (auto field = llvm::dyn_cast_or_null(child_decl)) { + throw report_error(field->getBeginLoc(), "Unknown field annotation"); + } else if (auto type_alias = llvm::dyn_cast_or_null(child_decl)) { + auto name = type_alias->getNameAsString(); + if (name == "uniform_va_type") { + ret.uniform_va_type = type_alias->getUnderlyingType(); + } else { + throw report_error(type_alias->getBeginLoc(), "Unknown type alias annotation"); + } } + } - return ret; + return ret; } void AnalysisAction::ExecuteAction() { - clang::ASTFrontendAction::ExecuteAction(); + clang::ASTFrontendAction::ExecuteAction(); - // Post-processing happens here rather than in an overridden EndSourceFileAction implementation. - // We can't move the logic to the latter since this code might still raise errors, but - // clang's diagnostics engine is already shut down by the time EndSourceFileAction is called. + // Post-processing happens here rather than in an overridden EndSourceFileAction implementation. + // We can't move the logic to the latter since this code might still raise errors, but + // clang's diagnostics engine is already shut down by the time EndSourceFileAction is called. - auto& context = getCompilerInstance().getASTContext(); - if (context.getDiagnostics().hasErrorOccurred()) { - return; - } - decl_contexts.front() = context.getTranslationUnitDecl(); + auto& context = getCompilerInstance().getASTContext(); + if (context.getDiagnostics().hasErrorOccurred()) { + return; + } + decl_contexts.front() = context.getTranslationUnitDecl(); - try { - ParseInterface(context); - CoverReferencedTypes(context); - OnAnalysisComplete(context); - } catch (ClangDiagnosticAsException& exception) { - exception.Report(context.getDiagnostics()); - } + try { + ParseInterface(context); + CoverReferencedTypes(context); + OnAnalysisComplete(context); + } catch (ClangDiagnosticAsException& exception) { + exception.Report(context.getDiagnostics()); + } } -static clang::ClassTemplateDecl* -FindClassTemplateDeclByName(clang::DeclContext& decl_context, std::string_view symbol_name) { - auto& ast_context = decl_context.getParentASTContext(); - auto* ident = &ast_context.Idents.get(symbol_name); - auto declname = ast_context.DeclarationNames.getIdentifier(ident); - auto result = decl_context.noload_lookup(declname); - if (result.empty()) { - return nullptr; - } else if (std::next(result.begin()) == result.end()) { - return llvm::dyn_cast(*result.begin()); - } else { - throw std::runtime_error("Found multiple matches to symbol " + std::string { symbol_name }); - } +static clang::ClassTemplateDecl* FindClassTemplateDeclByName(clang::DeclContext& decl_context, std::string_view symbol_name) { + auto& ast_context = decl_context.getParentASTContext(); + auto* ident = &ast_context.Idents.get(symbol_name); + auto declname = ast_context.DeclarationNames.getIdentifier(ident); + auto result = decl_context.noload_lookup(declname); + if (result.empty()) { + return nullptr; + } else if (std::next(result.begin()) == result.end()) { + return llvm::dyn_cast(*result.begin()); + } else { + throw std::runtime_error("Found multiple matches to symbol " + std::string {symbol_name}); + } } struct TypeAnnotations { - bool is_opaque = false; - bool assumed_compatible = false; - bool emit_layout_wrappers = false; + bool is_opaque = false; + bool assumed_compatible = false; + bool emit_layout_wrappers = false; }; static TypeAnnotations GetTypeAnnotations(clang::ASTContext& context, clang::CXXRecordDecl* decl) { - if (!decl->hasDefinition()) { - return {}; + if (!decl->hasDefinition()) { + return {}; + } + + ErrorReporter report_error {context}; + TypeAnnotations ret; + + for (const clang::CXXBaseSpecifier& base : decl->bases()) { + auto annotation = base.getType().getAsString(); + if (annotation == "fexgen::opaque_type") { + ret.is_opaque = true; + } else if (annotation == "fexgen::assume_compatible_data_layout") { + ret.assumed_compatible = true; + } else if (annotation == "fexgen::emit_layout_wrappers") { + ret.emit_layout_wrappers = true; + } else { + throw report_error(base.getSourceRange().getBegin(), "Unknown type annotation"); } + } - ErrorReporter report_error { context }; - TypeAnnotations ret; - - for (const clang::CXXBaseSpecifier& base : decl->bases()) { - auto annotation = base.getType().getAsString(); - if (annotation == "fexgen::opaque_type") { - ret.is_opaque = true; - } else if (annotation == "fexgen::assume_compatible_data_layout") { - ret.assumed_compatible = true; - } else if (annotation == "fexgen::emit_layout_wrappers") { - ret.emit_layout_wrappers = true; - } else { - throw report_error(base.getSourceRange().getBegin(), "Unknown type annotation"); - } - } - - return ret; + return ret; } static ParameterAnnotations GetParameterAnnotations(clang::ASTContext& context, clang::CXXRecordDecl* decl) { - if (!decl->hasDefinition()) { - return {}; + if (!decl->hasDefinition()) { + return {}; + } + + ErrorReporter report_error {context}; + ParameterAnnotations ret; + + for (const clang::CXXBaseSpecifier& base : decl->bases()) { + auto annotation = base.getType().getAsString(); + if (annotation == "fexgen::ptr_passthrough") { + ret.is_passthrough = true; + } else if (annotation == "fexgen::assume_compatible_data_layout") { + ret.assume_compatible = true; + } else { + throw report_error(base.getSourceRange().getBegin(), "Unknown parameter annotation"); } + } - ErrorReporter report_error { context }; - ParameterAnnotations ret; - - for (const clang::CXXBaseSpecifier& base : decl->bases()) { - auto annotation = base.getType().getAsString(); - if (annotation == "fexgen::ptr_passthrough") { - ret.is_passthrough = true; - } else if (annotation == "fexgen::assume_compatible_data_layout") { - ret.assume_compatible = true; - } else { - throw report_error(base.getSourceRange().getBegin(), "Unknown parameter annotation"); - } - } - - return ret; + return ret; } void AnalysisAction::ParseInterface(clang::ASTContext& context) { - ErrorReporter report_error { context }; + ErrorReporter report_error {context}; - const std::unordered_map no_param_annotations {}; + const std::unordered_map no_param_annotations {}; - // TODO: Assert fex_gen_type is not declared at non-global namespaces - if (auto template_decl = FindClassTemplateDeclByName(*context.getTranslationUnitDecl(), "fex_gen_type")) { - for (auto* decl : template_decl->specializations()) { - const auto& template_args = decl->getTemplateArgs(); - assert(template_args.size() == 1); + // TODO: Assert fex_gen_type is not declared at non-global namespaces + if (auto template_decl = FindClassTemplateDeclByName(*context.getTranslationUnitDecl(), "fex_gen_type")) { + for (auto* decl : template_decl->specializations()) { + const auto& template_args = decl->getTemplateArgs(); + assert(template_args.size() == 1); - // NOTE: Function types that are equivalent but use differently - // named types (e.g. GLuint/GLenum) are represented by - // different Type instances. The canonical type they refer - // to is unique, however. - clang::QualType type = context.getCanonicalType(template_args[0].getAsType()); - type = type->getLocallyUnqualifiedSingleStepDesugaredType(); + // NOTE: Function types that are equivalent but use differently + // named types (e.g. GLuint/GLenum) are represented by + // different Type instances. The canonical type they refer + // to is unique, however. + clang::QualType type = context.getCanonicalType(template_args[0].getAsType()); + type = type->getLocallyUnqualifiedSingleStepDesugaredType(); - const auto annotations = GetTypeAnnotations(context, decl); - if (type->isFunctionPointerType() || type->isFunctionType()) { - if (decl->getNumBases()) { - throw report_error(decl->getBeginLoc(), "Function pointer types cannot be annotated"); - } - thunked_funcptrs[type.getAsString()] = std::pair { type.getTypePtr(), no_param_annotations }; - } else { - RepackedType repack_info = { - .assumed_compatible = annotations.is_opaque || annotations.assumed_compatible, - .pointers_only = annotations.is_opaque && !annotations.assumed_compatible, - .emit_layout_wrappers = annotations.emit_layout_wrappers - }; - [[maybe_unused]] auto [it, inserted] = types.emplace(context.getCanonicalType(type.getTypePtr()), repack_info); - assert(inserted); - } + const auto annotations = GetTypeAnnotations(context, decl); + if (type->isFunctionPointerType() || type->isFunctionType()) { + if (decl->getNumBases()) { + throw report_error(decl->getBeginLoc(), "Function pointer types cannot be annotated"); } + thunked_funcptrs[type.getAsString()] = std::pair {type.getTypePtr(), no_param_annotations}; + } else { + RepackedType repack_info = {.assumed_compatible = annotations.is_opaque || annotations.assumed_compatible, + .pointers_only = annotations.is_opaque && !annotations.assumed_compatible, + .emit_layout_wrappers = annotations.emit_layout_wrappers}; + [[maybe_unused]] auto [it, inserted] = types.emplace(context.getCanonicalType(type.getTypePtr()), repack_info); + assert(inserted); + } } + } - // Process function parameter annotations - std::unordered_map> param_annotations; - for (auto& decl_context : decl_contexts) { - if (auto template_decl = FindClassTemplateDeclByName(*decl_context, "fex_gen_param")) { - for (auto* decl : template_decl->specializations()) { - const auto& template_args = decl->getTemplateArgs(); - assert(template_args.size() == 3); + // Process function parameter annotations + std::unordered_map> param_annotations; + for (auto& decl_context : decl_contexts) { + if (auto template_decl = FindClassTemplateDeclByName(*decl_context, "fex_gen_param")) { + for (auto* decl : template_decl->specializations()) { + const auto& template_args = decl->getTemplateArgs(); + assert(template_args.size() == 3); - auto function = llvm::dyn_cast(template_args[0].getAsDecl()); - auto param_idx = template_args[1].getAsIntegral().getZExtValue(); - clang::QualType type = context.getCanonicalType(template_args[2].getAsType()); - type = type->getLocallyUnqualifiedSingleStepDesugaredType(); + auto function = llvm::dyn_cast(template_args[0].getAsDecl()); + auto param_idx = template_args[1].getAsIntegral().getZExtValue(); + clang::QualType type = context.getCanonicalType(template_args[2].getAsType()); + type = type->getLocallyUnqualifiedSingleStepDesugaredType(); - if (param_idx >= function->getNumParams()) { - throw report_error(decl->getTypeAsWritten()->getTypeLoc().getAs().getArgLoc(1).getLocation(), "Out-of-bounds parameter index passed to fex_gen_param"); - } - - if (!type->isVoidType() && !context.hasSameType(type, function->getParamDecl(param_idx)->getType())) { - throw report_error(decl->getTypeAsWritten()->getTypeLoc().getAs().getArgLoc(2).getLocation(), "Type passed to fex_gen_param doesn't match the function signature") - .addNote(report_error(function->getParamDecl(param_idx)->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), "Expected this type instead")); - } - - param_annotations[function][param_idx] = GetParameterAnnotations(context, decl); - } + if (param_idx >= function->getNumParams()) { + throw report_error(decl->getTypeAsWritten()->getTypeLoc().getAs().getArgLoc(1).getLocation(), + "Out-of-bounds parameter index passed to fex_gen_param"); } + + if (!type->isVoidType() && !context.hasSameType(type, function->getParamDecl(param_idx)->getType())) { + throw report_error(decl->getTypeAsWritten()->getTypeLoc().getAs().getArgLoc(2).getLocation(), + "Type passed to fex_gen_param doesn't match the function signature") + .addNote(report_error(function->getParamDecl(param_idx)->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), "Expected this type " + "instead")); + } + + param_annotations[function][param_idx] = GetParameterAnnotations(context, decl); + } } + } - // Process declarations and specializations of fex_gen_config, - // i.e. the function descriptions of the thunked API - for (auto& decl_context : decl_contexts) { - if (const auto template_decl = FindClassTemplateDeclByName(*decl_context, "fex_gen_config")) { - // Gather general information about symbols in this namespace - const auto annotations = GetNamespaceAnnotations(context, template_decl->getTemplatedDecl()); + // Process declarations and specializations of fex_gen_config, + // i.e. the function descriptions of the thunked API + for (auto& decl_context : decl_contexts) { + if (const auto template_decl = FindClassTemplateDeclByName(*decl_context, "fex_gen_config")) { + // Gather general information about symbols in this namespace + const auto annotations = GetNamespaceAnnotations(context, template_decl->getTemplatedDecl()); - auto namespace_decl = llvm::dyn_cast(decl_context); - namespaces.push_back({ namespace_decl, - namespace_decl ? namespace_decl->getNameAsString() : "", - annotations.load_host_endpoint_via.value_or(""), - annotations.generate_guest_symtable, - annotations.indirect_guest_calls }); - const auto namespace_idx = namespaces.size() - 1; - const NamespaceInfo& namespace_info = namespaces.back(); + auto namespace_decl = llvm::dyn_cast(decl_context); + namespaces.push_back( + {namespace_decl, namespace_decl ? namespace_decl->getNameAsString() : "", annotations.load_host_endpoint_via.value_or(""), + annotations.generate_guest_symtable, annotations.indirect_guest_calls}); + const auto namespace_idx = namespaces.size() - 1; + const NamespaceInfo& namespace_info = namespaces.back(); - if (annotations.version) { - if (namespace_decl) { - throw report_error(template_decl->getBeginLoc(), "Library version must be defined in the global namespace"); - } - lib_version = annotations.version; + if (annotations.version) { + if (namespace_decl) { + throw report_error(template_decl->getBeginLoc(), "Library version must be defined in the global namespace"); + } + lib_version = annotations.version; + } + + // Process specializations of template fex_gen_config + // First, perform some validation and process member annotations + // In a second iteration, process the actual function API + for (auto* decl : template_decl->specializations()) { + if (decl->getSpecializationKind() == clang::TSK_ExplicitInstantiationDefinition) { + throw report_error(decl->getBeginLoc(), "fex_gen_config may not be partially specialized\n"); + } + + const auto& template_args = decl->getTemplateArgs(); + assert(template_args.size() == 1); + + const auto template_arg_loc = + decl->getTypeAsWritten()->getTypeLoc().castAs().getArgLoc(0).getLocation(); + + if (auto emitted_function = llvm::dyn_cast(template_args[0].getAsDecl())) { + // Process later + } else if (auto annotated_member = llvm::dyn_cast(template_args[0].getAsDecl())) { + { + if (decl->getNumBases() != 1 || decl->bases_begin()->getType().getAsString() != "fexgen::custom_repack") { + throw report_error(template_arg_loc, "Unsupported member annotation(s)"); } - // Process specializations of template fex_gen_config - // First, perform some validation and process member annotations - // In a second iteration, process the actual function API - for (auto* decl : template_decl->specializations()) { - if (decl->getSpecializationKind() == clang::TSK_ExplicitInstantiationDefinition) { - throw report_error(decl->getBeginLoc(), "fex_gen_config may not be partially specialized\n"); + if (!annotated_member->getType()->isPointerType() && !annotated_member->getType()->isArrayType()) { + throw report_error(template_arg_loc, "custom_repack annotation requires pointer member"); + } + } + + // Get or add parent type to list of structure types + auto repack_info_it = types.emplace(context.getCanonicalType(annotated_member->getParent()->getTypeForDecl()), RepackedType {}).first; + if (repack_info_it->second.assumed_compatible) { + throw report_error(template_arg_loc, "May not annotate members of opaque types"); + } + // Add member to its list of members + repack_info_it->second.custom_repacked_members.insert(annotated_member->getNameAsString()); + } else { + throw report_error(template_arg_loc, "Cannot annotate this kind of symbol"); + } + } + + // Process API functions + for (auto* decl : template_decl->specializations()) { + if (decl->getSpecializationKind() == clang::TSK_ExplicitInstantiationDefinition) { + throw report_error(decl->getBeginLoc(), "fex_gen_config may not be partially specialized\n"); + } + + const auto& template_args = decl->getTemplateArgs(); + assert(template_args.size() == 1); + + const auto template_arg_loc = + decl->getTypeAsWritten()->getTypeLoc().castAs().getArgLoc(0).getLocation(); + + if (auto emitted_function = llvm::dyn_cast(template_args[0].getAsDecl())) { + auto return_type = emitted_function->getReturnType(); + + const auto annotations = GetAnnotations(context, decl); + if (return_type->isFunctionPointerType() && !annotations.returns_guest_pointer) { + throw report_error(template_arg_loc, "Function pointer return types require explicit annotation\n"); + } + + // TODO: Use the types as written in the signature instead? + ThunkedFunction data; + data.function_name = emitted_function->getName().str(); + data.return_type = return_type; + data.is_variadic = emitted_function->isVariadic(); + + data.decl = emitted_function; + + data.custom_host_impl = annotations.custom_host_impl; + + data.param_annotations = param_annotations[emitted_function]; + + const int retval_index = -1; + for (int param_idx = retval_index; param_idx < (int)emitted_function->param_size(); ++param_idx) { + auto param_type = + param_idx == retval_index ? emitted_function->getReturnType() : emitted_function->getParamDecl(param_idx)->getType(); + auto param_loc = param_idx == retval_index ? emitted_function->getReturnTypeSourceRange().getBegin() : + emitted_function->getParamDecl(param_idx)->getBeginLoc(); + + if (param_idx != retval_index) { + data.param_types.push_back(param_type); + } else if (param_type->isVoidType()) { + continue; + } + + // Skip pointers-to-structs passed through to the host in guest_layout. + // This avoids pulling in member types that can't be processed. + if (data.param_annotations[param_idx].is_passthrough && param_type->isPointerType() && + param_type->getPointeeType()->isStructureType()) { + continue; + } + + auto check_struct_type = [&](const clang::Type* type) { + if (type->isIncompleteType()) { + throw report_error(type->getAsTagDecl()->getBeginLoc(), "Unannotated pointer with incomplete struct type; consider using " + "an opaque_type annotation") + .addNote(report_error(emitted_function->getNameInfo().getLoc(), "in function", clang::DiagnosticsEngine::Note)) + .addNote(report_error(template_arg_loc, "used in annotation here", clang::DiagnosticsEngine::Note)); + } + + for (auto* member : type->getAsStructureType()->getDecl()->fields()) { + auto annotated_type = types.find(type->getCanonicalTypeUnqualified().getTypePtr()); + if (annotated_type == types.end() || !annotated_type->second.UsesCustomRepackFor(member)) { + /*if (!member->getType()->isPointerType())*/ { + // TODO: Perform more elaborate validation for non-pointers to ensure ABI compatibility + continue; + } + + throw report_error(member->getBeginLoc(), "Unannotated pointer member") + .addNote(report_error(param_loc, "in struct type", clang::DiagnosticsEngine::Note)) + .addNote(report_error(template_arg_loc, "used in annotation here", clang::DiagnosticsEngine::Note)); } + } + }; - const auto& template_args = decl->getTemplateArgs(); - assert(template_args.size() == 1); + if (param_type->isFunctionPointerType()) { + if (param_idx == retval_index) { + // TODO: We already rely on this in a few places... + // throw report_error(template_arg_loc, "Support for returning function pointers is not implemented"); + continue; + } + auto funcptr = emitted_function->getParamDecl(param_idx)->getFunctionType()->getAs(); + ThunkedCallback callback; + callback.return_type = funcptr->getReturnType(); + for (auto& cb_param : funcptr->getParamTypes()) { + callback.param_types.push_back(cb_param); + } + callback.is_stub = annotations.callback_strategy == CallbackStrategy::Stub; + callback.is_variadic = funcptr->isVariadic(); - const auto template_arg_loc = decl->getTypeAsWritten()->getTypeLoc().castAs().getArgLoc(0).getLocation(); + data.callbacks.emplace(param_idx, callback); + if (!callback.is_stub && !data.custom_host_impl) { + thunked_funcptrs[emitted_function->getNameAsString() + "_cb" + std::to_string(param_idx)] = + std::pair {context.getCanonicalType(funcptr), no_param_annotations}; + } - if (auto emitted_function = llvm::dyn_cast(template_args[0].getAsDecl())) { - // Process later - } else if (auto annotated_member = llvm::dyn_cast(template_args[0].getAsDecl())) { - { - if (decl->getNumBases() != 1 || decl->bases_begin()->getType().getAsString() != "fexgen::custom_repack") { - throw report_error(template_arg_loc, "Unsupported member annotation(s)"); - } + if (data.callbacks.size() != 1) { + throw report_error(template_arg_loc, "Support for more than one callback is untested"); + } + if (funcptr->isVariadic() && !callback.is_stub) { + throw report_error(template_arg_loc, "Variadic callbacks are not supported"); + } - if (!annotated_member->getType()->isPointerType() && !annotated_member->getType()->isArrayType()) { - throw report_error(template_arg_loc, "custom_repack annotation requires pointer member"); - } - } + // Force treatment as passthrough-pointer + data.param_annotations[param_idx].is_passthrough = true; + } else if (param_type->isBuiltinType()) { + // NOTE: Intentionally not using getCanonicalType here since that would turn e.g. size_t into platform-specific types + // TODO: Still, we may want to de-duplicate some of these... + types.emplace(param_type.getTypePtr(), RepackedType {}); + } else if (param_type->isEnumeralType()) { + types.emplace(context.getCanonicalType(param_type.getTypePtr()), RepackedType {}); + } else if (param_type->isStructureType() && !(types.contains(context.getCanonicalType(param_type.getTypePtr())) && + LookupType(context, param_type.getTypePtr()).assumed_compatible)) { + check_struct_type(param_type.getTypePtr()); + types.emplace(context.getCanonicalType(param_type.getTypePtr()), RepackedType {}); + } else if (param_type->isPointerType()) { + auto pointee_type = param_type->getPointeeType(); - // Get or add parent type to list of structure types - auto repack_info_it = types.emplace(context.getCanonicalType(annotated_member->getParent()->getTypeForDecl()), RepackedType {}).first; - if (repack_info_it->second.assumed_compatible) { - throw report_error(template_arg_loc, "May not annotate members of opaque types"); - } - // Add member to its list of members - repack_info_it->second.custom_repacked_members.insert(annotated_member->getNameAsString()); + if (pointee_type->isIntegerType()) { + // Add builtin pointee type to type list + if (!pointee_type->isEnumeralType()) { + types.emplace(pointee_type.getTypePtr(), RepackedType {}); } else { - throw report_error(template_arg_loc, "Cannot annotate this kind of symbol"); + types.emplace(context.getCanonicalType(pointee_type.getTypePtr()), RepackedType {}); } + } + + if (data.param_annotations[param_idx].assume_compatible) { + // Nothing to do + } else if (types.contains(context.getCanonicalType(pointee_type.getTypePtr())) && + LookupType(context, pointee_type.getTypePtr()).assumed_compatible) { + // Parameter points to a type that is assumed compatible + data.param_annotations[param_idx].assume_compatible = true; + } else if (pointee_type->isStructureType()) { + // Unannotated pointer to unannotated structure. + // Append the structure type to the type list for checking data layout compatibility. + check_struct_type(pointee_type.getTypePtr()); + types.emplace(context.getCanonicalType(pointee_type.getTypePtr()), RepackedType {}); + } else if (data.param_annotations[param_idx].is_passthrough) { + if (!data.custom_host_impl) { + throw report_error(param_loc, "Passthrough annotation requires custom host implementation"); + } + + // Nothing to do + } else if (false /* TODO: Can't check if this is unsupported until data layout analysis is complete */) { + throw report_error(param_loc, "Unsupported parameter type") + .addNote(report_error(emitted_function->getNameInfo().getLoc(), "in function", clang::DiagnosticsEngine::Note)) + .addNote(report_error(template_arg_loc, "used in definition here", clang::DiagnosticsEngine::Note)); + } + } else { + // TODO: For non-pointer parameters, perform more elaborate validation to ensure ABI compatibility + } + } + + thunked_api.push_back(ThunkedAPIFunction {(const FunctionParams&)data, data.function_name, data.return_type, + namespace_info.host_loader.empty() ? "dlsym_default" : namespace_info.host_loader, + data.is_variadic || annotations.custom_guest_entrypoint, data.is_variadic, std::nullopt}); + if (namespace_info.generate_guest_symtable) { + thunked_api.back().symtable_namespace = namespace_idx; + } + + if (data.is_variadic) { + if (!annotations.uniform_va_type) { + throw report_error(decl->getBeginLoc(), "Variadic functions must be annotated with parameter type using uniform_va_type"); } - // Process API functions - for (auto* decl : template_decl->specializations()) { - if (decl->getSpecializationKind() == clang::TSK_ExplicitInstantiationDefinition) { - throw report_error(decl->getBeginLoc(), "fex_gen_config may not be partially specialized\n"); - } - - const auto& template_args = decl->getTemplateArgs(); - assert(template_args.size() == 1); - - const auto template_arg_loc = decl->getTypeAsWritten()->getTypeLoc().castAs().getArgLoc(0).getLocation(); - - if (auto emitted_function = llvm::dyn_cast(template_args[0].getAsDecl())) { - auto return_type = emitted_function->getReturnType(); - - const auto annotations = GetAnnotations(context, decl); - if (return_type->isFunctionPointerType() && !annotations.returns_guest_pointer) { - throw report_error( template_arg_loc, - "Function pointer return types require explicit annotation\n"); - } - - // TODO: Use the types as written in the signature instead? - ThunkedFunction data; - data.function_name = emitted_function->getName().str(); - data.return_type = return_type; - data.is_variadic = emitted_function->isVariadic(); - - data.decl = emitted_function; - - data.custom_host_impl = annotations.custom_host_impl; - - data.param_annotations = param_annotations[emitted_function]; - - const int retval_index = -1; - for (int param_idx = retval_index; param_idx < (int)emitted_function->param_size(); ++param_idx) { - auto param_type = param_idx == retval_index ? emitted_function->getReturnType() : emitted_function->getParamDecl(param_idx)->getType(); - auto param_loc = param_idx == retval_index ? emitted_function->getReturnTypeSourceRange().getBegin() : emitted_function->getParamDecl(param_idx)->getBeginLoc(); - - if (param_idx != retval_index) { - data.param_types.push_back(param_type); - } else if (param_type->isVoidType()) { - continue; - } - - // Skip pointers-to-structs passed through to the host in guest_layout. - // This avoids pulling in member types that can't be processed. - if (data.param_annotations[param_idx].is_passthrough && - param_type->isPointerType() && param_type->getPointeeType()->isStructureType()) { - continue; - } - - auto check_struct_type = [&](const clang::Type* type) { - if (type->isIncompleteType()) { - throw report_error(type->getAsTagDecl()->getBeginLoc(), "Unannotated pointer with incomplete struct type; consider using an opaque_type annotation") - .addNote(report_error(emitted_function->getNameInfo().getLoc(), "in function", clang::DiagnosticsEngine::Note)) - .addNote(report_error(template_arg_loc, "used in annotation here", clang::DiagnosticsEngine::Note)); - } - - for (auto* member : type->getAsStructureType()->getDecl()->fields()) { - auto annotated_type = types.find(type->getCanonicalTypeUnqualified().getTypePtr()); - if (annotated_type == types.end() || !annotated_type->second.UsesCustomRepackFor(member)) { - /*if (!member->getType()->isPointerType())*/ { - // TODO: Perform more elaborate validation for non-pointers to ensure ABI compatibility - continue; - } - - throw report_error(member->getBeginLoc(), "Unannotated pointer member") - .addNote(report_error(param_loc, "in struct type", clang::DiagnosticsEngine::Note)) - .addNote(report_error(template_arg_loc, "used in annotation here", clang::DiagnosticsEngine::Note)); - } - } - }; - - if (param_type->isFunctionPointerType()) { - if (param_idx == retval_index) { - // TODO: We already rely on this in a few places... -// throw report_error(template_arg_loc, "Support for returning function pointers is not implemented"); - continue; - } - auto funcptr = emitted_function->getParamDecl(param_idx)->getFunctionType()->getAs(); - ThunkedCallback callback; - callback.return_type = funcptr->getReturnType(); - for (auto& cb_param : funcptr->getParamTypes()) { - callback.param_types.push_back(cb_param); - } - callback.is_stub = annotations.callback_strategy == CallbackStrategy::Stub; - callback.is_variadic = funcptr->isVariadic(); - - data.callbacks.emplace(param_idx, callback); - if (!callback.is_stub && !data.custom_host_impl) { - thunked_funcptrs[emitted_function->getNameAsString() + "_cb" + std::to_string(param_idx)] = std::pair { context.getCanonicalType(funcptr), no_param_annotations }; - } - - if (data.callbacks.size() != 1) { - throw report_error(template_arg_loc, "Support for more than one callback is untested"); - } - if (funcptr->isVariadic() && !callback.is_stub) { - throw report_error(template_arg_loc, "Variadic callbacks are not supported"); - } - - // Force treatment as passthrough-pointer - data.param_annotations[param_idx].is_passthrough = true; - } else if (param_type->isBuiltinType()) { - // NOTE: Intentionally not using getCanonicalType here since that would turn e.g. size_t into platform-specific types - // TODO: Still, we may want to de-duplicate some of these... - types.emplace(param_type.getTypePtr(), RepackedType { }); - } else if (param_type->isEnumeralType()) { - types.emplace(context.getCanonicalType(param_type.getTypePtr()), RepackedType { }); - } else if ( param_type->isStructureType() && - !(types.contains(context.getCanonicalType(param_type.getTypePtr())) && - LookupType(context, param_type.getTypePtr()).assumed_compatible)) { - check_struct_type(param_type.getTypePtr()); - types.emplace(context.getCanonicalType(param_type.getTypePtr()), RepackedType { }); - } else if (param_type->isPointerType()) { - auto pointee_type = param_type->getPointeeType(); - - if (pointee_type->isIntegerType()) { - // Add builtin pointee type to type list - if (!pointee_type->isEnumeralType()) { - types.emplace(pointee_type.getTypePtr(), RepackedType { }); - } else { - types.emplace(context.getCanonicalType(pointee_type.getTypePtr()), RepackedType { }); - } - } - - if (data.param_annotations[param_idx].assume_compatible) { - // Nothing to do - } else if (types.contains(context.getCanonicalType(pointee_type.getTypePtr())) && LookupType(context, pointee_type.getTypePtr()).assumed_compatible) { - // Parameter points to a type that is assumed compatible - data.param_annotations[param_idx].assume_compatible = true; - } else if (pointee_type->isStructureType()) { - // Unannotated pointer to unannotated structure. - // Append the structure type to the type list for checking data layout compatibility. - check_struct_type(pointee_type.getTypePtr()); - types.emplace(context.getCanonicalType(pointee_type.getTypePtr()), RepackedType { }); - } else if (data.param_annotations[param_idx].is_passthrough) { - if (!data.custom_host_impl) { - throw report_error(param_loc, "Passthrough annotation requires custom host implementation"); - } - - // Nothing to do - } else if (false /* TODO: Can't check if this is unsupported until data layout analysis is complete */) { - throw report_error(param_loc, "Unsupported parameter type") - .addNote(report_error(emitted_function->getNameInfo().getLoc(), "in function", clang::DiagnosticsEngine::Note)) - .addNote(report_error(template_arg_loc, "used in definition here", clang::DiagnosticsEngine::Note)); - } - } else { - // TODO: For non-pointer parameters, perform more elaborate validation to ensure ABI compatibility - } - } - - thunked_api.push_back(ThunkedAPIFunction { (const FunctionParams&)data, data.function_name, data.return_type, - namespace_info.host_loader.empty() ? "dlsym_default" : namespace_info.host_loader, - data.is_variadic || annotations.custom_guest_entrypoint, - data.is_variadic, - std::nullopt }); - if (namespace_info.generate_guest_symtable) { - thunked_api.back().symtable_namespace = namespace_idx; - } - - if (data.is_variadic) { - if (!annotations.uniform_va_type) { - throw report_error(decl->getBeginLoc(), "Variadic functions must be annotated with parameter type using uniform_va_type"); - } - - // Convert variadic argument list into a count + pointer pair - data.param_types.push_back(context.getSizeType()); - data.param_types.push_back(context.getPointerType(*annotations.uniform_va_type)); - types.emplace(context.getSizeType()->getTypePtr(), RepackedType { }); - if (!annotations.uniform_va_type.value()->isVoidPointerType()) { - types.emplace(annotations.uniform_va_type->getTypePtr(), RepackedType { }); - } - } - - if (data.is_variadic) { - // This function is thunked through an "_internal" symbol since its signature - // is different from the one in the native host/guest libraries. - data.function_name = data.function_name + "_internal"; - if (data.custom_host_impl) { - throw report_error(decl->getBeginLoc(), "Custom host impl requested but this is implied by the function signature already"); - } - data.custom_host_impl = true; - } - - // For indirect calls, register the function signature as a function pointer type - if (namespace_info.indirect_guest_calls) { - thunked_funcptrs[emitted_function->getNameAsString()] = std::pair { context.getCanonicalType(emitted_function->getFunctionType()), data.param_annotations }; - } - - thunks.push_back(std::move(data)); - } + // Convert variadic argument list into a count + pointer pair + data.param_types.push_back(context.getSizeType()); + data.param_types.push_back(context.getPointerType(*annotations.uniform_va_type)); + types.emplace(context.getSizeType()->getTypePtr(), RepackedType {}); + if (!annotations.uniform_va_type.value()->isVoidPointerType()) { + types.emplace(annotations.uniform_va_type->getTypePtr(), RepackedType {}); } + } + + if (data.is_variadic) { + // This function is thunked through an "_internal" symbol since its signature + // is different from the one in the native host/guest libraries. + data.function_name = data.function_name + "_internal"; + if (data.custom_host_impl) { + throw report_error(decl->getBeginLoc(), "Custom host impl requested but this is implied by the function signature already"); + } + data.custom_host_impl = true; + } + + // For indirect calls, register the function signature as a function pointer type + if (namespace_info.indirect_guest_calls) { + thunked_funcptrs[emitted_function->getNameAsString()] = + std::pair {context.getCanonicalType(emitted_function->getFunctionType()), data.param_annotations}; + } + + thunks.push_back(std::move(data)); } + } } + } } void AnalysisAction::CoverReferencedTypes(clang::ASTContext& context) { - // Add common fixed-size integer types explicitly - for (unsigned size : { 8, 32, 64 }) { - types.emplace(context.getIntTypeForBitwidth(size, false).getTypePtr(), RepackedType {}); - types.emplace(context.getIntTypeForBitwidth(size, true).getTypePtr(), RepackedType {}); - } + // Add common fixed-size integer types explicitly + for (unsigned size : {8, 32, 64}) { + types.emplace(context.getIntTypeForBitwidth(size, false).getTypePtr(), RepackedType {}); + types.emplace(context.getIntTypeForBitwidth(size, true).getTypePtr(), RepackedType {}); + } - // Repeat until no more children are appended - for (bool changed = true; std::exchange(changed, false);) { - for ( auto next_type_it = types.begin(), type_it = next_type_it; - type_it != types.end(); - type_it = next_type_it) { - ++next_type_it; - const auto& [type, type_repack_info] = *type_it; - if (!type->isStructureType()) { - continue; - } + // Repeat until no more children are appended + for (bool changed = true; std::exchange(changed, false);) { + for (auto next_type_it = types.begin(), type_it = next_type_it; type_it != types.end(); type_it = next_type_it) { + ++next_type_it; + const auto& [type, type_repack_info] = *type_it; + if (!type->isStructureType()) { + continue; + } - if (type_repack_info.assumed_compatible) { - // If assumed compatible, we don't need the member definitions - continue; - } + if (type_repack_info.assumed_compatible) { + // If assumed compatible, we don't need the member definitions + continue; + } - for (auto* member : type->getAsStructureType()->getDecl()->fields()) { - auto member_type = member->getType().getTypePtr(); - while (member_type->isArrayType()) { - member_type = member_type->getArrayElementTypeNoTypeQual(); - } - while (member_type->isPointerType()) { - member_type = member_type->getPointeeType().getTypePtr(); - } - - if (!member_type->isBuiltinType()) { - member_type = context.getCanonicalType(member_type); - } - if (types.contains(member_type) && types.at(member_type).pointers_only) { - if (member_type == context.getCanonicalType(member->getType().getTypePtr())) { - throw std::runtime_error(fmt::format("\"{}\" references opaque type \"{}\" via non-pointer member \"{}\"", - clang::QualType { type, 0 }.getAsString(), - clang::QualType { member_type, 0 }.getAsString(), - member->getNameAsString())); - } - continue; - } - if (member_type->isUnionType() && !types.contains(member_type) && !type_repack_info.UsesCustomRepackFor(member)) { - throw std::runtime_error(fmt::format("\"{}\" has unannotated member \"{}\" of union type \"{}\"", - clang::QualType { type, 0 }.getAsString(), - member->getNameAsString(), - clang::QualType { member_type, 0 }.getAsString())); - } - - if (!member_type->isStructureType() && !(member_type->isBuiltinType() && !member_type->isVoidType()) && !member_type->isEnumeralType()) { - continue; - } - - auto [new_type_it, inserted] = types.emplace(member_type, RepackedType { }); - if (inserted) { - changed = true; - next_type_it = new_type_it; - } - } + for (auto* member : type->getAsStructureType()->getDecl()->fields()) { + auto member_type = member->getType().getTypePtr(); + while (member_type->isArrayType()) { + member_type = member_type->getArrayElementTypeNoTypeQual(); } + while (member_type->isPointerType()) { + member_type = member_type->getPointeeType().getTypePtr(); + } + + if (!member_type->isBuiltinType()) { + member_type = context.getCanonicalType(member_type); + } + if (types.contains(member_type) && types.at(member_type).pointers_only) { + if (member_type == context.getCanonicalType(member->getType().getTypePtr())) { + throw std::runtime_error( + fmt::format("\"{}\" references opaque type \"{}\" via non-pointer member \"{}\"", clang::QualType {type, 0}.getAsString(), + clang::QualType {member_type, 0}.getAsString(), member->getNameAsString())); + } + continue; + } + if (member_type->isUnionType() && !types.contains(member_type) && !type_repack_info.UsesCustomRepackFor(member)) { + throw std::runtime_error(fmt::format("\"{}\" has unannotated member \"{}\" of union type \"{}\"", clang::QualType {type, 0}.getAsString(), + member->getNameAsString(), clang::QualType {member_type, 0}.getAsString())); + } + + if (!member_type->isStructureType() && !(member_type->isBuiltinType() && !member_type->isVoidType()) && !member_type->isEnumeralType()) { + continue; + } + + auto [new_type_it, inserted] = types.emplace(member_type, RepackedType {}); + if (inserted) { + changed = true; + next_type_it = new_type_it; + } + } } + } } class ASTVisitor : public clang::RecursiveASTVisitor { - std::vector& decl_contexts; + std::vector& decl_contexts; public: - ASTVisitor(std::vector& decl_contexts_) - : decl_contexts(decl_contexts_) { + ASTVisitor(std::vector& decl_contexts_) + : decl_contexts(decl_contexts_) {} + + /** + * Matches "template struct fex_gen_config { ... }" + */ + bool VisitClassTemplateDecl(clang::ClassTemplateDecl* decl) { + if (decl->getName() != "fex_gen_config") { + return true; } - /** - * Matches "template struct fex_gen_config { ... }" - */ - bool VisitClassTemplateDecl(clang::ClassTemplateDecl* decl) { - if (decl->getName() != "fex_gen_config") { - return true; - } - - if (llvm::dyn_cast(decl->getDeclContext())) { - decl_contexts.push_back(decl->getDeclContext()); - } - - return true; + if (llvm::dyn_cast(decl->getDeclContext())) { + decl_contexts.push_back(decl->getDeclContext()); } + + return true; + } }; class ASTConsumer : public clang::ASTConsumer { - std::vector& decl_contexts; + std::vector& decl_contexts; public: - ASTConsumer(std::vector& decl_contexts_) - : decl_contexts(decl_contexts_) { - } + ASTConsumer(std::vector& decl_contexts_) + : decl_contexts(decl_contexts_) {} - void HandleTranslationUnit(clang::ASTContext& context) override { - ASTVisitor { decl_contexts }.TraverseDecl(context.getTranslationUnitDecl()); - } + void HandleTranslationUnit(clang::ASTContext& context) override { + ASTVisitor {decl_contexts}.TraverseDecl(context.getTranslationUnitDecl()); + } }; std::unique_ptr AnalysisAction::CreateASTConsumer(clang::CompilerInstance&, clang::StringRef) { - return std::make_unique(decl_contexts); + return std::make_unique(decl_contexts); } diff --git a/ThunkLibs/Generator/analysis.h b/ThunkLibs/Generator/analysis.h index 6b4d0f85d..ea253fef8 100644 --- a/ThunkLibs/Generator/analysis.h +++ b/ThunkLibs/Generator/analysis.h @@ -11,21 +11,21 @@ #include struct FunctionParams { - std::vector param_types; + std::vector param_types; }; struct ThunkedCallback : FunctionParams { - clang::QualType return_type; + clang::QualType return_type; - bool is_stub = false; // Callback will be replaced by a stub that calls std::abort - bool is_variadic = false; + bool is_stub = false; // Callback will be replaced by a stub that calls std::abort + bool is_variadic = false; }; struct ParameterAnnotations { - bool is_passthrough = false; - bool assume_compatible = false; + bool is_passthrough = false; + bool assume_compatible = false; - bool operator==(const ParameterAnnotations&) const = default; + bool operator==(const ParameterAnnotations&) const = default; }; /** @@ -37,33 +37,33 @@ struct ParameterAnnotations { * API. */ struct ThunkedFunction : FunctionParams { - std::string function_name; - clang::QualType return_type; + std::string function_name; + clang::QualType return_type; - // If true, param_types contains an extra size_t and the valist for marshalling through an internal function - bool is_variadic = false; + // If true, param_types contains an extra size_t and the valist for marshalling through an internal function + bool is_variadic = false; - // If true, the unpacking function will call a custom fexfn_impl function - // to be provided manually instead of calling the host library function - // directly. - // This is implied e.g. for thunks generated for variadic functions - bool custom_host_impl = false; + // If true, the unpacking function will call a custom fexfn_impl function + // to be provided manually instead of calling the host library function + // directly. + // This is implied e.g. for thunks generated for variadic functions + bool custom_host_impl = false; - std::string GetOriginalFunctionName() const { - const std::string suffix = "_internal"; - assert(function_name.length() > suffix.size()); - assert((std::string_view { &*function_name.end() - suffix.size(), suffix.size() } == suffix)); - return function_name.substr(0, function_name.size() - suffix.size()); - } + std::string GetOriginalFunctionName() const { + const std::string suffix = "_internal"; + assert(function_name.length() > suffix.size()); + assert((std::string_view {&*function_name.end() - suffix.size(), suffix.size()} == suffix)); + return function_name.substr(0, function_name.size() - suffix.size()); + } - // Maps parameter index to ThunkedCallback - std::unordered_map callbacks; + // Maps parameter index to ThunkedCallback + std::unordered_map callbacks; - // Maps parameter index to ParameterAnnotations - // TODO: Use index -1 for the return value? - std::unordered_map param_annotations; + // Maps parameter index to ParameterAnnotations + // TODO: Use index -1 for the return value? + std::unordered_map param_annotations; - clang::FunctionDecl* decl; + clang::FunctionDecl* decl; }; /** @@ -75,139 +75,139 @@ struct ThunkedFunction : FunctionParams { * - A ThunkedFunction with the same function_name (possibly suffixed with _internal) */ struct ThunkedAPIFunction : FunctionParams { - std::string function_name; + std::string function_name; - clang::QualType return_type; + clang::QualType return_type; - // name of the function to load the native host symbol with - std::string host_loader; + // name of the function to load the native host symbol with + std::string host_loader; - // If true, no guest-side implementation of this function will be autogenerated - bool custom_guest_impl; + // If true, no guest-side implementation of this function will be autogenerated + bool custom_guest_impl; - bool is_variadic; + bool is_variadic; - // Index of the symbol table to store this export in (see guest_symtables). - // If empty, a library export is created, otherwise the function is entered into a function pointer array - std::optional symtable_namespace; + // Index of the symbol table to store this export in (see guest_symtables). + // If empty, a library export is created, otherwise the function is entered into a function pointer array + std::optional symtable_namespace; }; struct NamespaceInfo { - clang::DeclContext* context; + clang::DeclContext* context; - std::string name; + std::string name; - // Function to load native host library functions with. - // This function must be defined manually with the signature "void* func(void*, const char*)" - std::string host_loader; + // Function to load native host library functions with. + // This function must be defined manually with the signature "void* func(void*, const char*)" + std::string host_loader; - bool generate_guest_symtable; + bool generate_guest_symtable; - bool indirect_guest_calls; + bool indirect_guest_calls; }; class AnalysisAction : public clang::ASTFrontendAction { public: - AnalysisAction() { - decl_contexts.push_back(nullptr); // global namespace (replaced by getTranslationUnitDecl later) + AnalysisAction() { + decl_contexts.push_back(nullptr); // global namespace (replaced by getTranslationUnitDecl later) + } + + void ExecuteAction() override; + + std::unique_ptr CreateASTConsumer(clang::CompilerInstance&, clang::StringRef /*file*/) override; + + struct RepackedType { + bool assumed_compatible = false; // opaque_type or assume_compatible_data_layout + bool pointers_only = assumed_compatible; // if true, only pointers to this type may be used + + // If true, emit guest_layout/host_layout definitions even if the type is non-repackable + bool emit_layout_wrappers = false; + + // Set of members (identified by their field name) with custom repacking + std::unordered_set custom_repacked_members; + + bool UsesCustomRepackFor(const clang::FieldDecl* member) const { + return custom_repacked_members.contains(member->getNameAsString()); } - - void ExecuteAction() override; - - std::unique_ptr CreateASTConsumer(clang::CompilerInstance&, clang::StringRef /*file*/) override; - - struct RepackedType { - bool assumed_compatible = false; // opaque_type or assume_compatible_data_layout - bool pointers_only = assumed_compatible; // if true, only pointers to this type may be used - - // If true, emit guest_layout/host_layout definitions even if the type is non-repackable - bool emit_layout_wrappers = false; - - // Set of members (identified by their field name) with custom repacking - std::unordered_set custom_repacked_members; - - bool UsesCustomRepackFor(const clang::FieldDecl* member) const { - return custom_repacked_members.contains(member->getNameAsString()); - } - bool UsesCustomRepackFor(const std::string& member_name) const { - return custom_repacked_members.contains(member_name); - } - }; + bool UsesCustomRepackFor(const std::string& member_name) const { + return custom_repacked_members.contains(member_name); + } + }; protected: - // Build the internal API representation by processing fex_gen_config and other annotated entities - void ParseInterface(clang::ASTContext&); + // Build the internal API representation by processing fex_gen_config and other annotated entities + void ParseInterface(clang::ASTContext&); - // Recursively extend the type set to include types of struct members - void CoverReferencedTypes(clang::ASTContext&); + // Recursively extend the type set to include types of struct members + void CoverReferencedTypes(clang::ASTContext&); - // Called from ExecuteAction() after parsing is complete - virtual void OnAnalysisComplete(clang::ASTContext&) {}; + // Called from ExecuteAction() after parsing is complete + virtual void OnAnalysisComplete(clang::ASTContext&) {}; - std::vector decl_contexts; + std::vector decl_contexts; - std::vector thunks; - std::vector thunked_api; + std::vector thunks; + std::vector thunked_api; - // Set of function types for which to generate Guest->Host thunking trampolines. - // The map key is a unique identifier that must be consistent between guest/host processing passes. - // The map value is a pair of the function pointer's clang::Type and the mapping of parameter annotations - std::unordered_map>> thunked_funcptrs; + // Set of function types for which to generate Guest->Host thunking trampolines. + // The map key is a unique identifier that must be consistent between guest/host processing passes. + // The map value is a pair of the function pointer's clang::Type and the mapping of parameter annotations + std::unordered_map>> thunked_funcptrs; - std::unordered_map types; - std::optional lib_version; - std::vector namespaces; + std::unordered_map types; + std::optional lib_version; + std::vector namespaces; - RepackedType& LookupType(clang::ASTContext& context, const clang::Type* type) { - return types.at(context.getCanonicalType(type)); - } + RepackedType& LookupType(clang::ASTContext& context, const clang::Type* type) { + return types.at(context.getCanonicalType(type)); + } }; inline std::string get_type_name(const clang::ASTContext& context, const clang::Type* type) { - if (type->isBuiltinType()) { - // Skip canonicalization - return clang::QualType { type, 0 }.getAsString(); - } + if (type->isBuiltinType()) { + // Skip canonicalization + return clang::QualType {type, 0}.getAsString(); + } - if (auto decl = type->getAsTagDecl()) { - // Replace unnamed types with a placeholder. This will fail to compile if referenced - // anywhere in generated code, but at least it will point to a useful location. - // - // A notable exception are C-style struct declarations like "typedef struct (unnamed) { ... } MyStruct;". - // A typedef name is associated with these for linking purposes, so - // getAsString() will produce a usable identifier. - // TODO: Consider turning this into a hard error instead of replacing the name - if (!decl->getDeclName() && !decl->getTypedefNameForAnonDecl()) { - auto loc = context.getSourceManager().getPresumedLoc(decl->getLocation()); - std::string filename = loc.getFilename(); - filename = std::move(filename).substr(filename.rfind("/")); - filename = std::move(filename).substr(1); - std::replace(filename.begin(), filename.end(), '.', '_'); - return "unnamed_type_" + filename + "_" + std::to_string(loc.getLine()); - } + if (auto decl = type->getAsTagDecl()) { + // Replace unnamed types with a placeholder. This will fail to compile if referenced + // anywhere in generated code, but at least it will point to a useful location. + // + // A notable exception are C-style struct declarations like "typedef struct (unnamed) { ... } MyStruct;". + // A typedef name is associated with these for linking purposes, so + // getAsString() will produce a usable identifier. + // TODO: Consider turning this into a hard error instead of replacing the name + if (!decl->getDeclName() && !decl->getTypedefNameForAnonDecl()) { + auto loc = context.getSourceManager().getPresumedLoc(decl->getLocation()); + std::string filename = loc.getFilename(); + filename = std::move(filename).substr(filename.rfind("/")); + filename = std::move(filename).substr(1); + std::replace(filename.begin(), filename.end(), '.', '_'); + return "unnamed_type_" + filename + "_" + std::to_string(loc.getLine()); } + } - auto type_name = clang::QualType { context.getCanonicalType(type), 0 }.getAsString(); - if (type_name.starts_with("struct ")) { - type_name = type_name.substr(7); - } - if (type_name.starts_with("class ") || type_name.starts_with("union ")) { - type_name = type_name.substr(6); - } - if (type_name.starts_with("enum ")) { - type_name = type_name.substr(5); - } - return type_name; + auto type_name = clang::QualType {context.getCanonicalType(type), 0}.getAsString(); + if (type_name.starts_with("struct ")) { + type_name = type_name.substr(7); + } + if (type_name.starts_with("class ") || type_name.starts_with("union ")) { + type_name = type_name.substr(6); + } + if (type_name.starts_with("enum ")) { + type_name = type_name.substr(5); + } + return type_name; } inline std::string get_fixed_size_int_name(bool is_signed, int size) { - return (!is_signed ? "u" : "") + std::string { "int" } + std::to_string(size) + "_t"; + return (!is_signed ? "u" : "") + std::string {"int"} + std::to_string(size) + "_t"; } inline std::string get_fixed_size_int_name(const clang::Type* type, int size) { - return get_fixed_size_int_name(type->isSignedIntegerType(), size); + return get_fixed_size_int_name(type->isSignedIntegerType(), size); } inline std::string get_fixed_size_int_name(const clang::Type* type, const clang::ASTContext& context) { - return get_fixed_size_int_name(type, context.getTypeSize(type)); + return get_fixed_size_int_name(type, context.getTypeSize(type)); } diff --git a/ThunkLibs/Generator/data_layout.cpp b/ThunkLibs/Generator/data_layout.cpp index 3955c175d..92f49f1a4 100644 --- a/ThunkLibs/Generator/data_layout.cpp +++ b/ThunkLibs/Generator/data_layout.cpp @@ -10,399 +10,406 @@ constexpr bool enable_debug_output = false; // Visitor for gathering data layout information that can be passed across libclang invocations class AnalyzeDataLayoutAction : public AnalysisAction { - ABI& type_abi; + ABI& type_abi; - void OnAnalysisComplete(clang::ASTContext&) override; + void OnAnalysisComplete(clang::ASTContext&) override; public: - AnalyzeDataLayoutAction(ABI&); + AnalyzeDataLayoutAction(ABI&); }; -AnalyzeDataLayoutAction::AnalyzeDataLayoutAction(ABI& abi_) : type_abi(abi_) { -} +AnalyzeDataLayoutAction::AnalyzeDataLayoutAction(ABI& abi_) + : type_abi(abi_) {} -std::unordered_map ComputeDataLayout(const clang::ASTContext& context, const std::unordered_map& types) { - std::unordered_map layout; +std::unordered_map +ComputeDataLayout(const clang::ASTContext& context, const std::unordered_map& types) { + std::unordered_map layout; - // First, add all types directly used in function signatures of the library API to the meta set - for (const auto& [type, type_repack_info] : types) { - if (type_repack_info.assumed_compatible) { - auto [_, inserted] = layout.insert(std::pair { context.getCanonicalType(type), TypeInfo {} }); - if (!inserted) { - throw std::runtime_error("Failed to gather type metadata: Opaque type \"" + clang::QualType { type, 0 }.getAsString() + "\" already registered"); - } - continue; - } - - if (type->isIncompleteType()) { - throw std::runtime_error("Cannot compute data layout of incomplete type \"" + clang::QualType { type, 0 }.getAsString() + "\". Did you forget any annotations?"); - } - - if (type->isStructureType()) { - StructInfo info; - info.size_bits = context.getTypeSize(type); - info.alignment_bits = context.getTypeAlign(type); - - auto [_, inserted] = layout.insert(std::pair { context.getCanonicalType(type), info }); - if (!inserted) { - throw std::runtime_error("Failed to gather type metadata: Type \"" + clang::QualType { type, 0 }.getAsString() + "\" already registered"); - } - } else if (type->isBuiltinType() || type->isEnumeralType()) { - SimpleTypeInfo info; - info.size_bits = context.getTypeSize(type); - info.alignment_bits = context.getTypeAlign(type); - - // NOTE: Non-enum types are intentionally not canonicalized since that would turn e.g. size_t into platform-specific types - auto [_, inserted] = layout.insert(std::pair { type->isEnumeralType() ? context.getCanonicalType(type) : type, info }); - if (!inserted) { - throw std::runtime_error("Failed to gather type metadata: Type \"" + clang::QualType { type, 0 }.getAsString() + "\" already registered"); - } - } + // First, add all types directly used in function signatures of the library API to the meta set + for (const auto& [type, type_repack_info] : types) { + if (type_repack_info.assumed_compatible) { + auto [_, inserted] = layout.insert(std::pair {context.getCanonicalType(type), TypeInfo {}}); + if (!inserted) { + throw std::runtime_error( + "Failed to gather type metadata: Opaque type \"" + clang::QualType {type, 0}.getAsString() + "\" already registered"); + } + continue; } - // Then, add information about members - for (const auto& [type, type_repack_info] : types) { - if (!type->isStructureType() || type_repack_info.assumed_compatible) { - continue; - } - - auto& info = *layout.at(context.getCanonicalType(type)).get_if_struct(); - - for (auto* field : type->getAsStructureType()->getDecl()->fields()) { - auto field_type = field->getType().getTypePtr(); - std::optional array_size; - if (auto array_type = llvm::dyn_cast(field->getType())) { - array_size = array_type->getSize().getZExtValue(); - field_type = array_type->getElementType().getTypePtr(); - if (llvm::isa(field_type)) { - throw std::runtime_error("Unsupported multi-dimensional array member \"" + field->getNameAsString() + "\" in type \"" + clang::QualType { type, 0 }.getAsString() + "\""); - } - } - - StructInfo::MemberInfo member_info { - .size_bits = context.getTypeSize(field->getType()), // Total size even for arrays - .offset_bits = context.getFieldOffset(field), - .type_name = get_type_name(context, field_type), - .member_name = field->getNameAsString(), - .array_size = array_size, - .is_function_pointer = field_type->isFunctionPointerType(), - .is_integral = field->getType()->isIntegerType(), - .is_signed_integer = field->getType()->isSignedIntegerType(), - }; - - // TODO: Process types in dependency-order. Currently we skip this - // check if we haven't processed the member type already, - // which is only safe since this is a consistency check - if (field_type->isStructureType() && layout.contains(context.getCanonicalType(field_type))) { - // Assert for self-consistency - auto field_meta = layout.at(context.getCanonicalType(field_type)); - (void)types.at(context.getCanonicalType(field_type)); - if (auto field_info = field_meta.get_if_simple_or_struct()) { - if (field_info->size_bits != member_info.size_bits / member_info.array_size.value_or(1)) { - throw std::runtime_error("Inconsistent type size detected"); - } - } - } - - // Add built-in types, even if referenced through a pointer - for (auto* inner_field_type = field_type; inner_field_type; inner_field_type = inner_field_type->getPointeeType().getTypePtrOrNull()) { - if (inner_field_type->isBuiltinType() || inner_field_type->isEnumeralType()) { - // The analysis pass doesn't explicitly register built-in types, so add them manually here - SimpleTypeInfo info { - .size_bits = context.getTypeSize(inner_field_type), - .alignment_bits = context.getTypeAlign(inner_field_type), - }; - if (!inner_field_type->isBuiltinType()) { - inner_field_type = context.getCanonicalType(inner_field_type); - } - [[maybe_unused]] auto [prev, inserted] = layout.insert(std::pair { inner_field_type, info }); -// if (!inserted && prev->second != TypeInfo { info }) { -// // TODO: Throw error since consistency check failed -// } - } - } - - info.members.push_back(member_info); - } + if (type->isIncompleteType()) { + throw std::runtime_error( + "Cannot compute data layout of incomplete type \"" + clang::QualType {type, 0}.getAsString() + "\". Did you forget any annotations?"); } - if (enable_debug_output) { - for (const auto& [type, info] : layout) { - auto basic_info = info.get_if_simple_or_struct(); - if (!basic_info) { - continue; - } + if (type->isStructureType()) { + StructInfo info; + info.size_bits = context.getTypeSize(type); + info.alignment_bits = context.getTypeAlign(type); - fprintf(stderr, " Host entry %s: %lu (%lu)\n", clang::QualType { type, 0 }.getAsString().c_str(), basic_info->size_bits / 8, basic_info->alignment_bits / 8); + auto [_, inserted] = layout.insert(std::pair {context.getCanonicalType(type), info}); + if (!inserted) { + throw std::runtime_error("Failed to gather type metadata: Type \"" + clang::QualType {type, 0}.getAsString() + "\" already registered"); + } + } else if (type->isBuiltinType() || type->isEnumeralType()) { + SimpleTypeInfo info; + info.size_bits = context.getTypeSize(type); + info.alignment_bits = context.getTypeAlign(type); - if (auto struct_info = info.get_if_struct()) { - for (const auto& member : struct_info->members) { - fprintf(stderr, " Offset %lu-%lu: %s %s%s\n", member.offset_bits / 8, (member.offset_bits + member.size_bits - 1) / 8, member.type_name.c_str(), member.member_name.c_str(), member.array_size ? fmt::format("[{}]", member.array_size.value()).c_str() : ""); - } - } - } + // NOTE: Non-enum types are intentionally not canonicalized since that would turn e.g. size_t into platform-specific types + auto [_, inserted] = layout.insert(std::pair {type->isEnumeralType() ? context.getCanonicalType(type) : type, info}); + if (!inserted) { + throw std::runtime_error("Failed to gather type metadata: Type \"" + clang::QualType {type, 0}.getAsString() + "\" already registered"); + } + } + } + + // Then, add information about members + for (const auto& [type, type_repack_info] : types) { + if (!type->isStructureType() || type_repack_info.assumed_compatible) { + continue; } - return layout; + auto& info = *layout.at(context.getCanonicalType(type)).get_if_struct(); + + for (auto* field : type->getAsStructureType()->getDecl()->fields()) { + auto field_type = field->getType().getTypePtr(); + std::optional array_size; + if (auto array_type = llvm::dyn_cast(field->getType())) { + array_size = array_type->getSize().getZExtValue(); + field_type = array_type->getElementType().getTypePtr(); + if (llvm::isa(field_type)) { + throw std::runtime_error("Unsupported multi-dimensional array member \"" + field->getNameAsString() + "\" in type \"" + + clang::QualType {type, 0}.getAsString() + "\""); + } + } + + StructInfo::MemberInfo member_info { + .size_bits = context.getTypeSize(field->getType()), // Total size even for arrays + .offset_bits = context.getFieldOffset(field), + .type_name = get_type_name(context, field_type), + .member_name = field->getNameAsString(), + .array_size = array_size, + .is_function_pointer = field_type->isFunctionPointerType(), + .is_integral = field->getType()->isIntegerType(), + .is_signed_integer = field->getType()->isSignedIntegerType(), + }; + + // TODO: Process types in dependency-order. Currently we skip this + // check if we haven't processed the member type already, + // which is only safe since this is a consistency check + if (field_type->isStructureType() && layout.contains(context.getCanonicalType(field_type))) { + // Assert for self-consistency + auto field_meta = layout.at(context.getCanonicalType(field_type)); + (void)types.at(context.getCanonicalType(field_type)); + if (auto field_info = field_meta.get_if_simple_or_struct()) { + if (field_info->size_bits != member_info.size_bits / member_info.array_size.value_or(1)) { + throw std::runtime_error("Inconsistent type size detected"); + } + } + } + + // Add built-in types, even if referenced through a pointer + for (auto* inner_field_type = field_type; inner_field_type; inner_field_type = inner_field_type->getPointeeType().getTypePtrOrNull()) { + if (inner_field_type->isBuiltinType() || inner_field_type->isEnumeralType()) { + // The analysis pass doesn't explicitly register built-in types, so add them manually here + SimpleTypeInfo info { + .size_bits = context.getTypeSize(inner_field_type), + .alignment_bits = context.getTypeAlign(inner_field_type), + }; + if (!inner_field_type->isBuiltinType()) { + inner_field_type = context.getCanonicalType(inner_field_type); + } + [[maybe_unused]] auto [prev, inserted] = layout.insert(std::pair {inner_field_type, info}); + // if (!inserted && prev->second != TypeInfo { info }) { + // // TODO: Throw error since consistency check failed + // } + } + } + + info.members.push_back(member_info); + } + } + + if (enable_debug_output) { + for (const auto& [type, info] : layout) { + auto basic_info = info.get_if_simple_or_struct(); + if (!basic_info) { + continue; + } + + fprintf(stderr, " Host entry %s: %lu (%lu)\n", clang::QualType {type, 0}.getAsString().c_str(), basic_info->size_bits / 8, + basic_info->alignment_bits / 8); + + if (auto struct_info = info.get_if_struct()) { + for (const auto& member : struct_info->members) { + fprintf(stderr, " Offset %lu-%lu: %s %s%s\n", member.offset_bits / 8, (member.offset_bits + member.size_bits - 1) / 8, + member.type_name.c_str(), member.member_name.c_str(), + member.array_size ? fmt::format("[{}]", member.array_size.value()).c_str() : ""); + } + } + } + } + + return layout; } ABI GetStableLayout(const clang::ASTContext& context, const std::unordered_map& data_layout) { - ABI stable_layout; + ABI stable_layout; - for (auto [type, type_info] : data_layout) { - auto type_name = get_type_name(context, type); - if (auto struct_info = type_info.get_if_struct()) { - for (auto& member : struct_info->members) { - if (member.is_integral) { - // Map member types to fixed-size integers - auto alt_type_name = get_fixed_size_int_name(member.is_signed_integer, member.size_bits); - auto alt_type_info = SimpleTypeInfo { - .size_bits = member.size_bits, - .alignment_bits = context.getTypeAlign(context.getIntTypeForBitwidth(member.size_bits, member.is_signed_integer)), - }; - stable_layout.insert(std::pair { alt_type_name, alt_type_info }); - member.type_name = std::move(alt_type_name); - } - } - } - - auto [it, inserted] = stable_layout.insert(std::pair { type_name, std::move(type_info) }); - if (type->isIntegerType()) { - auto alt_type_name = get_fixed_size_int_name(type, context); - stable_layout.insert(std::pair { std::move(alt_type_name), type_info }); - } - - if (!inserted && it->second != type_info && !type->isIntegerType()) { - throw std::runtime_error("Duplicate type information: Tried to re-register type \"" + type_name + "\""); + for (auto [type, type_info] : data_layout) { + auto type_name = get_type_name(context, type); + if (auto struct_info = type_info.get_if_struct()) { + for (auto& member : struct_info->members) { + if (member.is_integral) { + // Map member types to fixed-size integers + auto alt_type_name = get_fixed_size_int_name(member.is_signed_integer, member.size_bits); + auto alt_type_info = SimpleTypeInfo { + .size_bits = member.size_bits, + .alignment_bits = context.getTypeAlign(context.getIntTypeForBitwidth(member.size_bits, member.is_signed_integer)), + }; + stable_layout.insert(std::pair {alt_type_name, alt_type_info}); + member.type_name = std::move(alt_type_name); } + } } - stable_layout.pointer_size = context.getTypeSize(context.getUIntPtrType()) / 8; + auto [it, inserted] = stable_layout.insert(std::pair {type_name, std::move(type_info)}); + if (type->isIntegerType()) { + auto alt_type_name = get_fixed_size_int_name(type, context); + stable_layout.insert(std::pair {std::move(alt_type_name), type_info}); + } - return stable_layout; + if (!inserted && it->second != type_info && !type->isIntegerType()) { + throw std::runtime_error("Duplicate type information: Tried to re-register type \"" + type_name + "\""); + } + } + + stable_layout.pointer_size = context.getTypeSize(context.getUIntPtrType()) / 8; + + return stable_layout; } static std::array GetSha256(const std::string& function_name) { - std::array sha256; - SHA256(reinterpret_cast(function_name.data()), - function_name.size(), - sha256.data()); - return sha256; + std::array sha256; + SHA256(reinterpret_cast(function_name.data()), function_name.size(), sha256.data()); + return sha256; }; std::string GetTypeNameWithFixedSizeIntegers(clang::ASTContext& context, clang::QualType type) { - if (type->isBuiltinType() && type->isIntegerType()) { - auto size = context.getTypeSize(type); - return fmt::format("uint{}_t", size); - } else if (type->isPointerType() && type->getPointeeType()->isBuiltinType() && type->getPointeeType()->isIntegerType() && context.getTypeSize(type->getPointeeType()) > 8) { - // TODO: Also apply this path to char-like types - auto size = context.getTypeSize(type->getPointeeType()); - return fmt::format("uint{}_t*", size); - } else { - return type.getAsString(); - } + if (type->isBuiltinType() && type->isIntegerType()) { + auto size = context.getTypeSize(type); + return fmt::format("uint{}_t", size); + } else if (type->isPointerType() && type->getPointeeType()->isBuiltinType() && type->getPointeeType()->isIntegerType() && + context.getTypeSize(type->getPointeeType()) > 8) { + // TODO: Also apply this path to char-like types + auto size = context.getTypeSize(type->getPointeeType()); + return fmt::format("uint{}_t*", size); + } else { + return type.getAsString(); + } } void AnalyzeDataLayoutAction::OnAnalysisComplete(clang::ASTContext& context) { - type_abi = GetStableLayout(context, ComputeDataLayout(context, types)); + type_abi = GetStableLayout(context, ComputeDataLayout(context, types)); - // Register functions that must be guest-callable through host function pointers - for (auto funcptr_type_it = thunked_funcptrs.begin(); funcptr_type_it != thunked_funcptrs.end(); ++funcptr_type_it) { - auto& funcptr_id = funcptr_type_it->first; - auto& [type, param_annotations] = funcptr_type_it->second; - auto func_type = type->getAs(); - std::string mangled_name = clang::QualType { type, 0 }.getAsString(); - auto cb_sha256 = GetSha256("fexcallback_" + mangled_name); - FuncPtrInfo info = { cb_sha256 }; + // Register functions that must be guest-callable through host function pointers + for (auto funcptr_type_it = thunked_funcptrs.begin(); funcptr_type_it != thunked_funcptrs.end(); ++funcptr_type_it) { + auto& funcptr_id = funcptr_type_it->first; + auto& [type, param_annotations] = funcptr_type_it->second; + auto func_type = type->getAs(); + std::string mangled_name = clang::QualType {type, 0}.getAsString(); + auto cb_sha256 = GetSha256("fexcallback_" + mangled_name); + FuncPtrInfo info = {cb_sha256}; - // TODO: Also apply GetTypeNameWithFixedSizeIntegers here - info.result = func_type->getReturnType().getAsString(); + // TODO: Also apply GetTypeNameWithFixedSizeIntegers here + info.result = func_type->getReturnType().getAsString(); - for (auto arg : func_type->getParamTypes()) { - info.args.push_back(GetTypeNameWithFixedSizeIntegers(context, arg)); - } - type_abi.thunked_funcptrs[funcptr_id] = std::move(info); + for (auto arg : func_type->getParamTypes()) { + info.args.push_back(GetTypeNameWithFixedSizeIntegers(context, arg)); } + type_abi.thunked_funcptrs[funcptr_id] = std::move(info); + } } -TypeCompatibility DataLayoutCompareAction::GetTypeCompatibility( - const clang::ASTContext& context, - const clang::Type* type, - const std::unordered_map host_abi, - std::unordered_map& type_compat) { - assert(type->isCanonicalUnqualified() || type->isBuiltinType() || type->isEnumeralType()); +TypeCompatibility DataLayoutCompareAction::GetTypeCompatibility(const clang::ASTContext& context, const clang::Type* type, + const std::unordered_map host_abi, + std::unordered_map& type_compat) { + assert(type->isCanonicalUnqualified() || type->isBuiltinType() || type->isEnumeralType()); - { - // Reserve a slot to be filled later. The placeholder value is used - // to detect infinite recursions. - constexpr auto placeholder_compat = TypeCompatibility { 100 }; - auto [existing_compat_it, is_new_type] = type_compat.emplace(type, placeholder_compat); - if (!is_new_type) { - if (existing_compat_it->second == placeholder_compat) { - throw std::runtime_error("Found recursive reference to type \"" + clang::QualType { type, 0 }.getAsString() + "\""); - } + { + // Reserve a slot to be filled later. The placeholder value is used + // to detect infinite recursions. + constexpr auto placeholder_compat = TypeCompatibility {100}; + auto [existing_compat_it, is_new_type] = type_compat.emplace(type, placeholder_compat); + if (!is_new_type) { + if (existing_compat_it->second == placeholder_compat) { + throw std::runtime_error("Found recursive reference to type \"" + clang::QualType {type, 0}.getAsString() + "\""); + } - return existing_compat_it->second; + return existing_compat_it->second; + } + } + + if (types.contains(type) && types.at(type).assumed_compatible) { + if (types.at(type).pointers_only && !type->isPointerType()) { + throw std::runtime_error( + "Tried to dereference opaque type \"" + clang::QualType {type, 0}.getAsString() + "\" when querying data layout compatibility"); + } + type_compat.at(type) = TypeCompatibility::Full; + return TypeCompatibility::Full; + } + + auto type_name = get_type_name(context, type); + // Look up the same type name in the guest map, + // unless it's an integer (which is mapped to fixed-size uintX_t types) + auto guest_info = guest_abi.at(!type->isIntegerType() ? type_name : get_fixed_size_int_name(type, context)); + auto& host_info = host_abi.at(type->isBuiltinType() ? type : context.getCanonicalType(type)); + + const bool is_32bit = (guest_abi.pointer_size == 4); + + // Assume full compatibility, then downgrade as needed + auto compat = TypeCompatibility::Full; + + if (guest_info != host_info) { + // Non-matching data layout... downgrade to Repackable + // TODO: Even for non-structs, this only works if the types are reasonably similar (e.g. uint32_t -> uint64_t) + compat = TypeCompatibility::Repackable; + } + + auto guest_struct_info = guest_info.get_if_struct(); + if (guest_struct_info && guest_struct_info->members.size() != host_info.get_if_struct()->members.size()) { + // Members are missing from either the guest or host layout + // NOTE: If the members are merely named differently, this will be caught in the else-if below + compat = TypeCompatibility::None; + } else if (guest_struct_info) { + std::vector member_compat; + for (std::size_t member_idx = 0; member_idx < guest_struct_info->members.size(); ++member_idx) { + // Look up the corresponding member in the host struct definition. + // The members may be listed in a different order, so we can't + // directly use member_idx for this + auto* host_member_field = [&]() -> clang::FieldDecl* { + auto struct_decl = type->getAsStructureType()->getDecl(); + auto it = std::find_if(struct_decl->field_begin(), struct_decl->field_end(), + [&](auto* field) { return field->getName() == guest_struct_info->members.at(member_idx).member_name; }); + if (it == struct_decl->field_end()) { + return nullptr; } - } + return *it; + }(); + if (!host_member_field) { + // No corresponding host struct member + // TODO: Also detect host members that are missing from the guest struct + member_compat.push_back(TypeCompatibility::None); + break; + } - if (types.contains(type) && types.at(type).assumed_compatible) { - if (types.at(type).pointers_only && !type->isPointerType()) { - throw std::runtime_error("Tried to dereference opaque type \"" + clang::QualType { type, 0 }.getAsString() + "\" when querying data layout compatibility"); - } - type_compat.at(type) = TypeCompatibility::Full; - return TypeCompatibility::Full; - } + auto host_member_type = context.getCanonicalType(host_member_field->getType().getTypePtr()); + if (auto array_type = llvm::dyn_cast(host_member_type)) { + // Compare array element type only. The array size is already considered by the layout information of the containing struct. + host_member_type = context.getCanonicalType(array_type->getElementType().getTypePtr()); + } - auto type_name = get_type_name(context, type); - // Look up the same type name in the guest map, - // unless it's an integer (which is mapped to fixed-size uintX_t types) - auto guest_info = guest_abi.at(!type->isIntegerType() ? type_name : get_fixed_size_int_name(type, context)); - auto& host_info = host_abi.at(type->isBuiltinType() ? type : context.getCanonicalType(type)); + if (host_member_type->isPointerType()) { + // Automatic repacking of pointers to non-compatible types is only possible if: + // * Pointee is fully compatible, or + // * Pointer member is annotated + // TODO: Don't restrict this to structure types. it applies to pointers to builtin types too! + auto host_member_pointee_type = context.getCanonicalType(host_member_type->getPointeeType().getTypePtr()); + if (types.at(type).UsesCustomRepackFor(host_member_field)) { + member_compat.push_back(TypeCompatibility::Repackable); + } else if (types.contains(host_member_pointee_type) && types.at(host_member_pointee_type).assumed_compatible) { + // Pointee doesn't need repacking, but pointer needs extending on 32-bit + member_compat.push_back(is_32bit ? TypeCompatibility::Repackable : TypeCompatibility::Full); + } else if (host_member_pointee_type->isPointerType()) { + // This is a nested pointer, e.g. void** - const bool is_32bit = (guest_abi.pointer_size == 4); - - // Assume full compatibility, then downgrade as needed - auto compat = TypeCompatibility::Full; - - if (guest_info != host_info) { - // Non-matching data layout... downgrade to Repackable - // TODO: Even for non-structs, this only works if the types are reasonably similar (e.g. uint32_t -> uint64_t) - compat = TypeCompatibility::Repackable; - } - - auto guest_struct_info = guest_info.get_if_struct(); - if (guest_struct_info && guest_struct_info->members.size() != host_info.get_if_struct()->members.size()) { - // Members are missing from either the guest or host layout - // NOTE: If the members are merely named differently, this will be caught in the else-if below - compat = TypeCompatibility::None; - } else if (guest_struct_info) { - std::vector member_compat; - for (std::size_t member_idx = 0; member_idx < guest_struct_info->members.size(); ++member_idx) { - // Look up the corresponding member in the host struct definition. - // The members may be listed in a different order, so we can't - // directly use member_idx for this - auto* host_member_field = [&]() -> clang::FieldDecl* { - auto struct_decl = type->getAsStructureType()->getDecl(); - auto it = std::find_if(struct_decl->field_begin(), struct_decl->field_end(), [&](auto* field) { - return field->getName() == guest_struct_info->members.at(member_idx).member_name; - }); - if (it == struct_decl->field_end()) { - return nullptr; - } - return *it; - }(); - if (!host_member_field) { - // No corresponding host struct member - // TODO: Also detect host members that are missing from the guest struct - member_compat.push_back(TypeCompatibility::None); - break; - } - - auto host_member_type = context.getCanonicalType(host_member_field->getType().getTypePtr()); - if (auto array_type = llvm::dyn_cast(host_member_type)) { - // Compare array element type only. The array size is already considered by the layout information of the containing struct. - host_member_type = context.getCanonicalType(array_type->getElementType().getTypePtr()); - } - - if (host_member_type->isPointerType()) { - // Automatic repacking of pointers to non-compatible types is only possible if: - // * Pointee is fully compatible, or - // * Pointer member is annotated - // TODO: Don't restrict this to structure types. it applies to pointers to builtin types too! - auto host_member_pointee_type = context.getCanonicalType(host_member_type->getPointeeType().getTypePtr()); - if (types.at(type).UsesCustomRepackFor(host_member_field)) { - member_compat.push_back(TypeCompatibility::Repackable); - } else if (types.contains(host_member_pointee_type) && types.at(host_member_pointee_type).assumed_compatible) { - // Pointee doesn't need repacking, but pointer needs extending on 32-bit - member_compat.push_back(is_32bit ? TypeCompatibility::Repackable : TypeCompatibility::Full); - } else if (host_member_pointee_type->isPointerType()) { - // This is a nested pointer, e.g. void** - - if (is_32bit) { - // Nested pointers can't be repacked on 32-bit - member_compat.push_back(TypeCompatibility::None); - } else if (types.contains(host_member_pointee_type->getPointeeType().getTypePtr()) && types.at(host_member_pointee_type->getPointeeType().getTypePtr()).assumed_compatible) { - // Pointers to opaque types are fine - member_compat.push_back(TypeCompatibility::Full); - } else { - // Check the innermost type's compatibility on 64-bit - auto pointee_pointee_type = host_member_pointee_type->getPointeeType().getTypePtr(); - // TODO: Not sure how to handle void here. Probably should require an annotation instead of "just working" - auto pointee_pointee_compat = pointee_pointee_type->isVoidType() ? TypeCompatibility::Full : GetTypeCompatibility(context, pointee_pointee_type, host_abi, type_compat); - if (pointee_pointee_compat == TypeCompatibility::Full) { - member_compat.push_back(TypeCompatibility::Full); - } else { - member_compat.push_back(TypeCompatibility::None); - } - } - } else if (!host_member_pointee_type->isVoidType() && (host_member_pointee_type->isBuiltinType() || host_member_pointee_type->isEnumeralType())) { - // TODO: What are good heuristics for this? - // size_t should yield TypeCompatibility::Repackable - // inconsistent types should probably default to TypeCompatibility::None - // For now, just always assume compatible... (will degrade to Repackable below) - member_compat.push_back(TypeCompatibility::Full); - } else if (!host_member_pointee_type->isVoidType() && (host_member_pointee_type->isStructureType() || types.contains(host_member_pointee_type))) { - auto pointee_compat = GetTypeCompatibility(context, host_member_pointee_type, host_abi, type_compat); - if (pointee_compat == TypeCompatibility::Full) { - // Pointee is fully compatible, so automatic repacking only requires converting the pointers themselves - member_compat.push_back(is_32bit ? TypeCompatibility::Repackable : TypeCompatibility::Full); - } else { - // If the pointee is incompatible (even if repackable), automatic repacking isn't possible - member_compat.push_back(TypeCompatibility::None); - } - } else if (!is_32bit && host_member_pointee_type->isVoidType()) { - // TODO: Not sure how to handle void here. Probably should require an annotation instead of "just working" - member_compat.push_back(TypeCompatibility::Full); - } else { - member_compat.push_back(TypeCompatibility::None); - } - continue; - } - - if (guest_abi.at(guest_struct_info->members[member_idx].type_name).get_if_struct()) { - auto host_type_info = host_abi.at(host_member_type); - member_compat.push_back(GetTypeCompatibility(context, host_member_type, host_abi, type_compat)); + if (is_32bit) { + // Nested pointers can't be repacked on 32-bit + member_compat.push_back(TypeCompatibility::None); + } else if (types.contains(host_member_pointee_type->getPointeeType().getTypePtr()) && + types.at(host_member_pointee_type->getPointeeType().getTypePtr()).assumed_compatible) { + // Pointers to opaque types are fine + member_compat.push_back(TypeCompatibility::Full); + } else { + // Check the innermost type's compatibility on 64-bit + auto pointee_pointee_type = host_member_pointee_type->getPointeeType().getTypePtr(); + // TODO: Not sure how to handle void here. Probably should require an annotation instead of "just working" + auto pointee_pointee_compat = pointee_pointee_type->isVoidType() ? + TypeCompatibility::Full : + GetTypeCompatibility(context, pointee_pointee_type, host_abi, type_compat); + if (pointee_pointee_compat == TypeCompatibility::Full) { + member_compat.push_back(TypeCompatibility::Full); } else { - // Member was checked for size/alignment above already + member_compat.push_back(TypeCompatibility::None); } - } - - if (std::all_of(member_compat.begin(), member_compat.end(), [](auto compat) { return compat == TypeCompatibility::Full; })) { - // TypeCompatibility::Full or ::Repackable - } else if (std::none_of(member_compat.begin(), member_compat.end(), [](auto compat) { return compat == TypeCompatibility::None; })) { - // Downgrade to Repackable - compat = TypeCompatibility::Repackable; + } + } else if (!host_member_pointee_type->isVoidType() && + (host_member_pointee_type->isBuiltinType() || host_member_pointee_type->isEnumeralType())) { + // TODO: What are good heuristics for this? + // size_t should yield TypeCompatibility::Repackable + // inconsistent types should probably default to TypeCompatibility::None + // For now, just always assume compatible... (will degrade to Repackable below) + member_compat.push_back(TypeCompatibility::Full); + } else if (!host_member_pointee_type->isVoidType() && + (host_member_pointee_type->isStructureType() || types.contains(host_member_pointee_type))) { + auto pointee_compat = GetTypeCompatibility(context, host_member_pointee_type, host_abi, type_compat); + if (pointee_compat == TypeCompatibility::Full) { + // Pointee is fully compatible, so automatic repacking only requires converting the pointers themselves + member_compat.push_back(is_32bit ? TypeCompatibility::Repackable : TypeCompatibility::Full); + } else { + // If the pointee is incompatible (even if repackable), automatic repacking isn't possible + member_compat.push_back(TypeCompatibility::None); + } + } else if (!is_32bit && host_member_pointee_type->isVoidType()) { + // TODO: Not sure how to handle void here. Probably should require an annotation instead of "just working" + member_compat.push_back(TypeCompatibility::Full); } else { - // Downgrade to None - compat = TypeCompatibility::None; + member_compat.push_back(TypeCompatibility::None); } + continue; + } + + if (guest_abi.at(guest_struct_info->members[member_idx].type_name).get_if_struct()) { + auto host_type_info = host_abi.at(host_member_type); + member_compat.push_back(GetTypeCompatibility(context, host_member_type, host_abi, type_compat)); + } else { + // Member was checked for size/alignment above already + } } - type_compat.at(type) = compat; - return compat; + if (std::all_of(member_compat.begin(), member_compat.end(), [](auto compat) { return compat == TypeCompatibility::Full; })) { + // TypeCompatibility::Full or ::Repackable + } else if (std::none_of(member_compat.begin(), member_compat.end(), [](auto compat) { return compat == TypeCompatibility::None; })) { + // Downgrade to Repackable + compat = TypeCompatibility::Repackable; + } else { + // Downgrade to None + compat = TypeCompatibility::None; + } + } + + type_compat.at(type) = compat; + return compat; } FuncPtrInfo DataLayoutCompareAction::LookupGuestFuncPtrInfo(const char* funcptr_id) { - return guest_abi.thunked_funcptrs.at(funcptr_id); + return guest_abi.thunked_funcptrs.at(funcptr_id); } -DataLayoutCompareActionFactory::DataLayoutCompareActionFactory(const ABI& abi) : abi(abi) { - -} +DataLayoutCompareActionFactory::DataLayoutCompareActionFactory(const ABI& abi) + : abi(abi) {} DataLayoutCompareActionFactory::~DataLayoutCompareActionFactory() = default; std::unique_ptr DataLayoutCompareActionFactory::create() { - return std::make_unique(abi); + return std::make_unique(abi); } -AnalyzeDataLayoutActionFactory::AnalyzeDataLayoutActionFactory() : abi(std::make_unique()) { - -} +AnalyzeDataLayoutActionFactory::AnalyzeDataLayoutActionFactory() + : abi(std::make_unique()) {} AnalyzeDataLayoutActionFactory::~AnalyzeDataLayoutActionFactory() = default; std::unique_ptr AnalyzeDataLayoutActionFactory::create() { - return std::make_unique(*abi); + return std::make_unique(*abi); } diff --git a/ThunkLibs/Generator/data_layout.h b/ThunkLibs/Generator/data_layout.h index c378806f8..c83f329b7 100644 --- a/ThunkLibs/Generator/data_layout.h +++ b/ThunkLibs/Generator/data_layout.h @@ -12,86 +12,83 @@ #include struct SimpleTypeInfo { - uint64_t size_bits; - uint64_t alignment_bits; + uint64_t size_bits; + uint64_t alignment_bits; - bool operator==(const SimpleTypeInfo& other) const { - return size_bits == other.size_bits && - alignment_bits == other.alignment_bits; - } + bool operator==(const SimpleTypeInfo& other) const { + return size_bits == other.size_bits && alignment_bits == other.alignment_bits; + } }; struct StructInfo : SimpleTypeInfo { - struct MemberInfo { - uint64_t size_bits; // size of this member. For arrays, total size of all elements - uint64_t offset_bits; - std::string type_name; - std::string member_name; - std::optional array_size; - bool is_function_pointer; - bool is_integral; - bool is_signed_integer; + struct MemberInfo { + uint64_t size_bits; // size of this member. For arrays, total size of all elements + uint64_t offset_bits; + std::string type_name; + std::string member_name; + std::optional array_size; + bool is_function_pointer; + bool is_integral; + bool is_signed_integer; - bool operator==(const MemberInfo& other) const { - return size_bits == other.size_bits && - offset_bits == other.offset_bits && - // The type name may differ for integral types if all other parameters are equal - (type_name == other.type_name || (is_integral && other.is_integral)) && - member_name == other.member_name && - array_size == other.array_size && - is_function_pointer == other.is_function_pointer && - is_integral == other.is_integral; - } - }; - - std::vector members; - - bool operator==(const StructInfo& other) const { - return (const SimpleTypeInfo&)*this == (const SimpleTypeInfo&)other && - std::equal(members.begin(), members.end(), other.members.begin(), other.members.end()); + bool operator==(const MemberInfo& other) const { + return size_bits == other.size_bits && offset_bits == other.offset_bits && + // The type name may differ for integral types if all other parameters are equal + (type_name == other.type_name || (is_integral && other.is_integral)) && member_name == other.member_name && + array_size == other.array_size && is_function_pointer == other.is_function_pointer && is_integral == other.is_integral; } + }; + + std::vector members; + + bool operator==(const StructInfo& other) const { + return (const SimpleTypeInfo&)*this == (const SimpleTypeInfo&)other && + std::equal(members.begin(), members.end(), other.members.begin(), other.members.end()); + } }; struct TypeInfo : std::variant { - using Parent = std::variant; + using Parent = std::variant; - TypeInfo() = default; - TypeInfo(const SimpleTypeInfo& info) : Parent(info) {} - TypeInfo(const StructInfo& info) : Parent(info) {} + TypeInfo() = default; + TypeInfo(const SimpleTypeInfo& info) + : Parent(info) {} + TypeInfo(const StructInfo& info) + : Parent(info) {} - // Opaque declaration with no full definition. - // Pointers to these can still be passed along ABI boundaries assuming - // implementation details are only ever accessed on one side. - bool is_opaque() const { - return std::holds_alternative(*this); - } + // Opaque declaration with no full definition. + // Pointers to these can still be passed along ABI boundaries assuming + // implementation details are only ever accessed on one side. + bool is_opaque() const { + return std::holds_alternative(*this); + } - const StructInfo* get_if_struct() const { - return std::get_if(this); - } + const StructInfo* get_if_struct() const { + return std::get_if(this); + } - StructInfo* get_if_struct() { - return std::get_if(this); - } + StructInfo* get_if_struct() { + return std::get_if(this); + } - const SimpleTypeInfo* get_if_simple_or_struct() const { - auto as_struct = std::get_if(this); - if (as_struct) { - return as_struct; - } - return std::get_if(this); + const SimpleTypeInfo* get_if_simple_or_struct() const { + auto as_struct = std::get_if(this); + if (as_struct) { + return as_struct; } + return std::get_if(this); + } }; struct FuncPtrInfo { - std::array sha256; - std::string result; - std::vector args; + std::array sha256; + std::string result; + std::vector args; }; struct ABI : std::unordered_map { - std::unordered_map thunked_funcptrs; - int pointer_size; // in bytes + std::unordered_map thunked_funcptrs; + int pointer_size; // in bytes }; std::unordered_map @@ -113,24 +110,22 @@ ABI GetStableLayout(const clang::ASTContext& context, const std::unordered_map host_abi, - std::unordered_map& type_compat); + TypeCompatibility GetTypeCompatibility(const clang::ASTContext&, const clang::Type*, + const std::unordered_map host_abi, + std::unordered_map& type_compat); - FuncPtrInfo LookupGuestFuncPtrInfo(const char* funcptr_id); + FuncPtrInfo LookupGuestFuncPtrInfo(const char* funcptr_id); protected: - const ABI& guest_abi; + const ABI& guest_abi; }; diff --git a/ThunkLibs/Generator/diagnostics.h b/ThunkLibs/Generator/diagnostics.h index 20d26d09b..d3dce1169 100644 --- a/ThunkLibs/Generator/diagnostics.h +++ b/ThunkLibs/Generator/diagnostics.h @@ -8,53 +8,52 @@ #include struct ClangDiagnosticAsException { - std::pair diagnostic; + std::pair diagnostic; - std::vector notes; + std::vector notes; - // List of callbacks that add an argument to a clang::DiagnosticBuilder - std::vector> args; + // List of callbacks that add an argument to a clang::DiagnosticBuilder + std::vector> args; - ClangDiagnosticAsException& AddString(std::string str) { - args.push_back([arg=std::move(str)](clang::DiagnosticBuilder& db) { - db.AddString(arg); - }); - return *this; + ClangDiagnosticAsException& AddString(std::string str) { + args.push_back([arg = std::move(str)](clang::DiagnosticBuilder& db) { db.AddString(arg); }); + return *this; + } + + ClangDiagnosticAsException& AddTaggedVal(clang::QualType type) { + args.push_back([val = type](clang::DiagnosticBuilder& db) { + db.AddTaggedVal(reinterpret_cast(val.getAsOpaquePtr()), clang::DiagnosticsEngine::ak_qualtype); + }); + return *this; + } + + ClangDiagnosticAsException& addNote(ClangDiagnosticAsException diagnostic) { + notes.push_back(std::move(diagnostic)); + return *this; + } + + void Report(clang::DiagnosticsEngine& diagnostics) const { + { + auto builder = diagnostics.Report(diagnostic.first, diagnostic.second); + for (auto& arg_appender : args) { + arg_appender(builder); + } } - - ClangDiagnosticAsException& AddTaggedVal(clang::QualType type) { - args.push_back([val=type](clang::DiagnosticBuilder& db) { - db.AddTaggedVal(reinterpret_cast(val.getAsOpaquePtr()), clang::DiagnosticsEngine::ak_qualtype); - }); - return *this; - } - - ClangDiagnosticAsException& addNote(ClangDiagnosticAsException diagnostic) { - notes.push_back(std::move(diagnostic)); - return *this; - } - - void Report(clang::DiagnosticsEngine& diagnostics) const { - { - auto builder = diagnostics.Report(diagnostic.first, diagnostic.second); - for (auto& arg_appender : args) { - arg_appender(builder); - } - } - for (auto& note : notes) { - note.Report(diagnostics); - } + for (auto& note : notes) { + note.Report(diagnostics); } + } }; // Helper class to build a custom DiagID from the given message and store it in a throwable object struct ErrorReporter { - clang::ASTContext& context; + clang::ASTContext& context; - template - [[nodiscard]] ClangDiagnosticAsException operator()(clang::SourceLocation loc, const char (&message)[N], - clang::DiagnosticsEngine::Level level = clang::DiagnosticsEngine::Error) { - auto id = context.getDiagnostics().getCustomDiagID(level, message); - return { std::pair(loc, id) }; - } + template + [[nodiscard]] + ClangDiagnosticAsException + operator()(clang::SourceLocation loc, const char (&message)[N], clang::DiagnosticsEngine::Level level = clang::DiagnosticsEngine::Error) { + auto id = context.getDiagnostics().getCustomDiagID(level, message); + return {std::pair(loc, id)}; + } }; diff --git a/ThunkLibs/Generator/gen.cpp b/ThunkLibs/Generator/gen.cpp index c3246a165..ab76ac23e 100644 --- a/ThunkLibs/Generator/gen.cpp +++ b/ThunkLibs/Generator/gen.cpp @@ -18,38 +18,41 @@ class GenerateThunkLibsAction : public DataLayoutCompareAction { public: - GenerateThunkLibsAction(const std::string& libname, const OutputFilenames&, const ABI& abi); + GenerateThunkLibsAction(const std::string& libname, const OutputFilenames&, const ABI& abi); private: - // Generate helper code for thunk libraries and write them to the output file - void OnAnalysisComplete(clang::ASTContext&) override; + // Generate helper code for thunk libraries and write them to the output file + void OnAnalysisComplete(clang::ASTContext&) override; - // Emit guest_layout/host_layout wrappers for types passed across architecture boundaries - void EmitLayoutWrappers(clang::ASTContext&, std::ofstream&, std::unordered_map& type_compat); + // Emit guest_layout/host_layout wrappers for types passed across architecture boundaries + void EmitLayoutWrappers(clang::ASTContext&, std::ofstream&, std::unordered_map& type_compat); - const std::string& libfilename; - std::string libname; // sanitized filename, usable as part of emitted function names - const OutputFilenames& output_filenames; + const std::string& libfilename; + std::string libname; // sanitized filename, usable as part of emitted function names + const OutputFilenames& output_filenames; }; GenerateThunkLibsAction::GenerateThunkLibsAction(const std::string& libname_, const OutputFilenames& output_filenames_, const ABI& abi) - : DataLayoutCompareAction(abi), libfilename(libname_), libname(libname_), output_filenames(output_filenames_) { - for (auto& c : libname) { - if (c == '-') { - c = '_'; - } + : DataLayoutCompareAction(abi) + , libfilename(libname_) + , libname(libname_) + , output_filenames(output_filenames_) { + for (auto& c : libname) { + if (c == '-') { + c = '_'; } + } } template static std::string format_function_args(const FunctionParams& params, Fn&& format_arg) { - std::string ret; - for (std::size_t idx = 0; idx < params.param_types.size(); ++idx) { - ret += std::forward(format_arg)(idx) + ", "; - } - // drop trailing ", " - ret.resize(ret.size() > 2 ? ret.size() - 2 : 0); - return ret; + std::string ret; + for (std::size_t idx = 0; idx < params.param_types.size(); ++idx) { + ret += std::forward(format_arg)(idx) + ", "; + } + // drop trailing ", " + ret.resize(ret.size() > 2 ? ret.size() - 2 : 0); + return ret; }; // Custom sort algorithm that works with partial orders. @@ -62,737 +65,739 @@ static std::string format_function_args(const FunctionParams& params, Fn&& forma // order of A and B undetermined. In effect when iterating over the sorted // range, each dependency is visited before any of its dependees. template -void BubbleSort(It begin, It end, - std::relation, std::iter_value_t> auto compare) { - bool fixpoint; - do { - fixpoint = true; - for (auto it = begin; it != end; ++it) { - for (auto it2 = std::next(it); it2 != end; ++it2) { - if (compare(*it2, *it)) { - std::swap(*it, *it2); - fixpoint = false; - it2 = it; - } - } +void BubbleSort(It begin, It end, std::relation, std::iter_value_t> auto compare) { + bool fixpoint; + do { + fixpoint = true; + for (auto it = begin; it != end; ++it) { + for (auto it2 = std::next(it); it2 != end; ++it2) { + if (compare(*it2, *it)) { + std::swap(*it, *it2); + fixpoint = false; + it2 = it; } - } while (!fixpoint); + } + } + } while (!fixpoint); } // Compares such that A < B if B contains A as a member and requires A to be completely defined (i.e. non-pointer/non-reference). // This applies recursively to structs contained by B. struct compare_by_struct_dependency { - clang::ASTContext& context; + clang::ASTContext& context; - bool operator()(const std::pair& a, - const std::pair& b) const { - return (*this)(a.first, b.first); + bool operator()(const std::pair& a, + const std::pair& b) const { + return (*this)(a.first, b.first); + } + + bool operator()(const clang::Type* a, const clang::Type* b) const { + if (llvm::isa(b)) { + throw std::runtime_error("Cannot have \"b\" be an array"); } - bool operator()(const clang::Type* a, const clang::Type* b) const { - if (llvm::isa(b)) { - throw std::runtime_error("Cannot have \"b\" be an array"); - } - - auto* b_as_struct = b->getAsStructureType(); - if (!b_as_struct) { - // Not a struct => no dependency - return false; - } - - if (a->isArrayType()) { - throw std::runtime_error("Cannot have \"a\" be an array"); - } - - for (auto* child : b_as_struct->getDecl()->fields()) { - auto child_type = child->getType().getTypePtr(); - - if (child_type->isPointerType()) { - // Pointers don't need the definition to be available - continue; - } - - // Peel off any array type layers from the member - while (auto child_as_array = llvm::dyn_cast(child_type)) { - child_type = child_as_array->getArrayElementTypeNoTypeQual(); - } - - if (context.hasSameType(a, child_type)) { - return true; - } - - if ((*this)(a, child_type)) { - // Child depends on A => transitive dependency - return true; - } - } - - // No dependency found - return false; + auto* b_as_struct = b->getAsStructureType(); + if (!b_as_struct) { + // Not a struct => no dependency + return false; } + + if (a->isArrayType()) { + throw std::runtime_error("Cannot have \"a\" be an array"); + } + + for (auto* child : b_as_struct->getDecl()->fields()) { + auto child_type = child->getType().getTypePtr(); + + if (child_type->isPointerType()) { + // Pointers don't need the definition to be available + continue; + } + + // Peel off any array type layers from the member + while (auto child_as_array = llvm::dyn_cast(child_type)) { + child_type = child_as_array->getArrayElementTypeNoTypeQual(); + } + + if (context.hasSameType(a, child_type)) { + return true; + } + + if ((*this)(a, child_type)) { + // Child depends on A => transitive dependency + return true; + } + } + + // No dependency found + return false; + } }; -void GenerateThunkLibsAction::EmitLayoutWrappers( - clang::ASTContext& context, std::ofstream& file, - std::unordered_map& type_compat) { - // Sort struct types by dependency so that repacking code is emitted in an order that compiles fine - std::vector> types { this->types.begin(), this->types.end() }; - BubbleSort(types.begin(), types.end(), compare_by_struct_dependency { context }); +void GenerateThunkLibsAction::EmitLayoutWrappers(clang::ASTContext& context, std::ofstream& file, + std::unordered_map& type_compat) { + // Sort struct types by dependency so that repacking code is emitted in an order that compiles fine + std::vector> types {this->types.begin(), this->types.end()}; + BubbleSort(types.begin(), types.end(), compare_by_struct_dependency {context}); - for (const auto& [type, type_repack_info] : types) { - auto struct_name = get_type_name(context, type); + for (const auto& [type, type_repack_info] : types) { + auto struct_name = get_type_name(context, type); - // Opaque types don't need layout definitions - if (type_repack_info.assumed_compatible && type_repack_info.pointers_only) { - if (guest_abi.pointer_size != 4) { - fmt::print(file, "template<> inline constexpr bool has_compatible_data_layout<{}*> = true;\n", struct_name); - } - continue; - } else if (type_repack_info.assumed_compatible) { - // TODO: Handle more cleanly - type_compat[type] = TypeCompatibility::Full; - } - - // These must be handled later since they are not canonicalized and hence must be de-duplicated first - if (type->isBuiltinType()) { - continue; - } - - // TODO: Instead, map these names back to *some* type that's named? - if (struct_name.starts_with("unnamed_")) { - continue; - } - - if (type->isEnumeralType()) { - fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name); - fmt::print(file, " using type = {}int{}_t;\n", - type->isUnsignedIntegerOrEnumerationType() ? "u" : "", - guest_abi.at(struct_name).get_if_simple_or_struct()->size_bits); - fmt::print(file, " type data;\n"); - fmt::print(file, "}};\n"); - continue; - } - - if (type_compat.at(type) == TypeCompatibility::None && !type_repack_info.emit_layout_wrappers) { - // Disallow use of layout wrappers for this type by specializing without a definition - fmt::print(file, "template<>\nstruct guest_layout<{}>;\n", struct_name); - fmt::print(file, "template<>\nstruct host_layout<{}>;\n", struct_name); - fmt::print(file, "guest_layout<{}>& to_guest(const host_layout<{}>&) = delete;\n", struct_name, struct_name); - continue; - } - - // Guest layout definition - // NOTE: uint64_t has lower alignment requirements on 32-bit than on 64-bit, so we require tightly packed structs - // TODO: Now we must emit padding bytes explicitly, though! - fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name); - if (type_compat.at(type) == TypeCompatibility::Full) { - fmt::print(file, " using type = {};\n", struct_name); - } else { - fmt::print(file, " struct type {{\n"); - for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) { - fmt::print( file, " guest_layout<{}{}> {};\n", - member.type_name, - member.array_size ? fmt::format("[{}]", member.array_size.value()) : "", - member.member_name); - } - fmt::print(file, " }};\n"); - } - fmt::print(file, " type data;\n"); - fmt::print(file, "}};\n"); - - fmt::print(file, "template<>\nstruct guest_layout : guest_layout<{}> {{\n", struct_name, struct_name); - fmt::print(file, " guest_layout& operator=(const guest_layout<{}>& other) {{ memcpy(this, &other, sizeof(other)); return *this; }}\n", struct_name); - fmt::print(file, "}};\n"); - - // Host layout definition - fmt::print(file, "template<>\n"); - fmt::print(file, "struct host_layout<{}> {{\n", struct_name); - fmt::print(file, " using type = {};\n", struct_name); - fmt::print(file, " type data;\n"); - fmt::print(file, "\n"); - // Host->guest layout conversion - fmt::print(file, " host_layout(const guest_layout<{}>& from) :\n", struct_name); - if (type_compat.at(type) == TypeCompatibility::Full) { - fmt::print(file, " data {{ from.data }} {{\n"); - } else { - // Conversion needs struct repacking. - // Wrapping each member in `host_layout<>` ensures this is done recursively. - fmt::print(file, " data {{\n"); - auto map_field = [&file](clang::FieldDecl* member, bool skip_arrays) { - auto decl_name = member->getNameAsString(); - auto type_name = member->getType().getAsString(); - auto array_type = llvm::dyn_cast(member->getType()); - if (!array_type && skip_arrays) { - if (member->getType()->isFunctionPointerType()) { - // Function pointers must be handled manually, so zero them out by default - fmt::print(file, " .{} {{ }},\n", decl_name); - } else { - fmt::print(file, " .{} = host_layout<{}> {{ from.data.{} }}.data,\n", decl_name, type_name, decl_name); - } - } else if (array_type && !skip_arrays) { - // Copy element-wise below - fmt::print(file, " for (size_t i = 0; i < {}; ++i) {{\n", array_type->getSize().getZExtValue()); - fmt::print(file, " data.{}[i] = host_layout<{}> {{ from.data.{} }}.data[i];\n", decl_name, type_name, decl_name); - fmt::print(file, " }}\n"); - } - }; - // Prefer initialization via the constructor's initializer list if possible (to detect unintended narrowing), otherwise initialize in the body - for (auto* member : type->getAsStructureType()->getDecl()->fields()) { - if (!type_repack_info.UsesCustomRepackFor(member)) { - map_field(member, true); - } else { - // Leave field uninitialized - } - } - fmt::print(file, " }} {{\n"); - for (auto* member : type->getAsStructureType()->getDecl()->fields()) { - if (!type_repack_info.UsesCustomRepackFor(member)) { - map_field(member, false); - } else { - // Leave field uninitialized - } - } - } - fmt::print(file, " }}\n"); - fmt::print(file, "}};\n\n"); - - // Guest->host layout conversion - fmt::print(file, "inline guest_layout<{}> to_guest(const host_layout<{}>& from) {{\n", struct_name, struct_name); - if (type_compat.at(type) == TypeCompatibility::Full) { - fmt::print(file, " guest_layout<{}> ret;\n", struct_name); - fmt::print(file, " static_assert(sizeof(from) == sizeof(ret));\n"); - fmt::print(file, " memcpy(&ret, &from, sizeof(from));\n"); - } else { - // Conversion needs struct repacking. - // Wrapping each member in `to_guest(to_host_layout(...))` ensures this is done recursively. - fmt::print(file, " guest_layout<{}> ret {{ .data {{\n", struct_name); - auto map_field2 = [&file](const StructInfo::MemberInfo& member, bool skip_arrays) { - auto& decl_name = member.member_name; - auto& array_size = member.array_size; - if (!array_size && skip_arrays) { - if (member.is_function_pointer) { - // Function pointers must be handled manually, so zero them out by default - fmt::print(file, " .{} {{ }},\n", decl_name); - } else { - fmt::print(file, " .{} = to_guest(to_host_layout(from.data.{})),\n", decl_name, decl_name); - } - } else if (array_size && !skip_arrays) { - // Copy element-wise below - fmt::print(file, " for (size_t i = 0; i < {}; ++i) {{\n", array_size.value()); - fmt::print(file, " ret.data.{}.data[i] = to_guest(to_host_layout(from.data.{}[i]));\n", decl_name, decl_name); - fmt::print(file, " }}\n"); - } - }; - - // Prefer initialization via the constructor's initializer list if possible (to detect unintended narrowing), otherwise initialize in the body - for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) { - if (!type_repack_info.UsesCustomRepackFor(member.member_name)) { - map_field2(member, true); - } else { - // Leave field uninitialized - } - } - fmt::print(file, " }} }};\n"); - for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) { - if (!type_repack_info.UsesCustomRepackFor(member.member_name)) { - map_field2(member, false); - } else { - // Leave field uninitialized - } - } - } - fmt::print(file, " return ret;\n"); - fmt::print(file, "}}\n\n"); - - // Forward-declare user-provided repacking functions - if (type_repack_info.custom_repacked_members.empty()) { - fmt::print(file, "void fex_apply_custom_repacking_entry(host_layout<{}>& source, const guest_layout<{}>& from) {{\n", struct_name, struct_name); - fmt::print(file, "}}\n"); - fmt::print(file, "bool fex_apply_custom_repacking_exit(guest_layout<{}>& into, host_layout<{}>& from) {{\n", struct_name, struct_name); - fmt::print(file, " return false;\n"); - fmt::print(file, "}}\n"); - } else { - fmt::print(file, "void fex_custom_repack_entry(host_layout<{}>& into, const guest_layout<{}>& from);\n", - struct_name, struct_name); - fmt::print(file, "bool fex_custom_repack_exit(guest_layout<{}>& into, const host_layout<{}>& from);\n\n", - struct_name, struct_name); - - fmt::print(file, "void fex_apply_custom_repacking_entry(host_layout<{}>& source, const guest_layout<{}>& from) {{\n", struct_name, struct_name); - fmt::print(file, " fex_custom_repack_entry(source, from);\n"); - fmt::print(file, "}}\n"); - - fmt::print(file, "bool fex_apply_custom_repacking_exit(guest_layout<{}>& into, host_layout<{}>& from) {{\n", struct_name, struct_name); - fmt::print(file, " return fex_custom_repack_exit(into, from);\n"); - fmt::print(file, "}}\n"); - } - - fmt::print(file, "template<> inline constexpr bool has_compatible_data_layout<{}> = {};\n", - struct_name, (type_compat.at(type) == TypeCompatibility::Full)); + // Opaque types don't need layout definitions + if (type_repack_info.assumed_compatible && type_repack_info.pointers_only) { + if (guest_abi.pointer_size != 4) { + fmt::print(file, "template<> inline constexpr bool has_compatible_data_layout<{}*> = true;\n", struct_name); + } + continue; + } else if (type_repack_info.assumed_compatible) { + // TODO: Handle more cleanly + type_compat[type] = TypeCompatibility::Full; } + + // These must be handled later since they are not canonicalized and hence must be de-duplicated first + if (type->isBuiltinType()) { + continue; + } + + // TODO: Instead, map these names back to *some* type that's named? + if (struct_name.starts_with("unnamed_")) { + continue; + } + + if (type->isEnumeralType()) { + fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name); + fmt::print(file, " using type = {}int{}_t;\n", type->isUnsignedIntegerOrEnumerationType() ? "u" : "", + guest_abi.at(struct_name).get_if_simple_or_struct()->size_bits); + fmt::print(file, " type data;\n"); + fmt::print(file, "}};\n"); + continue; + } + + if (type_compat.at(type) == TypeCompatibility::None && !type_repack_info.emit_layout_wrappers) { + // Disallow use of layout wrappers for this type by specializing without a definition + fmt::print(file, "template<>\nstruct guest_layout<{}>;\n", struct_name); + fmt::print(file, "template<>\nstruct host_layout<{}>;\n", struct_name); + fmt::print(file, "guest_layout<{}>& to_guest(const host_layout<{}>&) = delete;\n", struct_name, struct_name); + continue; + } + + // Guest layout definition + // NOTE: uint64_t has lower alignment requirements on 32-bit than on 64-bit, so we require tightly packed structs + // TODO: Now we must emit padding bytes explicitly, though! + fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name); + if (type_compat.at(type) == TypeCompatibility::Full) { + fmt::print(file, " using type = {};\n", struct_name); + } else { + fmt::print(file, " struct type {{\n"); + for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) { + fmt::print(file, " guest_layout<{}{}> {};\n", member.type_name, + member.array_size ? fmt::format("[{}]", member.array_size.value()) : "", member.member_name); + } + fmt::print(file, " }};\n"); + } + fmt::print(file, " type data;\n"); + fmt::print(file, "}};\n"); + + fmt::print(file, "template<>\nstruct guest_layout : guest_layout<{}> {{\n", struct_name, struct_name); + fmt::print(file, " guest_layout& operator=(const guest_layout<{}>& other) {{ memcpy(this, &other, sizeof(other)); return *this; }}\n", + struct_name); + fmt::print(file, "}};\n"); + + // Host layout definition + fmt::print(file, "template<>\n"); + fmt::print(file, "struct host_layout<{}> {{\n", struct_name); + fmt::print(file, " using type = {};\n", struct_name); + fmt::print(file, " type data;\n"); + fmt::print(file, "\n"); + // Host->guest layout conversion + fmt::print(file, " host_layout(const guest_layout<{}>& from) :\n", struct_name); + if (type_compat.at(type) == TypeCompatibility::Full) { + fmt::print(file, " data {{ from.data }} {{\n"); + } else { + // Conversion needs struct repacking. + // Wrapping each member in `host_layout<>` ensures this is done recursively. + fmt::print(file, " data {{\n"); + auto map_field = [&file](clang::FieldDecl* member, bool skip_arrays) { + auto decl_name = member->getNameAsString(); + auto type_name = member->getType().getAsString(); + auto array_type = llvm::dyn_cast(member->getType()); + if (!array_type && skip_arrays) { + if (member->getType()->isFunctionPointerType()) { + // Function pointers must be handled manually, so zero them out by default + fmt::print(file, " .{} {{ }},\n", decl_name); + } else { + fmt::print(file, " .{} = host_layout<{}> {{ from.data.{} }}.data,\n", decl_name, type_name, decl_name); + } + } else if (array_type && !skip_arrays) { + // Copy element-wise below + fmt::print(file, " for (size_t i = 0; i < {}; ++i) {{\n", array_type->getSize().getZExtValue()); + fmt::print(file, " data.{}[i] = host_layout<{}> {{ from.data.{} }}.data[i];\n", decl_name, type_name, decl_name); + fmt::print(file, " }}\n"); + } + }; + // Prefer initialization via the constructor's initializer list if possible (to detect unintended narrowing), otherwise initialize in the body + for (auto* member : type->getAsStructureType()->getDecl()->fields()) { + if (!type_repack_info.UsesCustomRepackFor(member)) { + map_field(member, true); + } else { + // Leave field uninitialized + } + } + fmt::print(file, " }} {{\n"); + for (auto* member : type->getAsStructureType()->getDecl()->fields()) { + if (!type_repack_info.UsesCustomRepackFor(member)) { + map_field(member, false); + } else { + // Leave field uninitialized + } + } + } + fmt::print(file, " }}\n"); + fmt::print(file, "}};\n\n"); + + // Guest->host layout conversion + fmt::print(file, "inline guest_layout<{}> to_guest(const host_layout<{}>& from) {{\n", struct_name, struct_name); + if (type_compat.at(type) == TypeCompatibility::Full) { + fmt::print(file, " guest_layout<{}> ret;\n", struct_name); + fmt::print(file, " static_assert(sizeof(from) == sizeof(ret));\n"); + fmt::print(file, " memcpy(&ret, &from, sizeof(from));\n"); + } else { + // Conversion needs struct repacking. + // Wrapping each member in `to_guest(to_host_layout(...))` ensures this is done recursively. + fmt::print(file, " guest_layout<{}> ret {{ .data {{\n", struct_name); + auto map_field2 = [&file](const StructInfo::MemberInfo& member, bool skip_arrays) { + auto& decl_name = member.member_name; + auto& array_size = member.array_size; + if (!array_size && skip_arrays) { + if (member.is_function_pointer) { + // Function pointers must be handled manually, so zero them out by default + fmt::print(file, " .{} {{ }},\n", decl_name); + } else { + fmt::print(file, " .{} = to_guest(to_host_layout(from.data.{})),\n", decl_name, decl_name); + } + } else if (array_size && !skip_arrays) { + // Copy element-wise below + fmt::print(file, " for (size_t i = 0; i < {}; ++i) {{\n", array_size.value()); + fmt::print(file, " ret.data.{}.data[i] = to_guest(to_host_layout(from.data.{}[i]));\n", decl_name, decl_name); + fmt::print(file, " }}\n"); + } + }; + + // Prefer initialization via the constructor's initializer list if possible (to detect unintended narrowing), otherwise initialize in the body + for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) { + if (!type_repack_info.UsesCustomRepackFor(member.member_name)) { + map_field2(member, true); + } else { + // Leave field uninitialized + } + } + fmt::print(file, " }} }};\n"); + for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) { + if (!type_repack_info.UsesCustomRepackFor(member.member_name)) { + map_field2(member, false); + } else { + // Leave field uninitialized + } + } + } + fmt::print(file, " return ret;\n"); + fmt::print(file, "}}\n\n"); + + // Forward-declare user-provided repacking functions + if (type_repack_info.custom_repacked_members.empty()) { + fmt::print(file, "void fex_apply_custom_repacking_entry(host_layout<{}>& source, const guest_layout<{}>& from) {{\n", struct_name, struct_name); + fmt::print(file, "}}\n"); + fmt::print(file, "bool fex_apply_custom_repacking_exit(guest_layout<{}>& into, host_layout<{}>& from) {{\n", struct_name, struct_name); + fmt::print(file, " return false;\n"); + fmt::print(file, "}}\n"); + } else { + fmt::print(file, "void fex_custom_repack_entry(host_layout<{}>& into, const guest_layout<{}>& from);\n", struct_name, struct_name); + fmt::print(file, "bool fex_custom_repack_exit(guest_layout<{}>& into, const host_layout<{}>& from);\n\n", struct_name, struct_name); + + fmt::print(file, "void fex_apply_custom_repacking_entry(host_layout<{}>& source, const guest_layout<{}>& from) {{\n", struct_name, struct_name); + fmt::print(file, " fex_custom_repack_entry(source, from);\n"); + fmt::print(file, "}}\n"); + + fmt::print(file, "bool fex_apply_custom_repacking_exit(guest_layout<{}>& into, host_layout<{}>& from) {{\n", struct_name, struct_name); + fmt::print(file, " return fex_custom_repack_exit(into, from);\n"); + fmt::print(file, "}}\n"); + } + + fmt::print(file, "template<> inline constexpr bool has_compatible_data_layout<{}> = {};\n", struct_name, + (type_compat.at(type) == TypeCompatibility::Full)); + } } void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) { - ErrorReporter report_error { context }; + ErrorReporter report_error {context}; - // Compute data layout differences between host and guest - auto type_compat = [&]() { - std::unordered_map ret; - const auto host_abi = ComputeDataLayout(context, types); - for (const auto& [type, type_repack_info] : types) { - if (!type_repack_info.pointers_only) { - GetTypeCompatibility(context, type, host_abi, ret); - } + // Compute data layout differences between host and guest + auto type_compat = [&]() { + std::unordered_map ret; + const auto host_abi = ComputeDataLayout(context, types); + for (const auto& [type, type_repack_info] : types) { + if (!type_repack_info.pointers_only) { + GetTypeCompatibility(context, type, host_abi, ret); + } + } + return ret; + }(); + + static auto format_decl = [](clang::QualType type, const std::string_view& name) { + clang::QualType innermostPointee = type; + while (innermostPointee->isPointerType()) { + innermostPointee = innermostPointee->getPointeeType(); + } + if (innermostPointee->isFunctionType()) { + // Function pointer declarations (e.g. void (**callback)()) require + // the variable name to be prefixed *and* suffixed. + + auto signature = type.getAsString(); + + // Search for strings like (*), (**), or (*****). Insert the + // variable name before the closing parenthesis + auto needle = signature.begin(); + for (; needle != signature.end(); ++needle) { + if (signature.end() - needle < 3 || std::string_view {&*needle, 2} != "(*") { + continue; } - return ret; - }(); - - static auto format_decl = [](clang::QualType type, const std::string_view& name) { - clang::QualType innermostPointee = type; - while (innermostPointee->isPointerType()) { - innermostPointee = innermostPointee->getPointeeType(); + while (*++needle == '*') {} + if (*needle == ')') { + break; } - if (innermostPointee->isFunctionType()) { - // Function pointer declarations (e.g. void (**callback)()) require - // the variable name to be prefixed *and* suffixed. + } + if (needle == signature.end()) { + // It's *probably* a typedef, so this should be safe after all + return fmt::format("{} {}", signature, name); + } else { + signature.insert(needle, name.begin(), name.end()); + return signature; + } + } else { + return type.getAsString() + " " + std::string(name); + } + }; - auto signature = type.getAsString(); + auto format_function_params = [](const FunctionParams& params) { + std::string ret; + for (std::size_t idx = 0; idx < params.param_types.size(); ++idx) { + auto& type = params.param_types[idx]; + ret += format_decl(type, fmt::format("a_{}", idx)) + ", "; + } + // drop trailing ", " + ret.resize(ret.size() > 2 ? ret.size() - 2 : 0); + return ret; + }; - // Search for strings like (*), (**), or (*****). Insert the - // variable name before the closing parenthesis - auto needle = signature.begin(); - for (; needle != signature.end(); ++needle) { - if (signature.end() - needle < 3 || - std::string_view { &*needle, 2 } != "(*") { - continue; - } - while (*++needle == '*') { - } - if (*needle == ')') { - break; - } - } - if (needle == signature.end()) { - // It's *probably* a typedef, so this should be safe after all - return fmt::format("{} {}", signature, name); - } else { - signature.insert(needle, name.begin(), name.end()); - return signature; - } + auto get_sha256 = [this](const std::string& function_name, bool include_libname) { + std::string sha256_message = (include_libname ? libname + ":" : "") + function_name; + std::vector sha256(SHA256_DIGEST_LENGTH); + SHA256(reinterpret_cast(sha256_message.data()), sha256_message.size(), sha256.data()); + return sha256; + }; + + auto get_callback_name = [](std::string_view function_name, unsigned param_index) -> std::string { + return fmt::format("{}CBFN{}", function_name, param_index); + }; + + // Files used guest-side + if (!output_filenames.guest.empty()) { + std::ofstream file(output_filenames.guest); + + // Guest->Host transition points for API functions + file << "extern \"C\" {\n"; + for (auto& thunk : thunks) { + const auto& function_name = thunk.function_name; + auto sha256 = get_sha256(function_name, true); + fmt::print(file, "MAKE_THUNK({}, {}, \"{:#02x}\")\n", libname, function_name, fmt::join(sha256, ", ")); + } + file << "}\n"; + + // Guest->Host transition points for invoking runtime host-function pointers based on their signature + std::vector> sha256s; + for (auto type_it = thunked_funcptrs.begin(); type_it != thunked_funcptrs.end(); ++type_it) { + auto* type = type_it->second.first; + std::string funcptr_signature = clang::QualType {type, 0}.getAsString(); + + auto cb_sha256 = get_sha256("fexcallback_" + funcptr_signature, false); + auto it = std::find(sha256s.begin(), sha256s.end(), cb_sha256); + if (it != sha256s.end()) { + // TODO: Avoid this ugly way of avoiding duplicates + continue; + } else { + sha256s.push_back(cb_sha256); + } + + // Thunk used for guest-side calls to host function pointers + file << " // " << funcptr_signature << "\n"; + auto funcptr_idx = std::distance(thunked_funcptrs.begin(), type_it); + fmt::print(file, " MAKE_CALLBACK_THUNK(callback_{}, {}, \"{:#02x}\");\n", funcptr_idx, funcptr_signature, fmt::join(cb_sha256, ", ")); + } + + // Thunks-internal packing functions + file << "extern \"C\" {\n"; + for (auto& data : thunks) { + const auto& function_name = data.function_name; + bool is_void = data.return_type->isVoidType(); + file << "FEX_PACKFN_LINKAGE auto fexfn_pack_" << function_name << "("; + for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { + auto& type = data.param_types[idx]; + file << (idx == 0 ? "" : ", ") << format_decl(type, fmt::format("a_{}", idx)); + } + // Using trailing return type as it makes handling function pointer returns much easier + file << ") -> " << data.return_type.getAsString() << " {\n"; + file << " struct __attribute__((packed)) {\n"; + for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { + auto& type = data.param_types[idx]; + file << " " << format_decl(type.getUnqualifiedType(), fmt::format("a_{}", idx)) << ";\n"; + } + if (!is_void) { + file << " " << format_decl(data.return_type, "rv") << ";\n"; + } else if (data.param_types.size() == 0) { + // Avoid "empty struct has size 0 in C, size 1 in C++" warning + file << " char force_nonempty;\n"; + } + file << " } args;\n"; + + for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { + auto cb = data.callbacks.find(idx); + + file << " args.a_" << idx << " = "; + if (cb == data.callbacks.end() || cb->second.is_stub) { + file << "a_" << idx << ";\n"; } else { - return type.getAsString() + " " + std::string(name); + // Before passing guest function pointers to the host, wrap them in a host-callable trampoline + fmt::print(file, "AllocateHostTrampolineForGuestFunction(a_{});\n", idx); } - }; + } + file << " fexthunks_" << libname << "_" << function_name << "(&args);\n"; + if (!is_void) { + file << " return args.rv;\n"; + } + file << "}\n"; + } + file << "}\n"; - auto format_function_params = [](const FunctionParams& params) { - std::string ret; - for (std::size_t idx = 0; idx < params.param_types.size(); ++idx) { - auto& type = params.param_types[idx]; - ret += format_decl(type, fmt::format("a_{}", idx)) + ", "; + // Publicly exports equivalent to symbols exported from the native guest library + file << "extern \"C\" {\n"; + for (auto& data : thunked_api) { + if (data.custom_guest_impl) { + continue; + } + + const auto& function_name = data.function_name; + + file << "__attribute__((alias(\"fexfn_pack_" << function_name << "\"))) auto " << function_name << "("; + for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { + auto& type = data.param_types[idx]; + file << (idx == 0 ? "" : ", ") << format_decl(type, "a_" + std::to_string(idx)); + } + file << ") -> " << data.return_type.getAsString() << ";\n"; + } + file << "}\n"; + + // Symbol enumerators + for (std::size_t namespace_idx = 0; namespace_idx < namespaces.size(); ++namespace_idx) { + const auto& ns = namespaces[namespace_idx]; + file << "#define FOREACH_" << ns.name << (ns.name.empty() ? "" : "_") << "SYMBOL(EXPAND) \\\n"; + for (auto& symbol : thunked_api) { + if (symbol.symtable_namespace.value_or(0) == namespace_idx) { + file << " EXPAND(" << symbol.function_name << ", \"TODO\") \\\n"; } - // drop trailing ", " - ret.resize(ret.size() > 2 ? ret.size() - 2 : 0); - return ret; - }; + } + file << "\n"; + } + } - auto get_sha256 = [this](const std::string& function_name, bool include_libname) { - std::string sha256_message = (include_libname ? libname + ":" : "") + function_name; - std::vector sha256(SHA256_DIGEST_LENGTH); - SHA256(reinterpret_cast(sha256_message.data()), - sha256_message.size(), - sha256.data()); - return sha256; - }; + // Files used host-side + if (!output_filenames.host.empty()) { + std::ofstream file(output_filenames.host); - auto get_callback_name = [](std::string_view function_name, unsigned param_index) -> std::string { - return fmt::format("{}CBFN{}", function_name, param_index); - }; + EmitLayoutWrappers(context, file, type_compat); - // Files used guest-side - if (!output_filenames.guest.empty()) { - std::ofstream file(output_filenames.guest); - - // Guest->Host transition points for API functions - file << "extern \"C\" {\n"; - for (auto& thunk : thunks) { - const auto& function_name = thunk.function_name; - auto sha256 = get_sha256(function_name, true); - fmt::print( file, "MAKE_THUNK({}, {}, \"{:#02x}\")\n", - libname, function_name, fmt::join(sha256, ", ")); - } - file << "}\n"; - - // Guest->Host transition points for invoking runtime host-function pointers based on their signature - std::vector> sha256s; - for (auto type_it = thunked_funcptrs.begin(); type_it != thunked_funcptrs.end(); ++type_it) { - auto* type = type_it->second.first; - std::string funcptr_signature = clang::QualType { type, 0 }.getAsString(); - - auto cb_sha256 = get_sha256("fexcallback_" + funcptr_signature, false); - auto it = std::find(sha256s.begin(), sha256s.end(), cb_sha256); - if (it != sha256s.end()) { - // TODO: Avoid this ugly way of avoiding duplicates - continue; - } else { - sha256s.push_back(cb_sha256); - } - - // Thunk used for guest-side calls to host function pointers - file << " // " << funcptr_signature << "\n"; - auto funcptr_idx = std::distance(thunked_funcptrs.begin(), type_it); - fmt::print( file, " MAKE_CALLBACK_THUNK(callback_{}, {}, \"{:#02x}\");\n", - funcptr_idx, funcptr_signature, fmt::join(cb_sha256, ", ")); - } - - // Thunks-internal packing functions - file << "extern \"C\" {\n"; - for (auto& data : thunks) { - const auto& function_name = data.function_name; - bool is_void = data.return_type->isVoidType(); - file << "FEX_PACKFN_LINKAGE auto fexfn_pack_" << function_name << "("; - for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { - auto& type = data.param_types[idx]; - file << (idx == 0 ? "" : ", ") << format_decl(type, fmt::format("a_{}", idx)); - } - // Using trailing return type as it makes handling function pointer returns much easier - file << ") -> " << data.return_type.getAsString() << " {\n"; - file << " struct __attribute__((packed)) {\n"; - for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { - auto& type = data.param_types[idx]; - file << " " << format_decl(type.getUnqualifiedType(), fmt::format("a_{}", idx)) << ";\n"; - } - if (!is_void) { - file << " " << format_decl(data.return_type, "rv") << ";\n"; - } else if (data.param_types.size() == 0) { - // Avoid "empty struct has size 0 in C, size 1 in C++" warning - file << " char force_nonempty;\n"; - } - file << " } args;\n"; - - for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { - auto cb = data.callbacks.find(idx); - - file << " args.a_" << idx << " = "; - if (cb == data.callbacks.end() || cb->second.is_stub) { - file << "a_" << idx << ";\n"; - } else { - // Before passing guest function pointers to the host, wrap them in a host-callable trampoline - fmt::print(file, "AllocateHostTrampolineForGuestFunction(a_{});\n", idx); - } - } - file << " fexthunks_" << libname << "_" << function_name << "(&args);\n"; - if (!is_void) { - file << " return args.rv;\n"; - } - file << "}\n"; - } - file << "}\n"; - - // Publicly exports equivalent to symbols exported from the native guest library - file << "extern \"C\" {\n"; - for (auto& data : thunked_api) { - if (data.custom_guest_impl) { - continue; - } - - const auto& function_name = data.function_name; - - file << "__attribute__((alias(\"fexfn_pack_" << function_name << "\"))) auto " << function_name << "("; - for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) { - auto& type = data.param_types[idx]; - file << (idx == 0 ? "" : ", ") << format_decl(type, "a_" + std::to_string(idx)); - } - file << ") -> " << data.return_type.getAsString() << ";\n"; - } - file << "}\n"; - - // Symbol enumerators - for (std::size_t namespace_idx = 0; namespace_idx < namespaces.size(); ++namespace_idx) { - const auto& ns = namespaces[namespace_idx]; - file << "#define FOREACH_" << ns.name << (ns.name.empty() ? "" : "_") << "SYMBOL(EXPAND) \\\n"; - for (auto& symbol : thunked_api) { - if (symbol.symtable_namespace.value_or(0) == namespace_idx) { - file << " EXPAND(" << symbol.function_name << ", \"TODO\") \\\n"; - } - } - file << "\n"; - } + // Forward declarations for symbols loaded from the native host library + for (auto& import : thunked_api) { + const auto& function_name = import.function_name; + const char* variadic_ellipsis = import.is_variadic ? ", ..." : ""; + file << "using fexldr_type_" << libname << "_" << function_name << " = auto " + << "(" << format_function_params(import) << variadic_ellipsis << ") -> " << import.return_type.getAsString() << ";\n"; + file << "static fexldr_type_" << libname << "_" << function_name << " *fexldr_ptr_" << libname << "_" << function_name << ";\n"; } - // Files used host-side - if (!output_filenames.host.empty()) { - std::ofstream file(output_filenames.host); + file << "extern \"C\" {\n"; + for (auto& thunk : thunks) { + const auto& function_name = thunk.function_name; - EmitLayoutWrappers(context, file, type_compat); - - // Forward declarations for symbols loaded from the native host library - for (auto& import : thunked_api) { - const auto& function_name = import.function_name; - const char* variadic_ellipsis = import.is_variadic ? ", ..." : ""; - file << "using fexldr_type_" << libname << "_" << function_name << " = auto " << "(" << format_function_params(import) << variadic_ellipsis << ") -> " << import.return_type.getAsString() << ";\n"; - file << "static fexldr_type_" << libname << "_" << function_name << " *fexldr_ptr_" << libname << "_" << function_name << ";\n"; + // Generate stub callbacks + for (auto& [cb_idx, cb] : thunk.callbacks) { + if (cb.is_stub) { + const char* variadic_ellipsis = cb.is_variadic ? ", ..." : ""; + auto cb_function_name = "fexfn_unpack_" + get_callback_name(function_name, cb_idx) + "_stub"; + file << "[[noreturn]] static " << cb.return_type.getAsString() << " " << cb_function_name << "(" << format_function_params(cb) + << variadic_ellipsis << ") {\n"; + file << " fprintf(stderr, \"FATAL: Attempted to invoke callback stub for " << function_name << "\\n\");\n"; + file << " std::abort();\n"; + file << "}\n"; } + } - file << "extern \"C\" {\n"; - for (auto& thunk : thunks) { - const auto& function_name = thunk.function_name; - - // Generate stub callbacks - for (auto& [cb_idx, cb] : thunk.callbacks) { - if (cb.is_stub) { - const char* variadic_ellipsis = cb.is_variadic ? ", ..." : ""; - auto cb_function_name = "fexfn_unpack_" + get_callback_name(function_name, cb_idx) + "_stub"; - file << "[[noreturn]] static " << cb.return_type.getAsString() << " " - << cb_function_name << "(" - << format_function_params(cb) << variadic_ellipsis << ") {\n"; - file << " fprintf(stderr, \"FATAL: Attempted to invoke callback stub for " << function_name << "\\n\");\n"; - file << " std::abort();\n"; - file << "}\n"; - } - } - - auto get_guest_type_name = [this](clang::QualType type) { - if (type->isBuiltinType() && type->isIntegerType()) { - auto size = guest_abi.at(type.getUnqualifiedType().getAsString()).get_if_simple_or_struct()->size_bits; - return get_fixed_size_int_name(type.getTypePtr(), size); - } else if (type->isPointerType() && type->getPointeeType()->isBuiltinType() && type->getPointeeType()->isIntegerType() && !type->getPointeeType()->isVoidType()) { - auto size = guest_abi.at(type->getPointeeType().getUnqualifiedType().getAsString()).get_if_simple_or_struct()->size_bits; - return fmt::format("{}{}*", type->getPointeeType().isConstQualified() ? "const " : "", get_fixed_size_int_name(type->getPointeeType().getTypePtr(), size)); - } else { - return type.getUnqualifiedType().getAsString(); - } - }; - - // Forward declarations for user-provided implementations - if (thunk.custom_host_impl) { - file << "static auto fexfn_impl_" << libname << "_" << function_name << "("; - for (std::size_t idx = 0; idx < thunk.param_types.size(); ++idx) { - auto& type = thunk.param_types[idx]; - - file << (idx == 0 ? "" : ", "); - - if (thunk.param_annotations[idx].is_passthrough) { - fmt::print(file, "guest_layout<{}> a_{}", get_guest_type_name(type), idx); - } else { - file << format_decl(type, fmt::format("a_{}", idx)); - } - } - // Using trailing return type as it makes handling function pointer returns much easier - file << ") -> " << thunk.return_type.getAsString() << ";\n"; - } - - // Check data layout compatibility of parameter types - // TODO: Also check non-struct/non-pointer types - // TODO: Also check return type - for (size_t param_idx = 0; param_idx != thunk.param_types.size(); ++param_idx) { - const auto& param_type = thunk.param_types[param_idx]; - if (!param_type->isPointerType() || !param_type->getPointeeType()->isStructureType()) { - continue; - } - if (!thunk.param_annotations[param_idx].is_passthrough) { - auto type = param_type->getPointeeType(); - if (!types.at(context.getCanonicalType(type.getTypePtr())).assumed_compatible && type_compat.at(context.getCanonicalType(type.getTypePtr())) == TypeCompatibility::None) { - // TODO: Factor in "assume_compatible_layout" annotations here - // That annotation should cause the type to be treated as TypeCompatibility::Full - throw report_error(thunk.decl->getLocation(), "Unsupported parameter type %0").AddTaggedVal(param_type); - } - } - } - - // Packed argument structs used in fexfn_unpack_* - auto GeneratePackedArgs = [&](const auto &function_name, const ThunkedFunction &thunk) -> std::string { - std::string struct_name = "fexfn_packed_args_" + libname + "_" + function_name; - file << "struct __attribute__((packed)) " << struct_name << " {\n"; - - for (std::size_t idx = 0; idx < thunk.param_types.size(); ++idx) { - fmt::print(file, " guest_layout<{}> a_{};\n", get_guest_type_name(thunk.param_types[idx]), idx); - } - if (!thunk.return_type->isVoidType()) { - fmt::print(file, " guest_layout<{}> rv;\n", get_guest_type_name(thunk.return_type)); - } else if (thunk.param_types.size() == 0) { - // Avoid "empty struct has size 0 in C, size 1 in C++" warning - file << " char force_nonempty;\n"; - } - file << "};\n"; - return struct_name; - }; - auto struct_name = GeneratePackedArgs(function_name, thunk); - - // Unpacking functions - auto function_to_call = "fexldr_ptr_" + libname + "_" + function_name; - if (thunk.custom_host_impl) { - function_to_call = "fexfn_impl_" + libname + "_" + function_name; - } - - auto get_type_name_with_nonconst_pointee = [&](clang::QualType type) { - type = type.getLocalUnqualifiedType(); - if (type->isPointerType()) { - // Strip away "const" from pointee type - type = context.getPointerType(type->getPointeeType().getLocalUnqualifiedType()); - } - return get_type_name(context, type.getTypePtr()); - }; - - - file << "static void fexfn_unpack_" << libname << "_" << function_name << "(" << struct_name << "* args) {\n"; - - for (unsigned param_idx = 0; param_idx != thunk.param_types.size(); ++param_idx) { - if (thunk.callbacks.contains(param_idx) && thunk.callbacks.at(param_idx).is_stub) { - continue; - } - - auto& param_type = thunk.param_types[param_idx]; - const bool is_assumed_compatible = param_type->isPointerType() && - (thunk.param_annotations[param_idx].assume_compatible || ((param_type->getPointeeType()->isStructureType() || (param_type->getPointeeType()->isPointerType() && param_type->getPointeeType()->getPointeeType()->isStructureType())) && - (types.contains(context.getCanonicalType(param_type->getPointeeType()->getLocallyUnqualifiedSingleStepDesugaredType().getTypePtr())) && LookupType(context, context.getCanonicalType(param_type->getPointeeType()->getLocallyUnqualifiedSingleStepDesugaredType().getTypePtr())).assumed_compatible))); - - std::optional pointee_compat; - if (param_type->isPointerType()) { - // Get TypeCompatibility from existing entry, or register TypeCompatibility::None if no entry exists - // TODO: Currently needs TypeCompatibility::Full workaround... - pointee_compat = type_compat.emplace(context.getCanonicalType(param_type->getPointeeType().getTypePtr()), TypeCompatibility::Full).first->second; - } - - if (thunk.param_annotations[param_idx].is_passthrough) { - // args are passed directly to function, no need to use `unpacked` wrappers - continue; - } - - // Layout repacking happens here - if (!param_type->isPointerType() || (is_assumed_compatible || pointee_compat == TypeCompatibility::Full) || - param_type->getPointeeType()->isBuiltinType() /* TODO: handle size_t. Actually, properly check for data layout compatibility */) { - // Fully compatible - fmt::print(file, " host_layout<{}> a_{} {{ args->a_{} }};\n", get_type_name(context, param_type.getTypePtr()), param_idx, param_idx); - } else if (pointee_compat == TypeCompatibility::Repackable) { - // TODO: Require opt-in for this to be emitted since it's single-element only; otherwise, pointers-to-arrays arguments will cause stack trampling - fmt::print(file, " auto a_{} = make_repack_wrapper<{}>(args->a_{});\n", param_idx, get_type_name_with_nonconst_pointee(param_type), param_idx); - } else { - throw report_error(thunk.decl->getLocation(), "Cannot generate unpacking function for function %0 with unannotated pointer parameter %1").AddString(function_name).AddTaggedVal(param_type); - } - } - - if (!thunk.return_type->isVoidType()) { - fmt::print(file, " args->rv = "); - if (!thunk.return_type->isFunctionPointerType()) { - fmt::print(file, "to_guest(to_host_layout<{}>(", thunk.return_type.getAsString()); - } - } - fmt::print(file, "{}(", function_to_call); - { - auto format_param = [&](std::size_t idx) { - auto cb = thunk.callbacks.find(idx); - if (cb != thunk.callbacks.end() && cb->second.is_stub) { - return "fexfn_unpack_" + get_callback_name(function_name, cb->first) + "_stub"; - } else if (cb != thunk.callbacks.end()) { - auto arg_name = fmt::format("args->a_{}", idx); // Use parameter directly - // Use comma operator to inject a function call before returning the argument - // TODO: Avoid casting away the guest_layout - if (thunk.custom_host_impl) { - return fmt::format("(FinalizeHostTrampolineForGuestFunction({}), {})", arg_name, arg_name); - } else { - return fmt::format("(FinalizeHostTrampolineForGuestFunction({}), ({})(uint64_t {{ {}.data }}))", arg_name, get_type_name(context, thunk.param_types[idx].getTypePtr()), arg_name); - } - } else if (thunk.param_annotations[idx].is_passthrough) { - // Pass raw guest_layout - return fmt::format("args->a_{}", idx); - } else { - // Unwrap host_layout/repack_wrapper layer - return fmt::format("unwrap_host(a_{})", idx); - } - }; - - fmt::print(file, "{}", format_function_args(thunk, format_param)); - } - if (!thunk.return_type->isVoidType() && !thunk.return_type->isFunctionPointerType()) { - fmt::print(file, "))"); - } - fmt::print(file, ");\n"); - - file << "}\n"; + auto get_guest_type_name = [this](clang::QualType type) { + if (type->isBuiltinType() && type->isIntegerType()) { + auto size = guest_abi.at(type.getUnqualifiedType().getAsString()).get_if_simple_or_struct()->size_bits; + return get_fixed_size_int_name(type.getTypePtr(), size); + } else if (type->isPointerType() && type->getPointeeType()->isBuiltinType() && type->getPointeeType()->isIntegerType() && + !type->getPointeeType()->isVoidType()) { + auto size = guest_abi.at(type->getPointeeType().getUnqualifiedType().getAsString()).get_if_simple_or_struct()->size_bits; + return fmt::format("{}{}*", type->getPointeeType().isConstQualified() ? "const " : "", + get_fixed_size_int_name(type->getPointeeType().getTypePtr(), size)); + } else { + return type.getUnqualifiedType().getAsString(); } - file << "}\n"; + }; - // Endpoints for Guest->Host invocation of API functions - file << "static ExportEntry exports[] = {\n"; - for (auto& thunk : thunks) { - const auto& function_name = thunk.function_name; - auto sha256 = get_sha256(function_name, true); - fmt::print( file, " {{(uint8_t*)\"\\x{:02x}\", (void(*)(void *))&fexfn_unpack_{}_{}}}, // {}:{}\n", - fmt::join(sha256, "\\x"), libname, function_name, libname, function_name); + // Forward declarations for user-provided implementations + if (thunk.custom_host_impl) { + file << "static auto fexfn_impl_" << libname << "_" << function_name << "("; + for (std::size_t idx = 0; idx < thunk.param_types.size(); ++idx) { + auto& type = thunk.param_types[idx]; + + file << (idx == 0 ? "" : ", "); + + if (thunk.param_annotations[idx].is_passthrough) { + fmt::print(file, "guest_layout<{}> a_{}", get_guest_type_name(type), idx); + } else { + file << format_decl(type, fmt::format("a_{}", idx)); + } } + // Using trailing return type as it makes handling function pointer returns much easier + file << ") -> " << thunk.return_type.getAsString() << ";\n"; + } - // Endpoints for Guest->Host invocation of runtime host-function pointers - // NOTE: The function parameters may differ slightly between guest and host, - // e.g. due to differing sizes or due to data layout differences. - // Hence, two separate parameter lists are managed here. - for (auto& host_funcptr_entry : thunked_funcptrs) { - auto& [type, param_annotations] = host_funcptr_entry.second; - auto func_type = type->getAs(); - FuncPtrInfo info = { }; - - // TODO: Use GetTypeNameWithFixedSizeIntegers - info.result = func_type->getReturnType().getAsString(); - - // NOTE: In guest contexts, integer types must be mapped to - // fixed-size equivalents. Since this is a host context, this - // isn't strictly necessary here, but it makes matching up - // guest_layout/host_layout constructors easier. - for (auto arg : func_type->getParamTypes()) { - info.args.push_back(GetTypeNameWithFixedSizeIntegers(context, arg)); - } - - std::string annotations; - for (int param_idx = 0; param_idx < info.args.size(); ++param_idx) { - if (param_idx != 0) { - annotations += ", "; - } - - annotations += "ParameterAnnotations {"; - if (param_annotations.contains(param_idx) && param_annotations.at(param_idx).is_passthrough) { - annotations += ".is_passthrough=true,"; - } - if (param_annotations.contains(param_idx) && param_annotations.at(param_idx).assume_compatible) { - annotations += ".assume_compatible=true,"; - } - annotations += "}"; - } - auto guest_info = LookupGuestFuncPtrInfo(host_funcptr_entry.first.c_str()); - // TODO: Consider differences in guest/host return types - fmt::print( file, " {{(uint8_t*)\"\\x{:02x}\", (void(*)(void *))&GuestWrapperForHostFunction<{}({}){}{}>::Call<{}>}}, // {}\n", - fmt::join(guest_info.sha256, "\\x"), guest_info.result, fmt::join(info.args, ", "), guest_info.args.empty() ? "" : ", ", fmt::join(guest_info.args, ", "), annotations, host_funcptr_entry.first); + // Check data layout compatibility of parameter types + // TODO: Also check non-struct/non-pointer types + // TODO: Also check return type + for (size_t param_idx = 0; param_idx != thunk.param_types.size(); ++param_idx) { + const auto& param_type = thunk.param_types[param_idx]; + if (!param_type->isPointerType() || !param_type->getPointeeType()->isStructureType()) { + continue; } + if (!thunk.param_annotations[param_idx].is_passthrough) { + auto type = param_type->getPointeeType(); + if (!types.at(context.getCanonicalType(type.getTypePtr())).assumed_compatible && + type_compat.at(context.getCanonicalType(type.getTypePtr())) == TypeCompatibility::None) { + // TODO: Factor in "assume_compatible_layout" annotations here + // That annotation should cause the type to be treated as TypeCompatibility::Full + throw report_error(thunk.decl->getLocation(), "Unsupported parameter type %0").AddTaggedVal(param_type); + } + } + } - file << " { nullptr, nullptr }\n"; + // Packed argument structs used in fexfn_unpack_* + auto GeneratePackedArgs = [&](const auto& function_name, const ThunkedFunction& thunk) -> std::string { + std::string struct_name = "fexfn_packed_args_" + libname + "_" + function_name; + file << "struct __attribute__((packed)) " << struct_name << " {\n"; + + for (std::size_t idx = 0; idx < thunk.param_types.size(); ++idx) { + fmt::print(file, " guest_layout<{}> a_{};\n", get_guest_type_name(thunk.param_types[idx]), idx); + } + if (!thunk.return_type->isVoidType()) { + fmt::print(file, " guest_layout<{}> rv;\n", get_guest_type_name(thunk.return_type)); + } else if (thunk.param_types.size() == 0) { + // Avoid "empty struct has size 0 in C, size 1 in C++" warning + file << " char force_nonempty;\n"; + } file << "};\n"; + return struct_name; + }; + auto struct_name = GeneratePackedArgs(function_name, thunk); - // Symbol lookup from native host library - file << "static void* fexldr_ptr_" << libname << "_so;\n"; - file << "extern \"C\" bool fexldr_init_" << libname << "() {\n"; + // Unpacking functions + auto function_to_call = "fexldr_ptr_" + libname + "_" + function_name; + if (thunk.custom_host_impl) { + function_to_call = "fexfn_impl_" + libname + "_" + function_name; + } - std::string version_suffix; - if (lib_version) { - version_suffix = '.' + std::to_string(*lib_version); + auto get_type_name_with_nonconst_pointee = [&](clang::QualType type) { + type = type.getLocalUnqualifiedType(); + if (type->isPointerType()) { + // Strip away "const" from pointee type + type = context.getPointerType(type->getPointeeType().getLocalUnqualifiedType()); } - const std::string library_filename = libfilename + ".so" + version_suffix; + return get_type_name(context, type.getTypePtr()); + }; - // Load the host library in the global symbol namespace. - // This follows how these libraries get loaded in a non-emulated environment, - // Either by directly linking to the library or a loader (In OpenGL or Vulkan) putting everything in the global namespace. - file << " fexldr_ptr_" << libname << "_so = dlopen(\"" << library_filename << "\", RTLD_GLOBAL | RTLD_LAZY);\n"; - file << " if (!fexldr_ptr_" << libname << "_so) { return false; }\n\n"; - for (auto& import : thunked_api) { - fmt::print( file, " (void*&)fexldr_ptr_{}_{} = {}(fexldr_ptr_{}_so, \"{}\");\n", - libname, import.function_name, import.host_loader, libname, import.function_name); + file << "static void fexfn_unpack_" << libname << "_" << function_name << "(" << struct_name << "* args) {\n"; + + for (unsigned param_idx = 0; param_idx != thunk.param_types.size(); ++param_idx) { + if (thunk.callbacks.contains(param_idx) && thunk.callbacks.at(param_idx).is_stub) { + continue; } - file << " return true;\n"; - file << "}\n"; + + auto& param_type = thunk.param_types[param_idx]; + const bool is_assumed_compatible = + param_type->isPointerType() && + (thunk.param_annotations[param_idx].assume_compatible || + ((param_type->getPointeeType()->isStructureType() || + (param_type->getPointeeType()->isPointerType() && param_type->getPointeeType()->getPointeeType()->isStructureType())) && + (types.contains(context.getCanonicalType(param_type->getPointeeType()->getLocallyUnqualifiedSingleStepDesugaredType().getTypePtr())) && + LookupType(context, context.getCanonicalType(param_type->getPointeeType()->getLocallyUnqualifiedSingleStepDesugaredType().getTypePtr())) + .assumed_compatible))); + + std::optional pointee_compat; + if (param_type->isPointerType()) { + // Get TypeCompatibility from existing entry, or register TypeCompatibility::None if no entry exists + // TODO: Currently needs TypeCompatibility::Full workaround... + pointee_compat = + type_compat.emplace(context.getCanonicalType(param_type->getPointeeType().getTypePtr()), TypeCompatibility::Full).first->second; + } + + if (thunk.param_annotations[param_idx].is_passthrough) { + // args are passed directly to function, no need to use `unpacked` wrappers + continue; + } + + // Layout repacking happens here + if (!param_type->isPointerType() || (is_assumed_compatible || pointee_compat == TypeCompatibility::Full) || + param_type->getPointeeType()->isBuiltinType() /* TODO: handle size_t. Actually, properly check for data layout compatibility */) { + // Fully compatible + fmt::print(file, " host_layout<{}> a_{} {{ args->a_{} }};\n", get_type_name(context, param_type.getTypePtr()), param_idx, param_idx); + } else if (pointee_compat == TypeCompatibility::Repackable) { + // TODO: Require opt-in for this to be emitted since it's single-element only; otherwise, pointers-to-arrays arguments will cause stack trampling + fmt::print(file, " auto a_{} = make_repack_wrapper<{}>(args->a_{});\n", param_idx, + get_type_name_with_nonconst_pointee(param_type), param_idx); + } else { + throw report_error(thunk.decl->getLocation(), "Cannot generate unpacking function for function %0 with unannotated pointer " + "parameter %1") + .AddString(function_name) + .AddTaggedVal(param_type); + } + } + + if (!thunk.return_type->isVoidType()) { + fmt::print(file, " args->rv = "); + if (!thunk.return_type->isFunctionPointerType()) { + fmt::print(file, "to_guest(to_host_layout<{}>(", thunk.return_type.getAsString()); + } + } + fmt::print(file, "{}(", function_to_call); + { + auto format_param = [&](std::size_t idx) { + auto cb = thunk.callbacks.find(idx); + if (cb != thunk.callbacks.end() && cb->second.is_stub) { + return "fexfn_unpack_" + get_callback_name(function_name, cb->first) + "_stub"; + } else if (cb != thunk.callbacks.end()) { + auto arg_name = fmt::format("args->a_{}", idx); // Use parameter directly + // Use comma operator to inject a function call before returning the argument + // TODO: Avoid casting away the guest_layout + if (thunk.custom_host_impl) { + return fmt::format("(FinalizeHostTrampolineForGuestFunction({}), {})", arg_name, arg_name); + } else { + return fmt::format("(FinalizeHostTrampolineForGuestFunction({}), ({})(uint64_t {{ {}.data }}))", arg_name, + get_type_name(context, thunk.param_types[idx].getTypePtr()), arg_name); + } + } else if (thunk.param_annotations[idx].is_passthrough) { + // Pass raw guest_layout + return fmt::format("args->a_{}", idx); + } else { + // Unwrap host_layout/repack_wrapper layer + return fmt::format("unwrap_host(a_{})", idx); + } + }; + + fmt::print(file, "{}", format_function_args(thunk, format_param)); + } + if (!thunk.return_type->isVoidType() && !thunk.return_type->isFunctionPointerType()) { + fmt::print(file, "))"); + } + fmt::print(file, ");\n"); + + file << "}\n"; } + file << "}\n"; + + // Endpoints for Guest->Host invocation of API functions + file << "static ExportEntry exports[] = {\n"; + for (auto& thunk : thunks) { + const auto& function_name = thunk.function_name; + auto sha256 = get_sha256(function_name, true); + fmt::print(file, " {{(uint8_t*)\"\\x{:02x}\", (void(*)(void *))&fexfn_unpack_{}_{}}}, // {}:{}\n", fmt::join(sha256, "\\x"), libname, + function_name, libname, function_name); + } + + // Endpoints for Guest->Host invocation of runtime host-function pointers + // NOTE: The function parameters may differ slightly between guest and host, + // e.g. due to differing sizes or due to data layout differences. + // Hence, two separate parameter lists are managed here. + for (auto& host_funcptr_entry : thunked_funcptrs) { + auto& [type, param_annotations] = host_funcptr_entry.second; + auto func_type = type->getAs(); + FuncPtrInfo info = {}; + + // TODO: Use GetTypeNameWithFixedSizeIntegers + info.result = func_type->getReturnType().getAsString(); + + // NOTE: In guest contexts, integer types must be mapped to + // fixed-size equivalents. Since this is a host context, this + // isn't strictly necessary here, but it makes matching up + // guest_layout/host_layout constructors easier. + for (auto arg : func_type->getParamTypes()) { + info.args.push_back(GetTypeNameWithFixedSizeIntegers(context, arg)); + } + + std::string annotations; + for (int param_idx = 0; param_idx < info.args.size(); ++param_idx) { + if (param_idx != 0) { + annotations += ", "; + } + + annotations += "ParameterAnnotations {"; + if (param_annotations.contains(param_idx) && param_annotations.at(param_idx).is_passthrough) { + annotations += ".is_passthrough=true,"; + } + if (param_annotations.contains(param_idx) && param_annotations.at(param_idx).assume_compatible) { + annotations += ".assume_compatible=true,"; + } + annotations += "}"; + } + auto guest_info = LookupGuestFuncPtrInfo(host_funcptr_entry.first.c_str()); + // TODO: Consider differences in guest/host return types + fmt::print(file, " {{(uint8_t*)\"\\x{:02x}\", (void(*)(void *))&GuestWrapperForHostFunction<{}({}){}{}>::Call<{}>}}, // {}\n", + fmt::join(guest_info.sha256, "\\x"), guest_info.result, fmt::join(info.args, ", "), guest_info.args.empty() ? "" : ", ", + fmt::join(guest_info.args, ", "), annotations, host_funcptr_entry.first); + } + + file << " { nullptr, nullptr }\n"; + file << "};\n"; + + // Symbol lookup from native host library + file << "static void* fexldr_ptr_" << libname << "_so;\n"; + file << "extern \"C\" bool fexldr_init_" << libname << "() {\n"; + + std::string version_suffix; + if (lib_version) { + version_suffix = '.' + std::to_string(*lib_version); + } + const std::string library_filename = libfilename + ".so" + version_suffix; + + // Load the host library in the global symbol namespace. + // This follows how these libraries get loaded in a non-emulated environment, + // Either by directly linking to the library or a loader (In OpenGL or Vulkan) putting everything in the global namespace. + file << " fexldr_ptr_" << libname << "_so = dlopen(\"" << library_filename << "\", RTLD_GLOBAL | RTLD_LAZY);\n"; + + file << " if (!fexldr_ptr_" << libname << "_so) { return false; }\n\n"; + for (auto& import : thunked_api) { + fmt::print(file, " (void*&)fexldr_ptr_{}_{} = {}(fexldr_ptr_{}_so, \"{}\");\n", libname, import.function_name, import.host_loader, + libname, import.function_name); + } + file << " return true;\n"; + file << "}\n"; + } } -bool GenerateThunkLibsActionFactory::runInvocation( - std::shared_ptr Invocation, clang::FileManager *Files, - std::shared_ptr PCHContainerOps, - clang::DiagnosticConsumer *DiagConsumer) { +bool GenerateThunkLibsActionFactory::runInvocation(std::shared_ptr Invocation, clang::FileManager* Files, + std::shared_ptr PCHContainerOps, + clang::DiagnosticConsumer* DiagConsumer) { clang::CompilerInstance Compiler(std::move(PCHContainerOps)); Compiler.setInvocation(std::move(Invocation)); Compiler.setFileManager(Files); @@ -800,8 +805,9 @@ bool GenerateThunkLibsActionFactory::runInvocation( GenerateThunkLibsAction Action(libname, output_filenames, abi); Compiler.createDiagnostics(DiagConsumer, false); - if (!Compiler.hasDiagnostics()) + if (!Compiler.hasDiagnostics()) { return false; + } Compiler.createSourceManager(*Files); diff --git a/ThunkLibs/Generator/interface.h b/ThunkLibs/Generator/interface.h index 86768d34f..80ef58841 100644 --- a/ThunkLibs/Generator/interface.h +++ b/ThunkLibs/Generator/interface.h @@ -4,51 +4,50 @@ #include struct OutputFilenames { - std::string host; - std::string guest; + std::string host; + std::string guest; }; class AnalyzeDataLayoutActionFactory : public clang::tooling::FrontendActionFactory { - std::unique_ptr abi; + std::unique_ptr abi; public: - AnalyzeDataLayoutActionFactory(); - ~AnalyzeDataLayoutActionFactory(); + AnalyzeDataLayoutActionFactory(); + ~AnalyzeDataLayoutActionFactory(); - std::unique_ptr create() override; + std::unique_ptr create() override; - const ABI& GetDataLayout() { - return *abi; - } + const ABI& GetDataLayout() { + return *abi; + } - std::unique_ptr TakeDataLayout() { - return std::move(abi); - } + std::unique_ptr TakeDataLayout() { + return std::move(abi); + } }; class DataLayoutCompareActionFactory : public clang::tooling::FrontendActionFactory { - const ABI& abi; + const ABI& abi; public: - DataLayoutCompareActionFactory(const ABI&); - ~DataLayoutCompareActionFactory(); + DataLayoutCompareActionFactory(const ABI&); + ~DataLayoutCompareActionFactory(); - std::unique_ptr create() override; + std::unique_ptr create() override; }; class GenerateThunkLibsActionFactory : public clang::tooling::ToolAction { public: - GenerateThunkLibsActionFactory(std::string_view libname_, OutputFilenames output_filenames_, const ABI& abi_) - : libname(std::move(libname_)), output_filenames(std::move(output_filenames_)), abi(abi_) { - } + GenerateThunkLibsActionFactory(std::string_view libname_, OutputFilenames output_filenames_, const ABI& abi_) + : libname(std::move(libname_)) + , output_filenames(std::move(output_filenames_)) + , abi(abi_) {} - bool runInvocation( - std::shared_ptr Invocation, clang::FileManager *Files, - std::shared_ptr PCHContainerOps, - clang::DiagnosticConsumer *DiagConsumer) override; + bool runInvocation(std::shared_ptr Invocation, clang::FileManager* Files, + std::shared_ptr PCHContainerOps, clang::DiagnosticConsumer* DiagConsumer) override; private: - std::string libname; - OutputFilenames output_filenames; - const ABI& abi; + std::string libname; + OutputFilenames output_filenames; + const ABI& abi; }; diff --git a/ThunkLibs/Generator/main.cpp b/ThunkLibs/Generator/main.cpp index d238fc1ea..a378cc090 100644 --- a/ThunkLibs/Generator/main.cpp +++ b/ThunkLibs/Generator/main.cpp @@ -11,81 +11,81 @@ using namespace clang::tooling; void print_usage(const char* program_name) { - std::cerr << "Usage: " << program_name << " -- \n"; + std::cerr << "Usage: " << program_name << " -- \n"; } int main(int argc, char* const argv[]) { - llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); - if (argc < 5) { - print_usage(argv[0]); - return EXIT_FAILURE; - } + if (argc < 5) { + print_usage(argv[0]); + return EXIT_FAILURE; + } - // Parse compile flags after "--" (this updates argc to the index of the "--" separator) - std::string error; - auto compile_db = FixedCompilationDatabase::loadFromCommandLine(argc, argv, error); - if (!compile_db) { - print_usage(argv[0]); - std::cerr << "\nError: " << error << "\n"; - return EXIT_FAILURE; - } + // Parse compile flags after "--" (this updates argc to the index of the "--" separator) + std::string error; + auto compile_db = FixedCompilationDatabase::loadFromCommandLine(argc, argv, error); + if (!compile_db) { + print_usage(argv[0]); + std::cerr << "\nError: " << error << "\n"; + return EXIT_FAILURE; + } - // Process arguments before the "--" separator - if (argc != 5 && argc != 6) { - print_usage(argv[0]); - return EXIT_FAILURE; - } + // Process arguments before the "--" separator + if (argc != 5 && argc != 6) { + print_usage(argv[0]); + return EXIT_FAILURE; + } - char* const* arg = argv + 1; - const auto filename = *arg++; - const std::string libname = *arg++; - const std::string target_abi = *arg++; - const std::string output_filename = *arg++; + char* const* arg = argv + 1; + const auto filename = *arg++; + const std::string libname = *arg++; + const std::string target_abi = *arg++; + const std::string output_filename = *arg++; - OutputFilenames output_filenames; - if (target_abi == "-host") { - output_filenames.host = output_filename; - } else if (target_abi == "-guest") { - output_filenames.guest = output_filename; - } else { - std::cerr << "Unrecognized generator target ABI \"" << target_abi << "\"\n"; - return EXIT_FAILURE; - } + OutputFilenames output_filenames; + if (target_abi == "-host") { + output_filenames.host = output_filename; + } else if (target_abi == "-guest") { + output_filenames.guest = output_filename; + } else { + std::cerr << "Unrecognized generator target ABI \"" << target_abi << "\"\n"; + return EXIT_FAILURE; + } - ClangTool Tool(*compile_db, { filename }); - if (CLANG_RESOURCE_DIR[0] != 0) { - auto set_resource_directory = [](const clang::tooling::CommandLineArguments &Args, clang::StringRef) { - clang::tooling::CommandLineArguments AdjustedArgs = Args; - AdjustedArgs.push_back(std::string { "-resource-dir=" } + CLANG_RESOURCE_DIR); - return AdjustedArgs; - }; - Tool.appendArgumentsAdjuster(set_resource_directory); - } + ClangTool Tool(*compile_db, {filename}); + if (CLANG_RESOURCE_DIR[0] != 0) { + auto set_resource_directory = [](const clang::tooling::CommandLineArguments& Args, clang::StringRef) { + clang::tooling::CommandLineArguments AdjustedArgs = Args; + AdjustedArgs.push_back(std::string {"-resource-dir="} + CLANG_RESOURCE_DIR); + return AdjustedArgs; + }; + Tool.appendArgumentsAdjuster(set_resource_directory); + } - ClangTool GuestTool = Tool; + ClangTool GuestTool = Tool; - { - const bool is_32bit_guest = (argv[5] == std::string_view { "-for-32bit-guest" }); - auto append_guest_args = [is_32bit_guest](const clang::tooling::CommandLineArguments &Args, clang::StringRef) { - clang::tooling::CommandLineArguments AdjustedArgs = Args; - const char* platform = is_32bit_guest ? "i686" : "x86_64"; - if (is_32bit_guest) { - AdjustedArgs.push_back("-m32"); - AdjustedArgs.push_back("-DIS_32BIT_THUNK"); - } - AdjustedArgs.push_back(std::string { "--target=" } + platform + "-linux-unknown"); - AdjustedArgs.push_back("-isystem"); - AdjustedArgs.push_back(std::string { "/usr/" } + platform + "-linux-gnu/include/"); - AdjustedArgs.push_back("-DGUEST_THUNK_LIBRARY"); - return AdjustedArgs; - }; - GuestTool.appendArgumentsAdjuster(append_guest_args); - } + { + const bool is_32bit_guest = (argv[5] == std::string_view {"-for-32bit-guest"}); + auto append_guest_args = [is_32bit_guest](const clang::tooling::CommandLineArguments& Args, clang::StringRef) { + clang::tooling::CommandLineArguments AdjustedArgs = Args; + const char* platform = is_32bit_guest ? "i686" : "x86_64"; + if (is_32bit_guest) { + AdjustedArgs.push_back("-m32"); + AdjustedArgs.push_back("-DIS_32BIT_THUNK"); + } + AdjustedArgs.push_back(std::string {"--target="} + platform + "-linux-unknown"); + AdjustedArgs.push_back("-isystem"); + AdjustedArgs.push_back(std::string {"/usr/"} + platform + "-linux-gnu/include/"); + AdjustedArgs.push_back("-DGUEST_THUNK_LIBRARY"); + return AdjustedArgs; + }; + GuestTool.appendArgumentsAdjuster(append_guest_args); + } - auto data_layout_analysis_factory = std::make_unique(); - GuestTool.run(data_layout_analysis_factory.get()); - auto& data_layout = data_layout_analysis_factory->GetDataLayout(); + auto data_layout_analysis_factory = std::make_unique(); + GuestTool.run(data_layout_analysis_factory.get()); + auto& data_layout = data_layout_analysis_factory->GetDataLayout(); - return Tool.run(std::make_unique(std::move(libname), std::move(output_filenames), data_layout).get()); + return Tool.run(std::make_unique(std::move(libname), std::move(output_filenames), data_layout).get()); } diff --git a/ThunkLibs/include/common/GeneratorInterface.h b/ThunkLibs/include/common/GeneratorInterface.h index eb3a57883..fd747eb8c 100644 --- a/ThunkLibs/include/common/GeneratorInterface.h +++ b/ThunkLibs/include/common/GeneratorInterface.h @@ -7,8 +7,8 @@ struct generate_guest_symtable {}; struct indirect_guest_calls {}; struct callback_annotation_base { - // Prevent annotating multiple callback strategies - bool prevent_multiple; + // Prevent annotating multiple callback strategies + bool prevent_multiple; }; struct callback_stub : callback_annotation_base {}; @@ -33,7 +33,9 @@ struct custom_repack {}; // copied (or zero-extended) without regard for the referred data. struct emit_layout_wrappers {}; -struct type_annotation_base { bool prevent_multiple; }; +struct type_annotation_base { + bool prevent_multiple; +}; // Pointers to types annotated with this will be passed through without change struct opaque_type : type_annotation_base {}; diff --git a/ThunkLibs/include/common/Guest.h b/ThunkLibs/include/common/Guest.h index f4b171405..a6208d60c 100644 --- a/ThunkLibs/include/common/Guest.h +++ b/ThunkLibs/include/common/Guest.h @@ -15,31 +15,32 @@ #endif template -THUNK_ABI -const int (*fexthunks_invoke_callback)(void*); +THUNK_ABI const int (*fexthunks_invoke_callback)(void*); #ifndef _M_ARM_64 #define MAKE_THUNK(lib, name, hash) \ - extern "C" __attribute__((visibility("hidden"))) THUNK_ABI int fexthunks_##lib##_##name(void *args); \ - asm(".text\nfexthunks_" #lib "_" #name ":\n.byte 0xF, 0x3F\n.byte " hash ); + extern "C" __attribute__((visibility("hidden"))) THUNK_ABI int fexthunks_##lib##_##name(void* args); \ + asm(".text\nfexthunks_" #lib "_" #name ":\n.byte 0xF, 0x3F\n.byte " hash); #define MAKE_CALLBACK_THUNK(name, signature, hash) \ - extern "C" __attribute__((visibility("hidden"))) THUNK_ABI int fexthunks_##name(void *args); \ - asm(".text\nfexthunks_" #name ":\n.byte 0xF, 0x3F\n.byte " hash ); \ - template<> THUNK_ABI inline constexpr int (*fexthunks_invoke_callback)(void*) = fexthunks_##name; + extern "C" __attribute__((visibility("hidden"))) THUNK_ABI int fexthunks_##name(void* args); \ + asm(".text\nfexthunks_" #name ":\n.byte 0xF, 0x3F\n.byte " hash); \ + template<> \ + THUNK_ABI inline constexpr int (*fexthunks_invoke_callback)(void*) = fexthunks_##name; #else // We're compiling for IDE integration, so provide a dummy-implementation that just calls an undefined function. // The name of that function serves as an error message if this library somehow gets loaded at runtime. extern "C" void BROKEN_INSTALL___TRIED_LOADING_AARCH64_BUILD_OF_GUEST_THUNK(); #define MAKE_THUNK(lib, name, hash) \ - extern "C" int fexthunks_##lib##_##name(void *args) { \ + extern "C" int fexthunks_##lib##_##name(void* args) { \ BROKEN_INSTALL___TRIED_LOADING_AARCH64_BUILD_OF_GUEST_THUNK(); \ return 0; \ } #define MAKE_CALLBACK_THUNK(name, signature, hash) \ - extern "C" int fexthunks_##name(void *args); \ - template<> inline constexpr int (*fexthunks_invoke_callback)(void*) = fexthunks_##name; + extern "C" int fexthunks_##name(void* args); \ + template<> \ + inline constexpr int (*fexthunks_invoke_callback)(void*) = fexthunks_##name; #endif // Generated fexfn_pack_ symbols should be hidden by default, but clang does @@ -52,41 +53,50 @@ extern "C" void BROKEN_INSTALL___TRIED_LOADING_AARCH64_BUILD_OF_GUEST_THUNK(); #endif struct LoadlibArgs { - const char *Name; - uintptr_t CallbackThunks; + const char* Name; + uintptr_t CallbackThunks; }; -MAKE_THUNK(fex, loadlib, "0x27, 0x7e, 0xb7, 0x69, 0x5b, 0xe9, 0xab, 0x12, 0x6e, 0xf7, 0x85, 0x9d, 0x4b, 0xc9, 0xa2, 0x44, 0x46, 0xcf, 0xbd, 0xb5, 0x87, 0x43, 0xef, 0x28, 0xa2, 0x65, 0xba, 0xfc, 0x89, 0x0f, 0x77, 0x80") -MAKE_THUNK(fex, is_lib_loaded, "0xee, 0x57, 0xba, 0x0c, 0x5f, 0x6e, 0xef, 0x2a, 0x8c, 0xb5, 0x19, 0x81, 0xc9, 0x23, 0xe6, 0x51, 0xae, 0x65, 0x02, 0x8f, 0x2b, 0x5d, 0x59, 0x90, 0x6a, 0x7e, 0xe2, 0xe7, 0x1c, 0x33, 0x8a, 0xff") -MAKE_THUNK(fex, is_host_heap_allocation, "0xf5, 0x77, 0x68, 0x43, 0xbb, 0x6b, 0x28, 0x18, 0x40, 0xb0, 0xdb, 0x8a, 0x66, 0xfb, 0x0e, 0x2d, 0x98, 0xc2, 0xad, 0xe2, 0x5a, 0x18, 0x5a, 0x37, 0x2e, 0x13, 0xc9, 0xe7, 0xb9, 0x8c, 0xa9, 0x3e") -MAKE_THUNK(fex, link_address_to_function, "0xe6, 0xa8, 0xec, 0x1c, 0x7b, 0x74, 0x35, 0x27, 0xe9, 0x4f, 0x5b, 0x6e, 0x2d, 0xc9, 0xa0, 0x27, 0xd6, 0x1f, 0x2b, 0x87, 0x8f, 0x2d, 0x35, 0x50, 0xea, 0x16, 0xb8, 0xc4, 0x5e, 0x42, 0xfd, 0x77") -MAKE_THUNK(fex, allocate_host_trampoline_for_guest_function, "0x9b, 0xb2, 0xf4, 0xb4, 0x83, 0x7d, 0x28, 0x93, 0x40, 0xcb, 0xf4, 0x7a, 0x0b, 0x47, 0x85, 0x87, 0xf9, 0xbc, 0xb5, 0x27, 0xca, 0xa6, 0x93, 0xa5, 0xc0, 0x73, 0x27, 0x24, 0xae, 0xc8, 0xb8, 0x5a") +MAKE_THUNK(fex, loadlib, + "0x27, 0x7e, 0xb7, 0x69, 0x5b, 0xe9, 0xab, 0x12, 0x6e, 0xf7, 0x85, 0x9d, 0x4b, 0xc9, 0xa2, 0x44, 0x46, 0xcf, 0xbd, 0xb5, 0x87, " + "0x43, 0xef, 0x28, 0xa2, 0x65, 0xba, 0xfc, 0x89, 0x0f, 0x77, 0x80") +MAKE_THUNK(fex, is_lib_loaded, + "0xee, 0x57, 0xba, 0x0c, 0x5f, 0x6e, 0xef, 0x2a, 0x8c, 0xb5, 0x19, 0x81, 0xc9, 0x23, 0xe6, 0x51, 0xae, 0x65, 0x02, 0x8f, 0x2b, " + "0x5d, 0x59, 0x90, 0x6a, 0x7e, 0xe2, 0xe7, 0x1c, 0x33, 0x8a, 0xff") +MAKE_THUNK(fex, is_host_heap_allocation, + "0xf5, 0x77, 0x68, 0x43, 0xbb, 0x6b, 0x28, 0x18, 0x40, 0xb0, 0xdb, 0x8a, 0x66, 0xfb, 0x0e, 0x2d, 0x98, 0xc2, 0xad, 0xe2, 0x5a, " + "0x18, 0x5a, 0x37, 0x2e, 0x13, 0xc9, 0xe7, 0xb9, 0x8c, 0xa9, 0x3e") +MAKE_THUNK(fex, link_address_to_function, + "0xe6, 0xa8, 0xec, 0x1c, 0x7b, 0x74, 0x35, 0x27, 0xe9, 0x4f, 0x5b, 0x6e, 0x2d, 0xc9, 0xa0, 0x27, 0xd6, 0x1f, 0x2b, 0x87, 0x8f, " + "0x2d, 0x35, 0x50, 0xea, 0x16, 0xb8, 0xc4, 0x5e, 0x42, 0xfd, 0x77") +MAKE_THUNK(fex, allocate_host_trampoline_for_guest_function, + "0x9b, 0xb2, 0xf4, 0xb4, 0x83, 0x7d, 0x28, 0x93, 0x40, 0xcb, 0xf4, 0x7a, 0x0b, 0x47, 0x85, 0x87, 0xf9, 0xbc, 0xb5, 0x27, 0xca, " + "0xa6, 0x93, 0xa5, 0xc0, 0x73, 0x27, 0x24, 0xae, 0xc8, 0xb8, 0x5a") #define LOAD_LIB_BASE(name, init_fn) \ - __attribute__((constructor)) static void loadlib() \ - { \ - LoadlibArgs args = { #name }; \ + __attribute__((constructor)) static void loadlib() { \ + LoadlibArgs args = {#name}; \ fexthunks_fex_loadlib(&args); \ - if ((init_fn)) ((void(*)())init_fn)(); \ + if ((init_fn)) ((void (*)())init_fn)(); \ } #define LOAD_LIB(name) LOAD_LIB_BASE(name, nullptr) #define LOAD_LIB_INIT(name, init_fn) LOAD_LIB_BASE(name, init_fn) inline void LinkAddressToFunction(uintptr_t addr, uintptr_t target) { - struct args_t { - uint64_t original_callee; - uint64_t target_addr; // Function to call when branching to replaced_addr - }; - args_t args = { addr, target }; - fexthunks_fex_link_address_to_function(&args); + struct args_t { + uint64_t original_callee; + uint64_t target_addr; // Function to call when branching to replaced_addr + }; + args_t args = {addr, target}; + fexthunks_fex_link_address_to_function(&args); } -inline bool IsLibLoaded(const char *libname) { +inline bool IsLibLoaded(const char* libname) { struct { - const char *Name; + const char* Name; bool rv; - } argsrv = { libname }; + } argsrv = {libname}; fexthunks_fex_is_lib_loaded(&argsrv); @@ -108,7 +118,7 @@ inline Result CallHostFunction(Args... args) { // will clobber our r11 register we save the data that is inside of it. // First we need to declare the r11 register variable - register uintptr_t host_addr asm ("r11"); + register uintptr_t host_addr asm("r11"); // We then create an empty *volatile* asm block saying that it is assigning the register variable. // Yes, it is already set coming in to this function due to custom ABI. @@ -119,23 +129,22 @@ inline Result CallHostFunction(Args... args) { // don't have intersecting ranges. // // Note that this issue is more likely to occur when clang is used to compile thunks, since its optimizer is more aggressive at using R11. - // This magic incantation also works in that instance so this is about the best we can do without adding a new attribute to clang for modifying the - // ABI. - asm volatile("" : "=r" (host_addr)); + // This magic incantation also works in that instance so this is about the best we can do without adding a new attribute to clang for + // modifying the ABI. + asm volatile("" : "=r"(host_addr)); #else // Use mm0 to pass in host_addr (chosen to avoid conflicts with vectorcall). // Note this register overlaps the x87 st(0) register (used to return float values), // so applications that expect this register to be preserved could run into problems. - uintptr_t host_addr; \ - asm volatile("movd %%mm0, %0" : "=r" (host_addr)); + uintptr_t host_addr; + asm volatile("movd %%mm0, %0" : "=r"(host_addr)); #endif #else uintptr_t host_addr = 0; #endif PackedArguments packed_args = { - args..., - host_addr + args..., host_addr // Return value not explicitly initialized since an initializer would fail to compile for the void case }; @@ -148,21 +157,20 @@ inline Result CallHostFunction(Args... args) { // Convenience wrapper that returns the function pointer to a CallHostFunction // instantiation matching the function signature of `host_func` -template -static auto GetCallerForHostFunction(Result (*host_func)(Args...)) - -> Result(*)(Args...) { +template +static auto GetCallerForHostFunction(Result (*host_func)(Args...)) -> Result (*)(Args...) { return &CallHostFunction, Result, Args...>; } // Ensures the given host function can safely be called from guest code. -template +template inline void MakeHostFunctionGuestCallable(THUNK_ABI Result (*host_func)(Args...)) { auto caller = (uintptr_t)GetCallerForHostFunction(host_func); LinkAddressToFunction((uintptr_t)host_func, (uintptr_t)caller); } template -inline Target* AllocateHostTrampolineForGuestFunction(void THUNK_ABI (*GuestUnpacker)(uintptr_t, void*), Target *GuestTarget) { +inline Target* AllocateHostTrampolineForGuestFunction(void THUNK_ABI (*GuestUnpacker)(uintptr_t, void*), Target* GuestTarget) { if (!GuestTarget) { return 0; } @@ -171,7 +179,7 @@ inline Target* AllocateHostTrampolineForGuestFunction(void THUNK_ABI (*GuestUnpa uint64_t GuestUnpacker; uint64_t GuestTarget; uint64_t rv; - } argsrv = { (uintptr_t)GuestUnpacker, (uintptr_t)GuestTarget }; + } argsrv = {(uintptr_t)GuestUnpacker, (uintptr_t)GuestTarget}; fexthunks_fex_allocate_host_trampoline_for_guest_function((void*)&argsrv); @@ -183,30 +191,28 @@ struct CallbackUnpack; template struct CallbackUnpack { - static void THUNK_ABI Unpack(uintptr_t cb, void* argsv) { - using fn_t = Result(Args...); - auto callback = reinterpret_cast(cb); - auto args = reinterpret_cast*>(argsv); - Invoke(callback, *args); - } + static void THUNK_ABI Unpack(uintptr_t cb, void* argsv) { + using fn_t = Result(Args...); + auto callback = reinterpret_cast(cb); + auto args = reinterpret_cast*>(argsv); + Invoke(callback, *args); + } }; template -struct CallbackUnpack : CallbackUnpack { -}; +struct CallbackUnpack : CallbackUnpack {}; template -inline Target *AllocateHostTrampolineForGuestFunction(Target *GuestTarget) { - return AllocateHostTrampolineForGuestFunction(CallbackUnpack::Unpack, - GuestTarget); +inline Target* AllocateHostTrampolineForGuestFunction(Target* GuestTarget) { + return AllocateHostTrampolineForGuestFunction(CallbackUnpack::Unpack, GuestTarget); } inline bool IsHostHeapAllocation(void* ptr) { - struct { - void* ptr; - bool rv; - } args = { ptr, {} }; + struct { + void* ptr; + bool rv; + } args = {ptr, {}}; - fexthunks_fex_is_host_heap_allocation(&args); - return args.rv; + fexthunks_fex_is_host_heap_allocation(&args); + return args.rv; } diff --git a/ThunkLibs/include/common/Host.h b/ThunkLibs/include/common/Host.h index 10c940e0c..c1e26b549 100644 --- a/ThunkLibs/include/common/Host.h +++ b/ThunkLibs/include/common/Host.h @@ -21,56 +21,51 @@ $end_info$ // doesn't know about them when linking thunk libraries. This issue is avoided // by declaring the functions as weak symbols. namespace FEXCore { - struct HostToGuestTrampolinePtr; +struct HostToGuestTrampolinePtr; - __attribute__((weak)) - HostToGuestTrampolinePtr* - MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker); +__attribute__((weak)) HostToGuestTrampolinePtr* MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker); - __attribute__((weak)) - HostToGuestTrampolinePtr* - FinalizeHostTrampolineForGuestFunction(HostToGuestTrampolinePtr*, void* HostPacker); +__attribute__((weak)) HostToGuestTrampolinePtr* FinalizeHostTrampolineForGuestFunction(HostToGuestTrampolinePtr*, void* HostPacker); - __attribute__((weak)) - void* GetGuestStack(); +__attribute__((weak)) void* GetGuestStack(); - __attribute__((weak)) - void MoveGuestStack(uintptr_t NewAddress); -} +__attribute__((weak)) void MoveGuestStack(uintptr_t NewAddress); +} // namespace FEXCore template struct function_traits; template -struct function_traits { - using result_t = Result; - using arg_t = Arg; +struct function_traits { + using result_t = Result; + using arg_t = Arg; }; template -static typename function_traits::result_t -fexfn_type_erased_unpack(void* argsv) { - using args_t = typename function_traits::arg_t; - return Fn(reinterpret_cast(argsv)); +static typename function_traits::result_t fexfn_type_erased_unpack(void* argsv) { + using args_t = typename function_traits::arg_t; + return Fn(reinterpret_cast(argsv)); } -struct ExportEntry { uint8_t* sha256; void(*fn)(void *); }; +struct ExportEntry { + uint8_t* sha256; + void (*fn)(void*); +}; -typedef void fex_call_callback_t(uintptr_t callback, void *arg0, void* arg1); +typedef void fex_call_callback_t(uintptr_t callback, void* arg0, void* arg1); #define EXPORTS(name) \ extern "C" { \ - ExportEntry* fexthunks_exports_##name() { \ - if (!fexldr_init_##name()) { \ - return nullptr; \ - } \ - return exports; \ + ExportEntry* fexthunks_exports_##name() { \ + if (!fexldr_init_##name()) { \ + return nullptr; \ } \ + return exports; \ + } \ } #define LOAD_LIB_INIT(init_fn) \ - __attribute__((constructor)) static void loadlib() \ - { \ - init_fn (); \ + __attribute__((constructor)) static void loadlib() { \ + init_fn(); \ } struct GuestcallInfo { @@ -84,22 +79,21 @@ struct GuestcallInfo { // host register. This macro must be placed at the very beginning of // the function it is used in. #if defined(_M_X86_64) -#define LOAD_INTERNAL_GUESTPTR_VIA_CUSTOM_ABI(target_variable) \ - asm volatile("mov %%r11, %0" : "=r" (target_variable)) +#define LOAD_INTERNAL_GUESTPTR_VIA_CUSTOM_ABI(target_variable) asm volatile("mov %%r11, %0" : "=r"(target_variable)) #elif defined(_M_ARM_64) -#define LOAD_INTERNAL_GUESTPTR_VIA_CUSTOM_ABI(target_variable) \ - asm volatile("mov %0, x11" : "=r" (target_variable)) +#define LOAD_INTERNAL_GUESTPTR_VIA_CUSTOM_ABI(target_variable) asm volatile("mov %0, x11" : "=r"(target_variable)) #endif struct ParameterAnnotations { - bool is_passthrough = false; - bool assume_compatible = false; + bool is_passthrough = false; + bool assume_compatible = false; }; // Generator emits specializations for this for each type that has compatible layout template inline constexpr bool has_compatible_data_layout = - std::is_integral_v || std::is_enum_v || std::is_floating_point_v + std::is_integral_v || std::is_enum_v || + std::is_floating_point_v #ifndef IS_32BIT_THUNK // If none of the previous predicates matched, the thunk generator did *not* emit a specialization for T. // This should not happen on 64-bit with the currently thunked libraries, since their types @@ -109,7 +103,7 @@ inline constexpr bool has_compatible_data_layout = // Throwing a fake exception here will trigger a build failure. || (throw "Instantiated on a type that was expected to be compatible", true) #endif -; + ; #ifndef IS_32BIT_THUNK // Pointers have the same size, hence data layout compatibility only depends on the pointee type @@ -119,10 +113,14 @@ template inline constexpr bool has_compatible_data_layout = has_compatible_data_layout*>; // void* and void** are assumed to be compatible to simplify handling of libraries that use them ubiquitously -template<> inline constexpr bool has_compatible_data_layout = true; -template<> inline constexpr bool has_compatible_data_layout = true; -template<> inline constexpr bool has_compatible_data_layout = true; -template<> inline constexpr bool has_compatible_data_layout = true; +template<> +inline constexpr bool has_compatible_data_layout = true; +template<> +inline constexpr bool has_compatible_data_layout = true; +template<> +inline constexpr bool has_compatible_data_layout = true; +template<> +inline constexpr bool has_compatible_data_layout = true; #endif // Placeholder type to indicate the given data is in guest-layout @@ -154,26 +152,27 @@ struct guest_layout { type data; // Allow implicit conversion for function pointers, since they disallow use of host_layout - guest_layout& operator=(const T* from) requires (std::is_function_v) { + guest_layout& operator=(const T* from) requires (std::is_function_v) + { // TODO: Assert upper 32 bits are zero data = reinterpret_cast(from); return *this; } guest_layout* get_pointer() { - return reinterpret_cast*>(uintptr_t { data }); + return reinterpret_cast*>(uintptr_t {data}); } const guest_layout* get_pointer() const { - return reinterpret_cast*>(uintptr_t { data }); + return reinterpret_cast*>(uintptr_t {data}); } T* force_get_host_pointer() { - return reinterpret_cast(uintptr_t { data }); + return reinterpret_cast(uintptr_t {data}); } const T* force_get_host_pointer() const { - return reinterpret_cast(uintptr_t { data }); + return reinterpret_cast(uintptr_t {data}); } }; @@ -187,18 +186,19 @@ struct guest_layout { type data; // Allow implicit conversion for function pointers, since they disallow use of host_layout - guest_layout& operator=(const T* from) requires (std::is_function_v) { + guest_layout& operator=(const T* from) requires (std::is_function_v) + { // TODO: Assert upper 32 bits are zero data = reinterpret_cast(from); return *this; } guest_layout* get_pointer() { - return reinterpret_cast*>(uintptr_t { data }); + return reinterpret_cast*>(uintptr_t {data}); } const guest_layout* get_pointer() const { - return reinterpret_cast*>(uintptr_t { data }); + return reinterpret_cast*>(uintptr_t {data}); } }; @@ -215,23 +215,25 @@ struct host_layout { T data; - explicit host_layout(const guest_layout& from) requires (!std::is_enum_v) : data { from.data } { + explicit host_layout(const guest_layout& from) requires (!std::is_enum_v) + : data {from.data} { // NOTE: This is not strictly neccessary since differently sized types may // be used across architectures. It's important that the host type // can represent all guest values without loss, however. static_assert(sizeof(data) == sizeof(from)); } - explicit host_layout(const guest_layout& from) requires (std::is_enum_v) : data { static_cast(from.data) } { - } + explicit host_layout(const guest_layout& from) requires (std::is_enum_v) + : data {static_cast(from.data)} {} // Allow conversion of integral types of smaller or equal size and same sign // to each other. Zero-extension is applied if needed. // Notably, this is useful for handling "long"/"long long" on 64-bit, as well // as uint8_t/char. template - explicit host_layout(const guest_layout& from) requires (std::is_integral_v && sizeof(U) <= sizeof(T) && std::is_convertible_v && std::is_signed_v == std::is_signed_v) : data { static_cast(from.data) } { - } + explicit host_layout(const guest_layout& from) + requires (std::is_integral_v && sizeof(U) <= sizeof(T) && std::is_convertible_v && std::is_signed_v == std::is_signed_v) + : data {static_cast(from.data)} {} }; // Explicitly turn a host type into its corresponding host_layout @@ -243,10 +245,7 @@ const host_layout& to_host_layout(const T& t) { template constexpr bool is_long_or_longlong = - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; + std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; template struct host_layout { @@ -255,8 +254,8 @@ struct host_layout { static_assert(!std::is_function_v, "Function types must be handled separately"); // Assume underlying data is compatible and just convert the guest-sized pointer to 64-bit - explicit host_layout(const guest_layout& from) : data { (T*)(uintptr_t)from.data } { - } + explicit host_layout(const guest_layout& from) + : data {(T*)(uintptr_t)from.data} {} host_layout() = default; @@ -264,25 +263,30 @@ struct host_layout { // This is useful for handling "long"/"long long" on 64-bit, which are distinct types // but have equal data layout. template - explicit host_layout(const guest_layout& from) requires (is_long_or_longlong> && std::is_integral_v && std::is_convertible_v && std::is_signed_v == std::is_signed_v + explicit host_layout(const guest_layout& from) + requires (is_long_or_longlong> && std::is_integral_v && std::is_convertible_v && + std::is_signed_v == std::is_signed_v #if __clang_major__ >= 16 - // Old clang versions don't support using sizeof on incomplete types when evaluating requires() - && sizeof(T) == sizeof(U) + // Old clang versions don't support using sizeof on incomplete types when evaluating requires() + && sizeof(T) == sizeof(U) #endif - ) : data { (T*)(uintptr_t)from.data } { + ) + : data {(T*)(uintptr_t)from.data} { } // Allow conversion of pointers to 8-bit integer types to "char*". // This is useful since "char"/"signed char"/"unsigned char"/"int8_t"/"uint8_t" // may all be distinct types but have equal data layout template - explicit host_layout(const guest_layout& from) requires (std::is_same_v, char> && std::is_integral_v && std::is_convertible_v && sizeof(U) == 1) : data { (T*)(uintptr_t)from.data } { - } + explicit host_layout(const guest_layout& from) + requires (std::is_same_v, char> && std::is_integral_v && std::is_convertible_v && sizeof(U) == 1) + : data {(T*)(uintptr_t)from.data} {} // Allow conversion of pointers to 32-bit integer types to "wchar_t*". template - explicit host_layout(const guest_layout& from) requires (std::is_same_v, wchar_t> && std::is_integral_v && std::is_convertible_v && sizeof(U) == sizeof(wchar_t)) : data { (T*)(uintptr_t)from.data } { - } + explicit host_layout(const guest_layout& from) requires ( + std::is_same_v, wchar_t> && std::is_integral_v && std::is_convertible_v && sizeof(U) == sizeof(wchar_t)) + : data {(T*)(uintptr_t)from.data} {} }; template @@ -292,8 +296,8 @@ struct host_layout { static_assert(!std::is_function_v, "Function types must be handled separately"); // Assume underlying data is compatible and just convert the guest-sized pointer to 64-bit - explicit host_layout(const guest_layout& from) : data { (T*)(uintptr_t)from.data } { - } + explicit host_layout(const guest_layout& from) + : data {(T*)(uintptr_t)from.data} {} }; // Wrapper around host_layout that repacks from a guest_layout on construction @@ -311,9 +315,10 @@ struct repack_wrapper { std::optional> data; guest_layout& orig_arg; - repack_wrapper(guest_layout& orig_arg_) : orig_arg(orig_arg_) { + repack_wrapper(guest_layout& orig_arg_) + : orig_arg(orig_arg_) { if (orig_arg.get_pointer()) { - data = { *orig_arg_.get_pointer() }; + data = {*orig_arg_.get_pointer()}; if constexpr (!std::is_enum_v) { constexpr bool is_compatible = has_compatible_data_layout && std::is_same_v; @@ -326,7 +331,11 @@ struct repack_wrapper { ~repack_wrapper() { // TODO: Properly detect opaque types - if constexpr (std::is_class_v> && requires(guest_layout t, decltype(data) h) { t.get_pointer(); (bool)h; *data; }) { + if constexpr (std::is_class_v> && requires(guest_layout t, decltype(data) h) { + t.get_pointer(); + (bool)h; + *data; + }) { if (data) { // NOTE: It's assumed that the native host library didn't modify any // const-pointees, so we skip automatic exit repacking for them. @@ -353,7 +362,7 @@ struct repack_wrapper { template static repack_wrapper make_repack_wrapper(guest_layout& orig_arg) { - return { orig_arg }; + return {orig_arg}; } template @@ -371,17 +380,19 @@ struct host_to_guest_convertible { const host_layout& from; // Conversion from host to guest layout for non-pointers - operator guest_layout() const requires(!std::is_pointer_v) { + operator guest_layout() const requires (!std::is_pointer_v) + { if constexpr (std::is_enum_v) { // enums are represented by fixed-size integers in guest_layout, so explicitly cast them - return guest_layout { static_cast>(from.data) }; + return guest_layout {static_cast>(from.data)}; } else { - guest_layout ret { .data = from.data }; + guest_layout ret {.data = from.data}; return ret; } } - operator guest_layout() const requires(std::is_pointer_v) { + operator guest_layout() const requires (std::is_pointer_v) + { // TODO: Assert upper 32 bits are zero guest_layout ret; ret.data = reinterpret_cast(from.data); @@ -390,28 +401,33 @@ struct host_to_guest_convertible { #if IS_32BIT_THUNK // Allow size_t -> uint32_t conversions, since they are so common on 32-bit - operator guest_layout() const requires(std::is_same_v) { - return { static_cast(from.data) }; + operator guest_layout() const requires (std::is_same_v) + { + return {static_cast(from.data)}; } #endif // Make guest_layout of "long long" and "long" interoperable, since they are // the same type as far as data layout is concerned. - operator guest_layout() const requires(std::is_same_v) { + operator guest_layout() const requires (std::is_same_v) + { return (guest_layout)reinterpret_cast&>(*this); } // Make guest_layout of "char" and "uint8_t" interoperable - operator guest_layout() const requires(std::is_same_v) { + operator guest_layout() const requires (std::is_same_v) + { return (guest_layout)reinterpret_cast&>(*this); } - operator guest_layout() const requires(std::is_same_v) { + operator guest_layout() const requires (std::is_same_v) + { return (guest_layout)reinterpret_cast&>(*this); } // Make guest_layout of "wchar_t" and "uint32_t" interoperable - operator guest_layout() const requires(std::is_same_v) { + operator guest_layout() const requires (std::is_same_v) + { return (guest_layout)reinterpret_cast&>(*this); } @@ -420,14 +436,16 @@ struct host_to_guest_convertible { // Allow conversion of integral types of same size and sign to each other. // This is useful for handling "long"/"long long" on 64-bit, as well as uint8_t/char. template - operator guest_layout() const requires (std::is_integral_v && sizeof(U) == sizeof(T) && std::is_convertible_v && std::is_signed_v == std::is_signed_v) { - return guest_layout { .data { static_cast(from.data) } }; + operator guest_layout() const + requires (std::is_integral_v && sizeof(U) == sizeof(T) && std::is_convertible_v && std::is_signed_v == std::is_signed_v) + { + return guest_layout {.data {static_cast(from.data)}}; } }; template inline host_to_guest_convertible to_guest(const host_layout& from) { - return { from }; + return {from}; } template @@ -453,7 +471,7 @@ auto Projection(guest_layout& data) { if constexpr (Annotation.is_passthrough) { return data; } else if constexpr ((IsCompatible() && std::is_same_v) || !std::is_pointer_v) { - return host_layout { data }.data; + return host_layout {data}.data; } else { // This argument requires temporary storage for repacked data // *and* it needs to call custom repack functions (if any) @@ -481,11 +499,9 @@ public: template T* New(Args&&... args) { Next -= sizeof(T); - Next &= ~uintptr_t { alignof(T) - 1 }; + Next &= ~uintptr_t {alignof(T) - 1}; FEXCore::MoveGuestStack(Next); - return new (reinterpret_cast(Next)) T { - std::forward(args)... - }; + return new (reinterpret_cast(Next)) T {std::forward(args)...}; } }; #endif @@ -493,18 +509,14 @@ public: template struct CallbackUnpack { static Result CallGuestPtr(Args... args) { - GuestcallInfo *guestcall; + GuestcallInfo* guestcall; LOAD_INTERNAL_GUESTPTR_VIA_CUSTOM_ABI(guestcall); #ifndef IS_32BIT_THUNK - PackedArguments...> packed_args = { - to_guest(to_host_layout(args))... - }; + PackedArguments...> packed_args = {to_guest(to_host_layout(args))...}; #else GuestStackBumpAllocator GuestStack; - auto& packed_args = *GuestStack.New...>>( - to_guest(to_host_layout(args))... - ); + auto& packed_args = *GuestStack.New...>>(to_guest(to_host_layout(args))...); #endif guestcall->CallCallback(guestcall->GuestUnpacker, guestcall->GuestTarget, &packed_args); @@ -530,51 +542,51 @@ struct GuestWrapperForHostFunction { constexpr auto CBIndex = sizeof...(GuestArgs); uintptr_t cb; static_assert(CBIndex <= 18 || CBIndex == 23); - if constexpr(CBIndex == 0) { + if constexpr (CBIndex == 0) { cb = args->a0; - } else if constexpr(CBIndex == 1) { + } else if constexpr (CBIndex == 1) { cb = args->a1; - } else if constexpr(CBIndex == 2) { + } else if constexpr (CBIndex == 2) { cb = args->a2; - } else if constexpr(CBIndex == 3) { + } else if constexpr (CBIndex == 3) { cb = args->a3; - } else if constexpr(CBIndex == 4) { + } else if constexpr (CBIndex == 4) { cb = args->a4; - } else if constexpr(CBIndex == 5) { + } else if constexpr (CBIndex == 5) { cb = args->a5; - } else if constexpr(CBIndex == 6) { + } else if constexpr (CBIndex == 6) { cb = args->a6; - } else if constexpr(CBIndex == 7) { + } else if constexpr (CBIndex == 7) { cb = args->a7; - } else if constexpr(CBIndex == 8) { + } else if constexpr (CBIndex == 8) { cb = args->a8; - } else if constexpr(CBIndex == 9) { + } else if constexpr (CBIndex == 9) { cb = args->a9; - } else if constexpr(CBIndex == 10) { + } else if constexpr (CBIndex == 10) { cb = args->a10; - } else if constexpr(CBIndex == 11) { + } else if constexpr (CBIndex == 11) { cb = args->a11; - } else if constexpr(CBIndex == 12) { + } else if constexpr (CBIndex == 12) { cb = args->a12; - } else if constexpr(CBIndex == 13) { + } else if constexpr (CBIndex == 13) { cb = args->a13; - } else if constexpr(CBIndex == 14) { + } else if constexpr (CBIndex == 14) { cb = args->a14; - } else if constexpr(CBIndex == 15) { + } else if constexpr (CBIndex == 15) { cb = args->a15; - } else if constexpr(CBIndex == 16) { + } else if constexpr (CBIndex == 16) { cb = args->a16; - } else if constexpr(CBIndex == 17) { + } else if constexpr (CBIndex == 17) { cb = args->a17; - } else if constexpr(CBIndex == 18) { + } else if constexpr (CBIndex == 18) { cb = args->a18; - } else if constexpr(CBIndex == 23) { + } else if constexpr (CBIndex == 23) { cb = args->a23; } // This is almost the same type as "Result func(Args..., uintptr_t)", but // individual parameters annotated as passthrough are replaced by guest_layout - auto callback = reinterpret_cast, Args>..., uintptr_t)>(cb); + auto callback = reinterpret_cast, Args>..., uintptr_t)>(cb); auto f = [&callback](guest_layout... args, uintptr_t target) -> Result { // Fold over each of Annotations, Args, and args. This will match up the elements in triplets. @@ -585,25 +597,20 @@ struct GuestWrapperForHostFunction { }; template -void MakeHostTrampolineForGuestFunctionAt(uintptr_t GuestTarget, uintptr_t GuestUnpacker, FuncType **Func) { - *Func = (FuncType*)FEXCore::MakeHostTrampolineForGuestFunction( - (void*)&CallbackUnpack::CallGuestPtr, - GuestTarget, - GuestUnpacker); +void MakeHostTrampolineForGuestFunctionAt(uintptr_t GuestTarget, uintptr_t GuestUnpacker, FuncType** Func) { + *Func = (FuncType*)FEXCore::MakeHostTrampolineForGuestFunction((void*)&CallbackUnpack::CallGuestPtr, GuestTarget, GuestUnpacker); } template void FinalizeHostTrampolineForGuestFunction(F* PreallocatedTrampolineForGuestFunction) { - FEXCore::FinalizeHostTrampolineForGuestFunction( - (FEXCore::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction, - (void*)&CallbackUnpack::CallGuestPtr); + FEXCore::FinalizeHostTrampolineForGuestFunction((FEXCore::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction, + (void*)&CallbackUnpack::CallGuestPtr); } template void FinalizeHostTrampolineForGuestFunction(guest_layout PreallocatedTrampolineForGuestFunction) { - FEXCore::FinalizeHostTrampolineForGuestFunction( - (FEXCore::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction.data, - (void*)&CallbackUnpack::CallGuestPtr); + FEXCore::FinalizeHostTrampolineForGuestFunction((FEXCore::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction.data, + (void*)&CallbackUnpack::CallGuestPtr); } // In the case of the thunk host_loader being the default, FEX need to use dlsym with RTLD_DEFAULT. @@ -612,7 +619,6 @@ void FinalizeHostTrampolineForGuestFunction(guest_layout PreallocatedTrampol // Common usecase is LD_PRELOAD with a library that defines some symbols. // And then programs and libraries will pick up the preloaded symbols. // ex: MangoHud overrides GLX and EGL symbols. -inline -void *dlsym_default(void* handle, const char* symbol) { +inline void* dlsym_default(void* handle, const char* symbol) { return dlsym(RTLD_DEFAULT, symbol); } diff --git a/ThunkLibs/include/common/PackedArguments.h b/ThunkLibs/include/common/PackedArguments.h index 16f0f258a..4a9efcbf5 100644 --- a/ThunkLibs/include/common/PackedArguments.h +++ b/ThunkLibs/include/common/PackedArguments.h @@ -8,100 +8,513 @@ template struct __attribute__((packed)) PackedArguments; template -struct __attribute__((packed)) PackedArguments { R rv; }; +struct __attribute__((packed)) PackedArguments { + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; R rv; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + R rv; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; R rv; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; R rv; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; R rv; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; R rv; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; R rv; }; - -template -struct __attribute__((packed)) PackedArguments { - A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; - A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; A18 a18; A19 a19; - A20 a20; A21 a21; A22 a22; R rv; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + R rv; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + R rv; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + R rv; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + R rv; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; + R rv; }; -template -struct __attribute__((packed)) PackedArguments { - A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; - A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; A18 a18; A19 a19; - A20 a20; A21 a21; A22 a22; A23 a23; R rv; +template +struct __attribute__((packed)) +PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; + A15 a15; + A16 a16; + A17 a17; + A18 a18; + A19 a19; + A20 a20; + A21 a21; + A22 a22; + R rv; +}; + +template +struct __attribute__((packed)) +PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; + A15 a15; + A16 a16; + A17 a17; + A18 a18; + A19 a19; + A20 a20; + A21 a21; + A22 a22; + A23 a23; + R rv; }; template<> -struct __attribute__((packed)) PackedArguments { }; +struct __attribute__((packed)) PackedArguments {}; template -struct __attribute__((packed)) PackedArguments { A0 a0; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; +}; template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; }; -template -struct __attribute__((packed)) PackedArguments { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; A18 a18; }; +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; + A15 a15; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; + A15 a15; + A16 a16; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; + A15 a15; + A16 a16; + A17 a17; +}; +template +struct __attribute__((packed)) PackedArguments { + A0 a0; + A1 a1; + A2 a2; + A3 a3; + A4 a4; + A5 a5; + A6 a6; + A7 a7; + A8 a8; + A9 a9; + A10 a10; + A11 a11; + A12 a12; + A13 a13; + A14 a14; + A15 a15; + A16 a16; + A17 a17; + A18 a18; +}; // Helper struct that allows assigning the result of a function to a variable, even if that result is a void type. // @@ -110,60 +523,75 @@ struct __attribute__((packed)) PackedArguments T&& operator,(T&& t, Regularize) { - return std::forward(t); + return std::forward(t); } template -void Invoke(Func&& func, PackedArguments& args) requires(std::is_invocable_r_v) { - constexpr auto NumArgs = sizeof...(Args); - static_assert(NumArgs <= 19 || NumArgs == 24); +void Invoke(Func&& func, PackedArguments& args) requires (std::is_invocable_r_v) +{ + constexpr auto NumArgs = sizeof...(Args); + static_assert(NumArgs <= 19 || NumArgs == 24); - std::conditional_t, Regularize, Result> rv; - if constexpr (NumArgs == 0) { - rv = (func(), Regularize{}); - } else if constexpr (NumArgs == 1) { - rv = (func(args.a0), Regularize {}); - } else if constexpr (NumArgs == 2) { - rv = (func(args.a0, args.a1), Regularize{}); - } else if constexpr (NumArgs == 3) { - rv = (func(args.a0, args.a1, args.a2), Regularize{}); - } else if constexpr (NumArgs == 4) { - rv = (func(args.a0, args.a1, args.a2, args.a3), Regularize{}); - } else if constexpr (NumArgs == 5) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4), Regularize{}); - } else if constexpr (NumArgs == 6) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5), Regularize{}); - } else if constexpr (NumArgs == 7) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6), Regularize{}); - } else if constexpr (NumArgs == 8) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7), Regularize{}); - } else if constexpr (NumArgs == 9) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8), Regularize{}); - } else if constexpr (NumArgs == 10) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9), Regularize{}); - } else if constexpr (NumArgs == 11) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10), Regularize{}); - } else if constexpr (NumArgs == 12) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11), Regularize{}); - } else if constexpr (NumArgs == 13) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12), Regularize{}); - } else if constexpr (NumArgs == 14) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13), Regularize{}); - } else if constexpr (NumArgs == 15) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13, args.a14), Regularize{}); - } else if constexpr (NumArgs == 16) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13, args.a14, args.a15), Regularize{}); - } else if constexpr (NumArgs == 17) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13, args.a14, args.a15, args.a16), Regularize{}); - } else if constexpr (NumArgs == 18) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13, args.a14, args.a15, args.a16, args.a17), Regularize{}); - } else if constexpr (NumArgs == 19) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13, args.a14, args.a15, args.a16, args.a17, args.a18), Regularize{}); - } else if constexpr (NumArgs == 24) { - rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13, args.a14, args.a15, args.a16, args.a17, args.a18, args.a19, args.a20, args.a21, args.a22, args.a23), Regularize{}); - } + std::conditional_t, Regularize, Result> rv; + if constexpr (NumArgs == 0) { + rv = (func(), Regularize {}); + } else if constexpr (NumArgs == 1) { + rv = (func(args.a0), Regularize {}); + } else if constexpr (NumArgs == 2) { + rv = (func(args.a0, args.a1), Regularize {}); + } else if constexpr (NumArgs == 3) { + rv = (func(args.a0, args.a1, args.a2), Regularize {}); + } else if constexpr (NumArgs == 4) { + rv = (func(args.a0, args.a1, args.a2, args.a3), Regularize {}); + } else if constexpr (NumArgs == 5) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4), Regularize {}); + } else if constexpr (NumArgs == 6) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5), Regularize {}); + } else if constexpr (NumArgs == 7) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6), Regularize {}); + } else if constexpr (NumArgs == 8) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7), Regularize {}); + } else if constexpr (NumArgs == 9) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8), Regularize {}); + } else if constexpr (NumArgs == 10) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9), Regularize {}); + } else if constexpr (NumArgs == 11) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10), Regularize {}); + } else if constexpr (NumArgs == 12) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11), Regularize {}); + } else if constexpr (NumArgs == 13) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12), + Regularize {}); + } else if constexpr (NumArgs == 14) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, args.a13), + Regularize {}); + } else if constexpr (NumArgs == 15) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, + args.a13, args.a14), + Regularize {}); + } else if constexpr (NumArgs == 16) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, + args.a13, args.a14, args.a15), + Regularize {}); + } else if constexpr (NumArgs == 17) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, + args.a13, args.a14, args.a15, args.a16), + Regularize {}); + } else if constexpr (NumArgs == 18) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, + args.a13, args.a14, args.a15, args.a16, args.a17), + Regularize {}); + } else if constexpr (NumArgs == 19) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, + args.a13, args.a14, args.a15, args.a16, args.a17, args.a18), + Regularize {}); + } else if constexpr (NumArgs == 24) { + rv = (func(args.a0, args.a1, args.a2, args.a3, args.a4, args.a5, args.a6, args.a7, args.a8, args.a9, args.a10, args.a11, args.a12, + args.a13, args.a14, args.a15, args.a16, args.a17, args.a18, args.a19, args.a20, args.a21, args.a22, args.a23), + Regularize {}); + } - if constexpr (!std::is_void_v) { - args.rv = rv; - } + if constexpr (!std::is_void_v) { + args.rv = rv; + } } diff --git a/ThunkLibs/libEGL/libEGL_Guest.cpp b/ThunkLibs/libEGL/libEGL_Guest.cpp index 78f4890de..c157f00eb 100644 --- a/ThunkLibs/libEGL/libEGL_Guest.cpp +++ b/ThunkLibs/libEGL/libEGL_Guest.cpp @@ -19,10 +19,10 @@ typedef void voidFunc(); extern "C" { - voidFunc *eglGetProcAddress(const char *procname) { - // TODO: Fix this HACK - return glXGetProcAddress((const GLubyte*)procname); - } +voidFunc* eglGetProcAddress(const char* procname) { + // TODO: Fix this HACK + return glXGetProcAddress((const GLubyte*)procname); +} } LOAD_LIB(libEGL) diff --git a/ThunkLibs/libEGL/libEGL_interface.cpp b/ThunkLibs/libEGL/libEGL_interface.cpp index c9bb2d1cc..27de16df3 100644 --- a/ThunkLibs/libEGL/libEGL_interface.cpp +++ b/ThunkLibs/libEGL/libEGL_interface.cpp @@ -4,30 +4,48 @@ template struct fex_gen_config { - unsigned version = 1; + unsigned version = 1; }; // Function, parameter index, parameter type [optional] template struct fex_gen_param {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; // EGLNativeDisplayType is a pointer to opaque data (wl_display/(X)Display/...) -template<> struct fex_gen_config {}; -template<> struct fex_gen_param : fexgen::assume_compatible_data_layout {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_param : fexgen::assume_compatible_data_layout {}; diff --git a/ThunkLibs/libGL/glcorearb.h b/ThunkLibs/libGL/glcorearb.h index 7a4413826..60c8aa6ec 100644 --- a/ThunkLibs/libGL/glcorearb.h +++ b/ThunkLibs/libGL/glcorearb.h @@ -45,7 +45,7 @@ extern "C" { #define APIENTRY #endif #ifndef APIENTRYP -#define APIENTRYP APIENTRY * +#define APIENTRYP APIENTRY* #endif #ifndef GLAPI #define GLAPI extern @@ -56,7 +56,7 @@ extern "C" { ** included as . ** ** glcorearb.h includes only APIs in the latest OpenGL core profile -** implementation together with APIs in newer ARB extensions which +** implementation together with APIs in newer ARB extensions which ** can be supported by the core profile. It does not, and never will ** include functionality removed from the core profile, such as ** fixed-function vertex and fragment processing. @@ -88,276 +88,280 @@ typedef double GLdouble; typedef unsigned int GLuint; typedef unsigned char GLboolean; typedef khronos_uint8_t GLubyte; -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_FALSE 0 -#define GL_TRUE 1 -#define GL_POINTS 0x0000 -#define GL_LINES 0x0001 -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_STRIP 0x0003 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_FAN 0x0006 -#define GL_QUADS 0x0007 -#define GL_NEVER 0x0200 -#define GL_LESS 0x0201 -#define GL_EQUAL 0x0202 -#define GL_LEQUAL 0x0203 -#define GL_GREATER 0x0204 -#define GL_NOTEQUAL 0x0205 -#define GL_GEQUAL 0x0206 -#define GL_ALWAYS 0x0207 -#define GL_ZERO 0 -#define GL_ONE 1 -#define GL_SRC_COLOR 0x0300 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_SRC_ALPHA 0x0302 -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_DST_ALPHA 0x0304 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_DST_COLOR 0x0306 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_SRC_ALPHA_SATURATE 0x0308 -#define GL_NONE 0 -#define GL_FRONT_LEFT 0x0400 -#define GL_FRONT_RIGHT 0x0401 -#define GL_BACK_LEFT 0x0402 -#define GL_BACK_RIGHT 0x0403 -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 -#define GL_FRONT_AND_BACK 0x0408 -#define GL_NO_ERROR 0 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVALID_OPERATION 0x0502 -#define GL_OUT_OF_MEMORY 0x0505 -#define GL_CW 0x0900 -#define GL_CCW 0x0901 -#define GL_POINT_SIZE 0x0B11 -#define GL_POINT_SIZE_RANGE 0x0B12 -#define GL_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_LINE_SMOOTH 0x0B20 -#define GL_LINE_WIDTH 0x0B21 -#define GL_LINE_WIDTH_RANGE 0x0B22 -#define GL_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_POLYGON_MODE 0x0B40 -#define GL_POLYGON_SMOOTH 0x0B41 -#define GL_CULL_FACE 0x0B44 -#define GL_CULL_FACE_MODE 0x0B45 -#define GL_FRONT_FACE 0x0B46 -#define GL_DEPTH_RANGE 0x0B70 -#define GL_DEPTH_TEST 0x0B71 -#define GL_DEPTH_WRITEMASK 0x0B72 -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_DEPTH_FUNC 0x0B74 -#define GL_STENCIL_TEST 0x0B90 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_STENCIL_FUNC 0x0B92 -#define GL_STENCIL_VALUE_MASK 0x0B93 -#define GL_STENCIL_FAIL 0x0B94 -#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define GL_STENCIL_REF 0x0B97 -#define GL_STENCIL_WRITEMASK 0x0B98 -#define GL_VIEWPORT 0x0BA2 -#define GL_DITHER 0x0BD0 -#define GL_BLEND_DST 0x0BE0 -#define GL_BLEND_SRC 0x0BE1 -#define GL_BLEND 0x0BE2 -#define GL_LOGIC_OP_MODE 0x0BF0 -#define GL_DRAW_BUFFER 0x0C01 -#define GL_READ_BUFFER 0x0C02 -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_COLOR_WRITEMASK 0x0C23 -#define GL_DOUBLEBUFFER 0x0C32 -#define GL_STEREO 0x0C33 -#define GL_LINE_SMOOTH_HINT 0x0C52 -#define GL_POLYGON_SMOOTH_HINT 0x0C53 -#define GL_UNPACK_SWAP_BYTES 0x0CF0 -#define GL_UNPACK_LSB_FIRST 0x0CF1 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_PACK_SWAP_BYTES 0x0D00 -#define GL_PACK_LSB_FIRST 0x0D01 -#define GL_PACK_ROW_LENGTH 0x0D02 -#define GL_PACK_SKIP_ROWS 0x0D03 -#define GL_PACK_SKIP_PIXELS 0x0D04 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_VIEWPORT_DIMS 0x0D3A -#define GL_SUBPIXEL_BITS 0x0D50 -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_TEXTURE_WIDTH 0x1000 -#define GL_TEXTURE_HEIGHT 0x1001 -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_DONT_CARE 0x1100 -#define GL_FASTEST 0x1101 -#define GL_NICEST 0x1102 -#define GL_BYTE 0x1400 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_SHORT 0x1402 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_INT 0x1404 -#define GL_UNSIGNED_INT 0x1405 -#define GL_FLOAT 0x1406 -#define GL_STACK_OVERFLOW 0x0503 -#define GL_STACK_UNDERFLOW 0x0504 -#define GL_CLEAR 0x1500 -#define GL_AND 0x1501 -#define GL_AND_REVERSE 0x1502 -#define GL_COPY 0x1503 -#define GL_AND_INVERTED 0x1504 -#define GL_NOOP 0x1505 -#define GL_XOR 0x1506 -#define GL_OR 0x1507 -#define GL_NOR 0x1508 -#define GL_EQUIV 0x1509 -#define GL_INVERT 0x150A -#define GL_OR_REVERSE 0x150B -#define GL_COPY_INVERTED 0x150C -#define GL_OR_INVERTED 0x150D -#define GL_NAND 0x150E -#define GL_SET 0x150F -#define GL_TEXTURE 0x1702 -#define GL_COLOR 0x1800 -#define GL_DEPTH 0x1801 -#define GL_STENCIL 0x1802 -#define GL_STENCIL_INDEX 0x1901 -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_RED 0x1903 -#define GL_GREEN 0x1904 -#define GL_BLUE 0x1905 -#define GL_ALPHA 0x1906 -#define GL_RGB 0x1907 -#define GL_RGBA 0x1908 -#define GL_POINT 0x1B00 -#define GL_LINE 0x1B01 -#define GL_FILL 0x1B02 -#define GL_KEEP 0x1E00 -#define GL_REPLACE 0x1E01 -#define GL_INCR 0x1E02 -#define GL_DECR 0x1E03 -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_REPEAT 0x2901 -typedef void (APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); -typedef void (APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); -typedef void (APIENTRYP PFNGLPOINTSIZEPROC) (GLfloat size); -typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode); -typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLDRAWBUFFERPROC) (GLenum buf); -typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); -typedef void (APIENTRYP PFNGLCLEARDEPTHPROC) (GLdouble depth); -typedef void (APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); -typedef void (APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -typedef void (APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); -typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap); -typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap); -typedef void (APIENTRYP PFNGLFINISHPROC) (void); -typedef void (APIENTRYP PFNGLFLUSHPROC) (void); -typedef void (APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); -typedef void (APIENTRYP PFNGLLOGICOPPROC) (GLenum opcode); -typedef void (APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); -typedef void (APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); -typedef void (APIENTRYP PFNGLPIXELSTOREFPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLREADBUFFERPROC) (GLenum src); -typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); -typedef void (APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data); -typedef void (APIENTRYP PFNGLGETDOUBLEVPROC) (GLenum pname, GLdouble *data); -typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void); -typedef void (APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); -typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); -typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); -typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC) (GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); -typedef void (APIENTRYP PFNGLDEPTHRANGEPROC) (GLdouble n, GLdouble f); -typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_REPEAT 0x2901 +typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +typedef void(APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +typedef void(APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +typedef void(APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +typedef void(APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); +typedef void(APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +typedef void(APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, + GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); +typedef void(APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +typedef void(APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void(APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +typedef void(APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); +typedef void(APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +typedef void(APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void(APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +typedef void(APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +typedef void(APIENTRYP PFNGLENABLEPROC)(GLenum cap); +typedef void(APIENTRYP PFNGLFINISHPROC)(void); +typedef void(APIENTRYP PFNGLFLUSHPROC)(void); +typedef void(APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +typedef void(APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); +typedef void(APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +typedef void(APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +typedef void(APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +typedef void(APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); +typedef void(APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); +typedef void(APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean* data); +typedef void(APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble* data); +typedef GLenum(APIENTRYP PFNGLGETERRORPROC)(void); +typedef void(APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat* data); +typedef void(APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint* data); +typedef const GLubyte*(APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +typedef void(APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +typedef void(APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint* params); +typedef GLboolean(APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +typedef void(APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); +typedef void(APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCullFace (GLenum mode); -GLAPI void APIENTRY glFrontFace (GLenum mode); -GLAPI void APIENTRY glHint (GLenum target, GLenum mode); -GLAPI void APIENTRY glLineWidth (GLfloat width); -GLAPI void APIENTRY glPointSize (GLfloat size); -GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode); -GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glDrawBuffer (GLenum buf); -GLAPI void APIENTRY glClear (GLbitfield mask); -GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI void APIENTRY glClearStencil (GLint s); -GLAPI void APIENTRY glClearDepth (GLdouble depth); -GLAPI void APIENTRY glStencilMask (GLuint mask); -GLAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -GLAPI void APIENTRY glDepthMask (GLboolean flag); -GLAPI void APIENTRY glDisable (GLenum cap); -GLAPI void APIENTRY glEnable (GLenum cap); -GLAPI void APIENTRY glFinish (void); -GLAPI void APIENTRY glFlush (void); -GLAPI void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); -GLAPI void APIENTRY glLogicOp (GLenum opcode); -GLAPI void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); -GLAPI void APIENTRY glDepthFunc (GLenum func); -GLAPI void APIENTRY glPixelStoref (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param); -GLAPI void APIENTRY glReadBuffer (GLenum src); -GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); -GLAPI void APIENTRY glGetBooleanv (GLenum pname, GLboolean *data); -GLAPI void APIENTRY glGetDoublev (GLenum pname, GLdouble *data); -GLAPI GLenum APIENTRY glGetError (void); -GLAPI void APIENTRY glGetFloatv (GLenum pname, GLfloat *data); -GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data); -GLAPI const GLubyte *APIENTRY glGetString (GLenum name); -GLAPI void APIENTRY glGetTexImage (GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI void APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap); -GLAPI void APIENTRY glDepthRange (GLdouble n, GLdouble f); -GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glCullFace(GLenum mode); +GLAPI void APIENTRY glFrontFace(GLenum mode); +GLAPI void APIENTRY glHint(GLenum target, GLenum mode); +GLAPI void APIENTRY glLineWidth(GLfloat width); +GLAPI void APIENTRY glPointSize(GLfloat size); +GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode); +GLAPI void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params); +GLAPI void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params); +GLAPI void APIENTRY glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, + const void* pixels); +GLAPI void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glDrawBuffer(GLenum buf); +GLAPI void APIENTRY glClear(GLbitfield mask); +GLAPI void APIENTRY glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glClearStencil(GLint s); +GLAPI void APIENTRY glClearDepth(GLdouble depth); +GLAPI void APIENTRY glStencilMask(GLuint mask); +GLAPI void APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI void APIENTRY glDepthMask(GLboolean flag); +GLAPI void APIENTRY glDisable(GLenum cap); +GLAPI void APIENTRY glEnable(GLenum cap); +GLAPI void APIENTRY glFinish(void); +GLAPI void APIENTRY glFlush(void); +GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor); +GLAPI void APIENTRY glLogicOp(GLenum opcode); +GLAPI void APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI void APIENTRY glDepthFunc(GLenum func); +GLAPI void APIENTRY glPixelStoref(GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelStorei(GLenum pname, GLint param); +GLAPI void APIENTRY glReadBuffer(GLenum src); +GLAPI void APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); +GLAPI void APIENTRY glGetBooleanv(GLenum pname, GLboolean* data); +GLAPI void APIENTRY glGetDoublev(GLenum pname, GLdouble* data); +GLAPI GLenum APIENTRY glGetError(void); +GLAPI void APIENTRY glGetFloatv(GLenum pname, GLfloat* data); +GLAPI void APIENTRY glGetIntegerv(GLenum pname, GLint* data); +GLAPI const GLubyte* APIENTRY glGetString(GLenum name); +GLAPI void APIENTRY glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +GLAPI void APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params); +GLAPI GLboolean APIENTRY glIsEnabled(GLenum cap); +GLAPI void APIENTRY glDepthRange(GLdouble n, GLdouble f); +GLAPI void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_VERSION_1_0 */ @@ -365,250 +369,274 @@ GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height) #define GL_VERSION_1_1 1 typedef khronos_float_t GLclampf; typedef double GLclampd; -#define GL_COLOR_LOGIC_OP 0x0BF2 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_POLYGON_OFFSET_POINT 0x2A01 -#define GL_POLYGON_OFFSET_LINE 0x2A02 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_TEXTURE_BINDING_1D 0x8068 -#define GL_TEXTURE_BINDING_2D 0x8069 -#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 -#define GL_TEXTURE_RED_SIZE 0x805C -#define GL_TEXTURE_GREEN_SIZE 0x805D -#define GL_TEXTURE_BLUE_SIZE 0x805E -#define GL_TEXTURE_ALPHA_SIZE 0x805F -#define GL_DOUBLE 0x140A -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_2D 0x8064 -#define GL_R3_G3_B2 0x2A10 -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB8 0x8051 -#define GL_RGB10 0x8052 -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGBA2 0x8055 -#define GL_RGBA4 0x8056 -#define GL_RGB5_A1 0x8057 -#define GL_RGBA8 0x8058 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B -#define GL_VERTEX_ARRAY 0x8074 -typedef void (APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); -typedef void (APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, void **params); -typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); -typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DOUBLE 0x140A +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_VERTEX_ARRAY 0x8074 +typedef void(APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +typedef void(APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices); +typedef void(APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void** params); +typedef void(APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +typedef void(APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void(APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, + GLsizei height, GLint border); +typedef void(APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void(APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, + const void* pixels); +typedef void(APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +typedef void(APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint* textures); +typedef void(APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint* textures); +typedef GLboolean(APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); -GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); -GLAPI void APIENTRY glGetPointerv (GLenum pname, void **params); -GLAPI void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); -GLAPI void APIENTRY glCopyTexImage1D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture); -GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); -GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures); -GLAPI GLboolean APIENTRY glIsTexture (GLuint texture); +GLAPI void APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); +GLAPI void APIENTRY glGetPointerv(GLenum pname, void** params); +GLAPI void APIENTRY glPolygonOffset(GLfloat factor, GLfloat units); +GLAPI void APIENTRY glCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); +GLAPI void APIENTRY glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, + GLenum type, const void* pixels); +GLAPI void APIENTRY glBindTexture(GLenum target, GLuint texture); +GLAPI void APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures); +GLAPI void APIENTRY glGenTextures(GLsizei n, GLuint* textures); +GLAPI GLboolean APIENTRY glIsTexture(GLuint texture); #endif #endif /* GL_VERSION_1_1 */ #ifndef GL_VERSION_1_2 #define GL_VERSION_1_2 1 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +typedef void(APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); +typedef void(APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, + GLint y, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); +GLAPI void APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, + GLsizei depth, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, + GLsizei width, GLsizei height); #endif #endif /* GL_VERSION_1_2 */ #ifndef GL_VERSION_1_3 #define GL_VERSION_1_3 1 -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CLAMP_TO_BORDER 0x812D -typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img); +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +typedef void(APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +typedef void(APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLint border, GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, + GLint border, GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, + GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, + GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void* img); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveTexture (GLenum texture); -GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); -GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img); +GLAPI void APIENTRY glActiveTexture(GLenum texture); +GLAPI void APIENTRY glSampleCoverage(GLfloat value, GLboolean invert); +GLAPI void APIENTRY glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCompressedTexImage1D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, + GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCompressedTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, + const void* data); +GLAPI void APIENTRY glGetCompressedTexImage(GLenum target, GLint level, void* img); #endif #endif /* GL_VERSION_1_3 */ #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#define GL_BLEND_COLOR 0x8005 -#define GL_BLEND_EQUATION 0x8009 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_FUNC_SUBTRACT 0x800A -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_EQUATION 0x8009 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +typedef void(APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void(APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount); +typedef void(APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount); +typedef void(APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void(APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); -GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); -GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI void APIENTRY glBlendEquation (GLenum mode); +GLAPI void APIENTRY glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI void APIENTRY glMultiDrawArrays(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount); +GLAPI void APIENTRY glMultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount); +GLAPI void APIENTRY glPointParameterf(GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfv(GLenum pname, const GLfloat* params); +GLAPI void APIENTRY glPointParameteri(GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameteriv(GLenum pname, const GLint* params); +GLAPI void APIENTRY glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glBlendEquation(GLenum mode); #endif #endif /* GL_VERSION_1_4 */ @@ -616,73 +644,73 @@ GLAPI void APIENTRY glBlendEquation (GLenum mode); #define GL_VERSION_1_5 1 typedef khronos_ssize_t GLsizeiptr; typedef khronos_intptr_t GLintptr; -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#define GL_SRC1_ALPHA 0x8589 -typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); -typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +typedef void(APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint* ids); +typedef void(APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint* ids); +typedef GLboolean(APIENTRYP PFNGLISQUERYPROC)(GLuint id); +typedef void(APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +typedef void(APIENTRYP PFNGLENDQUERYPROC)(GLenum target); +typedef void(APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +typedef void(APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint* buffers); +typedef void(APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint* buffers); +typedef GLboolean(APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +typedef void(APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void* data, GLenum usage); +typedef void(APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); +typedef void(APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void* data); +typedef void*(APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +typedef GLboolean(APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); +typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void** params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsQuery (GLuint id); -GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); -GLAPI void APIENTRY glEndQuery (GLenum target); -GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); -GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); -GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); -GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); -GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data); -GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); -GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); -GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); +GLAPI void APIENTRY glGenQueries(GLsizei n, GLuint* ids); +GLAPI void APIENTRY glDeleteQueries(GLsizei n, const GLuint* ids); +GLAPI GLboolean APIENTRY glIsQuery(GLuint id); +GLAPI void APIENTRY glBeginQuery(GLenum target, GLuint id); +GLAPI void APIENTRY glEndQuery(GLenum target); +GLAPI void APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetQueryObjectiv(GLuint id, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params); +GLAPI void APIENTRY glBindBuffer(GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers); +GLAPI void APIENTRY glGenBuffers(GLsizei n, GLuint* buffers); +GLAPI GLboolean APIENTRY glIsBuffer(GLuint buffer); +GLAPI void APIENTRY glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage); +GLAPI void APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); +GLAPI void APIENTRY glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void* data); +GLAPI void* APIENTRY glMapBuffer(GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBuffer(GLenum target); +GLAPI void APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, void** params); #endif #endif /* GL_VERSION_1_5 */ @@ -692,417 +720,420 @@ typedef char GLchar; typedef khronos_int16_t GLshort; typedef khronos_int8_t GLbyte; typedef khronos_uint16_t GLushort; -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); -typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); -typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); -typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +typedef void(APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +typedef void(APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum* bufs); +typedef void(APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void(APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void(APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +typedef void(APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +typedef void(APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar* name); +typedef void(APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +typedef GLuint(APIENTRYP PFNGLCREATEPROGRAMPROC)(void); +typedef GLuint(APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +typedef void(APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +typedef void(APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +typedef void(APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void(APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void(APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, + GLchar* name); +typedef void(APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, + GLchar* name); +typedef void(APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders); +typedef GLint(APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar* name); +typedef void(APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +typedef void(APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +typedef void(APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source); +typedef GLint(APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar* name); +typedef void(APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat* params); +typedef void(APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint* params); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble* params); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void** pointer); +typedef GLboolean(APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +typedef GLboolean(APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +typedef void(APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); +typedef void(APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +typedef void(APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void(APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void(APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void(APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +typedef void(APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +typedef void(APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void(APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void(APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +typedef void(APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +typedef void(APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +typedef void(APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void(APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +typedef void(APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +typedef void(APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, + const void* pointer); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); -GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); -GLAPI void APIENTRY glCompileShader (GLuint shader); -GLAPI GLuint APIENTRY glCreateProgram (void); -GLAPI GLuint APIENTRY glCreateShader (GLenum type); -GLAPI void APIENTRY glDeleteProgram (GLuint program); -GLAPI void APIENTRY glDeleteShader (GLuint shader); -GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); -GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); -GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); -GLAPI GLboolean APIENTRY glIsProgram (GLuint program); -GLAPI GLboolean APIENTRY glIsShader (GLuint shader); -GLAPI void APIENTRY glLinkProgram (GLuint program); -GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -GLAPI void APIENTRY glUseProgram (GLuint program); -GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); -GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); -GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glValidateProgram (GLuint program); -GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glDrawBuffers(GLsizei n, const GLenum* bufs); +GLAPI void APIENTRY glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask); +GLAPI void APIENTRY glAttachShader(GLuint program, GLuint shader); +GLAPI void APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); +GLAPI void APIENTRY glCompileShader(GLuint shader); +GLAPI GLuint APIENTRY glCreateProgram(void); +GLAPI GLuint APIENTRY glCreateShader(GLenum type); +GLAPI void APIENTRY glDeleteProgram(GLuint program); +GLAPI void APIENTRY glDeleteShader(GLuint shader); +GLAPI void APIENTRY glDetachShader(GLuint program, GLuint shader); +GLAPI void APIENTRY glDisableVertexAttribArray(GLuint index); +GLAPI void APIENTRY glEnableVertexAttribArray(GLuint index); +GLAPI void APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GLAPI void APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GLAPI void APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders); +GLAPI GLint APIENTRY glGetAttribLocation(GLuint program, const GLchar* name); +GLAPI void APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +GLAPI void APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +GLAPI void APIENTRY glGetShaderSource(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source); +GLAPI GLint APIENTRY glGetUniformLocation(GLuint program, const GLchar* name); +GLAPI void APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params); +GLAPI void APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params); +GLAPI void APIENTRY glGetVertexAttribdv(GLuint index, GLenum pname, GLdouble* params); +GLAPI void APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer); +GLAPI GLboolean APIENTRY glIsProgram(GLuint program); +GLAPI GLboolean APIENTRY glIsShader(GLuint shader); +GLAPI void APIENTRY glLinkProgram(GLuint program); +GLAPI void APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); +GLAPI void APIENTRY glUseProgram(GLuint program); +GLAPI void APIENTRY glUniform1f(GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2f(GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1i(GLint location, GLint v0); +GLAPI void APIENTRY glUniform2i(GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3i(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glValidateProgram(GLuint program); +GLAPI void APIENTRY glVertexAttrib1d(GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttrib1f(GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* v); +GLAPI void APIENTRY glVertexAttrib1s(GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1sv(GLuint index, const GLshort* v); +GLAPI void APIENTRY glVertexAttrib2d(GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* v); +GLAPI void APIENTRY glVertexAttrib2s(GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2sv(GLuint index, const GLshort* v); +GLAPI void APIENTRY glVertexAttrib3d(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* v); +GLAPI void APIENTRY glVertexAttrib3s(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3sv(GLuint index, const GLshort* v); +GLAPI void APIENTRY glVertexAttrib4Nbv(GLuint index, const GLbyte* v); +GLAPI void APIENTRY glVertexAttrib4Niv(GLuint index, const GLint* v); +GLAPI void APIENTRY glVertexAttrib4Nsv(GLuint index, const GLshort* v); +GLAPI void APIENTRY glVertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4Nubv(GLuint index, const GLubyte* v); +GLAPI void APIENTRY glVertexAttrib4Nuiv(GLuint index, const GLuint* v); +GLAPI void APIENTRY glVertexAttrib4Nusv(GLuint index, const GLushort* v); +GLAPI void APIENTRY glVertexAttrib4bv(GLuint index, const GLbyte* v); +GLAPI void APIENTRY glVertexAttrib4d(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* v); +GLAPI void APIENTRY glVertexAttrib4iv(GLuint index, const GLint* v); +GLAPI void APIENTRY glVertexAttrib4s(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4sv(GLuint index, const GLshort* v); +GLAPI void APIENTRY glVertexAttrib4ubv(GLuint index, const GLubyte* v); +GLAPI void APIENTRY glVertexAttrib4uiv(GLuint index, const GLuint* v); +GLAPI void APIENTRY glVertexAttrib4usv(GLuint index, const GLushort* v); +GLAPI void APIENTRY glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); #endif #endif /* GL_VERSION_2_0 */ #ifndef GL_VERSION_2_1 #define GL_VERSION_2_1 1 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +typedef void(APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); #endif #endif /* GL_VERSION_2_1 */ #ifndef GL_VERSION_3_0 #define GL_VERSION_3_0 1 typedef khronos_uint16_t GLhalf; -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 @@ -1111,639 +1142,655 @@ typedef khronos_uint16_t GLhalf; #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_COLOR_ATTACHMENT16 0x8CF0 -#define GL_COLOR_ATTACHMENT17 0x8CF1 -#define GL_COLOR_ATTACHMENT18 0x8CF2 -#define GL_COLOR_ATTACHMENT19 0x8CF3 -#define GL_COLOR_ATTACHMENT20 0x8CF4 -#define GL_COLOR_ATTACHMENT21 0x8CF5 -#define GL_COLOR_ATTACHMENT22 0x8CF6 -#define GL_COLOR_ATTACHMENT23 0x8CF7 -#define GL_COLOR_ATTACHMENT24 0x8CF8 -#define GL_COLOR_ATTACHMENT25 0x8CF9 -#define GL_COLOR_ATTACHMENT26 0x8CFA -#define GL_COLOR_ATTACHMENT27 0x8CFB -#define GL_COLOR_ATTACHMENT28 0x8CFC -#define GL_COLOR_ATTACHMENT29 0x8CFD -#define GL_COLOR_ATTACHMENT30 0x8CFE -#define GL_COLOR_ATTACHMENT31 0x8CFF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_HALF_FLOAT 0x140B -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); +#define GL_MAX_SAMPLES 0x8D57 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +typedef void(APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void(APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean* data); +typedef void(APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint* data); +typedef void(APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); +typedef void(APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); +typedef GLboolean(APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +typedef void(APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +typedef void(APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void); +typedef void(APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void(APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +typedef void(APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode); +typedef void(APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, + GLenum* type, GLchar* name); +typedef void(APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +typedef void(APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +typedef void(APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void); +typedef void(APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort* v); +typedef void(APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint* params); +typedef void(APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar* name); +typedef GLint(APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar* name); +typedef void(APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +typedef void(APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +typedef void(APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void(APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void(APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint* params); +typedef void(APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint* value); +typedef void(APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint* value); +typedef void(APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat* value); +typedef void(APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte*(APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +typedef GLboolean(APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef void(APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void(APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint* renderbuffers); +typedef void(APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers); +typedef void(APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef GLboolean(APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef void(APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void(APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint* framebuffers); +typedef void(APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers); +typedef GLenum(APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void(APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void(APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +typedef void(APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, + GLint dstY1, GLbitfield mask, GLenum filter); +typedef void(APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void*(APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void(APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +typedef void(APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); +typedef void(APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint* arrays); +typedef void(APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays); +typedef GLboolean(APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); -GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); -GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedback (void); -GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); -GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRender (void); -GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); -GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); -GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); -GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); -GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); -GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); -GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); -GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index); -GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); -GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); -GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); -GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); -GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); -GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); -GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); -GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateMipmap (GLenum target); -GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glBindVertexArray (GLuint array); -GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); -GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); -GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); +GLAPI void APIENTRY glColorMaski(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI void APIENTRY glGetBooleani_v(GLenum target, GLuint index, GLboolean* data); +GLAPI void APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint* data); +GLAPI void APIENTRY glEnablei(GLenum target, GLuint index); +GLAPI void APIENTRY glDisablei(GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledi(GLenum target, GLuint index); +GLAPI void APIENTRY glBeginTransformFeedback(GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedback(void); +GLAPI void APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, + GLenum* type, GLchar* name); +GLAPI void APIENTRY glClampColor(GLenum target, GLenum clamp); +GLAPI void APIENTRY glBeginConditionalRender(GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRender(void); +GLAPI void APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI void APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params); +GLAPI void APIENTRY glVertexAttribI1i(GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2i(GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3i(GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1ui(GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2ui(GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3ui(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1iv(GLuint index, const GLint* v); +GLAPI void APIENTRY glVertexAttribI2iv(GLuint index, const GLint* v); +GLAPI void APIENTRY glVertexAttribI3iv(GLuint index, const GLint* v); +GLAPI void APIENTRY glVertexAttribI4iv(GLuint index, const GLint* v); +GLAPI void APIENTRY glVertexAttribI1uiv(GLuint index, const GLuint* v); +GLAPI void APIENTRY glVertexAttribI2uiv(GLuint index, const GLuint* v); +GLAPI void APIENTRY glVertexAttribI3uiv(GLuint index, const GLuint* v); +GLAPI void APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint* v); +GLAPI void APIENTRY glVertexAttribI4bv(GLuint index, const GLbyte* v); +GLAPI void APIENTRY glVertexAttribI4sv(GLuint index, const GLshort* v); +GLAPI void APIENTRY glVertexAttribI4ubv(GLuint index, const GLubyte* v); +GLAPI void APIENTRY glVertexAttribI4usv(GLuint index, const GLushort* v); +GLAPI void APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint* params); +GLAPI void APIENTRY glBindFragDataLocation(GLuint program, GLuint color, const GLchar* name); +GLAPI GLint APIENTRY glGetFragDataLocation(GLuint program, const GLchar* name); +GLAPI void APIENTRY glUniform1ui(GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2ui(GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glTexParameterIiv(GLenum target, GLenum pname, const GLint* params); +GLAPI void APIENTRY glTexParameterIuiv(GLenum target, GLenum pname, const GLuint* params); +GLAPI void APIENTRY glGetTexParameterIiv(GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetTexParameterIuiv(GLenum target, GLenum pname, GLuint* params); +GLAPI void APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); +GLAPI void APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); +GLAPI void APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); +GLAPI void APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI const GLubyte* APIENTRY glGetStringi(GLenum name, GLuint index); +GLAPI GLboolean APIENTRY glIsRenderbuffer(GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); +GLAPI void APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers); +GLAPI void APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params); +GLAPI GLboolean APIENTRY glIsFramebuffer(GLuint framebuffer); +GLAPI void APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers); +GLAPI void APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatus(GLenum target); +GLAPI void APIENTRY glFramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params); +GLAPI void APIENTRY glGenerateMipmap(GLenum target); +GLAPI void APIENTRY glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, + GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI void APIENTRY glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void* APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glBindVertexArray(GLuint array); +GLAPI void APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint* arrays); +GLAPI void APIENTRY glGenVertexArrays(GLsizei n, GLuint* arrays); +GLAPI GLboolean APIENTRY glIsVertexArray(GLuint array); #endif #endif /* GL_VERSION_3_0 */ #ifndef GL_VERSION_3_1 #define GL_VERSION_3_1 1 -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFFu -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); -typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#define GL_INVALID_INDEX 0xFFFFFFFFu +typedef void(APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void(APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount); +typedef void(APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +typedef void(APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); +typedef void(APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); +typedef void(APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices); +typedef void(APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName); +typedef GLuint(APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar* uniformBlockName); +typedef void(APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, + GLchar* uniformBlockName); +typedef void(APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); -GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); -GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +GLAPI void APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI void APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount); +GLAPI void APIENTRY glTexBuffer(GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glPrimitiveRestartIndex(GLuint index); +GLAPI void APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices); +GLAPI void APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetActiveUniformName(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName); +GLAPI GLuint APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName); +GLAPI void APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName); +GLAPI void APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); #endif #endif /* GL_VERSION_3_1 */ #ifndef GL_VERSION_3_2 #define GL_VERSION_3_2 1 -typedef struct __GLsync *GLsync; +typedef struct __GLsync* GLsync; typedef khronos_uint64_t GLuint64; typedef khronos_int64_t GLint64; -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -#define GL_DEPTH_CLAMP 0x864F +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); -typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); -typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); -typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); -typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); -typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); -typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +typedef void(APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex); +typedef void(APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, + const void* indices, GLint basevertex); +typedef void(APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei instancecount, GLint basevertex); +typedef void(APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, + GLsizei drawcount, const GLint* basevertex); +typedef void(APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); +typedef GLsync(APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +typedef GLboolean(APIENTRYP PFNGLISSYNCPROC)(GLsync sync); +typedef void(APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); +typedef GLenum(APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void(APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void(APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64* data); +typedef void(APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei* length, GLint* values); +typedef void(APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64* data); +typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64* params); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat* val); +typedef void(APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -GLAPI void APIENTRY glProvokingVertex (GLenum mode); -GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); -GLAPI GLboolean APIENTRY glIsSync (GLsync sync); -GLAPI void APIENTRY glDeleteSync (GLsync sync); -GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); -GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); -GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); -GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); +GLAPI void APIENTRY glDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex); +GLAPI void APIENTRY glDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices, + GLint basevertex); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, + GLint basevertex); +GLAPI void APIENTRY glMultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, + GLsizei drawcount, const GLint* basevertex); +GLAPI void APIENTRY glProvokingVertex(GLenum mode); +GLAPI GLsync APIENTRY glFenceSync(GLenum condition, GLbitfield flags); +GLAPI GLboolean APIENTRY glIsSync(GLsync sync); +GLAPI void APIENTRY glDeleteSync(GLsync sync); +GLAPI GLenum APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glGetInteger64v(GLenum pname, GLint64* data); +GLAPI void APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei count, GLsizei* length, GLint* values); +GLAPI void APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64* data); +GLAPI void APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params); +GLAPI void APIENTRY glFramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glTexImage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glGetMultisamplefv(GLenum pname, GLuint index, GLfloat* val); +GLAPI void APIENTRY glSampleMaski(GLuint maskNumber, GLbitfield mask); #endif #endif /* GL_VERSION_3_2 */ #ifndef GL_VERSION_3_3 #define GL_VERSION_3_3 1 -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -#define GL_SRC1_COLOR 0x88F9 -#define GL_ONE_MINUS_SRC1_COLOR 0x88FA -#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -#define GL_ANY_SAMPLES_PASSED 0x8C2F -#define GL_SAMPLER_BINDING 0x8919 -#define GL_RGB10_A2UI 0x906F -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#define GL_TIME_ELAPSED 0x88BF -#define GL_TIMESTAMP 0x8E28 -#define GL_INT_2_10_10_10_REV 0x8D9F -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); -typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); -typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); -typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +typedef void(APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar* name); +typedef GLint(APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar* name); +typedef void(APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint* samplers); +typedef void(APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint* samplers); +typedef GLboolean(APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler); +typedef void(APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); +typedef void(APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint* param); +typedef void(APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat* param); +typedef void(APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint* param); +typedef void(APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint* param); +typedef void(APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); +typedef void(APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64* params); +typedef void(APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64* params); +typedef void(APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void(APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); -GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); -GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); -GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); -GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); -GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); -GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); -GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); -GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); -GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); -GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); -GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glBindFragDataLocationIndexed(GLuint program, GLuint colorNumber, GLuint index, const GLchar* name); +GLAPI GLint APIENTRY glGetFragDataIndex(GLuint program, const GLchar* name); +GLAPI void APIENTRY glGenSamplers(GLsizei count, GLuint* samplers); +GLAPI void APIENTRY glDeleteSamplers(GLsizei count, const GLuint* samplers); +GLAPI GLboolean APIENTRY glIsSampler(GLuint sampler); +GLAPI void APIENTRY glBindSampler(GLuint unit, GLuint sampler); +GLAPI void APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param); +GLAPI void APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param); +GLAPI void APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param); +GLAPI void APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param); +GLAPI void APIENTRY glSamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param); +GLAPI void APIENTRY glSamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param); +GLAPI void APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params); +GLAPI void APIENTRY glQueryCounter(GLuint id, GLenum target); +GLAPI void APIENTRY glGetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params); +GLAPI void APIENTRY glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params); +GLAPI void APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor); +GLAPI void APIENTRY glVertexAttribP1ui(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP1uiv(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +GLAPI void APIENTRY glVertexAttribP2ui(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP2uiv(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +GLAPI void APIENTRY glVertexAttribP3ui(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP3uiv(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); +GLAPI void APIENTRY glVertexAttribP4ui(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP4uiv(GLuint index, GLenum type, GLboolean normalized, const GLuint* value); #endif #endif /* GL_VERSION_3_3 */ #ifndef GL_VERSION_4_0 #define GL_VERSION_4_0 1 -#define GL_SAMPLE_SHADING 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F -#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F -#define GL_DRAW_INDIRECT_BUFFER 0x8F3F -#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 -#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D -#define GL_MAX_VERTEX_STREAMS 0x8E71 -#define GL_DOUBLE_VEC2 0x8FFC -#define GL_DOUBLE_VEC3 0x8FFD -#define GL_DOUBLE_VEC4 0x8FFE -#define GL_DOUBLE_MAT2 0x8F46 -#define GL_DOUBLE_MAT3 0x8F47 -#define GL_DOUBLE_MAT4 0x8F48 -#define GL_DOUBLE_MAT2x3 0x8F49 -#define GL_DOUBLE_MAT2x4 0x8F4A -#define GL_DOUBLE_MAT3x2 0x8F4B -#define GL_DOUBLE_MAT3x4 0x8F4C -#define GL_DOUBLE_MAT4x2 0x8F4D -#define GL_DOUBLE_MAT4x3 0x8F4E -#define GL_ACTIVE_SUBROUTINES 0x8DE5 -#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_MAX_VERTEX_STREAMS 0x8E71 +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 #define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 -#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 #define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 -#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINES 0x8DE7 #define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 -#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A -#define GL_COMPATIBLE_SUBROUTINES 0x8E4B -#define GL_PATCHES 0x000E -#define GL_PATCH_VERTICES 0x8E72 -#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 -#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 -#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 -#define GL_TESS_GEN_MODE 0x8E76 -#define GL_TESS_GEN_SPACING 0x8E77 -#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 -#define GL_TESS_GEN_POINT_MODE 0x8E79 -#define GL_ISOLINES 0x8E7A -#define GL_FRACTIONAL_ODD 0x8E7B -#define GL_FRACTIONAL_EVEN 0x8E7C -#define GL_MAX_PATCH_VERTICES 0x8E7D -#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +#define GL_ISOLINES 0x8E7A +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 -#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 @@ -1754,346 +1801,355 @@ GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean no #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 -#define GL_TESS_EVALUATION_SHADER 0x8E87 -#define GL_TESS_CONTROL_SHADER 0x8E88 -#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); -typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); -typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); -typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); -typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); -typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); -typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); -typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); -typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +typedef void(APIENTRYP PFNGLMINSAMPLESHADINGPROC)(GLfloat value); +typedef void(APIENTRYP PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode); +typedef void(APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void(APIENTRYP PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst); +typedef void(APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void(APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void* indirect); +typedef void(APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void* indirect); +typedef void(APIENTRYP PFNGLUNIFORM1DPROC)(GLint location, GLdouble x); +typedef void(APIENTRYP PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void(APIENTRYP PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble* params); +typedef GLint(APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar* name); +typedef GLuint(APIENTRYP PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar* name); +typedef void(APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint* values); +typedef void(APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, + GLsizei* length, GLchar* name); +typedef void(APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei* length, + GLchar* name); +typedef void(APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint* indices); +typedef void(APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint* params); +typedef void(APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint* values); +typedef void(APIENTRYP PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value); +typedef void(APIENTRYP PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat* values); +typedef void(APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id); +typedef void(APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint* ids); +typedef void(APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint* ids); +typedef GLboolean(APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id); +typedef void(APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC)(void); +typedef void(APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC)(void); +typedef void(APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id); +typedef void(APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream); +typedef void(APIENTRYP PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id); +typedef void(APIENTRYP PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index); +typedef void(APIENTRYP PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint* params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShading (GLfloat value); -GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); -GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); -GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); -GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); -GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); -GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); -GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); -GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); -GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); -GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); -GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); -GLAPI void APIENTRY glPauseTransformFeedback (void); -GLAPI void APIENTRY glResumeTransformFeedback (void); -GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); -GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); -GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); -GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); -GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glMinSampleShading(GLfloat value); +GLAPI void APIENTRY glBlendEquationi(GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunci(GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glDrawArraysIndirect(GLenum mode, const void* indirect); +GLAPI void APIENTRY glDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect); +GLAPI void APIENTRY glUniform1d(GLint location, GLdouble x); +GLAPI void APIENTRY glUniform2d(GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glUniform3d(GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glUniform4d(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glUniform1dv(GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glUniform2dv(GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glUniform3dv(GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glUniform4dv(GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix2dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix3dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix4dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix2x3dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix2x4dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix3x2dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix3x4dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix4x2dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glUniformMatrix4x3dv(GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glGetUniformdv(GLuint program, GLint location, GLdouble* params); +GLAPI GLint APIENTRY glGetSubroutineUniformLocation(GLuint program, GLenum shadertype, const GLchar* name); +GLAPI GLuint APIENTRY glGetSubroutineIndex(GLuint program, GLenum shadertype, const GLchar* name); +GLAPI void APIENTRY glGetActiveSubroutineUniformiv(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint* values); +GLAPI void APIENTRY glGetActiveSubroutineUniformName(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei* length, + GLchar* name); +GLAPI void APIENTRY glGetActiveSubroutineName(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name); +GLAPI void APIENTRY glUniformSubroutinesuiv(GLenum shadertype, GLsizei count, const GLuint* indices); +GLAPI void APIENTRY glGetUniformSubroutineuiv(GLenum shadertype, GLint location, GLuint* params); +GLAPI void APIENTRY glGetProgramStageiv(GLuint program, GLenum shadertype, GLenum pname, GLint* values); +GLAPI void APIENTRY glPatchParameteri(GLenum pname, GLint value); +GLAPI void APIENTRY glPatchParameterfv(GLenum pname, const GLfloat* values); +GLAPI void APIENTRY glBindTransformFeedback(GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids); +GLAPI void APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint* ids); +GLAPI GLboolean APIENTRY glIsTransformFeedback(GLuint id); +GLAPI void APIENTRY glPauseTransformFeedback(void); +GLAPI void APIENTRY glResumeTransformFeedback(void); +GLAPI void APIENTRY glDrawTransformFeedback(GLenum mode, GLuint id); +GLAPI void APIENTRY glDrawTransformFeedbackStream(GLenum mode, GLuint id, GLuint stream); +GLAPI void APIENTRY glBeginQueryIndexed(GLenum target, GLuint index, GLuint id); +GLAPI void APIENTRY glEndQueryIndexed(GLenum target, GLuint index); +GLAPI void APIENTRY glGetQueryIndexediv(GLenum target, GLuint index, GLenum pname, GLint* params); #endif #endif /* GL_VERSION_4_0 */ #ifndef GL_VERSION_4_1 #define GL_VERSION_4_1 1 -#define GL_FIXED 0x140C +#define GL_FIXED 0x140C #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B -#define GL_LOW_FLOAT 0x8DF0 -#define GL_MEDIUM_FLOAT 0x8DF1 -#define GL_HIGH_FLOAT 0x8DF2 -#define GL_LOW_INT 0x8DF3 -#define GL_MEDIUM_INT 0x8DF4 -#define GL_HIGH_INT 0x8DF5 -#define GL_SHADER_COMPILER 0x8DFA -#define GL_SHADER_BINARY_FORMATS 0x8DF8 -#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define GL_MAX_VARYING_VECTORS 0x8DFC -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#define GL_RGB565 0x8D62 +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 -#define GL_PROGRAM_BINARY_LENGTH 0x8741 -#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE -#define GL_PROGRAM_BINARY_FORMATS 0x87FF -#define GL_VERTEX_SHADER_BIT 0x00000001 -#define GL_FRAGMENT_SHADER_BIT 0x00000002 -#define GL_GEOMETRY_SHADER_BIT 0x00000004 -#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 -#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 -#define GL_ALL_SHADER_BITS 0xFFFFFFFF -#define GL_PROGRAM_SEPARABLE 0x8258 -#define GL_ACTIVE_PROGRAM 0x8259 -#define GL_PROGRAM_PIPELINE_BINDING 0x825A -#define GL_MAX_VIEWPORTS 0x825B -#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C -#define GL_VIEWPORT_BOUNDS_RANGE 0x825D -#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E #define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F -#define GL_UNDEFINED_VERTEX 0x8260 -typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); -typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); -typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); -typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); -typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); -typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); -typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); -typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); -typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); -typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); +#define GL_UNDEFINED_VERTEX 0x8260 +typedef void(APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void); +typedef void(APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length); +typedef void(APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); +typedef void(APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +typedef void(APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d); +typedef void(APIENTRYP PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void* binary); +typedef void(APIENTRYP PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void* binary, GLsizei length); +typedef void(APIENTRYP PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value); +typedef void(APIENTRYP PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program); +typedef void(APIENTRYP PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program); +typedef GLuint(APIENTRYP PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar* const* strings); +typedef void(APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline); +typedef void(APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint* pipelines); +typedef void(APIENTRYP PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint* pipelines); +typedef GLboolean(APIENTRYP PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline); +typedef void(APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline); +typedef void(APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble* params); +typedef void(APIENTRYP PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat* v); +typedef void(APIENTRYP PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void(APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint* v); +typedef void(APIENTRYP PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble* v); +typedef void(APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f); +typedef void(APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat* data); +typedef void(APIENTRYP PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble* data); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReleaseShaderCompiler (void); -GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); -GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); -GLAPI void APIENTRY glClearDepthf (GLfloat d); -GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); -GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); -GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); -GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); -GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); -GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); -GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); -GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); -GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); -GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); -GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); -GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); -GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); -GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); +GLAPI void APIENTRY glReleaseShaderCompiler(void); +GLAPI void APIENTRY glShaderBinary(GLsizei count, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length); +GLAPI void APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); +GLAPI void APIENTRY glDepthRangef(GLfloat n, GLfloat f); +GLAPI void APIENTRY glClearDepthf(GLfloat d); +GLAPI void APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void* binary); +GLAPI void APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const void* binary, GLsizei length); +GLAPI void APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glUseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program); +GLAPI void APIENTRY glActiveShaderProgram(GLuint pipeline, GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramv(GLenum type, GLsizei count, const GLchar* const* strings); +GLAPI void APIENTRY glBindProgramPipeline(GLuint pipeline); +GLAPI void APIENTRY glDeleteProgramPipelines(GLsizei n, const GLuint* pipelines); +GLAPI void APIENTRY glGenProgramPipelines(GLsizei n, GLuint* pipelines); +GLAPI GLboolean APIENTRY glIsProgramPipeline(GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint* params); +GLAPI void APIENTRY glProgramUniform1i(GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform1iv(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniform1f(GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform1d(GLuint program, GLint location, GLdouble v0); +GLAPI void APIENTRY glProgramUniform1dv(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniform1ui(GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform2iv(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform2d(GLuint program, GLint location, GLdouble v0, GLdouble v1); +GLAPI void APIENTRY glProgramUniform2dv(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform3iv(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform3d(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +GLAPI void APIENTRY glProgramUniform3dv(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform4iv(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform4d(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +GLAPI void APIENTRY glProgramUniform4dv(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glProgramUniformMatrix2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix2dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix3dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix4dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glValidateProgramPipeline(GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineInfoLog(GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +GLAPI void APIENTRY glVertexAttribL1d(GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2d(GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3d(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4d(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttribL2dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttribL3dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttribL4dv(GLuint index, const GLdouble* v); +GLAPI void APIENTRY glVertexAttribLPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI void APIENTRY glGetVertexAttribLdv(GLuint index, GLenum pname, GLdouble* params); +GLAPI void APIENTRY glViewportArrayv(GLuint first, GLsizei count, const GLfloat* v); +GLAPI void APIENTRY glViewportIndexedf(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GLAPI void APIENTRY glViewportIndexedfv(GLuint index, const GLfloat* v); +GLAPI void APIENTRY glScissorArrayv(GLuint first, GLsizei count, const GLint* v); +GLAPI void APIENTRY glScissorIndexed(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GLAPI void APIENTRY glScissorIndexedv(GLuint index, const GLint* v); +GLAPI void APIENTRY glDepthRangeArrayv(GLuint first, GLsizei count, const GLdouble* v); +GLAPI void APIENTRY glDepthRangeIndexed(GLuint index, GLdouble n, GLdouble f); +GLAPI void APIENTRY glGetFloati_v(GLenum target, GLuint index, GLfloat* data); +GLAPI void APIENTRY glGetDoublei_v(GLenum target, GLuint index, GLdouble* data); #endif #endif /* GL_VERSION_4_1 */ #ifndef GL_VERSION_4_2 #define GL_VERSION_4_2 1 -#define GL_COPY_READ_BUFFER_BINDING 0x8F36 -#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 -#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 -#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 #define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 -#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 -#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A -#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B -#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C -#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D -#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E -#define GL_NUM_SAMPLE_COUNTS 0x9380 -#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC -#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 -#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 -#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 -#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 #define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 @@ -2108,346 +2164,352 @@ GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data) #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF #define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 #define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 -#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 -#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 -#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 #define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 #define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC -#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 #define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA -#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 -#define GL_COMMAND_BARRIER_BIT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 -#define GL_ALL_BARRIER_BITS 0xFFFFFFFF -#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 -#define GL_IMAGE_BINDING_NAME 0x8F3A -#define GL_IMAGE_BINDING_LEVEL 0x8F3B -#define GL_IMAGE_BINDING_LAYERED 0x8F3C -#define GL_IMAGE_BINDING_LAYER 0x8F3D -#define GL_IMAGE_BINDING_ACCESS 0x8F3E -#define GL_IMAGE_1D 0x904C -#define GL_IMAGE_2D 0x904D -#define GL_IMAGE_3D 0x904E -#define GL_IMAGE_2D_RECT 0x904F -#define GL_IMAGE_CUBE 0x9050 -#define GL_IMAGE_BUFFER 0x9051 -#define GL_IMAGE_1D_ARRAY 0x9052 -#define GL_IMAGE_2D_ARRAY 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 -#define GL_INT_IMAGE_1D 0x9057 -#define GL_INT_IMAGE_2D 0x9058 -#define GL_INT_IMAGE_3D 0x9059 -#define GL_INT_IMAGE_2D_RECT 0x905A -#define GL_INT_IMAGE_CUBE 0x905B -#define GL_INT_IMAGE_BUFFER 0x905C -#define GL_INT_IMAGE_1D_ARRAY 0x905D -#define GL_INT_IMAGE_2D_ARRAY 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C -#define GL_MAX_IMAGE_SAMPLES 0x906D -#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 -#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD -#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE -#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF -#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F -#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); -typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +typedef void(APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void(APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei instancecount, GLuint baseinstance); +typedef void(APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void(APIENTRYP PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint* params); +typedef void(APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, + GLenum format); +typedef void(APIENTRYP PFNGLMEMORYBARRIERPROC)(GLbitfield barriers); +typedef void(APIENTRYP PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void(APIENTRYP PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void(APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, GLsizei instancecount); +typedef void(APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); -GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); -GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); -GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +GLAPI void APIENTRY glDrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, + GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei instancecount, GLint basevertex, GLuint baseinstance); +GLAPI void APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint* params); +GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv(GLuint program, GLuint bufferIndex, GLenum pname, GLint* params); +GLAPI void APIENTRY glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +GLAPI void APIENTRY glMemoryBarrier(GLbitfield barriers); +GLAPI void APIENTRY glTexStorage1D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glDrawTransformFeedbackInstanced(GLenum mode, GLuint id, GLsizei instancecount); +GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); #endif #endif /* GL_VERSION_4_2 */ #ifndef GL_VERSION_4_3 #define GL_VERSION_4_3 1 -typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 -#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E -#define GL_COMPRESSED_RGB8_ETC2 0x9274 -#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +typedef void(APIENTRY* GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, + const void* userParam); +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 -#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 -#define GL_COMPRESSED_R11_EAC 0x9270 -#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 -#define GL_COMPRESSED_RG11_EAC 0x9272 -#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 -#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A -#define GL_MAX_ELEMENT_INDEX 0x8D6B -#define GL_COMPUTE_SHADER 0x91B9 -#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB #define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC -#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD #define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 #define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 -#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB -#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE -#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF -#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED -#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF -#define GL_COMPUTE_SHADER_BIT 0x00000020 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#define GL_DEBUG_SOURCE_API 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#define GL_DEBUG_SOURCE_OTHER 0x824B -#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#define GL_DEBUG_TYPE_OTHER 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#define GL_DEBUG_TYPE_MARKER 0x8268 -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#define GL_BUFFER 0x82E0 -#define GL_SHADER 0x82E1 -#define GL_PROGRAM 0x82E2 -#define GL_QUERY 0x82E3 -#define GL_PROGRAM_PIPELINE 0x82E4 -#define GL_SAMPLER 0x82E6 -#define GL_MAX_LABEL_LENGTH 0x82E8 -#define GL_DEBUG_OUTPUT 0x92E0 -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#define GL_MAX_UNIFORM_LOCATIONS 0x826E -#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 -#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 -#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 -#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 #define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 -#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 -#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 -#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 -#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 -#define GL_INTERNALFORMAT_SUPPORTED 0x826F -#define GL_INTERNALFORMAT_PREFERRED 0x8270 -#define GL_INTERNALFORMAT_RED_SIZE 0x8271 -#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 -#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 -#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 -#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 -#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 -#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 -#define GL_INTERNALFORMAT_RED_TYPE 0x8278 -#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 -#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A -#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B -#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C -#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D -#define GL_MAX_WIDTH 0x827E -#define GL_MAX_HEIGHT 0x827F -#define GL_MAX_DEPTH 0x8280 -#define GL_MAX_LAYERS 0x8281 -#define GL_MAX_COMBINED_DIMENSIONS 0x8282 -#define GL_COLOR_COMPONENTS 0x8283 -#define GL_DEPTH_COMPONENTS 0x8284 -#define GL_STENCIL_COMPONENTS 0x8285 -#define GL_COLOR_RENDERABLE 0x8286 -#define GL_DEPTH_RENDERABLE 0x8287 -#define GL_STENCIL_RENDERABLE 0x8288 -#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 #define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A -#define GL_FRAMEBUFFER_BLEND 0x828B -#define GL_READ_PIXELS 0x828C -#define GL_READ_PIXELS_FORMAT 0x828D -#define GL_READ_PIXELS_TYPE 0x828E -#define GL_TEXTURE_IMAGE_FORMAT 0x828F -#define GL_TEXTURE_IMAGE_TYPE 0x8290 -#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 -#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 -#define GL_MIPMAP 0x8293 -#define GL_MANUAL_GENERATE_MIPMAP 0x8294 -#define GL_AUTO_GENERATE_MIPMAP 0x8295 -#define GL_COLOR_ENCODING 0x8296 -#define GL_SRGB_READ 0x8297 -#define GL_SRGB_WRITE 0x8298 -#define GL_FILTER 0x829A -#define GL_VERTEX_TEXTURE 0x829B -#define GL_TESS_CONTROL_TEXTURE 0x829C -#define GL_TESS_EVALUATION_TEXTURE 0x829D -#define GL_GEOMETRY_TEXTURE 0x829E -#define GL_FRAGMENT_TEXTURE 0x829F -#define GL_COMPUTE_TEXTURE 0x82A0 -#define GL_TEXTURE_SHADOW 0x82A1 -#define GL_TEXTURE_GATHER 0x82A2 -#define GL_TEXTURE_GATHER_SHADOW 0x82A3 -#define GL_SHADER_IMAGE_LOAD 0x82A4 -#define GL_SHADER_IMAGE_STORE 0x82A5 -#define GL_SHADER_IMAGE_ATOMIC 0x82A6 -#define GL_IMAGE_TEXEL_SIZE 0x82A7 -#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 -#define GL_IMAGE_PIXEL_FORMAT 0x82A9 -#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF #define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 #define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 -#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 -#define GL_CLEAR_BUFFER 0x82B4 -#define GL_TEXTURE_VIEW 0x82B5 -#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 -#define GL_FULL_SUPPORT 0x82B7 -#define GL_CAVEAT_SUPPORT 0x82B8 -#define GL_IMAGE_CLASS_4_X_32 0x82B9 -#define GL_IMAGE_CLASS_2_X_32 0x82BA -#define GL_IMAGE_CLASS_1_X_32 0x82BB -#define GL_IMAGE_CLASS_4_X_16 0x82BC -#define GL_IMAGE_CLASS_2_X_16 0x82BD -#define GL_IMAGE_CLASS_1_X_16 0x82BE -#define GL_IMAGE_CLASS_4_X_8 0x82BF -#define GL_IMAGE_CLASS_2_X_8 0x82C0 -#define GL_IMAGE_CLASS_1_X_8 0x82C1 -#define GL_IMAGE_CLASS_11_11_10 0x82C2 -#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 -#define GL_VIEW_CLASS_128_BITS 0x82C4 -#define GL_VIEW_CLASS_96_BITS 0x82C5 -#define GL_VIEW_CLASS_64_BITS 0x82C6 -#define GL_VIEW_CLASS_48_BITS 0x82C7 -#define GL_VIEW_CLASS_32_BITS 0x82C8 -#define GL_VIEW_CLASS_24_BITS 0x82C9 -#define GL_VIEW_CLASS_16_BITS 0x82CA -#define GL_VIEW_CLASS_8_BITS 0x82CB -#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC -#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD -#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE -#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF -#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 -#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 -#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 -#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 -#define GL_UNIFORM 0x92E1 -#define GL_UNIFORM_BLOCK 0x92E2 -#define GL_PROGRAM_INPUT 0x92E3 -#define GL_PROGRAM_OUTPUT 0x92E4 -#define GL_BUFFER_VARIABLE 0x92E5 -#define GL_SHADER_STORAGE_BLOCK 0x92E6 -#define GL_VERTEX_SUBROUTINE 0x92E8 -#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 -#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA -#define GL_GEOMETRY_SUBROUTINE 0x92EB -#define GL_FRAGMENT_SUBROUTINE 0x92EC -#define GL_COMPUTE_SUBROUTINE 0x92ED -#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE #define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF #define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 -#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 -#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 -#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 -#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 -#define GL_ACTIVE_RESOURCES 0x92F5 -#define GL_MAX_NAME_LENGTH 0x92F6 -#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 #define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 -#define GL_NAME_LENGTH 0x92F9 -#define GL_TYPE 0x92FA -#define GL_ARRAY_SIZE 0x92FB -#define GL_OFFSET 0x92FC -#define GL_BLOCK_INDEX 0x92FD -#define GL_ARRAY_STRIDE 0x92FE -#define GL_MATRIX_STRIDE 0x92FF -#define GL_IS_ROW_MAJOR 0x9300 -#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 -#define GL_BUFFER_BINDING 0x9302 -#define GL_BUFFER_DATA_SIZE 0x9303 -#define GL_NUM_ACTIVE_VARIABLES 0x9304 -#define GL_ACTIVE_VARIABLES 0x9305 -#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 -#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 -#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A -#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B -#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C -#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D -#define GL_LOCATION 0x930E -#define GL_LOCATION_INDEX 0x930F -#define GL_IS_PER_PATCH 0x92E7 -#define GL_SHADER_STORAGE_BUFFER 0x90D2 -#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 -#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 -#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 #define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 @@ -2456,441 +2518,511 @@ typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum #define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB #define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD -#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF -#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 #define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 -#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA -#define GL_TEXTURE_BUFFER_OFFSET 0x919D -#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F -#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB -#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC -#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD -#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE -#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF -#define GL_VERTEX_ATTRIB_BINDING 0x82D4 -#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 -#define GL_VERTEX_BINDING_DIVISOR 0x82D6 -#define GL_VERTEX_BINDING_OFFSET 0x82D7 -#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 -#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA -#define GL_VERTEX_BINDING_BUFFER 0x8F4F -typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); -typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); -typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); -typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params); -typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); -typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); -typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params); -typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); -typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); -typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); -typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); -typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); -typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_VERTEX_BINDING_BUFFER 0x8F4F +typedef void(APIENTRYP PFNGLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, + GLenum type, const void* data); +typedef void(APIENTRYP PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +typedef void(APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect); +typedef void(APIENTRYP PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, + GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, + GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void(APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64* params); +typedef void(APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth); +typedef void(APIENTRYP PFNGLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void(APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer); +typedef void(APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum* attachments); +typedef void(APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, + GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); +typedef void(APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride); +typedef void(APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint* params); +typedef GLuint(APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar* name); +typedef void(APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, + GLsizei* length, GLchar* name); +typedef void(APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, + const GLenum* props, GLsizei count, GLsizei* length, GLint* params); +typedef GLint(APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar* name); +typedef GLint(APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, GLenum programInterface, const GLchar* name); +typedef void(APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +typedef void(APIENTRYP PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void(APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, + GLsizei height, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, + GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void(APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void(APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex); +typedef void(APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor); +typedef void(APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, + GLboolean enabled); +typedef void(APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); +typedef void(APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void* userParam); +typedef GLuint(APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, + GLenum* severities, GLsizei* lengths, GLchar* messageLog); +typedef void(APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar* message); +typedef void(APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void); +typedef void(APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar* label); +typedef void(APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label); +typedef void(APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void* ptr, GLsizei length, const GLchar* label); +typedef void(APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void* ptr, GLsizei bufSize, GLsizei* length, GLchar* label); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); -GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); -GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); -GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params); -GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); -GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); -GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); -GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); -GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); -GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); -GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params); -GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); -GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); -GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); -GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); -GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); -GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); -GLAPI void APIENTRY glPopDebugGroup (void); -GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); -GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI void APIENTRY glClearBufferData(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void* data); +GLAPI void APIENTRY glClearBufferSubData(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, + const void* data); +GLAPI void APIENTRY glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +GLAPI void APIENTRY glDispatchComputeIndirect(GLintptr indirect); +GLAPI void APIENTRY glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, + GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, + GLsizei srcHeight, GLsizei srcDepth); +GLAPI void APIENTRY glFramebufferParameteri(GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glGetFramebufferParameteriv(GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetInternalformati64v(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64* params); +GLAPI void APIENTRY glInvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth); +GLAPI void APIENTRY glInvalidateTexImage(GLuint texture, GLint level); +GLAPI void APIENTRY glInvalidateBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glInvalidateBufferData(GLuint buffer); +GLAPI void APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments); +GLAPI void APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, + GLsizei width, GLsizei height); +GLAPI void APIENTRY glMultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glGetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params); +GLAPI GLuint APIENTRY glGetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name); +GLAPI void APIENTRY glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name); +GLAPI void APIENTRY glGetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum* props, + GLsizei count, GLsizei* length, GLint* params); +GLAPI GLint APIENTRY glGetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name); +GLAPI GLint APIENTRY glGetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name); +GLAPI void APIENTRY glShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +GLAPI void APIENTRY glTexBufferRange(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTexStorage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureView(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, + GLuint numlevels, GLuint minlayer, GLuint numlayers); +GLAPI void APIENTRY glBindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormat(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribIFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribLFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribBinding(GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexBindingDivisor(GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); +GLAPI void APIENTRY glDebugMessageCallback(GLDEBUGPROC callback, const void* userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLog(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, + GLsizei* lengths, GLchar* messageLog); +GLAPI void APIENTRY glPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar* message); +GLAPI void APIENTRY glPopDebugGroup(void); +GLAPI void APIENTRY glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar* label); +GLAPI void APIENTRY glGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label); +GLAPI void APIENTRY glObjectPtrLabel(const void* ptr, GLsizei length, const GLchar* label); +GLAPI void APIENTRY glGetObjectPtrLabel(const void* ptr, GLsizei bufSize, GLsizei* length, GLchar* label); #endif #endif /* GL_VERSION_4_3 */ #ifndef GL_VERSION_4_4 #define GL_VERSION_4_4 1 -#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 #define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 -#define GL_TEXTURE_BUFFER_BINDING 0x8C2A -#define GL_MAP_PERSISTENT_BIT 0x0040 -#define GL_MAP_COHERENT_BIT 0x0080 -#define GL_DYNAMIC_STORAGE_BIT 0x0100 -#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_TEXTURE_BUFFER_BINDING 0x8C2A +#define GL_MAP_PERSISTENT_BIT 0x0040 +#define GL_MAP_COHERENT_BIT 0x0080 +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 #define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 -#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F -#define GL_BUFFER_STORAGE_FLAGS 0x8220 -#define GL_CLEAR_TEXTURE 0x9365 -#define GL_LOCATION_COMPONENT 0x934A +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 +#define GL_CLEAR_TEXTURE 0x9365 +#define GL_LOCATION_COMPONENT 0x934A #define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B #define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C -#define GL_QUERY_BUFFER 0x9192 -#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 -#define GL_QUERY_BUFFER_BINDING 0x9193 -#define GL_QUERY_RESULT_NO_WAIT 0x9194 -#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 -typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); -typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); -typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); -typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); -typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); -typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#define GL_QUERY_BUFFER 0x9192 +#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define GL_QUERY_BUFFER_BINDING 0x9193 +#define GL_QUERY_RESULT_NO_WAIT 0x9194 +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +typedef void(APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags); +typedef void(APIENTRYP PFNGLCLEARTEXIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNGLBINDBUFFERSBASEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint* buffers); +typedef void(APIENTRYP PFNGLBINDBUFFERSRANGEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint* buffers, + const GLintptr* offsets, const GLsizeiptr* sizes); +typedef void(APIENTRYP PFNGLBINDTEXTURESPROC)(GLuint first, GLsizei count, const GLuint* textures); +typedef void(APIENTRYP PFNGLBINDSAMPLERSPROC)(GLuint first, GLsizei count, const GLuint* samplers); +typedef void(APIENTRYP PFNGLBINDIMAGETEXTURESPROC)(GLuint first, GLsizei count, const GLuint* textures); +typedef void(APIENTRYP PFNGLBINDVERTEXBUFFERSPROC)(GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, + const GLsizei* strides); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); -GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); -GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); -GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures); -GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers); -GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures); -GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +GLAPI void APIENTRY glBufferStorage(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags); +GLAPI void APIENTRY glClearTexImage(GLuint texture, GLint level, GLenum format, GLenum type, const void* data); +GLAPI void APIENTRY glClearTexSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data); +GLAPI void APIENTRY glBindBuffersBase(GLenum target, GLuint first, GLsizei count, const GLuint* buffers); +GLAPI void APIENTRY glBindBuffersRange(GLenum target, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, + const GLsizeiptr* sizes); +GLAPI void APIENTRY glBindTextures(GLuint first, GLsizei count, const GLuint* textures); +GLAPI void APIENTRY glBindSamplers(GLuint first, GLsizei count, const GLuint* samplers); +GLAPI void APIENTRY glBindImageTextures(GLuint first, GLsizei count, const GLuint* textures); +GLAPI void APIENTRY glBindVertexBuffers(GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides); #endif #endif /* GL_VERSION_4_4 */ #ifndef GL_VERSION_4_5 #define GL_VERSION_4_5 1 -#define GL_CONTEXT_LOST 0x0507 -#define GL_NEGATIVE_ONE_TO_ONE 0x935E -#define GL_ZERO_TO_ONE 0x935F -#define GL_CLIP_ORIGIN 0x935C -#define GL_CLIP_DEPTH_MODE 0x935D -#define GL_QUERY_WAIT_INVERTED 0x8E17 -#define GL_QUERY_NO_WAIT_INVERTED 0x8E18 -#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 +#define GL_CONTEXT_LOST 0x0507 +#define GL_NEGATIVE_ONE_TO_ONE 0x935E +#define GL_ZERO_TO_ONE 0x935F +#define GL_CLIP_ORIGIN 0x935C +#define GL_CLIP_DEPTH_MODE 0x935D +#define GL_QUERY_WAIT_INVERTED 0x8E17 +#define GL_QUERY_NO_WAIT_INVERTED 0x8E18 +#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 #define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A -#define GL_MAX_CULL_DISTANCES 0x82F9 +#define GL_MAX_CULL_DISTANCES 0x82F9 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA -#define GL_TEXTURE_TARGET 0x1006 -#define GL_QUERY_TARGET 0x82EA -#define GL_GUILTY_CONTEXT_RESET 0x8253 -#define GL_INNOCENT_CONTEXT_RESET 0x8254 -#define GL_UNKNOWN_CONTEXT_RESET 0x8255 -#define GL_RESET_NOTIFICATION_STRATEGY 0x8256 -#define GL_LOSE_CONTEXT_ON_RESET 0x8252 -#define GL_NO_RESET_NOTIFICATION 0x8261 +#define GL_TEXTURE_TARGET 0x1006 +#define GL_QUERY_TARGET 0x82EA +#define GL_GUILTY_CONTEXT_RESET 0x8253 +#define GL_INNOCENT_CONTEXT_RESET 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET 0x8252 +#define GL_NO_RESET_NOTIFICATION 0x8261 #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 -#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB #define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC -typedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth); -typedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); -typedef void (APIENTRYP PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); -typedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access); -typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void **params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); -typedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src); -typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); -typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); -typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); -typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); -typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures); -typedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture); -typedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture); -typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); -typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); -typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); -typedef void (APIENTRYP PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers); -typedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); -typedef void (APIENTRYP PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers); -typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); -typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void); -typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -typedef void (APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC) (void); +typedef void(APIENTRYP PFNGLCLIPCONTROLPROC)(GLenum origin, GLenum depth); +typedef void(APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint* ids); +typedef void(APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)(GLuint xfb, GLuint index, GLuint buffer); +typedef void(APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void(APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC)(GLuint xfb, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint* param); +typedef void(APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint64* param); +typedef void(APIENTRYP PFNGLCREATEBUFFERSPROC)(GLsizei n, GLuint* buffers); +typedef void(APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC)(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags); +typedef void(APIENTRYP PFNGLNAMEDBUFFERDATAPROC)(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage); +typedef void(APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); +typedef void(APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC)(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); +typedef void(APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC)(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, const void* data); +typedef void*(APIENTRYP PFNGLMAPNAMEDBUFFERPROC)(GLuint buffer, GLenum access); +typedef void*(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef GLboolean(APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC)(GLuint buffer); +typedef void(APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC)(GLuint buffer, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)(GLuint buffer, GLenum pname, GLint64* params); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC)(GLuint buffer, GLenum pname, void** params); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, void* data); +typedef void(APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)(GLuint framebuffer, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)(GLuint framebuffer, GLenum buf); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)(GLuint framebuffer, GLsizei n, const GLenum* bufs); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)(GLuint framebuffer, GLenum src); +typedef void(APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments); +typedef void(APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, + GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value); +typedef void(APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value); +typedef void(APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value); +typedef void(APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef void(APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC)(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, + GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter); +typedef GLenum(APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)(GLuint framebuffer, GLenum target); +typedef void(APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)(GLuint framebuffer, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLCREATERENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers); +typedef void(APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC)(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLuint renderbuffer, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)(GLuint renderbuffer, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLCREATETEXTURESPROC)(GLenum target, GLsizei n, GLuint* textures); +typedef void(APIENTRYP PFNGLTEXTUREBUFFERPROC)(GLuint texture, GLenum internalformat, GLuint buffer); +typedef void(APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC)(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE1DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE2DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE3DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, + GLsizei depth); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, + GLsizei height, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, + const void* pixels); +typedef void(APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, + GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, + const void* data); +typedef void(APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void(APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, + GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERFPROC)(GLuint texture, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, const GLfloat* param); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIPROC)(GLuint texture, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, const GLuint* params); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, const GLint* param); +typedef void(APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC)(GLuint texture); +typedef void(APIENTRYP PFNGLBINDTEXTUREUNITPROC)(GLuint unit, GLuint texture); +typedef void(APIENTRYP PFNGLGETTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC)(GLuint texture, GLint level, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC)(GLuint texture, GLint level, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLCREATEVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays); +typedef void(APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); +typedef void(APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); +typedef void(APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC)(GLuint vaobj, GLuint buffer); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC)(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC)(GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, + const GLintptr* offsets, const GLsizei* strides); +typedef void(APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC)(GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void(APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, + GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC)(GLuint vaobj, GLuint bindingindex, GLuint divisor); +typedef void(APIENTRYP PFNGLGETVERTEXARRAYIVPROC)(GLuint vaobj, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint64* param); +typedef void(APIENTRYP PFNGLCREATESAMPLERSPROC)(GLsizei n, GLuint* samplers); +typedef void(APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC)(GLsizei n, GLuint* pipelines); +typedef void(APIENTRYP PFNGLCREATEQUERIESPROC)(GLenum target, GLsizei n, GLuint* ids); +typedef void(APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void(APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void(APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void(APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void(APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers); +typedef void(APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels); +typedef GLenum(APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC)(void); +typedef void(APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint lod, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNGLGETNTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNGLGETNUNIFORMDVPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMFVPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLint* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMUIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint* params); +typedef void(APIENTRYP PFNGLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, + void* data); +typedef void(APIENTRYP PFNGLTEXTUREBARRIERPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClipControl (GLenum origin, GLenum depth); -GLAPI void APIENTRY glCreateTransformFeedbacks (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glTransformFeedbackBufferBase (GLuint xfb, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackBufferRange (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glGetTransformFeedbackiv (GLuint xfb, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetTransformFeedbacki_v (GLuint xfb, GLenum pname, GLuint index, GLint *param); -GLAPI void APIENTRY glGetTransformFeedbacki64_v (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); -GLAPI void APIENTRY glCreateBuffers (GLsizei n, GLuint *buffers); -GLAPI void APIENTRY glNamedBufferStorage (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); -GLAPI void APIENTRY glNamedBufferData (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); -GLAPI void APIENTRY glNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI void APIENTRY glCopyNamedBufferSubData (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI void APIENTRY glClearNamedBufferData (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearNamedBufferSubData (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -GLAPI void *APIENTRY glMapNamedBuffer (GLuint buffer, GLenum access); -GLAPI void *APIENTRY glMapNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI GLboolean APIENTRY glUnmapNamedBuffer (GLuint buffer); -GLAPI void APIENTRY glFlushMappedNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glGetNamedBufferParameteriv (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedBufferParameteri64v (GLuint buffer, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetNamedBufferPointerv (GLuint buffer, GLenum pname, void **params); -GLAPI void APIENTRY glGetNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); -GLAPI void APIENTRY glCreateFramebuffers (GLsizei n, GLuint *framebuffers); -GLAPI void APIENTRY glNamedFramebufferRenderbuffer (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glNamedFramebufferParameteri (GLuint framebuffer, GLenum pname, GLint param); -GLAPI void APIENTRY glNamedFramebufferTexture (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTextureLayer (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glNamedFramebufferDrawBuffer (GLuint framebuffer, GLenum buf); -GLAPI void APIENTRY glNamedFramebufferDrawBuffers (GLuint framebuffer, GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glNamedFramebufferReadBuffer (GLuint framebuffer, GLenum src); -GLAPI void APIENTRY glInvalidateNamedFramebufferData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); -GLAPI void APIENTRY glInvalidateNamedFramebufferSubData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glClearNamedFramebufferiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI void APIENTRY glClearNamedFramebufferuiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI void APIENTRY glClearNamedFramebufferfv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI void APIENTRY glBlitNamedFramebuffer (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI GLenum APIENTRY glCheckNamedFramebufferStatus (GLuint framebuffer, GLenum target); -GLAPI void APIENTRY glGetNamedFramebufferParameteriv (GLuint framebuffer, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameteriv (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glCreateRenderbuffers (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glNamedRenderbufferStorage (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisample (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetNamedRenderbufferParameteriv (GLuint renderbuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glCreateTextures (GLenum target, GLsizei n, GLuint *textures); -GLAPI void APIENTRY glTextureBuffer (GLuint texture, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glTextureBufferRange (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glTextureStorage1D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTextureStorage2D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTextureStorage3D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glTextureStorage2DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTextureStorage3DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCompressedTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCompressedTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -GLAPI void APIENTRY glCopyTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glCopyTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTextureParameterf (GLuint texture, GLenum pname, GLfloat param); -GLAPI void APIENTRY glTextureParameterfv (GLuint texture, GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glTextureParameteri (GLuint texture, GLenum pname, GLint param); -GLAPI void APIENTRY glTextureParameterIiv (GLuint texture, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureParameterIuiv (GLuint texture, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glTextureParameteriv (GLuint texture, GLenum pname, const GLint *param); -GLAPI void APIENTRY glGenerateTextureMipmap (GLuint texture); -GLAPI void APIENTRY glBindTextureUnit (GLuint unit, GLuint texture); -GLAPI void APIENTRY glGetTextureImage (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -GLAPI void APIENTRY glGetCompressedTextureImage (GLuint texture, GLint level, GLsizei bufSize, void *pixels); -GLAPI void APIENTRY glGetTextureLevelParameterfv (GLuint texture, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureLevelParameteriv (GLuint texture, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureParameterfv (GLuint texture, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureParameterIiv (GLuint texture, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureParameterIuiv (GLuint texture, GLenum pname, GLuint *params); -GLAPI void APIENTRY glGetTextureParameteriv (GLuint texture, GLenum pname, GLint *params); -GLAPI void APIENTRY glCreateVertexArrays (GLsizei n, GLuint *arrays); -GLAPI void APIENTRY glDisableVertexArrayAttrib (GLuint vaobj, GLuint index); -GLAPI void APIENTRY glEnableVertexArrayAttrib (GLuint vaobj, GLuint index); -GLAPI void APIENTRY glVertexArrayElementBuffer (GLuint vaobj, GLuint buffer); -GLAPI void APIENTRY glVertexArrayVertexBuffer (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -GLAPI void APIENTRY glVertexArrayVertexBuffers (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); -GLAPI void APIENTRY glVertexArrayAttribBinding (GLuint vaobj, GLuint attribindex, GLuint bindingindex); -GLAPI void APIENTRY glVertexArrayAttribFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayAttribIFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayAttribLFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayBindingDivisor (GLuint vaobj, GLuint bindingindex, GLuint divisor); -GLAPI void APIENTRY glGetVertexArrayiv (GLuint vaobj, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayIndexediv (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayIndexed64iv (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); -GLAPI void APIENTRY glCreateSamplers (GLsizei n, GLuint *samplers); -GLAPI void APIENTRY glCreateProgramPipelines (GLsizei n, GLuint *pipelines); -GLAPI void APIENTRY glCreateQueries (GLenum target, GLsizei n, GLuint *ids); -GLAPI void APIENTRY glGetQueryBufferObjecti64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -GLAPI void APIENTRY glGetQueryBufferObjectiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -GLAPI void APIENTRY glGetQueryBufferObjectui64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -GLAPI void APIENTRY glGetQueryBufferObjectuiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -GLAPI void APIENTRY glMemoryBarrierByRegion (GLbitfield barriers); -GLAPI void APIENTRY glGetTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -GLAPI void APIENTRY glGetCompressedTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); -GLAPI GLenum APIENTRY glGetGraphicsResetStatus (void); -GLAPI void APIENTRY glGetnCompressedTexImage (GLenum target, GLint lod, GLsizei bufSize, void *pixels); -GLAPI void APIENTRY glGetnTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -GLAPI void APIENTRY glGetnUniformdv (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -GLAPI void APIENTRY glGetnUniformfv (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -GLAPI void APIENTRY glGetnUniformiv (GLuint program, GLint location, GLsizei bufSize, GLint *params); -GLAPI void APIENTRY glGetnUniformuiv (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -GLAPI void APIENTRY glReadnPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -GLAPI void APIENTRY glTextureBarrier (void); +GLAPI void APIENTRY glClipControl(GLenum origin, GLenum depth); +GLAPI void APIENTRY glCreateTransformFeedbacks(GLsizei n, GLuint* ids); +GLAPI void APIENTRY glTransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glGetTransformFeedbackiv(GLuint xfb, GLenum pname, GLint* param); +GLAPI void APIENTRY glGetTransformFeedbacki_v(GLuint xfb, GLenum pname, GLuint index, GLint* param); +GLAPI void APIENTRY glGetTransformFeedbacki64_v(GLuint xfb, GLenum pname, GLuint index, GLint64* param); +GLAPI void APIENTRY glCreateBuffers(GLsizei n, GLuint* buffers); +GLAPI void APIENTRY glNamedBufferStorage(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags); +GLAPI void APIENTRY glNamedBufferData(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); +GLAPI void APIENTRY glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data); +GLAPI void APIENTRY glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, + GLenum type, const void* data); +GLAPI void* APIENTRY glMapNamedBuffer(GLuint buffer, GLenum access); +GLAPI void* APIENTRY glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI GLboolean APIENTRY glUnmapNamedBuffer(GLuint buffer); +GLAPI void APIENTRY glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glGetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64* params); +GLAPI void APIENTRY glGetNamedBufferPointerv(GLuint buffer, GLenum pname, void** params); +GLAPI void APIENTRY glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, void* data); +GLAPI void APIENTRY glCreateFramebuffers(GLsizei n, GLuint* framebuffers); +GLAPI void APIENTRY glNamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glNamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glNamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glNamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf); +GLAPI void APIENTRY glNamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum* bufs); +GLAPI void APIENTRY glNamedFramebufferReadBuffer(GLuint framebuffer, GLenum src); +GLAPI void APIENTRY glInvalidateNamedFramebufferData(GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments); +GLAPI void APIENTRY glInvalidateNamedFramebufferSubData(GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, + GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value); +GLAPI void APIENTRY glClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value); +GLAPI void APIENTRY glClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value); +GLAPI void APIENTRY glClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI void APIENTRY glBlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, + GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI GLenum APIENTRY glCheckNamedFramebufferStatus(GLuint framebuffer, GLenum target); +GLAPI void APIENTRY glGetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, GLint* param); +GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params); +GLAPI void APIENTRY glCreateRenderbuffers(GLsizei n, GLuint* renderbuffers); +GLAPI void APIENTRY glNamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, GLint* params); +GLAPI void APIENTRY glCreateTextures(GLenum target, GLsizei n, GLuint* textures); +GLAPI void APIENTRY glTextureBuffer(GLuint texture, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTextureBufferRange(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTextureStorage1D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage2DMultisample(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisample(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureSubImage1D(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glTextureSubImage3D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glCompressedTextureSubImage1D(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, + GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCompressedTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCompressedTextureSubImage3D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +GLAPI void APIENTRY glCopyTextureSubImage1D(GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height); +GLAPI void APIENTRY glCopyTextureSubImage3D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, + GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureParameterf(GLuint texture, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTextureParameterfv(GLuint texture, GLenum pname, const GLfloat* param); +GLAPI void APIENTRY glTextureParameteri(GLuint texture, GLenum pname, GLint param); +GLAPI void APIENTRY glTextureParameterIiv(GLuint texture, GLenum pname, const GLint* params); +GLAPI void APIENTRY glTextureParameterIuiv(GLuint texture, GLenum pname, const GLuint* params); +GLAPI void APIENTRY glTextureParameteriv(GLuint texture, GLenum pname, const GLint* param); +GLAPI void APIENTRY glGenerateTextureMipmap(GLuint texture); +GLAPI void APIENTRY glBindTextureUnit(GLuint unit, GLuint texture); +GLAPI void APIENTRY glGetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels); +GLAPI void APIENTRY glGetCompressedTextureImage(GLuint texture, GLint level, GLsizei bufSize, void* pixels); +GLAPI void APIENTRY glGetTextureLevelParameterfv(GLuint texture, GLint level, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetTextureLevelParameteriv(GLuint texture, GLint level, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetTextureParameterfv(GLuint texture, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetTextureParameterIiv(GLuint texture, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetTextureParameterIuiv(GLuint texture, GLenum pname, GLuint* params); +GLAPI void APIENTRY glGetTextureParameteriv(GLuint texture, GLenum pname, GLint* params); +GLAPI void APIENTRY glCreateVertexArrays(GLsizei n, GLuint* arrays); +GLAPI void APIENTRY glDisableVertexArrayAttrib(GLuint vaobj, GLuint index); +GLAPI void APIENTRY glEnableVertexArrayAttrib(GLuint vaobj, GLuint index); +GLAPI void APIENTRY glVertexArrayElementBuffer(GLuint vaobj, GLuint buffer); +GLAPI void APIENTRY glVertexArrayVertexBuffer(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexBuffers(GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, + const GLsizei* strides); +GLAPI void APIENTRY glVertexArrayAttribBinding(GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayAttribFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayAttribIFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayAttribLFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayBindingDivisor(GLuint vaobj, GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glGetVertexArrayiv(GLuint vaobj, GLenum pname, GLint* param); +GLAPI void APIENTRY glGetVertexArrayIndexediv(GLuint vaobj, GLuint index, GLenum pname, GLint* param); +GLAPI void APIENTRY glGetVertexArrayIndexed64iv(GLuint vaobj, GLuint index, GLenum pname, GLint64* param); +GLAPI void APIENTRY glCreateSamplers(GLsizei n, GLuint* samplers); +GLAPI void APIENTRY glCreateProgramPipelines(GLsizei n, GLuint* pipelines); +GLAPI void APIENTRY glCreateQueries(GLenum target, GLsizei n, GLuint* ids); +GLAPI void APIENTRY glGetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glGetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glGetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glGetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glMemoryBarrierByRegion(GLbitfield barriers); +GLAPI void APIENTRY glGetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels); +GLAPI void APIENTRY glGetCompressedTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels); +GLAPI GLenum APIENTRY glGetGraphicsResetStatus(void); +GLAPI void APIENTRY glGetnCompressedTexImage(GLenum target, GLint lod, GLsizei bufSize, void* pixels); +GLAPI void APIENTRY glGetnTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels); +GLAPI void APIENTRY glGetnUniformdv(GLuint program, GLint location, GLsizei bufSize, GLdouble* params); +GLAPI void APIENTRY glGetnUniformfv(GLuint program, GLint location, GLsizei bufSize, GLfloat* params); +GLAPI void APIENTRY glGetnUniformiv(GLuint program, GLint location, GLsizei bufSize, GLint* params); +GLAPI void APIENTRY glGetnUniformuiv(GLuint program, GLint location, GLsizei bufSize, GLuint* params); +GLAPI void APIENTRY glReadnPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void* data); +GLAPI void APIENTRY glTextureBarrier(void); #endif #endif /* GL_VERSION_4_5 */ #ifndef GL_VERSION_4_6 #define GL_VERSION_4_6 1 -#define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551 -#define GL_SPIR_V_BINARY 0x9552 -#define GL_PARAMETER_BUFFER 0x80EE -#define GL_PARAMETER_BUFFER_BINDING 0x80EF -#define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 -#define GL_VERTICES_SUBMITTED 0x82EE -#define GL_PRIMITIVES_SUBMITTED 0x82EF -#define GL_VERTEX_SHADER_INVOCATIONS 0x82F0 -#define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1 +#define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551 +#define GL_SPIR_V_BINARY 0x9552 +#define GL_PARAMETER_BUFFER 0x80EE +#define GL_PARAMETER_BUFFER_BINDING 0x80EF +#define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 +#define GL_VERTICES_SUBMITTED 0x82EE +#define GL_PRIMITIVES_SUBMITTED 0x82EF +#define GL_VERTEX_SHADER_INVOCATIONS 0x82F0 +#define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1 #define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2 #define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3 -#define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4 -#define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5 -#define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6 -#define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7 -#define GL_POLYGON_OFFSET_CLAMP 0x8E1B -#define GL_SPIR_V_EXTENSIONS 0x9553 -#define GL_NUM_SPIR_V_EXTENSIONS 0x9554 -#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE -#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF -#define GL_TRANSFORM_FEEDBACK_OVERFLOW 0x82EC +#define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4 +#define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5 +#define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6 +#define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7 +#define GL_POLYGON_OFFSET_CLAMP 0x8E1B +#define GL_SPIR_V_EXTENSIONS 0x9553 +#define GL_NUM_SPIR_V_EXTENSIONS 0x9554 +#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF +#define GL_TRANSFORM_FEEDBACK_OVERFLOW 0x82EC #define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW 0x82ED -typedef void (APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC) (GLfloat factor, GLfloat units, GLfloat clamp); +typedef void(APIENTRYP PFNGLSPECIALIZESHADERPROC)(GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, + const GLuint* pConstantIndex, const GLuint* pConstantValue); +typedef void(APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)(GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, + GLsizei stride); +typedef void(APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, + GLsizei maxdrawcount, GLsizei stride); +typedef void(APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC)(GLfloat factor, GLfloat units, GLfloat clamp); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSpecializeShader (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); -GLAPI void APIENTRY glMultiDrawArraysIndirectCount (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirectCount (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -GLAPI void APIENTRY glPolygonOffsetClamp (GLfloat factor, GLfloat units, GLfloat clamp); +GLAPI void APIENTRY glSpecializeShader(GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, + const GLuint* pConstantIndex, const GLuint* pConstantValue); +GLAPI void APIENTRY glMultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, + GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glPolygonOffsetClamp(GLfloat factor, GLfloat units, GLfloat clamp); #endif #endif /* GL_VERSION_4_6 */ @@ -2904,12 +3036,14 @@ GLAPI void APIENTRY glPolygonOffsetClamp (GLfloat factor, GLfloat units, GLfloat #ifndef GL_ARB_ES3_2_compatibility #define GL_ARB_ES3_2_compatibility 1 -#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE +#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE #define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381 #define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382 -typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXARBPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +typedef void(APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXARBPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, + GLfloat maxZ, GLfloat maxW); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPrimitiveBoundingBoxARB (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +GLAPI void APIENTRY glPrimitiveBoundingBoxARB(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, + GLfloat maxZ, GLfloat maxW); #endif #endif /* GL_ARB_ES3_2_compatibility */ @@ -2928,40 +3062,40 @@ GLAPI void APIENTRY glPrimitiveBoundingBoxARB (GLfloat minX, GLfloat minY, GLflo #ifndef GL_ARB_bindless_texture #define GL_ARB_bindless_texture 1 typedef khronos_uint64_t GLuint64EXT; -#define GL_UNSIGNED_INT64_ARB 0x140F -typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); -typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); -typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); -typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +#define GL_UNSIGNED_INT64_ARB 0x140F +typedef GLuint64(APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC)(GLuint texture); +typedef GLuint64(APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC)(GLuint texture, GLuint sampler); +typedef void(APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC)(GLuint64 handle); +typedef void(APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC)(GLuint64 handle); +typedef GLuint64(APIENTRYP PFNGLGETIMAGEHANDLEARBPROC)(GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void(APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC)(GLuint64 handle, GLenum access); +typedef void(APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC)(GLuint64 handle); +typedef void(APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC)(GLint location, GLuint64 value); +typedef void(APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC)(GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC)(GLuint program, GLint location, GLuint64 value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64* values); +typedef GLboolean(APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC)(GLuint64 handle); +typedef GLboolean(APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC)(GLuint64 handle); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC)(GLuint index, GLuint64EXT x); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC)(GLuint index, const GLuint64EXT* v); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC)(GLuint index, GLenum pname, GLuint64EXT* params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture); -GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler); -GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle); -GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle); -GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access); -GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle); -GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value); -GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value); -GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle); -GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle); -GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x); -GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params); +GLAPI GLuint64 APIENTRY glGetTextureHandleARB(GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB(GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentARB(GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentARB(GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleARB(GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentARB(GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentARB(GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64ARB(GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vARB(GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glProgramUniformHandleui64ARB(GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vARB(GLuint program, GLint location, GLsizei count, const GLuint64* values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB(GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentARB(GLuint64 handle); +GLAPI void APIENTRY glVertexAttribL1ui64ARB(GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL1ui64vARB(GLuint index, const GLuint64EXT* v); +GLAPI void APIENTRY glGetVertexAttribLui64vARB(GLuint index, GLenum pname, GLuint64EXT* params); #endif #endif /* GL_ARB_bindless_texture */ @@ -2977,11 +3111,11 @@ GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLui #define GL_ARB_cl_event 1 struct _cl_context; struct _cl_event; -#define GL_SYNC_CL_EVENT_ARB 0x8240 -#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 -typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#define GL_SYNC_CL_EVENT_ARB 0x8240 +#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 +typedef GLsync(APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC)(struct _cl_context* context, struct _cl_event* event, GLbitfield flags); #ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB(struct _cl_context* context, struct _cl_event* event, GLbitfield flags); #endif #endif /* GL_ARB_cl_event */ @@ -3011,9 +3145,11 @@ GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, s #define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB #define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 #define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF -typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +typedef void(APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, + GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +GLAPI void APIENTRY glDispatchComputeGroupSizeARB(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, + GLuint group_size_y, GLuint group_size_z); #endif #endif /* GL_ARB_compute_variable_group_size */ @@ -3039,38 +3175,42 @@ GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint n #ifndef GL_ARB_debug_output #define GL_ARB_debug_output 1 -typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +typedef void(APIENTRY* GLDEBUGPROCARB)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, + const void* userParam); +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B -#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +typedef void(APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, + GLboolean enabled); +typedef void(APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); +typedef void(APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void* userParam); +typedef GLuint(APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, + GLenum* severities, GLsizei* lengths, GLchar* messageLog); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI void APIENTRY glDebugMessageControlARB(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertARB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); +GLAPI void APIENTRY glDebugMessageCallbackARB(GLDEBUGPROCARB callback, const void* userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogARB(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, + GLenum* severities, GLsizei* lengths, GLchar* messageLog); #endif #endif /* GL_ARB_debug_output */ @@ -3092,15 +3232,15 @@ GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GL #ifndef GL_ARB_draw_buffers_blend #define GL_ARB_draw_buffers_blend 1 -typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void(APIENTRYP PFNGLBLENDEQUATIONIARBPROC)(GLuint buf, GLenum mode); +typedef void(APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void(APIENTRYP PFNGLBLENDFUNCIARBPROC)(GLuint buf, GLenum src, GLenum dst); +typedef void(APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glBlendEquationiARB(GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunciARB(GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateiARB(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif #endif /* GL_ARB_draw_buffers_blend */ @@ -3114,11 +3254,11 @@ GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum d #ifndef GL_ARB_draw_instanced #define GL_ARB_draw_instanced 1 -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +typedef void(APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC)(GLenum mode, GLint first, GLsizei count, GLsizei primcount); +typedef void(APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +GLAPI void APIENTRY glDrawArraysInstancedARB(GLenum mode, GLint first, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedARB(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount); #endif #endif /* GL_ARB_draw_instanced */ @@ -3160,33 +3300,33 @@ GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLen #ifndef GL_ARB_geometry_shader4 #define GL_ARB_geometry_shader4 1 -#define GL_LINES_ADJACENCY_ARB 0x000A -#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B -#define GL_TRIANGLES_ADJACENCY_ARB 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D -#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_LINES_ADJACENCY_ARB 0x000A +#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B +#define GL_TRIANGLES_ADJACENCY_ARB 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D +#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 -#define GL_GEOMETRY_SHADER_ARB 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA -#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC +#define GL_GEOMETRY_SHADER_ARB 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +typedef void(APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC)(GLuint program, GLenum pname, GLint value); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); -GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +GLAPI void APIENTRY glProgramParameteriARB(GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glFramebufferTextureARB(GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTextureLayerARB(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glFramebufferTextureFaceARB(GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #endif /* GL_ARB_geometry_shader4 */ @@ -3201,10 +3341,12 @@ GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachmen #ifndef GL_ARB_gl_spirv #define GL_ARB_gl_spirv 1 #define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551 -#define GL_SPIR_V_BINARY_ARB 0x9552 -typedef void (APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); +#define GL_SPIR_V_BINARY_ARB 0x9552 +typedef void(APIENTRYP PFNGLSPECIALIZESHADERARBPROC)(GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, + const GLuint* pConstantIndex, const GLuint* pConstantValue); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSpecializeShaderARB (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); +GLAPI void APIENTRY glSpecializeShaderARB(GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, + const GLuint* pConstantIndex, const GLuint* pConstantValue); #endif #endif /* GL_ARB_gl_spirv */ @@ -3218,86 +3360,86 @@ GLAPI void APIENTRY glSpecializeShaderARB (GLuint shader, const GLchar *pEntryPo #ifndef GL_ARB_gpu_shader_int64 #define GL_ARB_gpu_shader_int64 1 -#define GL_INT64_ARB 0x140E -#define GL_INT64_VEC2_ARB 0x8FE9 -#define GL_INT64_VEC3_ARB 0x8FEA -#define GL_INT64_VEC4_ARB 0x8FEB -#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 -typedef void (APIENTRYP PFNGLUNIFORM1I64ARBPROC) (GLint location, GLint64 x); -typedef void (APIENTRYP PFNGLUNIFORM2I64ARBPROC) (GLint location, GLint64 x, GLint64 y); -typedef void (APIENTRYP PFNGLUNIFORM3I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z); -typedef void (APIENTRYP PFNGLUNIFORM4I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); -typedef void (APIENTRYP PFNGLUNIFORM1I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLUNIFORM2I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLUNIFORM3I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLUNIFORM4I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLUNIFORM1UI64ARBPROC) (GLint location, GLuint64 x); -typedef void (APIENTRYP PFNGLUNIFORM2UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y); -typedef void (APIENTRYP PFNGLUNIFORM3UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z); -typedef void (APIENTRYP PFNGLUNIFORM4UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); -typedef void (APIENTRYP PFNGLUNIFORM1UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLUNIFORM2UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLUNIFORM3UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLUNIFORM4UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLGETUNIFORMI64VARBPROC) (GLuint program, GLint location, GLint64 *params); -typedef void (APIENTRYP PFNGLGETUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLuint64 *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint64 *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64ARBPROC) (GLuint program, GLint location, GLint64 x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64ARBPROC) (GLuint program, GLint location, GLuint64 x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +#define GL_INT64_ARB 0x140E +#define GL_INT64_VEC2_ARB 0x8FE9 +#define GL_INT64_VEC3_ARB 0x8FEA +#define GL_INT64_VEC4_ARB 0x8FEB +#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 +typedef void(APIENTRYP PFNGLUNIFORM1I64ARBPROC)(GLint location, GLint64 x); +typedef void(APIENTRYP PFNGLUNIFORM2I64ARBPROC)(GLint location, GLint64 x, GLint64 y); +typedef void(APIENTRYP PFNGLUNIFORM3I64ARBPROC)(GLint location, GLint64 x, GLint64 y, GLint64 z); +typedef void(APIENTRYP PFNGLUNIFORM4I64ARBPROC)(GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +typedef void(APIENTRYP PFNGLUNIFORM1I64VARBPROC)(GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLUNIFORM2I64VARBPROC)(GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLUNIFORM3I64VARBPROC)(GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLUNIFORM4I64VARBPROC)(GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLUNIFORM1UI64ARBPROC)(GLint location, GLuint64 x); +typedef void(APIENTRYP PFNGLUNIFORM2UI64ARBPROC)(GLint location, GLuint64 x, GLuint64 y); +typedef void(APIENTRYP PFNGLUNIFORM3UI64ARBPROC)(GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +typedef void(APIENTRYP PFNGLUNIFORM4UI64ARBPROC)(GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +typedef void(APIENTRYP PFNGLUNIFORM1UI64VARBPROC)(GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLUNIFORM2UI64VARBPROC)(GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLUNIFORM3UI64VARBPROC)(GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLUNIFORM4UI64VARBPROC)(GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLGETUNIFORMI64VARBPROC)(GLuint program, GLint location, GLint64* params); +typedef void(APIENTRYP PFNGLGETUNIFORMUI64VARBPROC)(GLuint program, GLint location, GLuint64* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMI64VARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint64* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMUI64VARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint64* params); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1I64ARBPROC)(GLuint program, GLint location, GLint64 x); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2I64ARBPROC)(GLuint program, GLint location, GLint64 x, GLint64 y); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3I64ARBPROC)(GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4I64ARBPROC)(GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4I64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UI64ARBPROC)(GLuint program, GLint location, GLuint64 x); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UI64ARBPROC)(GLuint program, GLint location, GLuint64 x, GLuint64 y); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UI64ARBPROC)(GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UI64ARBPROC)(GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64* value); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1i64ARB (GLint location, GLint64 x); -GLAPI void APIENTRY glUniform2i64ARB (GLint location, GLint64 x, GLint64 y); -GLAPI void APIENTRY glUniform3i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z); -GLAPI void APIENTRY glUniform4i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); -GLAPI void APIENTRY glUniform1i64vARB (GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glUniform2i64vARB (GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glUniform3i64vARB (GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glUniform4i64vARB (GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glUniform1ui64ARB (GLint location, GLuint64 x); -GLAPI void APIENTRY glUniform2ui64ARB (GLint location, GLuint64 x, GLuint64 y); -GLAPI void APIENTRY glUniform3ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z); -GLAPI void APIENTRY glUniform4ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); -GLAPI void APIENTRY glUniform1ui64vARB (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glUniform2ui64vARB (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glUniform3ui64vARB (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glUniform4ui64vARB (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glGetUniformi64vARB (GLuint program, GLint location, GLint64 *params); -GLAPI void APIENTRY glGetUniformui64vARB (GLuint program, GLint location, GLuint64 *params); -GLAPI void APIENTRY glGetnUniformi64vARB (GLuint program, GLint location, GLsizei bufSize, GLint64 *params); -GLAPI void APIENTRY glGetnUniformui64vARB (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params); -GLAPI void APIENTRY glProgramUniform1i64ARB (GLuint program, GLint location, GLint64 x); -GLAPI void APIENTRY glProgramUniform2i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y); -GLAPI void APIENTRY glProgramUniform3i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); -GLAPI void APIENTRY glProgramUniform4i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); -GLAPI void APIENTRY glProgramUniform1i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glProgramUniform2i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glProgramUniform3i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glProgramUniform4i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); -GLAPI void APIENTRY glProgramUniform1ui64ARB (GLuint program, GLint location, GLuint64 x); -GLAPI void APIENTRY glProgramUniform2ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y); -GLAPI void APIENTRY glProgramUniform3ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); -GLAPI void APIENTRY glProgramUniform4ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); -GLAPI void APIENTRY glProgramUniform1ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glProgramUniform2ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glProgramUniform3ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glProgramUniform4ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glUniform1i64ARB(GLint location, GLint64 x); +GLAPI void APIENTRY glUniform2i64ARB(GLint location, GLint64 x, GLint64 y); +GLAPI void APIENTRY glUniform3i64ARB(GLint location, GLint64 x, GLint64 y, GLint64 z); +GLAPI void APIENTRY glUniform4i64ARB(GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +GLAPI void APIENTRY glUniform1i64vARB(GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glUniform2i64vARB(GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glUniform3i64vARB(GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glUniform4i64vARB(GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glUniform1ui64ARB(GLint location, GLuint64 x); +GLAPI void APIENTRY glUniform2ui64ARB(GLint location, GLuint64 x, GLuint64 y); +GLAPI void APIENTRY glUniform3ui64ARB(GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +GLAPI void APIENTRY glUniform4ui64ARB(GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +GLAPI void APIENTRY glUniform1ui64vARB(GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glUniform2ui64vARB(GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glUniform3ui64vARB(GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glUniform4ui64vARB(GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glGetUniformi64vARB(GLuint program, GLint location, GLint64* params); +GLAPI void APIENTRY glGetUniformui64vARB(GLuint program, GLint location, GLuint64* params); +GLAPI void APIENTRY glGetnUniformi64vARB(GLuint program, GLint location, GLsizei bufSize, GLint64* params); +GLAPI void APIENTRY glGetnUniformui64vARB(GLuint program, GLint location, GLsizei bufSize, GLuint64* params); +GLAPI void APIENTRY glProgramUniform1i64ARB(GLuint program, GLint location, GLint64 x); +GLAPI void APIENTRY glProgramUniform2i64ARB(GLuint program, GLint location, GLint64 x, GLint64 y); +GLAPI void APIENTRY glProgramUniform3i64ARB(GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); +GLAPI void APIENTRY glProgramUniform4i64ARB(GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +GLAPI void APIENTRY glProgramUniform1i64vARB(GLuint program, GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glProgramUniform2i64vARB(GLuint program, GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glProgramUniform3i64vARB(GLuint program, GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glProgramUniform4i64vARB(GLuint program, GLint location, GLsizei count, const GLint64* value); +GLAPI void APIENTRY glProgramUniform1ui64ARB(GLuint program, GLint location, GLuint64 x); +GLAPI void APIENTRY glProgramUniform2ui64ARB(GLuint program, GLint location, GLuint64 x, GLuint64 y); +GLAPI void APIENTRY glProgramUniform3ui64ARB(GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +GLAPI void APIENTRY glProgramUniform4ui64ARB(GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +GLAPI void APIENTRY glProgramUniform1ui64vARB(GLuint program, GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glProgramUniform2ui64vARB(GLuint program, GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glProgramUniform3ui64vARB(GLuint program, GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glProgramUniform4ui64vARB(GLuint program, GLint location, GLsizei count, const GLuint64* value); #endif #endif /* GL_ARB_gpu_shader_int64 */ @@ -3311,22 +3453,25 @@ GLAPI void APIENTRY glProgramUniform4ui64vARB (GLuint program, GLint location, G #ifndef GL_ARB_indirect_parameters #define GL_ARB_indirect_parameters 1 -#define GL_PARAMETER_BUFFER_ARB 0x80EE -#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#define GL_PARAMETER_BUFFER_ARB 0x80EE +#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF +typedef void(APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC)(GLenum mode, const void* indirect, GLintptr drawcount, + GLsizei maxdrawcount, GLsizei stride); +typedef void(APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC)(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, + GLsizei maxdrawcount, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB(GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, + GLsizei maxdrawcount, GLsizei stride); #endif #endif /* GL_ARB_indirect_parameters */ #ifndef GL_ARB_instanced_arrays #define GL_ARB_instanced_arrays 1 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); +typedef void(APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC)(GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); +GLAPI void APIENTRY glVertexAttribDivisorARB(GLuint index, GLuint divisor); #endif #endif /* GL_ARB_instanced_arrays */ @@ -3336,26 +3481,26 @@ GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); #ifndef GL_ARB_internalformat_query2 #define GL_ARB_internalformat_query2 1 -#define GL_SRGB_DECODE_ARB 0x8299 -#define GL_VIEW_CLASS_EAC_R11 0x9383 -#define GL_VIEW_CLASS_EAC_RG11 0x9384 -#define GL_VIEW_CLASS_ETC2_RGB 0x9385 -#define GL_VIEW_CLASS_ETC2_RGBA 0x9386 -#define GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387 -#define GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388 -#define GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389 -#define GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A -#define GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B -#define GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C -#define GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D -#define GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E -#define GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F -#define GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390 -#define GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391 -#define GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392 -#define GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393 -#define GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394 -#define GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395 +#define GL_SRGB_DECODE_ARB 0x8299 +#define GL_VIEW_CLASS_EAC_R11 0x9383 +#define GL_VIEW_CLASS_EAC_RG11 0x9384 +#define GL_VIEW_CLASS_ETC2_RGB 0x9385 +#define GL_VIEW_CLASS_ETC2_RGBA 0x9386 +#define GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387 +#define GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388 +#define GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389 +#define GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A +#define GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B +#define GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C +#define GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D +#define GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E +#define GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F +#define GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390 +#define GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391 +#define GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392 +#define GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393 +#define GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394 +#define GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395 #endif /* GL_ARB_internalformat_query2 */ #ifndef GL_ARB_invalidate_subdata @@ -3385,32 +3530,32 @@ GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); #ifndef GL_ARB_parallel_shader_compile #define GL_ARB_parallel_shader_compile 1 #define GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0 -#define GL_COMPLETION_STATUS_ARB 0x91B1 -typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSARBPROC) (GLuint count); +#define GL_COMPLETION_STATUS_ARB 0x91B1 +typedef void(APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSARBPROC)(GLuint count); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMaxShaderCompilerThreadsARB (GLuint count); +GLAPI void APIENTRY glMaxShaderCompilerThreadsARB(GLuint count); #endif #endif /* GL_ARB_parallel_shader_compile */ #ifndef GL_ARB_pipeline_statistics_query #define GL_ARB_pipeline_statistics_query 1 -#define GL_VERTICES_SUBMITTED_ARB 0x82EE -#define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF -#define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0 +#define GL_VERTICES_SUBMITTED_ARB 0x82EE +#define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF +#define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0 #define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1 #define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2 #define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3 #define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4 #define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5 -#define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6 +#define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6 #define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7 #endif /* GL_ARB_pipeline_statistics_query */ #ifndef GL_ARB_pixel_buffer_object #define GL_ARB_pixel_buffer_object 1 -#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB -#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED +#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF #endif /* GL_ARB_pixel_buffer_object */ @@ -3441,29 +3586,30 @@ GLAPI void APIENTRY glMaxShaderCompilerThreadsARB (GLuint count); #ifndef GL_ARB_robustness #define GL_ARB_robustness 1 #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 -#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 -#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 #define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 -typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); -typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); -typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img); -typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +typedef GLenum(APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC)(void); +typedef void(APIENTRYP PFNGLGETNTEXIMAGEARBPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* img); +typedef void(APIENTRYP PFNGLREADNPIXELSARBPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, + GLsizei bufSize, void* data); +typedef void(APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint lod, GLsizei bufSize, void* img); +typedef void(APIENTRYP PFNGLGETNUNIFORMFVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMUIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint* params); +typedef void(APIENTRYP PFNGLGETNUNIFORMDVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble* params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); -GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); -GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img); -GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); -GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB(void); +GLAPI void APIENTRY glGetnTexImageARB(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* img); +GLAPI void APIENTRY glReadnPixelsARB(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void* data); +GLAPI void APIENTRY glGetnCompressedTexImageARB(GLenum target, GLint lod, GLsizei bufSize, void* img); +GLAPI void APIENTRY glGetnUniformfvARB(GLuint program, GLint location, GLsizei bufSize, GLfloat* params); +GLAPI void APIENTRY glGetnUniformivARB(GLuint program, GLint location, GLsizei bufSize, GLint* params); +GLAPI void APIENTRY glGetnUniformuivARB(GLuint program, GLint location, GLsizei bufSize, GLuint* params); +GLAPI void APIENTRY glGetnUniformdvARB(GLuint program, GLint location, GLsizei bufSize, GLdouble* params); #endif #endif /* GL_ARB_robustness */ @@ -3477,27 +3623,27 @@ GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei #define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E #define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F #define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340 -#define GL_SAMPLE_LOCATION_ARB 0x8E50 +#define GL_SAMPLE_LOCATION_ARB 0x8E50 #define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341 #define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342 #define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343 -typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC) (void); +typedef void(APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLenum target, GLuint start, GLsizei count, const GLfloat* v); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v); +typedef void(APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFramebufferSampleLocationsfvARB (GLenum target, GLuint start, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvARB (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glEvaluateDepthValuesARB (void); +GLAPI void APIENTRY glFramebufferSampleLocationsfvARB(GLenum target, GLuint start, GLsizei count, const GLfloat* v); +GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v); +GLAPI void APIENTRY glEvaluateDepthValuesARB(void); #endif #endif /* GL_ARB_sample_locations */ #ifndef GL_ARB_sample_shading #define GL_ARB_sample_shading 1 -#define GL_SAMPLE_SHADING_ARB 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); +#define GL_SAMPLE_SHADING_ARB 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 +typedef void(APIENTRYP PFNGLMINSAMPLESHADINGARBPROC)(GLfloat value); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); +GLAPI void APIENTRY glMinSampleShadingARB(GLfloat value); #endif #endif /* GL_ARB_sample_shading */ @@ -3583,22 +3729,22 @@ GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); #ifndef GL_ARB_shading_language_include #define GL_ARB_shading_language_include 1 -#define GL_SHADER_INCLUDE_ARB 0x8DAE -#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 -#define GL_NAMED_STRING_TYPE_ARB 0x8DEA -typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); -typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#define GL_SHADER_INCLUDE_ARB 0x8DAE +#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 +#define GL_NAMED_STRING_TYPE_ARB 0x8DEA +typedef void(APIENTRYP PFNGLNAMEDSTRINGARBPROC)(GLenum type, GLint namelen, const GLchar* name, GLint stringlen, const GLchar* string); +typedef void(APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC)(GLint namelen, const GLchar* name); +typedef void(APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC)(GLuint shader, GLsizei count, const GLchar* const* path, const GLint* length); +typedef GLboolean(APIENTRYP PFNGLISNAMEDSTRINGARBPROC)(GLint namelen, const GLchar* name); +typedef void(APIENTRYP PFNGLGETNAMEDSTRINGARBPROC)(GLint namelen, const GLchar* name, GLsizei bufSize, GLint* stringlen, GLchar* string); +typedef void(APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC)(GLint namelen, const GLchar* name, GLenum pname, GLint* params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); -GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedStringARB(GLenum type, GLint namelen, const GLchar* name, GLint stringlen, const GLchar* string); +GLAPI void APIENTRY glDeleteNamedStringARB(GLint namelen, const GLchar* name); +GLAPI void APIENTRY glCompileShaderIncludeARB(GLuint shader, GLsizei count, const GLchar* const* path, const GLint* length); +GLAPI GLboolean APIENTRY glIsNamedStringARB(GLint namelen, const GLchar* name); +GLAPI void APIENTRY glGetNamedStringARB(GLint namelen, const GLchar* name, GLsizei bufSize, GLint* stringlen, GLchar* string); +GLAPI void APIENTRY glGetNamedStringivARB(GLint namelen, const GLchar* name, GLenum pname, GLint* params); #endif #endif /* GL_ARB_shading_language_include */ @@ -3608,34 +3754,36 @@ GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GL #ifndef GL_ARB_sparse_buffer #define GL_ARB_sparse_buffer 1 -#define GL_SPARSE_STORAGE_BIT_ARB 0x0400 -#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 -typedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTARBPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); -typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); -typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +#define GL_SPARSE_STORAGE_BIT_ARB 0x0400 +#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 +typedef void(APIENTRYP PFNGLBUFFERPAGECOMMITMENTARBPROC)(GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); +typedef void(APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +typedef void(APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferPageCommitmentARB (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); -GLAPI void APIENTRY glNamedBufferPageCommitmentEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); -GLAPI void APIENTRY glNamedBufferPageCommitmentARB (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +GLAPI void APIENTRY glBufferPageCommitmentARB(GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); +GLAPI void APIENTRY glNamedBufferPageCommitmentEXT(GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +GLAPI void APIENTRY glNamedBufferPageCommitmentARB(GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); #endif #endif /* GL_ARB_sparse_buffer */ #ifndef GL_ARB_sparse_texture #define GL_ARB_sparse_texture 1 -#define GL_TEXTURE_SPARSE_ARB 0x91A6 -#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 -#define GL_NUM_SPARSE_LEVELS_ARB 0x91AA -#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 -#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 -#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 -#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 -#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 +#define GL_TEXTURE_SPARSE_ARB 0x91A6 +#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 +#define GL_NUM_SPARSE_LEVELS_ARB 0x91AA +#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 +#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 #define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 #define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A #define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 -typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +typedef void(APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +GLAPI void APIENTRY glTexPageCommitmentARB(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLboolean commit); #endif #endif /* GL_ARB_sparse_texture */ @@ -3669,19 +3817,19 @@ GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xo #ifndef GL_ARB_texture_border_clamp #define GL_ARB_texture_border_clamp 1 -#define GL_CLAMP_TO_BORDER_ARB 0x812D +#define GL_CLAMP_TO_BORDER_ARB 0x812D #endif /* GL_ARB_texture_border_clamp */ #ifndef GL_ARB_texture_buffer_object #define GL_ARB_texture_buffer_object 1 -#define GL_TEXTURE_BUFFER_ARB 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C +#define GL_TEXTURE_BUFFER_ARB 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E -typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E +typedef void(APIENTRYP PFNGLTEXBUFFERARBPROC)(GLenum target, GLenum internalformat, GLuint buffer); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTexBufferARB(GLenum target, GLenum internalformat, GLuint buffer); #endif #endif /* GL_ARB_texture_buffer_object */ @@ -3707,10 +3855,10 @@ GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint #ifndef GL_ARB_texture_cube_map_array #define GL_ARB_texture_cube_map_array 1 -#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 +#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F @@ -3722,8 +3870,8 @@ GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint #ifndef GL_ARB_texture_filter_minmax #define GL_ARB_texture_filter_minmax 1 -#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 -#define GL_WEIGHTED_AVERAGE_ARB 0x9367 +#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 +#define GL_WEIGHTED_AVERAGE_ARB 0x9367 #endif /* GL_ARB_texture_filter_minmax */ #ifndef GL_ARB_texture_gather @@ -3739,7 +3887,7 @@ GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint #ifndef GL_ARB_texture_mirrored_repeat #define GL_ARB_texture_mirrored_repeat 1 -#define GL_MIRRORED_REPEAT_ARB 0x8370 +#define GL_MIRRORED_REPEAT_ARB 0x8370 #endif /* GL_ARB_texture_mirrored_repeat */ #ifndef GL_ARB_texture_multisample @@ -3838,40 +3986,40 @@ GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint #ifndef GL_ARB_viewport_array #define GL_ARB_viewport_array 1 -typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYDVNVPROC) (GLuint first, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDDNVPROC) (GLuint index, GLdouble n, GLdouble f); +typedef void(APIENTRYP PFNGLDEPTHRANGEARRAYDVNVPROC)(GLuint first, GLsizei count, const GLdouble* v); +typedef void(APIENTRYP PFNGLDEPTHRANGEINDEXEDDNVPROC)(GLuint index, GLdouble n, GLdouble f); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthRangeArraydvNV (GLuint first, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glDepthRangeIndexeddNV (GLuint index, GLdouble n, GLdouble f); +GLAPI void APIENTRY glDepthRangeArraydvNV(GLuint first, GLsizei count, const GLdouble* v); +GLAPI void APIENTRY glDepthRangeIndexeddNV(GLuint index, GLdouble n, GLdouble f); #endif #endif /* GL_ARB_viewport_array */ #ifndef GL_KHR_blend_equation_advanced #define GL_KHR_blend_equation_advanced 1 -#define GL_MULTIPLY_KHR 0x9294 -#define GL_SCREEN_KHR 0x9295 -#define GL_OVERLAY_KHR 0x9296 -#define GL_DARKEN_KHR 0x9297 -#define GL_LIGHTEN_KHR 0x9298 -#define GL_COLORDODGE_KHR 0x9299 -#define GL_COLORBURN_KHR 0x929A -#define GL_HARDLIGHT_KHR 0x929B -#define GL_SOFTLIGHT_KHR 0x929C -#define GL_DIFFERENCE_KHR 0x929E -#define GL_EXCLUSION_KHR 0x92A0 -#define GL_HSL_HUE_KHR 0x92AD -#define GL_HSL_SATURATION_KHR 0x92AE -#define GL_HSL_COLOR_KHR 0x92AF -#define GL_HSL_LUMINOSITY_KHR 0x92B0 -typedef void (APIENTRYP PFNGLBLENDBARRIERKHRPROC) (void); +#define GL_MULTIPLY_KHR 0x9294 +#define GL_SCREEN_KHR 0x9295 +#define GL_OVERLAY_KHR 0x9296 +#define GL_DARKEN_KHR 0x9297 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLORBURN_KHR 0x929A +#define GL_HARDLIGHT_KHR 0x929B +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_DIFFERENCE_KHR 0x929E +#define GL_EXCLUSION_KHR 0x92A0 +#define GL_HSL_HUE_KHR 0x92AD +#define GL_HSL_SATURATION_KHR 0x92AE +#define GL_HSL_COLOR_KHR 0x92AF +#define GL_HSL_LUMINOSITY_KHR 0x92B0 +typedef void(APIENTRYP PFNGLBLENDBARRIERKHRPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendBarrierKHR (void); +GLAPI void APIENTRY glBlendBarrierKHR(void); #endif #endif /* GL_KHR_blend_equation_advanced */ #ifndef GL_KHR_blend_equation_advanced_coherent #define GL_KHR_blend_equation_advanced_coherent 1 -#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 #endif /* GL_KHR_blend_equation_advanced_coherent */ #ifndef GL_KHR_context_flush_control @@ -3884,16 +4032,16 @@ GLAPI void APIENTRY glBlendBarrierKHR (void); #ifndef GL_KHR_no_error #define GL_KHR_no_error 1 -#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 +#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 #endif /* GL_KHR_no_error */ #ifndef GL_KHR_parallel_shader_compile #define GL_KHR_parallel_shader_compile 1 #define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0 -#define GL_COMPLETION_STATUS_KHR 0x91B1 -typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) (GLuint count); +#define GL_COMPLETION_STATUS_KHR 0x91B1 +typedef void(APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSKHRPROC)(GLuint count); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMaxShaderCompilerThreadsKHR (GLuint count); +GLAPI void APIENTRY glMaxShaderCompilerThreadsKHR(GLuint count); #endif #endif /* GL_KHR_parallel_shader_compile */ @@ -3903,38 +4051,38 @@ GLAPI void APIENTRY glMaxShaderCompilerThreadsKHR (GLuint count); #ifndef GL_KHR_robustness #define GL_KHR_robustness 1 -#define GL_CONTEXT_ROBUST_ACCESS 0x90F3 +#define GL_CONTEXT_ROBUST_ACCESS 0x90F3 #endif /* GL_KHR_robustness */ #ifndef GL_KHR_shader_subgroup #define GL_KHR_shader_subgroup 1 -#define GL_SUBGROUP_SIZE_KHR 0x9532 -#define GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533 +#define GL_SUBGROUP_SIZE_KHR 0x9532 +#define GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533 #define GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534 -#define GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535 +#define GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535 #define GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001 -#define GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002 +#define GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002 #define GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004 #define GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008 #define GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010 #define GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020 #define GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040 -#define GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080 +#define GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080 #endif /* GL_KHR_shader_subgroup */ #ifndef GL_KHR_texture_compression_astc_hdr #define GL_KHR_texture_compression_astc_hdr 1 -#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 -#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 -#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 -#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 -#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 -#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 -#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 -#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 -#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 -#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 -#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA #define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB #define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC #define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD @@ -3970,65 +4118,71 @@ GLAPI void APIENTRY glMaxShaderCompilerThreadsKHR (GLuint count); #define GL_MAX_DEPTH_STENCIL_FRAMEBUFFER_SAMPLES_AMD 0x91B5 #define GL_NUM_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B6 #define GL_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B7 -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC)(GLenum target, GLsizei samples, GLsizei storageSamples, + GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC)( + GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleAdvancedAMD (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleAdvancedAMD (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glRenderbufferStorageMultisampleAdvancedAMD(GLenum target, GLsizei samples, GLsizei storageSamples, + GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleAdvancedAMD(GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, + GLenum internalformat, GLsizei width, GLsizei height); #endif #endif /* GL_AMD_framebuffer_multisample_advanced */ #ifndef GL_AMD_performance_monitor #define GL_AMD_performance_monitor 1 -#define GL_COUNTER_TYPE_AMD 0x8BC0 -#define GL_COUNTER_RANGE_AMD 0x8BC1 -#define GL_UNSIGNED_INT64_AMD 0x8BC2 -#define GL_PERCENTAGE_AMD 0x8BC3 -#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 -#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 -#define GL_PERFMON_RESULT_AMD 0x8BC6 -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); -typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#define GL_COUNTER_TYPE_AMD 0x8BC0 +#define GL_COUNTER_RANGE_AMD 0x8BC1 +#define GL_UNSIGNED_INT64_AMD 0x8BC2 +#define GL_PERCENTAGE_AMD 0x8BC3 +#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 +#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 +#define GL_PERFMON_RESULT_AMD 0x8BC6 +typedef void(APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC)(GLint* numGroups, GLsizei groupsSize, GLuint* groups); +typedef void(APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC)(GLuint group, GLint* numCounters, GLint* maxActiveCounters, GLsizei counterSize, + GLuint* counters); +typedef void(APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC)(GLuint group, GLsizei bufSize, GLsizei* length, GLchar* groupString); +typedef void(APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei* length, + GLchar* counterString); +typedef void(APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC)(GLuint group, GLuint counter, GLenum pname, void* data); +typedef void(APIENTRYP PFNGLGENPERFMONITORSAMDPROC)(GLsizei n, GLuint* monitors); +typedef void(APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC)(GLsizei n, GLuint* monitors); +typedef void(APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC)(GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint* counterList); +typedef void(APIENTRYP PFNGLBEGINPERFMONITORAMDPROC)(GLuint monitor); +typedef void(APIENTRYP PFNGLENDPERFMONITORAMDPROC)(GLuint monitor); +typedef void(APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint* data, GLint* bytesWritten); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); -GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +GLAPI void APIENTRY glGetPerfMonitorGroupsAMD(GLint* numGroups, GLsizei groupsSize, GLuint* groups); +GLAPI void APIENTRY glGetPerfMonitorCountersAMD(GLuint group, GLint* numCounters, GLint* maxActiveCounters, GLsizei counterSize, GLuint* counters); +GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize, GLsizei* length, GLchar* groupString); +GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD(GLuint group, GLuint counter, GLsizei bufSize, GLsizei* length, GLchar* counterString); +GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname, void* data); +GLAPI void APIENTRY glGenPerfMonitorsAMD(GLsizei n, GLuint* monitors); +GLAPI void APIENTRY glDeletePerfMonitorsAMD(GLsizei n, GLuint* monitors); +GLAPI void APIENTRY glSelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint* counterList); +GLAPI void APIENTRY glBeginPerfMonitorAMD(GLuint monitor); +GLAPI void APIENTRY glEndPerfMonitorAMD(GLuint monitor); +GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint* data, GLint* bytesWritten); #endif #endif /* GL_AMD_performance_monitor */ #ifndef GL_APPLE_rgb_422 #define GL_APPLE_rgb_422 1 -#define GL_RGB_422_APPLE 0x8A1F -#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA -#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB -#define GL_RGB_RAW_422_APPLE 0x8A51 +#define GL_RGB_422_APPLE 0x8A1F +#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#define GL_RGB_RAW_422_APPLE 0x8A51 #endif /* GL_APPLE_rgb_422 */ #ifndef GL_EXT_EGL_image_storage #define GL_EXT_EGL_image_storage 1 -typedef void *GLeglImageOES; -typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) (GLenum target, GLeglImageOES image, const GLint* attrib_list); -typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) (GLuint texture, GLeglImageOES image, const GLint* attrib_list); +typedef void* GLeglImageOES; +typedef void(APIENTRYP PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC)(GLenum target, GLeglImageOES image, const GLint* attrib_list); +typedef void(APIENTRYP PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC)(GLuint texture, GLeglImageOES image, const GLint* attrib_list); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glEGLImageTargetTexStorageEXT (GLenum target, GLeglImageOES image, const GLint* attrib_list); -GLAPI void APIENTRY glEGLImageTargetTextureStorageEXT (GLuint texture, GLeglImageOES image, const GLint* attrib_list); +GLAPI void APIENTRY glEGLImageTargetTexStorageEXT(GLenum target, GLeglImageOES image, const GLint* attrib_list); +GLAPI void APIENTRY glEGLImageTargetTextureStorageEXT(GLuint texture, GLeglImageOES image, const GLint* attrib_list); #endif #endif /* GL_EXT_EGL_image_storage */ @@ -4038,558 +4192,686 @@ GLAPI void APIENTRY glEGLImageTargetTextureStorageEXT (GLuint texture, GLeglImag #ifndef GL_EXT_debug_label #define GL_EXT_debug_label 1 -#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F -#define GL_PROGRAM_OBJECT_EXT 0x8B40 -#define GL_SHADER_OBJECT_EXT 0x8B48 -#define GL_BUFFER_OBJECT_EXT 0x9151 -#define GL_QUERY_OBJECT_EXT 0x9153 -#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 -typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); -typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define GL_PROGRAM_OBJECT_EXT 0x8B40 +#define GL_SHADER_OBJECT_EXT 0x8B48 +#define GL_BUFFER_OBJECT_EXT 0x9151 +#define GL_QUERY_OBJECT_EXT 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +typedef void(APIENTRYP PFNGLLABELOBJECTEXTPROC)(GLenum type, GLuint object, GLsizei length, const GLchar* label); +typedef void(APIENTRYP PFNGLGETOBJECTLABELEXTPROC)(GLenum type, GLuint object, GLsizei bufSize, GLsizei* length, GLchar* label); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); -GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI void APIENTRY glLabelObjectEXT(GLenum type, GLuint object, GLsizei length, const GLchar* label); +GLAPI void APIENTRY glGetObjectLabelEXT(GLenum type, GLuint object, GLsizei bufSize, GLsizei* length, GLchar* label); #endif #endif /* GL_EXT_debug_label */ #ifndef GL_EXT_debug_marker #define GL_EXT_debug_marker 1 -typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); -typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); -typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); +typedef void(APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC)(GLsizei length, const GLchar* marker); +typedef void(APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC)(GLsizei length, const GLchar* marker); +typedef void(APIENTRYP PFNGLPOPGROUPMARKEREXTPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); -GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); -GLAPI void APIENTRY glPopGroupMarkerEXT (void); +GLAPI void APIENTRY glInsertEventMarkerEXT(GLsizei length, const GLchar* marker); +GLAPI void APIENTRY glPushGroupMarkerEXT(GLsizei length, const GLchar* marker); +GLAPI void APIENTRY glPopGroupMarkerEXT(void); #endif #endif /* GL_EXT_debug_marker */ #ifndef GL_EXT_direct_state_access #define GL_EXT_direct_state_access 1 -#define GL_PROGRAM_MATRIX_EXT 0x8E2D -#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E +#define GL_PROGRAM_MATRIX_EXT 0x8E2D +#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E #define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F -typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); -typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data); -typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); -typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); -typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); -typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); -typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); -typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param); -typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor); +typedef void(APIENTRYP PFNGLMATRIXLOADFEXTPROC)(GLenum mode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXLOADDEXTPROC)(GLenum mode, const GLdouble* m); +typedef void(APIENTRYP PFNGLMATRIXMULTFEXTPROC)(GLenum mode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXMULTDEXTPROC)(GLenum mode, const GLdouble* m); +typedef void(APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC)(GLenum mode); +typedef void(APIENTRYP PFNGLMATRIXROTATEFEXTPROC)(GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNGLMATRIXROTATEDEXTPROC)(GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNGLMATRIXSCALEFEXTPROC)(GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNGLMATRIXSCALEDEXTPROC)(GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC)(GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC)(GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC)(GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, + GLdouble zFar); +typedef void(APIENTRYP PFNGLMATRIXORTHOEXTPROC)(GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, + GLdouble zFar); +typedef void(APIENTRYP PFNGLMATRIXPOPEXTPROC)(GLenum mode); +typedef void(APIENTRYP PFNGLMATRIXPUSHEXTPROC)(GLenum mode); +typedef void(APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC)(GLbitfield mask); +typedef void(APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC)(GLbitfield mask); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC)(GLuint texture, GLenum target, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC)(GLuint texture, GLenum target, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC)(GLuint texture, GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC)(GLuint texture, GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, + GLint border, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, + GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLint border); +typedef void(APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border); +typedef void(APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, + GLsizei width); +typedef void(APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, + GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC)(GLuint texture, GLenum target, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC)(GLuint texture, GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC)(GLenum texunit, GLenum target, GLuint texture); +typedef void(APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC)(GLenum texunit, GLint size, GLenum type, GLsizei stride, const void* pointer); +typedef void(APIENTRYP PFNGLMULTITEXENVFEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLMULTITEXENVFVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNGLMULTITEXENVIEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLMULTITEXENVIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLMULTITEXGENDEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +typedef void(APIENTRYP PFNGLMULTITEXGENDVEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, const GLdouble* params); +typedef void(APIENTRYP PFNGLMULTITEXGENFEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLMULTITEXGENFVEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNGLMULTITEXGENIEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLMULTITEXGENIVEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, GLdouble* params); +typedef void(APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC)(GLenum texunit, GLenum coord, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, + GLint border, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, + GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLint border); +typedef void(APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border); +typedef void(APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, + GLsizei width); +typedef void(APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +typedef void(APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLenum type, const void* pixels); +typedef void(APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC)(GLenum array, GLuint index); +typedef void(APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC)(GLenum array, GLuint index); +typedef void(APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC)(GLenum target, GLuint index, GLfloat* data); +typedef void(APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC)(GLenum target, GLuint index, GLdouble* data); +typedef void(APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC)(GLenum target, GLuint index, void** data); +typedef void(APIENTRYP PFNGLENABLEINDEXEDEXTPROC)(GLenum target, GLuint index); +typedef void(APIENTRYP PFNGLDISABLEINDEXEDEXTPROC)(GLenum target, GLuint index); +typedef GLboolean(APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC)(GLenum target, GLuint index); +typedef void(APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC)(GLenum target, GLuint index, GLint* data); +typedef void(APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC)(GLenum target, GLuint index, GLboolean* data); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC)(GLuint texture, GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLint border, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, + GLenum format, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC)(GLuint texture, GLenum target, GLint lod, void* img); +typedef void(APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLint border, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, + const void* bits); +typedef void(APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC)(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, + GLenum format, GLsizei imageSize, const void* bits); +typedef void(APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC)(GLenum texunit, GLenum target, GLint lod, void* img); +typedef void(APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC)(GLenum mode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC)(GLenum mode, const GLdouble* m); +typedef void(APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC)(GLenum mode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC)(GLenum mode, const GLdouble* m); +typedef void(APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC)(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage); +typedef void(APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); +typedef void*(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC)(GLuint buffer, GLenum access); +typedef GLboolean(APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC)(GLuint buffer); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC)(GLuint buffer, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC)(GLuint buffer, GLenum pname, void** params); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, void* data); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC)(GLuint program, GLint location, GLfloat v0); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC)(GLuint program, GLint location, GLint v0); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); +typedef void(APIENTRYP PFNGLTEXTUREBUFFEREXTPROC)(GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +typedef void(APIENTRYP PFNGLMULTITEXBUFFEREXTPROC)(GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC)(GLuint texture, GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC)(GLuint texture, GLenum target, GLenum pname, const GLuint* params); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC)(GLuint texture, GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC)(GLuint texture, GLenum target, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, const GLuint* params); +typedef void(APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC)(GLenum texunit, GLenum target, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC)(GLuint program, GLint location, GLuint v0); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC)(GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat* params); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC)(GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC)(GLuint program, GLenum target, GLuint index, const GLint* params); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC)(GLuint program, GLenum target, GLuint index, GLsizei count, const GLint* params); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC)(GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, + GLuint z, GLuint w); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC)(GLuint program, GLenum target, GLuint index, const GLuint* params); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC)(GLuint program, GLenum target, GLuint index, GLsizei count, + const GLuint* params); +typedef void(APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC)(GLuint program, GLenum target, GLuint index, GLint* params); +typedef void(APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC)(GLuint program, GLenum target, GLuint index, GLuint* params); +typedef void(APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC)(GLenum array, GLuint index); +typedef void(APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC)(GLenum array, GLuint index); +typedef void(APIENTRYP PFNGLGETFLOATI_VEXTPROC)(GLenum pname, GLuint index, GLfloat* params); +typedef void(APIENTRYP PFNGLGETDOUBLEI_VEXTPROC)(GLenum pname, GLuint index, GLdouble* params); +typedef void(APIENTRYP PFNGLGETPOINTERI_VEXTPROC)(GLenum pname, GLuint index, void** params); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC)(GLuint program, GLenum target, GLenum format, GLsizei len, const void* string); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC)(GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, + GLdouble z, GLdouble w); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC)(GLuint program, GLenum target, GLuint index, const GLdouble* params); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC)(GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, + GLfloat z, GLfloat w); +typedef void(APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC)(GLuint program, GLenum target, GLuint index, const GLfloat* params); +typedef void(APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC)(GLuint program, GLenum target, GLuint index, GLdouble* params); +typedef void(APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC)(GLuint program, GLenum target, GLuint index, GLfloat* params); +typedef void(APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC)(GLuint program, GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC)(GLuint program, GLenum target, GLenum pname, void* string); +typedef void(APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC)(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC)(GLuint renderbuffer, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLuint renderbuffer, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC)( + GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +typedef GLenum(APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC)(GLuint framebuffer, GLenum target); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC)(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC)(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC)(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, + GLint level, GLint zoffset); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC)(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, + GLuint renderbuffer); +typedef void(APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC)(GLuint texture, GLenum target); +typedef void(APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC)(GLenum texunit, GLenum target); +typedef void(APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC)(GLuint framebuffer, GLenum mode); +typedef void(APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC)(GLuint framebuffer, GLsizei n, const GLenum* bufs); +typedef void(APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC)(GLuint framebuffer, GLenum mode); +typedef void(APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC)(GLuint framebuffer, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC)(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +typedef void(APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC)(GLuint texture, GLenum target, GLuint renderbuffer); +typedef void(APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC)(GLenum texunit, GLenum target, GLuint renderbuffer); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, + GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, + GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, + GLboolean normalized, GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, + GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC)(GLuint vaobj, GLenum array); +typedef void(APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC)(GLuint vaobj, GLenum array); +typedef void(APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC)(GLuint vaobj, GLuint index); +typedef void(APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC)(GLuint vaobj, GLuint index); +typedef void(APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC)(GLuint vaobj, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC)(GLuint vaobj, GLenum pname, void** param); +typedef void(APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC)(GLuint vaobj, GLuint index, GLenum pname, void** param); +typedef void*(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void(APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void(APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC)(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags); +typedef void(APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC)(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC)(GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, + GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC)(GLuint framebuffer, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC)(GLuint framebuffer, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC)(GLuint program, GLint location, GLdouble x); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC)(GLuint program, GLint location, GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC)(GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC)(GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, + const GLdouble* value); +typedef void(APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC)(GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, + GLsizeiptr size); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, + GLsizei height); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC)(GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC)(GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC)(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, + GLboolean normalized, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC)(GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC)(GLuint vaobj, GLuint bindingindex, GLuint divisor); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC)(GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, + GLsizei stride, GLintptr offset); +typedef void(APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +typedef void(APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC)(GLuint vaobj, GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); -GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); -GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); -GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); -GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); -GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data); -GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); -GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); -GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img); -GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); -GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img); -GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); -GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); -GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); -GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params); -GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); -GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); -GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params); -GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); -GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string); -GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); -GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); -GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); -GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array); -GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array); -GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index); -GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index); -GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param); -GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param); -GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); -GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); -GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); -GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); -GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); -GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); -GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor); +GLAPI void APIENTRY glMatrixLoadfEXT(GLenum mode, const GLfloat* m); +GLAPI void APIENTRY glMatrixLoaddEXT(GLenum mode, const GLdouble* m); +GLAPI void APIENTRY glMatrixMultfEXT(GLenum mode, const GLfloat* m); +GLAPI void APIENTRY glMatrixMultdEXT(GLenum mode, const GLdouble* m); +GLAPI void APIENTRY glMatrixLoadIdentityEXT(GLenum mode); +GLAPI void APIENTRY glMatrixRotatefEXT(GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixRotatedEXT(GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixScalefEXT(GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixScaledEXT(GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixTranslatefEXT(GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixTranslatedEXT(GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixFrustumEXT(GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixOrthoEXT(GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixPopEXT(GLenum mode); +GLAPI void APIENTRY glMatrixPushEXT(GLenum mode); +GLAPI void APIENTRY glClientAttribDefaultEXT(GLbitfield mask); +GLAPI void APIENTRY glPushClientAttribDefaultEXT(GLbitfield mask); +GLAPI void APIENTRY glTextureParameterfEXT(GLuint texture, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTextureParameterfvEXT(GLuint texture, GLenum target, GLenum pname, const GLfloat* params); +GLAPI void APIENTRY glTextureParameteriEXT(GLuint texture, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glTextureParameterivEXT(GLuint texture, GLenum target, GLenum pname, const GLint* params); +GLAPI void APIENTRY glTextureImage1DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, + GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glTextureSubImage1DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, + GLenum type, const void* pixels); +GLAPI void APIENTRY glTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glCopyTextureImage1DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTextureSubImage1DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, + GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetTextureImageEXT(GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +GLAPI void APIENTRY glGetTextureParameterfvEXT(GLuint texture, GLenum target, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetTextureParameterivEXT(GLuint texture, GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetTextureLevelParameterfvEXT(GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetTextureLevelParameterivEXT(GLuint texture, GLenum target, GLint level, GLenum pname, GLint* params); +GLAPI void APIENTRY glTextureImage3DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glTextureSubImage3DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glCopyTextureSubImage3DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glBindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture); +GLAPI void APIENTRY glMultiTexCoordPointerEXT(GLenum texunit, GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI void APIENTRY glMultiTexEnvfEXT(GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexEnvfvEXT(GLenum texunit, GLenum target, GLenum pname, const GLfloat* params); +GLAPI void APIENTRY glMultiTexEnviEXT(GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexEnvivEXT(GLenum texunit, GLenum target, GLenum pname, const GLint* params); +GLAPI void APIENTRY glMultiTexGendEXT(GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +GLAPI void APIENTRY glMultiTexGendvEXT(GLenum texunit, GLenum coord, GLenum pname, const GLdouble* params); +GLAPI void APIENTRY glMultiTexGenfEXT(GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexGenfvEXT(GLenum texunit, GLenum coord, GLenum pname, const GLfloat* params); +GLAPI void APIENTRY glMultiTexGeniEXT(GLenum texunit, GLenum coord, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexGenivEXT(GLenum texunit, GLenum coord, GLenum pname, const GLint* params); +GLAPI void APIENTRY glGetMultiTexEnvfvEXT(GLenum texunit, GLenum target, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetMultiTexEnvivEXT(GLenum texunit, GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetMultiTexGendvEXT(GLenum texunit, GLenum coord, GLenum pname, GLdouble* params); +GLAPI void APIENTRY glGetMultiTexGenfvEXT(GLenum texunit, GLenum coord, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetMultiTexGenivEXT(GLenum texunit, GLenum coord, GLenum pname, GLint* params); +GLAPI void APIENTRY glMultiTexParameteriEXT(GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexParameterivEXT(GLenum texunit, GLenum target, GLenum pname, const GLint* params); +GLAPI void APIENTRY glMultiTexParameterfEXT(GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexParameterfvEXT(GLenum texunit, GLenum target, GLenum pname, const GLfloat* params); +GLAPI void APIENTRY glMultiTexImage1DEXT(GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, + GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glMultiTexImage2DEXT(GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glMultiTexSubImage1DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, + GLenum type, const void* pixels); +GLAPI void APIENTRY glMultiTexSubImage2DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glCopyMultiTexImage1DEXT(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLint border); +GLAPI void APIENTRY glCopyMultiTexImage2DEXT(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, + GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetMultiTexImageEXT(GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +GLAPI void APIENTRY glGetMultiTexParameterfvEXT(GLenum texunit, GLenum target, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetMultiTexParameterivEXT(GLenum texunit, GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT(GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat* params); +GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT(GLenum texunit, GLenum target, GLint level, GLenum pname, GLint* params); +GLAPI void APIENTRY glMultiTexImage3DEXT(GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glMultiTexSubImage3DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glEnableClientStateIndexedEXT(GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateIndexedEXT(GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloatIndexedvEXT(GLenum target, GLuint index, GLfloat* data); +GLAPI void APIENTRY glGetDoubleIndexedvEXT(GLenum target, GLuint index, GLdouble* data); +GLAPI void APIENTRY glGetPointerIndexedvEXT(GLenum target, GLuint index, void** data); +GLAPI void APIENTRY glEnableIndexedEXT(GLenum target, GLuint index); +GLAPI void APIENTRY glDisableIndexedEXT(GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT(GLenum target, GLuint index); +GLAPI void APIENTRY glGetIntegerIndexedvEXT(GLenum target, GLuint index, GLint* data); +GLAPI void APIENTRY glGetBooleanIndexedvEXT(GLenum target, GLuint index, GLboolean* data); +GLAPI void APIENTRY glCompressedTextureImage3DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedTextureImage1DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLint border, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedTextureSubImage3DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedTextureSubImage1DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, + GLenum format, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glGetCompressedTextureImageEXT(GLuint texture, GLenum target, GLint lod, void* img); +GLAPI void APIENTRY glCompressedMultiTexImage3DEXT(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedMultiTexImage2DEXT(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedMultiTexImage1DEXT(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLint border, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT(GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, + GLenum format, GLsizei imageSize, const void* bits); +GLAPI void APIENTRY glGetCompressedMultiTexImageEXT(GLenum texunit, GLenum target, GLint lod, void* img); +GLAPI void APIENTRY glMatrixLoadTransposefEXT(GLenum mode, const GLfloat* m); +GLAPI void APIENTRY glMatrixLoadTransposedEXT(GLenum mode, const GLdouble* m); +GLAPI void APIENTRY glMatrixMultTransposefEXT(GLenum mode, const GLfloat* m); +GLAPI void APIENTRY glMatrixMultTransposedEXT(GLenum mode, const GLdouble* m); +GLAPI void APIENTRY glNamedBufferDataEXT(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubDataEXT(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); +GLAPI void* APIENTRY glMapNamedBufferEXT(GLuint buffer, GLenum access); +GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT(GLuint buffer); +GLAPI void APIENTRY glGetNamedBufferParameterivEXT(GLuint buffer, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetNamedBufferPointervEXT(GLuint buffer, GLenum pname, void** params); +GLAPI void APIENTRY glGetNamedBufferSubDataEXT(GLuint buffer, GLintptr offset, GLsizeiptr size, void* data); +GLAPI void APIENTRY glProgramUniform1fEXT(GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform2fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform3fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform4fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform1iEXT(GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform2iEXT(GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform3iEXT(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform4iEXT(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform1fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform2fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform3fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform4fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat* value); +GLAPI void APIENTRY glProgramUniform1ivEXT(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniform2ivEXT(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniform3ivEXT(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniform4ivEXT(GLuint program, GLint location, GLsizei count, const GLint* value); +GLAPI void APIENTRY glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI void APIENTRY glTextureBufferEXT(GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glMultiTexBufferEXT(GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTextureParameterIivEXT(GLuint texture, GLenum target, GLenum pname, const GLint* params); +GLAPI void APIENTRY glTextureParameterIuivEXT(GLuint texture, GLenum target, GLenum pname, const GLuint* params); +GLAPI void APIENTRY glGetTextureParameterIivEXT(GLuint texture, GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetTextureParameterIuivEXT(GLuint texture, GLenum target, GLenum pname, GLuint* params); +GLAPI void APIENTRY glMultiTexParameterIivEXT(GLenum texunit, GLenum target, GLenum pname, const GLint* params); +GLAPI void APIENTRY glMultiTexParameterIuivEXT(GLenum texunit, GLenum target, GLenum pname, const GLuint* params); +GLAPI void APIENTRY glGetMultiTexParameterIivEXT(GLenum texunit, GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetMultiTexParameterIuivEXT(GLenum texunit, GLenum target, GLenum pname, GLuint* params); +GLAPI void APIENTRY glProgramUniform1uiEXT(GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform2uiEXT(GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform3uiEXT(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform4uiEXT(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform1uivEXT(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glProgramUniform2uivEXT(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glProgramUniform3uivEXT(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glProgramUniform4uivEXT(GLuint program, GLint location, GLsizei count, const GLuint* value); +GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT(GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat* params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT(GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT(GLuint program, GLenum target, GLuint index, const GLint* params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT(GLuint program, GLenum target, GLuint index, GLsizei count, const GLint* params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT(GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT(GLuint program, GLenum target, GLuint index, const GLuint* params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT(GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint* params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT(GLuint program, GLenum target, GLuint index, GLint* params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT(GLuint program, GLenum target, GLuint index, GLuint* params); +GLAPI void APIENTRY glEnableClientStateiEXT(GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateiEXT(GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloati_vEXT(GLenum pname, GLuint index, GLfloat* params); +GLAPI void APIENTRY glGetDoublei_vEXT(GLenum pname, GLuint index, GLdouble* params); +GLAPI void APIENTRY glGetPointeri_vEXT(GLenum pname, GLuint index, void** params); +GLAPI void APIENTRY glNamedProgramStringEXT(GLuint program, GLenum target, GLenum format, GLsizei len, const void* string); +GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT(GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT(GLuint program, GLenum target, GLuint index, const GLdouble* params); +GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT(GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT(GLuint program, GLenum target, GLuint index, const GLfloat* params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT(GLuint program, GLenum target, GLuint index, GLdouble* params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT(GLuint program, GLenum target, GLuint index, GLfloat* params); +GLAPI void APIENTRY glGetNamedProgramivEXT(GLuint program, GLenum target, GLenum pname, GLint* params); +GLAPI void APIENTRY glGetNamedProgramStringEXT(GLuint program, GLenum target, GLenum pname, void* string); +GLAPI void APIENTRY glNamedRenderbufferStorageEXT(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT(GLuint renderbuffer, GLenum pname, GLint* params); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, + GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT(GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, + GLenum internalformat, GLsizei width, GLsizei height); +GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target); +GLAPI void APIENTRY glNamedFramebufferTexture1DEXT(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture2DEXT(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture3DEXT(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, + GLint zoffset); +GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params); +GLAPI void APIENTRY glGenerateTextureMipmapEXT(GLuint texture, GLenum target); +GLAPI void APIENTRY glGenerateMultiTexMipmapEXT(GLenum texunit, GLenum target); +GLAPI void APIENTRY glFramebufferDrawBufferEXT(GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glFramebufferDrawBuffersEXT(GLuint framebuffer, GLsizei n, const GLenum* bufs); +GLAPI void APIENTRY glFramebufferReadBufferEXT(GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glGetFramebufferParameterivEXT(GLuint framebuffer, GLenum pname, GLint* params); +GLAPI void APIENTRY glNamedCopyBufferSubDataEXT(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glNamedFramebufferTextureEXT(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +GLAPI void APIENTRY glTextureRenderbufferEXT(GLuint texture, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glMultiTexRenderbufferEXT(GLenum texunit, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glVertexArrayVertexOffsetEXT(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayColorOffsetEXT(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT(GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayIndexOffsetEXT(GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayNormalOffsetEXT(GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, + GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT(GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT(GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, + GLboolean normalized, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT(GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, + GLintptr offset); +GLAPI void APIENTRY glEnableVertexArrayEXT(GLuint vaobj, GLenum array); +GLAPI void APIENTRY glDisableVertexArrayEXT(GLuint vaobj, GLenum array); +GLAPI void APIENTRY glEnableVertexArrayAttribEXT(GLuint vaobj, GLuint index); +GLAPI void APIENTRY glDisableVertexArrayAttribEXT(GLuint vaobj, GLuint index); +GLAPI void APIENTRY glGetVertexArrayIntegervEXT(GLuint vaobj, GLenum pname, GLint* param); +GLAPI void APIENTRY glGetVertexArrayPointervEXT(GLuint vaobj, GLenum pname, void** param); +GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT(GLuint vaobj, GLuint index, GLenum pname, GLint* param); +GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT(GLuint vaobj, GLuint index, GLenum pname, void** param); +GLAPI void* APIENTRY glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glNamedBufferStorageEXT(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags); +GLAPI void APIENTRY glClearNamedBufferDataEXT(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data); +GLAPI void APIENTRY glClearNamedBufferSubDataEXT(GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, + GLenum type, const void* data); +GLAPI void APIENTRY glNamedFramebufferParameteriEXT(GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT(GLuint framebuffer, GLenum pname, GLint* params); +GLAPI void APIENTRY glProgramUniform1dEXT(GLuint program, GLint location, GLdouble x); +GLAPI void APIENTRY glProgramUniform2dEXT(GLuint program, GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glProgramUniform3dEXT(GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glProgramUniform4dEXT(GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramUniform1dvEXT(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniform2dvEXT(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniform3dvEXT(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniform4dvEXT(GLuint program, GLint location, GLsizei count, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix2dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix3dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix4dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble* value); +GLAPI void APIENTRY glTextureBufferRangeEXT(GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage2DMultisampleEXT(GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, + GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisampleEXT(GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, + GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT(GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT(GLuint vaobj, GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT(GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, + GLintptr offset); +GLAPI void APIENTRY glTexturePageCommitmentEXT(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLboolean commit); +GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT(GLuint vaobj, GLuint index, GLuint divisor); #endif #endif /* GL_EXT_direct_state_access */ #ifndef GL_EXT_draw_instanced #define GL_EXT_draw_instanced 1 -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +typedef void(APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC)(GLenum mode, GLint start, GLsizei count, GLsizei primcount); +typedef void(APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +GLAPI void APIENTRY glDrawArraysInstancedEXT(GLenum mode, GLint start, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount); #endif #endif /* GL_EXT_draw_instanced */ @@ -4607,10 +4889,10 @@ GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLen #ifndef GL_EXT_polygon_offset_clamp #define GL_EXT_polygon_offset_clamp 1 -#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B -typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp); +#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B +typedef void(APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC)(GLfloat factor, GLfloat units, GLfloat clamp); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfloat clamp); +GLAPI void APIENTRY glPolygonOffsetClampEXT(GLfloat factor, GLfloat units, GLfloat clamp); #endif #endif /* GL_EXT_polygon_offset_clamp */ @@ -4620,28 +4902,28 @@ GLAPI void APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfl #ifndef GL_EXT_raster_multisample #define GL_EXT_raster_multisample 1 -#define GL_RASTER_MULTISAMPLE_EXT 0x9327 -#define GL_RASTER_SAMPLES_EXT 0x9328 -#define GL_MAX_RASTER_SAMPLES_EXT 0x9329 +#define GL_RASTER_MULTISAMPLE_EXT 0x9327 +#define GL_RASTER_SAMPLES_EXT 0x9328 +#define GL_MAX_RASTER_SAMPLES_EXT 0x9329 #define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A #define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B -#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C -typedef void (APIENTRYP PFNGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations); +#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C +typedef void(APIENTRYP PFNGLRASTERSAMPLESEXTPROC)(GLuint samples, GLboolean fixedsamplelocations); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRasterSamplesEXT (GLuint samples, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glRasterSamplesEXT(GLuint samples, GLboolean fixedsamplelocations); #endif #endif /* GL_EXT_raster_multisample */ #ifndef GL_EXT_separate_shader_objects #define GL_EXT_separate_shader_objects 1 -#define GL_ACTIVE_PROGRAM_EXT 0x8B8D -typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); -typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); +#define GL_ACTIVE_PROGRAM_EXT 0x8B8D +typedef void(APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC)(GLenum type, GLuint program); +typedef void(APIENTRYP PFNGLACTIVEPROGRAMEXTPROC)(GLuint program); +typedef GLuint(APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC)(GLenum type, const GLchar* string); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); -GLAPI void APIENTRY glActiveProgramEXT (GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); +GLAPI void APIENTRY glUseShaderProgramEXT(GLenum type, GLuint program); +GLAPI void APIENTRY glActiveProgramEXT(GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramEXT(GLenum type, const GLchar* string); #endif #endif /* GL_EXT_separate_shader_objects */ @@ -4652,9 +4934,9 @@ GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *strin #ifndef GL_EXT_shader_framebuffer_fetch_non_coherent #define GL_EXT_shader_framebuffer_fetch_non_coherent 1 -typedef void (APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) (void); +typedef void(APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFramebufferFetchBarrierEXT (void); +GLAPI void APIENTRY glFramebufferFetchBarrierEXT(void); #endif #endif /* GL_EXT_shader_framebuffer_fetch_non_coherent */ @@ -4664,28 +4946,28 @@ GLAPI void APIENTRY glFramebufferFetchBarrierEXT (void); #ifndef GL_EXT_texture_compression_s3tc #define GL_EXT_texture_compression_s3tc 1 -#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #endif /* GL_EXT_texture_compression_s3tc */ #ifndef GL_EXT_texture_filter_minmax #define GL_EXT_texture_filter_minmax 1 -#define GL_TEXTURE_REDUCTION_MODE_EXT 0x9366 -#define GL_WEIGHTED_AVERAGE_EXT 0x9367 +#define GL_TEXTURE_REDUCTION_MODE_EXT 0x9366 +#define GL_WEIGHTED_AVERAGE_EXT 0x9367 #endif /* GL_EXT_texture_filter_minmax */ #ifndef GL_EXT_texture_sRGB_R8 #define GL_EXT_texture_sRGB_R8 1 -#define GL_SR8_EXT 0x8FBD +#define GL_SR8_EXT 0x8FBD #endif /* GL_EXT_texture_sRGB_R8 */ #ifndef GL_EXT_texture_sRGB_decode #define GL_EXT_texture_sRGB_decode 1 -#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 -#define GL_DECODE_EXT 0x8A49 -#define GL_SKIP_DECODE_EXT 0x8A4A +#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define GL_DECODE_EXT 0x8A49 +#define GL_SKIP_DECODE_EXT 0x8A4A #endif /* GL_EXT_texture_sRGB_decode */ #ifndef GL_EXT_texture_shadow_lod @@ -4694,21 +4976,21 @@ GLAPI void APIENTRY glFramebufferFetchBarrierEXT (void); #ifndef GL_EXT_window_rectangles #define GL_EXT_window_rectangles 1 -#define GL_INCLUSIVE_EXT 0x8F10 -#define GL_EXCLUSIVE_EXT 0x8F11 -#define GL_WINDOW_RECTANGLE_EXT 0x8F12 -#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 -#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 -#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 -typedef void (APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box); +#define GL_INCLUSIVE_EXT 0x8F10 +#define GL_EXCLUSIVE_EXT 0x8F11 +#define GL_WINDOW_RECTANGLE_EXT 0x8F12 +#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 +#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 +#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 +typedef void(APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC)(GLenum mode, GLsizei count, const GLint* box); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLint *box); +GLAPI void APIENTRY glWindowRectanglesEXT(GLenum mode, GLsizei count, const GLint* box); #endif #endif /* GL_EXT_window_rectangles */ #ifndef GL_INTEL_blackhole_render #define GL_INTEL_blackhole_render 1 -#define GL_BLACKHOLE_RENDER_INTEL 0x83FC +#define GL_BLACKHOLE_RENDER_INTEL 0x83FC #endif /* GL_INTEL_blackhole_render */ #ifndef GL_INTEL_conservative_rasterization @@ -4718,9 +5000,9 @@ GLAPI void APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLi #ifndef GL_INTEL_framebuffer_CMAA #define GL_INTEL_framebuffer_CMAA 1 -typedef void (APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void); +typedef void(APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void); +GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL(void); #endif #endif /* GL_INTEL_framebuffer_CMAA */ @@ -4728,14 +5010,14 @@ GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void); #define GL_INTEL_performance_query 1 #define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 #define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 -#define GL_PERFQUERY_WAIT_INTEL 0x83FB -#define GL_PERFQUERY_FLUSH_INTEL 0x83FA -#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 -#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 +#define GL_PERFQUERY_WAIT_INTEL 0x83FB +#define GL_PERFQUERY_FLUSH_INTEL 0x83FA +#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 +#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 #define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 #define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 #define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 -#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 +#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 #define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 #define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 #define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 @@ -4746,240 +5028,260 @@ GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void); #define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE #define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF #define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 -typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle); -typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle); -typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle); -typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle); -typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId); -typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId); -typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); -typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten); -typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId); -typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +typedef void(APIENTRYP PFNGLBEGINPERFQUERYINTELPROC)(GLuint queryHandle); +typedef void(APIENTRYP PFNGLCREATEPERFQUERYINTELPROC)(GLuint queryId, GLuint* queryHandle); +typedef void(APIENTRYP PFNGLDELETEPERFQUERYINTELPROC)(GLuint queryHandle); +typedef void(APIENTRYP PFNGLENDPERFQUERYINTELPROC)(GLuint queryHandle); +typedef void(APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC)(GLuint* queryId); +typedef void(APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC)(GLuint queryId, GLuint* nextQueryId); +typedef void(APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC)( + GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar* counterName, GLuint counterDescLength, GLchar* counterDesc, + GLuint* counterOffset, GLuint* counterDataSize, GLuint* counterTypeEnum, GLuint* counterDataTypeEnum, GLuint64* rawCounterMaxValue); +typedef void(APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC)(GLuint queryHandle, GLuint flags, GLsizei dataSize, void* data, GLuint* bytesWritten); +typedef void(APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC)(GLchar* queryName, GLuint* queryId); +typedef void(APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC)(GLuint queryId, GLuint queryNameLength, GLchar* queryName, GLuint* dataSize, + GLuint* noCounters, GLuint* noInstances, GLuint* capsMask); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle); -GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle); -GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle); -GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle); -GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId); -GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId); -GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); -GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten); -GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId); -GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +GLAPI void APIENTRY glBeginPerfQueryINTEL(GLuint queryHandle); +GLAPI void APIENTRY glCreatePerfQueryINTEL(GLuint queryId, GLuint* queryHandle); +GLAPI void APIENTRY glDeletePerfQueryINTEL(GLuint queryHandle); +GLAPI void APIENTRY glEndPerfQueryINTEL(GLuint queryHandle); +GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL(GLuint* queryId); +GLAPI void APIENTRY glGetNextPerfQueryIdINTEL(GLuint queryId, GLuint* nextQueryId); +GLAPI void APIENTRY glGetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar* counterName, + GLuint counterDescLength, GLchar* counterDesc, GLuint* counterOffset, GLuint* counterDataSize, + GLuint* counterTypeEnum, GLuint* counterDataTypeEnum, GLuint64* rawCounterMaxValue); +GLAPI void APIENTRY glGetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags, GLsizei dataSize, void* data, GLuint* bytesWritten); +GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL(GLchar* queryName, GLuint* queryId); +GLAPI void APIENTRY glGetPerfQueryInfoINTEL(GLuint queryId, GLuint queryNameLength, GLchar* queryName, GLuint* dataSize, GLuint* noCounters, + GLuint* noInstances, GLuint* capsMask); #endif #endif /* GL_INTEL_performance_query */ #ifndef GL_MESA_framebuffer_flip_x #define GL_MESA_framebuffer_flip_x 1 -#define GL_FRAMEBUFFER_FLIP_X_MESA 0x8BBC +#define GL_FRAMEBUFFER_FLIP_X_MESA 0x8BBC #endif /* GL_MESA_framebuffer_flip_x */ #ifndef GL_MESA_framebuffer_flip_y #define GL_MESA_framebuffer_flip_y 1 -#define GL_FRAMEBUFFER_FLIP_Y_MESA 0x8BBB -typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIMESAPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVMESAPROC) (GLenum target, GLenum pname, GLint *params); +#define GL_FRAMEBUFFER_FLIP_Y_MESA 0x8BBB +typedef void(APIENTRYP PFNGLFRAMEBUFFERPARAMETERIMESAPROC)(GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVMESAPROC)(GLenum target, GLenum pname, GLint* params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFramebufferParameteriMESA (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glGetFramebufferParameterivMESA (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glFramebufferParameteriMESA(GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glGetFramebufferParameterivMESA(GLenum target, GLenum pname, GLint* params); #endif #endif /* GL_MESA_framebuffer_flip_y */ #ifndef GL_MESA_framebuffer_swap_xy #define GL_MESA_framebuffer_swap_xy 1 -#define GL_FRAMEBUFFER_SWAP_XY_MESA 0x8BBD +#define GL_FRAMEBUFFER_SWAP_XY_MESA 0x8BBD #endif /* GL_MESA_framebuffer_swap_xy */ #ifndef GL_NV_bindless_multi_draw_indirect #define GL_NV_bindless_multi_draw_indirect 1 -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +typedef void(APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC)(GLenum mode, const void* indirect, GLsizei drawCount, GLsizei stride, + GLint vertexBufferCount); +typedef void(APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC)(GLenum mode, GLenum type, const void* indirect, GLsizei drawCount, + GLsizei stride, GLint vertexBufferCount); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV(GLenum mode, const void* indirect, GLsizei drawCount, GLsizei stride, + GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV(GLenum mode, GLenum type, const void* indirect, GLsizei drawCount, GLsizei stride, + GLint vertexBufferCount); #endif #endif /* GL_NV_bindless_multi_draw_indirect */ #ifndef GL_NV_bindless_multi_draw_indirect_count #define GL_NV_bindless_multi_draw_indirect_count 1 -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +typedef void(APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC)(GLenum mode, const void* indirect, GLsizei drawCount, + GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +typedef void(APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC)(GLenum mode, GLenum type, const void* indirect, GLsizei drawCount, + GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessCountNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); -GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessCountNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessCountNV(GLenum mode, const void* indirect, GLsizei drawCount, GLsizei maxDrawCount, + GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessCountNV(GLenum mode, GLenum type, const void* indirect, GLsizei drawCount, + GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); #endif #endif /* GL_NV_bindless_multi_draw_indirect_count */ #ifndef GL_NV_bindless_texture #define GL_NV_bindless_texture 1 -typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); -typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle); -typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access); -typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); -typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle); +typedef GLuint64(APIENTRYP PFNGLGETTEXTUREHANDLENVPROC)(GLuint texture); +typedef GLuint64(APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC)(GLuint texture, GLuint sampler); +typedef void(APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC)(GLuint64 handle); +typedef void(APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC)(GLuint64 handle); +typedef GLuint64(APIENTRYP PFNGLGETIMAGEHANDLENVPROC)(GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void(APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC)(GLuint64 handle, GLenum access); +typedef void(APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC)(GLuint64 handle); +typedef void(APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC)(GLint location, GLuint64 value); +typedef void(APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC)(GLint location, GLsizei count, const GLuint64* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC)(GLuint program, GLint location, GLuint64 value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLuint64* values); +typedef GLboolean(APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC)(GLuint64 handle); +typedef GLboolean(APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC)(GLuint64 handle); #ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture); -GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler); -GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle); -GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle); -GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); -GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access); -GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle); -GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value); -GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value); -GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value); -GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values); -GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle); -GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetTextureHandleNV(GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV(GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentNV(GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentNV(GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleNV(GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentNV(GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentNV(GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64NV(GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vNV(GLint location, GLsizei count, const GLuint64* value); +GLAPI void APIENTRY glProgramUniformHandleui64NV(GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64* values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV(GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentNV(GLuint64 handle); #endif #endif /* GL_NV_bindless_texture */ #ifndef GL_NV_blend_equation_advanced #define GL_NV_blend_equation_advanced 1 -#define GL_BLEND_OVERLAP_NV 0x9281 -#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 -#define GL_BLUE_NV 0x1905 -#define GL_COLORBURN_NV 0x929A -#define GL_COLORDODGE_NV 0x9299 -#define GL_CONJOINT_NV 0x9284 -#define GL_CONTRAST_NV 0x92A1 -#define GL_DARKEN_NV 0x9297 -#define GL_DIFFERENCE_NV 0x929E -#define GL_DISJOINT_NV 0x9283 -#define GL_DST_ATOP_NV 0x928F -#define GL_DST_IN_NV 0x928B -#define GL_DST_NV 0x9287 -#define GL_DST_OUT_NV 0x928D -#define GL_DST_OVER_NV 0x9289 -#define GL_EXCLUSION_NV 0x92A0 -#define GL_GREEN_NV 0x1904 -#define GL_HARDLIGHT_NV 0x929B -#define GL_HARDMIX_NV 0x92A9 -#define GL_HSL_COLOR_NV 0x92AF -#define GL_HSL_HUE_NV 0x92AD -#define GL_HSL_LUMINOSITY_NV 0x92B0 -#define GL_HSL_SATURATION_NV 0x92AE -#define GL_INVERT_OVG_NV 0x92B4 -#define GL_INVERT_RGB_NV 0x92A3 -#define GL_LIGHTEN_NV 0x9298 -#define GL_LINEARBURN_NV 0x92A5 -#define GL_LINEARDODGE_NV 0x92A4 -#define GL_LINEARLIGHT_NV 0x92A7 -#define GL_MINUS_CLAMPED_NV 0x92B3 -#define GL_MINUS_NV 0x929F -#define GL_MULTIPLY_NV 0x9294 -#define GL_OVERLAY_NV 0x9296 -#define GL_PINLIGHT_NV 0x92A8 -#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 -#define GL_PLUS_CLAMPED_NV 0x92B1 -#define GL_PLUS_DARKER_NV 0x9292 -#define GL_PLUS_NV 0x9291 -#define GL_RED_NV 0x1903 -#define GL_SCREEN_NV 0x9295 -#define GL_SOFTLIGHT_NV 0x929C -#define GL_SRC_ATOP_NV 0x928E -#define GL_SRC_IN_NV 0x928A -#define GL_SRC_NV 0x9286 -#define GL_SRC_OUT_NV 0x928C -#define GL_SRC_OVER_NV 0x9288 -#define GL_UNCORRELATED_NV 0x9282 -#define GL_VIVIDLIGHT_NV 0x92A6 -#define GL_XOR_NV 0x1506 -typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); +#define GL_BLEND_OVERLAP_NV 0x9281 +#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define GL_BLUE_NV 0x1905 +#define GL_COLORBURN_NV 0x929A +#define GL_COLORDODGE_NV 0x9299 +#define GL_CONJOINT_NV 0x9284 +#define GL_CONTRAST_NV 0x92A1 +#define GL_DARKEN_NV 0x9297 +#define GL_DIFFERENCE_NV 0x929E +#define GL_DISJOINT_NV 0x9283 +#define GL_DST_ATOP_NV 0x928F +#define GL_DST_IN_NV 0x928B +#define GL_DST_NV 0x9287 +#define GL_DST_OUT_NV 0x928D +#define GL_DST_OVER_NV 0x9289 +#define GL_EXCLUSION_NV 0x92A0 +#define GL_GREEN_NV 0x1904 +#define GL_HARDLIGHT_NV 0x929B +#define GL_HARDMIX_NV 0x92A9 +#define GL_HSL_COLOR_NV 0x92AF +#define GL_HSL_HUE_NV 0x92AD +#define GL_HSL_LUMINOSITY_NV 0x92B0 +#define GL_HSL_SATURATION_NV 0x92AE +#define GL_INVERT_OVG_NV 0x92B4 +#define GL_INVERT_RGB_NV 0x92A3 +#define GL_LIGHTEN_NV 0x9298 +#define GL_LINEARBURN_NV 0x92A5 +#define GL_LINEARDODGE_NV 0x92A4 +#define GL_LINEARLIGHT_NV 0x92A7 +#define GL_MINUS_CLAMPED_NV 0x92B3 +#define GL_MINUS_NV 0x929F +#define GL_MULTIPLY_NV 0x9294 +#define GL_OVERLAY_NV 0x9296 +#define GL_PINLIGHT_NV 0x92A8 +#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 +#define GL_PLUS_CLAMPED_NV 0x92B1 +#define GL_PLUS_DARKER_NV 0x9292 +#define GL_PLUS_NV 0x9291 +#define GL_RED_NV 0x1903 +#define GL_SCREEN_NV 0x9295 +#define GL_SOFTLIGHT_NV 0x929C +#define GL_SRC_ATOP_NV 0x928E +#define GL_SRC_IN_NV 0x928A +#define GL_SRC_NV 0x9286 +#define GL_SRC_OUT_NV 0x928C +#define GL_SRC_OVER_NV 0x9288 +#define GL_UNCORRELATED_NV 0x9282 +#define GL_VIVIDLIGHT_NV 0x92A6 +#define GL_XOR_NV 0x1506 +typedef void(APIENTRYP PFNGLBLENDPARAMETERINVPROC)(GLenum pname, GLint value); +typedef void(APIENTRYP PFNGLBLENDBARRIERNVPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value); -GLAPI void APIENTRY glBlendBarrierNV (void); +GLAPI void APIENTRY glBlendParameteriNV(GLenum pname, GLint value); +GLAPI void APIENTRY glBlendBarrierNV(void); #endif #endif /* GL_NV_blend_equation_advanced */ #ifndef GL_NV_blend_equation_advanced_coherent #define GL_NV_blend_equation_advanced_coherent 1 -#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 +#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 #endif /* GL_NV_blend_equation_advanced_coherent */ #ifndef GL_NV_blend_minmax_factor #define GL_NV_blend_minmax_factor 1 -#define GL_FACTOR_MIN_AMD 0x901C -#define GL_FACTOR_MAX_AMD 0x901D +#define GL_FACTOR_MIN_AMD 0x901C +#define GL_FACTOR_MAX_AMD 0x901D #endif /* GL_NV_blend_minmax_factor */ #ifndef GL_NV_clip_space_w_scaling #define GL_NV_clip_space_w_scaling 1 -#define GL_VIEWPORT_POSITION_W_SCALE_NV 0x937C +#define GL_VIEWPORT_POSITION_W_SCALE_NV 0x937C #define GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D #define GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E -typedef void (APIENTRYP PFNGLVIEWPORTPOSITIONWSCALENVPROC) (GLuint index, GLfloat xcoeff, GLfloat ycoeff); +typedef void(APIENTRYP PFNGLVIEWPORTPOSITIONWSCALENVPROC)(GLuint index, GLfloat xcoeff, GLfloat ycoeff); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glViewportPositionWScaleNV (GLuint index, GLfloat xcoeff, GLfloat ycoeff); +GLAPI void APIENTRY glViewportPositionWScaleNV(GLuint index, GLfloat xcoeff, GLfloat ycoeff); #endif #endif /* GL_NV_clip_space_w_scaling */ #ifndef GL_NV_command_list #define GL_NV_command_list 1 -#define GL_TERMINATE_SEQUENCE_COMMAND_NV 0x0000 -#define GL_NOP_COMMAND_NV 0x0001 -#define GL_DRAW_ELEMENTS_COMMAND_NV 0x0002 -#define GL_DRAW_ARRAYS_COMMAND_NV 0x0003 +#define GL_TERMINATE_SEQUENCE_COMMAND_NV 0x0000 +#define GL_NOP_COMMAND_NV 0x0001 +#define GL_DRAW_ELEMENTS_COMMAND_NV 0x0002 +#define GL_DRAW_ARRAYS_COMMAND_NV 0x0003 #define GL_DRAW_ELEMENTS_STRIP_COMMAND_NV 0x0004 -#define GL_DRAW_ARRAYS_STRIP_COMMAND_NV 0x0005 +#define GL_DRAW_ARRAYS_STRIP_COMMAND_NV 0x0005 #define GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV 0x0006 #define GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV 0x0007 -#define GL_ELEMENT_ADDRESS_COMMAND_NV 0x0008 -#define GL_ATTRIBUTE_ADDRESS_COMMAND_NV 0x0009 -#define GL_UNIFORM_ADDRESS_COMMAND_NV 0x000A -#define GL_BLEND_COLOR_COMMAND_NV 0x000B -#define GL_STENCIL_REF_COMMAND_NV 0x000C -#define GL_LINE_WIDTH_COMMAND_NV 0x000D -#define GL_POLYGON_OFFSET_COMMAND_NV 0x000E -#define GL_ALPHA_REF_COMMAND_NV 0x000F -#define GL_VIEWPORT_COMMAND_NV 0x0010 -#define GL_SCISSOR_COMMAND_NV 0x0011 -#define GL_FRONT_FACE_COMMAND_NV 0x0012 -typedef void (APIENTRYP PFNGLCREATESTATESNVPROC) (GLsizei n, GLuint *states); -typedef void (APIENTRYP PFNGLDELETESTATESNVPROC) (GLsizei n, const GLuint *states); -typedef GLboolean (APIENTRYP PFNGLISSTATENVPROC) (GLuint state); -typedef void (APIENTRYP PFNGLSTATECAPTURENVPROC) (GLuint state, GLenum mode); -typedef GLuint (APIENTRYP PFNGLGETCOMMANDHEADERNVPROC) (GLenum tokenID, GLuint size); -typedef GLushort (APIENTRYP PFNGLGETSTAGEINDEXNVPROC) (GLenum shadertype); -typedef void (APIENTRYP PFNGLDRAWCOMMANDSNVPROC) (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count); -typedef void (APIENTRYP PFNGLDRAWCOMMANDSADDRESSNVPROC) (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count); -typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESNVPROC) (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); -typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC) (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); -typedef void (APIENTRYP PFNGLCREATECOMMANDLISTSNVPROC) (GLsizei n, GLuint *lists); -typedef void (APIENTRYP PFNGLDELETECOMMANDLISTSNVPROC) (GLsizei n, const GLuint *lists); -typedef GLboolean (APIENTRYP PFNGLISCOMMANDLISTNVPROC) (GLuint list); -typedef void (APIENTRYP PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC) (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); -typedef void (APIENTRYP PFNGLCOMMANDLISTSEGMENTSNVPROC) (GLuint list, GLuint segments); -typedef void (APIENTRYP PFNGLCOMPILECOMMANDLISTNVPROC) (GLuint list); -typedef void (APIENTRYP PFNGLCALLCOMMANDLISTNVPROC) (GLuint list); +#define GL_ELEMENT_ADDRESS_COMMAND_NV 0x0008 +#define GL_ATTRIBUTE_ADDRESS_COMMAND_NV 0x0009 +#define GL_UNIFORM_ADDRESS_COMMAND_NV 0x000A +#define GL_BLEND_COLOR_COMMAND_NV 0x000B +#define GL_STENCIL_REF_COMMAND_NV 0x000C +#define GL_LINE_WIDTH_COMMAND_NV 0x000D +#define GL_POLYGON_OFFSET_COMMAND_NV 0x000E +#define GL_ALPHA_REF_COMMAND_NV 0x000F +#define GL_VIEWPORT_COMMAND_NV 0x0010 +#define GL_SCISSOR_COMMAND_NV 0x0011 +#define GL_FRONT_FACE_COMMAND_NV 0x0012 +typedef void(APIENTRYP PFNGLCREATESTATESNVPROC)(GLsizei n, GLuint* states); +typedef void(APIENTRYP PFNGLDELETESTATESNVPROC)(GLsizei n, const GLuint* states); +typedef GLboolean(APIENTRYP PFNGLISSTATENVPROC)(GLuint state); +typedef void(APIENTRYP PFNGLSTATECAPTURENVPROC)(GLuint state, GLenum mode); +typedef GLuint(APIENTRYP PFNGLGETCOMMANDHEADERNVPROC)(GLenum tokenID, GLuint size); +typedef GLushort(APIENTRYP PFNGLGETSTAGEINDEXNVPROC)(GLenum shadertype); +typedef void(APIENTRYP PFNGLDRAWCOMMANDSNVPROC)(GLenum primitiveMode, GLuint buffer, const GLintptr* indirects, const GLsizei* sizes, GLuint count); +typedef void(APIENTRYP PFNGLDRAWCOMMANDSADDRESSNVPROC)(GLenum primitiveMode, const GLuint64* indirects, const GLsizei* sizes, GLuint count); +typedef void(APIENTRYP PFNGLDRAWCOMMANDSSTATESNVPROC)(GLuint buffer, const GLintptr* indirects, const GLsizei* sizes, const GLuint* states, + const GLuint* fbos, GLuint count); +typedef void(APIENTRYP PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC)(const GLuint64* indirects, const GLsizei* sizes, const GLuint* states, + const GLuint* fbos, GLuint count); +typedef void(APIENTRYP PFNGLCREATECOMMANDLISTSNVPROC)(GLsizei n, GLuint* lists); +typedef void(APIENTRYP PFNGLDELETECOMMANDLISTSNVPROC)(GLsizei n, const GLuint* lists); +typedef GLboolean(APIENTRYP PFNGLISCOMMANDLISTNVPROC)(GLuint list); +typedef void(APIENTRYP PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC)(GLuint list, GLuint segment, const void** indirects, const GLsizei* sizes, + const GLuint* states, const GLuint* fbos, GLuint count); +typedef void(APIENTRYP PFNGLCOMMANDLISTSEGMENTSNVPROC)(GLuint list, GLuint segments); +typedef void(APIENTRYP PFNGLCOMPILECOMMANDLISTNVPROC)(GLuint list); +typedef void(APIENTRYP PFNGLCALLCOMMANDLISTNVPROC)(GLuint list); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCreateStatesNV (GLsizei n, GLuint *states); -GLAPI void APIENTRY glDeleteStatesNV (GLsizei n, const GLuint *states); -GLAPI GLboolean APIENTRY glIsStateNV (GLuint state); -GLAPI void APIENTRY glStateCaptureNV (GLuint state, GLenum mode); -GLAPI GLuint APIENTRY glGetCommandHeaderNV (GLenum tokenID, GLuint size); -GLAPI GLushort APIENTRY glGetStageIndexNV (GLenum shadertype); -GLAPI void APIENTRY glDrawCommandsNV (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count); -GLAPI void APIENTRY glDrawCommandsAddressNV (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count); -GLAPI void APIENTRY glDrawCommandsStatesNV (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); -GLAPI void APIENTRY glDrawCommandsStatesAddressNV (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); -GLAPI void APIENTRY glCreateCommandListsNV (GLsizei n, GLuint *lists); -GLAPI void APIENTRY glDeleteCommandListsNV (GLsizei n, const GLuint *lists); -GLAPI GLboolean APIENTRY glIsCommandListNV (GLuint list); -GLAPI void APIENTRY glListDrawCommandsStatesClientNV (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); -GLAPI void APIENTRY glCommandListSegmentsNV (GLuint list, GLuint segments); -GLAPI void APIENTRY glCompileCommandListNV (GLuint list); -GLAPI void APIENTRY glCallCommandListNV (GLuint list); +GLAPI void APIENTRY glCreateStatesNV(GLsizei n, GLuint* states); +GLAPI void APIENTRY glDeleteStatesNV(GLsizei n, const GLuint* states); +GLAPI GLboolean APIENTRY glIsStateNV(GLuint state); +GLAPI void APIENTRY glStateCaptureNV(GLuint state, GLenum mode); +GLAPI GLuint APIENTRY glGetCommandHeaderNV(GLenum tokenID, GLuint size); +GLAPI GLushort APIENTRY glGetStageIndexNV(GLenum shadertype); +GLAPI void APIENTRY glDrawCommandsNV(GLenum primitiveMode, GLuint buffer, const GLintptr* indirects, const GLsizei* sizes, GLuint count); +GLAPI void APIENTRY glDrawCommandsAddressNV(GLenum primitiveMode, const GLuint64* indirects, const GLsizei* sizes, GLuint count); +GLAPI void APIENTRY glDrawCommandsStatesNV(GLuint buffer, const GLintptr* indirects, const GLsizei* sizes, const GLuint* states, + const GLuint* fbos, GLuint count); +GLAPI void APIENTRY glDrawCommandsStatesAddressNV(const GLuint64* indirects, const GLsizei* sizes, const GLuint* states, const GLuint* fbos, + GLuint count); +GLAPI void APIENTRY glCreateCommandListsNV(GLsizei n, GLuint* lists); +GLAPI void APIENTRY glDeleteCommandListsNV(GLsizei n, const GLuint* lists); +GLAPI GLboolean APIENTRY glIsCommandListNV(GLuint list); +GLAPI void APIENTRY glListDrawCommandsStatesClientNV(GLuint list, GLuint segment, const void** indirects, const GLsizei* sizes, + const GLuint* states, const GLuint* fbos, GLuint count); +GLAPI void APIENTRY glCommandListSegmentsNV(GLuint list, GLuint segments); +GLAPI void APIENTRY glCompileCommandListNV(GLuint list); +GLAPI void APIENTRY glCallCommandListNV(GLuint list); #endif #endif /* GL_NV_command_list */ @@ -4989,38 +5291,38 @@ GLAPI void APIENTRY glCallCommandListNV (GLuint list); #ifndef GL_NV_conditional_render #define GL_NV_conditional_render 1 -#define GL_QUERY_WAIT_NV 0x8E13 -#define GL_QUERY_NO_WAIT_NV 0x8E14 -#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); +#define GL_QUERY_WAIT_NV 0x8E13 +#define GL_QUERY_NO_WAIT_NV 0x8E14 +#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 +typedef void(APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC)(GLuint id, GLenum mode); +typedef void(APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRenderNV (void); +GLAPI void APIENTRY glBeginConditionalRenderNV(GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRenderNV(void); #endif #endif /* GL_NV_conditional_render */ #ifndef GL_NV_conservative_raster #define GL_NV_conservative_raster 1 -#define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 +#define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 #define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347 #define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348 #define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349 -typedef void (APIENTRYP PFNGLSUBPIXELPRECISIONBIASNVPROC) (GLuint xbits, GLuint ybits); +typedef void(APIENTRYP PFNGLSUBPIXELPRECISIONBIASNVPROC)(GLuint xbits, GLuint ybits); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybits); +GLAPI void APIENTRY glSubpixelPrecisionBiasNV(GLuint xbits, GLuint ybits); #endif #endif /* GL_NV_conservative_raster */ #ifndef GL_NV_conservative_raster_dilate #define GL_NV_conservative_raster_dilate 1 -#define GL_CONSERVATIVE_RASTER_DILATE_NV 0x9379 +#define GL_CONSERVATIVE_RASTER_DILATE_NV 0x9379 #define GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A #define GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B -typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERFNVPROC) (GLenum pname, GLfloat value); +typedef void(APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERFNVPROC)(GLenum pname, GLfloat value); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glConservativeRasterParameterfNV (GLenum pname, GLfloat value); +GLAPI void APIENTRY glConservativeRasterParameterfNV(GLenum pname, GLfloat value); #endif #endif /* GL_NV_conservative_raster_dilate */ @@ -5031,12 +5333,12 @@ GLAPI void APIENTRY glConservativeRasterParameterfNV (GLenum pname, GLfloat valu #ifndef GL_NV_conservative_raster_pre_snap_triangles #define GL_NV_conservative_raster_pre_snap_triangles 1 -#define GL_CONSERVATIVE_RASTER_MODE_NV 0x954D +#define GL_CONSERVATIVE_RASTER_MODE_NV 0x954D #define GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E #define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F -typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void(APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC)(GLenum pname, GLint param); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param); +GLAPI void APIENTRY glConservativeRasterParameteriNV(GLenum pname, GLint param); #endif #endif /* GL_NV_conservative_raster_pre_snap_triangles */ @@ -5046,49 +5348,51 @@ GLAPI void APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param) #ifndef GL_NV_depth_buffer_float #define GL_NV_depth_buffer_float 1 -#define GL_DEPTH_COMPONENT32F_NV 0x8DAB -#define GL_DEPTH32F_STENCIL8_NV 0x8DAC +#define GL_DEPTH_COMPONENT32F_NV 0x8DAB +#define GL_DEPTH32F_STENCIL8_NV 0x8DAC #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD -#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF -typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); -typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); +#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF +typedef void(APIENTRYP PFNGLDEPTHRANGEDNVPROC)(GLdouble zNear, GLdouble zFar); +typedef void(APIENTRYP PFNGLCLEARDEPTHDNVPROC)(GLdouble depth); +typedef void(APIENTRYP PFNGLDEPTHBOUNDSDNVPROC)(GLdouble zmin, GLdouble zmax); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); -GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); +GLAPI void APIENTRY glDepthRangedNV(GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glClearDepthdNV(GLdouble depth); +GLAPI void APIENTRY glDepthBoundsdNV(GLdouble zmin, GLdouble zmax); #endif #endif /* GL_NV_depth_buffer_float */ #ifndef GL_NV_draw_vulkan_image #define GL_NV_draw_vulkan_image 1 -typedef void (APIENTRY *GLVULKANPROCNV)(void); -typedef void (APIENTRYP PFNGLDRAWVKIMAGENVPROC) (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); -typedef GLVULKANPROCNV (APIENTRYP PFNGLGETVKPROCADDRNVPROC) (const GLchar *name); -typedef void (APIENTRYP PFNGLWAITVKSEMAPHORENVPROC) (GLuint64 vkSemaphore); -typedef void (APIENTRYP PFNGLSIGNALVKSEMAPHORENVPROC) (GLuint64 vkSemaphore); -typedef void (APIENTRYP PFNGLSIGNALVKFENCENVPROC) (GLuint64 vkFence); +typedef void(APIENTRY* GLVULKANPROCNV)(void); +typedef void(APIENTRYP PFNGLDRAWVKIMAGENVPROC)(GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, + GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +typedef GLVULKANPROCNV(APIENTRYP PFNGLGETVKPROCADDRNVPROC)(const GLchar* name); +typedef void(APIENTRYP PFNGLWAITVKSEMAPHORENVPROC)(GLuint64 vkSemaphore); +typedef void(APIENTRYP PFNGLSIGNALVKSEMAPHORENVPROC)(GLuint64 vkSemaphore); +typedef void(APIENTRYP PFNGLSIGNALVKFENCENVPROC)(GLuint64 vkFence); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawVkImageNV (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); -GLAPI GLVULKANPROCNV APIENTRY glGetVkProcAddrNV (const GLchar *name); -GLAPI void APIENTRY glWaitVkSemaphoreNV (GLuint64 vkSemaphore); -GLAPI void APIENTRY glSignalVkSemaphoreNV (GLuint64 vkSemaphore); -GLAPI void APIENTRY glSignalVkFenceNV (GLuint64 vkFence); +GLAPI void APIENTRY glDrawVkImageNV(GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, + GLfloat t0, GLfloat s1, GLfloat t1); +GLAPI GLVULKANPROCNV APIENTRY glGetVkProcAddrNV(const GLchar* name); +GLAPI void APIENTRY glWaitVkSemaphoreNV(GLuint64 vkSemaphore); +GLAPI void APIENTRY glSignalVkSemaphoreNV(GLuint64 vkSemaphore); +GLAPI void APIENTRY glSignalVkFenceNV(GLuint64 vkFence); #endif #endif /* GL_NV_draw_vulkan_image */ #ifndef GL_NV_fill_rectangle #define GL_NV_fill_rectangle 1 -#define GL_FILL_RECTANGLE_NV 0x933C +#define GL_FILL_RECTANGLE_NV 0x933C #endif /* GL_NV_fill_rectangle */ #ifndef GL_NV_fragment_coverage_to_color #define GL_NV_fragment_coverage_to_color 1 -#define GL_FRAGMENT_COVERAGE_TO_COLOR_NV 0x92DD -#define GL_FRAGMENT_COVERAGE_COLOR_NV 0x92DE -typedef void (APIENTRYP PFNGLFRAGMENTCOVERAGECOLORNVPROC) (GLuint color); +#define GL_FRAGMENT_COVERAGE_TO_COLOR_NV 0x92DD +#define GL_FRAGMENT_COVERAGE_COLOR_NV 0x92DE +typedef void(APIENTRYP PFNGLFRAGMENTCOVERAGECOLORNVPROC)(GLuint color); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFragmentCoverageColorNV (GLuint color); +GLAPI void APIENTRY glFragmentCoverageColorNV(GLuint color); #endif #endif /* GL_NV_fragment_coverage_to_color */ @@ -5102,33 +5406,35 @@ GLAPI void APIENTRY glFragmentCoverageColorNV (GLuint color); #ifndef GL_NV_framebuffer_mixed_samples #define GL_NV_framebuffer_mixed_samples 1 -#define GL_COVERAGE_MODULATION_TABLE_NV 0x9331 -#define GL_COLOR_SAMPLES_NV 0x8E20 -#define GL_DEPTH_SAMPLES_NV 0x932D -#define GL_STENCIL_SAMPLES_NV 0x932E +#define GL_COVERAGE_MODULATION_TABLE_NV 0x9331 +#define GL_COLOR_SAMPLES_NV 0x8E20 +#define GL_DEPTH_SAMPLES_NV 0x932D +#define GL_STENCIL_SAMPLES_NV 0x932E #define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F #define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330 -#define GL_COVERAGE_MODULATION_NV 0x9332 +#define GL_COVERAGE_MODULATION_NV 0x9332 #define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333 -typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONTABLENVPROC) (GLsizei n, const GLfloat *v); -typedef void (APIENTRYP PFNGLGETCOVERAGEMODULATIONTABLENVPROC) (GLsizei bufSize, GLfloat *v); -typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONNVPROC) (GLenum components); +typedef void(APIENTRYP PFNGLCOVERAGEMODULATIONTABLENVPROC)(GLsizei n, const GLfloat* v); +typedef void(APIENTRYP PFNGLGETCOVERAGEMODULATIONTABLENVPROC)(GLsizei bufSize, GLfloat* v); +typedef void(APIENTRYP PFNGLCOVERAGEMODULATIONNVPROC)(GLenum components); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCoverageModulationTableNV (GLsizei n, const GLfloat *v); -GLAPI void APIENTRY glGetCoverageModulationTableNV (GLsizei bufSize, GLfloat *v); -GLAPI void APIENTRY glCoverageModulationNV (GLenum components); +GLAPI void APIENTRY glCoverageModulationTableNV(GLsizei n, const GLfloat* v); +GLAPI void APIENTRY glGetCoverageModulationTableNV(GLsizei bufSize, GLfloat* v); +GLAPI void APIENTRY glCoverageModulationNV(GLenum components); #endif #endif /* GL_NV_framebuffer_mixed_samples */ #ifndef GL_NV_framebuffer_multisample_coverage #define GL_NV_framebuffer_multisample_coverage 1 #define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB -#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 +#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 #define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 -#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 +typedef void(APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC)(GLenum target, GLsizei coverageSamples, GLsizei colorSamples, + GLenum internalformat, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV(GLenum target, GLsizei coverageSamples, GLsizei colorSamples, + GLenum internalformat, GLsizei width, GLsizei height); #endif #endif /* GL_NV_framebuffer_multisample_coverage */ @@ -5139,482 +5445,527 @@ GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, G #ifndef GL_NV_gpu_shader5 #define GL_NV_gpu_shader5 1 typedef khronos_int64_t GLint64EXT; -#define GL_INT64_NV 0x140E -#define GL_UNSIGNED_INT64_NV 0x140F -#define GL_INT8_NV 0x8FE0 -#define GL_INT8_VEC2_NV 0x8FE1 -#define GL_INT8_VEC3_NV 0x8FE2 -#define GL_INT8_VEC4_NV 0x8FE3 -#define GL_INT16_NV 0x8FE4 -#define GL_INT16_VEC2_NV 0x8FE5 -#define GL_INT16_VEC3_NV 0x8FE6 -#define GL_INT16_VEC4_NV 0x8FE7 -#define GL_INT64_VEC2_NV 0x8FE9 -#define GL_INT64_VEC3_NV 0x8FEA -#define GL_INT64_VEC4_NV 0x8FEB -#define GL_UNSIGNED_INT8_NV 0x8FEC -#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED -#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE -#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF -#define GL_UNSIGNED_INT16_NV 0x8FF0 -#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 -#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 -#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 -#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 -#define GL_FLOAT16_NV 0x8FF8 -#define GL_FLOAT16_VEC2_NV 0x8FF9 -#define GL_FLOAT16_VEC3_NV 0x8FFA -#define GL_FLOAT16_VEC4_NV 0x8FFB -typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#define GL_INT64_NV 0x140E +#define GL_UNSIGNED_INT64_NV 0x140F +#define GL_INT8_NV 0x8FE0 +#define GL_INT8_VEC2_NV 0x8FE1 +#define GL_INT8_VEC3_NV 0x8FE2 +#define GL_INT8_VEC4_NV 0x8FE3 +#define GL_INT16_NV 0x8FE4 +#define GL_INT16_VEC2_NV 0x8FE5 +#define GL_INT16_VEC3_NV 0x8FE6 +#define GL_INT16_VEC4_NV 0x8FE7 +#define GL_INT64_VEC2_NV 0x8FE9 +#define GL_INT64_VEC3_NV 0x8FEA +#define GL_INT64_VEC4_NV 0x8FEB +#define GL_UNSIGNED_INT8_NV 0x8FEC +#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED +#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE +#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF +#define GL_UNSIGNED_INT16_NV 0x8FF0 +#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 +#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 +#define GL_FLOAT16_NV 0x8FF8 +#define GL_FLOAT16_VEC2_NV 0x8FF9 +#define GL_FLOAT16_VEC3_NV 0x8FFA +#define GL_FLOAT16_VEC4_NV 0x8FFB +typedef void(APIENTRYP PFNGLUNIFORM1I64NVPROC)(GLint location, GLint64EXT x); +typedef void(APIENTRYP PFNGLUNIFORM2I64NVPROC)(GLint location, GLint64EXT x, GLint64EXT y); +typedef void(APIENTRYP PFNGLUNIFORM3I64NVPROC)(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void(APIENTRYP PFNGLUNIFORM4I64NVPROC)(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void(APIENTRYP PFNGLUNIFORM1I64VNVPROC)(GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLUNIFORM2I64VNVPROC)(GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLUNIFORM3I64VNVPROC)(GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLUNIFORM4I64VNVPROC)(GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLUNIFORM1UI64NVPROC)(GLint location, GLuint64EXT x); +typedef void(APIENTRYP PFNGLUNIFORM2UI64NVPROC)(GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void(APIENTRYP PFNGLUNIFORM3UI64NVPROC)(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void(APIENTRYP PFNGLUNIFORM4UI64NVPROC)(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void(APIENTRYP PFNGLUNIFORM1UI64VNVPROC)(GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLUNIFORM2UI64VNVPROC)(GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLUNIFORM3UI64VNVPROC)(GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLUNIFORM4UI64VNVPROC)(GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLGETUNIFORMI64VNVPROC)(GLuint program, GLint location, GLint64EXT* params); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC)(GLuint program, GLint location, GLint64EXT x); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC)(GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC)(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC)(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC)(GLuint program, GLint location, GLuint64EXT x); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC)(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC)(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC)(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); -GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); -GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); -GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); -GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); -GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform1i64NV(GLint location, GLint64EXT x); +GLAPI void APIENTRY glUniform2i64NV(GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glUniform3i64NV(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glUniform4i64NV(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glUniform1i64vNV(GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glUniform2i64vNV(GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glUniform3i64vNV(GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glUniform4i64vNV(GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glUniform1ui64NV(GLint location, GLuint64EXT x); +GLAPI void APIENTRY glUniform2ui64NV(GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glUniform3ui64NV(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glUniform4ui64NV(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glUniform1ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glUniform2ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glUniform3ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glUniform4ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glGetUniformi64vNV(GLuint program, GLint location, GLint64EXT* params); +GLAPI void APIENTRY glProgramUniform1i64NV(GLuint program, GLint location, GLint64EXT x); +GLAPI void APIENTRY glProgramUniform2i64NV(GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glProgramUniform3i64NV(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glProgramUniform4i64NV(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glProgramUniform1i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glProgramUniform2i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glProgramUniform3i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glProgramUniform4i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value); +GLAPI void APIENTRY glProgramUniform1ui64NV(GLuint program, GLint location, GLuint64EXT x); +GLAPI void APIENTRY glProgramUniform2ui64NV(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glProgramUniform3ui64NV(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glProgramUniform4ui64NV(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glProgramUniform1ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glProgramUniform2ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glProgramUniform3ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glProgramUniform4ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); #endif #endif /* GL_NV_gpu_shader5 */ #ifndef GL_NV_internalformat_sample_query #define GL_NV_internalformat_sample_query 1 -#define GL_MULTISAMPLES_NV 0x9371 -#define GL_SUPERSAMPLE_SCALE_X_NV 0x9372 -#define GL_SUPERSAMPLE_SCALE_Y_NV 0x9373 -#define GL_CONFORMANT_NV 0x9374 -typedef void (APIENTRYP PFNGLGETINTERNALFORMATSAMPLEIVNVPROC) (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei count, GLint *params); +#define GL_MULTISAMPLES_NV 0x9371 +#define GL_SUPERSAMPLE_SCALE_X_NV 0x9372 +#define GL_SUPERSAMPLE_SCALE_Y_NV 0x9373 +#define GL_CONFORMANT_NV 0x9374 +typedef void(APIENTRYP PFNGLGETINTERNALFORMATSAMPLEIVNVPROC)(GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, + GLsizei count, GLint* params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetInternalformatSampleivNV (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei count, GLint *params); +GLAPI void APIENTRY glGetInternalformatSampleivNV(GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei count, GLint* params); #endif #endif /* GL_NV_internalformat_sample_query */ #ifndef GL_NV_memory_attachment #define GL_NV_memory_attachment 1 -#define GL_ATTACHED_MEMORY_OBJECT_NV 0x95A4 -#define GL_ATTACHED_MEMORY_OFFSET_NV 0x95A5 +#define GL_ATTACHED_MEMORY_OBJECT_NV 0x95A4 +#define GL_ATTACHED_MEMORY_OFFSET_NV 0x95A5 #define GL_MEMORY_ATTACHABLE_ALIGNMENT_NV 0x95A6 -#define GL_MEMORY_ATTACHABLE_SIZE_NV 0x95A7 -#define GL_MEMORY_ATTACHABLE_NV 0x95A8 +#define GL_MEMORY_ATTACHABLE_SIZE_NV 0x95A7 +#define GL_MEMORY_ATTACHABLE_NV 0x95A8 #define GL_DETACHED_MEMORY_INCARNATION_NV 0x95A9 -#define GL_DETACHED_TEXTURES_NV 0x95AA -#define GL_DETACHED_BUFFERS_NV 0x95AB -#define GL_MAX_DETACHED_TEXTURES_NV 0x95AC -#define GL_MAX_DETACHED_BUFFERS_NV 0x95AD -typedef void (APIENTRYP PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC) (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params); -typedef void (APIENTRYP PFNGLRESETMEMORYOBJECTPARAMETERNVPROC) (GLuint memory, GLenum pname); -typedef void (APIENTRYP PFNGLTEXATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset); -typedef void (APIENTRYP PFNGLBUFFERATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset); -typedef void (APIENTRYP PFNGLTEXTUREATTACHMEMORYNVPROC) (GLuint texture, GLuint memory, GLuint64 offset); -typedef void (APIENTRYP PFNGLNAMEDBUFFERATTACHMEMORYNVPROC) (GLuint buffer, GLuint memory, GLuint64 offset); +#define GL_DETACHED_TEXTURES_NV 0x95AA +#define GL_DETACHED_BUFFERS_NV 0x95AB +#define GL_MAX_DETACHED_TEXTURES_NV 0x95AC +#define GL_MAX_DETACHED_BUFFERS_NV 0x95AD +typedef void(APIENTRYP PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC)(GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint* params); +typedef void(APIENTRYP PFNGLRESETMEMORYOBJECTPARAMETERNVPROC)(GLuint memory, GLenum pname); +typedef void(APIENTRYP PFNGLTEXATTACHMEMORYNVPROC)(GLenum target, GLuint memory, GLuint64 offset); +typedef void(APIENTRYP PFNGLBUFFERATTACHMEMORYNVPROC)(GLenum target, GLuint memory, GLuint64 offset); +typedef void(APIENTRYP PFNGLTEXTUREATTACHMEMORYNVPROC)(GLuint texture, GLuint memory, GLuint64 offset); +typedef void(APIENTRYP PFNGLNAMEDBUFFERATTACHMEMORYNVPROC)(GLuint buffer, GLuint memory, GLuint64 offset); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetMemoryObjectDetachedResourcesuivNV (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params); -GLAPI void APIENTRY glResetMemoryObjectParameterNV (GLuint memory, GLenum pname); -GLAPI void APIENTRY glTexAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset); -GLAPI void APIENTRY glBufferAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset); -GLAPI void APIENTRY glTextureAttachMemoryNV (GLuint texture, GLuint memory, GLuint64 offset); -GLAPI void APIENTRY glNamedBufferAttachMemoryNV (GLuint buffer, GLuint memory, GLuint64 offset); +GLAPI void APIENTRY glGetMemoryObjectDetachedResourcesuivNV(GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint* params); +GLAPI void APIENTRY glResetMemoryObjectParameterNV(GLuint memory, GLenum pname); +GLAPI void APIENTRY glTexAttachMemoryNV(GLenum target, GLuint memory, GLuint64 offset); +GLAPI void APIENTRY glBufferAttachMemoryNV(GLenum target, GLuint memory, GLuint64 offset); +GLAPI void APIENTRY glTextureAttachMemoryNV(GLuint texture, GLuint memory, GLuint64 offset); +GLAPI void APIENTRY glNamedBufferAttachMemoryNV(GLuint buffer, GLuint memory, GLuint64 offset); #endif #endif /* GL_NV_memory_attachment */ #ifndef GL_NV_mesh_shader #define GL_NV_mesh_shader 1 -#define GL_MESH_SHADER_NV 0x9559 -#define GL_TASK_SHADER_NV 0x955A -#define GL_MAX_MESH_UNIFORM_BLOCKS_NV 0x8E60 +#define GL_MESH_SHADER_NV 0x9559 +#define GL_TASK_SHADER_NV 0x955A +#define GL_MAX_MESH_UNIFORM_BLOCKS_NV 0x8E60 #define GL_MAX_MESH_TEXTURE_IMAGE_UNITS_NV 0x8E61 -#define GL_MAX_MESH_IMAGE_UNIFORMS_NV 0x8E62 +#define GL_MAX_MESH_IMAGE_UNIFORMS_NV 0x8E62 #define GL_MAX_MESH_UNIFORM_COMPONENTS_NV 0x8E63 #define GL_MAX_MESH_ATOMIC_COUNTER_BUFFERS_NV 0x8E64 -#define GL_MAX_MESH_ATOMIC_COUNTERS_NV 0x8E65 +#define GL_MAX_MESH_ATOMIC_COUNTERS_NV 0x8E65 #define GL_MAX_MESH_SHADER_STORAGE_BLOCKS_NV 0x8E66 #define GL_MAX_COMBINED_MESH_UNIFORM_COMPONENTS_NV 0x8E67 -#define GL_MAX_TASK_UNIFORM_BLOCKS_NV 0x8E68 +#define GL_MAX_TASK_UNIFORM_BLOCKS_NV 0x8E68 #define GL_MAX_TASK_TEXTURE_IMAGE_UNITS_NV 0x8E69 -#define GL_MAX_TASK_IMAGE_UNIFORMS_NV 0x8E6A +#define GL_MAX_TASK_IMAGE_UNIFORMS_NV 0x8E6A #define GL_MAX_TASK_UNIFORM_COMPONENTS_NV 0x8E6B #define GL_MAX_TASK_ATOMIC_COUNTER_BUFFERS_NV 0x8E6C -#define GL_MAX_TASK_ATOMIC_COUNTERS_NV 0x8E6D +#define GL_MAX_TASK_ATOMIC_COUNTERS_NV 0x8E6D #define GL_MAX_TASK_SHADER_STORAGE_BLOCKS_NV 0x8E6E #define GL_MAX_COMBINED_TASK_UNIFORM_COMPONENTS_NV 0x8E6F #define GL_MAX_MESH_WORK_GROUP_INVOCATIONS_NV 0x95A2 #define GL_MAX_TASK_WORK_GROUP_INVOCATIONS_NV 0x95A3 -#define GL_MAX_MESH_TOTAL_MEMORY_SIZE_NV 0x9536 -#define GL_MAX_TASK_TOTAL_MEMORY_SIZE_NV 0x9537 -#define GL_MAX_MESH_OUTPUT_VERTICES_NV 0x9538 -#define GL_MAX_MESH_OUTPUT_PRIMITIVES_NV 0x9539 -#define GL_MAX_TASK_OUTPUT_COUNT_NV 0x953A -#define GL_MAX_DRAW_MESH_TASKS_COUNT_NV 0x953D -#define GL_MAX_MESH_VIEWS_NV 0x9557 +#define GL_MAX_MESH_TOTAL_MEMORY_SIZE_NV 0x9536 +#define GL_MAX_TASK_TOTAL_MEMORY_SIZE_NV 0x9537 +#define GL_MAX_MESH_OUTPUT_VERTICES_NV 0x9538 +#define GL_MAX_MESH_OUTPUT_PRIMITIVES_NV 0x9539 +#define GL_MAX_TASK_OUTPUT_COUNT_NV 0x953A +#define GL_MAX_DRAW_MESH_TASKS_COUNT_NV 0x953D +#define GL_MAX_MESH_VIEWS_NV 0x9557 #define GL_MESH_OUTPUT_PER_VERTEX_GRANULARITY_NV 0x92DF #define GL_MESH_OUTPUT_PER_PRIMITIVE_GRANULARITY_NV 0x9543 -#define GL_MAX_MESH_WORK_GROUP_SIZE_NV 0x953B -#define GL_MAX_TASK_WORK_GROUP_SIZE_NV 0x953C -#define GL_MESH_WORK_GROUP_SIZE_NV 0x953E -#define GL_TASK_WORK_GROUP_SIZE_NV 0x953F -#define GL_MESH_VERTICES_OUT_NV 0x9579 -#define GL_MESH_PRIMITIVES_OUT_NV 0x957A -#define GL_MESH_OUTPUT_TYPE_NV 0x957B +#define GL_MAX_MESH_WORK_GROUP_SIZE_NV 0x953B +#define GL_MAX_TASK_WORK_GROUP_SIZE_NV 0x953C +#define GL_MESH_WORK_GROUP_SIZE_NV 0x953E +#define GL_TASK_WORK_GROUP_SIZE_NV 0x953F +#define GL_MESH_VERTICES_OUT_NV 0x9579 +#define GL_MESH_PRIMITIVES_OUT_NV 0x957A +#define GL_MESH_OUTPUT_TYPE_NV 0x957B #define GL_UNIFORM_BLOCK_REFERENCED_BY_MESH_SHADER_NV 0x959C #define GL_UNIFORM_BLOCK_REFERENCED_BY_TASK_SHADER_NV 0x959D -#define GL_REFERENCED_BY_MESH_SHADER_NV 0x95A0 -#define GL_REFERENCED_BY_TASK_SHADER_NV 0x95A1 -#define GL_MESH_SHADER_BIT_NV 0x00000040 -#define GL_TASK_SHADER_BIT_NV 0x00000080 -#define GL_MESH_SUBROUTINE_NV 0x957C -#define GL_TASK_SUBROUTINE_NV 0x957D -#define GL_MESH_SUBROUTINE_UNIFORM_NV 0x957E -#define GL_TASK_SUBROUTINE_UNIFORM_NV 0x957F +#define GL_REFERENCED_BY_MESH_SHADER_NV 0x95A0 +#define GL_REFERENCED_BY_TASK_SHADER_NV 0x95A1 +#define GL_MESH_SHADER_BIT_NV 0x00000040 +#define GL_TASK_SHADER_BIT_NV 0x00000080 +#define GL_MESH_SUBROUTINE_NV 0x957C +#define GL_TASK_SUBROUTINE_NV 0x957D +#define GL_MESH_SUBROUTINE_UNIFORM_NV 0x957E +#define GL_TASK_SUBROUTINE_UNIFORM_NV 0x957F #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_MESH_SHADER_NV 0x959E #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TASK_SHADER_NV 0x959F -typedef void (APIENTRYP PFNGLDRAWMESHTASKSNVPROC) (GLuint first, GLuint count); -typedef void (APIENTRYP PFNGLDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect); -typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect, GLsizei drawcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC) (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +typedef void(APIENTRYP PFNGLDRAWMESHTASKSNVPROC)(GLuint first, GLuint count); +typedef void(APIENTRYP PFNGLDRAWMESHTASKSINDIRECTNVPROC)(GLintptr indirect); +typedef void(APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC)(GLintptr indirect, GLsizei drawcount, GLsizei stride); +typedef void(APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC)(GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawMeshTasksNV (GLuint first, GLuint count); -GLAPI void APIENTRY glDrawMeshTasksIndirectNV (GLintptr indirect); -GLAPI void APIENTRY glMultiDrawMeshTasksIndirectNV (GLintptr indirect, GLsizei drawcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawMeshTasksIndirectCountNV (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glDrawMeshTasksNV(GLuint first, GLuint count); +GLAPI void APIENTRY glDrawMeshTasksIndirectNV(GLintptr indirect); +GLAPI void APIENTRY glMultiDrawMeshTasksIndirectNV(GLintptr indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawMeshTasksIndirectCountNV(GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); #endif #endif /* GL_NV_mesh_shader */ #ifndef GL_NV_path_rendering #define GL_NV_path_rendering 1 -#define GL_PATH_FORMAT_SVG_NV 0x9070 -#define GL_PATH_FORMAT_PS_NV 0x9071 -#define GL_STANDARD_FONT_NAME_NV 0x9072 -#define GL_SYSTEM_FONT_NAME_NV 0x9073 -#define GL_FILE_NAME_NV 0x9074 -#define GL_PATH_STROKE_WIDTH_NV 0x9075 -#define GL_PATH_END_CAPS_NV 0x9076 -#define GL_PATH_INITIAL_END_CAP_NV 0x9077 -#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 -#define GL_PATH_JOIN_STYLE_NV 0x9079 -#define GL_PATH_MITER_LIMIT_NV 0x907A -#define GL_PATH_DASH_CAPS_NV 0x907B -#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C -#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D -#define GL_PATH_DASH_OFFSET_NV 0x907E -#define GL_PATH_CLIENT_LENGTH_NV 0x907F -#define GL_PATH_FILL_MODE_NV 0x9080 -#define GL_PATH_FILL_MASK_NV 0x9081 -#define GL_PATH_FILL_COVER_MODE_NV 0x9082 -#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 -#define GL_PATH_STROKE_MASK_NV 0x9084 -#define GL_COUNT_UP_NV 0x9088 -#define GL_COUNT_DOWN_NV 0x9089 -#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A -#define GL_CONVEX_HULL_NV 0x908B -#define GL_BOUNDING_BOX_NV 0x908D -#define GL_TRANSLATE_X_NV 0x908E -#define GL_TRANSLATE_Y_NV 0x908F -#define GL_TRANSLATE_2D_NV 0x9090 -#define GL_TRANSLATE_3D_NV 0x9091 -#define GL_AFFINE_2D_NV 0x9092 -#define GL_AFFINE_3D_NV 0x9094 -#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 -#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 -#define GL_UTF8_NV 0x909A -#define GL_UTF16_NV 0x909B +#define GL_PATH_FORMAT_SVG_NV 0x9070 +#define GL_PATH_FORMAT_PS_NV 0x9071 +#define GL_STANDARD_FONT_NAME_NV 0x9072 +#define GL_SYSTEM_FONT_NAME_NV 0x9073 +#define GL_FILE_NAME_NV 0x9074 +#define GL_PATH_STROKE_WIDTH_NV 0x9075 +#define GL_PATH_END_CAPS_NV 0x9076 +#define GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define GL_PATH_JOIN_STYLE_NV 0x9079 +#define GL_PATH_MITER_LIMIT_NV 0x907A +#define GL_PATH_DASH_CAPS_NV 0x907B +#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define GL_PATH_DASH_OFFSET_NV 0x907E +#define GL_PATH_CLIENT_LENGTH_NV 0x907F +#define GL_PATH_FILL_MODE_NV 0x9080 +#define GL_PATH_FILL_MASK_NV 0x9081 +#define GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define GL_PATH_STROKE_MASK_NV 0x9084 +#define GL_COUNT_UP_NV 0x9088 +#define GL_COUNT_DOWN_NV 0x9089 +#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define GL_CONVEX_HULL_NV 0x908B +#define GL_BOUNDING_BOX_NV 0x908D +#define GL_TRANSLATE_X_NV 0x908E +#define GL_TRANSLATE_Y_NV 0x908F +#define GL_TRANSLATE_2D_NV 0x9090 +#define GL_TRANSLATE_3D_NV 0x9091 +#define GL_AFFINE_2D_NV 0x9092 +#define GL_AFFINE_3D_NV 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define GL_UTF8_NV 0x909A +#define GL_UTF16_NV 0x909B #define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C -#define GL_PATH_COMMAND_COUNT_NV 0x909D -#define GL_PATH_COORD_COUNT_NV 0x909E -#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F -#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 -#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 -#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 -#define GL_SQUARE_NV 0x90A3 -#define GL_ROUND_NV 0x90A4 -#define GL_TRIANGULAR_NV 0x90A5 -#define GL_BEVEL_NV 0x90A6 -#define GL_MITER_REVERT_NV 0x90A7 -#define GL_MITER_TRUNCATE_NV 0x90A8 -#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 -#define GL_USE_MISSING_GLYPH_NV 0x90AA -#define GL_PATH_ERROR_POSITION_NV 0x90AB -#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD -#define GL_ADJACENT_PAIRS_NV 0x90AE -#define GL_FIRST_TO_REST_NV 0x90AF -#define GL_PATH_GEN_MODE_NV 0x90B0 -#define GL_PATH_GEN_COEFF_NV 0x90B1 -#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 -#define GL_PATH_STENCIL_FUNC_NV 0x90B7 -#define GL_PATH_STENCIL_REF_NV 0x90B8 -#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define GL_PATH_COMMAND_COUNT_NV 0x909D +#define GL_PATH_COORD_COUNT_NV 0x909E +#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define GL_SQUARE_NV 0x90A3 +#define GL_ROUND_NV 0x90A4 +#define GL_TRIANGULAR_NV 0x90A5 +#define GL_BEVEL_NV 0x90A6 +#define GL_MITER_REVERT_NV 0x90A7 +#define GL_MITER_TRUNCATE_NV 0x90A8 +#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define GL_USE_MISSING_GLYPH_NV 0x90AA +#define GL_PATH_ERROR_POSITION_NV 0x90AB +#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define GL_ADJACENT_PAIRS_NV 0x90AE +#define GL_FIRST_TO_REST_NV 0x90AF +#define GL_PATH_GEN_MODE_NV 0x90B0 +#define GL_PATH_GEN_COEFF_NV 0x90B1 +#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define GL_PATH_STENCIL_REF_NV 0x90B8 +#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 #define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD #define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE -#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF -#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 -#define GL_MOVE_TO_RESETS_NV 0x90B5 -#define GL_MOVE_TO_CONTINUES_NV 0x90B6 -#define GL_CLOSE_PATH_NV 0x00 -#define GL_MOVE_TO_NV 0x02 -#define GL_RELATIVE_MOVE_TO_NV 0x03 -#define GL_LINE_TO_NV 0x04 -#define GL_RELATIVE_LINE_TO_NV 0x05 -#define GL_HORIZONTAL_LINE_TO_NV 0x06 +#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define GL_MOVE_TO_RESETS_NV 0x90B5 +#define GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define GL_CLOSE_PATH_NV 0x00 +#define GL_MOVE_TO_NV 0x02 +#define GL_RELATIVE_MOVE_TO_NV 0x03 +#define GL_LINE_TO_NV 0x04 +#define GL_RELATIVE_LINE_TO_NV 0x05 +#define GL_HORIZONTAL_LINE_TO_NV 0x06 #define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 -#define GL_VERTICAL_LINE_TO_NV 0x08 -#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 -#define GL_QUADRATIC_CURVE_TO_NV 0x0A +#define GL_VERTICAL_LINE_TO_NV 0x08 +#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define GL_QUADRATIC_CURVE_TO_NV 0x0A #define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B -#define GL_CUBIC_CURVE_TO_NV 0x0C -#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D -#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define GL_CUBIC_CURVE_TO_NV 0x0C +#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E #define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F -#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 #define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 -#define GL_SMALL_CCW_ARC_TO_NV 0x12 -#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 -#define GL_SMALL_CW_ARC_TO_NV 0x14 -#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 -#define GL_LARGE_CCW_ARC_TO_NV 0x16 -#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 -#define GL_LARGE_CW_ARC_TO_NV 0x18 -#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 -#define GL_RESTART_PATH_NV 0xF0 -#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 -#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 -#define GL_RECT_NV 0xF6 -#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 -#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA -#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC -#define GL_ARC_TO_NV 0xFE -#define GL_RELATIVE_ARC_TO_NV 0xFF -#define GL_BOLD_BIT_NV 0x01 -#define GL_ITALIC_BIT_NV 0x02 -#define GL_GLYPH_WIDTH_BIT_NV 0x01 -#define GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define GL_SMALL_CCW_ARC_TO_NV 0x12 +#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define GL_SMALL_CW_ARC_TO_NV 0x14 +#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define GL_LARGE_CCW_ARC_TO_NV 0x16 +#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define GL_LARGE_CW_ARC_TO_NV 0x18 +#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define GL_RESTART_PATH_NV 0xF0 +#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define GL_RECT_NV 0xF6 +#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define GL_ARC_TO_NV 0xFE +#define GL_RELATIVE_ARC_TO_NV 0xFF +#define GL_BOLD_BIT_NV 0x01 +#define GL_ITALIC_BIT_NV 0x02 +#define GL_GLYPH_WIDTH_BIT_NV 0x01 +#define GL_GLYPH_HEIGHT_BIT_NV 0x02 #define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 #define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 #define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 #define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 #define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 #define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 -#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 -#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 -#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 -#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 -#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 -#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 -#define GL_FONT_ASCENDER_BIT_NV 0x00200000 -#define GL_FONT_DESCENDER_BIT_NV 0x00400000 -#define GL_FONT_HEIGHT_BIT_NV 0x00800000 -#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 #define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 #define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 #define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 -#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 -#define GL_ROUNDED_RECT_NV 0xE8 -#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 -#define GL_ROUNDED_RECT2_NV 0xEA -#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB -#define GL_ROUNDED_RECT4_NV 0xEC -#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED -#define GL_ROUNDED_RECT8_NV 0xEE -#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF -#define GL_RELATIVE_RECT_NV 0xF7 -#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 -#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 -#define GL_FONT_UNAVAILABLE_NV 0x936A -#define GL_FONT_UNINTELLIGIBLE_NV 0x936B -#define GL_CONIC_CURVE_TO_NV 0x1A -#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B -#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 -#define GL_STANDARD_FONT_FORMAT_NV 0x936C -#define GL_PATH_PROJECTION_NV 0x1701 -#define GL_PATH_MODELVIEW_NV 0x1700 -#define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 -#define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 +#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define GL_ROUNDED_RECT_NV 0xE8 +#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 +#define GL_ROUNDED_RECT2_NV 0xEA +#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB +#define GL_ROUNDED_RECT4_NV 0xEC +#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED +#define GL_ROUNDED_RECT8_NV 0xEE +#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF +#define GL_RELATIVE_RECT_NV 0xF7 +#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 +#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 +#define GL_FONT_UNAVAILABLE_NV 0x936A +#define GL_FONT_UNINTELLIGIBLE_NV 0x936B +#define GL_CONIC_CURVE_TO_NV 0x1A +#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B +#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 +#define GL_STANDARD_FONT_FORMAT_NV 0x936C +#define GL_PATH_PROJECTION_NV 0x1701 +#define GL_PATH_MODELVIEW_NV 0x1700 +#define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 +#define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 #define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 #define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 #define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 -#define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 +#define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 #define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 #define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 -#define GL_FRAGMENT_INPUT_NV 0x936D -typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); -typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); -typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); -typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); -typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); -typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); -typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); -typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); -typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); -typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); -typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); -typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); -typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); -typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); -typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); -typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -typedef void (APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); -typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); -typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode); -typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); -typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef GLenum (APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); -typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLfloat *params); +#define GL_FRAGMENT_INPUT_NV 0x936D +typedef GLuint(APIENTRYP PFNGLGENPATHSNVPROC)(GLsizei range); +typedef void(APIENTRYP PFNGLDELETEPATHSNVPROC)(GLuint path, GLsizei range); +typedef GLboolean(APIENTRYP PFNGLISPATHNVPROC)(GLuint path); +typedef void(APIENTRYP PFNGLPATHCOMMANDSNVPROC)(GLuint path, GLsizei numCommands, const GLubyte* commands, GLsizei numCoords, + GLenum coordType, const void* coords); +typedef void(APIENTRYP PFNGLPATHCOORDSNVPROC)(GLuint path, GLsizei numCoords, GLenum coordType, const void* coords); +typedef void(APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC)(GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, + const GLubyte* commands, GLsizei numCoords, GLenum coordType, const void* coords); +typedef void(APIENTRYP PFNGLPATHSUBCOORDSNVPROC)(GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void* coords); +typedef void(APIENTRYP PFNGLPATHSTRINGNVPROC)(GLuint path, GLenum format, GLsizei length, const void* pathString); +typedef void(APIENTRYP PFNGLPATHGLYPHSNVPROC)(GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, + GLsizei numGlyphs, GLenum type, const void* charcodes, GLenum handleMissingGlyphs, + GLuint pathParameterTemplate, GLfloat emScale); +typedef void(APIENTRYP PFNGLPATHGLYPHRANGENVPROC)(GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, + GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, + GLuint pathParameterTemplate, GLfloat emScale); +typedef void(APIENTRYP PFNGLWEIGHTPATHSNVPROC)(GLuint resultPath, GLsizei numPaths, const GLuint* paths, const GLfloat* weights); +typedef void(APIENTRYP PFNGLCOPYPATHNVPROC)(GLuint resultPath, GLuint srcPath); +typedef void(APIENTRYP PFNGLINTERPOLATEPATHSNVPROC)(GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +typedef void(APIENTRYP PFNGLTRANSFORMPATHNVPROC)(GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat* transformValues); +typedef void(APIENTRYP PFNGLPATHPARAMETERIVNVPROC)(GLuint path, GLenum pname, const GLint* value); +typedef void(APIENTRYP PFNGLPATHPARAMETERINVPROC)(GLuint path, GLenum pname, GLint value); +typedef void(APIENTRYP PFNGLPATHPARAMETERFVNVPROC)(GLuint path, GLenum pname, const GLfloat* value); +typedef void(APIENTRYP PFNGLPATHPARAMETERFNVPROC)(GLuint path, GLenum pname, GLfloat value); +typedef void(APIENTRYP PFNGLPATHDASHARRAYNVPROC)(GLuint path, GLsizei dashCount, const GLfloat* dashArray); +typedef void(APIENTRYP PFNGLPATHSTENCILFUNCNVPROC)(GLenum func, GLint ref, GLuint mask); +typedef void(APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC)(GLfloat factor, GLfloat units); +typedef void(APIENTRYP PFNGLSTENCILFILLPATHNVPROC)(GLuint path, GLenum fillMode, GLuint mask); +typedef void(APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC)(GLuint path, GLint reference, GLuint mask); +typedef void(APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC)(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat* transformValues); +typedef void(APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC)(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLint reference, GLuint mask, GLenum transformType, const GLfloat* transformValues); +typedef void(APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC)(GLenum func); +typedef void(APIENTRYP PFNGLCOVERFILLPATHNVPROC)(GLuint path, GLenum coverMode); +typedef void(APIENTRYP PFNGLCOVERSTROKEPATHNVPROC)(GLuint path, GLenum coverMode); +typedef void(APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC)(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLenum coverMode, GLenum transformType, const GLfloat* transformValues); +typedef void(APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC)(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLenum coverMode, GLenum transformType, const GLfloat* transformValues); +typedef void(APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC)(GLuint path, GLenum pname, GLint* value); +typedef void(APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC)(GLuint path, GLenum pname, GLfloat* value); +typedef void(APIENTRYP PFNGLGETPATHCOMMANDSNVPROC)(GLuint path, GLubyte* commands); +typedef void(APIENTRYP PFNGLGETPATHCOORDSNVPROC)(GLuint path, GLfloat* coords); +typedef void(APIENTRYP PFNGLGETPATHDASHARRAYNVPROC)(GLuint path, GLfloat* dashArray); +typedef void(APIENTRYP PFNGLGETPATHMETRICSNVPROC)(GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void* paths, + GLuint pathBase, GLsizei stride, GLfloat* metrics); +typedef void(APIENTRYP PFNGLGETPATHMETRICRANGENVPROC)(GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, + GLfloat* metrics); +typedef void(APIENTRYP PFNGLGETPATHSPACINGNVPROC)(GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat* returnedSpacing); +typedef GLboolean(APIENTRYP PFNGLISPOINTINFILLPATHNVPROC)(GLuint path, GLuint mask, GLfloat x, GLfloat y); +typedef GLboolean(APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC)(GLuint path, GLfloat x, GLfloat y); +typedef GLfloat(APIENTRYP PFNGLGETPATHLENGTHNVPROC)(GLuint path, GLsizei startSegment, GLsizei numSegments); +typedef GLboolean(APIENTRYP PFNGLPOINTALONGPATHNVPROC)(GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat* x, + GLfloat* y, GLfloat* tangentX, GLfloat* tangentY); +typedef void(APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC)(GLenum matrixMode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC)(GLenum matrixMode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC)(GLenum matrixMode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXMULT3X2FNVPROC)(GLenum matrixMode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXMULT3X3FNVPROC)(GLenum matrixMode, const GLfloat* m); +typedef void(APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC)(GLenum matrixMode, const GLfloat* m); +typedef void(APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC)(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +typedef void(APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC)(GLuint path, GLint reference, GLuint mask, GLenum coverMode); +typedef void(APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC)(GLsizei numPaths, GLenum pathNameType, const void* paths, + GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, + GLenum transformType, const GLfloat* transformValues); +typedef void(APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC)(GLsizei numPaths, GLenum pathNameType, const void* paths, + GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, + GLenum transformType, const GLfloat* transformValues); +typedef GLenum(APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC)(GLenum fontTarget, const void* fontName, GLbitfield fontStyle, + GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); +typedef GLenum(APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC)(GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, + GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef GLenum(APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC)(GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, + const void* fontData, GLsizei faceIndex, GLuint firstGlyphIndex, + GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void(APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC)(GLuint program, GLint location, GLenum genMode, GLint components, + const GLfloat* coeffs); +typedef void(APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, + const GLenum* props, GLsizei count, GLsizei* length, GLfloat* params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); -GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); -GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); -GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); -GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString); -GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); -GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); -GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); -GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); -GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); -GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); -GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); -GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); -GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); -GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); -GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); -GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); -GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); -GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); -GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); -GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); -GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -GLAPI void APIENTRY glMatrixLoad3x2fNV (GLenum matrixMode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoad3x3fNV (GLenum matrixMode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoadTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMult3x2fNV (GLenum matrixMode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMult3x3fNV (GLenum matrixMode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); -GLAPI void APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); -GLAPI void APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode); -GLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); -GLAPI GLenum APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); -GLAPI void APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLfloat *params); +GLAPI GLuint APIENTRY glGenPathsNV(GLsizei range); +GLAPI void APIENTRY glDeletePathsNV(GLuint path, GLsizei range); +GLAPI GLboolean APIENTRY glIsPathNV(GLuint path); +GLAPI void APIENTRY glPathCommandsNV(GLuint path, GLsizei numCommands, const GLubyte* commands, GLsizei numCoords, GLenum coordType, + const void* coords); +GLAPI void APIENTRY glPathCoordsNV(GLuint path, GLsizei numCoords, GLenum coordType, const void* coords); +GLAPI void APIENTRY glPathSubCommandsNV(GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, + const GLubyte* commands, GLsizei numCoords, GLenum coordType, const void* coords); +GLAPI void APIENTRY glPathSubCoordsNV(GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void* coords); +GLAPI void APIENTRY glPathStringNV(GLuint path, GLenum format, GLsizei length, const void* pathString); +GLAPI void APIENTRY glPathGlyphsNV(GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, GLsizei numGlyphs, + GLenum type, const void* charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glPathGlyphRangeNV(GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, GLuint firstGlyph, + GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glWeightPathsNV(GLuint resultPath, GLsizei numPaths, const GLuint* paths, const GLfloat* weights); +GLAPI void APIENTRY glCopyPathNV(GLuint resultPath, GLuint srcPath); +GLAPI void APIENTRY glInterpolatePathsNV(GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +GLAPI void APIENTRY glTransformPathNV(GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat* transformValues); +GLAPI void APIENTRY glPathParameterivNV(GLuint path, GLenum pname, const GLint* value); +GLAPI void APIENTRY glPathParameteriNV(GLuint path, GLenum pname, GLint value); +GLAPI void APIENTRY glPathParameterfvNV(GLuint path, GLenum pname, const GLfloat* value); +GLAPI void APIENTRY glPathParameterfNV(GLuint path, GLenum pname, GLfloat value); +GLAPI void APIENTRY glPathDashArrayNV(GLuint path, GLsizei dashCount, const GLfloat* dashArray); +GLAPI void APIENTRY glPathStencilFuncNV(GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glPathStencilDepthOffsetNV(GLfloat factor, GLfloat units); +GLAPI void APIENTRY glStencilFillPathNV(GLuint path, GLenum fillMode, GLuint mask); +GLAPI void APIENTRY glStencilStrokePathNV(GLuint path, GLint reference, GLuint mask); +GLAPI void APIENTRY glStencilFillPathInstancedNV(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum fillMode, + GLuint mask, GLenum transformType, const GLfloat* transformValues); +GLAPI void APIENTRY glStencilStrokePathInstancedNV(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLint reference, GLuint mask, GLenum transformType, const GLfloat* transformValues); +GLAPI void APIENTRY glPathCoverDepthFuncNV(GLenum func); +GLAPI void APIENTRY glCoverFillPathNV(GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverStrokePathNV(GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverFillPathInstancedNV(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum coverMode, + GLenum transformType, const GLfloat* transformValues); +GLAPI void APIENTRY glCoverStrokePathInstancedNV(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLenum coverMode, GLenum transformType, const GLfloat* transformValues); +GLAPI void APIENTRY glGetPathParameterivNV(GLuint path, GLenum pname, GLint* value); +GLAPI void APIENTRY glGetPathParameterfvNV(GLuint path, GLenum pname, GLfloat* value); +GLAPI void APIENTRY glGetPathCommandsNV(GLuint path, GLubyte* commands); +GLAPI void APIENTRY glGetPathCoordsNV(GLuint path, GLfloat* coords); +GLAPI void APIENTRY glGetPathDashArrayNV(GLuint path, GLfloat* dashArray); +GLAPI void APIENTRY glGetPathMetricsNV(GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void* paths, + GLuint pathBase, GLsizei stride, GLfloat* metrics); +GLAPI void APIENTRY glGetPathMetricRangeNV(GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat* metrics); +GLAPI void APIENTRY glGetPathSpacingNV(GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat* returnedSpacing); +GLAPI GLboolean APIENTRY glIsPointInFillPathNV(GLuint path, GLuint mask, GLfloat x, GLfloat y); +GLAPI GLboolean APIENTRY glIsPointInStrokePathNV(GLuint path, GLfloat x, GLfloat y); +GLAPI GLfloat APIENTRY glGetPathLengthNV(GLuint path, GLsizei startSegment, GLsizei numSegments); +GLAPI GLboolean APIENTRY glPointAlongPathNV(GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat* x, + GLfloat* y, GLfloat* tangentX, GLfloat* tangentY); +GLAPI void APIENTRY glMatrixLoad3x2fNV(GLenum matrixMode, const GLfloat* m); +GLAPI void APIENTRY glMatrixLoad3x3fNV(GLenum matrixMode, const GLfloat* m); +GLAPI void APIENTRY glMatrixLoadTranspose3x3fNV(GLenum matrixMode, const GLfloat* m); +GLAPI void APIENTRY glMatrixMult3x2fNV(GLenum matrixMode, const GLfloat* m); +GLAPI void APIENTRY glMatrixMult3x3fNV(GLenum matrixMode, const GLfloat* m); +GLAPI void APIENTRY glMatrixMultTranspose3x3fNV(GLenum matrixMode, const GLfloat* m); +GLAPI void APIENTRY glStencilThenCoverFillPathNV(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +GLAPI void APIENTRY glStencilThenCoverStrokePathNV(GLuint path, GLint reference, GLuint mask, GLenum coverMode); +GLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, + const GLfloat* transformValues); +GLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV(GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, + GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, + const GLfloat* transformValues); +GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV(GLenum fontTarget, const void* fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, + GLfloat emScale, GLuint baseAndCount[2]); +GLAPI GLenum APIENTRY glPathGlyphIndexArrayNV(GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, + GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV(GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void* fontData, + GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, + GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glProgramPathFragmentInputGenNV(GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat* coeffs); +GLAPI void APIENTRY glGetProgramResourcefvNV(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum* props, + GLsizei count, GLsizei* length, GLfloat* params); #endif #endif /* GL_NV_path_rendering */ #ifndef GL_NV_path_rendering_shared_edge #define GL_NV_path_rendering_shared_edge 1 -#define GL_SHARED_EDGE_NV 0xC0 +#define GL_SHARED_EDGE_NV 0xC0 #endif /* GL_NV_path_rendering_shared_edge */ #ifndef GL_NV_representative_fragment_test @@ -5628,17 +5979,17 @@ GLAPI void APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInte #define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E #define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F #define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340 -#define GL_SAMPLE_LOCATION_NV 0x8E50 +#define GL_SAMPLE_LOCATION_NV 0x8E50 #define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341 #define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342 #define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343 -typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLRESOLVEDEPTHVALUESNVPROC) (void); +typedef void(APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)(GLenum target, GLuint start, GLsizei count, const GLfloat* v); +typedef void(APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v); +typedef void(APIENTRYP PFNGLRESOLVEDEPTHVALUESNVPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFramebufferSampleLocationsfvNV (GLenum target, GLuint start, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvNV (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glResolveDepthValuesNV (void); +GLAPI void APIENTRY glFramebufferSampleLocationsfvNV(GLenum target, GLuint start, GLsizei count, const GLfloat* v); +GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvNV(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v); +GLAPI void APIENTRY glResolveDepthValuesNV(void); #endif #endif /* GL_NV_sample_locations */ @@ -5648,13 +5999,13 @@ GLAPI void APIENTRY glResolveDepthValuesNV (void); #ifndef GL_NV_scissor_exclusive #define GL_NV_scissor_exclusive 1 -#define GL_SCISSOR_TEST_EXCLUSIVE_NV 0x9555 -#define GL_SCISSOR_BOX_EXCLUSIVE_NV 0x9556 -typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVENVPROC) (GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVEARRAYVNVPROC) (GLuint first, GLsizei count, const GLint *v); +#define GL_SCISSOR_TEST_EXCLUSIVE_NV 0x9555 +#define GL_SCISSOR_BOX_EXCLUSIVE_NV 0x9556 +typedef void(APIENTRYP PFNGLSCISSOREXCLUSIVENVPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNGLSCISSOREXCLUSIVEARRAYVNVPROC)(GLuint first, GLsizei count, const GLint* v); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glScissorExclusiveNV (GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glScissorExclusiveArrayvNV (GLuint first, GLsizei count, const GLint *v); +GLAPI void APIENTRY glScissorExclusiveNV(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glScissorExclusiveArrayvNV(GLuint first, GLsizei count, const GLint* v); #endif #endif /* GL_NV_scissor_exclusive */ @@ -5680,38 +6031,38 @@ GLAPI void APIENTRY glScissorExclusiveArrayvNV (GLuint first, GLsizei count, con #ifndef GL_NV_shader_buffer_load #define GL_NV_shader_buffer_load 1 -#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D -#define GL_GPU_ADDRESS_NV 0x8F34 -#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 -typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); -typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); -typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); -typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); -typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D +#define GL_GPU_ADDRESS_NV 0x8F34 +#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 +typedef void(APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC)(GLenum target, GLenum access); +typedef void(APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC)(GLenum target); +typedef GLboolean(APIENTRYP PFNGLISBUFFERRESIDENTNVPROC)(GLenum target); +typedef void(APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC)(GLuint buffer, GLenum access); +typedef void(APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC)(GLuint buffer); +typedef GLboolean(APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC)(GLuint buffer); +typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC)(GLenum target, GLenum pname, GLuint64EXT* params); +typedef void(APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC)(GLuint buffer, GLenum pname, GLuint64EXT* params); +typedef void(APIENTRYP PFNGLGETINTEGERUI64VNVPROC)(GLenum value, GLuint64EXT* result); +typedef void(APIENTRYP PFNGLUNIFORMUI64NVPROC)(GLint location, GLuint64EXT value); +typedef void(APIENTRYP PFNGLUNIFORMUI64VNVPROC)(GLint location, GLsizei count, const GLuint64EXT* value); +typedef void(APIENTRYP PFNGLGETUNIFORMUI64VNVPROC)(GLuint program, GLint location, GLuint64EXT* params); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC)(GLuint program, GLint location, GLuint64EXT value); +typedef void(APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC)(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); -GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); -GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); -GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); -GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); -GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); -GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); -GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); -GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); -GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); -GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glMakeBufferResidentNV(GLenum target, GLenum access); +GLAPI void APIENTRY glMakeBufferNonResidentNV(GLenum target); +GLAPI GLboolean APIENTRY glIsBufferResidentNV(GLenum target); +GLAPI void APIENTRY glMakeNamedBufferResidentNV(GLuint buffer, GLenum access); +GLAPI void APIENTRY glMakeNamedBufferNonResidentNV(GLuint buffer); +GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV(GLuint buffer); +GLAPI void APIENTRY glGetBufferParameterui64vNV(GLenum target, GLenum pname, GLuint64EXT* params); +GLAPI void APIENTRY glGetNamedBufferParameterui64vNV(GLuint buffer, GLenum pname, GLuint64EXT* params); +GLAPI void APIENTRY glGetIntegerui64vNV(GLenum value, GLuint64EXT* result); +GLAPI void APIENTRY glUniformui64NV(GLint location, GLuint64EXT value); +GLAPI void APIENTRY glUniformui64vNV(GLint location, GLsizei count, const GLuint64EXT* value); +GLAPI void APIENTRY glGetUniformui64vNV(GLuint program, GLint location, GLuint64EXT* params); +GLAPI void APIENTRY glProgramUniformui64NV(GLuint program, GLint location, GLuint64EXT value); +GLAPI void APIENTRY glProgramUniformui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value); #endif #endif /* GL_NV_shader_buffer_load */ @@ -5731,9 +6082,9 @@ GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLs #ifndef GL_NV_shader_thread_group #define GL_NV_shader_thread_group 1 -#define GL_WARP_SIZE_NV 0x9339 -#define GL_WARPS_PER_SM_NV 0x933A -#define GL_SM_COUNT_NV 0x933B +#define GL_WARP_SIZE_NV 0x9339 +#define GL_WARPS_PER_SM_NV 0x933A +#define GL_SM_COUNT_NV 0x933B #endif /* GL_NV_shader_thread_group */ #ifndef GL_NV_shader_thread_shuffle @@ -5742,7 +6093,7 @@ GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLs #ifndef GL_NV_shading_rate_image #define GL_NV_shading_rate_image 1 -#define GL_SHADING_RATE_IMAGE_NV 0x9563 +#define GL_SHADING_RATE_IMAGE_NV 0x9563 #define GL_SHADING_RATE_NO_INVOCATIONS_NV 0x9564 #define GL_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV 0x9565 #define GL_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV 0x9566 @@ -5755,7 +6106,7 @@ GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLs #define GL_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV 0x956D #define GL_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV 0x956E #define GL_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV 0x956F -#define GL_SHADING_RATE_IMAGE_BINDING_NV 0x955B +#define GL_SHADING_RATE_IMAGE_BINDING_NV 0x955B #define GL_SHADING_RATE_IMAGE_TEXEL_WIDTH_NV 0x955C #define GL_SHADING_RATE_IMAGE_TEXEL_HEIGHT_NV 0x955D #define GL_SHADING_RATE_IMAGE_PALETTE_SIZE_NV 0x955E @@ -5763,21 +6114,21 @@ GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLs #define GL_SHADING_RATE_SAMPLE_ORDER_DEFAULT_NV 0x95AE #define GL_SHADING_RATE_SAMPLE_ORDER_PIXEL_MAJOR_NV 0x95AF #define GL_SHADING_RATE_SAMPLE_ORDER_SAMPLE_MAJOR_NV 0x95B0 -typedef void (APIENTRYP PFNGLBINDSHADINGRATEIMAGENVPROC) (GLuint texture); -typedef void (APIENTRYP PFNGLGETSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint entry, GLenum *rate); -typedef void (APIENTRYP PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC) (GLenum rate, GLuint samples, GLuint index, GLint *location); -typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEBARRIERNVPROC) (GLboolean synchronize); -typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates); -typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERNVPROC) (GLenum order); -typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC) (GLenum rate, GLuint samples, const GLint *locations); +typedef void(APIENTRYP PFNGLBINDSHADINGRATEIMAGENVPROC)(GLuint texture); +typedef void(APIENTRYP PFNGLGETSHADINGRATEIMAGEPALETTENVPROC)(GLuint viewport, GLuint entry, GLenum* rate); +typedef void(APIENTRYP PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC)(GLenum rate, GLuint samples, GLuint index, GLint* location); +typedef void(APIENTRYP PFNGLSHADINGRATEIMAGEBARRIERNVPROC)(GLboolean synchronize); +typedef void(APIENTRYP PFNGLSHADINGRATEIMAGEPALETTENVPROC)(GLuint viewport, GLuint first, GLsizei count, const GLenum* rates); +typedef void(APIENTRYP PFNGLSHADINGRATESAMPLEORDERNVPROC)(GLenum order); +typedef void(APIENTRYP PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC)(GLenum rate, GLuint samples, const GLint* locations); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindShadingRateImageNV (GLuint texture); -GLAPI void APIENTRY glGetShadingRateImagePaletteNV (GLuint viewport, GLuint entry, GLenum *rate); -GLAPI void APIENTRY glGetShadingRateSampleLocationivNV (GLenum rate, GLuint samples, GLuint index, GLint *location); -GLAPI void APIENTRY glShadingRateImageBarrierNV (GLboolean synchronize); -GLAPI void APIENTRY glShadingRateImagePaletteNV (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates); -GLAPI void APIENTRY glShadingRateSampleOrderNV (GLenum order); -GLAPI void APIENTRY glShadingRateSampleOrderCustomNV (GLenum rate, GLuint samples, const GLint *locations); +GLAPI void APIENTRY glBindShadingRateImageNV(GLuint texture); +GLAPI void APIENTRY glGetShadingRateImagePaletteNV(GLuint viewport, GLuint entry, GLenum* rate); +GLAPI void APIENTRY glGetShadingRateSampleLocationivNV(GLenum rate, GLuint samples, GLuint index, GLint* location); +GLAPI void APIENTRY glShadingRateImageBarrierNV(GLboolean synchronize); +GLAPI void APIENTRY glShadingRateImagePaletteNV(GLuint viewport, GLuint first, GLsizei count, const GLenum* rates); +GLAPI void APIENTRY glShadingRateSampleOrderNV(GLenum order); +GLAPI void APIENTRY glShadingRateSampleOrderCustomNV(GLenum rate, GLuint samples, const GLint* locations); #endif #endif /* GL_NV_shading_rate_image */ @@ -5787,9 +6138,9 @@ GLAPI void APIENTRY glShadingRateSampleOrderCustomNV (GLenum rate, GLuint sample #ifndef GL_NV_texture_barrier #define GL_NV_texture_barrier 1 -typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); +typedef void(APIENTRYP PFNGLTEXTUREBARRIERNVPROC)(void); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureBarrierNV (void); +GLAPI void APIENTRY glTextureBarrierNV(void); #endif #endif /* GL_NV_texture_barrier */ @@ -5799,107 +6150,107 @@ GLAPI void APIENTRY glTextureBarrierNV (void); #ifndef GL_NV_uniform_buffer_unified_memory #define GL_NV_uniform_buffer_unified_memory 1 -#define GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E -#define GL_UNIFORM_BUFFER_ADDRESS_NV 0x936F -#define GL_UNIFORM_BUFFER_LENGTH_NV 0x9370 +#define GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E +#define GL_UNIFORM_BUFFER_ADDRESS_NV 0x936F +#define GL_UNIFORM_BUFFER_LENGTH_NV 0x9370 #endif /* GL_NV_uniform_buffer_unified_memory */ #ifndef GL_NV_vertex_attrib_integer_64bit #define GL_NV_vertex_attrib_integer_64bit 1 -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC)(GLuint index, GLint64EXT x); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC)(GLuint index, GLint64EXT x, GLint64EXT y); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC)(GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC)(GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC)(GLuint index, const GLint64EXT* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC)(GLuint index, const GLint64EXT* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC)(GLuint index, const GLint64EXT* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC)(GLuint index, const GLint64EXT* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC)(GLuint index, GLuint64EXT x); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC)(GLuint index, GLuint64EXT x, GLuint64EXT y); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC)(GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC)(GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC)(GLuint index, const GLuint64EXT* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC)(GLuint index, const GLuint64EXT* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC)(GLuint index, const GLuint64EXT* v); +typedef void(APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC)(GLuint index, const GLuint64EXT* v); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC)(GLuint index, GLenum pname, GLint64EXT* params); +typedef void(APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC)(GLuint index, GLenum pname, GLuint64EXT* params); +typedef void(APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC)(GLuint index, GLint size, GLenum type, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); -GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); -GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glVertexAttribL1i64NV(GLuint index, GLint64EXT x); +GLAPI void APIENTRY glVertexAttribL2i64NV(GLuint index, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glVertexAttribL3i64NV(GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glVertexAttribL4i64NV(GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glVertexAttribL1i64vNV(GLuint index, const GLint64EXT* v); +GLAPI void APIENTRY glVertexAttribL2i64vNV(GLuint index, const GLint64EXT* v); +GLAPI void APIENTRY glVertexAttribL3i64vNV(GLuint index, const GLint64EXT* v); +GLAPI void APIENTRY glVertexAttribL4i64vNV(GLuint index, const GLint64EXT* v); +GLAPI void APIENTRY glVertexAttribL1ui64NV(GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL2ui64NV(GLuint index, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glVertexAttribL3ui64NV(GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glVertexAttribL4ui64NV(GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glVertexAttribL1ui64vNV(GLuint index, const GLuint64EXT* v); +GLAPI void APIENTRY glVertexAttribL2ui64vNV(GLuint index, const GLuint64EXT* v); +GLAPI void APIENTRY glVertexAttribL3ui64vNV(GLuint index, const GLuint64EXT* v); +GLAPI void APIENTRY glVertexAttribL4ui64vNV(GLuint index, const GLuint64EXT* v); +GLAPI void APIENTRY glGetVertexAttribLi64vNV(GLuint index, GLenum pname, GLint64EXT* params); +GLAPI void APIENTRY glGetVertexAttribLui64vNV(GLuint index, GLenum pname, GLuint64EXT* params); +GLAPI void APIENTRY glVertexAttribLFormatNV(GLuint index, GLint size, GLenum type, GLsizei stride); #endif #endif /* GL_NV_vertex_attrib_integer_64bit */ #ifndef GL_NV_vertex_buffer_unified_memory #define GL_NV_vertex_buffer_unified_memory 1 #define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E -#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F +#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F #define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 -#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 -#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 -#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 -#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 +#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 +#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 +#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 +#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 #define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 -#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 +#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 #define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 -#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 -#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 -#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A -#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B -#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C -#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D -#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E -#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F -#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 +#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 +#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 +#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A +#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B +#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C +#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D +#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E +#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F +#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 #define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 -#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 -#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 -#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 -#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 -#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 -typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); +#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 +#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 +#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 +#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 +#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 +typedef void(APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC)(GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +typedef void(APIENTRYP PFNGLVERTEXFORMATNVPROC)(GLint size, GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLNORMALFORMATNVPROC)(GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLCOLORFORMATNVPROC)(GLint size, GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLINDEXFORMATNVPROC)(GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLTEXCOORDFORMATNVPROC)(GLint size, GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLEDGEFLAGFORMATNVPROC)(GLsizei stride); +typedef void(APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC)(GLint size, GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLFOGCOORDFORMATNVPROC)(GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +typedef void(APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC)(GLuint index, GLint size, GLenum type, GLsizei stride); +typedef void(APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC)(GLenum value, GLuint index, GLuint64EXT* result); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); -GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); +GLAPI void APIENTRY glBufferAddressRangeNV(GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +GLAPI void APIENTRY glVertexFormatNV(GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glNormalFormatNV(GLenum type, GLsizei stride); +GLAPI void APIENTRY glColorFormatNV(GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glIndexFormatNV(GLenum type, GLsizei stride); +GLAPI void APIENTRY glTexCoordFormatNV(GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glEdgeFlagFormatNV(GLsizei stride); +GLAPI void APIENTRY glSecondaryColorFormatNV(GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glFogCoordFormatNV(GLenum type, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormatNV(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +GLAPI void APIENTRY glVertexAttribIFormatNV(GLuint index, GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glGetIntegerui64i_vNV(GLenum value, GLuint index, GLuint64EXT* result); #endif #endif /* GL_NV_vertex_buffer_unified_memory */ @@ -5917,13 +6268,13 @@ GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64E #define GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355 #define GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356 #define GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357 -#define GL_VIEWPORT_SWIZZLE_X_NV 0x9358 -#define GL_VIEWPORT_SWIZZLE_Y_NV 0x9359 -#define GL_VIEWPORT_SWIZZLE_Z_NV 0x935A -#define GL_VIEWPORT_SWIZZLE_W_NV 0x935B -typedef void (APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC) (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); +#define GL_VIEWPORT_SWIZZLE_X_NV 0x9358 +#define GL_VIEWPORT_SWIZZLE_Y_NV 0x9359 +#define GL_VIEWPORT_SWIZZLE_Z_NV 0x935A +#define GL_VIEWPORT_SWIZZLE_W_NV 0x935B +typedef void(APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC)(GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); +GLAPI void APIENTRY glViewportSwizzleNV(GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); #endif #endif /* GL_NV_viewport_swizzle */ @@ -5931,11 +6282,13 @@ GLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum s #define GL_OVR_multiview 1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 -#define GL_MAX_VIEWS_OVR 0x9631 +#define GL_MAX_VIEWS_OVR 0x9631 #define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633 -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); +typedef void(APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, + GLint baseViewIndex, GLsizei numViews); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); +GLAPI void APIENTRY glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, + GLsizei numViews); #endif #endif /* GL_OVR_multiview */ diff --git a/ThunkLibs/libGL/libGL_Guest.cpp b/ThunkLibs/libGL/libGL_Guest.cpp index 8c21af541..3d09be3f7 100644 --- a/ThunkLibs/libGL/libGL_Guest.cpp +++ b/ThunkLibs/libGL/libGL_Guest.cpp @@ -30,48 +30,46 @@ typedef void voidFunc(); // Maps OpenGL API function names to the address of a guest function which is // linked to the corresponding host function pointer -const std::unordered_map HostPtrInvokers = - std::invoke([]() { +const std::unordered_map HostPtrInvokers = std::invoke([]() { #define PAIR(name, unused) Ret[#name] = reinterpret_cast(GetCallerForHostFunction(name)); - std::unordered_map Ret; - FOREACH_internal_SYMBOL(PAIR); - return Ret; + std::unordered_map Ret; + FOREACH_internal_SYMBOL(PAIR); + return Ret; #undef PAIR - }); +}); extern "C" { - voidFunc *glXGetProcAddress(const GLubyte *procname) { - auto Ret = fexfn_pack_glXGetProcAddress(procname); - if (!Ret) { - return nullptr; - } - - auto TargetFuncIt = HostPtrInvokers.find(reinterpret_cast(procname)); - if (TargetFuncIt == HostPtrInvokers.end()) { - std::string_view procname_s { reinterpret_cast(procname) }; - // If glXGetProcAddress is querying itself, then we can just return itself. - // Some games do this for unknown reasons. - if (procname_s == "glXGetProcAddress" || - procname_s == "glXGetProcAddressARB") { - return reinterpret_cast(glXGetProcAddress); - } - - // Extension found in host but not in our interface definition => Not fatal but warn about it - // Some games query leaked GLES symbols but don't use them - // glFrustrumf : ES 1.x function - // - Papers, Please - // - Dicey Dungeons - fprintf(stderr, "glXGetProcAddress: not found %s\n", procname); - return nullptr; - } - - LinkAddressToFunction((uintptr_t)Ret, TargetFuncIt->second); - return Ret; +voidFunc* glXGetProcAddress(const GLubyte* procname) { + auto Ret = fexfn_pack_glXGetProcAddress(procname); + if (!Ret) { + return nullptr; } - voidFunc *glXGetProcAddressARB(const GLubyte *procname) { - return glXGetProcAddress(procname); + auto TargetFuncIt = HostPtrInvokers.find(reinterpret_cast(procname)); + if (TargetFuncIt == HostPtrInvokers.end()) { + std::string_view procname_s {reinterpret_cast(procname)}; + // If glXGetProcAddress is querying itself, then we can just return itself. + // Some games do this for unknown reasons. + if (procname_s == "glXGetProcAddress" || procname_s == "glXGetProcAddressARB") { + return reinterpret_cast(glXGetProcAddress); + } + + // Extension found in host but not in our interface definition => Not fatal but warn about it + // Some games query leaked GLES symbols but don't use them + // glFrustrumf : ES 1.x function + // - Papers, Please + // - Dicey Dungeons + fprintf(stderr, "glXGetProcAddress: not found %s\n", procname); + return nullptr; } + + LinkAddressToFunction((uintptr_t)Ret, TargetFuncIt->second); + return Ret; +} + +voidFunc* glXGetProcAddressARB(const GLubyte* procname) { + return glXGetProcAddress(procname); +} } // libGL.so must pull in libX11.so as a dependency. Referencing some libX11 diff --git a/ThunkLibs/libGL/libGL_Host.cpp b/ThunkLibs/libGL/libGL_Host.cpp index a35f4bb33..aad50da4a 100644 --- a/ThunkLibs/libGL/libGL_Host.cpp +++ b/ThunkLibs/libGL/libGL_Host.cpp @@ -25,7 +25,7 @@ $end_info$ #include "thunkgen_host_libGL.inl" void* symbolFromGlXGetProcAddr(void*, const char* name) { - return (void*)glXGetProcAddress((const GLubyte*)name); + return (void*)glXGetProcAddress((const GLubyte*)name); } EXPORTS(libGL) diff --git a/ThunkLibs/libGL/libGL_interface.cpp b/ThunkLibs/libGL/libGL_interface.cpp index d05c0cbab..856dc2b26 100644 --- a/ThunkLibs/libGL/libGL_interface.cpp +++ b/ThunkLibs/libGL/libGL_interface.cpp @@ -15,3146 +15,6255 @@ template struct fex_gen_config { - unsigned version = 1; + unsigned version = 1; }; -template<> struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::returns_guest_pointer {}; +template<> +struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::returns_guest_pointer {}; template struct fex_gen_type {}; -template<> struct fex_gen_type> : fexgen::opaque_type {}; -template<> struct fex_gen_type> : fexgen::opaque_type {}; -template<> struct fex_gen_type> : fexgen::opaque_type {}; +template<> +struct fex_gen_type> : fexgen::opaque_type {}; +template<> +struct fex_gen_type> : fexgen::opaque_type {}; +template<> +struct fex_gen_type> : fexgen::opaque_type {}; // NOTE: These should be opaque, but actually aren't because the respective libraries aren't thunked -template<> struct fex_gen_type<_cl_context> : fexgen::opaque_type {}; -template<> struct fex_gen_type<_cl_event> : fexgen::opaque_type {}; +template<> +struct fex_gen_type<_cl_context> : fexgen::opaque_type {}; +template<> +struct fex_gen_type<_cl_event> : fexgen::opaque_type {}; // Opaque for the purpose of libGL -template<> struct fex_gen_type<_XDisplay> : fexgen::opaque_type {}; +template<> +struct fex_gen_type<_XDisplay> : fexgen::opaque_type {}; #ifndef IS_32BIT_THUNK // TODO: These are largely compatible, *but* contain function pointer members that need adjustment! -template<> struct fex_gen_type : fexgen::assume_compatible_data_layout {}; +template<> +struct fex_gen_type : fexgen::assume_compatible_data_layout {}; #endif // Symbols queryable through glXGetProcAddr namespace internal { template -struct fex_gen_config : fexgen::generate_guest_symtable, fexgen::indirect_guest_calls { -}; +struct fex_gen_config : fexgen::generate_guest_symtable, fexgen::indirect_guest_calls {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; -//template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; +// template<> struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config : fexgen::callback_stub {}; -template<> struct fex_gen_config : fexgen::callback_stub {}; -template<> struct fex_gen_config : fexgen::callback_stub {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config : fexgen::callback_stub {}; +template<> +struct fex_gen_config : fexgen::callback_stub {}; +template<> +struct fex_gen_config : fexgen::callback_stub {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; // GLext.h -//template<> struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::returns_guest_pointer{}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; +// template<> struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::returns_guest_pointer{}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; // glx.h -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; // glxext.h -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; -template<> struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; +template<> +struct fex_gen_config {}; } // namespace internal diff --git a/ThunkLibs/libSDL2/libSDL2_Guest.cpp b/ThunkLibs/libSDL2/libSDL2_Guest.cpp index 788a8d1ad..da362ea64 100644 --- a/ThunkLibs/libSDL2/libSDL2_Guest.cpp +++ b/ThunkLibs/libSDL2/libSDL2_Guest.cpp @@ -28,44 +28,72 @@ LOAD_LIB(libSDL2) struct __va_list_tag; -int SDL_snprintf(char*, size_t, const char*, ...) { return printf("SDL2: SDL_snprintf\n"); } -int SDL_sscanf(const char*, const char*, ...) { return printf("SDL2: SDL_sscanf\n"); } -void SDL_Log(const char*, ...) { printf("SDL2: SDL_Log\n"); } -void SDL_LogCritical(int, const char*, ...) { printf("SDL2: SDL_LogCritical\n"); } -void SDL_LogDebug(int, const char*, ...) { printf("SDL2: SDL_LogDebug\n"); } -void SDL_LogError(int, const char*, ...) { printf("SDL2: SDL_LogError\n"); } -void SDL_LogInfo(int, const char*, ...) { printf("SDL2: SDL_LogInfo\n"); } -void SDL_LogMessage(int, SDL_LogPriority, const char*, ...) { printf("SDL2: SDL_LogMessage\n"); } -void SDL_LogVerbose(int, const char*, ...) { printf("SDL2: SDL_LogVerbose\n"); } -void SDL_LogWarn(int, const char*, ...) { printf("SDL2: SDL_LogWarn\n"); } -int SDL_SetError(const char*, ...) { return printf("SDL2: SDL_SetError\n"); } +int SDL_snprintf(char*, size_t, const char*, ...) { + return printf("SDL2: SDL_snprintf\n"); +} +int SDL_sscanf(const char*, const char*, ...) { + return printf("SDL2: SDL_sscanf\n"); +} +void SDL_Log(const char*, ...) { + printf("SDL2: SDL_Log\n"); +} +void SDL_LogCritical(int, const char*, ...) { + printf("SDL2: SDL_LogCritical\n"); +} +void SDL_LogDebug(int, const char*, ...) { + printf("SDL2: SDL_LogDebug\n"); +} +void SDL_LogError(int, const char*, ...) { + printf("SDL2: SDL_LogError\n"); +} +void SDL_LogInfo(int, const char*, ...) { + printf("SDL2: SDL_LogInfo\n"); +} +void SDL_LogMessage(int, SDL_LogPriority, const char*, ...) { + printf("SDL2: SDL_LogMessage\n"); +} +void SDL_LogVerbose(int, const char*, ...) { + printf("SDL2: SDL_LogVerbose\n"); +} +void SDL_LogWarn(int, const char*, ...) { + printf("SDL2: SDL_LogWarn\n"); +} +int SDL_SetError(const char*, ...) { + return printf("SDL2: SDL_SetError\n"); +} -void SDL_LogMessageV(int, SDL_LogPriority, const char*, __va_list_tag*) { printf("SDL2: SDL_LogMessageV\n");} -int SDL_vsnprintf(char*, size_t, const char*, __va_list_tag*) { return printf("SDL2: SDL_vsnprintf\n");} -int SDL_vsscanf(const char*, const char*, __va_list_tag*) { return printf("SDL2: SDL_vsscanf\n");} +void SDL_LogMessageV(int, SDL_LogPriority, const char*, __va_list_tag*) { + printf("SDL2: SDL_LogMessageV\n"); +} +int SDL_vsnprintf(char*, size_t, const char*, __va_list_tag*) { + return printf("SDL2: SDL_vsnprintf\n"); +} +int SDL_vsscanf(const char*, const char*, __va_list_tag*) { + return printf("SDL2: SDL_vsscanf\n"); +} extern "C" { - void* SDL_GL_GetProcAddress(const char* name) { - // TODO: Fix this HACK - return (void*)glXGetProcAddress((const GLubyte*)name); - } +void* SDL_GL_GetProcAddress(const char* name) { + // TODO: Fix this HACK + return (void*)glXGetProcAddress((const GLubyte*)name); +} - // TODO: These are not 100% conforming to SDL either - void *SDL_LoadObject(const char *sofile) { - auto lib = dlopen(sofile, RTLD_NOW | RTLD_LOCAL); - if (!lib) { - printf("SDL_LoadObject: Failed to load %s\n", sofile); - } - return lib; - } +// TODO: These are not 100% conforming to SDL either +void* SDL_LoadObject(const char* sofile) { + auto lib = dlopen(sofile, RTLD_NOW | RTLD_LOCAL); + if (!lib) { + printf("SDL_LoadObject: Failed to load %s\n", sofile); + } + return lib; +} - void *SDL_LoadFunction(void *lib, const char *name) { - return dlsym(lib, name); - } +void* SDL_LoadFunction(void* lib, const char* name) { + return dlsym(lib, name); +} - void SDL_UnloadObject(void *lib) { - if (lib) { - dlclose(lib); - } - } +void SDL_UnloadObject(void* lib) { + if (lib) { + dlclose(lib); + } +} } diff --git a/ThunkLibs/libVDSO/libVDSO_Guest.cpp b/ThunkLibs/libVDSO/libVDSO_Guest.cpp index f3ede2e3e..b8ce3d6cb 100644 --- a/ThunkLibs/libVDSO/libVDSO_Guest.cpp +++ b/ThunkLibs/libVDSO/libVDSO_Guest.cpp @@ -19,28 +19,26 @@ $end_info$ #include "thunkgen_guest_libVDSO.inl" extern "C" { -time_t __vdso_time(time_t *tloc) __attribute__((alias("fexfn_pack_time"))); -int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) __attribute__((alias("fexfn_pack_gettimeofday"))); -int __vdso_clock_gettime(clockid_t, struct timespec *) __attribute__((alias("fexfn_pack_clock_gettime"))); -int __vdso_clock_getres(clockid_t, struct timespec *) __attribute__((alias("fexfn_pack_clock_getres"))); -int __vdso_getcpu(uint32_t *, uint32_t *) __attribute__((alias("fexfn_pack_getcpu"))); +time_t __vdso_time(time_t* tloc) __attribute__((alias("fexfn_pack_time"))); +int __vdso_gettimeofday(struct timeval* tv, struct timezone* tz) __attribute__((alias("fexfn_pack_gettimeofday"))); +int __vdso_clock_gettime(clockid_t, struct timespec*) __attribute__((alias("fexfn_pack_clock_gettime"))); +int __vdso_clock_getres(clockid_t, struct timespec*) __attribute__((alias("fexfn_pack_clock_getres"))); +int __vdso_getcpu(uint32_t*, uint32_t*) __attribute__((alias("fexfn_pack_getcpu"))); #if __SIZEOF_POINTER__ == 4 -int __vdso_clock_gettime64(clockid_t, struct timespec64 *) __attribute__((alias("fexfn_pack_clock_gettime64"))); +int __vdso_clock_gettime64(clockid_t, struct timespec64*) __attribute__((alias("fexfn_pack_clock_gettime64"))); -__attribute__((naked)) -int __kernel_vsyscall() { +__attribute__((naked)) int __kernel_vsyscall() { asm volatile(R"( .intel_syntax noprefix int 0x80; ret; .att_syntax prefix - )" - ::: "memory"); + )" :: + : "memory"); } -__attribute__((naked)) -void __kernel_sigreturn() { +__attribute__((naked)) void __kernel_sigreturn() { asm volatile(R"( .intel_syntax noprefix pop eax; @@ -48,18 +46,17 @@ void __kernel_sigreturn() { int 0x80; nop; .att_syntax prefix - )" - ::: "memory"); + )" :: + : "memory"); } -__attribute__((naked)) -void __kernel_rt_sigreturn() { +__attribute__((naked)) void __kernel_rt_sigreturn() { asm volatile(R"( .intel_syntax noprefix mov eax, 0xad; int 0x80; .att_syntax prefix - )" - ::: "memory"); + )" :: + : "memory"); } #endif diff --git a/ThunkLibs/libVDSO/libVDSO_interface.cpp b/ThunkLibs/libVDSO/libVDSO_interface.cpp index 6d123cee6..ac924cd2f 100644 --- a/ThunkLibs/libVDSO/libVDSO_interface.cpp +++ b/ThunkLibs/libVDSO/libVDSO_interface.cpp @@ -7,16 +7,21 @@ #include "Types.h" template -struct fex_gen_config { -}; +struct fex_gen_config {}; -template<> struct fex_gen_config