Bug 1122402 - Flag fallible instructions as guards if used by UCE. r=sunfish

This commit is contained in:
Nicolas B. Pierron 2015-02-02 18:09:22 +01:00
Родитель 410ac1f6e2
Коммит d6db7cbeca
3 изменённых файлов: 80 добавлений и 0 удалений

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

@ -0,0 +1,11 @@
// |jit-test| error:TypeError
(function() {
let r
g = function(x) {
((-0x80000000 + (x >>> 0)) != 0) ? 0 : x()
}
})()
g(NaN)
g(0x80000000);

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

@ -0,0 +1,8 @@
function f(y) {
var x1 = Math.max(-2147483649 >> 0, y >>> 0);
var x2 = x1 | 0;
return (x2 >= 0) ? 1 : 0;
}
assertEq(f(0), 1);
assertEq(f(-1), 0);

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

@ -3218,6 +3218,8 @@ RangeAnalysis::prepareForUCE(bool *shouldRemoveDeadCode)
{ {
*shouldRemoveDeadCode = false; *shouldRemoveDeadCode = false;
MDefinitionVector deadConditions(alloc());
for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) { for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) {
MBasicBlock *block = *iter; MBasicBlock *block = *iter;
@ -3232,6 +3234,7 @@ RangeAnalysis::prepareForUCE(bool *shouldRemoveDeadCode)
// chosen based which of the successors has the unreachable flag which is // chosen based which of the successors has the unreachable flag which is
// added by MBeta::computeRange on its own block. // added by MBeta::computeRange on its own block.
MTest *test = cond->toTest(); MTest *test = cond->toTest();
MDefinition *condition = test->input();
MConstant *constant = nullptr; MConstant *constant = nullptr;
if (block == test->ifTrue()) { if (block == test->ifTrue()) {
constant = MConstant::New(alloc(), BooleanValue(false)); constant = MConstant::New(alloc(), BooleanValue(false));
@ -3239,7 +3242,15 @@ RangeAnalysis::prepareForUCE(bool *shouldRemoveDeadCode)
MOZ_ASSERT(block == test->ifFalse()); MOZ_ASSERT(block == test->ifFalse());
constant = MConstant::New(alloc(), BooleanValue(true)); constant = MConstant::New(alloc(), BooleanValue(true));
} }
if (DeadIfUnused(condition) && !condition->isInWorklist()) {
condition->setInWorklist();
if (!deadConditions.append(condition))
return false;
}
test->block()->insertBefore(test, constant); test->block()->insertBefore(test, constant);
test->replaceOperand(0, constant); test->replaceOperand(0, constant);
JitSpew(JitSpew_Range, "Update condition of %d to reflect unreachable branches.", JitSpew(JitSpew_Range, "Update condition of %d to reflect unreachable branches.",
test->id()); test->id());
@ -3247,5 +3258,55 @@ RangeAnalysis::prepareForUCE(bool *shouldRemoveDeadCode)
*shouldRemoveDeadCode = true; *shouldRemoveDeadCode = true;
} }
// Flag all fallible instructions which were indirectly used in the
// computation of the condition, such that we do not ignore
// bailout-paths which are used to shrink the input range of the
// operands of the condition.
for (size_t i = 0; i < deadConditions.length(); i++) {
MDefinition *cond = deadConditions[i];
// If this instruction is a guard, then there is not need to continue on
// this instruction.
if (cond->isGuard())
continue;
if (cond->range()) {
// Filter the range of the instruction based on its MIRType.
Range typeFilteredRange(cond);
// If the filtered range is updated by adding the original range,
// then the MIRType act as an effectful filter. As we do not know if
// this filtered Range might change or not the result of the
// previous comparison, we have to keep this instruction as a guard
// because it has to bailout in order to restrict the Range to its
// MIRType.
if (typeFilteredRange.update(cond->range())) {
cond->setGuard();
continue;
}
}
for (size_t op = 0, e = cond->numOperands(); op < e; op++) {
MDefinition *operand = cond->getOperand(op);
if (!DeadIfUnused(operand) || operand->isInWorklist())
continue;
// If the operand has no range, then its range is always infered
// from its MIRType, so it cannot be used change the result deduced
// by Range Analysis.
if (!operand->range())
continue;
operand->setInWorklist();
if (!deadConditions.append(operand))
return false;
}
}
while (!deadConditions.empty()) {
MDefinition *cond = deadConditions.popCopy();
cond->setNotInWorklist();
}
return true; return true;
} }