Add narrowing into range analysis, greatly speeding up some testcases (bug 765119, jandem)

This commit is contained in:
Marty Rosenberg 2012-10-02 04:34:28 -04:00
parent de197e9224
commit 395f81ba4d
4 changed files with 90 additions and 20 deletions

View File

@ -10,6 +10,7 @@
#include "MIR.h"
#include "MIRGraph.h"
#include "EdgeCaseAnalysis.h"
#include "IonSpewer.h"
#include "jsnum.h"
#include "jsstr.h"
#include "jsatominlines.h"
@ -458,6 +459,39 @@ 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 0
if (getOperand(i)->block()->earlyAbort()) {
IonSpew(IonSpew_Range, "Ignoring unreachable input %d", getOperand(i)->id());
continue;
}
#endif
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;
}
}
}
return range()->update(&r);
}
uint32
MPrepareCall::argc() const
{

View File

@ -2684,7 +2684,9 @@ 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),
@ -2741,19 +2743,9 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool recomputeRange() {
if (type() != MIRType_Int32)
return false;
Range r;
r.update(getOperand(0)->range());
JS_ASSERT(getOperand(0)->op() != MDefinition::Op_OsrValue);
for (size_t i = 0; i < numOperands(); i++) {
if (!isOSRLikeValue(getOperand(i)))
r.unionWith(getOperand(i)->range(), true);
}
return range()->update(&r);
bool recomputeRange();
bool initCounts() {
return changeCounts_.resize(inputs_.length());
}
};

View File

@ -278,12 +278,29 @@ Range::intersect(const Range *lhs, const Range *rhs)
}
void
Range::unionWith(const Range *other, bool useNarrowing)
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_;
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;
}
}
Range
@ -391,6 +408,15 @@ 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;

View File

@ -35,6 +35,7 @@ class RangeAnalysis
bool removeBetaNobes();
};
struct RangeChangeCount;
class Range {
private:
// :TODO: we should do symbolic range evaluation, where we have
@ -106,7 +107,8 @@ class Range {
// modification. This is to avoid a bunch of useless extra
// copying when chaining together unions when handling Phi
// nodes.
void unionWith(const Range *other, bool useNarrowing = false);
void unionWith(const Range *other);
void unionWith(RangeChangeCount *other);
static Range intersect(const Range *lhs, const Range *rhs);
static Range add(const Range *lhs, const Range *rhs);
@ -174,6 +176,22 @@ class Range {
}
};
struct RangeChangeCount {
Range oldRange;
unsigned char lowerCount_ : 4;
unsigned char upperCount_ : 4;
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;
}
};
} // namespace ion
} // namespace js