Bug 984018 - sincos optimization. r=nbp

This commit is contained in:
Victor Carlquist 2015-09-13 10:58:23 -03:00
Родитель e19e1ac0e0
Коммит 4d5d75f626
29 изменённых файлов: 477 добавлений и 2 удалений

Просмотреть файл

@ -2402,6 +2402,7 @@ fi
dnl Checks for math functions.
dnl ========================================================
AC_CHECK_LIB(m, sin)
AC_CHECK_LIB(m, __sincos, AC_DEFINE(HAVE_SINCOS))
AC_CHECK_FUNCS([log2 log1p expm1 sqrt1pm1 acosh asinh atanh cbrt])

Просмотреть файл

@ -0,0 +1,62 @@
var x = 0;
function test() {
function sincos1(a, b) {
var sa = Math.sin(a);
var sb = Math.sin(b);
var ca = Math.cos(a);
var cb = Math.cos(b);
var ra = sa * sa + ca * ca;
var rb = sb * sb + cb * cb;
var dec = 100000;
assertEq(Math.round(ra * dec) / dec, Math.round(rb * dec) / dec);
ca = Math.cos(a);
cb = Math.cos(b);
sa = Math.sin(a);
sb = Math.sin(b);
var ra = sa * sa + ca * ca;
var rb = sb * sb + cb * cb;
assertEq(Math.round(ra * dec) / dec, Math.round(rb * dec) / dec);
return ra;
}
function sincos2(x) {
var s1 = Math.sin(x);
var c1 = Math.cos(x);
var c2 = Math.cos(x);
var s2 = Math.sin(x);
return (s1 * s1 + c1 * c1) - (s2 * s2 + c2 * c2);
}
function bailoutHere() { bailout(); }
function sincos3(x) {
var s = Math.sin(x);
bailoutHere();
var c = Math.cos(x);
assertEq(Math.round(s * s + c * c), 1);
return s;
}
function sincos4(x) {
if (x < 2500)
x = Math.sin(x);
else
x = Math.cos(x);
return x;
}
for (var i=0; i<5000; i++) {
x += sincos1(x, x + 1);
x += sincos2(x);
x += sincos3(x);
x += sincos4(i);
}
}
x += 1;
test();

Просмотреть файл

@ -6400,6 +6400,42 @@ CodeGenerator::visitFromCharCode(LFromCharCode* lir)
masm.bind(ool->rejoin());
}
void
CodeGenerator::visitSinCos(LSinCos *lir)
{
Register temp = ToRegister(lir->temp());
Register params = ToRegister(lir->temp2());
FloatRegister input = ToFloatRegister(lir->input());
FloatRegister outputSin = ToFloatRegister(lir->outputSin());
FloatRegister outputCos = ToFloatRegister(lir->outputCos());
masm.reserveStack(sizeof(double) * 2);
masm.movePtr(masm.getStackPointer(), params);
const MathCache* mathCache = lir->mir()->cache();
masm.setupUnalignedABICall(temp);
if (mathCache) {
masm.movePtr(ImmPtr(mathCache), temp);
masm.passABIArg(temp);
}
#define MAYBE_CACHED_(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
masm.passABIArg(input, MoveOp::DOUBLE);
masm.passABIArg(MoveOperand(params, sizeof(double), MoveOperand::EFFECTIVE_ADDRESS),
MoveOp::GENERAL);
masm.passABIArg(MoveOperand(params, 0, MoveOperand::EFFECTIVE_ADDRESS),
MoveOp::GENERAL);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED_(js::math_sincos)));
#undef MAYBE_CACHED_
masm.loadDouble(Address(masm.getStackPointer(), 0), outputCos);
masm.loadDouble(Address(masm.getStackPointer(), sizeof(double)), outputSin);
masm.freeStack(sizeof(double) * 2);
}
typedef JSObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString);
static const VMFunction StringSplitInfo = FunctionInfo<StringSplitFn>(js::str_split_string);

Просмотреть файл

@ -242,6 +242,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitConcat(LConcat* lir);
void visitCharCodeAt(LCharCodeAt* lir);
void visitFromCharCode(LFromCharCode* lir);
void visitSinCos(LSinCos *lir);
void visitStringSplit(LStringSplit* lir);
void visitFunctionEnvironment(LFunctionEnvironment* lir);
void visitCallGetProperty(LCallGetProperty* lir);

