Bug 1239075 - RangeAnalysis: Assume that all captured results are used in bailing branches. r=h4writer
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Thu, 03 Mar 2016 13:29:24 +0000
changeset 286609 b4300d783a34181af73612711f21ae98e54f4d69
parent 286608 78d20ae3f50ebe4ce416bbf788a55d7b3050931d
child 286610 2213f8796d4f4a627bc7c4baadf81fddf15a04c8
push id72839
push usernpierron@mozilla.com
push dateThu, 03 Mar 2016 13:42:28 +0000
treeherdermozilla-inbound@b4300d783a34 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1239075
milestone47.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 1239075 - RangeAnalysis: Assume that all captured results are used in bailing branches. r=h4writer
js/src/jit-test/tests/ion/bug1239075.js
js/src/jit/RangeAnalysis.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1239075.js
@@ -0,0 +1,29 @@
+
+function g0() { with({}){}; }
+function f0(y, x) {
+    var a = y >>> 0;
+    a = a - 1 + 1;
+    g0(); // Capture the truncate result after the call.
+    var b = x / 2; // bailout.
+    return ~(a + b);
+}
+assertEq(f0(-1, 0), 0);
+assertEq(f0(-1, 1), 0);
+
+
+function g1() { with({}){}; }
+function f1(y, x) {
+    var a = y >>> 0;
+    a = a - 1 + 1;
+    g1(); // Capture the truncate result after the call.
+    var b = Math.pow(x / 2, x); // bailout.
+    return ~(a + b);
+}
+assertEq(f1(-1, 0), -1);
+assertEq(f1(-1, 1), 0);
+
+function f2(x) {
+    return ~(((~0 | 0) >>> 0 || 0) + Math.pow(Math.cos(x >>> 0), Math.atan2(0, x)))
+}
+assertEq(f2(0), -1);
+assertEq(f2(-9999), 0);
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -2865,39 +2865,34 @@ CloneForDeadBranches(TempAllocator& allo
 }
 
 // Examine all the users of |candidate| and determine the most aggressive
 // truncate kind that satisfies all of them.
 static MDefinition::TruncateKind
 ComputeRequestedTruncateKind(MDefinition* candidate, bool* shouldClone)
 {
     bool isCapturedResult = false;
-    bool isObservableResult = false;
     bool isRecoverableResult = true;
-    bool hasUseRemoved = candidate->isUseRemoved();
 
     MDefinition::TruncateKind kind = MDefinition::Truncate;
     for (MUseIterator use(candidate->usesBegin()); use != candidate->usesEnd(); use++) {
         if (use->consumer()->isResumePoint()) {
             // Truncation is a destructive optimization, as such, we need to pay
             // attention to removed branches and prevent optimization
             // destructive optimizations if we have no alternative. (see
             // UseRemoved flag)
             isCapturedResult = true;
-            isObservableResult = isObservableResult ||
-                use->consumer()->toResumePoint()->isObservableOperand(*use);
             isRecoverableResult = isRecoverableResult &&
                 use->consumer()->toResumePoint()->isRecoverableOperand(*use);
             continue;
         }
 
         MDefinition* consumer = use->consumer()->toDefinition();
         if (consumer->isRecoveredOnBailout()) {
             isCapturedResult = true;
-            hasUseRemoved = hasUseRemoved || consumer->isUseRemoved();
             continue;
         }
 
         MDefinition::TruncateKind consumerKind = consumer->operandTruncateKind(consumer->indexOf(*use));
         kind = Min(kind, consumerKind);
         if (kind == MDefinition::NoTruncate)
             break;
     }
@@ -2912,34 +2907,26 @@ ComputeRequestedTruncateKind(MDefinition
     bool needsConversion = !candidate->range() || !candidate->range()->isInt32();
 
     // If the candidate instruction appears as operand of a resume point or a
     // recover instruction, and we have to truncate its result, then we might
     // have to either recover the result during the bailout, or avoid the
     // truncation.
     if (isCapturedResult && needsConversion) {
 
-        // These optimizations are pointless if there are no removed uses or any
-        // resume point observing the result.  Not having any means that we know
-        // everything about where this results flows into.
-        if ((hasUseRemoved || (isObservableResult && isRecoverableResult)) &&
-            candidate->canRecoverOnBailout())
-        {
-            // The cloned instruction is expected to be used as a recover
-            // instruction.
+        // If the result can be recovered from all the resume points (not needed
+        // for iterating over the inlined frames), and this instruction can be
+        // recovered on bailout, then we can clone it and use the cloned
+        // instruction to encode the recover instruction.  Otherwise, we should
+        // keep the original result and bailout if the value is not in the int32
+        // range.
+        if (isRecoverableResult && candidate->canRecoverOnBailout())
             *shouldClone = true;
-
-        } else if (hasUseRemoved || isObservableResult) {
-            // 1. If uses are removed and we cannot recover the result, then we
-            // need to keep the expected result for dead branches.
-            //
-            // 2. If the result is observable and not recoverable, then the
-            // result might be read while the frame is on the stack.
+        else
             kind = Min(kind, MDefinition::TruncateAfterBailouts);
-        }
     }
 
     return kind;
 }
 
 static MDefinition::TruncateKind
 ComputeTruncateKind(MDefinition* candidate, bool* shouldClone)
 {