Backout 4a76e692a4ab, 2962951f5fcc, d1d2149443ed, 83c3735801e7, 675ef796ed5b, f4b029b6b164, 83fa2144aa1d (bug 765119) for make check failures

This commit is contained in:
Ed Morley 2012-10-05 13:12:10 +01:00
parent d86717645b
commit 73c1ee9ba7
9 changed files with 188 additions and 381 deletions

View File

@ -165,7 +165,7 @@ struct IonOptions
lsra(true),
inlining(true),
edgeCaseAnalysis(true),
rangeAnalysis(true),
rangeAnalysis(false),
parallelCompilation(false),
usesBeforeCompile(10240),
usesBeforeCompileNoJaeger(40),

View File

@ -255,8 +255,7 @@ JSONSpewer::spewMDef(MDefinition *def)
integerValue(use.def()->id());
endList();
stringProperty("type", "%s : [%d, %d]", StringFromMIRType(def->type()),
def->range()->lower(), def->range()->upper());
stringProperty("type", StringFromMIRType(def->type()));
if (def->isInstruction()) {
if (MResumePoint *rp = def->toInstruction()->resumePoint())

View File

@ -10,7 +10,6 @@
#include "MIR.h"
#include "MIRGraph.h"
#include "EdgeCaseAnalysis.h"
#include "IonSpewer.h"
#include "jsnum.h"
#include "jsstr.h"
#include "jsatominlines.h"
@ -34,23 +33,6 @@ MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op)
fprintf(fp, "%c", tolower(name[i]));
}
// If one of the inputs to any non-phi are in a block that will abort, then there is
// no point in processing this instruction, since control flow cannot reach here.
bool
MDefinition::earlyAbortCheck()
{
if (isPhi())
return false;
for (int i = 0; i < numOperands(); i++) {
if (getOperand(i)->block()->earlyAbort()) {
block()->setEarlyAbort();
IonSpew(IonSpew_Range, "Ignoring value from block %d because instruction %d is in a block that aborts", block()->id(), getOperand(i)->id());
return true;
}
}
return false;
}
static inline bool
EqualValues(bool useGVN, MDefinition *left, MDefinition *right)
{
@ -476,55 +458,6 @@ MPhi::addInput(MDefinition *ins)
return inputs_.append(ins);
}
bool
MPhi::recomputeRange()
{
if (type() != MIRType_Int32)
return false;
Range r;
JS_ASSERT(getOperand(0)->op() != MDefinition::Op_OsrValue);
bool updated = false;
for (size_t i = 0; i < numOperands(); i++) {
if (getOperand(i)->block()->earlyAbort()) {
IonSpew(IonSpew_Range, "Ignoring unreachable input %d", getOperand(i)->id());
continue;
}
if (!isOSRLikeValue(getOperand(i))) {
if (block()->isLoopHeader())
changeCounts_[i].updateRange(getOperand(i)->range());
if (updated) {
if (block()->isLoopHeader())
r.unionWith(&changeCounts_[i]);
else
r.unionWith(getOperand(i)->range());
} else {
r.update(getOperand(0)->range());
updated = true;
}
#ifdef DEBUG
if (IonSpewEnabled(IonSpew_Range)) {
fprintf(IonSpewFile, " %d:", getOperand(i)->id());
getOperand(i)->range()->printRange(IonSpewFile);
fprintf(IonSpewFile, " => ");
r.printRange(IonSpewFile);
fprintf(IonSpewFile, "\n");
}
#endif
}
}
if (!updated) {
IonSpew(IonSpew_Range, "My block is unreachable %d", id());
block()->setEarlyAbort();
return false;
}
return range()->update(&r);
}
uint32
MPrepareCall::argc() const
{
@ -1530,15 +1463,3 @@ MBeta::printOpcode(FILE *fp)
fprintf(fp, " ");
comparison_.printRange(fp);
}
bool
MBeta::recomputeRange()
{
bool nullRange = false;
bool ret = range()->update(Range::intersect(val_->range(), &comparison_, &nullRange));
if (nullRange) {
IonSpew(IonSpew_Range, "Marking block for inst %d unexitable", id());
block()->setEarlyAbort();
}
return ret;
}