Просмотреть файл

@ -1378,6 +1378,111 @@ jit::ToggleBarriers(JS::Zone* zone, bool needs)
namespace js {
namespace jit {
static void
OptimizeSinCos(MIRGenerator *mir, MIRGraph &graph)
{
// Now, we are looking for:
// var y = sin(x);
// var z = cos(x);
// Graph before:
// - 1 op
// - 6 mathfunction op1 Sin
// - 7 mathfunction op1 Cos
// Graph will look like:
// - 1 op
// - 5 sincos op1
// - 6 mathfunction sincos5 Sin
// - 7 mathfunction sincos5 Cos
for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
for (MInstructionIterator iter(block->begin()), end(block->end()); iter != end; ) {
MInstruction *ins = *iter++;
if (!ins->isMathFunction() || ins->isRecoveredOnBailout())
continue;
MMathFunction *insFunc = ins->toMathFunction();
if (insFunc->function() != MMathFunction::Sin && insFunc->function() != MMathFunction::Cos)
continue;
// Check if sin/cos is already optimized.
if (insFunc->getOperand(0)->type() == MIRType_SinCosDouble)
continue;
// insFunc is either a |sin(x)| or |cos(x)| instruction. The
// following loop iterates over the uses of |x| to check if both
// |sin(x)| and |cos(x)| instructions exist.
bool hasSin = false;
bool hasCos = false;
for (MUseDefIterator uses(insFunc->input()); uses; uses++)
{
if (!uses.def()->isInstruction())
continue;
// We should replacing the argument of the sin/cos just when it
// is dominated by the |block|.
if (!block->dominates(uses.def()->block()))
continue;
MInstruction *insUse = uses.def()->toInstruction();
if (!insUse->isMathFunction() || insUse->isRecoveredOnBailout())
continue;
MMathFunction *mathIns = insUse->toMathFunction();
if (!hasSin && mathIns->function() == MMathFunction::Sin) {
hasSin = true;
JitSpew(JitSpew_Sincos, "Found sin in block %d.", mathIns->block()->id());
}
else if (!hasCos && mathIns->function() == MMathFunction::Cos) {
hasCos = true;
JitSpew(JitSpew_Sincos, "Found cos in block %d.", mathIns->block()->id());
}
if (hasCos && hasSin)
break;
}
if (!hasCos || !hasSin) {
JitSpew(JitSpew_Sincos, "No sin/cos pair found.");
continue;
}
JitSpew(JitSpew_Sincos, "Found, at least, a pair sin/cos. Adding sincos in block %d",
block->id());
// Adding the MSinCos and replacing the parameters of the
// sin(x)/cos(x) to sin(sincos(x))/cos(sincos(x)).
MSinCos *insSinCos = MSinCos::New(graph.alloc(),
insFunc->input(),
insFunc->toMathFunction()->cache());
insSinCos->setImplicitlyUsedUnchecked();
block->insertBefore(insFunc, insSinCos);
for (MUseDefIterator uses(insFunc->input()); uses; )
{
MDefinition* def = uses.def();
uses++;
if (!def->isInstruction())
continue;
// We should replacing the argument of the sin/cos just when it
// is dominated by the |block|.
if (!block->dominates(def->block()))
continue;
MInstruction *insUse = def->toInstruction();
if (!insUse->isMathFunction() || insUse->isRecoveredOnBailout())
continue;
MMathFunction *mathIns = insUse->toMathFunction();
if (mathIns->function() != MMathFunction::Sin && mathIns->function() != MMathFunction::Cos)
continue;
mathIns->replaceOperand(0, insSinCos);
JitSpew(JitSpew_Sincos, "Replacing %s by sincos in block %d",
mathIns->function() == MMathFunction::Sin ? "sin" : "cos",
mathIns->block()->id());
}
}
}
}
bool
OptimizeMIR(MIRGenerator* mir)
{
@ -1653,6 +1758,16 @@ OptimizeMIR(MIRGenerator* mir)
return false;
}
if (mir->optimizationInfo().sincosEnabled()) {
AutoTraceLog log(logger, TraceLogger_Sincos);
OptimizeSinCos(mir, graph);
gs.spewPass("Sincos optimization");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Sincos optimization"))
return false;
}
{
AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
if (!EliminateDeadCode(mir, graph))

Просмотреть файл

@ -2094,6 +2094,7 @@ IsResumableMIRType(MIRType type)
case MIRType_Shape:
case MIRType_ObjectGroup:
case MIRType_Doublex2: // NYI, see also RSimdBox::recover
case MIRType_SinCosDouble:
return false;
}
MOZ_CRASH("Unknown MIRType.");

Просмотреть файл

@ -35,6 +35,7 @@ OptimizationInfo::initNormalOptimizationInfo()
loopUnrolling_ = true;
reordering_ = true;
autoTruncate_ = true;
sincos_ = true;
sink_ = true;
registerAllocator_ = RegisterAllocator_Backtracking;
@ -66,6 +67,7 @@ OptimizationInfo::initAsmjsOptimizationInfo()
edgeCaseAnalysis_ = false;
eliminateRedundantChecks_ = false;
autoTruncate_ = false;
sincos_ = false;
sink_ = false;
registerAllocator_ = RegisterAllocator_Backtracking;
scalarReplacement_ = false; // AsmJS has no objects.

Просмотреть файл

@ -85,6 +85,9 @@ class OptimizationInfo
// Toggles whether Truncation based on Range Analysis is used.
bool autoTruncate_;
// Toggles whether sincos is used.
bool sincos_;
// Toggles whether sink is used.
bool sink_;
@ -186,6 +189,10 @@ class OptimizationInfo
return autoTruncate_ && rangeAnalysisEnabled();
}
bool sincosEnabled() const {
return sincos_ && !js_JitOptions.disableSincos;
}
bool sinkEnabled() const {
return sink_ && !js_JitOptions.disableSink;
}

