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:
chss95cs@gmail.com
2022-07-23 12:10:07 -07:00
parent 1fcac00924
commit 33a6cfc0a7
23 changed files with 1299 additions and 786 deletions

View File

@@ -379,7 +379,7 @@ typedef struct alignas(64) PPCContext_s {
uint64_t lr; // 0x10 Link register
double f[32]; // 0x120 Floating-point registers
vec128_t v[128]; // 0x220 VMX128 vector registers
vec128_t vscr_vec;
// XER register:
// Split to make it easier to do individual updates.
uint8_t xer_ca;
@@ -422,7 +422,7 @@ typedef struct alignas(64) PPCContext_s {
// Value of last reserved load
uint64_t reserved_val;
ThreadState* thread_state;
uint8_t* virtual_membase;
uint8_t* virtual_membase;
static std::string GetRegisterName(PPCRegister reg);
std::string GetStringFromValue(PPCRegister reg) const;
void SetValueFromString(PPCRegister reg, std::string value);
@@ -432,6 +432,7 @@ typedef struct alignas(64) PPCContext_s {
std::string& result) const;
} PPCContext;
#pragma pack(pop)
constexpr size_t ppcctx_size = sizeof(PPCContext);
static_assert(sizeof(PPCContext) % 64 == 0, "64b padded");
} // namespace ppc

View File

@@ -355,13 +355,18 @@ int InstrEmit_stvrxl128(PPCHIRBuilder& f, const InstrData& i) {
}
int InstrEmit_mfvscr(PPCHIRBuilder& f, const InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// is this the right format?
f.StoreVR(i.VX128_1.RB,
f.LoadContext(offsetof(PPCContext, vscr_vec), VEC128_TYPE));
return 0;
}
int InstrEmit_mtvscr(PPCHIRBuilder& f, const InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// is this the right format?
Value* v = f.LoadVR(i.VX128_1.RB);
f.StoreContext(offsetof(PPCContext, vscr_vec), v);
return 0;
}
int InstrEmit_vaddcuw(PPCHIRBuilder& f, const InstrData& i) {
@@ -1105,7 +1110,7 @@ int InstrEmit_vmsum3fp128(PPCHIRBuilder& f, const InstrData& i) {
// Dot product XYZ.
// (VD.xyzw) = (VA.x * VB.x) + (VA.y * VB.y) + (VA.z * VB.z)
Value* v = f.DotProduct3(f.LoadVR(VX128_VA128), f.LoadVR(VX128_VB128));
//chrispy: denormal outputs for Dot product are unconditionally made 0
// chrispy: denormal outputs for Dot product are unconditionally made 0
v = f.VectorDenormFlush(v);
f.StoreVR(VX128_VD128, v);
return 0;

View File

@@ -336,6 +336,7 @@ int InstrEmit_mulhwx(PPCHIRBuilder& f, const InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v = f.SignExtend(f.MulHi(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE),
f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE)),
INT64_TYPE);
@@ -353,6 +354,7 @@ int InstrEmit_mulhwux(PPCHIRBuilder& f, const InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v = f.ZeroExtend(
f.MulHi(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE),
f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), ARITHMETIC_UNSIGNED),

View File

@@ -46,7 +46,7 @@ int InstrEmit_faddx(PPCHIRBuilder& f, const InstrData& i) {
int InstrEmit_faddsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- (frA) + (frB)
Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
v = f.ToSingle(v);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
@@ -63,7 +63,7 @@ int InstrEmit_fdivx(PPCHIRBuilder& f, const InstrData& i) {
int InstrEmit_fdivsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- frA / frB
Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
v = f.ToSingle(v);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
@@ -80,7 +80,7 @@ int InstrEmit_fmulx(PPCHIRBuilder& f, const InstrData& i) {
int InstrEmit_fmulsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- (frA) x (frC)
Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
v = f.ToSingle(v);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
@@ -88,9 +88,9 @@ int InstrEmit_fmulsx(PPCHIRBuilder& f, const InstrData& i) {
int InstrEmit_fresx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- 1.0 / (frB)
Value* v = f.Convert(f.Div(f.LoadConstantFloat32(1.0f),
f.Convert(f.LoadFPR(i.A.FRB), FLOAT32_TYPE)),
FLOAT64_TYPE);
Value* v = f.Recip(f.LoadFPR(i.A.FRB));
v = f.ToSingle(v);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
@@ -116,7 +116,7 @@ int InstrEmit_fsubx(PPCHIRBuilder& f, const InstrData& i) {
int InstrEmit_fsubsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- (frA) - (frB)
Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
v = f.ToSingle(v);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
@@ -132,64 +132,63 @@ int InstrEmit_fselx(PPCHIRBuilder& f, const InstrData& i) {
f.UpdateFPSCR(v, i.A.Rc);
return 0;
}
int InstrEmit_fsqrtx(PPCHIRBuilder& f, const InstrData& i) {
// Double precision:
static int InstrEmit_fsqrt(PPCHIRBuilder& f, const InstrData& i, bool single) {
// frD <- sqrt(frB)
Value* v = f.Sqrt(f.LoadFPR(i.A.FRB));
if (single) {
v = f.ToSingle(v);
}
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
}
int InstrEmit_fsqrtx(PPCHIRBuilder& f, const InstrData& i) {
return InstrEmit_fsqrt(f, i, false);
}
int InstrEmit_fsqrtsx(PPCHIRBuilder& f, const InstrData& i) {
// Single precision:
// frD <- sqrt(frB)
Value* v = f.Sqrt(f.LoadFPR(i.A.FRB));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
return InstrEmit_fsqrt(f, i, true);
}
// Floating-point multiply-add (A-9)
int InstrEmit_fmaddx(PPCHIRBuilder& f, const InstrData& i) {
static int InstrEmit_fmadd(PPCHIRBuilder& f, const InstrData& i, bool single) {
// frD <- (frA x frC) + frB
Value* v =
f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB));
if (single) {
v = f.ToSingle(v);
}
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
}
int InstrEmit_fmaddx(PPCHIRBuilder& f, const InstrData& i) {
return InstrEmit_fmadd(f, i, false);
}
int InstrEmit_fmaddsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- (frA x frC) + frB
return InstrEmit_fmadd(f, i, true);
}
static int InstrEmit_fmsub(PPCHIRBuilder& f, const InstrData& i, bool single) {
// frD <- (frA x frC) - frB
Value* v =
f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB));
if (single) {
v = f.ToSingle(v);
}
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
}
int InstrEmit_fmsubx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- (frA x frC) - frB
Value* v =
f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB));
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
return InstrEmit_fmsub(f, i, false);
}
int InstrEmit_fmsubsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- (frA x frC) - frB
Value* v =
f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
return InstrEmit_fmsub(f, i, true);
}
int InstrEmit_fnmaddx(PPCHIRBuilder& f, const InstrData& i) {
@@ -205,7 +204,7 @@ int InstrEmit_fnmaddsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- -([frA x frC] + frB)
Value* v = f.Neg(
f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
v = f.ToSingle(v);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;
@@ -224,7 +223,7 @@ int InstrEmit_fnmsubsx(PPCHIRBuilder& f, const InstrData& i) {
// frD <- -([frA x frC] - frB)
Value* v = f.Neg(
f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)));
v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE);
v = f.ToSingle(v);
f.StoreFPR(i.A.FRT, v);
f.UpdateFPSCR(v, i.A.Rc);
return 0;