Bug 600414 - TM: Use a more precise check for negative zero when multiplying (r=nnethercote)

This commit is contained in:
Bill McCloskey 2010-10-18 15:13:55 -07:00
parent 07c37b877b
commit 8db35b0563
2 changed files with 74 additions and 8 deletions

View File

@ -1266,12 +1266,27 @@ Oracle::isInstructionUndemotable(jsbytecode* pc) const
return _pcDontDemote.get(PCHash(pc));
}
/* Tell the oracle that the instruction at bytecode location should use a stronger (slower) test for -0. */
void
Oracle::markInstructionSlowZeroTest(jsbytecode* pc)
{
_pcSlowZeroTest.set(PCHash(pc));
}
/* Consult with the oracle whether we should use a stronger (slower) test for -0. */
bool
Oracle::isInstructionSlowZeroTest(jsbytecode* pc) const
{
return _pcSlowZeroTest.get(PCHash(pc));
}
void
Oracle::clearDemotability()
{
_stackDontDemote.reset();
_globalDontDemote.reset();
_pcDontDemote.reset();
_pcSlowZeroTest.reset();
}
JS_REQUIRES_STACK void
@ -6250,8 +6265,12 @@ TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount)
: ARECORD_ABORTED;
}
case MUL_ZERO_EXIT:
case OVERFLOW_EXIT:
traceMonitor->oracle->markInstructionUndemotable(cx->regs->pc);
if (lr->exitType == MUL_ZERO_EXIT)
traceMonitor->oracle->markInstructionSlowZeroTest(cx->regs->pc);
else
traceMonitor->oracle->markInstructionUndemotable(cx->regs->pc);
/* FALL THROUGH */
case BRANCH_EXIT:
case CASE_EXIT:
@ -7221,8 +7240,12 @@ MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
#endif
return RecordingIfTrue(rv);
case MUL_ZERO_EXIT:
case OVERFLOW_EXIT:
tm->oracle->markInstructionUndemotable(cx->regs->pc);
if (lr->exitType == MUL_ZERO_EXIT)
tm->oracle->markInstructionSlowZeroTest(cx->regs->pc);
else
tm->oracle->markInstructionUndemotable(cx->regs->pc);
/* FALL THROUGH */
case BRANCH_EXIT:
case CASE_EXIT:
@ -8330,6 +8353,21 @@ TraceRecorder::stack(int n, LIns* i)
set(&stackval(n), i);
}
/* Leave trace iff one operand is negative and the other is non-negative. */
JS_REQUIRES_STACK void
TraceRecorder::guardNonNeg(LIns* d0, LIns* d1, VMSideExit* exit)
{
if (d0->isImmI())
JS_ASSERT(d0->immI() >= 0);
else
guard(false, lir->ins2ImmI(LIR_lti, d0, 0), exit);
if (d1->isImmI())
JS_ASSERT(d1->immI() >= 0);
else
guard(false, lir->ins2ImmI(LIR_lti, d1, 0), exit);
}
JS_REQUIRES_STACK LIns*
TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1)
{
@ -8360,7 +8398,7 @@ TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1)
break;
case LIR_muld:
r = v0 * v1;
if (r == 0.0)
if (r == 0.0 && (v0 < 0.0 || v1 < 0.0))
goto out;
break;
#if defined NANOJIT_IA32 || defined NANOJIT_X64
@ -8475,11 +8513,30 @@ TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1)
result = lir->ins2(v, d0, d1);
}
if (needsNegZeroCheck) {
// make sure we don't lose a -0
JS_ASSERT(v == LIR_muli);
if (!exit)
exit = snapshot(OVERFLOW_EXIT);
guard(false, lir->insEqI_0(result), exit);
/*
* Make sure we don't lose a -0. We exit if the result is zero and if
* either operand is negative. We start out using a weaker guard, checking
* if either argument is negative. If this ever fails, we recompile with
* a stronger, but slower, guard.
*/
if (v0 < 0.0 || v1 < 0.0
|| !oracle || oracle->isInstructionSlowZeroTest(cx->regs->pc))
{
if (!exit)
exit = snapshot(OVERFLOW_EXIT);
guard(true,
lir->insEqI_0(lir->ins2(LIR_andi,
lir->insEqI_0(result),
lir->ins2(LIR_ori,
lir->ins2ImmI(LIR_lti, d0, 0),
lir->ins2ImmI(LIR_lti, d1, 0)))),
exit);
} else {
guardNonNeg(d0, d1, snapshot(MUL_ZERO_EXIT));
}
}
break;
}
@ -16597,8 +16654,12 @@ MonitorTracePoint(JSContext* cx, uintN& inlineCallCount, bool& blacklist)
return TPA_RanStuff;
break;
case MUL_ZERO_EXIT:
case OVERFLOW_EXIT:
tm->oracle->markInstructionUndemotable(cx->regs->pc);
if (lr->exitType == MUL_ZERO_EXIT)
tm->oracle->markInstructionSlowZeroTest(cx->regs->pc);
else
tm->oracle->markInstructionUndemotable(cx->regs->pc);
/* FALL THROUGH */
case BRANCH_EXIT:
case CASE_EXIT:

View File

@ -303,6 +303,7 @@ class Oracle {
avmplus::BitSet _stackDontDemote;
avmplus::BitSet _globalDontDemote;
avmplus::BitSet _pcDontDemote;
avmplus::BitSet _pcSlowZeroTest;
public:
Oracle();
@ -314,6 +315,8 @@ public:
JS_REQUIRES_STACK bool isStackSlotUndemotable(JSContext* cx, unsigned slot, const void* pc) const;
void markInstructionUndemotable(jsbytecode* pc);
bool isInstructionUndemotable(jsbytecode* pc) const;
void markInstructionSlowZeroTest(jsbytecode* pc);
bool isInstructionSlowZeroTest(jsbytecode* pc) const;
void clearDemotability();
void clear() {
@ -369,6 +372,7 @@ public:
*/ \
_(OOM) \
_(OVERFLOW) \
_(MUL_ZERO) \
_(UNSTABLE_LOOP) \
_(TIMEOUT) \
_(DEEP_BAIL) \
@ -1111,6 +1115,7 @@ class TraceRecorder
JS_REQUIRES_STACK nanojit::LIns* stack(int n);
JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i);
JS_REQUIRES_STACK void guardNonNeg(nanojit::LIns* d0, nanojit::LIns* d1, VMSideExit* exit);
JS_REQUIRES_STACK nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1,
nanojit::LIns* s0, nanojit::LIns* s1);