Просмотреть файл

@ -379,6 +379,7 @@ enum MIRType
MIRType_MagicIsConstructing, // JS_IS_CONSTRUCTING magic value.
MIRType_MagicUninitializedLexical, // JS_UNINITIALIZED_LEXICAL magic value.
MIRType_Value,
MIRType_SinCosDouble, // Optimizing a sin/cos to sincos.
MIRType_ObjectOrNull,
MIRType_None, // Invalid, used as a placeholder.
MIRType_Slots, // A slots vector
@ -492,6 +493,8 @@ StringFromMIRType(MIRType type)
return "MagicUninitializedLexical";
case MIRType_Value:
return "Value";
case MIRType_SinCosDouble:
return "SinCosDouble";
case MIRType_ObjectOrNull:
return "ObjectOrNull";
case MIRType_None:

Просмотреть файл

@ -110,6 +110,14 @@ JitOptions::JitOptions()
// Toggles whether shared stubs are used in Ionmonkey.
SET_DEFAULT(disableSharedStubs, true);
// Toggles whether sincos optimization is globally disabled.
// See bug984018: The MacOS is the only one that has the sincos fast.
#if defined(XP_MACOSX)
SET_DEFAULT(disableSincos, false);
#else
SET_DEFAULT(disableSincos, true);
#endif
// Toggles whether sink code motion is globally disabled.
SET_DEFAULT(disableSink, true);

Просмотреть файл

@ -59,6 +59,7 @@ struct JitOptions
bool disableRangeAnalysis;
bool disableScalarReplacement;
bool disableSharedStubs;
bool disableSincos;
bool disableSink;
bool eagerCompilation;
bool forceInlineCaches;

Просмотреть файл

@ -404,6 +404,7 @@ jit::CheckLogging()
" alias Alias analysis\n"
" gvn Global Value Numbering\n"
" licm Loop invariant code motion\n"
" sincos Replace sin/cos by sincos\n"
" sink Sink transformation\n"
" regalloc Register allocation\n"
" inline Inlining\n"
@ -455,6 +456,8 @@ jit::CheckLogging()
EnableChannel(JitSpew_Unrolling);
if (ContainsFlag(env, "licm"))
EnableChannel(JitSpew_LICM);
if (ContainsFlag(env, "sincos"))
EnableChannel(JitSpew_Sincos);
if (ContainsFlag(env, "sink"))
EnableChannel(JitSpew_Sink);
if (ContainsFlag(env, "regalloc"))

Просмотреть файл

