mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout 4a76e692a4ab, 2962951f5fcc, d1d2149443ed, 83c3735801e7, 675ef796ed5b, f4b029b6b164, 83fa2144aa1d (bug 765119) for make check failures
This commit is contained in:
parent
d86717645b
commit
73c1ee9ba7
@ -165,7 +165,7 @@ struct IonOptions
|
||||
lsra(true),
|
||||
inlining(true),
|
||||
edgeCaseAnalysis(true),
|
||||
rangeAnalysis(true),
|
||||
rangeAnalysis(false),
|
||||
parallelCompilation(false),
|
||||
usesBeforeCompile(10240),
|
||||
usesBeforeCompileNoJaeger(40),
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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++) {
|
||||
|
@ -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
|
||||
|
@ -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()))
|
||||
|
Loading…
Reference in New Issue
Block a user