Add special cases to DOT_PRODUCT_3/4 that detect whether they're calculating lengthsquared
Add alternate path to DOT_PRODUCT_3/4 for use_fast_dot_product that skips all the status register stuff and just remaps inf to qnan Add OPCODE_TO_SINGLE to replace the CONVERT_F32_F64 - CONVERT_F64_F32 sequence we used to emit with the idea that a backend could implement a more correct rounding behavior if possible on its arch Remove some impossible sequences like MUL_HI_I8/I16, MUL_ADD_F32, DIV_V128. These instructions have no equivalent in PPC. Many other instructions are unused/dead code and should be removed to make the x64 backend a better reference for future ones Add backend_flags to Instr. Basically, flags field that a backend can use for whatever it wants when generating code. Add backend instr flag to x64 that tells it to not generate code for an instruction. this allows sequences to consume subsequent instructions Generate actual x64 code for VSL instruction instead of using callnativesafe Detect repeated COMPARE instructions w/ identical operands and reuse the results in FLAGS if so. this eliminates a ton of garbage compare/set instructions. If a COMPARE instructions destination is stored to context with no intervening instruction and no additional uses besides the store, do setx [ctx address] Detect prefetchw and use it in CACHE_CONTROL if prefetch for write is requested instead of doing prefetch to all cache levels Fixed an accident in an earlier commit by me, VECTOR_DENORMFLUSH was not being emitted at all, so denormal inputs to MUL_ADD_V128 were not becoming zero and outputs from DOT_PRODUCT_X were not either. I believe this introduced a bug into RDR where a wagon wouldnt spawn? (https://discord.com/channels/308194948048486401/308207592482668545/1000443975817252874) Compute fresx in double precision using RECIP_F64 and then round to single instead of doing (double)(1.0f / (float)value), matching original behavior better Refactor some of ppc_emit_fpu, much of the InstrEmit function are identical except for whether they round to single or not Added "tail emitters" to X64Emitter. These are callbacks that get invoked with their label and the X64Emitter after the epilog code. This allows us to move cold code out of the critical path and in the future place constant pools near functions guest_to_host_thunk/host_to_guest_thunk now gets directly rel32 called, instead of doing a mov Add X64BackendContext structure, represents data before the start of the PPCContext Instead of doing branchless sequence, do a compare and jump to tail emitted code for address translation. This makes converting addresses a 3 uop affair in most cases. Do qnan move for dot product in a tail emitter Detect whether EFLAGS bits are independent variables for the current cpu (not really detecting it ehe, just checking if zen) and if so generate inc/dec for add/sub 1 Detect whether low 32 bits of membase are 0. If they are then we can use membasereg.cvt32() in place of immediate 0 in many places, particularly in stores Detect LOAD MODIFY STORE pattern for context variables (currently only done for 64 bit ones) and turn them into modify [context ptr]. This is done for add, sub, and, or, xor, not, neg Tail emit error handling for TRAP opcodes Stub out unused trap opcodes like TRAP_TRUE_I32, TRAP_TRUE_I64, TRAP_TRUE_I16 (the call_true/return_true opcodes for these types are also probably unused) Remove BackpropTruncations. It was poorly written and causes crashes on the game Viva pinata (https://discord.com/channels/308194948048486401/701111856600711208/1000249460451983420)
This commit is contained in:
@@ -155,7 +155,15 @@ enum XmmConst {
|
||||
XMMLVSRTableBase,
|
||||
XMMSingleDenormalMask,
|
||||
XMMThreeFloatMask, // for clearing the fourth float prior to DOT_PRODUCT_3
|
||||
XMMXenosF16ExtRangeStart
|
||||
XMMXenosF16ExtRangeStart,
|
||||
XMMVSRShlByteshuf,
|
||||
XMMVSRMask
|
||||
};
|
||||
// X64Backend specific Instr->runtime_flags
|
||||
enum : uint32_t {
|
||||
INSTR_X64_FLAGS_ELIMINATED =
|
||||
1, // another sequence marked this instruction as not needing codegen,
|
||||
// meaning they likely already handled it
|
||||
};
|
||||
|
||||
// Unfortunately due to the design of xbyak we have to pass this to the ctor.
|
||||
@@ -185,7 +193,13 @@ enum X64EmitterFeatureFlags {
|
||||
kX64FastJrcx = 1 << 12, // jrcxz is as fast as any other jump ( >= Zen1)
|
||||
kX64FastLoop =
|
||||
1 << 13, // loop/loope/loopne is as fast as any other jump ( >= Zen2)
|
||||
kX64EmitAVX512VBMI = 1 << 14
|
||||
kX64EmitAVX512VBMI = 1 << 14,
|
||||
kX64FlagsIndependentVars =
|
||||
1 << 15, // if true, instructions that only modify some flags (like
|
||||
// inc/dec) do not introduce false dependencies on EFLAGS
|
||||
// because the individual flags are treated as different vars by
|
||||
// the processor. (this applies to zen)
|
||||
kX64EmitPrefetchW = 1 << 16
|
||||
};
|
||||
class ResolvableGuestCall {
|
||||
public:
|
||||
@@ -194,6 +208,13 @@ class ResolvableGuestCall {
|
||||
// rgcid
|
||||
unsigned offset_;
|
||||
};
|
||||
class X64Emitter;
|
||||
using TailEmitCallback = std::function<void(X64Emitter& e, Xbyak::Label& lbl)>;
|
||||
struct TailEmitter {
|
||||
Xbyak::Label label;
|
||||
uint32_t alignment;
|
||||
TailEmitCallback func;
|
||||
};
|
||||
|
||||
class X64Emitter : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
@@ -264,7 +285,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
|
||||
Xbyak::Reg64 GetContextReg();
|
||||
Xbyak::Reg64 GetMembaseReg();
|
||||
|
||||
bool CanUseMembaseLow32As0() const { return may_use_membase32_as_zero_reg_; }
|
||||
void ReloadMembase();
|
||||
|
||||
void nop(size_t length = 1);
|
||||
@@ -274,6 +295,8 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
void MovMem64(const Xbyak::RegExp& addr, uint64_t v);
|
||||
|
||||
Xbyak::Address GetXmmConstPtr(XmmConst id);
|
||||
Xbyak::Address GetBackendCtxPtr(int offset_in_x64backendctx);
|
||||
|
||||
void LoadConstantXmm(Xbyak::Xmm dest, float v);
|
||||
void LoadConstantXmm(Xbyak::Xmm dest, double v);
|
||||
void LoadConstantXmm(Xbyak::Xmm dest, const vec128_t& v);
|
||||
@@ -289,6 +312,8 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
return (feature_flags_ & feature_flag) == feature_flag;
|
||||
}
|
||||
|
||||
Xbyak::Label& AddToTail(TailEmitCallback callback, uint32_t alignment = 0);
|
||||
Xbyak::Label& NewCachedLabel();
|
||||
FunctionDebugInfo* debug_info() const { return debug_info_; }
|
||||
|
||||
size_t stack_size() const { return stack_size_; }
|
||||
@@ -324,6 +349,16 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
static const uint32_t xmm_reg_map_[XMM_COUNT];
|
||||
uint32_t current_rgc_id_ = 0xEEDDF00F;
|
||||
std::vector<ResolvableGuestCall> call_sites_;
|
||||
/*
|
||||
set to true if the low 32 bits of membase == 0.
|
||||
only really advantageous if you are storing 32 bit 0 to a displaced address,
|
||||
which would have to represent 0 as 4 bytes
|
||||
*/
|
||||
bool may_use_membase32_as_zero_reg_;
|
||||
std::vector<TailEmitter> tail_code_;
|
||||
std::vector<Xbyak::Label*>
|
||||
label_cache_; // for creating labels that need to be referenced much
|
||||
// later by tail emitters
|
||||
};
|
||||
|
||||
} // namespace x64
|
||||
|
||||
Reference in New Issue
Block a user