@ -26,6 +26,8 @@ namespace jit {
_(Alias) \
/* Information during GVN */ \
_(GVN) \
/* Information during sincos */ \
_(Sincos) \
/* Information during sinking */ \
_(Sink) \
/* Information during Range analysis */ \

Просмотреть файл

@ -350,6 +350,7 @@ static const char * const TypeChars[] =
"d", // DOUBLE
"i32x4", // INT32X4
"f32x4", // FLOAT32X4
"sincos", // SINCOS
#ifdef JS_NUNBOX32
"t", // TYPE
"p" // PAYLOAD

Просмотреть файл

@ -422,6 +422,7 @@ class LDefinition
DOUBLE, // 64-bit floating-point value (FPU).
INT32X4, // SIMD data containing four 32-bit integers (FPU).
FLOAT32X4, // SIMD data containing four 32-bit floats (FPU).
SINCOS,
#ifdef JS_NUNBOX32
// A type virtual register must be followed by a payload virtual
// register, as both will be tracked as a single gcthing.
@ -562,6 +563,8 @@ class LDefinition
case MIRType_Value:
return LDefinition::BOX;
#endif
case MIRType_SinCosDouble:
return LDefinition::SINCOS;
case MIRType_Slots:
case MIRType_Elements:
return LDefinition::SLOTS;

Просмотреть файл

@ -1393,7 +1393,14 @@ void
LIRGenerator::visitMathFunction(MMathFunction* ins)
{
MOZ_ASSERT(IsFloatingPointType(ins->type()));
MOZ_ASSERT(ins->type() == ins->input()->type());
MOZ_ASSERT_IF(ins->input()->type() != MIRType_SinCosDouble,
ins->type() == ins->input()->type());
if (ins->input()->type() == MIRType_SinCosDouble) {
MOZ_ASSERT(ins->type() == MIRType_Double);
redefine(ins, ins->input(), ins->function());
return;
}
LInstruction* lir;
if (ins->type() == MIRType_Double) {
@ -2981,6 +2988,20 @@ LIRGenerator::visitArrayJoin(MArrayJoin* ins)
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitSinCos(MSinCos *ins)
{
MOZ_ASSERT(ins->type() == MIRType_SinCosDouble);
MOZ_ASSERT(ins->input()->type() == MIRType_Double ||
ins->input()->type() == MIRType_Float32 ||
ins->input()->type() == MIRType_Int32);
LSinCos *lir = new (alloc()) LSinCos(useRegisterAtStart(ins->input()),
tempFixed(CallTempReg0),
temp());
defineSinCos(lir, ins);
}
void
LIRGenerator::visitStringSplit(MStringSplit* ins)
{

Просмотреть файл

@ -141,6 +141,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitConcat(MConcat* ins);
void visitCharCodeAt(MCharCodeAt* ins);
void visitFromCharCode(MFromCharCode* ins);
void visitSinCos(MSinCos *ins);
void visitStringSplit(MStringSplit* ins);
void visitStart(MStart* start);
void visitOsrEntry(MOsrEntry* entry);

Просмотреть файл

@ -6119,6 +6119,8 @@ class MMathFunction
void computeRange(TempAllocator& alloc) override;
bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
if (input()->type() == MIRType_SinCosDouble)
return false;
switch(function_) {
case Sin:
case Log:
@ -6626,6 +6628,40 @@ class MFromCharCode
ALLOW_CLONE(MFromCharCode)
};
class MSinCos
: public MUnaryInstruction,
public FloatingPointPolicy<0>::Data
{
const MathCache* cache_;
MSinCos(MDefinition *input, const MathCache *cache) : MUnaryInstruction(input), cache_(cache)
{
setResultType(MIRType_SinCosDouble);
specialization_ = MIRType_Double;
setMovable();
}
public:
INSTRUCTION_HEADER(SinCos)
static MSinCos *New(TempAllocator &alloc, MDefinition *input, const MathCache *cache)
{
return new (alloc) MSinCos(input, cache);
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
bool congruentTo(const MDefinition *ins) const override {
return congruentIfOperandsEqual(ins);
}
bool possiblyCalls() const override {
return true;
}
const MathCache* cache() const {
return cache_;
}
};
class MStringSplit
: public MTernaryInstruction,
public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data

Просмотреть файл

@ -99,6 +99,7 @@ namespace jit {
_(Concat) \
_(CharCodeAt) \
_(FromCharCode) \
_(SinCos) \
_(StringSplit) \
_(Substr) \
_(Return) \

Просмотреть файл

@ -97,6 +97,7 @@ class StackSlotAllocator
case LDefinition::PAYLOAD:
#endif
case LDefinition::DOUBLE: return 8;
case LDefinition::SINCOS:
case LDefinition::FLOAT32X4:
case LDefinition::INT32X4: return 16;
}

Просмотреть файл

@ -493,7 +493,7 @@ bool
DoublePolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def)
{
MDefinition* in = def->getOperand(Op);
if (in->type() == MIRType_Double)
if (in->type() == MIRType_Double || in->type() == MIRType_SinCosDouble)
return true;
MToDouble* replace = MToDouble::New(alloc, in);

Просмотреть файл

@ -3311,6 +3311,38 @@ class LFromCharCode : public LInstructionHelper<1, 1, 0>
}
};
// Calculates sincos(x) and returns two values (sin/cos).
class LSinCos : public LCallInstructionHelper<2, 1, 2>
{
public:
LIR_HEADER(SinCos)
LSinCos(const LAllocation &input, const LDefinition &temp, const LDefinition &temp2)
{
setOperand(0, input);
setTemp(0, temp);
setTemp(1, temp2);
}
const LAllocation *input() {
return getOperand(0);
}
const LDefinition *outputSin() {
return getDef(0);
}
const LDefinition *outputCos() {
return getDef(1);
}
const LDefinition *temp() {
return getTemp(0);
}
const LDefinition *temp2() {
return getTemp(1);
}
const MSinCos *mir() const {
return mir_->toSinCos();
}
};
class LStringSplit : public LCallInstructionHelper<1, 2, 0>
{
public:

Просмотреть файл

@ -162,6 +162,7 @@
_(Concat) \
_(CharCodeAt) \
_(FromCharCode) \
_(SinCos) \
_(StringSplit) \
_(Int32ToDouble) \
_(Float32ToDouble) \

Просмотреть файл

@ -176,6 +176,35 @@ LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir)
add(lir);
}
template <size_t Ops, size_t Temps> void
LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefinition *mir,
LDefinition::Policy policy)
{
MOZ_ASSERT(lir->isCall());
uint32_t vreg = getVirtualRegister();
lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg)));
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(d1)));
#elif defined(JS_CODEGEN_MIPS)
lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2)));
#elif defined(JS_CODEGEN_NONE)
MOZ_CRASH();
#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(xmm1)));
#else
#error "Unsupported architecture for SinCos"
#endif
getVirtualRegister();
lir->setMir(mir);
mir->setVirtualRegister(vreg);
add(lir);
return;
}
// In LIR, we treat booleans and integers as the same low-level type (INTEGER).
// When snapshotting, we recover the actual JS type from MIR. This function
// checks that when making redefinitions, we don't accidentally coerce two
@ -195,6 +224,30 @@ IsCompatibleLIRCoercion(MIRType to, MIRType from)
return false;
}
// We can redefine the sin(x) and cos(x) function to return the sincos result.
void
LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func)
{
MOZ_ASSERT(def->isMathFunction());
MOZ_ASSERT(def->type() == MIRType_Double && as->type() == MIRType_SinCosDouble);
MOZ_ASSERT(MMathFunction::Sin == func || MMathFunction::Cos == func);
ensureDefined(as);
MMathFunction *math = def->toMathFunction();
MOZ_ASSERT(math->function() == MMathFunction::Cos ||
math->function() == MMathFunction::Sin);
// The sincos returns two values:
// - VREG: it returns the sin's value of the sincos;
// - VREG + VREG_INCREMENT: it returns the cos' value of the sincos.
if (math->function() == MMathFunction::Sin)
def->setVirtualRegister(as->virtualRegister());
else
def->setVirtualRegister(as->virtualRegister() + VREG_INCREMENT);
}
void
LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as)
{

Просмотреть файл

@ -142,6 +142,10 @@ class LIRGeneratorShared : public MDefinitionVisitor
inline void defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir,
LDefinition::Policy policy = LDefinition::REGISTER);
template <size_t Ops, size_t Temps>
inline void defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefinition *mir,
LDefinition::Policy policy = LDefinition::REGISTER);
inline void defineSharedStubReturn(LInstruction* lir, MDefinition* mir);
inline void defineReturn(LInstruction* lir, MDefinition* mir);
@ -163,6 +167,9 @@ class LIRGeneratorShared : public MDefinitionVisitor
// virtual register as |as|.
inline void redefine(MDefinition* ins, MDefinition* as);
// Redefine a sin/cos call to sincos.
inline void redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func);
TempAllocator& alloc() const {
return graph.alloc();
}

