Adding fallback for pre-MOVBE-supporting processors.

This commit is contained in:
Ben Vanik 2015-06-16 20:05:55 -07:00
parent 75206149ab
commit c34db170f5
7 changed files with 62 additions and 14 deletions

View File

@ -17,6 +17,8 @@ namespace cpu {
namespace backend {
struct MachineInfo {
bool supports_extended_load_store;
struct RegisterSet {
enum Types {
INT_TYPES = (1 << 1),

View File

@ -14,6 +14,11 @@
#include "xenia/cpu/backend/x64/x64_sequences.h"
#include "xenia/cpu/backend/x64/x64_thunk_emitter.h"
#include "xenia/cpu/processor.h"
#include "third_party/xbyak/xbyak/xbyak_util.h"
DEFINE_bool(
enable_haswell_instructions, true,
"Uses the AVX2/FMA/etc instructions on Haswell processors, if available.");
namespace xe {
namespace cpu {
@ -38,6 +43,15 @@ bool X64Backend::Initialize() {
RegisterSequences();
// Need movbe to do advanced LOAD/STORE tricks.
if (FLAGS_enable_haswell_instructions) {
Xbyak::util::Cpu cpu;
machine_info_.supports_extended_load_store =
cpu.has(Xbyak::util::Cpu::tMOVBE);
} else {
machine_info_.supports_extended_load_store = false;
}
machine_info_.register_sets[0] = {
0, "gpr", MachineInfo::RegisterSet::INT_TYPES, X64Emitter::GPR_COUNT,
};

View File

@ -10,8 +10,12 @@
#ifndef XENIA_BACKEND_X64_X64_BACKEND_H_
#define XENIA_BACKEND_X64_X64_BACKEND_H_
#include <gflags/gflags.h>
#include "xenia/cpu/backend/backend.h"
DECLARE_bool(enable_haswell_instructions);
namespace xe {
namespace cpu {
namespace backend {

View File

@ -31,10 +31,6 @@
#include "xenia/cpu/thread_state.h"
#include "xenia/profiling.h"
DEFINE_bool(
enable_haswell_instructions, true,
"Uses the AVX2/FMA/etc instructions on Haswell processors, if available.");
DEFINE_bool(enable_debugprint_log, false,
"Log debugprint traps to the active debugger");
@ -87,10 +83,10 @@ X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator)
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tLZCNT) ? kX64EmitLZCNT : 0;
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tBMI2) ? kX64EmitBMI2 : 0;
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tF16C) ? kX64EmitF16C : 0;
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tMOVBE) ? kX64EmitMovbe : 0;
}
if (!cpu_.has(Xbyak::util::Cpu::tAVX) ||
!cpu_.has(Xbyak::util::Cpu::tMOVBE)) {
if (!cpu_.has(Xbyak::util::Cpu::tAVX)) {
XEFATAL(
"Your CPU is too old to support Xenia. See the FAQ for system "
"requirements at http://xenia.jp");

View File

@ -104,6 +104,7 @@ enum X64EmitterFeatureFlags {
kX64EmitLZCNT = 1 << 3,
kX64EmitBMI2 = 1 << 4,
kX64EmitF16C = 1 << 5,
kX64EmitMovbe = 1 << 6,
};
class X64Emitter : public Xbyak::CodeGenerator {

View File

@ -1524,7 +1524,12 @@ EMITTER(LOAD_I16, MATCH(I<OPCODE_LOAD, I16<>, I64<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
auto addr = ComputeMemoryAddress(e, i.src1);
if (i.instr->flags & LoadStoreFlags::LOAD_STORE_BYTE_SWAP) {
e.movbe(i.dest, e.word[addr]);
if (e.IsFeatureEnabled(kX64EmitMovbe)) {
e.movbe(i.dest, e.word[addr]);
} else {
e.mov(i.dest, e.word[addr]);
e.ror(i.dest, 8);
}
} else {
e.mov(i.dest, e.word[addr]);
}
@ -1539,7 +1544,12 @@ EMITTER(LOAD_I32, MATCH(I<OPCODE_LOAD, I32<>, I64<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
auto addr = ComputeMemoryAddress(e, i.src1);
if (i.instr->flags & LoadStoreFlags::LOAD_STORE_BYTE_SWAP) {
e.movbe(i.dest, e.dword[addr]);
if (e.IsFeatureEnabled(kX64EmitMovbe)) {
e.movbe(i.dest, e.dword[addr]);
} else {
e.mov(i.dest, e.dword[addr]);
e.bswap(i.dest);
}
} else {
e.mov(i.dest, e.dword[addr]);
}
@ -1554,7 +1564,12 @@ EMITTER(LOAD_I64, MATCH(I<OPCODE_LOAD, I64<>, I64<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
auto addr = ComputeMemoryAddress(e, i.src1);
if (i.instr->flags & LoadStoreFlags::LOAD_STORE_BYTE_SWAP) {
e.movbe(i.dest, e.qword[addr]);
if (e.IsFeatureEnabled(kX64EmitMovbe)) {
e.movbe(i.dest, e.qword[addr]);
} else {
e.mov(i.dest, e.qword[addr]);
e.bswap(i.dest);
}
} else {
e.mov(i.dest, e.qword[addr]);
}
@ -1645,7 +1660,11 @@ EMITTER(STORE_I16, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I16<>>)) {
auto addr = ComputeMemoryAddress(e, i.src1);
if (i.instr->flags & LoadStoreFlags::LOAD_STORE_BYTE_SWAP) {
assert_false(i.src2.is_constant);
e.movbe(e.word[addr], i.src2);
if (e.IsFeatureEnabled(kX64EmitMovbe)) {
e.movbe(e.word[addr], i.src2);
} else {
assert_always("not implemented");
}
} else {
if (i.src2.is_constant) {
e.mov(e.word[addr], i.src2.constant());
@ -1666,7 +1685,11 @@ EMITTER(STORE_I32, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I32<>>)) {
auto addr = ComputeMemoryAddress(e, i.src1);
if (i.instr->flags & LoadStoreFlags::LOAD_STORE_BYTE_SWAP) {
assert_false(i.src2.is_constant);
e.movbe(e.dword[addr], i.src2);
if (e.IsFeatureEnabled(kX64EmitMovbe)) {
e.movbe(e.dword[addr], i.src2);
} else {
assert_always("not implemented");
}
} else {
if (i.src2.is_constant) {
e.mov(e.dword[addr], i.src2.constant());
@ -1687,7 +1710,11 @@ EMITTER(STORE_I64, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I64<>>)) {
auto addr = ComputeMemoryAddress(e, i.src1);
if (i.instr->flags & LoadStoreFlags::LOAD_STORE_BYTE_SWAP) {
assert_false(i.src2.is_constant);
e.movbe(e.qword[addr], i.src2);
if (e.IsFeatureEnabled(kX64EmitMovbe)) {
e.movbe(e.qword[addr], i.src2);
} else {
assert_always("not implemented");
}
} else {
if (i.src2.is_constant) {
e.MovMem64(addr, i.src2.constant());

View File

@ -60,8 +60,12 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
if (validate) compiler_->AddPass(std::make_unique<passes::ValidationPass>());
compiler_->AddPass(std::make_unique<passes::ConstantPropagationPass>());
if (validate) compiler_->AddPass(std::make_unique<passes::ValidationPass>());
compiler_->AddPass(std::make_unique<passes::MemorySequenceCombinationPass>());
if (validate) compiler_->AddPass(std::make_unique<passes::ValidationPass>());
if (backend->machine_info()->supports_extended_load_store) {
// Backend supports the advanced LOAD/STORE instructions.
// These will save us a lot of HIR opcodes.
compiler_->AddPass(std::make_unique<passes::MemorySequenceCombinationPass>());
if (validate) compiler_->AddPass(std::make_unique<passes::ValidationPass>());
}
compiler_->AddPass(std::make_unique<passes::SimplificationPass>());
if (validate) compiler_->AddPass(std::make_unique<passes::ValidationPass>());
// compiler_->AddPass(std::make_unique<passes::DeadStoreEliminationPass>());