remove xe_kernel_export_shim_fn field of Export function_data, trampoline is now the only way exports get invoked Remove kernelstate argument from string functions in order to conform to the trampoline signature (the argument was unused anyway) Constant-evaluated initialization of ppc_opcode_disasm_table, removal of unused std::vector fields Constant-evaluated initialization of export tables name field on export is just a const char* now, only immutable static strings are ever passed to it Remove unused callcount field of export. PM4 compare op function extracted Globally apply /Oy, /GS-, /Gw on msvc windows Remove imgui testwindow code call, it took up like 300 kb
127 lines
4.7 KiB
C++
127 lines
4.7 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2020 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "xenia/base/cvar.h"
|
|
#include "xenia/base/platform.h"
|
|
#define XBYAK_NO_OP_NAMES
|
|
#include "third_party/xbyak/xbyak/xbyak.h"
|
|
#include "third_party/xbyak/xbyak/xbyak_util.h"
|
|
DEFINE_int64(x64_extension_mask, -1LL,
|
|
"Allow the detection and utilization of specific instruction set "
|
|
"features.\n"
|
|
" 0 = x86_64 + AVX1\n"
|
|
" 1 = AVX2\n"
|
|
" 2 = FMA\n"
|
|
" 4 = LZCNT\n"
|
|
" 8 = BMI1\n"
|
|
" 16 = BMI2\n"
|
|
" 32 = F16C\n"
|
|
" 64 = Movbe\n"
|
|
" 128 = GFNI\n"
|
|
" 256 = AVX512F\n"
|
|
" 512 = AVX512VL\n"
|
|
" 1024 = AVX512BW\n"
|
|
" 2048 = AVX512DQ\n"
|
|
" -1 = Detect and utilize all possible processor features\n",
|
|
"x64");
|
|
namespace xe {
|
|
namespace amd64 {
|
|
static uint64_t g_feature_flags = 0U;
|
|
static bool g_did_initialize_feature_flags = false;
|
|
uint64_t GetFeatureFlags() {
|
|
xenia_assert(g_did_initialize_feature_flags);
|
|
return g_feature_flags;
|
|
}
|
|
XE_COLD
|
|
XE_NOINLINE
|
|
void InitFeatureFlags() {
|
|
uint64_t feature_flags_ = 0U;
|
|
{
|
|
Xbyak::util::Cpu cpu_;
|
|
#define TEST_EMIT_FEATURE(emit, ext) \
|
|
if ((cvars::x64_extension_mask & emit) == emit) { \
|
|
feature_flags_ |= (cpu_.has(ext) ? emit : 0); \
|
|
}
|
|
|
|
TEST_EMIT_FEATURE(kX64EmitAVX2, Xbyak::util::Cpu::tAVX2);
|
|
TEST_EMIT_FEATURE(kX64EmitFMA, Xbyak::util::Cpu::tFMA);
|
|
TEST_EMIT_FEATURE(kX64EmitLZCNT, Xbyak::util::Cpu::tLZCNT);
|
|
TEST_EMIT_FEATURE(kX64EmitBMI1, Xbyak::util::Cpu::tBMI1);
|
|
TEST_EMIT_FEATURE(kX64EmitBMI2, Xbyak::util::Cpu::tBMI2);
|
|
TEST_EMIT_FEATURE(kX64EmitMovbe, Xbyak::util::Cpu::tMOVBE);
|
|
TEST_EMIT_FEATURE(kX64EmitGFNI, Xbyak::util::Cpu::tGFNI);
|
|
TEST_EMIT_FEATURE(kX64EmitAVX512F, Xbyak::util::Cpu::tAVX512F);
|
|
TEST_EMIT_FEATURE(kX64EmitAVX512VL, Xbyak::util::Cpu::tAVX512VL);
|
|
TEST_EMIT_FEATURE(kX64EmitAVX512BW, Xbyak::util::Cpu::tAVX512BW);
|
|
TEST_EMIT_FEATURE(kX64EmitAVX512DQ, Xbyak::util::Cpu::tAVX512DQ);
|
|
TEST_EMIT_FEATURE(kX64EmitAVX512VBMI, Xbyak::util::Cpu::tAVX512VBMI);
|
|
TEST_EMIT_FEATURE(kX64EmitPrefetchW, Xbyak::util::Cpu::tPREFETCHW);
|
|
#undef TEST_EMIT_FEATURE
|
|
/*
|
|
fix for xbyak bug/omission, amd cpus are never checked for lzcnt. fixed in
|
|
latest version of xbyak
|
|
*/
|
|
unsigned int data[4];
|
|
Xbyak::util::Cpu::getCpuid(0x80000001, data);
|
|
unsigned amd_flags = data[2];
|
|
if (amd_flags & (1U << 5)) {
|
|
if ((cvars::x64_extension_mask & kX64EmitLZCNT) == kX64EmitLZCNT) {
|
|
feature_flags_ |= kX64EmitLZCNT;
|
|
}
|
|
}
|
|
// todo: although not reported by cpuid, zen 1 and zen+ also have fma4
|
|
if (amd_flags & (1U << 16)) {
|
|
if ((cvars::x64_extension_mask & kX64EmitFMA4) == kX64EmitFMA4) {
|
|
feature_flags_ |= kX64EmitFMA4;
|
|
}
|
|
}
|
|
if (amd_flags & (1U << 21)) {
|
|
if ((cvars::x64_extension_mask & kX64EmitTBM) == kX64EmitTBM) {
|
|
feature_flags_ |= kX64EmitTBM;
|
|
}
|
|
}
|
|
if (amd_flags & (1U << 11)) {
|
|
if ((cvars::x64_extension_mask & kX64EmitXOP) == kX64EmitXOP) {
|
|
feature_flags_ |= kX64EmitXOP;
|
|
}
|
|
}
|
|
if (cpu_.has(Xbyak::util::Cpu::tAMD)) {
|
|
bool is_zennish = cpu_.displayFamily >= 0x17;
|
|
/*
|
|
chrispy: according to agner's tables, all amd architectures
|
|
that we support (ones with avx) have the same timings for
|
|
jrcxz/loop/loope/loopne as for other jmps
|
|
*/
|
|
feature_flags_ |= kX64FastJrcx;
|
|
feature_flags_ |= kX64FastLoop;
|
|
if (is_zennish) {
|
|
// ik that i heard somewhere that this is the case for zen, but i need
|
|
// to verify. cant find my original source for that. todo: ask agner?
|
|
feature_flags_ |= kX64FlagsIndependentVars;
|
|
}
|
|
}
|
|
}
|
|
{
|
|
unsigned int data[4];
|
|
memset(data, 0, sizeof(data));
|
|
// intel extended features
|
|
Xbyak::util::Cpu::getCpuidEx(7, 0, data);
|
|
if ((data[2] & (1 << 28)) &&
|
|
(cvars::x64_extension_mask & kX64EmitMovdir64M)) {
|
|
feature_flags_ |= kX64EmitMovdir64M;
|
|
}
|
|
if ((data[1] & (1 << 9)) && (cvars::x64_extension_mask & kX64FastRepMovs)) {
|
|
feature_flags_ |= kX64FastRepMovs;
|
|
}
|
|
}
|
|
g_feature_flags = feature_flags_;
|
|
g_did_initialize_feature_flags = true;
|
|
}
|
|
} // namespace amd64
|
|
} // namespace xe
|