Просмотреть файл

@ -953,6 +953,40 @@ js::math_sin(JSContext* cx, unsigned argc, Value* vp)
return math_sin_handle(cx, args[0], args.rval());
}
void
js::math_sincos_uncached(double x, double *sin, double *cos)
{
#if defined(__GLIBC__)
sincos(x, sin, cos);
#elif defined(HAVE_SINCOS)
__sincos(x, sin, cos);
#else
*sin = js::math_sin_uncached(x);
*cos = js::math_cos_uncached(x);
#endif
}
void
js::math_sincos_impl(MathCache* mathCache, double x, double *sin, double *cos)
{
unsigned indexSin;
unsigned indexCos;
bool hasSin = mathCache->isCached(x, MathCache::Sin, sin, &indexSin);
bool hasCos = mathCache->isCached(x, MathCache::Cos, cos, &indexCos);
if (!(hasSin || hasCos)) {
js::math_sincos_uncached(x, sin, cos);
mathCache->store(MathCache::Sin, x, *sin, indexSin);
mathCache->store(MathCache::Cos, x, *cos, indexCos);
return;
}
if (!hasSin)
*sin = js::math_sin_impl(mathCache, x);
if (!hasCos)
*cos = js::math_cos_impl(mathCache, x);
}
bool
js::math_sqrt_handle(JSContext* cx, HandleValue number, MutableHandleValue result)
{

Просмотреть файл

@ -80,6 +80,25 @@ class MathCache
return e.out = f(x);
}
bool isCached(double x, MathFuncId id, double *r, unsigned *index) {
*index = hash(x, id);
Entry& e = table[*index];
if (e.in == x && e.id == id) {
*r = e.out;
return true;
}
return false;
}
void store(MathFuncId id, double x, double v, unsigned index) {
Entry &e = table[index];
if (e.in == x && e.id == id)
return;
e.in = x;
e.id = id;
e.out = v;
}
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
};
@ -149,6 +168,12 @@ extern bool
minmax_impl(JSContext* cx, bool max, js::HandleValue a, js::HandleValue b,
js::MutableHandleValue res);
extern void
math_sincos_uncached(double x, double *sin, double *cos);
extern void
math_sincos_impl(MathCache* mathCache, double x, double *sin, double *cos);
extern bool
math_sqrt_handle(JSContext* cx, js::HandleValue number, js::MutableHandleValue result);

