mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-11-11 17:11:38 -10:00
Compare commits
45
Commits
FEX-2611_1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab135df091 | ||
|
|
059a623b41 | ||
|
|
9143ccaf2b | ||
|
|
afee4dcc9e | ||
|
|
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
|
||||
@@ -665,11 +665,11 @@ void Arm64Emitter::FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Regi
|
||||
// We don't bother spilling these in SpillStaticRegs,
|
||||
// since all that matters is we restore them on a fill.
|
||||
// It's not a concern if they get trounced by something else.
|
||||
if (EmitterCTX->HostFeatures.SupportsSVE256) {
|
||||
if (EmitterCTX->HostFeatures.SupportsSVE256()) {
|
||||
ptrue(ARMEmitter::SubRegSize::i8Bit, PRED_TMP_32B, ARMEmitter::PredicatePattern::SVE_VL32);
|
||||
}
|
||||
|
||||
if (EmitterCTX->HostFeatures.SupportsSVE128) {
|
||||
if (EmitterCTX->HostFeatures.SupportsSVE128()) {
|
||||
ptrue(ARMEmitter::SubRegSize::i8Bit, PRED_TMP_16B, ARMEmitter::PredicatePattern::SVE_VL16);
|
||||
}
|
||||
|
||||
@@ -739,7 +739,7 @@ void Arm64Emitter::SpillStaticRegs(ARMEmitter::Register TmpReg, SpillStaticRegOp
|
||||
}
|
||||
|
||||
if (Options.FPRs) {
|
||||
if (EmitterCTX->HostFeatures.SupportsAVX && EmitterCTX->HostFeatures.SupportsSVE256) {
|
||||
if (EmitterCTX->HostFeatures.SupportsAVX() && EmitterCTX->HostFeatures.SupportsSVE256()) {
|
||||
for (size_t i = 0; i < StaticFPRegisters.size(); i++) {
|
||||
const auto Reg = StaticFPRegisters[i];
|
||||
|
||||
@@ -826,7 +826,7 @@ void Arm64Emitter::FillStaticRegs(FillStaticRegOptions Options) {
|
||||
FillSpecialRegs(TmpReg, TmpReg2, {.SetFIZ = true, .SetPredRegs = Options.FPRs});
|
||||
|
||||
if (Options.FPRs) {
|
||||
if (EmitterCTX->HostFeatures.SupportsAVX && EmitterCTX->HostFeatures.SupportsSVE256) {
|
||||
if (EmitterCTX->HostFeatures.SupportsAVX() && EmitterCTX->HostFeatures.SupportsSVE256()) {
|
||||
for (size_t i = 0; i < StaticFPRegisters.size(); i++) {
|
||||
const auto Reg = StaticFPRegisters[i];
|
||||
if (((1U << Reg.Idx()) & Options.FPRFillMask) != 0) {
|
||||
@@ -990,7 +990,7 @@ void Arm64Emitter::PopGeneralRegisters(std::span<const ARMEmitter::Register> Reg
|
||||
}
|
||||
|
||||
size_t Arm64Emitter::PushDynamicRegs(ARMEmitter::Register TmpReg) {
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256;
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256();
|
||||
const auto GPRSize = GeneralRegistersNotPreserved.size() * Core::CPUState::GPR_REG_SIZE;
|
||||
const auto FPRRegSize = CanUseSVE256 ? 32 : 16;
|
||||
const auto FPRSize = GeneralFPRegisters.size() * FPRRegSize;
|
||||
@@ -1013,7 +1013,7 @@ size_t Arm64Emitter::PushDynamicRegs(ARMEmitter::Register TmpReg) {
|
||||
}
|
||||
|
||||
void Arm64Emitter::PopDynamicRegs() {
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256;
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256();
|
||||
|
||||
// Pop vectors first
|
||||
PopVectorRegisters(CanUseSVE256, GeneralFPRegisters);
|
||||
@@ -1023,7 +1023,7 @@ void Arm64Emitter::PopDynamicRegs() {
|
||||
}
|
||||
|
||||
size_t Arm64Emitter::SpillForPreserveAllABICall(ARMEmitter::Register TmpReg, bool FPRs) {
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256;
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256();
|
||||
const auto FPRRegSize = CanUseSVE256 ? 32 : 16;
|
||||
|
||||
std::span<const ARMEmitter::Register> DynamicGPRs {};
|
||||
@@ -1078,7 +1078,7 @@ size_t Arm64Emitter::SpillForPreserveAllABICall(ARMEmitter::Register TmpReg, boo
|
||||
}
|
||||
|
||||
void Arm64Emitter::FillForPreserveAllABICall(bool FPRs) {
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256;
|
||||
const auto CanUseSVE256 = EmitterCTX->HostFeatures.SupportsSVE256();
|
||||
|
||||
std::span<const ARMEmitter::Register> DynamicGPRs {};
|
||||
std::span<const ARMEmitter::VRegister> DynamicFPRs {};
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -443,7 +443,7 @@ void CPUIDEmu::SetupHostHybridFlag() {}
|
||||
|
||||
|
||||
void CPUIDEmu::SetupFeatures() {
|
||||
if (CTX->HostFeatures.SupportsAVX) {
|
||||
if (CTX->HostFeatures.SupportsAVX()) {
|
||||
XCR0 |= XCR0_AVX;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1162,14 +1166,14 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0004h(uint32_t Leaf) con
|
||||
|
||||
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0002h(uint32_t Leaf, uint32_t CPU) const {
|
||||
FEXCore::CPUID::FunctionResults Res {};
|
||||
auto& Data = PerCPUData[CPU];
|
||||
auto& Data = PerCPUData[std::min<uint32_t>(CPU, PerCPUData.size() - 1)];
|
||||
memcpy(&Res, Data.ProductName, std::min(strlen(Data.ProductName), sizeof(FEXCore::CPUID::FunctionResults)));
|
||||
return Res;
|
||||
}
|
||||
|
||||
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0003h(uint32_t Leaf, uint32_t CPU) const {
|
||||
FEXCore::CPUID::FunctionResults Res {};
|
||||
auto& Data = PerCPUData[CPU];
|
||||
auto& Data = PerCPUData[std::min<uint32_t>(CPU, PerCPUData.size() - 1)];
|
||||
const auto RemainingStringSize = std::max<ssize_t>(0, strlen(Data.ProductName) - 16);
|
||||
memcpy(&Res, Data.ProductName + 16, std::min<size_t>(RemainingStringSize, sizeof(FEXCore::CPUID::FunctionResults)));
|
||||
return Res;
|
||||
@@ -1177,7 +1181,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0003h(uint32_t Leaf, uin
|
||||
|
||||
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0004h(uint32_t Leaf, uint32_t CPU) const {
|
||||
FEXCore::CPUID::FunctionResults Res {};
|
||||
auto& Data = PerCPUData[CPU];
|
||||
auto& Data = PerCPUData[std::min<uint32_t>(CPU, PerCPUData.size() - 1)];
|
||||
const auto RemainingStringSize = std::max<ssize_t>(0, strlen(Data.ProductName) - 32);
|
||||
memcpy(&Res, Data.ProductName + 32, std::min<size_t>(RemainingStringSize, sizeof(FEXCore::CPUID::FunctionResults)));
|
||||
return Res;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -264,8 +264,8 @@ uint32_t ContextImpl::ReconstructCompactedEFLAGS(FEXCore::Core::InternalThreadSt
|
||||
void ContextImpl::ReconstructXMMRegisters(const FEXCore::Core::InternalThreadState* Thread, __uint128_t* XMM_Low, __uint128_t* YMM_High) {
|
||||
const size_t MaximumRegisters = Config.Is64BitMode ? FEXCore::Core::CPUState::NUM_XMMS : 8;
|
||||
|
||||
if (YMM_High != nullptr && HostFeatures.SupportsAVX) {
|
||||
const bool SupportsConvergedRegisters = HostFeatures.SupportsSVE256;
|
||||
if (YMM_High != nullptr && HostFeatures.SupportsAVX()) {
|
||||
const bool SupportsConvergedRegisters = HostFeatures.SupportsSVE256();
|
||||
|
||||
if (SupportsConvergedRegisters) {
|
||||
///< Output wants to de-interleave
|
||||
@@ -288,8 +288,8 @@ void ContextImpl::ReconstructXMMRegisters(const FEXCore::Core::InternalThreadSta
|
||||
|
||||
void ContextImpl::SetXMMRegistersFromState(FEXCore::Core::InternalThreadState* Thread, const __uint128_t* XMM_Low, const __uint128_t* YMM_High) {
|
||||
const size_t MaximumRegisters = Config.Is64BitMode ? FEXCore::Core::CPUState::NUM_XMMS : 8;
|
||||
if (YMM_High != nullptr && HostFeatures.SupportsAVX) {
|
||||
const bool SupportsConvergedRegisters = HostFeatures.SupportsSVE256;
|
||||
if (YMM_High != nullptr && HostFeatures.SupportsAVX()) {
|
||||
const bool SupportsConvergedRegisters = HostFeatures.SupportsSVE256();
|
||||
|
||||
if (SupportsConvergedRegisters) {
|
||||
///< Output wants to de-interleave
|
||||
|
||||
@@ -409,6 +409,12 @@ namespace DiskCache {
|
||||
uint64_t HostFeaturesHash;
|
||||
} MachineBucketData = {FormatVersion, HostFeatureHash.HostFeaturesHash};
|
||||
|
||||
uint8_t ProcessFeaturesHash {};
|
||||
memcpy(&ProcessFeaturesHash, &HostFeatureHash.ProcessFeaturesHash, sizeof(ProcessFeaturesHash));
|
||||
LogMan::Msg::IFmt("Disk Cache features:");
|
||||
LogMan::Msg::IFmt("HostFeatures Hash: 0x{:016x}", HostFeatureHash.HostFeaturesHash);
|
||||
LogMan::Msg::IFmt("ProcessFeaturesHash: 0x{:02x}", ProcessFeaturesHash);
|
||||
|
||||
fextl::vector<uint8_t> BucketBytes(sizeof(MachineBucketData) + sizeof(HostFeatureHash.ProcessFeaturesHash) + SerializedConfig.size());
|
||||
memcpy(BucketBytes.data(), &MachineBucketData, sizeof(MachineBucketData));
|
||||
|
||||
|
||||
@@ -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 = 42;
|
||||
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 {};
|
||||
|
||||
@@ -79,10 +79,10 @@ Decoder::Decoder(FEXCore::Core::InternalThreadState* Thread)
|
||||
X87Table = &FEXCore::X86Tables::X87F80Ops;
|
||||
}
|
||||
|
||||
if (CTX->HostFeatures.SupportsAVX && CTX->HostFeatures.SupportsSVE256) {
|
||||
if (CTX->HostFeatures.SupportsAVX() && CTX->HostFeatures.SupportsSVE256()) {
|
||||
VEXTable = &FEXCore::X86Tables::VEXTableOps;
|
||||
VEXTableGroup = &FEXCore::X86Tables::VEXTableGroupOps;
|
||||
} else if (CTX->HostFeatures.SupportsAVX) {
|
||||
} else if (CTX->HostFeatures.SupportsAVX()) {
|
||||
VEXTable = &FEXCore::X86Tables::VEXTableOps_AVX128;
|
||||
VEXTableGroup = &FEXCore::X86Tables::VEXTableGroupOps_AVX128;
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -625,9 +625,9 @@ void Arm64JITCore::Op_NoOp(const IR::IROp_Header* IROp, IR::Ref Node) {}
|
||||
Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl* ctx, FEXCore::Core::InternalThreadState* Thread)
|
||||
: CPUBackend(*ctx, Thread)
|
||||
, Arm64Emitter(ctx)
|
||||
, HostSupportsSVE128 {ctx->HostFeatures.SupportsSVE128 != 0}
|
||||
, HostSupportsSVE256 {ctx->HostFeatures.SupportsSVE256 != 0}
|
||||
, HostSupportsAVX256 {ctx->HostFeatures.SupportsAVX && ctx->HostFeatures.SupportsSVE256}
|
||||
, HostSupportsSVE128 {ctx->HostFeatures.SupportsSVE128()}
|
||||
, HostSupportsSVE256 {ctx->HostFeatures.SupportsSVE256()}
|
||||
, HostSupportsAVX256 {ctx->HostFeatures.SupportsAVX() && ctx->HostFeatures.SupportsSVE256()}
|
||||
, HostSupportsRPRES {ctx->HostFeatures.SupportsRPRES != 0}
|
||||
, HostSupportsAFP {ctx->HostFeatures.SupportsAFP != 0}
|
||||
, CTX {ctx}
|
||||
|
||||
@@ -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) {
|
||||
@@ -4752,11 +4751,11 @@ OpDispatchBuilder::OpDispatchBuilder(FEXCore::Context::ContextImpl* ctx, FEXCore
|
||||
: IREmitter {ctx->OpDispatcherAllocator, ctx->HostFeatures.SupportsTSOImm9 != 0}
|
||||
, CTX {ctx}
|
||||
, Thread {Thread} {
|
||||
if (CTX->HostFeatures.SupportsAVX && CTX->HostFeatures.SupportsSVE256) {
|
||||
if (CTX->HostFeatures.SupportsAVX() && CTX->HostFeatures.SupportsSVE256()) {
|
||||
SaveAVXStateFunc = &OpDispatchBuilder::SaveAVXState;
|
||||
RestoreAVXStateFunc = &OpDispatchBuilder::RestoreAVXState;
|
||||
DefaultAVXStateFunc = &OpDispatchBuilder::DefaultAVXState;
|
||||
} else if (CTX->HostFeatures.SupportsAVX) {
|
||||
} else if (CTX->HostFeatures.SupportsAVX()) {
|
||||
SaveAVXStateFunc = &OpDispatchBuilder::AVX128_SaveAVXState;
|
||||
RestoreAVXStateFunc = &OpDispatchBuilder::AVX128_RestoreAVXState;
|
||||
DefaultAVXStateFunc = &OpDispatchBuilder::AVX128_DefaultAVXState;
|
||||
|
||||
@@ -1330,7 +1330,7 @@ protected:
|
||||
/* On ASIMD platforms, the emulation happens to preserve NZCV, unlike the
|
||||
* more optimal SVE implementation that clobbers.
|
||||
*/
|
||||
if (!CTX->HostFeatures.SupportsSVE128 && !CTX->HostFeatures.SupportsSVE256) {
|
||||
if (!CTX->HostFeatures.SupportsSVE()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1677,7 +1677,7 @@ private:
|
||||
}
|
||||
|
||||
constexpr OpSize GetGuestVectorLength() const {
|
||||
return (CTX->HostFeatures.SupportsSVE256 && CTX->HostFeatures.SupportsAVX) ? OpSize::i256Bit : OpSize::i128Bit;
|
||||
return (CTX->HostFeatures.SupportsSVE256() && CTX->HostFeatures.SupportsAVX()) ? OpSize::i256Bit : OpSize::i128Bit;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
|
||||
@@ -2067,7 +2067,7 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherImpl(OpcodeArgs, Op
|
||||
BaseAddr = Invalid();
|
||||
}
|
||||
|
||||
if (CTX->HostFeatures.SupportsSVE128) {
|
||||
if (CTX->HostFeatures.SupportsSVE128()) {
|
||||
if (ElementLoadSize == OpSize::i64Bit && AddrElementSize == OpSize::i32Bit) {
|
||||
// In the case that FEX is loading double the amount of data than the number of address bits then we can optimize this case.
|
||||
// For 256-bits of data we need to sign extend all four 32-bit address elements to be 64-bit.
|
||||
@@ -2170,7 +2170,7 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherQPSImpl(OpcodeArgs,
|
||||
|
||||
bool NeedsSVEScale = (VSIB.Scale == 2 || VSIB.Scale == 8) || (BaseAddr == Invalid() && VSIB.Scale != 1);
|
||||
|
||||
if (CTX->HostFeatures.SupportsSVE128 && NeedsSVEScale) {
|
||||
if (CTX->HostFeatures.SupportsSVE128() && NeedsSVEScale) {
|
||||
// SVE gather instructions don't support scaling their vector elements by anything other than 1 or the address element size.
|
||||
// Pre-scale 64-bit addresses in the case that scale doesn't match in-order to hit SVE code paths more frequently.
|
||||
// Only hit this path if the host supports SVE. Otherwise it's a degradation for the ASIMD codepath.
|
||||
@@ -2236,7 +2236,7 @@ void OpDispatchBuilder::AVX128_VPGATHER(OpcodeArgs, OpSize AddrElementSize) {
|
||||
bool NeedsSVEScale = (VSIB.Scale == 2 || VSIB.Scale == 8) || (VSIB.BaseAddr == Invalid() && VSIB.Scale != 1);
|
||||
|
||||
const bool NeedsExplicitSVEPath =
|
||||
CTX->HostFeatures.SupportsSVE128 && AddrElementSize == OpSize::i32Bit && ElementLoadSize == OpSize::i32Bit && NeedsSVEScale;
|
||||
CTX->HostFeatures.SupportsSVE128() && AddrElementSize == OpSize::i32Bit && ElementLoadSize == OpSize::i32Bit && NeedsSVEScale;
|
||||
|
||||
RefPair Result {};
|
||||
if (NeedsExplicitSVEPath) {
|
||||
|
||||
@@ -27,7 +27,7 @@ void OpDispatchBuilder::SHA1NEXTEOp(OpcodeArgs) {
|
||||
Ref Src = LoadSourceFPR(Op, Op->Src[0], Op->Flags);
|
||||
|
||||
Ref Result {};
|
||||
if (CTX->HostFeatures.SupportsSVE128) {
|
||||
if (CTX->HostFeatures.SupportsSVE128()) {
|
||||
auto ZeroVec = LoadZeroVector(OpSize::i128Bit);
|
||||
auto Tmp = _VInsElement(OpSize::i128Bit, OpSize::i32Bit, 3, 3, ZeroVec, Dest);
|
||||
auto Xar = _VXar(OpSize::i128Bit, OpSize::i32Bit, ZeroVec, Tmp, 2);
|
||||
|
||||
@@ -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
|
||||
@@ -201,6 +201,8 @@ constexpr DispatchTableEntry OpDispatch_SecondaryRepNEModTables[] = {
|
||||
{0x79, 1, &OpDispatchBuilder::Insertq},
|
||||
{0x7C, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::VectorALUOp, IR::OP_VFADDP, OpSize::i32Bit>},
|
||||
{0x7D, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::HSUBP, OpSize::i32Bit>},
|
||||
{0xBC, 1, &OpDispatchBuilder::BSFOp},
|
||||
{0xBD, 1, &OpDispatchBuilder::BSROp},
|
||||
{0xD0, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ADDSUBPOp, OpSize::i32Bit>},
|
||||
{0xD6, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::MOVQ2DQ, false>},
|
||||
{0xC2, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::InsertScalarFCMPOp, OpSize::i64Bit>},
|
||||
|
||||
@@ -3025,7 +3025,7 @@ void OpDispatchBuilder::XSaveOpImpl(OpcodeArgs) {
|
||||
StoreIfFlagSet(1, [this, Op] { SaveSSEState(XSaveBase(Op)); });
|
||||
}
|
||||
// AVX
|
||||
if (CTX->HostFeatures.SupportsAVX) {
|
||||
if (CTX->HostFeatures.SupportsAVX()) {
|
||||
StoreIfFlagSet(2, [this, Op] { std::invoke(SaveAVXStateFunc, this, XSaveBase(Op)); });
|
||||
}
|
||||
|
||||
@@ -3232,7 +3232,7 @@ void OpDispatchBuilder::XRstorOpImpl(OpcodeArgs) {
|
||||
RestoreIfFlagSetOrDefault(1, [this, Op] { RestoreSSEState(XSaveBase(Op)); }, [this] { DefaultSSEState(); });
|
||||
}
|
||||
// AVX
|
||||
if (CTX->HostFeatures.SupportsAVX) {
|
||||
if (CTX->HostFeatures.SupportsAVX()) {
|
||||
RestoreIfFlagSetOrDefault(
|
||||
2, [this, Op] { std::invoke(RestoreAVXStateFunc, this, XSaveBase(Op)); }, [this] { std::invoke(DefaultAVXStateFunc, this); });
|
||||
}
|
||||
|
||||
@@ -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}},
|
||||
@@ -454,10 +454,13 @@ constexpr std::array<X86InstInfo, MAX_REPNE_MOD_TABLE_SIZE> RepNEModOps = []() c
|
||||
{0x90, 16, X86InstInfo{"", TYPE_COPY_OTHER, FLAGS_NONE, 0}},
|
||||
{0xA0, 16, X86InstInfo{"", TYPE_COPY_OTHER, FLAGS_NONE, 0}},
|
||||
{0xB0, 8, X86InstInfo{"", TYPE_COPY_OTHER, FLAGS_NONE, 0}},
|
||||
{0xB8, 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{0xB8, 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{0xB9, 1, X86InstInfo{"", TYPE_COPY_OTHER, FLAGS_NONE, 0}},
|
||||
{0xBA, 1, X86InstInfo{"", TYPE_COPY_OTHER, FLAGS_NONE, 0}},
|
||||
{0xBB, 5, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{0xBB, 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{0xBC, 1, X86InstInfo{"BSF", TYPE_INST, FLAGS_MODRM | FLAGS_NO_PREFIX_ORDER | FLAGS_NO_OVERLAY66, 0}},
|
||||
{0xBD, 1, X86InstInfo{"BSR", TYPE_INST, FLAGS_MODRM | FLAGS_NO_PREFIX_ORDER | FLAGS_NO_OVERLAY66, 0}},
|
||||
{0xBE, 2, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{0xC0, 2, X86InstInfo{"", TYPE_COPY_OTHER, FLAGS_NONE, 0}},
|
||||
{0xC2, 1, X86InstInfo{"CMPSD", TYPE_INST, GenFlagsSizes(SIZE_128BIT, SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 1}},
|
||||
{0xC3, 5, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 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 {};
|
||||
|
||||
@@ -24,7 +24,22 @@ struct HostFeatures {
|
||||
// Whether or not the host supports any kind of SVE implementation.
|
||||
[[nodiscard]]
|
||||
bool SupportsSVE() const {
|
||||
return SupportsSVE128 || SupportsSVE256;
|
||||
return ProcessFeatures.SupportsSVE128 || ProcessFeatures.SupportsSVE256;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool SupportsSVE128() const {
|
||||
return ProcessFeatures.SupportsSVE128;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool SupportsSVE256() const {
|
||||
return ProcessFeatures.SupportsSVE256;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool SupportsAVX() const {
|
||||
return ProcessFeatures.SupportsAVX;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -42,7 +57,13 @@ struct HostFeatures {
|
||||
// This only determines the starting mode a process started in.
|
||||
// The process can technically long jump to-from the other modes.
|
||||
uint8_t Is64BitMode : 1 {};
|
||||
uint8_t pad : 4 {};
|
||||
|
||||
// These are technically HostFeatures, but they differ between Linux, wow64, arm64.
|
||||
uint8_t SupportsAVX : 1 {};
|
||||
uint8_t SupportsSVE128 : 1 {};
|
||||
uint8_t SupportsSVE256 : 1 {};
|
||||
|
||||
uint8_t pad : 1 {};
|
||||
};
|
||||
static_assert(sizeof(ProcessFeaturesHash) == 1);
|
||||
|
||||
@@ -76,35 +97,32 @@ struct HostFeatures {
|
||||
uint32_t SupportsRCPC : 1 {}; // [9]
|
||||
uint32_t SupportsTSOImm9 : 1 {}; // [10]
|
||||
uint32_t SupportsRAND : 1 {}; // [11]
|
||||
uint32_t SupportsAVX : 1 {}; // [12] // Not enabled on wine?
|
||||
uint32_t SupportsSVE128 : 1 {}; // [13]
|
||||
uint32_t SupportsSVE256 : 1 {}; // [14]
|
||||
uint32_t SupportsSHA : 1 {}; // [15]
|
||||
uint32_t SupportsPMULL_128Bit : 1 {}; // [16]
|
||||
uint32_t SupportsCSSC : 1 {}; // [17]
|
||||
uint32_t SupportsFCMA : 1 {}; // [18]
|
||||
uint32_t SupportsFlagM : 1 {}; // [19]
|
||||
uint32_t SupportsFlagM2 : 1 {}; // [20]
|
||||
uint32_t SupportsRPRES : 1 {}; // [21]
|
||||
uint32_t SupportsPreserveAllABI : 1 {}; // [22] // Not enabled on wine
|
||||
uint32_t SupportsAES256 : 1 {}; // [23]
|
||||
uint32_t SupportsSVEBitPerm : 1 {}; // [24]
|
||||
uint32_t SupportsCPUIndexInTPIDRRO : 1 {}; // [25]
|
||||
uint32_t SupportsFRINTTS : 1 {}; // [26]
|
||||
uint32_t SupportsECV : 1 {}; // [27]
|
||||
uint32_t SupportsWFXT : 1 {}; // [28]
|
||||
uint32_t Supports3DNow : 1 {}; // [29]
|
||||
uint32_t SupportsSSE4a : 1 {}; // [30]
|
||||
uint32_t SupportsMOPS : 1 {}; // [31]
|
||||
uint32_t SupportsI8MM : 1 {}; // [32]
|
||||
uint32_t SupportsDotProd : 1 {}; // [33]
|
||||
uint32_t PreferZVAForVZero : 1 {}; // [34]
|
||||
uint32_t SupportsAFP : 1 {}; // [35]
|
||||
uint32_t SupportsFloatExceptions : 1 {}; // [36]
|
||||
uint32_t SupportsBF16 : 1 {}; // [37]
|
||||
uint32_t SupportsSHA : 1 {}; // [12]
|
||||
uint32_t SupportsPMULL_128Bit : 1 {}; // [13]
|
||||
uint32_t SupportsCSSC : 1 {}; // [14]
|
||||
uint32_t SupportsFCMA : 1 {}; // [15]
|
||||
uint32_t SupportsFlagM : 1 {}; // [16]
|
||||
uint32_t SupportsFlagM2 : 1 {}; // [17]
|
||||
uint32_t SupportsRPRES : 1 {}; // [18]
|
||||
uint32_t SupportsPreserveAllABI : 1 {}; // [19]
|
||||
uint32_t SupportsAES256 : 1 {}; // [20]
|
||||
uint32_t SupportsSVEBitPerm : 1 {}; // [21]
|
||||
uint32_t SupportsCPUIndexInTPIDRRO : 1 {}; // [22]
|
||||
uint32_t SupportsFRINTTS : 1 {}; // [23]
|
||||
uint32_t SupportsECV : 1 {}; // [24]
|
||||
uint32_t SupportsWFXT : 1 {}; // [25]
|
||||
uint32_t Supports3DNow : 1 {}; // [26]
|
||||
uint32_t SupportsSSE4a : 1 {}; // [27]
|
||||
uint32_t SupportsMOPS : 1 {}; // [28]
|
||||
uint32_t SupportsI8MM : 1 {}; // [29]
|
||||
uint32_t SupportsDotProd : 1 {}; // [30]
|
||||
uint32_t PreferZVAForVZero : 1 {}; // [31]
|
||||
uint32_t SupportsAFP : 1 {}; // [32]
|
||||
uint32_t SupportsFloatExceptions : 1 {}; // [33]
|
||||
uint32_t SupportsBF16 : 1 {}; // [34]
|
||||
// Flag if this is InstCountCI
|
||||
uint32_t IsInstCountCI : 1 {}; // [38]
|
||||
uint32_t pad : 25 {}; // [63:39]
|
||||
uint32_t pad : 28 {}; // [63:35]
|
||||
|
||||
// This affects codegen, but it isn't machine state
|
||||
ProcessFeaturesHash ProcessFeatures {};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -354,8 +356,8 @@ static void OverrideFeatures(FEXCore::HostFeatures* Features, uint64_t ForceSVEW
|
||||
const bool Enable##name = (HostFeatures() & FEXCore::Config::HostFeatures::ENABLE##enum_name) != 0; \
|
||||
LogMan::Throw::AFmt(!(Disable##name && Enable##name), "Disabling and Enabling CPU feature (" #name ") is mutually exclusive");
|
||||
|
||||
ENABLE_DISABLE_OPTION(SupportsAVX, AVX, AVX);
|
||||
ENABLE_DISABLE_OPTION(SupportsSVE128, SVE, SVE);
|
||||
ENABLE_DISABLE_OPTION(ProcessFeatures.SupportsAVX, AVX, AVX);
|
||||
ENABLE_DISABLE_OPTION(ProcessFeatures.SupportsSVE128, SVE, SVE);
|
||||
ENABLE_DISABLE_OPTION(SupportsAFP, AFP, AFP);
|
||||
ENABLE_DISABLE_OPTION(SupportsRCPC, LRCPC, LRCPC);
|
||||
ENABLE_DISABLE_OPTION(SupportsTSOImm9, LRCPC2, LRCPC2);
|
||||
@@ -399,7 +401,7 @@ static void OverrideFeatures(FEXCore::HostFeatures* Features, uint64_t ForceSVEW
|
||||
}
|
||||
|
||||
///< Only force enable SVE256 if SVE is already enabled and ForceSVEWidth is set to >= 256.
|
||||
Features->SupportsSVE256 = ForceSVEWidth && ForceSVEWidth >= 256;
|
||||
Features->ProcessFeatures.SupportsSVE256 = ForceSVEWidth && ForceSVEWidth >= 256;
|
||||
}
|
||||
|
||||
static void HandleErrata(FEXCore::HostFeatures* HostFeatures, uint64_t MIDR) {
|
||||
@@ -515,15 +517,15 @@ void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFe
|
||||
|
||||
#ifdef VIXL_SIMULATOR
|
||||
// Hardcode enable SVE with 256-bit wide registers.
|
||||
HostFeatures.SupportsSVE128 = ForceSVEWidth() ? ForceSVEWidth() >= 128 : true;
|
||||
HostFeatures.SupportsSVE256 = ForceSVEWidth() ? ForceSVEWidth() >= 256 : true;
|
||||
HostFeatures.ProcessFeatures.SupportsSVE128 = ForceSVEWidth() ? ForceSVEWidth() >= 128 : true;
|
||||
HostFeatures.ProcessFeatures.SupportsSVE256 = ForceSVEWidth() ? ForceSVEWidth() >= 256 : true;
|
||||
HostFeatures.SupportsMOPS = true;
|
||||
|
||||
// Simulator has a hardcoded ZVA size of 64-bytes.
|
||||
HostFeatures.SupportsCLZERO = true;
|
||||
HostFeatures.SupportsAES = true;
|
||||
HostFeatures.SupportsCRC = true;
|
||||
HostFeatures.SupportsAVX = true;
|
||||
HostFeatures.ProcessFeatures.SupportsAVX = true;
|
||||
HostFeatures.SupportsSHA = true;
|
||||
HostFeatures.SupportsPMULL_128Bit = true;
|
||||
HostFeatures.SupportsAES256 = true;
|
||||
@@ -532,8 +534,8 @@ void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFe
|
||||
HostFeatures.SupportsRPRES = false;
|
||||
HostFeatures.SupportsAFP = false;
|
||||
#else
|
||||
HostFeatures.SupportsSVE128 = Features.Supports(CPUFeatures::Feature::SVE2);
|
||||
HostFeatures.SupportsSVE256 = Features.Supports(CPUFeatures::Feature::SVE2) && Features.GetSVEVectorLengthInBits() >= 256;
|
||||
HostFeatures.ProcessFeatures.SupportsSVE128 = Features.Supports(CPUFeatures::Feature::SVE2);
|
||||
HostFeatures.ProcessFeatures.SupportsSVE256 = Features.Supports(CPUFeatures::Feature::SVE2) && Features.GetSVEVectorLengthInBits() >= 256;
|
||||
HostFeatures.SupportsMOPS = Features.Supports(CPUFeatures::Feature::MOPS);
|
||||
|
||||
// Check if we can support cacheline clears
|
||||
@@ -546,8 +548,8 @@ void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFe
|
||||
#endif
|
||||
|
||||
HostFeatures.Supports3DNow = true;
|
||||
HostFeatures.SupportsAVX = true;
|
||||
HostFeatures.SupportsAES256 = HostFeatures.SupportsAVX && HostFeatures.SupportsAES;
|
||||
HostFeatures.ProcessFeatures.SupportsAVX = true;
|
||||
HostFeatures.SupportsAES256 = HostFeatures.SupportsAVX() && HostFeatures.SupportsAES;
|
||||
HostFeatures.SupportsPreserveAllABI = FEX_HAS_PRESERVE_ALL_ATTR;
|
||||
HostFeatures.PreferZVAForVZero = false;
|
||||
|
||||
@@ -589,7 +591,7 @@ void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFe
|
||||
HostFeatures.SupportsRAND = Feature.Feat_rand;
|
||||
HostFeatures.SupportsRCPC = true;
|
||||
HostFeatures.SupportsTSOImm9 = true;
|
||||
HostFeatures.SupportsAVX = Feature.Feat_avx;
|
||||
HostFeatures.ProcessFeatures.SupportsAVX = Feature.Feat_avx;
|
||||
HostFeatures.SupportsSHA = Feature.Feat_sha;
|
||||
HostFeatures.SupportsPMULL_128Bit = Feature.Feat_pclmulqdq;
|
||||
HostFeatures.SupportsAES256 = Feature.Feat_aes;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,8 +551,8 @@ int main(int argc, char** argv, char** const envp) {
|
||||
{
|
||||
auto HostFeatures = FEX::FetchHostFeatures(Loader.Is64BitMode());
|
||||
CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures);
|
||||
SupportsAVX = HostFeatures.SupportsAVX;
|
||||
SupportsSVE256 = HostFeatures.SupportsSVE256;
|
||||
SupportsAVX = HostFeatures.SupportsAVX();
|
||||
SupportsSVE256 = HostFeatures.SupportsSVE256();
|
||||
}
|
||||
|
||||
FEX::Kernel::Init(Loader.Is64BitMode(), CTX.get());
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
|
||||
#include "Common/cpp-optparse/OptionParser.h"
|
||||
#include "Common/JSONPool.h"
|
||||
@@ -1050,6 +1051,11 @@ bool ValidateDownloadSelection(const WebFileFetcher::FileTargets& Target) {
|
||||
|
||||
namespace ConfigSetter {
|
||||
void SetRootFSAsDefault(const fextl::string& RootFS) {
|
||||
// Create config diectory.
|
||||
if (!FHU::Filesystem::CreateDirectories(FEXCore::Config::GetConfigDirectory(false))) {
|
||||
ExecWithInfo(fextl::fmt::format("Failed to create config directory: {}", FEXCore::Config::GetConfigDirectory(false)));
|
||||
}
|
||||
|
||||
fextl::string Filename = FEXCore::Config::GetConfigFileLocation();
|
||||
auto LoadedConfig = FEX::Config::CreateMainLayer(&Filename);
|
||||
LoadedConfig->Load();
|
||||
@@ -1146,6 +1152,12 @@ int main(int argc, char** argv, char** const envp) {
|
||||
}
|
||||
|
||||
FEX_CONFIG_OPT(LDPath, ROOTFS);
|
||||
const fextl::string RootFSPath = FEXCore::Config::GetDataDirectory() + "RootFS/";
|
||||
|
||||
// Create the rootfs path as early as possible.
|
||||
if (!FHU::Filesystem::CreateDirectories(RootFSPath)) {
|
||||
ExecWithInfo(fextl::fmt::format("Failed to create RootFS directory: {}", RootFSPath));
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
fextl::string Question {};
|
||||
@@ -1172,9 +1184,8 @@ int main(int argc, char** argv, char** const envp) {
|
||||
int32_t DistroIndex = AskForDistroSelection(Targets);
|
||||
if (DistroIndex != -1) {
|
||||
const auto& Target = Targets[DistroIndex];
|
||||
fextl::string RootFS = FEXCore::Config::GetDataDirectory() + "RootFS/";
|
||||
auto filename = Target.URL.substr(Target.URL.find_last_of('/') + 1);
|
||||
auto PathName = RootFS + filename;
|
||||
auto PathName = RootFSPath + filename;
|
||||
|
||||
if (!ValidateCheckExists(Target)) {
|
||||
// Keep going
|
||||
@@ -1295,7 +1306,7 @@ int main(int argc, char** argv, char** const envp) {
|
||||
|
||||
if (UseImageAs == ArgOptions::CompressedImageOption::OPTION_EXTRACT) {
|
||||
auto FolderName = filename.substr(0, filename.find_last_of('.'));
|
||||
if (ExtractHelper(RootFS, PathName, FolderName)) {
|
||||
if (ExtractHelper(RootFSPath, PathName, FolderName)) {
|
||||
// Remove the image file suffix since we extracted to that.
|
||||
filename = std::move(FolderName);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -247,7 +247,7 @@ int main(int argc, char** argv, char** const envp) {
|
||||
auto CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures);
|
||||
|
||||
#ifndef _WIN32
|
||||
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), {}, HostFeatures.SupportsAVX, HostFeatures.SupportsSVE256);
|
||||
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), {}, HostFeatures.SupportsAVX(), HostFeatures.SupportsSVE256());
|
||||
#else
|
||||
// Enable exit on HLT while Wine's longjump is broken.
|
||||
//
|
||||
@@ -257,7 +257,7 @@ int main(int argc, char** argv, char** const envp) {
|
||||
#endif
|
||||
|
||||
// Skip any tests that the host doesn't support features for
|
||||
SupportsAVX = HostFeatures.SupportsAVX;
|
||||
SupportsAVX = HostFeatures.SupportsAVX();
|
||||
|
||||
bool TestUnsupported = (!SupportsAVX && Loader.RequiresAVX()) || (!HostFeatures.SupportsRAND && Loader.RequiresRAND()) ||
|
||||
(!HostFeatures.SupportsSHA && Loader.RequiresSHA()) || (!HostFeatures.SupportsCLZERO && Loader.RequiresCLZERO()) ||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -903,6 +898,11 @@ bool ResetToConsistentStateImpl(const ThreadCPUArea CPUArea, EXCEPTION_RECORD* E
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NativeContext->Pc == reinterpret_cast<uint64_t>(&FEXCore::Assert::ForcedAssert)) {
|
||||
LogMan::Msg::DFmt("FEX: Forced assert");
|
||||
NtTerminateProcess(NtCurrentProcess(), 0x42);
|
||||
}
|
||||
|
||||
if (!IsJIT && !IsDispatcherAddress(NativeContext->Pc)) {
|
||||
LogMan::Msg::DFmt("Passing through exception");
|
||||
return false;
|
||||
|
||||
@@ -79,15 +79,15 @@ FEXCore::HostFeatures CPUFeatures::FetchHostFeatures(bool IsWine, FEXCore::HostF
|
||||
FEX::FetchHostFeatures(Features, HostFeatures, IsWine, CTR, MIDR);
|
||||
|
||||
// Force-disable SVE until wine/windows gain support for SVE context save/restore
|
||||
HostFeatures.SupportsSVE128 = false;
|
||||
HostFeatures.SupportsSVE256 = false;
|
||||
HostFeatures.ProcessFeatures.SupportsSVE128 = false;
|
||||
HostFeatures.ProcessFeatures.SupportsSVE256 = false;
|
||||
|
||||
HostFeatures.SupportsCPUIndexInTPIDRRO = !IsWine || FEX::Windows::UnixLib::SupportsTPIDRRO_CPU();
|
||||
|
||||
HostFeatures.ProcessPID = ProcessPID;
|
||||
|
||||
// AVX is unsupported for WOW64
|
||||
HostFeatures.SupportsAVX = HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec;
|
||||
HostFeatures.ProcessFeatures.SupportsAVX = HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec;
|
||||
|
||||
HostFeatures.ProcessFeatures.HostType = HostType;
|
||||
HostFeatures.ProcessFeatures.Is64BitMode = HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec;
|
||||
@@ -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;
|
||||
|
||||
@@ -182,20 +182,23 @@ FEXCore::ExecutableFileSectionInfo ImageTracker::HandleImageMap(std::string_view
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage;
|
||||
fextl::set<uint64_t> VolatileInstructions {};
|
||||
FEXCore::IntervalList<uint64_t> VolatileValidRanges {};
|
||||
LoadImageVolatileMetadata(VolatileInstructions, VolatileValidRanges, Module, Nt, Address, EndAddress);
|
||||
if (auto It = ExtendedMetaData.find(ID); It != ExtendedMetaData.end()) {
|
||||
FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress);
|
||||
}
|
||||
if (auto It = ExtendedMetaData.find(fextl::string {ModuleName}); It != ExtendedMetaData.end()) {
|
||||
FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress);
|
||||
}
|
||||
|
||||
if (!VolatileInstructions.empty() || !VolatileValidRanges.Empty()) {
|
||||
LogMan::Msg::DFmt("Loaded volatile metadata for {:X}: {} entries", Address, VolatileInstructions.size());
|
||||
CTX.AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions));
|
||||
if (FEXCore::Config::Get_VOLATILEMETADATA()) {
|
||||
uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage;
|
||||
fextl::set<uint64_t> VolatileInstructions {};
|
||||
FEXCore::IntervalList<uint64_t> VolatileValidRanges {};
|
||||
LoadImageVolatileMetadata(VolatileInstructions, VolatileValidRanges, Module, Nt, Address, EndAddress);
|
||||
if (auto It = ExtendedMetaData.find(ID); It != ExtendedMetaData.end()) {
|
||||
FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress);
|
||||
}
|
||||
if (auto It = ExtendedMetaData.find(fextl::string {ModuleName}); It != ExtendedMetaData.end()) {
|
||||
FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress);
|
||||
}
|
||||
|
||||
if (!VolatileInstructions.empty() || !VolatileValidRanges.Empty()) {
|
||||
LogMan::Msg::DFmt("Loaded volatile metadata for {:X}: {} entries", Address, VolatileInstructions.size());
|
||||
CTX.AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions));
|
||||
}
|
||||
}
|
||||
|
||||
return ImageInfo->SectionInfo;
|
||||
|
||||
@@ -833,6 +833,11 @@ bool BTCpuResetToConsistentStateImpl(EXCEPTION_POINTERS* Ptrs) {
|
||||
}
|
||||
}
|
||||
|
||||
if (Context->Pc == reinterpret_cast<uint64_t>(&FEXCore::Assert::ForcedAssert)) {
|
||||
LogMan::Msg::DFmt("FEX: Forced assert");
|
||||
NtTerminateProcess(NtCurrentProcess(), 0x42);
|
||||
}
|
||||
|
||||
if (!Thread || !IsAddressInJit(Context->Pc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0",
|
||||
"RBX": "0x81828384",
|
||||
"RCX": "0x71727374",
|
||||
"RDX": "0x51525354",
|
||||
"RSP": "0x61626364",
|
||||
"RSI": "0x21222324",
|
||||
"RDI": "2",
|
||||
"RBP": "0x1e"
|
||||
},
|
||||
"Mode": "32BIT"
|
||||
}
|
||||
%endif
|
||||
|
||||
; FEX-Emu had a bug where BSR and BSF prefixed with repne didn't exist.
|
||||
; Documentation says that these only work without a prefix.
|
||||
; With `rep` prefix these change instructions, but with `repne` they still behave like BSF/BSR.
|
||||
mov eax, 0
|
||||
mov ebx, 0x81828384
|
||||
mov ecx, 0x71727374
|
||||
mov esp, 0x61626364
|
||||
mov esi, 0x21222324
|
||||
mov edi, 0x31323334
|
||||
mov ebp, 0x41424344
|
||||
mov edx, 0x51525354
|
||||
|
||||
repne bsr ebp, edx
|
||||
repne bsf edi, edx
|
||||
|
||||
setz al
|
||||
hlt
|
||||
@@ -0,0 +1,32 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0",
|
||||
"RBX": "0x8182838485868788",
|
||||
"RCX": "0x7172737475767778",
|
||||
"RDX": "0x5152535455565758",
|
||||
"RSP": "0x6162636465666768",
|
||||
"RSI": "0x2122232425262728",
|
||||
"RDI": "3",
|
||||
"RBP": "0x1e"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
; FEX-Emu had a bug where BSR and BSF prefixed with repne didn't exist.
|
||||
; Documentation says that these only work without a prefix.
|
||||
; With `rep` prefix these change instructions, but with `repne` they still behave like BSF/BSR.
|
||||
mov rax, 0
|
||||
mov rbx, 0x8182838485868788
|
||||
mov rcx, 0x7172737475767778
|
||||
mov rsp, 0x6162636465666768
|
||||
mov rsi, 0x2122232425262728
|
||||
mov rdi, 0x3132333435363738
|
||||
mov rbp, 0x4142434445464748
|
||||
mov rdx, 0x5152535455565758
|
||||
|
||||
repne bsr ebp, edx
|
||||
repne bsf edi, edx
|
||||
|
||||
setz al
|
||||
hlt
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <unistd.h>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <windows.h>
|
||||
|
||||
// Checks various paths that FEX generates for synchronous exceptions to ensure the data is correct.
|
||||
#ifdef __x86_64__
|
||||
#define PREFIX(x) _##x
|
||||
#else
|
||||
#define PREFIX(x) x
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
__attribute__((naked)) void Ret() {
|
||||
__asm volatile(R"(
|
||||
.global _RetInstruction
|
||||
_RetInstruction:
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
__attribute__((naked)) void Do_UD2() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_UD2
|
||||
_Inst_UD2:
|
||||
ud2;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
__attribute__((naked)) void Do_INT1() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_INT1
|
||||
_Inst_INT1:
|
||||
.byte 0xF1; # int1;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
__attribute__((naked)) void Do_Long_INT1() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_Long_INT1
|
||||
_Inst_Long_INT1:
|
||||
.byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66;
|
||||
.byte 0xF1; # int1;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
__attribute__((naked)) void Do_INT3() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_INT3
|
||||
_Inst_INT3:
|
||||
int3;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
__attribute__((naked)) void Do_Long_INT3() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_Long_INT3
|
||||
_Inst_Long_INT3:
|
||||
.byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66;
|
||||
int3;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
__attribute__((naked)) void Do_HLT() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_HLT
|
||||
_Inst_HLT:
|
||||
hlt;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
// Technically an invalid encoding in the 3DNow! space.
|
||||
__attribute__((naked)) void Do_Invalid_D6() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_Invalid_D6
|
||||
_Inst_Invalid_D6:
|
||||
.byte 0x0f, 0x0f, 0xd6;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
__attribute__((naked)) void Do_MOVCS() {
|
||||
__asm volatile(R"(
|
||||
.global _Inst_MOVCS
|
||||
_Inst_MOVCS:
|
||||
mov cs, ax;
|
||||
ret;
|
||||
)");
|
||||
}
|
||||
|
||||
extern void* PREFIX(RetInstruction);
|
||||
|
||||
// Test instructions.
|
||||
extern void* PREFIX(Inst_UD2);
|
||||
extern void* PREFIX(Inst_INT1);
|
||||
extern void* PREFIX(Inst_Long_INT1);
|
||||
extern void* PREFIX(Inst_INT3);
|
||||
extern void* PREFIX(Inst_Long_INT3);
|
||||
extern void* PREFIX(Inst_HLT);
|
||||
extern void* PREFIX(Inst_Invalid_D6);
|
||||
extern void* PREFIX(Inst_MOVCS);
|
||||
}
|
||||
|
||||
struct ReturnDataStruct {
|
||||
DWORD Signal {};
|
||||
size_t FaultRIP {};
|
||||
size_t FaultAddr {};
|
||||
};
|
||||
|
||||
std::optional<ReturnDataStruct> SignalReturnData {};
|
||||
|
||||
__attribute__((stdcall)) static long CapturingHandler(struct _EXCEPTION_POINTERS* ExceptionInfo) {
|
||||
#ifdef __x86_64__
|
||||
auto& RIP = ExceptionInfo->ContextRecord->Rip;
|
||||
#else
|
||||
auto& RIP = ExceptionInfo->ContextRecord->Eip;
|
||||
#endif
|
||||
|
||||
ReturnDataStruct ReturnData {
|
||||
.Signal = ExceptionInfo->ExceptionRecord->ExceptionCode,
|
||||
.FaultRIP = RIP,
|
||||
.FaultAddr = {},
|
||||
};
|
||||
if (ExceptionInfo->ExceptionRecord->NumberParameters == 2) {
|
||||
ReturnData.FaultAddr = ExceptionInfo->ExceptionRecord->ExceptionInformation[1];
|
||||
}
|
||||
|
||||
SignalReturnData = ReturnData;
|
||||
|
||||
RIP = reinterpret_cast<size_t>(&PREFIX(RetInstruction));
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
TEST_CASE("Synchronous faults") {
|
||||
AddVectoredExceptionHandler(true, CapturingHandler);
|
||||
|
||||
using PtrType = void (*)();
|
||||
struct ResultsStruct {
|
||||
PtrType Code {};
|
||||
ReturnDataStruct Result;
|
||||
};
|
||||
|
||||
ResultsStruct TestResults[] = {
|
||||
{Do_UD2,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_ILLEGAL_INSTRUCTION,
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_UD2)),
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
{Do_INT1,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_SINGLE_STEP,
|
||||
// Fault RIP is RIP+Size
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_INT1)) + 1,
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
{Do_Long_INT1,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_SINGLE_STEP,
|
||||
// Fault RIP is RIP+Size
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_Long_INT1)) + 7,
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
{Do_INT3,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_BREAKPOINT,
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_INT3)),
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
{Do_Long_INT3,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_BREAKPOINT,
|
||||
// Fault RIP is at the fault instruction after the prefixes?
|
||||
// This might be a WINE bug.
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_Long_INT3)) + 6,
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
{Do_HLT,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_PRIVILEGED_INSTRUCTION,
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_HLT)),
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
{Do_Invalid_D6,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_ILLEGAL_INSTRUCTION,
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_Invalid_D6)),
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
{Do_MOVCS,
|
||||
ReturnDataStruct {
|
||||
.Signal = STATUS_ILLEGAL_INSTRUCTION,
|
||||
.FaultRIP = reinterpret_cast<size_t>(&PREFIX(Inst_MOVCS)),
|
||||
.FaultAddr = 0, // No fault addr here.
|
||||
}},
|
||||
};
|
||||
|
||||
for (auto& TestResult : TestResults) {
|
||||
SignalReturnData.reset();
|
||||
|
||||
// Execute it. This will fault and return.
|
||||
TestResult.Code();
|
||||
|
||||
REQUIRE(SignalReturnData.has_value());
|
||||
auto Result = SignalReturnData;
|
||||
|
||||
CHECK(TestResult.Result.Signal == Result->Signal);
|
||||
CHECK(TestResult.Result.FaultRIP == Result->FaultRIP);
|
||||
CHECK(TestResult.Result.FaultAddr == Result->FaultAddr);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"roundss xmm0, xmm1, 00000000b": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"AFP"
|
||||
],
|
||||
"DisabledHostFeatures": [],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtpi2ps xmm0, [rax]": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"DisabledHostFeatures": [
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2ss xmm0, eax": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"AFP"
|
||||
],
|
||||
"DisabledHostFeatures": [],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2sd xmm0, eax": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtpi2ps xmm0, [rax]": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2ss xmm0, eax": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"cvtsi2sd xmm0, eax": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"DisabledHostFeatures": [
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vsqrtss xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"AFP"
|
||||
],
|
||||
"DisabledHostFeatures": [],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vroundss xmm0, xmm1, 00000000b": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"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": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vmovups xmm0, xmm0": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vaddsubpd xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"FLAGM2",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vmovntps [rax], xmm0": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vucomiss xmm0, xmm1": {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"I8MM",
|
||||
"DOTPROD"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"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": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vfmadd132ss xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"SVE256",
|
||||
"I8MM"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpdpbusd xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpdpbusd xmm0, xmm1, xmm2": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"FLAGM2",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vmovntdqa xmm0, [rax]": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"SVE256",
|
||||
"SVEBITPERM"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vtestps xmm0, xmm1": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpermq ymm0, ymm1, 1": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"AFP",
|
||||
"SVE256"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vblendvps xmm0, xmm1, xmm2, xmm3": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"SVE128"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"vpsrlw xmm0, xmm1, 0": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"FLAGM",
|
||||
"FLAGM2"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"lock add byte [rax], cl": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"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": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"sha1nexte xmm0, xmm1": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Instructions": {
|
||||
"pclmulqdq xmm0, xmm1, 00000b": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"AFP",
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These 3DNow! instructions are optimal assuming that FEX doesn't SRA MMX registers",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
|
||||
|
||||
@@ -13,36 +13,12 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"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": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"SVE256",
|
||||
"RPRES"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"RPRES",
|
||||
"AFP"
|
||||
],
|
||||
"BinaryCacheVersion": 42
|
||||
"BinaryCacheVersion": 44
|
||||
},
|
||||
"Comment": [
|
||||
"These are instruction combinations that could be more optimal if FEX optimized for them"
|
||||
|
||||
Loaded 100 of 174 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user