[LINT] Linted files + Added lint job to CI
This commit is contained in:
committed by
Radosław Gliński
parent
e8afad8f8a
commit
b9061e6292
@@ -78,7 +78,8 @@ class Backend {
|
||||
virtual void InitializeBackendContext(void* ctx) {}
|
||||
|
||||
/*
|
||||
Free any dynamically allocated data/resources that the backendcontext uses
|
||||
Free any dynamically allocated data/resources that the backendcontext
|
||||
uses
|
||||
*/
|
||||
virtual void DeinitializeBackendContext(void* ctx) {}
|
||||
virtual void SetGuestRoundingMode(void* ctx, unsigned int mode){};
|
||||
|
||||
@@ -314,7 +314,6 @@ SIMPLE_THREEOPERAND(vpshaw, xop_VPSHAW)
|
||||
SIMPLE_THREEOPERAND(vpshad, xop_VPSHAD)
|
||||
SIMPLE_THREEOPERAND(vpshaq, xop_VPSHAQ)
|
||||
|
||||
|
||||
SIMPLE_THREEOPERAND(vpshlb, xop_VPSHLB)
|
||||
SIMPLE_THREEOPERAND(vpshlw, xop_VPSHLW)
|
||||
SIMPLE_THREEOPERAND(vpshld, xop_VPSHLD)
|
||||
|
||||
@@ -924,7 +924,8 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
Xbyak::Label L18, L2, L35, L4, L9, L8, L10, L11, L12, L13, L1;
|
||||
Xbyak::Label LC1, _LCPI3_1;
|
||||
Xbyak::Label handle_denormal_input;
|
||||
Xbyak::Label specialcheck_1, convert_to_signed_inf_and_ret, handle_oddball_denormal;
|
||||
Xbyak::Label specialcheck_1, convert_to_signed_inf_and_ret,
|
||||
handle_oddball_denormal;
|
||||
|
||||
auto emulate_lzcnt_helper_unary_reg = [this](auto& reg, auto& scratch_reg) {
|
||||
inLocalLabel();
|
||||
@@ -941,19 +942,19 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
vmovd(r8d, xmm0);
|
||||
vmovaps(xmm1, xmm0);
|
||||
mov(ecx, r8d);
|
||||
//extract mantissa
|
||||
// extract mantissa
|
||||
and_(ecx, 0x7fffff);
|
||||
mov(edx, ecx);
|
||||
cmp(r8d, 0xff800000);
|
||||
jz(specialcheck_1, CodeGenerator::T_NEAR);
|
||||
//is exponent zero?
|
||||
// is exponent zero?
|
||||
test(r8d, 0x7f800000);
|
||||
jne(L18);
|
||||
test(ecx, ecx);
|
||||
jne(L2);
|
||||
|
||||
L(L18);
|
||||
//extract biased exponent and unbias
|
||||
// extract biased exponent and unbias
|
||||
mov(r9d, r8d);
|
||||
shr(r9d, 23);
|
||||
movzx(r9d, r9b);
|
||||
@@ -988,7 +989,7 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
vxorps(xmm0, xmm0, xmm0);
|
||||
vcomiss(xmm0, xmm1);
|
||||
jbe(L9);
|
||||
vmovss(xmm2, ptr[rip+LC1]);
|
||||
vmovss(xmm2, ptr[rip + LC1]);
|
||||
vandps(xmm1, GetXmmConstPtr(XMMSignMaskF32));
|
||||
|
||||
test(edx, edx);
|
||||
@@ -1019,7 +1020,7 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
|
||||
L(L11);
|
||||
vxorps(xmm2, xmm2, xmm2);
|
||||
vmovss(xmm0, ptr[rip+LC1]);
|
||||
vmovss(xmm0, ptr[rip + LC1]);
|
||||
vcomiss(xmm2, xmm1);
|
||||
ja(L1, CodeGenerator::T_NEAR);
|
||||
mov(ecx, 127);
|
||||
@@ -1080,7 +1081,7 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
or_(ecx, r8d);
|
||||
or_(ecx, eax);
|
||||
vmovd(xmm0, ecx);
|
||||
vaddss(xmm0, xmm1);//apply DAZ behavior to output
|
||||
vaddss(xmm0, xmm1); // apply DAZ behavior to output
|
||||
|
||||
L(L1);
|
||||
ret();
|
||||
@@ -1107,7 +1108,8 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
xchg(ecx, edx);
|
||||
// esi is just the value of xmm0's low word, so we can restore it from there
|
||||
shl(r8d, cl);
|
||||
mov(ecx, edx); // restore ecx, dont xchg because we're going to spoil edx anyway
|
||||
mov(ecx,
|
||||
edx); // restore ecx, dont xchg because we're going to spoil edx anyway
|
||||
mov(edx, r8d);
|
||||
vmovd(r8d, xmm0);
|
||||
}
|
||||
@@ -1115,8 +1117,8 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
jmp(L4);
|
||||
|
||||
L(specialcheck_1);
|
||||
//should be extremely rare
|
||||
vmovss(xmm0, ptr[rip+LC1]);
|
||||
// should be extremely rare
|
||||
vmovss(xmm0, ptr[rip + LC1]);
|
||||
ret();
|
||||
|
||||
L(handle_oddball_denormal);
|
||||
@@ -1131,7 +1133,8 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
|
||||
dd(0xFF800000);
|
||||
dd(0x7F800000);
|
||||
L(LC1);
|
||||
//the position of 7FC00000 here matters, this address will be indexed in handle_oddball_denormal
|
||||
// the position of 7FC00000 here matters, this address will be indexed in
|
||||
// handle_oddball_denormal
|
||||
dd(0x7FC00000);
|
||||
dd(0x5F34FD00);
|
||||
|
||||
@@ -1148,11 +1151,13 @@ void* X64HelperEmitter::EmitVectorVRsqrteHelper(void* scalar_helper) {
|
||||
Xbyak::Label check_scalar_operation_in_vmx, actual_vector_version;
|
||||
auto result_ptr =
|
||||
GetBackendCtxPtr(offsetof(X64BackendContext, helper_scratch_xmms[0]));
|
||||
auto counter_ptr = GetBackendCtxPtr(offsetof(X64BackendContext, helper_scratch_u64s[2]));
|
||||
auto counter_ptr =
|
||||
GetBackendCtxPtr(offsetof(X64BackendContext, helper_scratch_u64s[2]));
|
||||
counter_ptr.setBit(64);
|
||||
|
||||
//shuffle and xor to check whether all lanes are equal
|
||||
//sadly has to leave the float pipeline for the vptest, which is moderate yikes
|
||||
// shuffle and xor to check whether all lanes are equal
|
||||
// sadly has to leave the float pipeline for the vptest, which is moderate
|
||||
// yikes
|
||||
vmovhlps(xmm2, xmm0, xmm0);
|
||||
vmovsldup(xmm1, xmm0);
|
||||
vxorps(xmm1, xmm1, xmm0);
|
||||
@@ -1160,7 +1165,7 @@ void* X64HelperEmitter::EmitVectorVRsqrteHelper(void* scalar_helper) {
|
||||
vorps(xmm2, xmm1, xmm2);
|
||||
vptest(xmm2, xmm2);
|
||||
jnz(check_scalar_operation_in_vmx);
|
||||
//jmp(scalar_helper, CodeGenerator::T_NEAR);
|
||||
// jmp(scalar_helper, CodeGenerator::T_NEAR);
|
||||
call(scalar_helper);
|
||||
vshufps(xmm0, xmm0, xmm0, 0);
|
||||
ret();
|
||||
@@ -1169,7 +1174,7 @@ void* X64HelperEmitter::EmitVectorVRsqrteHelper(void* scalar_helper) {
|
||||
|
||||
vptest(xmm0, ptr[backend()->LookupXMMConstantAddress(XMMThreeFloatMask)]);
|
||||
jnz(actual_vector_version);
|
||||
vshufps(xmm0, xmm0,xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
vshufps(xmm0, xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
call(scalar_helper);
|
||||
// this->DebugBreak();
|
||||
vinsertps(xmm0, xmm0, (3 << 4));
|
||||
@@ -1189,11 +1194,11 @@ void* X64HelperEmitter::EmitVectorVRsqrteHelper(void* scalar_helper) {
|
||||
|
||||
L(loop);
|
||||
lea(rax, result_ptr);
|
||||
vmovss(xmm0, ptr[rax+rcx*4]);
|
||||
vmovss(xmm0, ptr[rax + rcx * 4]);
|
||||
call(scalar_helper);
|
||||
mov(rcx, counter_ptr);
|
||||
lea(rax, result_ptr);
|
||||
vmovss(ptr[rax+rcx*4], xmm0);
|
||||
vmovss(ptr[rax + rcx * 4], xmm0);
|
||||
inc(ecx);
|
||||
cmp(ecx, 4);
|
||||
mov(counter_ptr, rcx);
|
||||
@@ -1274,7 +1279,7 @@ void* X64HelperEmitter::EmitFrsqrteHelper() {
|
||||
xor_(eax, 8);
|
||||
sub(edx, ecx);
|
||||
lea(rcx, ptr[rip + frsqrte_table2]);
|
||||
movzx(eax, byte[rax+rcx]);
|
||||
movzx(eax, byte[rax + rcx]);
|
||||
sal(rdx, 52);
|
||||
sal(rax, 44);
|
||||
or_(rax, rdx);
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/bit_map.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
|
||||
#if XE_PLATFORM_WIN32 == 1
|
||||
@@ -44,9 +44,10 @@ typedef void* (*GuestToHostThunk)(void* target, void* arg0, void* arg1);
|
||||
typedef void (*ResolveFunctionThunk)();
|
||||
|
||||
/*
|
||||
place guest trampolines in the memory range that the HV normally occupies.
|
||||
This way guests can call in via the indirection table and we don't have to clobber/reuse an existing memory range
|
||||
The xboxkrnl range is already used by export trampolines (see kernel/kernel_module.cc)
|
||||
place guest trampolines in the memory range that the HV normally occupies.
|
||||
This way guests can call in via the indirection table and we don't have to
|
||||
clobber/reuse an existing memory range The xboxkrnl range is already used by
|
||||
export trampolines (see kernel/kernel_module.cc)
|
||||
*/
|
||||
static constexpr uint32_t GUEST_TRAMPOLINE_BASE = 0x80000000;
|
||||
static constexpr uint32_t GUEST_TRAMPOLINE_END = 0x80040000;
|
||||
@@ -75,11 +76,13 @@ struct X64BackendStackpoint {
|
||||
// use
|
||||
unsigned guest_return_address_;
|
||||
};
|
||||
enum : uint32_t {
|
||||
kX64BackendMXCSRModeBit = 0,
|
||||
kX64BackendHasReserveBit = 1,
|
||||
kX64BackendNJMOn = 2, //non-java mode bit is currently set. for use in software fp routines
|
||||
kX64BackendNonIEEEMode = 3, //non-ieee mode is currently enabled for scalar fpu.
|
||||
enum : uint32_t {
|
||||
kX64BackendMXCSRModeBit = 0,
|
||||
kX64BackendHasReserveBit = 1,
|
||||
kX64BackendNJMOn =
|
||||
2, // non-java mode bit is currently set. for use in software fp routines
|
||||
kX64BackendNonIEEEMode =
|
||||
3, // non-ieee mode is currently enabled for scalar fpu.
|
||||
};
|
||||
// located prior to the ctx register
|
||||
// some things it would be nice to have be per-emulator instance instead of per
|
||||
@@ -170,8 +173,8 @@ class X64Backend : public Backend {
|
||||
reinterpret_cast<intptr_t>(ctx) - sizeof(X64BackendContext));
|
||||
}
|
||||
virtual uint32_t CreateGuestTrampoline(GuestTrampolineProc proc,
|
||||
void* userdata1,
|
||||
void* userdata2, bool long_term) override;
|
||||
void* userdata1, void* userdata2,
|
||||
bool long_term) override;
|
||||
|
||||
virtual void FreeGuestTrampoline(uint32_t trampoline_addr) override;
|
||||
virtual void SetGuestRoundingMode(void* ctx, unsigned int mode) override;
|
||||
@@ -213,6 +216,7 @@ class X64Backend : public Backend {
|
||||
void* vrsqrtefp_vector_helper = nullptr;
|
||||
void* vrsqrtefp_scalar_helper = nullptr;
|
||||
void* frsqrtefp_helper = nullptr;
|
||||
|
||||
private:
|
||||
#if XE_X64_PROFILER_AVAILABLE == 1
|
||||
GuestProfilerData profiler_data_;
|
||||
|
||||
@@ -93,7 +93,8 @@ class X64CodeCache : public CodeCache {
|
||||
// This is picked to be high enough to cover whatever we can reasonably
|
||||
// expect. If we hit issues with this it probably means some corner case
|
||||
// in analysis triggering.
|
||||
//chrispy: raised this, some games that were compiled with low optimization levels can exceed this
|
||||
// chrispy: raised this, some games that were compiled with low optimization
|
||||
// levels can exceed this
|
||||
static const size_t kMaximumFunctionCount = 1000000;
|
||||
|
||||
struct UnwindReservation {
|
||||
|
||||
@@ -213,7 +213,8 @@ Win32X64CodeCache::RequestUnwindReservation(uint8_t* entry_address) {
|
||||
if (unwind_table_count_ >= kMaximumFunctionCount) {
|
||||
// we should not just be ignoring this in release if it happens
|
||||
xe::FatalError(
|
||||
"Unwind table count (unwind_table_count_) exceeded maximum! Please report this to "
|
||||
"Unwind table count (unwind_table_count_) exceeded maximum! Please "
|
||||
"report this to "
|
||||
"Xenia/Canary developers");
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -210,24 +210,27 @@ bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
|
||||
// Adding or changing anything here must be matched!
|
||||
|
||||
/*
|
||||
pick a page to use as the local base as close to the commonly accessed page that contains most backend fields
|
||||
the sizes that are checked are chosen based on PTE coalescing sizes. zen does 16k or 32k
|
||||
pick a page to use as the local base as close to the commonly accessed page
|
||||
that contains most backend fields the sizes that are checked are chosen
|
||||
based on PTE coalescing sizes. zen does 16k or 32k
|
||||
*/
|
||||
size_t stack_size = StackLayout::GUEST_STACK_SIZE;
|
||||
if (stack_offset < (4096 - sizeof(X64BackendContext))) {
|
||||
locals_page_delta_ = 4096;
|
||||
} else if (stack_offset < (16384 - sizeof(X64BackendContext))) {//16k PTE coalescing
|
||||
} else if (stack_offset <
|
||||
(16384 - sizeof(X64BackendContext))) { // 16k PTE coalescing
|
||||
locals_page_delta_ = 16384;
|
||||
} else if (stack_offset < (32768 - sizeof(X64BackendContext))) {
|
||||
locals_page_delta_ = 32768;
|
||||
} else if (stack_offset < (65536 - sizeof(X64BackendContext))) {
|
||||
locals_page_delta_ = 65536;
|
||||
} else {
|
||||
//extremely unlikely, fall back to stack
|
||||
stack_size = xe::align<size_t>(StackLayout::GUEST_STACK_SIZE + stack_offset, 16);
|
||||
// extremely unlikely, fall back to stack
|
||||
stack_size =
|
||||
xe::align<size_t>(StackLayout::GUEST_STACK_SIZE + stack_offset, 16);
|
||||
locals_page_delta_ = 0;
|
||||
}
|
||||
|
||||
|
||||
assert_true((stack_size + 8) % 16 == 0);
|
||||
func_info.stack_size = stack_size;
|
||||
stack_size_ = stack_size;
|
||||
@@ -1002,7 +1005,7 @@ static inline vec128_t v128_setr_bytes(unsigned char v0, unsigned char v1,
|
||||
}
|
||||
|
||||
static inline vec128_t v128_setr_words(uint32_t v0, uint32_t v1, uint32_t v2,
|
||||
uint32_t v3) {
|
||||
uint32_t v3) {
|
||||
vec128_t result;
|
||||
result.u32[0] = v0;
|
||||
result.u32[1] = v1;
|
||||
@@ -1181,7 +1184,7 @@ static const vec128_t xmm_consts[] = {
|
||||
v128_setr_bytes(13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3, 0x80),
|
||||
// XMMVSRMask
|
||||
vec128b(1),
|
||||
//XMMVRsqrteTableStart
|
||||
// XMMVRsqrteTableStart
|
||||
v128_setr_words(0x568B4FD, 0x4F3AF97, 0x48DAAA5, 0x435A618),
|
||||
v128_setr_words(0x3E7A1E4, 0x3A29DFE, 0x3659A5C, 0x32E96F8),
|
||||
v128_setr_words(0x2FC93CA, 0x2D090CE, 0x2A88DFE, 0x2838B57),
|
||||
@@ -1190,8 +1193,8 @@ static const vec128_t xmm_consts[] = {
|
||||
v128_setr_words(0x2C27279, 0x2926FB7, 0x2666D26, 0x23F6AC0),
|
||||
v128_setr_words(0x21D6881, 0x1FD6665, 0x1E16468, 0x1C76287),
|
||||
v128_setr_words(0x1AF60C1, 0x1995F12, 0x1855D79, 0x1735BF4),
|
||||
//XMMVRsqrteTableBase
|
||||
vec128i(0) //filled in later
|
||||
// XMMVRsqrteTableBase
|
||||
vec128i(0) // filled in later
|
||||
};
|
||||
|
||||
void* X64Emitter::FindByteConstantOffset(unsigned bytevalue) {
|
||||
@@ -1267,12 +1270,13 @@ uintptr_t X64Emitter::PlaceConstData() {
|
||||
|
||||
std::memcpy(mem, xmm_consts, sizeof(xmm_consts));
|
||||
/*
|
||||
set each 32-bit element of the constant XMMVRsqrteTableBase to be the address of the start of the constant XMMVRsqrteTableStart
|
||||
this
|
||||
set each 32-bit element of the constant XMMVRsqrteTableBase to be the
|
||||
address of the start of the constant XMMVRsqrteTableStart this
|
||||
*/
|
||||
vec128_t* deferred_constants = reinterpret_cast<vec128_t*>(mem);
|
||||
vec128_t* vrsqrte_table_base = &deferred_constants[XMMVRsqrteTableBase];
|
||||
uint32_t ptr_to_vrsqrte_table32 = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&deferred_constants[XMMVRsqrteTableStart]));
|
||||
uint32_t ptr_to_vrsqrte_table32 = static_cast<uint32_t>(
|
||||
reinterpret_cast<uintptr_t>(&deferred_constants[XMMVRsqrteTableStart]));
|
||||
*vrsqrte_table_base = vec128i(ptr_to_vrsqrte_table32);
|
||||
|
||||
memory::Protect(mem, kConstDataSize, memory::PageAccess::kReadOnly, nullptr);
|
||||
@@ -1288,8 +1292,10 @@ void X64Emitter::FreeConstData(uintptr_t data) {
|
||||
Xbyak::Address X64Emitter::GetXmmConstPtr(XmmConst id) {
|
||||
// Load through fixed constant table setup by PlaceConstData.
|
||||
// It's important that the pointer is not signed, as it will be sign-extended.
|
||||
void* emitter_data_ptr = backend_->LookupXMMConstantAddress(static_cast<unsigned>(id));
|
||||
xenia_assert(reinterpret_cast<uintptr_t>(emitter_data_ptr) < (1ULL << 31));//must not have signbit set
|
||||
void* emitter_data_ptr =
|
||||
backend_->LookupXMMConstantAddress(static_cast<unsigned>(id));
|
||||
xenia_assert(reinterpret_cast<uintptr_t>(emitter_data_ptr) <
|
||||
(1ULL << 31)); // must not have signbit set
|
||||
return ptr[emitter_data_ptr];
|
||||
}
|
||||
// Implies possible StashXmm(0, ...)!
|
||||
@@ -1610,8 +1616,8 @@ SimdDomain X64Emitter::DeduceSimdDomain(const hir::Value* for_value) {
|
||||
|
||||
return SimdDomain::DONTCARE;
|
||||
}
|
||||
Xbyak::RegExp X64Emitter::GetLocalsBase() const {
|
||||
return !locals_page_delta_ ? rsp : GetContextReg() - locals_page_delta_;
|
||||
Xbyak::RegExp X64Emitter::GetLocalsBase() const {
|
||||
return !locals_page_delta_ ? rsp : GetContextReg() - locals_page_delta_;
|
||||
}
|
||||
Xbyak::Address X64Emitter::GetBackendCtxPtr(int offset_in_x64backendctx) const {
|
||||
/*
|
||||
|
||||
@@ -176,7 +176,10 @@ enum XmmConst {
|
||||
XMMVSRShlByteshuf,
|
||||
XMMVSRMask,
|
||||
XMMVRsqrteTableStart,
|
||||
XMMVRsqrteTableBase = XMMVRsqrteTableStart + (32 / 4), //32 4-byte elements in table, 4 4-byte elements fit in each xmm
|
||||
XMMVRsqrteTableBase =
|
||||
XMMVRsqrteTableStart +
|
||||
(32 /
|
||||
4), // 32 4-byte elements in table, 4 4-byte elements fit in each xmm
|
||||
|
||||
};
|
||||
using amdfx::xopcompare_e;
|
||||
@@ -311,7 +314,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
size_t stack_size() const { return stack_size_; }
|
||||
Xbyak::RegExp GetLocalsBase() const;
|
||||
SimdDomain DeduceSimdDomain(const hir::Value* for_value);
|
||||
|
||||
|
||||
void ForgetMxcsrMode() { mxcsr_mode_ = MXCSRMode::Unknown; }
|
||||
/*
|
||||
returns true if had to load mxcsr. DOT_PRODUCT can use this to skip
|
||||
@@ -390,6 +393,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
void EmitGetCurrentThreadId();
|
||||
void EmitTraceUserCallReturn();
|
||||
static void HandleStackpointOverflowError(ppc::PPCContext* context);
|
||||
|
||||
protected:
|
||||
Processor* processor_ = nullptr;
|
||||
X64Backend* backend_ = nullptr;
|
||||
|
||||
@@ -398,8 +398,7 @@ struct I<OPCODE, DEST, SRC1, SRC2, SRC3> : DestField<DEST> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
XE_MAYBE_UNUSED
|
||||
static const T GetTempReg(X64Emitter& e);
|
||||
XE_MAYBE_UNUSED static const T GetTempReg(X64Emitter& e);
|
||||
template <>
|
||||
XE_MAYBE_UNUSED const Reg8 GetTempReg<Reg8>(X64Emitter& e) {
|
||||
return e.al;
|
||||
|
||||
@@ -705,7 +705,8 @@ struct STORE_LOCAL_I16
|
||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||
// e.TraceStoreI16(DATA_LOCAL, i.src1.constant, i.src2);
|
||||
if (LocalStoreMayUseMembaseLow(e, i)) {
|
||||
e.mov(e.word[e.GetLocalsBase() + i.src1.constant()], e.GetMembaseReg().cvt16());
|
||||
e.mov(e.word[e.GetLocalsBase() + i.src1.constant()],
|
||||
e.GetMembaseReg().cvt16());
|
||||
} else {
|
||||
e.mov(e.word[e.GetLocalsBase() + i.src1.constant()], i.src2);
|
||||
}
|
||||
@@ -716,7 +717,8 @@ struct STORE_LOCAL_I32
|
||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||
// e.TraceStoreI32(DATA_LOCAL, i.src1.constant, i.src2);
|
||||
if (LocalStoreMayUseMembaseLow(e, i)) {
|
||||
e.mov(e.dword[e.GetLocalsBase() + i.src1.constant()], e.GetMembaseReg().cvt32());
|
||||
e.mov(e.dword[e.GetLocalsBase() + i.src1.constant()],
|
||||
e.GetMembaseReg().cvt32());
|
||||
} else {
|
||||
e.mov(e.dword[e.GetLocalsBase() + i.src1.constant()], i.src2);
|
||||
}
|
||||
|
||||
@@ -2120,9 +2120,9 @@ struct RSQRT_V128 : Sequence<RSQRT_V128, I<OPCODE_RSQRT, V128Op, V128Op>> {
|
||||
e.ChangeMxcsrMode(MXCSRMode::Vmx);
|
||||
Xmm src1 = GetInputRegOrConstant(e, i.src1, e.xmm3);
|
||||
/*
|
||||
the vast majority of inputs to vrsqrte come from vmsum3 or vmsum4 as part
|
||||
of a vector normalization sequence. in fact, its difficult to find uses of vrsqrte in titles
|
||||
that have inputs which do not come from vmsum.
|
||||
the vast majority of inputs to vrsqrte come from vmsum3 or vmsum4 as
|
||||
part of a vector normalization sequence. in fact, its difficult to find
|
||||
uses of vrsqrte in titles that have inputs which do not come from vmsum.
|
||||
*/
|
||||
if (i.src1.value && i.src1.value->AllFloatVectorLanesSameValue()) {
|
||||
e.vmovss(e.xmm0, src1);
|
||||
@@ -3193,8 +3193,7 @@ struct SET_ROUNDING_MODE_I32
|
||||
|
||||
if (constant_value & 4) {
|
||||
e.or_(flags_ptr, 1U << kX64BackendNonIEEEMode);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
e.btr(flags_ptr, kX64BackendNonIEEEMode);
|
||||
}
|
||||
e.mov(e.dword[e.rsp + StackLayout::GUEST_SCRATCH], e.eax);
|
||||
@@ -3202,14 +3201,14 @@ struct SET_ROUNDING_MODE_I32
|
||||
e.vldmxcsr(e.dword[e.rsp + StackLayout::GUEST_SCRATCH]);
|
||||
|
||||
} else {
|
||||
//can andnot, but this is a very infrequently used opcode
|
||||
// can andnot, but this is a very infrequently used opcode
|
||||
e.mov(e.eax, 1U << kX64BackendNonIEEEMode);
|
||||
e.mov(e.edx, e.eax);
|
||||
e.not_(e.edx);
|
||||
e.mov(e.ecx, flags_ptr);
|
||||
//edx = flags w/ non ieee cleared
|
||||
// edx = flags w/ non ieee cleared
|
||||
e.and_(e.edx, e.ecx);
|
||||
//eax = flags w/ non ieee set
|
||||
// eax = flags w/ non ieee set
|
||||
e.or_(e.eax, e.ecx);
|
||||
e.bt(i.src1, 2);
|
||||
|
||||
|
||||
@@ -122,10 +122,12 @@ class StackLayout {
|
||||
*
|
||||
*/
|
||||
static const size_t GUEST_STACK_SIZE = 104;
|
||||
//was GUEST_CTX_HOME, can't remove because that'd throw stack alignment off. instead, can be used as a temporary in sequences
|
||||
// was GUEST_CTX_HOME, can't remove because that'd throw stack alignment off.
|
||||
// instead, can be used as a temporary in sequences
|
||||
static const size_t GUEST_SCRATCH = 0;
|
||||
|
||||
//when profiling is on, this stores the nanosecond time at the start of the function
|
||||
|
||||
// when profiling is on, this stores the nanosecond time at the start of the
|
||||
// function
|
||||
static const size_t GUEST_PROFILER_START = 80;
|
||||
static const size_t GUEST_RET_ADDR = 88;
|
||||
static const size_t GUEST_CALL_RET_ADDR = 96;
|
||||
|
||||
@@ -29,15 +29,14 @@ namespace x64 {
|
||||
|
||||
bool trace_enabled = true;
|
||||
|
||||
#define THREAD_MATCH \
|
||||
(!TARGET_THREAD || ppc_context->thread_id == TARGET_THREAD)
|
||||
#define THREAD_MATCH (!TARGET_THREAD || ppc_context->thread_id == TARGET_THREAD)
|
||||
#define IFLUSH()
|
||||
#define IPRINT(s) \
|
||||
if (trace_enabled && THREAD_MATCH) \
|
||||
xe::logging::AppendLogLine(xe::LogLevel::Debug, 't', s, xe::LogSrc::Cpu)
|
||||
#define DFLUSH()
|
||||
#define DPRINT(...) \
|
||||
if (trace_enabled && THREAD_MATCH) \
|
||||
#define DPRINT(...) \
|
||||
if (trace_enabled && THREAD_MATCH) \
|
||||
xe::logging::AppendLogLineFormat(xe::LogSrc::Cpu, xe::LogLevel::Debug, 't', \
|
||||
__VA_ARGS__)
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ bool RegisterAllocationPass::SpillOneRegister(HIRBuilder* builder, Block* block,
|
||||
|
||||
// Set the local slot of the new value to our existing one. This way we will
|
||||
// reuse that same memory if needed.
|
||||
new_value->SetLocalSlot( spill_value->GetLocalSlot());
|
||||
new_value->SetLocalSlot(spill_value->GetLocalSlot());
|
||||
|
||||
// Rename all future uses of the SSA value to the new value as loaded
|
||||
// from the local.
|
||||
|
||||
@@ -1372,27 +1372,27 @@ bool SimplificationPass::SimplifyVectorOps(hir::Instr* i,
|
||||
}
|
||||
|
||||
/*
|
||||
splatting a 32-bit value extracted from a vector where all 4 32-bit values are the same should be eliminated and
|
||||
instead use the vector extracted from, which will be identical
|
||||
have seen this happen, some games vmsum and then splat the low float to all 4 floats, even though it already is there
|
||||
splatting a 32-bit value extracted from a vector where all 4 32-bit values
|
||||
are the same should be eliminated and instead use the vector extracted from,
|
||||
which will be identical have seen this happen, some games vmsum and then
|
||||
splat the low float to all 4 floats, even though it already is there
|
||||
*/
|
||||
if (opc == OPCODE_SPLAT) {
|
||||
if (i->dest->type == VEC128_TYPE) {
|
||||
auto splatted_value = i->src1.value;
|
||||
auto splat_type = splatted_value->type;
|
||||
if (splat_type == FLOAT32_TYPE || splat_type == INT32_TYPE) {
|
||||
//its a splat of a fourbyte value, check the definition
|
||||
// its a splat of a fourbyte value, check the definition
|
||||
auto splat_input_definition = splatted_value->GetDefSkipAssigns();
|
||||
if (splat_input_definition) {
|
||||
auto defining_opcode = splat_input_definition->GetOpcodeNum();
|
||||
if (defining_opcode == OPCODE_EXTRACT) {
|
||||
auto value_extracted_from = splat_input_definition->src1.value;
|
||||
if (value_extracted_from->type == VEC128_TYPE) {
|
||||
|
||||
xenia_assert(splat_input_definition->dest->type == splat_type);
|
||||
|
||||
if (value_extracted_from->AllFloatVectorLanesSameValue()) {
|
||||
i->Replace(&OPCODE_ASSIGN_info,0);
|
||||
i->Replace(&OPCODE_ASSIGN_info, 0);
|
||||
i->set_src1(value_extracted_from);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class SimplificationPass : public ConditionalGroupSubpass {
|
||||
// handles simple multiplication/addition rules
|
||||
bool SimplifyBasicArith(hir::HIRBuilder* builder);
|
||||
|
||||
bool SimplifyVectorOps(hir::HIRBuilder* builder);
|
||||
bool SimplifyVectorOps(hir::HIRBuilder* builder);
|
||||
bool SimplifyVectorOps(hir::Instr* i, hir::HIRBuilder* builder);
|
||||
bool SimplifyBasicArith(hir::Instr* i, hir::HIRBuilder* builder);
|
||||
bool SimplifyAddWithSHL(hir::Instr* i, hir::HIRBuilder* builder);
|
||||
|
||||
@@ -49,7 +49,7 @@ class EntryTable {
|
||||
xe::global_critical_region global_critical_region_;
|
||||
// TODO(benvanik): replace with a better data structure.
|
||||
xe::split_map<uint32_t, Entry*> map_;
|
||||
//std::unordered_map<uint32_t, Entry*> map_;
|
||||
// std::unordered_map<uint32_t, Entry*> map_;
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
@@ -95,7 +95,6 @@ class Export {
|
||||
uint32_t variable_ptr;
|
||||
|
||||
struct {
|
||||
|
||||
// Trampoline that is called from the guest-to-host thunk.
|
||||
// Expects only PPC context as first arg.
|
||||
ExportTrampoline trampoline;
|
||||
|
||||
@@ -115,7 +115,6 @@ uintptr_t GuestFunction::MapGuestAddressToMachineCode(
|
||||
return reinterpret_cast<uintptr_t>(machine_code()) + entry->code_offset;
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,11 @@ class Instr {
|
||||
void MoveBefore(Instr* other);
|
||||
void Replace(const OpcodeInfo* new_opcode, uint16_t new_flags);
|
||||
void UnlinkAndNOP();
|
||||
//chrispy: wanted to change this one to Remove, but i changed Remove's name to UnlinkAndNOP,
|
||||
//so if changes happened in master that we wanted to port over, and those changes used Remove, then we would have a lot of issues that the cause of would
|
||||
//be difficult to track
|
||||
//^todo: rework this comment, im frazzled
|
||||
// chrispy: wanted to change this one to Remove, but i changed Remove's name
|
||||
// to UnlinkAndNOP, so if changes happened in master that we wanted to port
|
||||
// over, and those changes used Remove, then we would have a lot of issues
|
||||
// that the cause of would be difficult to track ^todo: rework this comment,
|
||||
// im frazzled
|
||||
void Deallocate();
|
||||
const OpcodeInfo* GetOpcodeInfo() const { return opcode; }
|
||||
// if opcode is null, we have bigger problems
|
||||
|
||||
@@ -30,9 +30,7 @@ class Label {
|
||||
// this will later be used as an input to xbyak. xbyak only accepts
|
||||
// std::string as a value, not passed by reference, so precomputing the
|
||||
// stringification does not help
|
||||
std::string GetIdString() {
|
||||
return std::to_string(id);
|
||||
}
|
||||
std::string GetIdString() { return std::to_string(id); }
|
||||
};
|
||||
|
||||
} // namespace hir
|
||||
|
||||
@@ -43,7 +43,7 @@ void Value::RemoveUse(Use* use) {
|
||||
use->next->prev = use->prev;
|
||||
}
|
||||
|
||||
//HIRBuilder::GetCurrent()->DeallocateUse(use);
|
||||
// HIRBuilder::GetCurrent()->DeallocateUse(use);
|
||||
}
|
||||
|
||||
uint32_t Value::AsUint32() {
|
||||
@@ -1805,7 +1805,7 @@ bool Value::AllUsesByOneInsn() const {
|
||||
return true;
|
||||
}
|
||||
bool Value::AllFloatVectorLanesSameValue(const hir::Value* for_value,
|
||||
uint32_t current_depth) {
|
||||
uint32_t current_depth) {
|
||||
// limit recursion, otherwise this function will slow down emission
|
||||
if (current_depth == 16) {
|
||||
return false;
|
||||
@@ -1819,7 +1819,8 @@ re_enter:
|
||||
xenia_assert(for_value->IsConstant());
|
||||
|
||||
auto&& constant_value = for_value->constant.v128;
|
||||
for (unsigned constant_lane_index = 1; constant_lane_index < 4; ++constant_lane_index) {
|
||||
for (unsigned constant_lane_index = 1; constant_lane_index < 4;
|
||||
++constant_lane_index) {
|
||||
if (constant_value.u32[0] != constant_value.u32[constant_lane_index]) {
|
||||
return false;
|
||||
}
|
||||
@@ -1844,9 +1845,10 @@ re_enter:
|
||||
definition_opcode_number == OPCODE_DOT_PRODUCT_3) {
|
||||
return true;
|
||||
}
|
||||
//if splat of 32-bit value type, return true
|
||||
//technically a splat of int16 or int8 would also produce the same "float" in all lanes
|
||||
//but i think its best to keep this function focused on specifically float data
|
||||
// if splat of 32-bit value type, return true
|
||||
// technically a splat of int16 or int8 would also produce the same "float" in
|
||||
// all lanes but i think its best to keep this function focused on
|
||||
// specifically float data
|
||||
if (definition_opcode_number == OPCODE_SPLAT) {
|
||||
if (definition->dest->type == VEC128_TYPE) {
|
||||
auto splat_src_value_type = definition->src1.value->type;
|
||||
@@ -1857,33 +1859,32 @@ re_enter:
|
||||
}
|
||||
}
|
||||
|
||||
switch (definition_opcode_number) {
|
||||
//all of these opcodes produce the same value for the same input
|
||||
case OPCODE_RSQRT:
|
||||
case OPCODE_RECIP:
|
||||
case OPCODE_POW2:
|
||||
case OPCODE_LOG2:
|
||||
switch (definition_opcode_number) {
|
||||
// all of these opcodes produce the same value for the same input
|
||||
case OPCODE_RSQRT:
|
||||
case OPCODE_RECIP:
|
||||
case OPCODE_POW2:
|
||||
case OPCODE_LOG2:
|
||||
for_value = definition->src1.value;
|
||||
goto re_enter;
|
||||
|
||||
//binary opcodes
|
||||
case OPCODE_ADD:
|
||||
case OPCODE_SUB:
|
||||
case OPCODE_MUL:
|
||||
// binary opcodes
|
||||
case OPCODE_ADD:
|
||||
case OPCODE_SUB:
|
||||
case OPCODE_MUL:
|
||||
if (!AllFloatVectorLanesSameValue(definition->src1.value,
|
||||
current_depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
for_value = definition->src2.value;
|
||||
goto re_enter;
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace hir
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
@@ -621,6 +621,7 @@ class Value {
|
||||
bool AllFloatVectorLanesSameValue() const {
|
||||
return Value::AllFloatVectorLanesSameValue(this);
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
returns true if for_value (which must be VEC128_TYPE) has the same value in
|
||||
|
||||
@@ -48,7 +48,9 @@ class MMIOHandler {
|
||||
typedef uint32_t (*HostToGuestVirtual)(const void* context,
|
||||
const void* host_address);
|
||||
typedef bool (*AccessViolationCallback)(
|
||||
global_unique_lock_type global_lock_locked_once, //not passed by reference with const like the others?
|
||||
global_unique_lock_type
|
||||
global_lock_locked_once, // not passed by reference with const like
|
||||
// the others?
|
||||
void* context, void* host_address, bool is_write);
|
||||
|
||||
// access_violation_callback is called with global_critical_region locked once
|
||||
|
||||
@@ -55,6 +55,7 @@ class Module {
|
||||
bool ReadMap(const char* file_name);
|
||||
|
||||
virtual void Precompile() {}
|
||||
|
||||
protected:
|
||||
virtual std::unique_ptr<Function> CreateFunction(uint32_t address) = 0;
|
||||
|
||||
|
||||
@@ -375,11 +375,11 @@ typedef struct alignas(64) PPCContext_s {
|
||||
|
||||
// Most frequently used registers first.
|
||||
|
||||
uint64_t r[32]; // 0x20 General purpose registers
|
||||
uint64_t ctr; // 0x18 Count register
|
||||
uint64_t lr; // 0x10 Link register
|
||||
uint64_t r[32]; // 0x20 General purpose registers
|
||||
uint64_t ctr; // 0x18 Count register
|
||||
uint64_t lr; // 0x10 Link register
|
||||
|
||||
uint64_t msr; //machine state register
|
||||
uint64_t msr; // machine state register
|
||||
|
||||
double f[32]; // 0x120 Floating-point registers
|
||||
vec128_t v[128]; // 0x220 VMX128 vector registers
|
||||
|
||||
@@ -46,7 +46,7 @@ struct PPCDecodeData {
|
||||
uint32_t LEV() const { return bits_.LEV; }
|
||||
|
||||
private:
|
||||
XE_MAYBE_UNUSED
|
||||
XE_MAYBE_UNUSED
|
||||
uint32_t address_;
|
||||
union {
|
||||
uint32_t value_;
|
||||
|
||||
@@ -132,23 +132,23 @@ int InstrEmit_branch(PPCHIRBuilder& f, const char* src, uint64_t cia,
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
// Jump to pointer.
|
||||
bool likely_return = !lk && nia_is_lr;
|
||||
if (likely_return) {
|
||||
call_flags |= CALL_POSSIBLE_RETURN;
|
||||
}
|
||||
if (cond) {
|
||||
if (!expect_true) {
|
||||
cond = f.IsFalse(cond);
|
||||
// Jump to pointer.
|
||||
bool likely_return = !lk && nia_is_lr;
|
||||
if (likely_return) {
|
||||
call_flags |= CALL_POSSIBLE_RETURN;
|
||||
}
|
||||
if (cond) {
|
||||
if (!expect_true) {
|
||||
cond = f.IsFalse(cond);
|
||||
}
|
||||
f.CallIndirectTrue(cond, nia, call_flags);
|
||||
} else {
|
||||
f.CallIndirect(nia, call_flags);
|
||||
}
|
||||
f.CallIndirectTrue(cond, nia, call_flags);
|
||||
} else {
|
||||
f.CallIndirect(nia, call_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
} // namespace ppc
|
||||
|
||||
int InstrEmit_bx(PPCHIRBuilder& f, const InstrData& i) {
|
||||
@@ -789,9 +789,8 @@ int InstrEmit_mtspr(PPCHIRBuilder& f, const InstrData& i) {
|
||||
// code requires it. Sequences of mtmsr/lwar/stcw/mtmsr come up a lot, and
|
||||
// without the lock here threads can livelock.
|
||||
|
||||
|
||||
//0x400 = debug singlestep i think
|
||||
//ive seen 0x8000 used in kernel code
|
||||
// 0x400 = debug singlestep i think
|
||||
// ive seen 0x8000 used in kernel code
|
||||
int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) {
|
||||
// bit 48 = EE; interrupt enabled
|
||||
// bit 62 = RI; recoverable interrupt
|
||||
@@ -806,7 +805,7 @@ int InstrEmit_mtmsr(PPCHIRBuilder& f, const InstrData& i) {
|
||||
}
|
||||
|
||||
int InstrEmit_mtmsrd(PPCHIRBuilder& f, const InstrData& i) {
|
||||
//todo: this is moving msr under a mask, so only writing EE and RI
|
||||
// todo: this is moving msr under a mask, so only writing EE and RI
|
||||
|
||||
Value* from = f.LoadGPR(i.X.RT);
|
||||
Value* mtmsrd_mask = f.LoadConstantUint64((1ULL << 15));
|
||||
|
||||
@@ -106,16 +106,17 @@ bool PPCFrontend::Initialize() {
|
||||
}
|
||||
|
||||
bool PPCFrontend::DeclareFunction(GuestFunction* function) {
|
||||
|
||||
//chrispy: make sure we aren't declaring a function that is actually padding data, this will mess up PPCScanner and is hard to debug
|
||||
//wow, this halo reach actually has branches into 0 opcodes, look into further
|
||||
//xenia_assert(*reinterpret_cast<const uint32_t*>(
|
||||
// this->memory()->TranslateVirtual(function->address())) != 0);
|
||||
// Could scan or something here.
|
||||
// Could also check to see if it's a well-known function type and classify
|
||||
// for later.
|
||||
// Could also kick off a precompiler, since we know it's likely the function
|
||||
// will be demanded soon.
|
||||
// chrispy: make sure we aren't declaring a function that is actually padding
|
||||
// data, this will mess up PPCScanner and is hard to debug wow, this halo
|
||||
// reach actually has branches into 0 opcodes, look into further
|
||||
// xenia_assert(*reinterpret_cast<const uint32_t*>(
|
||||
// this->memory()->TranslateVirtual(function->address())) !=
|
||||
// 0);
|
||||
// Could scan or something here.
|
||||
// Could also check to see if it's a well-known function type and classify
|
||||
// for later.
|
||||
// Could also kick off a precompiler, since we know it's likely the function
|
||||
// will be demanded soon.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,8 +80,10 @@ class PPCHIRBuilder : public hir::HIRBuilder {
|
||||
|
||||
void StoreReserved(Value* val);
|
||||
Value* LoadReserved();
|
||||
//calls original impl in hirbuilder, but also records the is_return_site bit into flags in the guestmodule
|
||||
// calls original impl in hirbuilder, but also records the is_return_site bit
|
||||
// into flags in the guestmodule
|
||||
void SetReturnAddress(Value* value);
|
||||
|
||||
private:
|
||||
void MaybeBreakOnInstruction(uint32_t address);
|
||||
void AnnotateLabel(uint32_t address, Label* label);
|
||||
|
||||
@@ -267,7 +267,7 @@ Function* Processor::ResolveFunction(uint32_t address) {
|
||||
entry->status = Entry::STATUS_FAILED;
|
||||
return nullptr;
|
||||
}
|
||||
//only add it to the list of resolved functions if resolving succeeded
|
||||
// only add it to the list of resolved functions if resolving succeeded
|
||||
auto module_for = function->module();
|
||||
|
||||
auto xexmod = dynamic_cast<XexModule*>(module_for);
|
||||
@@ -1300,7 +1300,7 @@ uint32_t Processor::GuestAtomicIncrement32(ppc::PPCContext* context,
|
||||
result = *host_address;
|
||||
// todo: should call a processor->backend function that acquires a
|
||||
// reservation instead of using host atomics
|
||||
if (xe::atomic_cas(result, xe::byte_swap(xe::byte_swap(result)+1),
|
||||
if (xe::atomic_cas(result, xe::byte_swap(xe::byte_swap(result) + 1),
|
||||
host_address)) {
|
||||
break;
|
||||
}
|
||||
@@ -1316,7 +1316,7 @@ uint32_t Processor::GuestAtomicDecrement32(ppc::PPCContext* context,
|
||||
result = *host_address;
|
||||
// todo: should call a processor->backend function that acquires a
|
||||
// reservation instead of using host atomics
|
||||
if (xe::atomic_cas(result,xe::byte_swap( xe::byte_swap(result)-1),
|
||||
if (xe::atomic_cas(result, xe::byte_swap(xe::byte_swap(result) - 1),
|
||||
host_address)) {
|
||||
break;
|
||||
}
|
||||
@@ -1326,9 +1326,9 @@ uint32_t Processor::GuestAtomicDecrement32(ppc::PPCContext* context,
|
||||
|
||||
uint32_t Processor::GuestAtomicOr32(ppc::PPCContext* context,
|
||||
uint32_t guest_address, uint32_t mask) {
|
||||
return xe::byte_swap(xe::atomic_or(
|
||||
context->TranslateVirtual<volatile int32_t*>(guest_address),
|
||||
xe::byte_swap(mask)));
|
||||
return xe::byte_swap(
|
||||
xe::atomic_or(context->TranslateVirtual<volatile int32_t*>(guest_address),
|
||||
xe::byte_swap(mask)));
|
||||
}
|
||||
uint32_t Processor::GuestAtomicXor32(ppc::PPCContext* context,
|
||||
uint32_t guest_address, uint32_t mask) {
|
||||
|
||||
@@ -189,11 +189,11 @@ class Processor {
|
||||
uint32_t GuestAtomicDecrement32(ppc::PPCContext* context,
|
||||
uint32_t guest_address);
|
||||
uint32_t GuestAtomicOr32(ppc::PPCContext* context, uint32_t guest_address,
|
||||
uint32_t mask);
|
||||
uint32_t mask);
|
||||
uint32_t GuestAtomicXor32(ppc::PPCContext* context, uint32_t guest_address,
|
||||
uint32_t mask);
|
||||
uint32_t mask);
|
||||
uint32_t GuestAtomicAnd32(ppc::PPCContext* context, uint32_t guest_address,
|
||||
uint32_t mask);
|
||||
uint32_t mask);
|
||||
bool GuestAtomicCAS32(ppc::PPCContext* context, uint32_t old_value,
|
||||
uint32_t new_value, uint32_t guest_address);
|
||||
|
||||
|
||||
@@ -77,8 +77,7 @@ ThreadState::ThreadState(Processor* processor, uint32_t thread_id,
|
||||
|
||||
// Allocate with 64b alignment.
|
||||
|
||||
context_ = reinterpret_cast<ppc::PPCContext*>(
|
||||
AllocateContext());
|
||||
context_ = reinterpret_cast<ppc::PPCContext*>(AllocateContext());
|
||||
processor->backend()->InitializeBackendContext(context_);
|
||||
assert_true(((uint64_t)context_ & 0x3F) == 0);
|
||||
std::memset(context_, 0, sizeof(ppc::PPCContext));
|
||||
@@ -97,9 +96,11 @@ ThreadState::ThreadState(Processor* processor, uint32_t thread_id,
|
||||
// fixme: VSCR must be set here!
|
||||
context_->msr = 0x9030; // dumped from a real 360, 0x8000
|
||||
|
||||
//this register can be used for arbitrary data according to the PPC docs
|
||||
//but the suggested use is to mark which vector registers are in use, for faster save/restore
|
||||
//it seems unlikely anything uses this, especially since we have way more than 32 vrs, but setting it to all ones seems closer to correct than 0
|
||||
// this register can be used for arbitrary data according to the PPC docs
|
||||
// but the suggested use is to mark which vector registers are in use, for
|
||||
// faster save/restore it seems unlikely anything uses this, especially since
|
||||
// we have way more than 32 vrs, but setting it to all ones seems closer to
|
||||
// correct than 0
|
||||
context_->vrsave = ~0u;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user