зеркало из https://github.com/mozilla/gecko-dev.git
Bug 865259 - Specialized arith ops based on baseline info r=bhackett
This commit is contained in:
Родитель
11a894d05f
Коммит
921353f8ea
|
@ -144,3 +144,64 @@ BaselineInspector::expectedCompareType(jsbytecode *pc)
|
|||
|
||||
return MCompare::Compare_Unknown;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryToSpecializeBinaryArithOp(ICStub::Kind *kinds,
|
||||
uint32_t nkinds,
|
||||
MIRType *result)
|
||||
{
|
||||
bool sawInt32 = false;
|
||||
bool sawDouble = false;
|
||||
bool sawOther = false;
|
||||
|
||||
for (uint32_t i = 0; i < nkinds; i++) {
|
||||
switch (kinds[i]) {
|
||||
case ICStub::BinaryArith_Int32:
|
||||
sawInt32 = true;
|
||||
break;
|
||||
case ICStub::BinaryArith_BooleanWithInt32:
|
||||
sawInt32 = true;
|
||||
break;
|
||||
case ICStub::BinaryArith_Double:
|
||||
sawDouble = true;
|
||||
break;
|
||||
case ICStub::BinaryArith_DoubleWithInt32:
|
||||
sawDouble = true;
|
||||
break;
|
||||
default:
|
||||
sawOther = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sawOther)
|
||||
return false;
|
||||
|
||||
if (sawDouble) {
|
||||
*result = MIRType_Double;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ASSERT(sawInt32);
|
||||
*result = MIRType_Int32;
|
||||
return true;
|
||||
}
|
||||
|
||||
MIRType
|
||||
BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
|
||||
{
|
||||
MIRType result;
|
||||
ICStub::Kind kinds[2];
|
||||
|
||||
kinds[0] = monomorphicStubKind(pc);
|
||||
if (TryToSpecializeBinaryArithOp(kinds, 1, &result))
|
||||
return result;
|
||||
|
||||
if (dimorphicStubKind(pc, &kinds[0], &kinds[1])) {
|
||||
if (TryToSpecializeBinaryArithOp(kinds, 2, &result))
|
||||
return result;
|
||||
}
|
||||
|
||||
return MIRType_None;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ class BaselineInspector
|
|||
|
||||
MIRType expectedResultType(jsbytecode *pc);
|
||||
MCompare::CompareType expectedCompareType(jsbytecode *pc);
|
||||
MIRType expectedBinaryArithSpecialization(jsbytecode *pc);
|
||||
};
|
||||
|
||||
} // namespace ion
|
||||
|
|
|
@ -3259,7 +3259,7 @@ IonBuilder::jsop_binary(JSOp op, MDefinition *left, MDefinition *right)
|
|||
bool overflowed = types::HasOperationOverflowed(script(), pc);
|
||||
|
||||
current->add(ins);
|
||||
ins->infer(overflowed);
|
||||
ins->infer(inspector, pc, overflowed);
|
||||
current->push(ins);
|
||||
|
||||
if (ins->isEffectful())
|
||||
|
|
|
@ -1236,7 +1236,9 @@ KnownNonStringPrimitive(MDefinition *op)
|
|||
}
|
||||
|
||||
void
|
||||
MBinaryArithInstruction::infer(bool overflowed)
|
||||
MBinaryArithInstruction::infer(BaselineInspector *inspector,
|
||||
jsbytecode *pc,
|
||||
bool overflowed)
|
||||
{
|
||||
JS_ASSERT(this->type() == MIRType_Value);
|
||||
|
||||
|
@ -1246,9 +1248,10 @@ MBinaryArithInstruction::infer(bool overflowed)
|
|||
MIRType lhs = getOperand(0)->type();
|
||||
MIRType rhs = getOperand(1)->type();
|
||||
|
||||
// Anything complex - strings and objects - are not specialized.
|
||||
// Anything complex - strings and objects - are not specialized
|
||||
// unless baseline type hints suggest it might be profitable
|
||||
if (!KnownNonStringPrimitive(getOperand(0)) || !KnownNonStringPrimitive(getOperand(1)))
|
||||
return;
|
||||
return inferFallback(inspector, pc);
|
||||
|
||||
// Guess a result type based on the inputs.
|
||||
// Don't specialize for neither-integer-nor-double results.
|
||||
|
@ -1257,7 +1260,7 @@ MBinaryArithInstruction::infer(bool overflowed)
|
|||
else if (lhs == MIRType_Double || rhs == MIRType_Double)
|
||||
setResultType(MIRType_Double);
|
||||
else
|
||||
return;
|
||||
return inferFallback(inspector, pc);
|
||||
|
||||
// If the operation has ever overflowed, use a double specialization.
|
||||
if (overflowed)
|
||||
|
@ -1290,6 +1293,29 @@ MBinaryArithInstruction::infer(bool overflowed)
|
|||
setResultType(rval);
|
||||
}
|
||||
|
||||
void
|
||||
MBinaryArithInstruction::inferFallback(BaselineInspector *inspector,
|
||||
jsbytecode *pc)
|
||||
{
|
||||
// Try to specialize based on what baseline observed in practice.
|
||||
specialization_ = inspector->expectedBinaryArithSpecialization(pc);
|
||||
if (specialization_ != MIRType_None) {
|
||||
setResultType(specialization_);
|
||||
return;
|
||||
}
|
||||
|
||||
// In parallel execution, for now anyhow, we *only* support adding
|
||||
// and manipulating numbers (not strings or objects). So no
|
||||
// matter what we can specialize to double...if the result ought
|
||||
// to have been something else, we'll fail in the various type
|
||||
// guards that get inserted later.
|
||||
if (block()->info().executionMode() == ParallelExecution) {
|
||||
specialization_ = MIRType_Double;
|
||||
setResultType(MIRType_Double);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
SafelyCoercesToDouble(MDefinition *op)
|
||||
{
|
||||
|
|
|
@ -2839,6 +2839,8 @@ class MBinaryArithInstruction
|
|||
// analysis detect a precision loss in the multiplication.
|
||||
bool implicitTruncate_;
|
||||
|
||||
void inferFallback(BaselineInspector *inspector, jsbytecode *pc);
|
||||
|
||||
public:
|
||||
MBinaryArithInstruction(MDefinition *left, MDefinition *right)
|
||||
: MBinaryInstruction(left, right),
|
||||
|
@ -2858,7 +2860,8 @@ class MBinaryArithInstruction
|
|||
|
||||
virtual double getIdentity() = 0;
|
||||
|
||||
void infer(bool overflowed);
|
||||
void infer(BaselineInspector *inspector,
|
||||
jsbytecode *pc, bool overflowed);
|
||||
|
||||
void setInt32() {
|
||||
specialization_ = MIRType_Int32;
|
||||
|
|
|
@ -493,9 +493,13 @@ bool
|
|||
ParallelArrayVisitor::visitCompare(MCompare *compare)
|
||||
{
|
||||
MCompare::CompareType type = compare->compareType();
|
||||
return type == MCompare::Compare_Int32 ||
|
||||
type == MCompare::Compare_Double ||
|
||||
type == MCompare::Compare_String;
|
||||
if (type != MCompare::Compare_Int32 &&
|
||||
type != MCompare::Compare_Double &&
|
||||
type != MCompare::Compare_String)
|
||||
{
|
||||
return markUnsafe();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
load(libdir + "parallelarray-helpers.js");
|
||||
|
||||
// Test that we are able to add numbers even if the typesets are not
|
||||
// "clean" because we have previously added strings and numbers. This
|
||||
// should cause fallible unboxing to occur.
|
||||
|
||||
function theTest() {
|
||||
var mixedArray = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.1,
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
|
||||
|
||||
function op(e, i) {
|
||||
return mixedArray[e % mixedArray.length] + i;
|
||||
}
|
||||
|
||||
// run op once where it has to add doubles and strings,
|
||||
// just to pullute the typesets:
|
||||
var jsarray0 = range(0, 1024);
|
||||
jsarray0.map(op);
|
||||
|
||||
// this version will never actually touch the strings:
|
||||
var jsarray1 = range(0, 1024).map(i => i % 10);
|
||||
compareAgainstArray(jsarray1, "map", op);
|
||||
|
||||
// but if we try against the original we get bailouts:
|
||||
new ParallelArray(jsarray0).map(op, {mode:"par", expect:"disqualified"});
|
||||
}
|
||||
|
||||
if (getBuildConfiguration().parallelJS)
|
||||
theTest();
|
Загрузка…
Ссылка в новой задаче