mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 322529 part 3 - Fix LRandom JIT code to use the new algorithm. r=arai,jwalden
This commit is contained in:
parent
54fbee1a74
commit
42883becc8
@ -10344,127 +10344,74 @@ CodeGenerator::visitCheckReturn(LCheckReturn* ins)
|
||||
masm.bind(&noChecks);
|
||||
}
|
||||
|
||||
// Out-of-line math_random_no_outparam call for LRandom.
|
||||
class OutOfLineRandom : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LRandom* lir_;
|
||||
|
||||
public:
|
||||
explicit OutOfLineRandom(LRandom* lir)
|
||||
: lir_(lir)
|
||||
{ }
|
||||
|
||||
void accept(CodeGenerator* codegen) {
|
||||
codegen->visitOutOfLineRandom(this);
|
||||
}
|
||||
|
||||
LRandom* lir() const {
|
||||
return lir_;
|
||||
}
|
||||
};
|
||||
|
||||
static const uint64_t RNG_HIGH_MASK = (0xFFFFFFFFFFFFFFFFULL >>
|
||||
(RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS;
|
||||
static const double RNG_DSCALE_INV = 1 / RNG_DSCALE;
|
||||
|
||||
void
|
||||
CodeGenerator::visitRandom(LRandom* ins)
|
||||
{
|
||||
using mozilla::non_crypto::XorShift128PlusRNG;
|
||||
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
Register JSCompartmentReg = ToRegister(ins->temp1());
|
||||
Register tempReg = ToRegister(ins->temp0());
|
||||
|
||||
#ifdef JS_PUNBOX64
|
||||
Register64 rngStateReg = Register64(ToRegister(ins->tempMaybeEAX()));
|
||||
Register64 highReg = Register64(ToRegister(ins->tempMaybeEDX()));
|
||||
Register64 s0Reg(ToRegister(ins->temp1()));
|
||||
Register64 s1Reg(ToRegister(ins->temp2()));
|
||||
#else
|
||||
Register64 rngStateReg = Register64(ToRegister(ins->temp2()), ToRegister(ins->temp3()));
|
||||
Register64 highReg = Register64(ToRegister(ins->tempMaybeEAX()), ToRegister(ins->tempMaybeEDX()));
|
||||
#endif
|
||||
// tempReg is used only on x86.
|
||||
Register tempReg = ToRegister(ins->tempMaybeEAX());
|
||||
|
||||
// rngState = cx->compartment()->rngState;
|
||||
masm.loadJSContext(JSCompartmentReg);
|
||||
masm.loadPtr(Address(JSCompartmentReg, JSContext::offsetOfCompartment()), JSCompartmentReg);
|
||||
masm.load64(Address(JSCompartmentReg, JSCompartment::offsetOfRngState()), rngStateReg);
|
||||
|
||||
// if rngState == 0, escape from inlined code and call
|
||||
// math_random_no_outparam.
|
||||
OutOfLineRandom* ool = new(alloc()) OutOfLineRandom(ins);
|
||||
addOutOfLineCode(ool, ins->mir());
|
||||
masm.branchTest64(Assembler::Zero, rngStateReg, rngStateReg, tempReg, ool->entry());
|
||||
|
||||
// rngState = rngState * RNG_MULTIPLIER;
|
||||
masm.mul64(Imm64(RNG_MULTIPLIER), rngStateReg);
|
||||
|
||||
// rngState += RNG_ADDEND;
|
||||
masm.add64(Imm32(RNG_ADDEND), rngStateReg);
|
||||
|
||||
// rngState &= RNG_MASK;
|
||||
masm.and64(Imm64(RNG_MASK), rngStateReg);
|
||||
|
||||
// if rngState == 0, escape from inlined code and call
|
||||
// math_random_no_outparam.
|
||||
masm.branchTest64(Assembler::Zero, rngStateReg, rngStateReg, tempReg, ool->entry());
|
||||
|
||||
// high = (rngState >> (RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS;
|
||||
masm.move64(rngStateReg, highReg);
|
||||
masm.lshift64(Imm32(RNG_LOW_BITS - (RNG_STATE_WIDTH - RNG_HIGH_BITS)), highReg);
|
||||
masm.and64(Imm64(RNG_HIGH_MASK), highReg);
|
||||
#ifdef JS_CODEGEN_X86
|
||||
// eax and edx are overwritten by mul64 on x86.
|
||||
masm.push64(highReg);
|
||||
Register64 s0Reg(ToRegister(ins->temp1()), ToRegister(ins->temp2()));
|
||||
Register64 s1Reg(ToRegister(ins->temp3()), ToRegister(ins->temp4()));
|
||||
#endif
|
||||
|
||||
// rngState = rngState * RNG_MULTIPLIER;
|
||||
masm.mul64(Imm64(RNG_MULTIPLIER), rngStateReg);
|
||||
const void* rng = gen->compartment->addressOfRandomNumberGenerator();
|
||||
masm.movePtr(ImmPtr(rng), tempReg);
|
||||
|
||||
// rngState += RNG_ADDEND;
|
||||
masm.add64(Imm32(RNG_ADDEND), rngStateReg);
|
||||
static_assert(sizeof(XorShift128PlusRNG) == 2 * sizeof(uint64_t),
|
||||
"Code below assumes XorShift128PlusRNG contains two uint64_t values");
|
||||
|
||||
// rngState &= RNG_MASK;
|
||||
masm.and64(Imm64(RNG_MASK), rngStateReg);
|
||||
Address state0Addr(tempReg, XorShift128PlusRNG::offsetOfState0());
|
||||
Address state1Addr(tempReg, XorShift128PlusRNG::offsetOfState1());
|
||||
|
||||
// cx->compartment()->rngState = rngState;
|
||||
masm.store64(rngStateReg, Address(JSCompartmentReg, JSCompartment::offsetOfRngState()));
|
||||
// uint64_t s1 = mState[0];
|
||||
masm.load64(state0Addr, s1Reg);
|
||||
|
||||
// low = rngState >> (RNG_STATE_WIDTH - RNG_LOW_BITS);
|
||||
const Register64& lowReg = rngStateReg;
|
||||
masm.rshift64(Imm32(RNG_STATE_WIDTH - RNG_LOW_BITS), lowReg);
|
||||
// s1 ^= s1 << 23;
|
||||
masm.move64(s1Reg, s0Reg);
|
||||
masm.lshift64(Imm32(23), s1Reg);
|
||||
masm.xor64(s0Reg, s1Reg);
|
||||
|
||||
// output = double(high | low);
|
||||
#ifdef JS_CODEGEN_X86
|
||||
masm.pop64(highReg);
|
||||
#endif
|
||||
masm.or64(highReg, lowReg);
|
||||
masm.convertUInt64ToDouble(lowReg, tempReg, output);
|
||||
// s1 ^= s1 >> 17
|
||||
masm.move64(s1Reg, s0Reg);
|
||||
masm.rshift64(Imm32(17), s1Reg);
|
||||
masm.xor64(s0Reg, s1Reg);
|
||||
|
||||
// output = output * RNG_DSCALE_INV;
|
||||
masm.mulDoublePtr(ImmPtr(&RNG_DSCALE_INV), tempReg, output);
|
||||
// const uint64_t s0 = mState[1];
|
||||
masm.load64(state1Addr, s0Reg);
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
// mState[0] = s0;
|
||||
masm.store64(s0Reg, state0Addr);
|
||||
|
||||
void
|
||||
CodeGenerator::visitOutOfLineRandom(OutOfLineRandom* ool)
|
||||
{
|
||||
LRandom* ins = ool->lir();
|
||||
Register temp1 = ToRegister(ins->tempMaybeEAX());
|
||||
Register temp2 = ToRegister(ins->tempMaybeEDX());
|
||||
MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
|
||||
// s1 ^= s0
|
||||
masm.xor64(s0Reg, s1Reg);
|
||||
|
||||
LiveRegisterSet regs;
|
||||
setReturnDoubleRegs(®s);
|
||||
saveVolatile(regs);
|
||||
// s1 ^= s0 >> 26
|
||||
masm.rshift64(Imm32(26), s0Reg);
|
||||
masm.xor64(s0Reg, s1Reg);
|
||||
|
||||
masm.loadJSContext(temp1);
|
||||
// mState[1] = s1
|
||||
masm.store64(s1Reg, state1Addr);
|
||||
|
||||
masm.setupUnalignedABICall(temp2);
|
||||
masm.passABIArg(temp1);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
|
||||
// s1 += mState[0]
|
||||
masm.load64(state0Addr, s0Reg);
|
||||
masm.add64(s0Reg, s1Reg);
|
||||
|
||||
restoreVolatile(regs);
|
||||
// See comment in XorShift128PlusRNG::nextDouble().
|
||||
static const int MantissaBits = FloatingPoint<double>::kExponentShift + 1;
|
||||
static const double ScaleInv = double(1) / (1ULL << MantissaBits);
|
||||
|
||||
masm.jump(ool->rejoin());
|
||||
masm.and64(Imm64((1ULL << MantissaBits) - 1), s1Reg);
|
||||
|
||||
masm.convertUInt64ToDouble(s1Reg, tempReg, output);
|
||||
|
||||
// output *= ScaleInv
|
||||
masm.mulDoublePtr(ImmPtr(&ScaleInv), tempReg, output);
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
|
@ -47,7 +47,6 @@ class OutOfLineIsCallable;
|
||||
class OutOfLineRegExpExec;
|
||||
class OutOfLineRegExpTest;
|
||||
class OutOfLineLambdaArrow;
|
||||
class OutOfLineRandom;
|
||||
|
||||
class CodeGenerator : public CodeGeneratorSpecific
|
||||
{
|
||||
@ -388,7 +387,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitRecompileCheck(LRecompileCheck* ins);
|
||||
|
||||
void visitRandom(LRandom* ins);
|
||||
void visitOutOfLineRandom(OutOfLineRandom* ool);
|
||||
|
||||
IonScriptCounts* extractScriptCounts() {
|
||||
IonScriptCounts* counts = scriptCounts_;
|
||||
|
@ -256,6 +256,12 @@ CompileCompartment::addressOfEnumerators()
|
||||
return &compartment()->enumerators;
|
||||
}
|
||||
|
||||
const void*
|
||||
CompileCompartment::addressOfRandomNumberGenerator()
|
||||
{
|
||||
return compartment()->randomNumberGenerator.ptr();
|
||||
}
|
||||
|
||||
const JitCompartment*
|
||||
CompileCompartment::jitCompartment()
|
||||
{
|
||||
|
@ -115,6 +115,7 @@ class CompileCompartment
|
||||
CompileRuntime* runtime();
|
||||
|
||||
const void* addressOfEnumerators();
|
||||
const void* addressOfRandomNumberGenerator();
|
||||
|
||||
const JitCompartment* jitCompartment();
|
||||
|
||||
|
@ -1372,6 +1372,9 @@ IonBuilder::inlineMathRandom(CallInfo& callInfo)
|
||||
if (getInlineReturnType() != MIRType_Double)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MOZ_ASSERT(script()->compartment()->randomNumberGenerator.isSome(),
|
||||
"MRandom JIT code depends on RNG being initialized");
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MRandom* rand = MRandom::New(alloc());
|
||||
|
@ -7316,37 +7316,35 @@ class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(Random)
|
||||
LRandom(const LDefinition &tempMaybeEAX, const LDefinition &tempMaybeEDX,
|
||||
const LDefinition &temp1
|
||||
LRandom(const LDefinition &temp0, const LDefinition &temp1,
|
||||
const LDefinition &temp2
|
||||
#ifndef JS_PUNBOX64
|
||||
, const LDefinition &temp2, const LDefinition &temp3
|
||||
, const LDefinition &temp3, const LDefinition &temp4
|
||||
#endif
|
||||
)
|
||||
{
|
||||
setTemp(0, tempMaybeEAX);
|
||||
setTemp(1, tempMaybeEDX);
|
||||
setTemp(2, temp1);
|
||||
setTemp(0, temp0);
|
||||
setTemp(1, temp1);
|
||||
setTemp(2, temp2);
|
||||
#ifndef JS_PUNBOX64
|
||||
setTemp(3, temp2);
|
||||
setTemp(4, temp3);
|
||||
setTemp(3, temp3);
|
||||
setTemp(4, temp4);
|
||||
#endif
|
||||
}
|
||||
// On x86, following 2 methods return eax and edx necessary for mull.
|
||||
// On others, following 2 methods return ordinary temporary registers.
|
||||
const LDefinition* tempMaybeEAX() {
|
||||
const LDefinition* temp0() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const LDefinition* tempMaybeEDX() {
|
||||
const LDefinition* temp1() {
|
||||
return getTemp(1);
|
||||
}
|
||||
const LDefinition *temp1() {
|
||||
const LDefinition *temp2() {
|
||||
return getTemp(2);
|
||||
}
|
||||
#ifndef JS_PUNBOX64
|
||||
const LDefinition *temp2() {
|
||||
const LDefinition *temp3() {
|
||||
return getTemp(3);
|
||||
}
|
||||
const LDefinition *temp3() {
|
||||
const LDefinition *temp4() {
|
||||
return getTemp(4);
|
||||
}
|
||||
#endif
|
||||
|
@ -441,9 +441,8 @@ LIRGeneratorX86::visitSubstr(MSubstr* ins)
|
||||
void
|
||||
LIRGeneratorX86::visitRandom(MRandom* ins)
|
||||
{
|
||||
// eax and edx are necessary for mull.
|
||||
LRandom *lir = new(alloc()) LRandom(tempFixed(eax),
|
||||
tempFixed(edx),
|
||||
LRandom *lir = new(alloc()) LRandom(temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp());
|
||||
|
@ -52,6 +52,12 @@ class XorShift128PlusRNG {
|
||||
|
||||
/* Return a pseudo-random 64-bit number. */
|
||||
uint64_t next() {
|
||||
/*
|
||||
* The offsetOfState*() methods below are provided so that exceedingly-rare
|
||||
* callers that want to observe or poke at RNG state in C++ type-system-
|
||||
* ignoring means can do so. Don't change the next() or nextDouble()
|
||||
* algorithms without altering code that uses offsetOfState*()!
|
||||
*/
|
||||
uint64_t s1 = mState[0];
|
||||
const uint64_t s0 = mState[1];
|
||||
mState[0] = s0;
|
||||
@ -89,6 +95,13 @@ class XorShift128PlusRNG {
|
||||
mState[0] = aState0;
|
||||
mState[1] = aState1;
|
||||
}
|
||||
|
||||
static size_t offsetOfState0() {
|
||||
return offsetof(XorShift128PlusRNG, mState[0]);
|
||||
}
|
||||
static size_t offsetOfState1() {
|
||||
return offsetof(XorShift128PlusRNG, mState[1]);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace non_crypto
|
||||
|
Loading…
Reference in New Issue
Block a user