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 286679 b4300d783a34181af73612711f21ae98e54f4d69
parent 286678 78d20ae3f50ebe4ce416bbf788a55d7b3050931d
child 286680 2213f8796d4f4a627bc7c4baadf81fddf15a04c8
push id18000
push usercbook@mozilla.com
push dateFri, 04 Mar 2016 12:40:23 +0000
treeherderfx-team@365dff9e6e1f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1239075
milestone47.0a1
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)
 {