mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-11-11 10:01:33 -10:00
Compare commits
41
Commits
FEX-2611.1
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1800ddad5d | ||
|
|
15f30601b7 | ||
|
|
e3b30dda25 | ||
|
|
95b7bf0f5f | ||
|
|
2a62720470 | ||
|
|
dbbda7b2b3 | ||
|
|
5c0cfdbd2a | ||
|
|
c8e9fc10e9 | ||
|
|
f00813de7b | ||
|
|
65da98d642 | ||
|
|
eb7a9f2339 | ||
|
|
0fe0648349 | ||
|
|
e760431de4 | ||
|
|
7fdac22483 | ||
|
|
9e860a852b | ||
|
|
90c9595cf4 | ||
|
|
74e9029d53 | ||
|
|
26d8ec55fc | ||
|
|
b4ebbb5dc9 | ||
|
|
08f35b3330 | ||
|
|
fe931e3aa5 | ||
|
|
8646d5b07f | ||
|
|
44dd02ac2f | ||
|
|
bfad5d6925 | ||
|
|
16c100025b | ||
|
|
9cf556baa3 | ||
|
|
388fd9cf40 | ||
|
|
ec3d5ace98 | ||
|
|
ae495b971b | ||
|
|
feee41a768 | ||
|
|
cf2f831ad9 | ||
|
|
b9fc587ac8 | ||
|
|
c985199ed5 | ||
|
|
e67bbd3ecf | ||
|
|
02e932d9f4 | ||
|
|
a3f5700c33 | ||
|
|
a2b15c8e0f | ||
|
|
05293166ce | ||
|
|
ef586f03a8 | ||
|
|
6a3d85a26f | ||
|
|
36aec0d54d |
No files matched your search
@@ -24,7 +24,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
- name: Configure CMake
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False \
|
||||
-DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True
|
||||
-DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DBUILD_FEX_LINUX_TESTS=True
|
||||
|
||||
# These steps make a lot of noise but rarely fail.
|
||||
# Put them in a separate step to make normal build logs easier to parse
|
||||
@@ -57,9 +57,16 @@ jobs:
|
||||
with:
|
||||
target: asm_tests
|
||||
|
||||
# host fex tests tests
|
||||
- name: Host Tests
|
||||
if: ${{ always() }}
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: fex_linux_tests_host
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
run: which git-clang-format-19
|
||||
|
||||
- name: Setup Python env
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: 3.11
|
||||
cache: pip
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
run: DESTDIR="$PWD"/install distrobox enter --name steamrt4 -- cmake --build build -t install
|
||||
|
||||
- name: Upload libraries
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
overwrite: true
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
target: arm64ec
|
||||
|
||||
- name: Upload libraries
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
overwrite: true
|
||||
|
||||
@@ -337,7 +337,7 @@ def print_parse_envloader_options(options):
|
||||
value_type = op_vals["Type"]
|
||||
if (value_type == "strenum"):
|
||||
output_argloader.write("else if (Key == \"FEX_{0}\") {{\n".format(op_key.upper()))
|
||||
output_argloader.write("\tValue = FEXCore::Config::EnumParser<FEXCore::Config::{}ConfigPair>(FEXCore::Config::{}_EnumPairs, Value_View);\n".format(op_key, op_key))
|
||||
output_argloader.write("\tValue = FEXCore::Config::EnumParser(FEXCore::Config::{}_EnumPairs, Value_View);\n".format(op_key))
|
||||
output_argloader.write("}\n")
|
||||
|
||||
if ("ArgumentHandler" in op_vals):
|
||||
@@ -357,7 +357,7 @@ def print_parse_jsonloader_options(options):
|
||||
value_type = op_vals["Type"]
|
||||
if (value_type == "strenum"):
|
||||
output_argloader.write("else if (KeyName == \"{0}\") {{\n".format(op_key))
|
||||
output_argloader.write("\tSet(KeyOption, FEXCore::Config::EnumParser<FEXCore::Config::{}ConfigPair>(FEXCore::Config::{}_EnumPairs, Value_View));\n".format(op_key, op_key))
|
||||
output_argloader.write("\tSet(KeyOption, FEXCore::Config::EnumParser(FEXCore::Config::{}_EnumPairs, Value_View));\n".format(op_key))
|
||||
output_argloader.write("}\n")
|
||||
elif (value_type == "strarray"):
|
||||
output_argloader.write("else if (KeyName == \"{0}\") {{\n".format(op_key))
|
||||
@@ -394,13 +394,12 @@ def print_parse_enum_options(options):
|
||||
if (op_vals["Type"] == "strenum"):
|
||||
Enums = op_vals["Enums"]
|
||||
|
||||
output_argloader.write("using {}ConfigPair = std::pair<std::string_view, FEXCore::Config::{}>;\n".format(op_key, op_key))
|
||||
output_argloader.write("constexpr static std::array<{}ConfigPair, {}> {}_EnumPairs = {{{{\n".format(op_key, len(Enums) + 1, op_key))
|
||||
output_argloader.write("constexpr static std::array<StringEnumPairType, {}> {}_EnumPairs = {{{{\n".format(len(Enums) + 1, op_key))
|
||||
i = 0
|
||||
# Always have an OFF.
|
||||
output_argloader.write("\t{{ \"off\", FEXCore::Config::{}::OFF }},\n".format(op_key))
|
||||
output_argloader.write("\t{{ \"off\", FEXCore::ToUnderlying(FEXCore::Config::{}::OFF) }},\n".format(op_key))
|
||||
for enum_op_key, enum_op_vals in Enums.items():
|
||||
output_argloader.write("\t{{ \"{}\", FEXCore::Config::{}::{} }},\n".format(enum_op_vals, op_key, enum_op_key.upper()))
|
||||
output_argloader.write("\t{{ \"{}\", FEXCore::ToUnderlying(FEXCore::Config::{}::{}) }},\n".format(enum_op_vals, op_key, enum_op_key.upper()))
|
||||
i += 1
|
||||
|
||||
output_argloader.write("}};\n")
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
@@ -558,4 +559,36 @@ FEX_DEFAULT_VISIBILITY bool CheckConfigMatches(std::string_view Config) {
|
||||
return SerializeForCache() == Config;
|
||||
}
|
||||
|
||||
std::optional<fextl::string> EnumParser(std::span<const StringEnumPairType> EnumPairs, const std::string_view 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 StringEnumPairType& Value) -> bool { return Value.first == Option; });
|
||||
|
||||
if (EnumValue == EnumPairs.end()) {
|
||||
LogMan::Msg::IFmt("Skipping Unknown option: {}", Option);
|
||||
} else {
|
||||
EnumMask |= 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 FEXCore::Config
|
||||
@@ -1129,4 +1129,9 @@ void Arm64Emitter::Align16B() {
|
||||
}
|
||||
}
|
||||
|
||||
ARMEmitter::Register Arm64Emitter::GetX86GPRMapping(FEXCore::X86State::X86Reg Reg) {
|
||||
LOGMAN_THROW_A_FMT(Reg <= FEXCore::X86State::X86Reg::REG_R15, "Incorrect register");
|
||||
return StaticRegisters[Reg];
|
||||
}
|
||||
|
||||
} // namespace FEXCore::CPU
|
||||
@@ -235,6 +235,8 @@ protected:
|
||||
|
||||
void Align16B();
|
||||
|
||||
ARMEmitter::Register GetX86GPRMapping(FEXCore::X86State::X86Reg Reg);
|
||||
|
||||
#ifdef VIXL_SIMULATOR
|
||||
// Generates a vixl simulator runtime call.
|
||||
//
|
||||
|
||||
@@ -545,7 +545,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_01h(uint32_t Leaf) const {
|
||||
(1 << 25) | // SSE
|
||||
(1 << 26) | // SSE2
|
||||
(0 << 27) | // Self Snoop
|
||||
(0 << 28) | // (HTT) Max APIC IDs reserved field is valid
|
||||
(1 << 28) | // (HTT) Max APIC IDs reserved field is valid
|
||||
(1 << 29) | // Thermal monitor
|
||||
(0 << 30) | // Reserved
|
||||
(0 << 31); // Pending break enable
|
||||
@@ -572,6 +572,10 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_02h(uint32_t Leaf) const {
|
||||
// 4: Deterministic cache parameters for each level
|
||||
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_04h(uint32_t Leaf) const {
|
||||
FEXCore::CPUID::FunctionResults Res {};
|
||||
#ifdef CPUID_AMD
|
||||
// CPUID function 4h is Intel exclusive.
|
||||
return Res;
|
||||
#endif
|
||||
constexpr uint32_t CacheType_Data = 1;
|
||||
constexpr uint32_t CacheType_Instruction = 2;
|
||||
constexpr uint32_t CacheType_Unified = 3;
|
||||
@@ -823,7 +827,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_07h(uint32_t Leaf) const {
|
||||
(0U << 14) | // Reserved
|
||||
(0U << 15) | // Reserved
|
||||
(0U << 16) | // Reserved
|
||||
(0U << 17) | // FRED (Flexible Return and Event Delivery)
|
||||
(1U << 17) | // FRED (Flexible Return and Event Delivery)
|
||||
(0U << 18) | // LKGS (Load into Kernel GS Base)
|
||||
(0U << 19) | // WRMSRNS
|
||||
(0U << 20) | // NMI_SRC
|
||||
@@ -1264,9 +1268,9 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0008h(uint32_t Leaf) con
|
||||
(CTX->HostFeatures.SupportsCLZERO << 0); // CLZERO support
|
||||
|
||||
uint32_t CoreCount = Cores - 1;
|
||||
Res.ecx = (0 << 16) | // PerfTscSize: Performance timestamp count size
|
||||
(std::bit_ceil(Cores) << 12) | // ApicIdSize: Number of bits in ApicID
|
||||
(CoreCount << 0); // Count count subtract one
|
||||
Res.ecx = (0 << 16) | // PerfTscSize: Performance timestamp count size
|
||||
(FEXCore::ilog2(std::bit_ceil(Cores)) << 12) | // ApicIdSize: Number of bits in ApicID
|
||||
(CoreCount << 0); // Count count subtract one
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ namespace DiskCache {
|
||||
// The current version of the diskcache.
|
||||
// This must be changed any time codegen changes occur!
|
||||
// Be aware of the impact of changing this frequently!
|
||||
static constexpr uint16_t FormatVersion = 43;
|
||||
static constexpr uint16_t FormatVersion = 44;
|
||||
|
||||
static constexpr uint32_t LOOKUP_KEY_MAX_BUCKET_DEPTH = 500;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <FEXCore/Core/SignalDelegator.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
#include <FEXCore/Utils/Event.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
@@ -417,6 +418,7 @@ void Dispatcher::EmitDispatcher() {
|
||||
brk(0);
|
||||
}
|
||||
|
||||
ARMEmitter::BackwardLabel GuestSIGSEGVLabelPostSpill;
|
||||
{
|
||||
// Guest Overflow handler
|
||||
// Needs to be distinct from the SignalHandlerReturnAddress
|
||||
@@ -424,6 +426,8 @@ void Dispatcher::EmitDispatcher() {
|
||||
|
||||
SpillStaticRegs(TMP1);
|
||||
|
||||
(void)Bind(&GuestSIGSEGVLabelPostSpill);
|
||||
|
||||
// hlt/udf = SIGILL
|
||||
// brk = SIGTRAP
|
||||
// ??? = SIGSEGV
|
||||
@@ -534,6 +538,35 @@ void Dispatcher::EmitDispatcher() {
|
||||
(void)b(&LoopTop);
|
||||
}
|
||||
|
||||
auto EmitL1Lookup = [&](int rip_offset = 0) {
|
||||
// L1 lookup after syscall. Mirrors the implementation in `ExitFunction`.
|
||||
// Most syscall instructions just return to the following RIP, so it is highly likely to be in the L1 in tight loops.
|
||||
ldr(TMP3, STATE_PTR(CpuStateFrame, State.rip));
|
||||
|
||||
// TF may be set: a single-stepped SYSCALL or CPUID. An L1 hit would jump into a block compiled without the
|
||||
// per-instruction single-step trap, and the trap would only be raised at the next dispatcher entry, instructions
|
||||
// later. The loop top checks TF and compiles single-step blocks.
|
||||
ldrb(TMP1, STATE_PTR(CpuStateFrame, State.flags[X86State::RFLAG_TF_RAW_LOC]));
|
||||
(void)cbnz(ARMEmitter::Size::i32Bit, TMP1, &LoopTop);
|
||||
|
||||
ldp<ARMEmitter::IndexType::OFFSET>(TMP1, TMP2, STATE, offsetof(FEXCore::Core::CpuStateFrame, State.L1Pointer));
|
||||
|
||||
if (rip_offset) {
|
||||
add(ARMEmitter::Size::i64Bit, TMP3, TMP3, rip_offset);
|
||||
}
|
||||
|
||||
// Calculate (tmp1 + ((ripreg & L1_ENTRIES_MASK) << 4)) for the address
|
||||
// L1Mask is pre-shifted.
|
||||
and_(ARMEmitter::Size::i64Bit, TMP2, TMP2, TMP3, ARMEmitter::ShiftType::LSL, FEXCore::ilog2(sizeof(LookupCache::LookupCacheEntry)));
|
||||
add(TMP1, TMP1, TMP2);
|
||||
|
||||
ldp<ARMEmitter::IndexType::OFFSET>(TMP2, TMP1, TMP1, 0);
|
||||
|
||||
sub(TMP1, TMP1, TMP3);
|
||||
(void)cbnz(ARMEmitter::Size::i64Bit, TMP1, &LoopTop);
|
||||
br(TMP2);
|
||||
};
|
||||
|
||||
{
|
||||
// All dynamic and static registers are spilled coming in to this handler.
|
||||
// It's also the end of block and RIP might have changed, so we jump directly to the top of the loop.
|
||||
@@ -566,23 +599,90 @@ void Dispatcher::EmitDispatcher() {
|
||||
// We can safely claim we are no longer in a syscall
|
||||
str(ARMEmitter::XReg::zr, STATE, offsetof(FEXCore::Core::CpuStateFrame, InSyscallInfo));
|
||||
|
||||
{
|
||||
// L1 lookup after syscall. Mirrors the implementation in `ExitFunction`.
|
||||
// Most syscall instructions just return to the following RIP, so it is highly likely to be in the L1 in tight loops.
|
||||
ldr(TMP3, STATE_PTR(CpuStateFrame, State.rip));
|
||||
ldp<ARMEmitter::IndexType::OFFSET>(TMP1, TMP2, STATE, offsetof(FEXCore::Core::CpuStateFrame, State.L1Pointer));
|
||||
EmitL1Lookup();
|
||||
}
|
||||
|
||||
// Calculate (tmp1 + ((ripreg & L1_ENTRIES_MASK) << 4)) for the address
|
||||
// L1Mask is pre-shifted.
|
||||
and_(ARMEmitter::Size::i64Bit, TMP2, TMP2, TMP3, ARMEmitter::ShiftType::LSL, FEXCore::ilog2(sizeof(LookupCache::LookupCacheEntry)));
|
||||
add(TMP1, TMP1, TMP2);
|
||||
{
|
||||
// All dynamic and static registers are spilled coming in to this handler.
|
||||
// It's also the end of block and RIP might have changed, so we jump directly to the top of the loop.
|
||||
ThreadDispatchCPUIDHandler = GetCursorAddress<uint64_t>();
|
||||
|
||||
ldp<ARMEmitter::IndexType::OFFSET>(TMP2, TMP1, TMP1, 0);
|
||||
// CPUID behaves like an ISB.
|
||||
isb();
|
||||
|
||||
sub(TMP1, TMP1, TMP3);
|
||||
(void)cbnz(ARMEmitter::Size::i64Bit, TMP1, &LoopTop);
|
||||
br(TMP2);
|
||||
auto RAXReg = GetX86GPRMapping(FEXCore::X86State::REG_RAX);
|
||||
auto RBXReg = GetX86GPRMapping(FEXCore::X86State::REG_RBX);
|
||||
auto RCXReg = GetX86GPRMapping(FEXCore::X86State::REG_RCX);
|
||||
auto RDXReg = GetX86GPRMapping(FEXCore::X86State::REG_RDX);
|
||||
|
||||
ARMEmitter::ForwardLabel SetupCPUIDFault {};
|
||||
ldr(TMP2, STATE, offsetof(FEXCore::Core::CPUState, CoreFlags));
|
||||
(void)tbz(TMP2, FEXCore::ilog2(FEXCore::ToUnderlying(FEXCore::Core::CoreFlagsEnum::CPUID_ENABLED)), &SetupCPUIDFault);
|
||||
|
||||
// TMP1 passes the instruction size. Usually only 2-bytes but prefixes can make it 15.
|
||||
ldr(TMP2, STATE_PTR(CpuStateFrame, State.rip));
|
||||
add(TMP2, TMP2, TMP1);
|
||||
str(TMP2, STATE_PTR(CpuStateFrame, State.rip));
|
||||
|
||||
mov(ARMEmitter::XReg::x1, RAXReg.X());
|
||||
mov(ARMEmitter::XReg::x2, RCXReg.X());
|
||||
|
||||
// x0 = CPUID Handler
|
||||
// x1 = CPUID Function (RAX)
|
||||
// x2 = CPUID Leaf (RCX)
|
||||
ldr(ARMEmitter::XReg::x0, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.CPUIDObj));
|
||||
ldr(ARMEmitter::XReg::x3, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.CPUIDFunction));
|
||||
|
||||
if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] {
|
||||
GenerateIndirectRuntimeCall<__uint128_t, void*, uint64_t, uint64_t>(ARMEmitter::Reg::r3);
|
||||
} else {
|
||||
blr(ARMEmitter::Reg::r3);
|
||||
}
|
||||
|
||||
// Results are in x0, x1
|
||||
auto Res0 = ARMEmitter::Reg::r0;
|
||||
auto Res1 = ARMEmitter::Reg::r1;
|
||||
|
||||
if (!TMP_ABIARGS) {
|
||||
// SRA Overlaps, need to move.
|
||||
mov(ARMEmitter::Size::i64Bit, TMP1, Res0);
|
||||
mov(ARMEmitter::Size::i64Bit, TMP2, Res1);
|
||||
Res0 = TMP1;
|
||||
Res1 = TMP2;
|
||||
}
|
||||
|
||||
FillStaticRegs();
|
||||
|
||||
// Results need to be moved to 32-bit EAX, ECX, EBX, EDX.
|
||||
mov(ARMEmitter::Size::i32Bit, RAXReg, Res0);
|
||||
mov(ARMEmitter::Size::i32Bit, RCXReg, Res1);
|
||||
ubfx(ARMEmitter::Size::i64Bit, RBXReg, Res0, 32, 32);
|
||||
ubfx(ARMEmitter::Size::i64Bit, RDXReg, Res1, 32, 32);
|
||||
|
||||
EmitL1Lookup();
|
||||
|
||||
// CPUID fault handling
|
||||
(void)Bind(&SetupCPUIDFault);
|
||||
|
||||
constexpr Core::CpuStateFrame::SynchronousFaultDataStruct State = {
|
||||
.FaultToTopAndGeneratedException = 1,
|
||||
.Signal = Core::FAULT_SIGSEGV,
|
||||
.TrapNo = X86State::X86_TRAPNO_GP,
|
||||
.si_code = 0x80,
|
||||
.err_code = 0,
|
||||
.FaultAddress = 0, // Comes from register.
|
||||
};
|
||||
|
||||
uint64_t Constant {};
|
||||
memcpy(&Constant, &State, sizeof(uint64_t));
|
||||
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP1, static_cast<uint64_t>(Constant));
|
||||
|
||||
str(TMP1, STATE, offsetof(FEXCore::Core::CpuStateFrame, SynchronousFaultData));
|
||||
ldr(TMP2, STATE_PTR(CpuStateFrame, State.rip));
|
||||
str(TMP2, STATE, offsetof(FEXCore::Core::CpuStateFrame, SynchronousFaultData) + 8);
|
||||
|
||||
(void)b(&GuestSIGSEGVLabelPostSpill);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -2683,6 +2783,7 @@ void Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState* Thread)
|
||||
Ptrs.ThreadStopHandlerSpillSRA = ThreadStopHandlerAddressSpillSRA;
|
||||
Ptrs.ThreadPauseHandlerSpillSRA = ThreadPauseHandlerAddressSpillSRA;
|
||||
Ptrs.ThreadDispatchSyscallHandler = ThreadDispatchSyscallHandler;
|
||||
Ptrs.ThreadDispatchCPUIDHandler = ThreadDispatchCPUIDHandler;
|
||||
Ptrs.ThreadDispatchRemoveCodeEntry = ThreadDispatchRemoveCodeEntry;
|
||||
Ptrs.GuestSignal_SIGILL = GuestSignal_SIGILL;
|
||||
Ptrs.GuestSignal_SIGTRAP = GuestSignal_SIGTRAP;
|
||||
|
||||
@@ -82,6 +82,7 @@ private:
|
||||
uint64_t ThreadPauseHandlerAddress {};
|
||||
uint64_t ThreadPauseHandlerAddressSpillSRA {};
|
||||
uint64_t ThreadDispatchSyscallHandler {};
|
||||
uint64_t ThreadDispatchCPUIDHandler {};
|
||||
uint64_t ThreadDispatchRemoveCodeEntry {};
|
||||
uint64_t ExitFunctionLinkerAddress {};
|
||||
uint64_t SignalHandlerReturnAddress {};
|
||||
|
||||
@@ -390,6 +390,10 @@ Decoder::DecodedBlockStatus Decoder::NormalOp(const FEXCore::X86Tables::X86InstI
|
||||
return DecodedBlockStatus::INVALID_INST;
|
||||
}
|
||||
|
||||
if (Info->Type == FEXCore::X86Tables::TYPE_UNIMPLEMENTED) {
|
||||
return DecodedBlockStatus::UNIMPLEMENTED_INST;
|
||||
}
|
||||
|
||||
if (!(Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SUPPORTS_LOCK) && (DecodeInst->Flags & DecodeFlags::FLAG_LOCK)) {
|
||||
// Instruction has lock prefix but doesn't support lock.
|
||||
return DecodedBlockStatus::UNIMPLEMENTED_INST;
|
||||
@@ -699,6 +703,10 @@ Decoder::DecodedBlockStatus Decoder::NormalOpHeader(const FEXCore::X86Tables::X8
|
||||
return DecodedBlockStatus::INVALID_INST;
|
||||
}
|
||||
|
||||
if (Info->Type == FEXCore::X86Tables::TYPE_UNIMPLEMENTED) {
|
||||
return DecodedBlockStatus::UNIMPLEMENTED_INST;
|
||||
}
|
||||
|
||||
LOGMAN_THROW_A_FMT(Info->Type != FEXCore::X86Tables::TYPE_REX_PREFIX, "REX PREFIX should have been decoded before this!");
|
||||
|
||||
// A normal instruction is the most likely.
|
||||
@@ -749,7 +757,7 @@ Decoder::DecodedBlockStatus Decoder::NormalOpHeader(const FEXCore::X86Tables::X8
|
||||
if (LocalInfo->Type == FEXCore::X86Tables::TYPE_SECOND_GROUP_MODRM && ModRM.mod == 0b11) {
|
||||
// Everything in this group is privileged instructions aside from XGETBV
|
||||
constexpr std::array<uint8_t, 8> RegToField = {
|
||||
255, 0, 1, 2, 255, 255, 255, 3,
|
||||
255, 0, 1, 2, 255, 3, 255, 4,
|
||||
};
|
||||
uint8_t Field = RegToField[ModRM.reg];
|
||||
if (Field == 255) {
|
||||
@@ -758,6 +766,9 @@ Decoder::DecodedBlockStatus Decoder::NormalOpHeader(const FEXCore::X86Tables::X8
|
||||
|
||||
LocalOp = (Field << 3) | ModRM.rm;
|
||||
return NormalOp(&SecondModRMTableOps[LocalOp], LocalOp);
|
||||
} else if (LocalInfo->Type == FEXCore::X86Tables::TYPE_SECOND_GROUP_MODRM && ModRM.reg == 5) {
|
||||
// Special case 0x0F 0x01 /5 group as they are currently all reserved.
|
||||
return DecodedBlockStatus::UNIMPLEMENTED_INST;
|
||||
} else {
|
||||
return NormalOp(&SecondInstGroupOps[LocalOp], LocalOp);
|
||||
}
|
||||
|
||||
@@ -285,6 +285,9 @@ DEF_OP(CondJump) {
|
||||
DEF_OP(Syscall) {
|
||||
SpillStaticRegs(TMP1);
|
||||
|
||||
// Not coming back.
|
||||
ResetStack();
|
||||
|
||||
// Jump to the syscall dispatch handler. We won't return after this.
|
||||
ldr(TMP1, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.ThreadDispatchSyscallHandler));
|
||||
br(TMP1);
|
||||
@@ -376,6 +379,9 @@ DEF_OP(ThreadRemoveCodeEntry) {
|
||||
|
||||
SpillStaticRegs(TMP1);
|
||||
|
||||
// Not coming back.
|
||||
ResetStack();
|
||||
|
||||
// Store the new RIP to go to.
|
||||
str(GetReg(Op->NewRIP).X(), STATE, offsetof(FEXCore::Core::CpuStateFrame, State.rip));
|
||||
|
||||
@@ -395,45 +401,15 @@ DEF_OP(ThreadRemoveCodeEntry) {
|
||||
DEF_OP(CPUID) {
|
||||
auto Op = IROp->C<IR::IROp_CPUID>();
|
||||
|
||||
isb();
|
||||
mov(ARMEmitter::Size::i64Bit, TMP2, GetReg(Op->Function));
|
||||
mov(ARMEmitter::Size::i64Bit, TMP3, GetReg(Op->Leaf));
|
||||
SpillStaticRegs(TMP1);
|
||||
|
||||
PushDynamicRegs(TMP4);
|
||||
SpillStaticRegs(TMP4);
|
||||
// Not coming back.
|
||||
ResetStack();
|
||||
|
||||
// x0 = CPUID Handler
|
||||
// x1 = CPUID Function
|
||||
// x2 = CPUID Leaf
|
||||
ldr(ARMEmitter::XReg::x0, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.CPUIDObj));
|
||||
ldr(ARMEmitter::XReg::x3, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.CPUIDFunction));
|
||||
|
||||
if (!TMP_ABIARGS) {
|
||||
mov(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r1, TMP2);
|
||||
mov(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r2, TMP3);
|
||||
}
|
||||
|
||||
if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] {
|
||||
GenerateIndirectRuntimeCall<__uint128_t, void*, uint64_t, uint64_t>(ARMEmitter::Reg::r3);
|
||||
} else {
|
||||
blr(ARMEmitter::Reg::r3);
|
||||
}
|
||||
|
||||
if (!TMP_ABIARGS) {
|
||||
mov(ARMEmitter::Size::i64Bit, TMP1, ARMEmitter::Reg::r0);
|
||||
mov(ARMEmitter::Size::i64Bit, TMP2, ARMEmitter::Reg::r1);
|
||||
}
|
||||
|
||||
FillStaticRegs();
|
||||
|
||||
PopDynamicRegs();
|
||||
|
||||
// Results are in x0, x1
|
||||
// Results want to be 4xi32 scalars
|
||||
mov(ARMEmitter::Size::i32Bit, GetReg(Op->OutEAX), TMP1);
|
||||
mov(ARMEmitter::Size::i32Bit, GetReg(Op->OutECX), TMP2);
|
||||
ubfx(ARMEmitter::Size::i64Bit, GetReg(Op->OutEBX), TMP1, 32, 32);
|
||||
ubfx(ARMEmitter::Size::i64Bit, GetReg(Op->OutEDX), TMP2, 32, 32);
|
||||
LoadConstant(ARMEmitter::Size::i32Bit, TMP1, Op->InstSize);
|
||||
// Jump to the syscall dispatch handler. We won't return after this.
|
||||
ldr(TMP2, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.ThreadDispatchCPUIDHandler));
|
||||
br(TMP2);
|
||||
}
|
||||
|
||||
DEF_OP(XGetBV) {
|
||||
|
||||
@@ -1370,20 +1370,19 @@ void OpDispatchBuilder::MOVOffsetOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CPUIDOp(OpcodeArgs) {
|
||||
Ref Src = LoadGPRRegister(X86State::REG_RAX);
|
||||
Ref Leaf = LoadGPRRegister(X86State::REG_RCX);
|
||||
BlockSetRIP = true;
|
||||
|
||||
Ref RAX = _AllocateGPR(false);
|
||||
Ref RBX = _AllocateGPR(false);
|
||||
Ref RCX = _AllocateGPR(false);
|
||||
Ref RDX = _AllocateGPR(false);
|
||||
// Calculate flags early.
|
||||
CalculateDeferredFlags();
|
||||
|
||||
_CPUID(Src, Leaf, RAX, RBX, RCX, RDX);
|
||||
// Similar to Syscall. Store the RIP to the start of the instruction.
|
||||
// CPUID operation will modify the RIP itself.
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
auto NewRIP = GetRelocatedPC(Op, -Op->InstSize);
|
||||
_StoreContextGPR(GPRSize, NewRIP, offsetof(FEXCore::Core::CPUState, rip));
|
||||
|
||||
StoreGPRRegister(X86State::REG_RAX, RAX);
|
||||
StoreGPRRegister(X86State::REG_RBX, RBX);
|
||||
StoreGPRRegister(X86State::REG_RCX, RCX);
|
||||
StoreGPRRegister(X86State::REG_RDX, RDX);
|
||||
FlushRegisterCache();
|
||||
_CPUID(Op->InstSize);
|
||||
}
|
||||
|
||||
uint32_t OpDispatchBuilder::GetConstantShift(X86Tables::DecodedOp Op, bool Is1Bit) {
|
||||
|
||||
@@ -41,8 +41,6 @@ constexpr DispatchTableEntry OpDispatch_SecondaryGroupTables[] = {
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_7, PF_66, 4), 1, &OpDispatchBuilder::SMSWOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_7, PF_F2, 4), 1, &OpDispatchBuilder::SMSWOp},
|
||||
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_7, PF_NONE, 5), 1, &OpDispatchBuilder::SerializeOp},
|
||||
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_7, PF_NONE, 6), 1, &OpDispatchBuilder::PermissionRestrictedOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_7, PF_F3, 6), 1, &OpDispatchBuilder::PermissionRestrictedOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_7, PF_66, 6), 1, &OpDispatchBuilder::PermissionRestrictedOp},
|
||||
|
||||
@@ -15,9 +15,12 @@ constexpr DispatchTableEntry OpDispatch_SecondaryModRMTables[] = {
|
||||
// REG /3
|
||||
{((2 << 3) | 7), 1, &OpDispatchBuilder::PermissionRestrictedOp},
|
||||
|
||||
// REG /5
|
||||
{((3 << 3) | 0), 1, &OpDispatchBuilder::SerializeOp},
|
||||
|
||||
// REG /7
|
||||
{((3 << 3) | 1), 1, &OpDispatchBuilder::RDTSCPOp},
|
||||
{((3 << 3) | 4), 1, &OpDispatchBuilder::CLZeroOp},
|
||||
{((4 << 3) | 1), 1, &OpDispatchBuilder::RDTSCPOp},
|
||||
{((4 << 3) | 4), 1, &OpDispatchBuilder::CLZeroOp},
|
||||
};
|
||||
|
||||
} // namespace FEXCore::IR
|
||||
@@ -98,13 +98,13 @@ constexpr std::array<X86InstInfo, MAX_INST_SECOND_GROUP_TABLE_SIZE> SecondInstGr
|
||||
{OPD(TYPE_GROUP_6, PF_F2, 7), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
|
||||
// GROUP 7
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 0), 1, X86InstInfo{"SGDT", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 1), 1, X86InstInfo{"SIDT", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 2), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 3), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 4), 1, X86InstInfo{"SMSW", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 5), 1, X86InstInfo{"SERIALIZE", TYPE_INST, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 6), 1, X86InstInfo{"LMSW", TYPE_INST, FLAGS_MODRM, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 0), 1, X86InstInfo{"SGDT", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 1), 1, X86InstInfo{"SIDT", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 2), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 3), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 4), 1, X86InstInfo{"SMSW", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 5), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 6), 1, X86InstInfo{"LMSW", TYPE_INST, FLAGS_MODRM, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_NONE, 7), 1, X86InstInfo{"INVLPG", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 0), 1, X86InstInfo{"SGDT", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
@@ -112,7 +112,7 @@ constexpr std::array<X86InstInfo, MAX_INST_SECOND_GROUP_TABLE_SIZE> SecondInstGr
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 2), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 3), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 4), 1, X86InstInfo{"SMSW", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 5), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 5), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 6), 1, X86InstInfo{"LMSW", TYPE_INST, FLAGS_MODRM, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F3, 7), 1, X86InstInfo{"INVLPG", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
|
||||
@@ -121,7 +121,7 @@ constexpr std::array<X86InstInfo, MAX_INST_SECOND_GROUP_TABLE_SIZE> SecondInstGr
|
||||
{OPD(TYPE_GROUP_7, PF_66, 2), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_66, 3), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_66, 4), 1, X86InstInfo{"SMSW", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_66, 5), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_66, 5), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_66, 6), 1, X86InstInfo{"LMSW", TYPE_INST, FLAGS_MODRM, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_66, 7), 1, X86InstInfo{"INVLPG", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
|
||||
@@ -130,7 +130,7 @@ constexpr std::array<X86InstInfo, MAX_INST_SECOND_GROUP_TABLE_SIZE> SecondInstGr
|
||||
{OPD(TYPE_GROUP_7, PF_F2, 2), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F2, 3), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F2, 4), 1, X86InstInfo{"SMSW", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F2, 5), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F2, 5), 1, X86InstInfo{"", TYPE_SECOND_GROUP_MODRM, FLAGS_NONE, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F2, 6), 1, X86InstInfo{"LMSW", TYPE_INST, FLAGS_MODRM, 0}},
|
||||
{OPD(TYPE_GROUP_7, PF_F2, 7), 1, X86InstInfo{"INVLPG", TYPE_SECOND_GROUP_MODRM, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}},
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ $end_info$
|
||||
namespace FEXCore::X86Tables {
|
||||
using namespace InstFlags;
|
||||
enum ModRM_LUT {
|
||||
ENTRY_3_0,
|
||||
ENTRY_7_0,
|
||||
ENTRY_MAX,
|
||||
};
|
||||
|
||||
constexpr std::array<X86InstInfo[2], ENTRY_MAX> ModRM_ArchSelect_LUT = {{
|
||||
// ENTRY_3_0
|
||||
// ENTRY_7_0
|
||||
{
|
||||
{"SWAPGS", TYPE_INST, FLAGS_NONE, 0, { .OpDispatch = &IR::OpDispatchBuilder::UnimplementedOp }},
|
||||
{"SWAPGS", TYPE_INST, FLAGS_NONE, 0, { .OpDispatch = &IR::OpDispatchBuilder::PermissionRestrictedOp }},
|
||||
@@ -58,15 +58,25 @@ constexpr std::array<X86InstInfo, MAX_SECOND_MODRM_TABLE_SIZE> SecondModRMTableO
|
||||
{((2 << 3) | 6), 1, X86InstInfo{"SKINIT", TYPE_PRIV, FLAGS_NONE, 0}},
|
||||
{((2 << 3) | 7), 1, X86InstInfo{"INVLPGA", TYPE_INST, FLAGS_NONE, 0}},
|
||||
|
||||
// REG /5
|
||||
{((3 << 3) | 0), 1, X86InstInfo{"SERIALIZE", TYPE_INST, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 1), 1, X86InstInfo{"", TYPE_UNIMPLEMENTED, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 2), 1, X86InstInfo{"", TYPE_UNIMPLEMENTED, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 3), 1, X86InstInfo{"", TYPE_UNIMPLEMENTED, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 4), 1, X86InstInfo{"", TYPE_UNIMPLEMENTED, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 5), 1, X86InstInfo{"", TYPE_UNIMPLEMENTED, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 6), 1, X86InstInfo{"RDPKRU", TYPE_UNIMPLEMENTED, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 7), 1, X86InstInfo{"WRPKRU", TYPE_UNIMPLEMENTED, FLAGS_NONE, 0}},
|
||||
|
||||
// REG /7
|
||||
{((3 << 3) | 0), 1, X86InstInfo{"", TYPE_ARCH_DISPATCHER, FLAGS_NONE, 0, { .Indirect = ModRM_ArchSelect_LUT[ENTRY_3_0] }}},
|
||||
{((3 << 3) | 1), 1, X86InstInfo{"RDTSCP", TYPE_INST, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 2), 1, X86InstInfo{"MONITORX", TYPE_PRIV, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 3), 1, X86InstInfo{"MWAITX", TYPE_PRIV, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 4), 1, X86InstInfo{"CLZERO", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_DEBUG_MEM_ACCESS, 0}},
|
||||
{((3 << 3) | 5), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 6), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{((3 << 3) | 7), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{((4 << 3) | 0), 1, X86InstInfo{"", TYPE_ARCH_DISPATCHER, FLAGS_NONE, 0, { .Indirect = ModRM_ArchSelect_LUT[ENTRY_7_0] }}},
|
||||
{((4 << 3) | 1), 1, X86InstInfo{"RDTSCP", TYPE_INST, FLAGS_NONE, 0}},
|
||||
{((4 << 3) | 2), 1, X86InstInfo{"MONITORX", TYPE_PRIV, FLAGS_NONE, 0}},
|
||||
{((4 << 3) | 3), 1, X86InstInfo{"MWAITX", TYPE_PRIV, FLAGS_NONE, 0}},
|
||||
{((4 << 3) | 4), 1, X86InstInfo{"CLZERO", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_DEBUG_MEM_ACCESS, 0}},
|
||||
{((4 << 3) | 5), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{((4 << 3) | 6), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{((4 << 3) | 7), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
};
|
||||
|
||||
GenerateTable(Table.data(), SecondaryModRMExtensionOpTable, std::size(SecondaryModRMExtensionOpTable));
|
||||
|
||||
@@ -204,7 +204,7 @@ constexpr std::array<X86InstInfo, MAX_SECOND_TABLE_SIZE> SecondBaseOps = []() co
|
||||
|
||||
{0xA0, 1, X86InstInfo{"", TYPE_ARCH_DISPATCHER, FLAGS_DEBUG_MEM_ACCESS | FLAGS_NO_OVERLAY, 0, { .Indirect = Secondary_ArchSelect_LUT[ENTRY_A0] }}},
|
||||
{0xA1, 1, X86InstInfo{"", TYPE_ARCH_DISPATCHER, FLAGS_DEBUG_MEM_ACCESS | FLAGS_NO_OVERLAY, 0, { .Indirect = Secondary_ArchSelect_LUT[ENTRY_A1] }}},
|
||||
{0xA2, 1, X86InstInfo{"CPUID", TYPE_INST, FLAGS_NO_OVERLAY, 0}},
|
||||
{0xA2, 1, X86InstInfo{"CPUID", TYPE_INST, FLAGS_NO_OVERLAY | FLAGS_BLOCK_END, 0}},
|
||||
{0xA3, 1, X86InstInfo{"BT", TYPE_INST, FLAGS_DEBUG_MEM_ACCESS | FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_NO_OVERLAY | FLAGS_SUPPORTS_LOCK, 0}},
|
||||
{0xA4, 1, X86InstInfo{"SHLD", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_NO_OVERLAY, 1}},
|
||||
{0xA5, 1, X86InstInfo{"SHLD", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_NO_OVERLAY, 0}},
|
||||
|
||||
@@ -272,6 +272,7 @@ enum InstType {
|
||||
TYPE_INST,
|
||||
TYPE_X87 = TYPE_INST,
|
||||
TYPE_INVALID,
|
||||
TYPE_UNIMPLEMENTED,
|
||||
TYPE_COPY_OTHER,
|
||||
// Changes `X86InstInfo::OpcodeDispatcher` member to use the `Indirect` version.
|
||||
// Points to a 2 member array of X86InstInfo to choose instruction description based on executing bitness.
|
||||
@@ -521,7 +522,7 @@ constexpr size_t MAX_INST_GROUP_TABLE_SIZE = 512;
|
||||
// 12 (groups) | 3(max indexes) | 8 ops = 0b1111'11'111 = 9 bits
|
||||
constexpr size_t MAX_INST_SECOND_GROUP_TABLE_SIZE = 512;
|
||||
constexpr size_t MAX_X87_TABLE_SIZE = 1 << 11;
|
||||
constexpr size_t MAX_SECOND_MODRM_TABLE_SIZE = 32;
|
||||
constexpr size_t MAX_SECOND_MODRM_TABLE_SIZE = 40;
|
||||
// (3 bit prefixes) | 8 bit opcode
|
||||
constexpr size_t MAX_0F_38_TABLE_SIZE = (1 << 11);
|
||||
// 1 REX | 1 prefixes | 8 bit opcode
|
||||
|
||||
@@ -337,9 +337,8 @@
|
||||
"HasSideEffects": true
|
||||
},
|
||||
|
||||
"GPR:$EAX, GPR:$EBX, GPR:$ECX, GPR:$EDX = CPUID GPR:$Function, GPR:$Leaf": {
|
||||
"CPUID i8:$InstSize": {
|
||||
"Desc": ["Calls in to the CPUID handler function to return emulated CPUID"],
|
||||
"DestSize": "OpSize::i32Bit",
|
||||
"HasSideEffects": true
|
||||
},
|
||||
"GPR:$EAX, GPR:$EDX = XGetBV GPR:$Function": {
|
||||
|
||||
@@ -21,6 +21,7 @@ static bool IsFragmentExit(FEXCore::IR::IROps Op) {
|
||||
switch (Op) {
|
||||
case OP_THREADREMOVECODEENTRY:
|
||||
case OP_SYSCALL:
|
||||
case OP_CPUID:
|
||||
case OP_EXITFUNCTION:
|
||||
case OP_BREAK: return true;
|
||||
default: return false;
|
||||
|
||||
@@ -12,6 +12,7 @@ $end_info$
|
||||
#include "Interface/IR/Passes/RegisterAllocationPass.h"
|
||||
#include "Interface/Core/OpcodeDispatcher.h"
|
||||
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
namespace FEXCore::IR::Debug {
|
||||
|
||||
@@ -527,27 +527,6 @@ bool ConstrainedRAPass::TryPostRAMerge(Ref LastNode, Ref CodeNode, IROp_Header*
|
||||
IREmit->RemovePostRA(CodeNode);
|
||||
return false;
|
||||
}
|
||||
} else if (IROp->Op == OP_CPUID && PhysicalRegister(IROp->Args[0]) == PhysicalRegister(LastNode) && LastOp->Op == OP_CONSTANT) {
|
||||
// Try to constant fold. As a limitation of merging only 2 instructions, we
|
||||
// can only handle constant functions, not constant leafs. This could be
|
||||
// lifted if we generalized at a (significant) complexity cost.
|
||||
uint64_t ConstantFunction = LastOp->C<IROp_Constant>()->Constant;
|
||||
auto Op = IROp->CW<IR::IROp_CPUID>();
|
||||
|
||||
const auto SupportsConstant = CPUID->DoesFunctionReportConstantData(ConstantFunction);
|
||||
if (SupportsConstant.SupportsConstantFunction == CPUIDEmu::SupportsConstant::CONSTANT &&
|
||||
SupportsConstant.NeedsLeaf != CPUIDEmu::NeedsLeafConstant::NEEDSLEAFCONSTANT) {
|
||||
const auto Result = CPUID->RunFunction(ConstantFunction, 0 /* leaf */);
|
||||
|
||||
IREmit->SetWriteCursorBefore(CodeNode);
|
||||
IREmit->_Fence(IR::FenceType::Inst);
|
||||
IREmit->_Constant(Result.eax).Node->Reg = PhysicalRegister(Op->OutEAX).Raw;
|
||||
IREmit->_Constant(Result.ebx).Node->Reg = PhysicalRegister(Op->OutEBX).Raw;
|
||||
IREmit->_Constant(Result.ecx).Node->Reg = PhysicalRegister(Op->OutECX).Raw;
|
||||
IREmit->_Constant(Result.edx).Node->Reg = PhysicalRegister(Op->OutEDX).Raw;
|
||||
IREmit->RemovePostRA(CodeNode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge moves that are immediately consumed.
|
||||
|
||||
@@ -4,18 +4,15 @@
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
#include <FEXCore/Utils/EnumOperators.h>
|
||||
#include <FEXCore/Utils/EnumUtils.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/fextl/memory.h>
|
||||
#include <FEXCore/fextl/list.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/unordered_map.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
@@ -39,6 +36,9 @@ enum ConfigOption {
|
||||
CONFIG_MAX,
|
||||
};
|
||||
|
||||
using StringArrayType = fextl::list<fextl::string>;
|
||||
using StringEnumPairType = std::pair<std::string_view, uint64_t>;
|
||||
|
||||
#define ENUMDEFINES
|
||||
#include <FEXCore/Config/ConfigOptions.inl>
|
||||
|
||||
@@ -61,41 +61,6 @@ enum class LayerType {
|
||||
LAYER_TOP,
|
||||
};
|
||||
|
||||
template<typename PairTypes, typename ArrayPairType>
|
||||
static inline std::optional<fextl::string> EnumParser(const ArrayPairType& EnumPairs, const std::string_view 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);
|
||||
}
|
||||
|
||||
using StringArrayType = fextl::list<fextl::string>;
|
||||
|
||||
namespace detail {
|
||||
template<ConfigOption Option>
|
||||
struct ConfigOptionInfo;
|
||||
@@ -124,6 +89,7 @@ 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);
|
||||
FEX_DEFAULT_VISIBILITY const fextl::string& GetCacheDirectory();
|
||||
FEX_DEFAULT_VISIBILITY std::optional<fextl::string> EnumParser(std::span<const StringEnumPairType> EnumPairs, const std::string_view View);
|
||||
|
||||
using LayerValue = std::variant< fextl::string, StringArrayType, uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, bool >;
|
||||
|
||||
|
||||
@@ -71,6 +71,12 @@ static_assert(std::is_standard_layout_v<NonAtomicRefCounter<uint64_t>>, "Needs t
|
||||
static_assert(std::is_trivially_copyable_v<NonAtomicRefCounter<uint64_t>>, "needs to be trivially copyable");
|
||||
static_assert(sizeof(NonAtomicRefCounter<uint64_t>) == sizeof(uint64_t), "Needs to be correct size");
|
||||
|
||||
// Flags about the core state that the JIT can query.
|
||||
enum class CoreFlagsEnum : uint64_t {
|
||||
CPUID_ENABLED = (1ULL << 0),
|
||||
};
|
||||
FEX_DEF_NUM_OPS(CoreFlagsEnum)
|
||||
|
||||
struct alignas(64) CPUState {
|
||||
// Allows more efficient handling of the register
|
||||
// file in the event AVX is not supported.
|
||||
@@ -107,7 +113,9 @@ struct alignas(64) CPUState {
|
||||
uint64_t L1Pointer {};
|
||||
uint64_t L1Mask {};
|
||||
uint64_t callret_sp {};
|
||||
uint64_t _pad1 {};
|
||||
|
||||
// CPUID is default enabled.
|
||||
CoreFlagsEnum CoreFlags {CoreFlagsEnum::CPUID_ENABLED};
|
||||
|
||||
// Cacheline: 1,2,3,4
|
||||
// The high 128-bits of AVX registers when not being emulated by SVE256.
|
||||
@@ -406,6 +414,7 @@ struct JITPointers {
|
||||
uint64_t ThreadStopHandlerSpillSRA {};
|
||||
uint64_t ThreadPauseHandlerSpillSRA {};
|
||||
uint64_t ThreadDispatchSyscallHandler {};
|
||||
uint64_t ThreadDispatchCPUIDHandler {};
|
||||
uint64_t ThreadDispatchRemoveCodeEntry {};
|
||||
uint64_t GuestSignal_SIGILL {};
|
||||
uint64_t GuestSignal_SIGTRAP {};
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <FEXCore/Utils/WildcardMatcher.h>
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
#include <FEXHeaderUtils/SymlinkChecks.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
#include <functional>
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Core/HostFeatures.h>
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/Utils/FileLoading.h>
|
||||
#include <FEXCore/Utils/PrctlUtils.h>
|
||||
#include <FEXCore/Utils/StringUtils.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <range/v3/view/split.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "PortabilityInfo.h"
|
||||
#include "Common/FEXServerClient.h"
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/Utils/SignalScopeGuards.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace CodeSize {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
#include <limits.h>
|
||||
|
||||
#include "Common/Config.h"
|
||||
|
||||
#include <charconv>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEX {
|
||||
static inline std::optional<fextl::string> GetSelfPath() {
|
||||
// Read the FEX path from `/proc/self/exe` which is always a symlink to the absolute path of the executable running.
|
||||
|
||||
@@ -58,7 +58,6 @@ $end_info$
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <system_error>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
@@ -434,7 +433,7 @@ int main(int argc, char** argv, char** const envp) {
|
||||
if (StallProcess) {
|
||||
while (1) {
|
||||
// Stall this process out forever
|
||||
select(0, nullptr, nullptr, nullptr, nullptr);
|
||||
ppoll(nullptr, 0, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -362,6 +362,7 @@ static fextl::string GenerateCPUInfo(FEXCore::Context::Context* ctx, uint32_t CP
|
||||
add_flag_if(res_7_1.eax & (1 << 0), "sha512");
|
||||
add_flag_if(res_7_1.eax & (1 << 4), "avx_vnni");
|
||||
add_flag_if(res_7_1.eax & (1 << 5), "avx512_bf16");
|
||||
add_flag_if(res_7_1.eax & (1 << 17), "fred");
|
||||
add_flag_if(res_7_1.eax & (1 << 23), "avx_ifma");
|
||||
add_flag_if(res_7_1.edx & (1 << 4), "avx_vnni_int8");
|
||||
add_flag_if(res_7_1.edx & (1 << 5), "avx_ne_convert");
|
||||
|
||||
@@ -9,6 +9,7 @@ $end_info$
|
||||
#include "CodeLoader.h"
|
||||
#include "GdbServer/Info.h"
|
||||
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <iomanip>
|
||||
|
||||
@@ -7,6 +7,8 @@ $end_info$
|
||||
|
||||
#include "LinuxSyscalls/Seccomp/SeccompEmulator.h"
|
||||
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
|
||||
#include <linux/bpf_common.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/seccomp.h>
|
||||
|
||||
@@ -546,11 +546,16 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) {
|
||||
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;
|
||||
return (Frame->State.CoreFlags & FEXCore::Core::CoreFlagsEnum::CPUID_ENABLED) == FEXCore::Core::CoreFlagsEnum::CPUID_ENABLED ? 1 : 0;
|
||||
case 0x1012: // ARCH_SET_CPUID
|
||||
if (addr == 0) {
|
||||
// Disable CPUID (thus enabling CPUID faulting)
|
||||
Frame->State.CoreFlags = Frame->State.CoreFlags & ~FEXCore::Core::CoreFlagsEnum::CPUID_ENABLED;
|
||||
} else {
|
||||
// Enable CPUID (thus disabling CPUID faulting)
|
||||
Frame->State.CoreFlags = Frame->State.CoreFlags | FEXCore::Core::CoreFlagsEnum::CPUID_ENABLED;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
LogMan::Msg::EFmt("Unknown prctl: 0x{:x}", code);
|
||||
Result = -EINVAL;
|
||||
|
||||
@@ -549,11 +549,6 @@ static ARM64_NT_CONTEXT StoreStateToPackedECContext(FEXCore::Core::InternalThrea
|
||||
ARM64_NT_CONTEXT ECContext {};
|
||||
|
||||
ECContext.ContextFlags = CONTEXT_ARM64_FULL;
|
||||
if (CPUFeatures->IsFeaturePresent(PF_AVX2_INSTRUCTIONS_AVAILABLE)) {
|
||||
// This is a FEX extension and requires corresponding wine-side patches to be of use, however it is harmless to set
|
||||
// even if those patches are not used.
|
||||
ECContext.ContextFlags |= CONTEXT_ARM64_FEX_YMMSTATE;
|
||||
}
|
||||
|
||||
auto& State = Thread->CurrentFrame->State;
|
||||
|
||||
|
||||
@@ -134,6 +134,8 @@ CPUFeatures::CPUFeatures(FEXCore::Context::Context& CTX) {
|
||||
CpuInfo.ProcessorRevision = (FamilyIdentifier & 0xf0000) >> 4; // Extended Model
|
||||
CpuInfo.ProcessorRevision |= (FamilyIdentifier & 0xf0) << 4; // Model
|
||||
CpuInfo.ProcessorRevision |= FamilyIdentifier & 0xf; // Stepping
|
||||
// 8-bits in CPUID 01.ebx for up to 256 cores.
|
||||
CpuInfo.MaximumProcessors = ((CPUIDResult01.ebx >> 16) & 0xFF) + 1;
|
||||
}
|
||||
|
||||
bool CPUFeatures::IsFeaturePresent(uint32_t Feature) {
|
||||
@@ -166,6 +168,7 @@ bool CPUFeatures::IsFeaturePresent(uint32_t Feature) {
|
||||
}
|
||||
|
||||
void CPUFeatures::UpdateInformation(SYSTEM_CPU_INFORMATION* Info) {
|
||||
Info->MaximumProcessors = CpuInfo.MaximumProcessors;
|
||||
Info->ProcessorArchitecture = CpuInfo.ProcessorArchitecture;
|
||||
Info->ProcessorLevel = CpuInfo.ProcessorLevel;
|
||||
Info->ProcessorRevision = CpuInfo.ProcessorRevision;
|
||||
|
||||
@@ -209,9 +209,6 @@ typedef struct _IMAGE_VOLATILE_RANGE_METADATA {
|
||||
|
||||
NTSYSAPI DWORD WINAPI RtlRunOnceExecuteOnce(PRTL_RUN_ONCE, PRTL_RUN_ONCE_INIT_FN, PVOID, PVOID*);
|
||||
|
||||
// This is a FEX extension, and requires corresponding wine patches
|
||||
#define CONTEXT_ARM64_FEX_YMMSTATE (CONTEXT_ARM64 | 0x00000040)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
# FEX-2611.1
|
||||
# FEX-2611
|
||||
|
||||
## FEXCore
|
||||
See [FEXCore/Readme.md](../FEXCore/Readme.md) for more details
|
||||
|
||||
@@ -16,7 +16,7 @@ struct core_info {
|
||||
uint32_t max_addressible_ids;
|
||||
uint32_t cores;
|
||||
uint32_t threads;
|
||||
bool HTT;
|
||||
bool SMT;
|
||||
};
|
||||
|
||||
struct cpuid_fn {
|
||||
@@ -42,7 +42,7 @@ std::optional<core_info> cpuid_calculate_core_info() {
|
||||
const auto cpuid_fn_1 = get_cpuid(1);
|
||||
|
||||
info.local_apicid = cpuid_fn_1.ebx >> 24;
|
||||
info.HTT = (cpuid_fn_1.edx >> 28) & 1;
|
||||
bool HTT = (cpuid_fn_1.edx >> 28) & 1;
|
||||
|
||||
const auto cpuid_fn_8000_0000 = get_cpuid(0x8000'0000U);
|
||||
|
||||
@@ -50,8 +50,10 @@ std::optional<core_info> cpuid_calculate_core_info() {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto cpuid_fn_8000_0001 = get_cpuid(0x8000'0001U);
|
||||
const auto cpuid_fn_8000_0008 = get_cpuid(0x8000'0008U);
|
||||
const uint32_t apic_id_size = (cpuid_fn_8000_0008.ecx >> 12) & 0xF;
|
||||
const bool CmpLegacy = cpuid_fn_8000_0001.ecx & 0b10;
|
||||
|
||||
// E.5.2: MNLP (Maximum Number of Logical Processors)
|
||||
uint32_t MNLP {};
|
||||
@@ -67,18 +69,24 @@ std::optional<core_info> cpuid_calculate_core_info() {
|
||||
info.max_addressible_ids = MNLP;
|
||||
|
||||
const auto cpuid_fn_4 = get_cpuid(4);
|
||||
if (cpuid_fn_4.eax & 0xF) {
|
||||
if (CmpLegacy && HTT) {
|
||||
// For CMPLegacy with HTT, number of "logical" cores is just func_1h_ebx[LogicalProcessorCount]
|
||||
info.threads = (cpuid_fn_1.ebx >> 16) & 0xFF;
|
||||
// Physical cores is just func_8000_0008.ecx[NC] + 1
|
||||
info.cores = (cpuid_fn_8000_0008.ecx & 0xFF) + 1;
|
||||
info.SMT = info.threads != info.cores;
|
||||
} else if (cpuid_fn_4.eax & 0xF) {
|
||||
// Intel exclusive cpuid function, AMD returns zero as unsupported.
|
||||
// `Maximum number of addressable IDs for processor cores in the physical package`
|
||||
info.cores = (cpuid_fn_4.eax >> 26) + 1;
|
||||
if (info.HTT) {
|
||||
if (HTT) {
|
||||
// `A value of 1 for HTT indicates the value in CPUID.1.EBX[23:16] (the Maximum number of addressable IDs for logical processors in
|
||||
// this package) is valid for the package. `Maximum number of addressable IDs for logical processors in this physical package`
|
||||
info.threads = (cpuid_fn_1.ebx >> 16) & 0xFF;
|
||||
} else {
|
||||
info.threads = info.cores;
|
||||
}
|
||||
} else if (info.HTT) {
|
||||
} else if (HTT) {
|
||||
info.cores = (cpuid_fn_1.ebx >> 16) & 0xFF;
|
||||
info.threads = info.cores * 2;
|
||||
} else {
|
||||
@@ -96,7 +104,7 @@ TEST_CASE("cpu count - cpuid") {
|
||||
CHECK(core_info->local_apicid < hw_concurrency);
|
||||
CHECK(core_info->local_apicid < core_info->max_addressible_ids);
|
||||
CHECK(core_info->max_addressible_ids >= hw_concurrency);
|
||||
if (core_info->HTT) {
|
||||
if (core_info->SMT) {
|
||||
// May not be entirely correct on systems that mix HTT and non-HTT cpu cores.
|
||||
CHECK((core_info->cores * 2) == core_info->threads);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef ARCH_GET_CPUID
|
||||
#define ARCH_GET_CPUID 0x1011
|
||||
#endif
|
||||
#ifndef ARCH_SET_CPUID
|
||||
#define ARCH_SET_CPUID 0x1012
|
||||
#endif
|
||||
|
||||
struct cpuid_fn {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
|
||||
static cpuid_fn get_cpuid(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile("cpuid" : "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx) : "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_looooong_cpuid(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x66, 0x66, 0x66, 0x66;"
|
||||
".byte 0x66, 0x66, 0x66, 0x66;"
|
||||
".byte 0x66, 0x66, 0x66, 0x66;"
|
||||
".byte 0x66;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_2(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x26;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_3(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x2e;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_4(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x36;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_5(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x3E;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_6(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x64;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_7(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x65;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_8(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x66;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_9(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x67;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_10(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0xF2;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static cpuid_fn get_cpuid_11(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0xf3;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
#ifdef REG_RIP
|
||||
// 0x40 isn't REX prefix on 32-bit.
|
||||
static cpuid_fn get_cpuid_12(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__asm volatile(".byte 0x40;"
|
||||
"cpuid"
|
||||
: "=a"(fn.eax), "=b"(fn.ebx), "=c"(fn.ecx), "=d"(fn.edx)
|
||||
: "a"(func), "c"(leaf));
|
||||
|
||||
return fn;
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t is_cpuid(uint8_t* data) {
|
||||
size_t inst_size {};
|
||||
|
||||
while (true) {
|
||||
if (inst_size == 15) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t byte = data[inst_size];
|
||||
|
||||
switch (byte) {
|
||||
case 0x26: // ES
|
||||
case 0x2e: // CS
|
||||
case 0x36: // SS
|
||||
case 0x3E: // DS
|
||||
case 0x64: // FS
|
||||
case 0x65: // GS
|
||||
case 0x66: // Opcode size
|
||||
case 0x67: // Addr size
|
||||
case 0xF2: // REPNE
|
||||
case 0xF3: // REPE
|
||||
#ifdef REG_RIP
|
||||
case 0x40 ... 0x4f: // REX
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xF0: return 0; // Lock explicitly isn't supported on CPUID, should fault.
|
||||
case 0xf: {
|
||||
++inst_size;
|
||||
byte = data[inst_size];
|
||||
if (byte == 0xa2) {
|
||||
return inst_size + 1;
|
||||
}
|
||||
|
||||
// Nope
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
++inst_size;
|
||||
}
|
||||
return inst_size;
|
||||
}
|
||||
|
||||
static int faults {};
|
||||
static void SignalHandler(int signal, siginfo_t* siginfo, void* context) {
|
||||
ucontext_t* _context = (ucontext_t*)context;
|
||||
|
||||
#ifdef REG_RIP
|
||||
#define FEX_IP_REG REG_RIP
|
||||
#define FEX_RAX_REG REG_RAX
|
||||
#define FEX_RBX_REG REG_RBX
|
||||
#define FEX_RCX_REG REG_RCX
|
||||
#define FEX_RDX_REG REG_RDX
|
||||
#else
|
||||
#define FEX_IP_REG REG_EIP
|
||||
#define FEX_RAX_REG REG_EAX
|
||||
#define FEX_RBX_REG REG_EBX
|
||||
#define FEX_RCX_REG REG_ECX
|
||||
#define FEX_RDX_REG REG_EDX
|
||||
#endif
|
||||
if (signal != SIGSEGV) {
|
||||
FAIL("Incorrect signal");
|
||||
}
|
||||
|
||||
if (_context->uc_mcontext.gregs[REG_TRAPNO] != 13) {
|
||||
FAIL("Incorrect trapno");
|
||||
}
|
||||
|
||||
if (_context->uc_mcontext.gregs[REG_ERR] != 0) {
|
||||
FAIL("Incorrect reg_err");
|
||||
}
|
||||
|
||||
if (siginfo->si_code != 0x80) {
|
||||
FAIL("Incorrect si_code");
|
||||
}
|
||||
|
||||
size_t inst_size = is_cpuid(reinterpret_cast<uint8_t*>(_context->uc_mcontext.gregs[FEX_IP_REG]));
|
||||
if (inst_size == 0) {
|
||||
FAIL("Isn't cpuid");
|
||||
}
|
||||
|
||||
// Return bogus data
|
||||
_context->uc_mcontext.gregs[FEX_RAX_REG] = 0x41424344U + faults;
|
||||
_context->uc_mcontext.gregs[FEX_RBX_REG] = 0x51525354U + faults;
|
||||
_context->uc_mcontext.gregs[FEX_RCX_REG] = 0x61626364U + faults;
|
||||
_context->uc_mcontext.gregs[FEX_RDX_REG] = 0x71727374U + faults;
|
||||
|
||||
_context->uc_mcontext.gregs[FEX_IP_REG] += inst_size;
|
||||
|
||||
++faults;
|
||||
}
|
||||
|
||||
TEST_CASE("cpuid faulting") {
|
||||
cpuid_fn fn0 = get_cpuid(0);
|
||||
if (syscall(SYS_arch_prctl, ARCH_SET_CPUID, (void*)1) != 0) {
|
||||
// Unsupported, just skip.
|
||||
return;
|
||||
}
|
||||
|
||||
struct sigaction act {};
|
||||
act.sa_sigaction = SignalHandler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGSEGV, &act, nullptr);
|
||||
|
||||
using ptr_type = cpuid_fn (*)(uint32_t, uint32_t);
|
||||
ptr_type test_funcs[] = {
|
||||
get_cpuid, get_cpuid_2, get_cpuid_3, get_cpuid_4, get_cpuid_5, get_cpuid_6,
|
||||
get_cpuid_7, get_cpuid_8, get_cpuid_9, get_cpuid_10, get_cpuid_11,
|
||||
#ifdef REG_RIP
|
||||
get_cpuid_12,
|
||||
#endif
|
||||
get_looooong_cpuid,
|
||||
};
|
||||
|
||||
// Just attempt regular CPUID for now.
|
||||
for (auto ptr : test_funcs) {
|
||||
faults = 0;
|
||||
cpuid_fn fn_emu = ptr(0, 0);
|
||||
REQUIRE(faults == 0);
|
||||
|
||||
CHECK(fn0.eax == fn_emu.eax);
|
||||
CHECK(fn0.ebx == fn_emu.ebx);
|
||||
CHECK(fn0.ecx == fn_emu.ecx);
|
||||
CHECK(fn0.edx == fn_emu.edx);
|
||||
}
|
||||
|
||||
// Enable faulting.
|
||||
REQUIRE(syscall(SYS_arch_prctl, ARCH_SET_CPUID, (void*)0) == 0);
|
||||
|
||||
for (auto ptr : test_funcs) {
|
||||
faults = 0;
|
||||
cpuid_fn fn_emu = ptr(0, 0);
|
||||
REQUIRE(faults == 1);
|
||||
|
||||
CHECK(fn0.eax != fn_emu.eax);
|
||||
CHECK(fn0.ebx != fn_emu.ebx);
|
||||
CHECK(fn0.ecx != fn_emu.ecx);
|
||||
CHECK(fn0.edx != fn_emu.edx);
|
||||
|
||||
CHECK(fn_emu.eax == 0x41424344U);
|
||||
CHECK(fn_emu.ebx == 0x51525354U);
|
||||
CHECK(fn_emu.ecx == 0x61626364U);
|
||||
CHECK(fn_emu.edx == 0x71727374U);
|
||||
}
|
||||
|
||||
// Disable faulting.
|
||||
REQUIRE(syscall(SYS_arch_prctl, ARCH_SET_CPUID, (void*)1) == 0);
|
||||
|
||||
// Just attempt regular CPUID for now.
|
||||
for (auto ptr : test_funcs) {
|
||||
faults = 0;
|
||||
cpuid_fn fn_emu = ptr(0, 0);
|
||||
REQUIRE(faults == 0);
|
||||
|
||||
CHECK(fn0.eax == fn_emu.eax);
|
||||
CHECK(fn0.ebx == fn_emu.ebx);
|
||||
CHECK(fn0.ecx == fn_emu.ecx);
|
||||
CHECK(fn0.edx == fn_emu.edx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "invalid_util.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef REG_RIP
|
||||
#define REG_RIP REG_EIP
|
||||
#endif
|
||||
|
||||
enum trapno {
|
||||
X86_TRAPNO_UD = 6,
|
||||
X86_TRAPNO_GP = 13,
|
||||
};
|
||||
|
||||
#define CONCAT(x, y) x##y
|
||||
#define TestSymbols(num) \
|
||||
extern "C" uint64_t CONCAT(TestBegin_, num); \
|
||||
extern "C" uint64_t CONCAT(TestEnd_, num);
|
||||
|
||||
#define Test(num, asm, trapno, errno, si_code, signal) \
|
||||
capturing_handler_skip = (unsigned long)&CONCAT(TestEnd_, num) - (unsigned long)&CONCAT(TestBegin_, num); \
|
||||
const unsigned long EXPECTED_RIP = (unsigned long)&CONCAT(TestBegin_, num); \
|
||||
const int EXPECTED_TRAPNO = trapno; \
|
||||
const int EXPECTED_ERR = errno; \
|
||||
const int EXPECTED_SI_CODE = si_code; \
|
||||
const int EXPECTED_SIGNAL = signal; \
|
||||
__asm volatile("TestBegin_" #num ":" asm ";" \
|
||||
"TestEnd_" #num ":" :: \
|
||||
: "memory");
|
||||
|
||||
#define TEST(num, name, asm, trapno, errno, _si_code, _signal) \
|
||||
TestSymbols(num); \
|
||||
TEST_CASE("Signals: " #name) { \
|
||||
struct sigaction act {}; \
|
||||
act.sa_sigaction = CapturingHandler; \
|
||||
act.sa_flags = SA_SIGINFO; \
|
||||
sigaction(SIGSEGV, &act, nullptr); \
|
||||
sigaction(SIGTRAP, &act, nullptr); \
|
||||
sigaction(SIGILL, &act, nullptr); \
|
||||
\
|
||||
Test(num, asm, trapno, errno, _si_code, _signal); \
|
||||
\
|
||||
REQUIRE(from_handler.has_value()); \
|
||||
CHECK(from_handler->mctx.gregs[REG_RIP] == EXPECTED_RIP); \
|
||||
CHECK(from_handler->mctx.gregs[REG_TRAPNO] == EXPECTED_TRAPNO); \
|
||||
CHECK(from_handler->mctx.gregs[REG_ERR] == EXPECTED_ERR); \
|
||||
CHECK(from_handler->si_code == EXPECTED_SI_CODE); \
|
||||
CHECK(from_handler->signal == EXPECTED_SIGNAL); \
|
||||
from_handler.reset(); \
|
||||
}
|
||||
|
||||
// Invalid group 7 row 5 instructions
|
||||
// 0xe8 is serialize, so skipped.
|
||||
TEST(0, "0xe9", ".byte 0x0f, 0x01, 0xe9", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(1, "0xea", ".byte 0x0f, 0x01, 0xea", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(2, "0xeb", ".byte 0x0f, 0x01, 0xeb", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(3, "0xec", ".byte 0x0f, 0x01, 0xec", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(4, "0xed", ".byte 0x0f, 0x01, 0xed", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
// Skipped as these are real instructions.
|
||||
// TEST(5, "rdpkru", "rdpkru", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
// TEST(6, "wrpkru", "wrpkru", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
|
||||
// Testing with prefixes as well.
|
||||
TEST(5, "0x66 0xe9", ".byte 0x66, 0x0f, 0x01, 0xe9", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(6, "0x66 0xea", ".byte 0x66, 0x0f, 0x01, 0xea", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(7, "0x66 0xeb", ".byte 0x66, 0x0f, 0x01, 0xeb", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(8, "0x66 0xec", ".byte 0x66, 0x0f, 0x01, 0xec", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(9, "0x66 0xed", ".byte 0x66, 0x0f, 0x01, 0xed", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
|
||||
TEST(10, "0xf2 0xe9", ".byte 0xf2, 0x0f, 0x01, 0xe9", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(11, "0xf2 0xea", ".byte 0xf2, 0x0f, 0x01, 0xea", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(12, "0xf2 0xeb", ".byte 0xf2, 0x0f, 0x01, 0xeb", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(13, "0xf2 0xec", ".byte 0xf2, 0x0f, 0x01, 0xec", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(14, "0xf2 0xed", ".byte 0xf2, 0x0f, 0x01, 0xed", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
|
||||
TEST(15, "0xf3 0xe9", ".byte 0xf3, 0x0f, 0x01, 0xe9", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(16, "0xf3 0xea", ".byte 0xf3, 0x0f, 0x01, 0xea", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(17, "0xf3 0xeb", ".byte 0xf3, 0x0f, 0x01, 0xeb", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(18, "0xf3 0xec", ".byte 0xf3, 0x0f, 0x01, 0xec", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(19, "0xf3 0xed", ".byte 0xf3, 0x0f, 0x01, 0xed", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
|
||||
#ifdef __x86_64__
|
||||
TEST(20, "0x48 0xe9", ".byte 0x48, 0x0f, 0x01, 0xe9", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(21, "0x48 0xea", ".byte 0x48, 0x0f, 0x01, 0xea", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(22, "0x48 0xeb", ".byte 0x48, 0x0f, 0x01, 0xeb", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(23, "0x48 0xec", ".byte 0x48, 0x0f, 0x01, 0xec", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(24, "0x48 0xed", ".byte 0x48, 0x0f, 0x01, 0xed", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
#endif
|
||||
|
||||
// Test row 5 with modrm.mod != 11, aka r/m == memory
|
||||
// These are all reserved as #UD.
|
||||
TEST(25, "0x28 mod==0", ".byte 0x0f, 0x01, 0x28", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(26, "0x29 mod==0", ".byte 0x0f, 0x01, 0x29", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(27, "0x2a mod==0", ".byte 0x0f, 0x01, 0x2a", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(28, "0x2b mod==0", ".byte 0x0f, 0x01, 0x2b", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(29, "0x2c mod==0", ".byte 0x0f, 0x01, 0x2c", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(30, "0x2d mod==0", ".byte 0x0f, 0x01, 0x2d", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(31, "0x2e mod==0", ".byte 0x0f, 0x01, 0x2e", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
TEST(32, "0x2f mod==0", ".byte 0x0f, 0x01, 0x2f", X86_TRAPNO_UD, 0, 2, SIGILL);
|
||||
@@ -28,7 +28,7 @@ static void SIGSEGV_Handler(int signal, siginfo_t* siginfo, void* context) {
|
||||
TEST_CASE("Signals: Test No-Exec") {
|
||||
struct sigaction act {};
|
||||
act.sa_sigaction = SIGSEGV_Handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_flags = SA_SIGINFO | SA_NODEFER;
|
||||
|
||||
sigaction(SIGSEGV, &act, nullptr);
|
||||
auto PageSize = sysconf(_SC_PAGESIZE);
|
||||
@@ -71,7 +71,7 @@ TEST_CASE("Signals: Test No-Exec") {
|
||||
TEST_CASE("Signals: Partial decode") {
|
||||
struct sigaction act {};
|
||||
act.sa_sigaction = SIGSEGV_Handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_flags = SA_SIGINFO | SA_NODEFER;
|
||||
|
||||
sigaction(SIGSEGV, &act, nullptr);
|
||||
auto PageSize = sysconf(_SC_PAGESIZE);
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iterator>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
// Single-stepping with TF over CPUID and SYSCALL.
|
||||
//
|
||||
// Both instructions leave the JIT block: CPUID runs through a dispatcher stub, SYSCALL through the syscall handler,
|
||||
// and both return to guest code through an L1 cache lookup. With TF set the trap must still land on the instruction
|
||||
// after CPUID/SYSCALL and on every instruction that follows.
|
||||
//
|
||||
// The lookup only hits when the code behind the instruction is already compiled, so each probe runs from its `Warm`
|
||||
// label once with TF clear. The stepped run shares nothing else with that first run: it sets TF in a lead-in of its
|
||||
// own that jumps onto the CPUID/SYSCALL instruction, and the handler clears TF when the trap on the final RET
|
||||
// arrives. The only compiled block the stepped run can enter is then the one behind CPUID/SYSCALL.
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wattributes" // Suppress warning in case control-flow checks aren't enabled
|
||||
|
||||
extern "C" void ProbeCPUID();
|
||||
extern "C" void ProbeCPUIDWarm();
|
||||
extern "C" void TF_CPUID_1();
|
||||
extern "C" void TF_CPUID_2();
|
||||
extern "C" void TF_CPUID_3();
|
||||
extern "C" void TF_CPUID_4();
|
||||
extern "C" void TF_CPUID_5();
|
||||
extern "C" void TF_CPUID_6();
|
||||
extern "C" void TF_CPUID_7();
|
||||
|
||||
// Sets TF. Every instruction after the first one then traps, up to the RET where the handler clears TF.
|
||||
extern "C" __attribute__((naked, nocf_check)) void ProbeCPUID() {
|
||||
__asm volatile(R"(
|
||||
pushfq;
|
||||
or qword ptr [rsp], 0x100;
|
||||
popfq;
|
||||
push rbx;
|
||||
TF_CPUID_1:
|
||||
xor eax, eax;
|
||||
TF_CPUID_2:
|
||||
jmp TF_CPUID_3;
|
||||
|
||||
ProbeCPUIDWarm:
|
||||
push rbx;
|
||||
xor eax, eax;
|
||||
TF_CPUID_3:
|
||||
cpuid;
|
||||
TF_CPUID_4:
|
||||
nop;
|
||||
TF_CPUID_5:
|
||||
nop;
|
||||
TF_CPUID_6:
|
||||
pop rbx;
|
||||
TF_CPUID_7:
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
extern "C" void ProbeSYSCALL();
|
||||
extern "C" void ProbeSYSCALLWarm();
|
||||
extern "C" void TF_SYSCALL_1();
|
||||
extern "C" void TF_SYSCALL_2();
|
||||
extern "C" void TF_SYSCALL_3();
|
||||
extern "C" void TF_SYSCALL_4();
|
||||
extern "C" void TF_SYSCALL_5();
|
||||
|
||||
extern "C" __attribute__((naked, nocf_check)) void ProbeSYSCALL() {
|
||||
__asm volatile(R"(
|
||||
pushfq;
|
||||
or qword ptr [rsp], 0x100;
|
||||
popfq;
|
||||
mov eax, 39;
|
||||
TF_SYSCALL_1:
|
||||
jmp TF_SYSCALL_2;
|
||||
|
||||
ProbeSYSCALLWarm:
|
||||
mov eax, 39;
|
||||
TF_SYSCALL_2:
|
||||
syscall;
|
||||
TF_SYSCALL_3:
|
||||
nop;
|
||||
TF_SYSCALL_4:
|
||||
nop;
|
||||
TF_SYSCALL_5:
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
constexpr int MAX_TRAPS = 32;
|
||||
static uintptr_t trap_rips[MAX_TRAPS];
|
||||
static int trap_count;
|
||||
static int trap_bad_si_code;
|
||||
static uintptr_t trap_last_rip;
|
||||
|
||||
static void TrapHandler(int, siginfo_t* siginfo, void* context) {
|
||||
auto* ctx = static_cast<ucontext_t*>(context);
|
||||
const uintptr_t rip = ctx->uc_mcontext.gregs[REG_RIP];
|
||||
if (trap_count < MAX_TRAPS) {
|
||||
trap_rips[trap_count] = rip;
|
||||
}
|
||||
trap_count++;
|
||||
if (siginfo->si_code != TRAP_TRACE) {
|
||||
trap_bad_si_code++;
|
||||
}
|
||||
// Stop stepping on the probe's RET, or once the traps have run away from the probe.
|
||||
if (rip == trap_last_rip || trap_count >= MAX_TRAPS) {
|
||||
ctx->uc_mcontext.gregs[REG_EFL] &= ~0x100;
|
||||
}
|
||||
}
|
||||
|
||||
static void InstallTrapHandler(void (*last)()) {
|
||||
struct sigaction act {};
|
||||
act.sa_sigaction = TrapHandler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGTRAP, &act, nullptr);
|
||||
trap_count = 0;
|
||||
trap_bad_si_code = 0;
|
||||
trap_last_rip = reinterpret_cast<uintptr_t>(last);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
static void CheckTraps(const uintptr_t (&expected)[N]) {
|
||||
REQUIRE(trap_count == N);
|
||||
CHECK(trap_bad_si_code == 0);
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
INFO("trap " << i);
|
||||
CHECK(trap_rips[i] == expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Signals: Trap Flag across CPUID") {
|
||||
ProbeCPUIDWarm();
|
||||
InstallTrapHandler(&TF_CPUID_7);
|
||||
ProbeCPUID();
|
||||
|
||||
const uintptr_t expected[] = {
|
||||
reinterpret_cast<uintptr_t>(&TF_CPUID_1), reinterpret_cast<uintptr_t>(&TF_CPUID_2), reinterpret_cast<uintptr_t>(&TF_CPUID_3),
|
||||
reinterpret_cast<uintptr_t>(&TF_CPUID_4), reinterpret_cast<uintptr_t>(&TF_CPUID_5), reinterpret_cast<uintptr_t>(&TF_CPUID_6),
|
||||
reinterpret_cast<uintptr_t>(&TF_CPUID_7),
|
||||
};
|
||||
CheckTraps(expected);
|
||||
}
|
||||
|
||||
TEST_CASE("Signals: Trap Flag across SYSCALL") {
|
||||
ProbeSYSCALLWarm();
|
||||
InstallTrapHandler(&TF_SYSCALL_5);
|
||||
ProbeSYSCALL();
|
||||
|
||||
// Where the trap after SYSCALL lands depends on the kernel's return path. FEX and a FRED kernel trap before the
|
||||
// next instruction runs. A kernel returning through IRET does not trap after the IRET itself, so the first trap
|
||||
// after the syscall lands after the following instruction.
|
||||
const uintptr_t trap_after_syscall[] = {
|
||||
reinterpret_cast<uintptr_t>(&TF_SYSCALL_1), reinterpret_cast<uintptr_t>(&TF_SYSCALL_2), reinterpret_cast<uintptr_t>(&TF_SYSCALL_3),
|
||||
reinterpret_cast<uintptr_t>(&TF_SYSCALL_4), reinterpret_cast<uintptr_t>(&TF_SYSCALL_5),
|
||||
};
|
||||
const uintptr_t trap_after_next[] = {
|
||||
reinterpret_cast<uintptr_t>(&TF_SYSCALL_1),
|
||||
reinterpret_cast<uintptr_t>(&TF_SYSCALL_2),
|
||||
reinterpret_cast<uintptr_t>(&TF_SYSCALL_4),
|
||||
reinterpret_cast<uintptr_t>(&TF_SYSCALL_5),
|
||||
};
|
||||
if (trap_count == std::size(trap_after_next)) {
|
||||
CheckTraps(trap_after_next);
|
||||
} else {
|
||||
CheckTraps(trap_after_syscall);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"roundss xmm0, xmm1, 00000000b": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"AFP"
|
||||
],
|
||||
"DisabledHostFeatures": [],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtpi2ps xmm0, [rax]": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"DisabledHostFeatures": [
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2ss xmm0, eax": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"AFP"
|
||||
],
|
||||
"DisabledHostFeatures": [],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2sd xmm0, eax": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtpi2ps xmm0, [rax]": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2ss xmm0, eax": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2sd xmm0, eax": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"DisabledHostFeatures": [
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vsqrtss xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"AFP"
|
||||
],
|
||||
"DisabledHostFeatures": [],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vroundss xmm0, xmm1, 00000000b": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vfmaddsubps xmm0, xmm1, xmm2, xmm3": {
|
||||
@@ -22,7 +22,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -38,7 +38,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -54,7 +54,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -70,7 +70,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -86,7 +86,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -102,7 +102,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -118,7 +118,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -134,7 +134,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -150,7 +150,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -166,7 +166,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -182,7 +182,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -198,7 +198,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -214,7 +214,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -230,7 +230,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -246,7 +246,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -262,7 +262,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -278,7 +278,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -294,7 +294,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -310,7 +310,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -326,7 +326,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -342,7 +342,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -358,7 +358,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -374,7 +374,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -390,7 +390,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -406,7 +406,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -422,7 +422,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -438,7 +438,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -454,7 +454,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -470,7 +470,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -486,7 +486,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vmovups xmm0, xmm0": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vaddsubpd xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"FLAGM2",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vmovntps [rax], xmm0": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vucomiss xmm0, xmm1": {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"I8MM",
|
||||
"DOTPROD"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpshufb xmm0, xmm1, xmm2": {
|
||||
@@ -2224,7 +2224,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2241,7 +2241,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2258,7 +2258,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2275,7 +2275,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2292,7 +2292,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2309,7 +2309,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2326,7 +2326,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2343,7 +2343,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2360,7 +2360,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2377,7 +2377,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2394,7 +2394,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -2411,7 +2411,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6268,7 +6268,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6284,7 +6284,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6300,7 +6300,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6316,7 +6316,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6457,7 +6457,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6474,7 +6474,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6491,7 +6491,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6508,7 +6508,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6525,7 +6525,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6542,7 +6542,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6559,7 +6559,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6576,7 +6576,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6593,7 +6593,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6610,7 +6610,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6627,7 +6627,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -6644,7 +6644,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vfmadd132ss xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"SVE256",
|
||||
"I8MM"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpdpbusd xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpdpbusd xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"FLAGM2",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vmovntdqa xmm0, [rax]": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"SVE256",
|
||||
"SVEBITPERM"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vtestps xmm0, xmm1": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpermq ymm0, ymm1, 1": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"AFP",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vblendvps xmm0, xmm1, xmm2, xmm3": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpsrlw xmm0, xmm1, 0": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"FLAGM",
|
||||
"FLAGM2"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"lock add byte [rax], cl": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"sha1nexte xmm0, xmm1": {
|
||||
@@ -91,7 +91,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -107,7 +107,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
@@ -123,7 +123,7 @@
|
||||
"mov w0, #0x401",
|
||||
"str x0, [x28, #1296]",
|
||||
"str x20, [x28, #1304]",
|
||||
"ldr x0, [x28, #2800]",
|
||||
"ldr x0, [x28, #2808]",
|
||||
"br x0"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"sha1nexte xmm0, xmm1": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"pclmulqdq xmm0, xmm1, 00000b": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"AFP",
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These 3DNow! instructions are optimal assuming that FEX doesn't SRA MMX registers",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
|
||||
|
||||
@@ -13,36 +13,12 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
],
|
||||
"Instructions": {
|
||||
"cpuid constant": {
|
||||
"x86InstructionCount": 2,
|
||||
"ExpectedInstructionCount": 11,
|
||||
"Comment": [
|
||||
"CPUID function call with constant function id"
|
||||
],
|
||||
"x86Insts": [
|
||||
"mov rax, 0",
|
||||
"cpuid"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"mov w4, #0x0",
|
||||
"isb",
|
||||
"mov w20, #0x16",
|
||||
"mov w6, #0x6547",
|
||||
"movk w6, #0x756e, lsl #16",
|
||||
"mov w21, #0x746e",
|
||||
"movk w21, #0x6c65, lsl #16",
|
||||
"mov w5, #0x6e69",
|
||||
"movk w5, #0x4965, lsl #16",
|
||||
"mov x7, x21",
|
||||
"mov x4, x20"
|
||||
]
|
||||
},
|
||||
"xgetbv constant": {
|
||||
"x86InstructionCount": 2,
|
||||
"ExpectedInstructionCount": 3,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"I8MM",
|
||||
"DOTPROD"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"This file tracks the translations for the 'peephole' optimizations in FEX.",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"FLAGM2",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"This file tracks the translations for the 'peephole' optimizations in FEX.",
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [],
|
||||
"Instructions": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"lock add byte [rax], cl": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"Chained add": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"ptest xmm0, xmm1": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"The Witcher 3": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"Sonic Mania movie player": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"FMOD scalar loop": {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"The Sims 1 hot block": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"add bl, cl": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"add al, 1": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"push es": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 43
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"ucomiss xmm0, xmm1": {
|
||||
|
||||
Loaded 100 of 159 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user