View File

@ -61,8 +61,6 @@ class MUse;
class MIRGraph;
class MResumePoint;
static inline bool isOSRLikeValue (MDefinition *def);
// Represents a use of a node.
class MUse : public TempObject, public InlineForwardListNode<MUse>
{
@ -305,7 +303,7 @@ class MDefinition : public MNode
virtual void analyzeEdgeCasesForward();
virtual void analyzeEdgeCasesBackward();
virtual void analyzeTruncateBackward();
bool earlyAbortCheck();
// Propagate a range. Return true if the range changed.
virtual bool recomputeRange() {
return false;
@ -1921,12 +1919,6 @@ class MBitAnd : public MBinaryBitwiseInstruction
MDefinition *foldIfEqual() {
return getOperand(0); // x & x => x;
}
bool recomputeRange() {
Range *left = getOperand(0)->range();
Range *right = getOperand(1)->range();
return range()->update(Range::and_(left, right));
}
};
class MBitOr : public MBinaryBitwiseInstruction
@ -2403,8 +2395,7 @@ class MAdd : public MBinaryArithInstruction
return false;
Range *left = getOperand(0)->range();
Range *right = getOperand(1)->range();
Range next = isTruncated() ? Range::addTruncate(left,right) : Range::add(left, right);
return range()->update(next);
return range()->update(Range::add(left, right));
}
};
@ -2446,8 +2437,7 @@ class MSub : public MBinaryArithInstruction
return false;
Range *left = getOperand(0)->range();
Range *right = getOperand(1)->range();
Range next = isTruncated() ? Range::subTruncate(left,right) : Range::sub(left, right);
return range()->update(next);
return range()->update(Range::sub(left, right));
}
};
@ -2486,7 +2476,7 @@ class MMul : public MBinaryArithInstruction
}
bool canBeNegativeZero() {
if (range()->lower() > 0 || range()->upper() < 0)
if (range()->lower() >= 0 && range()->upper() >= 0)
return false;
return canBeNegativeZero_;
}
@ -2589,16 +2579,11 @@ class MMod : public MBinaryArithInstruction
bool recomputeRange() {
if (specialization() != MIRType_Int32)
return false;
Range *rhs = getOperand(1)->range();
int64_t a = Range::abs64((int64_t)rhs->lower());
int64_t b = Range::abs64((int64_t)rhs->upper());
if (a ==0 && b == 0) {
// We should never take something % 0.
Range r(INT_MIN, INT_MAX);
return range()->update(r);
}
int64_t bound = Max(1-a, b-1);
Range r(-bound, bound);
Range *other = getOperand(0)->range();
int64_t a = Range::abs64((int64_t)other->lower());
int64_t b = Range::abs64((int64_t)other->upper());
Range r(Min(-a+1, -b+1),
Max( a-1, b-1));
return range()->update(r);
}
};
@ -2691,9 +2676,7 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
bool triedToSpecialize_;
bool hasBytecodeUses_;
bool isIterator_;
// For every input to the phi, track how many times it has changed
// Only used in loop headers, so it defaults to 0 elements to conserve space
js::Vector<RangeChangeCount, 0, IonAllocPolicy> changeCounts_;
MPhi(uint32 slot)
: slot_(slot),
triedToSpecialize_(false),
@ -2750,9 +2733,18 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool recomputeRange();
bool initCounts() {
return changeCounts_.resize(inputs_.length());
bool recomputeRange() {
if (type() != MIRType_Int32)
return false;
Range r;
r.update(getOperand(0)->range());
for (size_t i = 0; i < numOperands(); i++)
r.unionWith(getOperand(i)->range());
return range()->update(&r);
}
};
@ -2763,9 +2755,9 @@ class MBeta : public MUnaryInstruction
private:
Range comparison_;
MDefinition *val_;
MBeta(MDefinition *val, const Range &comp)
MBeta(MDefinition *val, int32 low, int32 high)
: MUnaryInstruction(val),
comparison_(comp),
comparison_(low, high),
val_(val)
{
}
@ -2773,16 +2765,19 @@ class MBeta : public MUnaryInstruction
public:
INSTRUCTION_HEADER(Beta);
void printOpcode(FILE *fp);
static MBeta *New(MDefinition *val, const Range &comp)
static MBeta *New(MDefinition *val, int32 low, int32 high)
{
return new MBeta(val, comp);
return new MBeta(val, low, high);
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool recomputeRange();
bool recomputeRange() {
return range()->update(
Range::intersect(val_->range(), &comparison_));
}
};
// MIR representation of a Value on the OSR StackFrame.
@ -5578,16 +5573,6 @@ void MNode::initOperand(size_t index, MDefinition *ins)
setOperand(index, ins);
ins->addUse(this, index);
}
static inline bool isOSRLikeValue (MDefinition *def) {
if (def->isOsrValue())
return true;
if (def->isUnbox())
if (def->getOperand(0)->isOsrValue())
return true;
return false;
}
typedef Vector<MDefinition *, 8, IonAllocPolicy> MDefinitionVector;

