Bug 865259 - Specialized arith ops based on baseline info r=bhackett

This commit is contained in:
Nicholas D. Matsakis 2013-04-24 14:28:26 -04:00
Родитель 11a894d05f
Коммит 921353f8ea
7 изменённых файлов: 133 добавлений и 9 удалений

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

@ -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();