Skip to content

Commit

Permalink
Bug 825006: There are some more cases where we can convert double ari…
Browse files Browse the repository at this point in the history
…thmetic to integer arithmetic. (r=nbp)
  • Loading branch information
Marty Rosenberg committed Jan 13, 2013
1 parent 14a8578 commit e87a80c
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 33 deletions.
14 changes: 0 additions & 14 deletions js/src/ion/EdgeCaseAnalysis.cpp
Expand Up @@ -47,20 +47,6 @@ EdgeCaseAnalysis::analyzeLate()
return true;
}

bool
EdgeCaseAnalysis::analyzeEarly()
{

for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); block++) {
if (mir->shouldCancel("Analyze Early (main loop)"))
return false;
for (MInstructionReverseIterator riter(block->rbegin()); riter != block->rend(); riter++)
riter->analyzeTruncateBackward();
}

return true;
}

int
EdgeCaseAnalysis::AllUsesTruncate(MInstruction *m)
{
Expand Down
1 change: 0 additions & 1 deletion js/src/ion/EdgeCaseAnalysis.h
Expand Up @@ -20,7 +20,6 @@ class EdgeCaseAnalysis

public:
EdgeCaseAnalysis(MIRGenerator *mir, MIRGraph &graph);
bool analyzeEarly();
bool analyzeLate();
static int AllUsesTruncate(MInstruction *m);
};
Expand Down
11 changes: 0 additions & 11 deletions js/src/ion/Ion.cpp
Expand Up @@ -850,17 +850,6 @@ CompileBackEnd(MIRGenerator *mir)
return NULL;
}

if (js_IonOptions.edgeCaseAnalysis) {
EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
if (!edgeCaseAnalysis.analyzeEarly())
return NULL;
IonSpewPass("Edge Case Analysis (Early)");
AssertExtendedGraphCoherency(graph);

if (mir->shouldCancel("Edge Case Analysis (Early)"))
return NULL;
}