View File

@ -117,8 +117,7 @@ MBasicBlock::NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred)
}
MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind)
: earlyAbort_(false),
graph_(graph),
: graph_(graph),
info_(info),
stackPosition_(info_.firstStackSlot()),
lastIns_(NULL),

View File

@ -53,10 +53,6 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
bool inheritResumePoint(MBasicBlock *pred);
void assertUsesAreNotWithin(MUseIterator use, MUseIterator end);
// Does this block do something that forces it to terminate early?
bool earlyAbort_;
// Sets a slot, taking care to rewrite copies.
void setSlot(uint32 slot, MDefinition *ins);
@ -88,15 +84,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
void setId(uint32 id) {
id_ = id;
}
void setEarlyAbort() {
earlyAbort_ = true;
}
void clearEarlyAbort() {
earlyAbort_ = false;
}
bool earlyAbort() {
return earlyAbort_;
}
// Move the definition to the top of the stack.
void pick(int32 depth);

View File

@ -156,16 +156,16 @@ RangeAnalysis::addBetaNobes()
if (jsop == JSOP_LT) {
smaller = left;
greater = right;
} else if (jsop == JSOP_GT) {
} else if (JSOP_GT) {
smaller = right;
greater = left;
}
if (smaller && greater) {
MBeta *beta;
beta = MBeta::New(smaller, Range(JSVAL_INT_MIN, JSVAL_INT_MAX-1));
beta = MBeta::New(smaller, JSVAL_INT_MIN, JSVAL_INT_MAX-1);
block->insertBefore(*block->begin(), beta);
replaceDominatedUsesWith(smaller, beta, block);
beta = MBeta::New(greater, Range(JSVAL_INT_MIN+1, JSVAL_INT_MAX));
beta = MBeta::New(greater, JSVAL_INT_MIN+1, JSVAL_INT_MAX);
block->insertBefore(*block->begin(), beta);
replaceDominatedUsesWith(greater, beta, block);
}
@ -175,34 +175,35 @@ RangeAnalysis::addBetaNobes()
JS_ASSERT(val);
Range comp;
int32 low = JSVAL_INT_MIN;
int32 high = JSVAL_INT_MAX;
switch (jsop) {
case JSOP_LE:
comp.setUpper(bound);
high = bound;
break;
case JSOP_LT:
if (!SafeSub(bound, 1, &bound))
break;
comp.setUpper(bound);
high = bound;
break;
case JSOP_GE:
comp.setLower(bound);
low = bound;
break;
case JSOP_GT:
if (!SafeAdd(bound, 1, &bound))
break;
comp.setLower(bound);
low = bound;
break;
case JSOP_EQ:
comp.setLower(bound);
comp.setUpper(bound);
low = bound;
high = bound;
default:
break; // well, for neq we could have
// [-\inf, bound-1] U [bound+1, \inf] but we only use contiguous ranges.
}
IonSpew(IonSpew_Range, "Adding beta node for %d", val->id());
MBeta *beta = MBeta::New(val, comp);
MBeta *beta = MBeta::New(val, low, high);
block->insertBefore(*block->begin(), beta);
replaceDominatedUsesWith(val, beta, block);
}
@ -249,7 +250,7 @@ Range::printRange(FILE *fp)
}
Range
Range::intersect(const Range *lhs, const Range *rhs, bool *nullRange)
Range::intersect(const Range *lhs, const Range *rhs)
{
Range r(
Max(lhs->lower_, rhs->lower_),
@ -272,87 +273,36 @@ Range::intersect(const Range *lhs, const Range *rhs, bool *nullRange)
//
// Instead, we should use it to eliminate the dead block.
// (Bug 765127)
if (r.upper_ < r.lower_) {
*nullRange = true;
if (r.upper_ < r.lower_)
r.makeRangeInfinite();
}
return r;
}
void
Range::unionWith(const Range *other)
{
setLower(Min(lower_, other->lower_));
lower_infinite_ |= other->lower_infinite_;
setUpper(Max(upper_, other->upper_));
upper_infinite_ |= other->upper_infinite_;
}
void
Range::unionWith(RangeChangeCount *other)
{
if (other->lowerCount_ <= 2) {
setLower(Min(lower_, other->oldRange.lower_));
lower_infinite_ |= other->oldRange.lower_infinite_;
} else {
other->lowerCount_ = 0;
}
if (other->upperCount_ <= 2) {
setUpper(Max(upper_, other->oldRange.upper_));
upper_infinite_ |= other->oldRange.upper_infinite_;
} else {
other->upperCount_ = 0;
}
setLower(Min(lower_, other->lower_));
setUpper(Max(upper_, other->upper_));
lower_infinite_ |= other->lower_infinite_;
upper_infinite_ |= other->upper_infinite_;
}
Range
Range::add(const Range *lhs, const Range *rhs)
{
Range ret(
return Range(
(int64_t)lhs->lower_ + (int64_t)rhs->lower_,
(int64_t)lhs->upper_ + (int64_t)rhs->upper_);
return ret;
}
Range
Range::sub(const Range *lhs, const Range *rhs)
{
Range ret(
return Range(
(int64_t)lhs->lower_ - (int64_t)rhs->upper_,
(int64_t)lhs->upper_ - (int64_t)rhs->lower_);
return ret;
}
Range
Range::addTruncate(const Range *lhs, const Range *rhs)
{
Range ret = Truncate((int64_t)lhs->lower_ + (int64_t)rhs->lower_,
(int64_t)lhs->upper_ + (int64_t)rhs->upper_);
return ret;
}
Range
Range::subTruncate(const Range *lhs, const Range *rhs)
{
Range ret = Truncate((int64_t)lhs->lower_ - (int64_t)rhs->upper_,
(int64_t)lhs->upper_ - (int64_t)rhs->lower_);
return ret;
}
Range
Range::and_(const Range *lhs, const Range *rhs)
{
uint64_t lower = 0;
// If both numbers can be negative, issues can be had.
if (lhs->lower_ < 0 && rhs->lower_ < 0)
lower = INT_MIN;
uint64_t upper = lhs->upper_;
if (rhs->upper_ < lhs->upper_)
upper = rhs->upper_;
Range ret(lower, upper);
return ret;
}
Range
Range::mul(const Range *lhs, const Range *rhs)
{
@ -360,30 +310,27 @@ Range::mul(const Range *lhs, const Range *rhs)
int64_t b = (int64_t)lhs->lower_ * (int64_t)rhs->upper_;
int64_t c = (int64_t)lhs->upper_ * (int64_t)rhs->lower_;
int64_t d = (int64_t)lhs->upper_ * (int64_t)rhs->upper_;
Range ret(
return Range(
Min( Min(a, b), Min(c, d) ),
Max( Max(a, b), Max(c, d) ));
return ret;
}
Range
Range::shl(const Range *lhs, int32 c)
{
int32 shift = c & 0x1f;
Range ret(
return Range(
(int64_t)lhs->lower_ << shift,
(int64_t)lhs->upper_ << shift);
return ret;
}
Range
Range::shr(const Range *lhs, int32 c)
{
int32 shift = c & 0x1f;
Range ret(
return Range(
(int64_t)lhs->lower_ >> shift,
(int64_t)lhs->upper_ >> shift);
return ret;
}
bool
@ -394,6 +341,7 @@ Range::update(const Range *other)
lower_infinite_ != other->lower_infinite_ ||
upper_ != other->upper_ ||
upper_infinite_ != other->upper_infinite_;
if (changed) {
lower_ = other->lower_;
lower_infinite_ = other->lower_infinite_;
@ -426,15 +374,6 @@ PopFromWorklist(MDefinitionVector &worklist)
bool
RangeAnalysis::analyze()
{
for (PostorderIterator i(graph_.poBegin()); i != graph_.poEnd(); i++) {
MBasicBlock *curBlock = *i;
if (!curBlock->isLoopHeader())
continue;
for (MPhiIterator pi(curBlock->phisBegin()); pi != curBlock->phisEnd(); pi++)
if (!pi->initCounts())
return false;
}
IonSpew(IonSpew_Range, "Doing range propagation");
MDefinitionVector worklist;
@ -442,17 +381,24 @@ RangeAnalysis::analyze()
for (MDefinitionIterator iter(*block); iter; iter++) {
MDefinition *def = *iter;
if (!def->isPhi() && !def->isBeta())
continue;
AddToWorklist(worklist, def);
}
}
size_t iters = 0;
while (!worklist.empty()) {
#define MAX_ITERS 4096
// XXX: hack: range analysis iloops on jit-test/tests/basic/fannkuch.js
// To circumvent this and land the pass, we just run for a fixed number of
// iterations.
//
// (Bug 765119)
while (!worklist.empty() /* && iters < MAX_ITERS*/) {
MDefinition *def = PopFromWorklist(worklist);
IonSpew(IonSpew_Range, "recomputing range on %d", def->id());
SpewRange(def);
if (!def->earlyAbortCheck() && def->recomputeRange()) {
if (def->recomputeRange()) {
JS_ASSERT(def->range()->lower() <= def->range()->upper());
IonSpew(IonSpew_Range, "Range changed; adding consumers");
for (MUseDefIterator use(def); use; use++) {
@ -466,6 +412,7 @@ RangeAnalysis::analyze()
for(size_t i = 0; i < worklist.length(); i++)
worklist[i]->setNotInWorklist();
#undef MAX_ITERS
#ifdef DEBUG
for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {

View File

@ -21,9 +21,9 @@ class MIRGraph;
class RangeAnalysis
{
protected:
bool blockDominates(MBasicBlock *b, MBasicBlock *b2);
void replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom,
MBasicBlock *block);
bool blockDominates(MBasicBlock *b, MBasicBlock *b2);
void replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom,
MBasicBlock *block);
protected:
MIRGraph &graph_;
@ -35,170 +35,136 @@ class RangeAnalysis
bool removeBetaNobes();
};
struct RangeChangeCount;
class Range {
private:
// :TODO: we should do symbolic range evaluation, where we have
// information of the form v1 < v2 for arbitrary defs v1 and v2, not
// just constants of type int32.
// (Bug 766592)
private:
// :TODO: we should do symbolic range evaluation, where we have
// information of the form v1 < v2 for arbitrary defs v1 and v2, not
// just constants of type int32.
// (Bug 766592)
// We represent ranges where the endpoints can be in the set:
// {-infty} U [INT_MIN, INT_MAX] U {infty}. A bound of +/-
// infty means that the value may have overflowed in that
// direction. When computing the range of an integer
// instruction, the ranges of the operands can be clamped to
// [INT_MIN, INT_MAX], since if they had overflowed they would
// no longer be integers. This is important for optimizations
// and somewhat subtle.
//
// N.B.: All of the operations that compute new ranges based
// on existing ranges will ignore the _infinite_ flags of the
// input ranges; that is, they implicitly clamp the ranges of
// the inputs to [INT_MIN, INT_MAX]. Therefore, while our range might
// be infinite (and could overflow), when using this information to
// propagate through other ranges, we disregard this fact; if that code
// executes, then the overflow did not occur, so we may safely assume
// that the range is [INT_MIN, INT_MAX] instead.
//
// To facilitate this trick, we maintain the invariants that:
// 1) lower_infinite == true implies lower_ == JSVAL_INT_MIN
// 2) upper_infinite == true implies upper_ == JSVAL_INT_MAX
int32 lower_;
bool lower_infinite_;
int32 upper_;
bool upper_infinite_;
// We represent ranges where the endpoints can be in the set:
// {-infty} U [INT_MIN, INT_MAX] U {infty}. A bound of +/-
// infty means that the value may have overflowed in that
// direction. When computing the range of an integer
// instruction, the ranges of the operands can be clamped to
// [INT_MIN, INT_MAX], since if they had overflowed they would
// no longer be integers. This is important for optimizations
// and somewhat subtle.
//
// N.B.: All of the operations that compute new ranges based
// on existing ranges will ignore the _infinite_ flags of the
// input ranges; that is, they implicitly clamp the ranges of
// the inputs to [INT_MIN, INT_MAX]. Therefore, while our range might
// be infinite (and could overflow), when using this information to
// propagate through other ranges, we disregard this fact; if that code
// executes, then the overflow did not occur, so we may safely assume
// that the range is [INT_MIN, INT_MAX] instead.
//
// To facilitate this trick, we maintain the invariants that:
// 1) lower_infinite == true implies lower_ == JSVAL_INT_MIN
// 2) upper_infinite == true implies upper_ == JSVAL_INT_MAX
int32 lower_;
bool lower_infinite_;
int32 upper_;
bool upper_infinite_;
public:
Range()
: lower_(JSVAL_INT_MIN),
lower_infinite_(true),
upper_(JSVAL_INT_MAX),
upper_infinite_(true)
{}
public:
Range() :
lower_(JSVAL_INT_MIN),
lower_infinite_(true),
upper_(JSVAL_INT_MAX),
upper_infinite_(true)
{}
Range(int64_t l, int64_t h) {
setLower(l);
setUpper(h);
}
Range(const Range &other)
: lower_(other.lower_),
lower_infinite_(other.lower_infinite_),
upper_(other.upper_),
upper_infinite_(other.upper_infinite_)
{}
static Range Truncate(int64_t l, int64_t h) {
Range ret(l,h);
if (!ret.isFinite()) {
ret.makeLowerInfinite();
ret.makeUpperInfinite();
Range(int64_t l, int64_t h) {
setLower(l);
setUpper(h);
}
return ret;
}
static int64_t abs64(int64_t x) {
static int64_t abs64(int64_t x) {
#ifdef WTF_OS_WINDOWS
return _abs64(x);
return _abs64(x);
#else
return llabs(x);
return llabs(x);
#endif
}
}
void printRange(FILE *fp);
bool update(const Range *other);
bool update(const Range &other) {
return update(&other);
}
void printRange(FILE *fp);
bool update(const Range *other);
bool update(const Range &other) {
return update(&other);
}
// Unlike the other operations, unionWith is an in-place
// modification. This is to avoid a bunch of useless extra
// copying when chaining together unions when handling Phi
// nodes.
void unionWith(const Range *other);
void unionWith(RangeChangeCount *other);
static Range intersect(const Range *lhs, const Range *rhs, bool *nullRange);
static Range addTruncate(const Range *lhs, const Range *rhs);
static Range subTruncate(const Range *lhs, const Range *rhs);
static Range add(const Range *lhs, const Range *rhs);
static Range sub(const Range *lhs, const Range *rhs);
static Range mul(const Range *lhs, const Range *rhs);
static Range and_(const Range *lhs, const Range *rhs);
static Range shl(const Range *lhs, int32 c);
static Range shr(const Range *lhs, int32 c);
// Unlike the other operations, unionWith is an in-place
// modification. This is to avoid a bunch of useless extra
// copying when chaining together unions when handling Phi
// nodes.
void unionWith(const Range *other);
inline void makeLowerInfinite() {
lower_infinite_ = true;
lower_ = JSVAL_INT_MIN;
}
inline void makeUpperInfinite() {
upper_infinite_ = true;
upper_ = JSVAL_INT_MAX;
}
inline void makeRangeInfinite() {
makeLowerInfinite();
makeUpperInfinite();
}
static Range intersect(const Range *lhs, const Range *rhs);
static Range add(const Range *lhs, const Range *rhs);
static Range sub(const Range *lhs, const Range *rhs);
static Range mul(const Range *lhs, const Range *rhs);
inline bool isLowerInfinite() const {
return lower_infinite_;
}
inline bool isUpperInfinite() const {
return upper_infinite_;
}
static Range shl(const Range *lhs, int32 c);
static Range shr(const Range *lhs, int32 c);
inline bool isFinite() const {
return !isLowerInfinite() && !isUpperInfinite();
}
inline int32 lower() const {
return lower_;
}
inline int32 upper() const {
return upper_;
}
inline void setLower(int64_t x) {
if (x > JSVAL_INT_MAX) { // c.c
lower_ = JSVAL_INT_MAX;
} else if (x < JSVAL_INT_MIN) {
inline void makeLowerInfinite() {
lower_infinite_ = true;
lower_ = JSVAL_INT_MIN;
}
inline void makeUpperInfinite() {
upper_infinite_ = true;
upper_ = JSVAL_INT_MAX;
}
inline void makeRangeInfinite() {
makeLowerInfinite();
} else {
lower_ = (int32)x;
lower_infinite_ = false;
}
}
inline void setUpper(int64_t x) {
if (x > JSVAL_INT_MAX) {
makeUpperInfinite();
} else if (x < JSVAL_INT_MIN) { // c.c
upper_ = JSVAL_INT_MIN;
} else {
upper_ = (int32)x;
upper_infinite_ = false;
}
}
void set(int64_t l, int64_t h) {
setLower(l);
setUpper(h);
}
};
struct RangeChangeCount {
Range oldRange;
unsigned char lowerCount_ : 4;
unsigned char upperCount_ : 4;
RangeChangeCount() : oldRange(), lowerCount_(0), upperCount_(0) {};
void updateRange(Range *newRange) {
JS_ASSERT(newRange->lower() >= oldRange.lower());
if (newRange->lower() != oldRange.lower())
lowerCount_ = lowerCount_ < 15 ? lowerCount_ + 1 : lowerCount_;
JS_ASSERT(newRange->upper() <= oldRange.upper());
if (newRange->upper() != oldRange.upper())
upperCount_ = upperCount_ < 15 ? upperCount_ + 1 : upperCount_;
oldRange = *newRange;
}
inline bool isLowerInfinite() const {
return lower_infinite_;
}
inline bool isUpperInfinite() const {
return upper_infinite_;
}
inline bool isFinite() const {
return !isLowerInfinite() && !isUpperInfinite();
}
inline int32 lower() const {
return lower_;
}
inline int32 upper() const {
return upper_;
}
inline void setLower(int64_t x) {
if (x > JSVAL_INT_MAX) { // c.c
lower_ = JSVAL_INT_MAX;
} else if (x < JSVAL_INT_MIN) {
makeLowerInfinite();
} else {
lower_ = (int32)x;
lower_infinite_ = false;
}
}
inline void setUpper(int64_t x) {
if (x > JSVAL_INT_MAX) {
makeUpperInfinite();
} else if (x < JSVAL_INT_MIN) { // c.c
upper_ = JSVAL_INT_MIN;
} else {
upper_ = (int32)x;
upper_infinite_ = false;
}
}
void set(int64_t l, int64_t h) {
setLower(l);
setUpper(h);
}
};
} // namespace ion

View File

@ -467,10 +467,12 @@ CodeGeneratorARM::visitMulI(LMulI *ins)
Assembler::Condition c = Assembler::Overflow;
//masm.imull(ToOperand(rhs), ToRegister(lhs));
if (mul->canOverflow())
if (mul->canOverflow()) {
c = masm.ma_check_mul(ToRegister(lhs), ToRegister(rhs), ToRegister(dest), c);
else
} else {
masm.ma_mul(ToRegister(lhs), ToRegister(rhs), ToRegister(dest));
}
// Bailout on overflow
if (mul->canOverflow() && !bailoutIf(c, ins->snapshot()))