Bug 836102: Minimal truncate analysis for constants, r=mjrosenb
authorHannes Verschore <hv1989@gmail.com>
Thu, 31 Jan 2013 19:36:58 +0100
changeset 120489 efc9d9f5f30ee04ced4ce563d7f50a8e6cf97a5b
parent 120488 ccdcf297a43fe35a8155b7549c9de2df5578c630
child 120490 1ce8f535ff87099eeff0492079fa5bb12686477b
push id24256
push userryanvm@gmail.com
push dateFri, 01 Feb 2013 20:50:01 +0000
treeherdermozilla-central@4e7c92906a79 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjrosenb
bugs836102
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 836102: Minimal truncate analysis for constants, r=mjrosenb
js/src/ion/MIR.cpp
js/src/ion/MIR.h
js/src/jit-test/tests/ion/bug836102.js
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -329,16 +329,28 @@ MConstant::New(const Value &v)
 
 MConstant::MConstant(const js::Value &vp)
   : value_(vp)
 {
     setResultType(MIRTypeFromValue(vp));
     setMovable();
 }
 
+void
+MConstant::analyzeTruncateBackward()
+{
+    if (js::ion::EdgeCaseAnalysis::AllUsesTruncate(this) &&
+        value_.isDouble() && isBigIntOutput())
+    {
+        // Truncate the double to int, since all uses truncates it.
+        value_.setInt32(ToInt32(value_.toDouble()));
+        setResultType(MIRType_Int32);
+    }
+}
+
 HashNumber
 MConstant::valueHash() const
 {
     // This disregards some state, since values are 64 bits. But for a hash,
     // it's completely acceptable.
     return (HashNumber)JSVAL_TO_IMPL(value_).asBits;
 }
 bool
@@ -977,19 +989,18 @@ bool
 MMod::fallible()
 {
     return !isTruncated();
 }
 
 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)
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -697,16 +697,36 @@ class MConstant : public MNullaryInstruc
 
     HashNumber valueHash() const;
     bool congruentTo(MDefinition * const &ins) const;
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
+    void analyzeTruncateBackward();
+
+    // Returns true if constant is integer between -2^33 & 2^33,
+    // Max cap could be 2^53, if not for the 20 additions hack.
+    bool isBigIntOutput() {
+        if (value_.isInt32())
+            return true;
+        if (value_.isDouble()) {
+            double value = value_.toDouble();
+            int64_t valint = value;
+            int64_t max = 1LL<<33;
+            if (double(valint) != value)
+                return false;
+            if (valint < 0)
+                valint = -valint;
+            return valint < max;
+        }
+        return false;
+    }
+
     void computeRange();
 };
 
 class MParameter : public MNullaryInstruction
 {
     int32_t index_;
     const types::StackTypeSet *typeSet_;
 
@@ -2648,21 +2668,21 @@ class MAdd : public MBinaryArithInstruct
         return 0;
     }
 
     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() {
+    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() {
+    void recalculateBigInt() {
         isBigInt_ = (lhs()->isBigIntOutput() && rhs()->isBigIntOutput());
     }
 };
 
 class MSub : public MBinaryArithInstruction
 {
     int implicitTruncate_;
     MSub(MDefinition *left, MDefinition *right)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug836102.js
@@ -0,0 +1,26 @@
+function t() {
+  var x = 0x123456789abcd;
+  x = x + x; // x = 640511947003802
+  x = x + x; // x = 1281023894007604
+  x = x + x; // x = 2562047788015208
+  x = x + x; // x = 5124095576030416
+  x = x + x; // x = 10248191152060832
+  assertEq(x+1 | 0, -248153696)
+}
+t()
+
+function t2() {
+  var x = -0x123456789abcd;
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  assertEq(x + 7 | 0, 248153704)
+}
+t2()
+
+function t() {
+  var x = 4294967296+1;
+  assertEq(x|0, 1);
+}