if (js_IonOptions.gvn) {
ValueNumberer gvn(mir, graph, js_IonOptions.gvnIsOptimistic);
if (!gvn.analyze())
Expand Down
35 changes: 35 additions & 0 deletions js/src/ion/IonAnalysis.cpp
Expand Up @@ -374,6 +374,7 @@ class TypeAnalyzer
bool respecialize(MPhi *phi, MIRType type);
bool propagateSpecialization(MPhi *phi);
bool specializePhis();
bool specializeTruncatedInstructions();
void replaceRedundantPhi(MPhi *phi);
void adjustPhiInputs(MPhi *phi);
bool adjustInputs(MDefinition *def);
Expand Down Expand Up @@ -607,6 +608,8 @@ TypeAnalyzer::analyze()
{
if (!specializePhis())
return false;
if (!specializeTruncatedInstructions())
return false;
if (!insertConversions())
return false;
return true;
Expand Down Expand Up @@ -1435,3 +1438,35 @@ LinearSum::print(Sprinter &sp) const
else if (constant_ < 0)
sp.printf("%d", constant_);
}

bool
TypeAnalyzer::specializeTruncatedInstructions()
{
// This specialization is a two step process: First we loop over the
// instruction stream forwards, marking all of the instructions that
// are computed purely from integers. The theory is that we can observe
// values that don't fit into a 32 bit integer that can still be treated as
// integers.
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
if (mir->shouldCancel("recoverBigInts (forwards loop)"))
return false;

for (MDefinitionIterator iter(*block); iter; iter++) {
iter->recalculateBigInt();
}
}

// Now, if these adds of doubles-that-are-really-big-ints get truncated
// on all reads, then we know that we don't care that any of these operations
// produces a value that is not an integer. To achieve this, loop over the instruction
// stream backwards, marking every instruction where all reads are operations that truncate
// If we have a double operation that is marked both "bigInt" and "truncated", then we can
// safely convert it into an integer instruction
for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); block++) {
if (mir->shouldCancel("Propagate Truncates (backwards loop)"))
return false;
for (MInstructionReverseIterator riter(block->rbegin()); riter != block->rend(); riter++)
riter->analyzeTruncateBackward();
}
return true;
}
9 changes: 5 additions & 4 deletions js/src/ion/LIR.cpp
Expand Up @@ -297,15 +297,16 @@ LInstruction::assignSnapshot(LSnapshot *snapshot)
void
LInstruction::print(FILE *fp)
{
printName(fp);

fprintf(fp, " (");
fprintf(fp, "{");
for (size_t i = 0; i < numDefs(); i++) {
PrintDefinition(fp, *getDef(i));
if (i != numDefs() - 1)
fprintf(fp, ", ");
}
fprintf(fp, ")");
fprintf(fp, "} <- ");

printName(fp);


printInfo(fp);

Expand Down
16 changes: 15 additions & 1 deletion js/src/ion/MIR.cpp
Expand Up @@ -860,8 +860,22 @@ MMod::foldsTo(bool useValueNumbers)
void
MAdd::analyzeTruncateBackward()
{
if (!isTruncated())
if (!isTruncated()) {
setTruncated(js::ion::EdgeCaseAnalysis::AllUsesTruncate(this));
}
if (isTruncated() && isTruncated() < 20) {
// Super obvious optimization... If this operation is a double
// BUT it happens to look like a large precision int that eventually
// gets truncated, then just call it an int.
// This can arise if we have x+y | 0, and x and y are both INT_MAX,
// TI will observe an overflow, thus marking the addition as double-like
// but we'll have MTruncate(MAddD(toDouble(x), toDouble(y))), which we know
// we'll be able to convert to MAddI(x,y)
if (isBigInt_ && type() == MIRType_Double) {
specialization_ = MIRType_Int32;
setResultType(MIRType_Int32);
}
}
}

bool
Expand Down
24 changes: 22 additions & 2 deletions js/src/ion/MIR.h
Expand Up @@ -473,6 +473,14 @@ class MDefinition : public MNode
JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags());
return true;
}
// This indicates if this instruction is "integral at heart". This will
// be the case if
// a) its result type is int32
// b) it is an instruction that is very likely to produce an integer or integer-truncatable
// result (add, mul, sub), and both of its inputs are ints. (currently only implemented for add)
virtual bool isBigIntOutput() { return resultType_ == MIRType_Int32; }
virtual void recalculateBigInt() {}

};

// An MUseDefIterator walks over uses in a definition, skipping any use that is
Expand Down Expand Up @@ -2568,10 +2576,12 @@ class MMathFunction
class MAdd : public MBinaryArithInstruction
{
int implicitTruncate_;

// Is this instruction really an int at heart?
bool isBigInt_;
MAdd(MDefinition *left, MDefinition *right)
: MBinaryArithInstruction(left, right),
implicitTruncate_(0)
implicitTruncate_(0),
isBigInt_(left->isBigIntOutput() && right->isBigIntOutput())
{
setResultType(MIRType_Value);
}
Expand All @@ -2596,6 +2606,16 @@ class MAdd : public MBinaryArithInstruction

bool fallible();
void computeRange();
// This is an add, so the return value is from only
// integer sources if we know we return an int32
// or it has been explicitly marked as being a large int.
virtual bool isBigIntOutput() {
return (type() == MIRType_Int32) || isBigInt_;
}
// An add will produce a big int if both of its sources are big ints.
virtual void recalculateBigInt() {
isBigInt_ = (lhs()->isBigIntOutput() && rhs()->isBigIntOutput());
}
};

class MSub : public MBinaryArithInstruction
Expand Down
28 changes: 28 additions & 0 deletions js/src/jit-test/tests/ion/truncate.js
@@ -0,0 +1,28 @@
function f() {
var x = Math.pow(2, 31); // take it as argument if constant propagation comes in you way.
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 32
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 33
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 34
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 35
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 36
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 37
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 38
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 39
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 40
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 41
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 42
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 43
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 44
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 45
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 46
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 47
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 48
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 49
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 50
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 51
x = x + x; assertEq((x + 1) | 0, 1); // 2 ** 52
x = x + x; assertEq((x + 1) | 0, 0); // 2 ** 53
}

for (var i = 0; i <= 100000; i++)
f();

0 comments on commit e87a80c

Please sign in to comment.