Просмотреть файл

@ -5918,6 +5918,15 @@ SetRuntimeOptions(JSRuntime* rt, const OptionParser& op)
return OptionFailure("ion-range-analysis", str);
}
if (const char *str = op.getStringOption("ion-sincos")) {
if (strcmp(str, "on") == 0)
jit::js_JitOptions.disableSincos = false;
else if (strcmp(str, "off") == 0)
jit::js_JitOptions.disableSincos = true;
else
return OptionFailure("ion-sincos", str);
}
if (const char* str = op.getStringOption("ion-sink")) {
if (strcmp(str, "on") == 0)
jit::js_JitOptions.disableSink = false;
@ -6256,6 +6265,13 @@ main(int argc, char** argv, char** envp)
"Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
|| !op.addStringOption('\0', "ion-range-analysis", "on/off",
"Range analysis (default: on, off to disable)")
#if defined(__APPLE__)
|| !op.addStringOption('\0', "ion-sincos", "on/off",
"Replace sin(x)/cos(x) to sincos(x) (default: on, off to disable)")
#else
|| !op.addStringOption('\0', "ion-sincos", "on/off",
"Replace sin(x)/cos(x) to sincos(x) (default: off, on to enable)")
#endif
|| !op.addStringOption('\0', "ion-sink", "on/off",
"Sink code motion (default: off, on to enable)")
|| !op.addStringOption('\0', "ion-loop-unrolling", "on/off",

Просмотреть файл

@ -49,6 +49,7 @@
_(AliasAnalysis) \
_(GVN) \
_(LICM) \
_(Sincos) \
_(RangeAnalysis) \
_(LoopUnrolling) \
_(EffectiveAddressAnalysis) \