Bug 1010586 - IonMonkey: Eliminate the isObserved flag and compute observability on demand. r=nbp
authorDan Gohman <sunfish@mozilla.com>
Tue, 20 May 2014 18:43:15 -0700
changeset 184046 d016c59f0876a3a99913bf057a8c3047cfbbac5b
parent 184045 0e9ed96596b14b99a692d1b8415fb68b11d42abc
child 184047 13a2d22d5eb3048118a97212dd86838218e47a79
push id26810
push usercbook@mozilla.com
push dateWed, 21 May 2014 11:46:36 +0000
treeherdermozilla-central@50fb8c4db2fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1010586
milestone32.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 1010586 - IonMonkey: Eliminate the isObserved flag and compute observability on demand. r=nbp
js/src/jit/IonAnalysis.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -102,37 +102,42 @@ jit::EliminateDeadResumePointOperands(MI
             }
 
             // If the instruction's behavior has been constant folded into a
             // separate instruction, we can't determine precisely where the
             // instruction becomes dead and can't eliminate its uses.
             if (ins->isImplicitlyUsed())
                 continue;
 
-            // If the instruction's is captured by one of the resume point, then
-            // it might be observed indirectly while the frame is live on the
-            // stack, so it has to be computed.
-            if (ins->isObserved())
-                continue;
-
             // Check if this instruction's result is only used within the
             // current block, and keep track of its last use in a definition
             // (not resume point). This requires the instructions in the block
             // to be numbered, ensured by running this immediately after alias
             // analysis.
             uint32_t maxDefinition = 0;
-            for (MUseDefIterator uses(*ins); uses; uses++) {
-                if (uses.def()->block() != *block ||
-                    uses.def()->isBox() ||
-                    uses.def()->isPhi())
-                {
+            for (MUseIterator uses(ins->usesBegin()); uses != ins->usesEnd(); uses++) {
+                MNode *consumer = uses->consumer();
+                if (consumer->isResumePoint()) {
+                    // If the instruction's is captured by one of the resume point, then
+                    // it might be observed indirectly while the frame is live on the
+                    // stack, so it has to be computed.
+                    MResumePoint *resume = consumer->toResumePoint();
+                    if (resume->isObservableOperand(*uses)) {
+                        maxDefinition = UINT32_MAX;
+                        break;
+                    }
+                    continue;
+                }
+
+                MDefinition *def = consumer->toDefinition();
+                if (def->block() != *block || def->isBox() || def->isPhi()) {
                     maxDefinition = UINT32_MAX;
                     break;
                 }
-                maxDefinition = Max(maxDefinition, uses.def()->id());
+                maxDefinition = Max(maxDefinition, def->id());
             }
             if (maxDefinition == UINT32_MAX)
                 continue;
 
             // Walk the uses a second time, removing any in resume points after
             // the last use in a definition.
             for (MUseIterator uses(ins->usesBegin()); uses != ins->usesEnd(); ) {
                 if (uses->consumer()->isDefinition()) {
@@ -208,34 +213,32 @@ IsPhiObservable(MPhi *phi, Observability
     // Check for uses of this phi node outside of other phi nodes.
     // Note that, initially, we skip reading resume points, which we
     // don't count as actual uses. If the only uses are resume points,
     // then the SSA name is never consumed by the program.  However,
     // after optimizations have been performed, it's possible that the
     // actual uses in the program have been (incorrectly) optimized
     // away, so we must be more conservative and consider resume
     // points as well.
-    switch (observe) {
-      case AggressiveObservability:
-        for (MUseDefIterator iter(phi); iter; iter++) {
-            if (!iter.def()->isPhi())
+    for (MUseIterator iter(phi->usesBegin()); iter != phi->usesEnd(); iter++) {
+        MNode *consumer = iter->consumer();
+        if (consumer->isResumePoint()) {
+            MResumePoint *resume = consumer->toResumePoint();
+            if (observe == ConservativeObservability)
+                return true;
+            if (resume->isObservableOperand(*iter))
+                return true;
+        } else {
+            MDefinition *def = consumer->toDefinition();
+            if (!def->isPhi())
                 return true;
         }
-        break;
-
-      case ConservativeObservability:
-        for (MUseIterator iter(phi->usesBegin()); iter != phi->usesEnd(); iter++) {
-            if (!iter->consumer()->isDefinition() ||
-                !iter->consumer()->toDefinition()->isPhi())
-                return true;
-        }
-        break;
     }
 
-    return phi->isObserved();
+    return false;
 }
 
 // Handles cases like:
 //    x is phi(a, x) --> a
 //    x is phi(a, a) --> a
 static inline MDefinition *
 IsPhiRedundant(MPhi *phi)
 {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2377,16 +2377,22 @@ MResumePoint::dump(FILE *fp) const
 
 void
 MResumePoint::dump() const
 {
     dump(stderr);
 }
 
 bool
+MResumePoint::isObservableOperand(MUse *u) const
+{
+    return isObservableOperand(indexOf(u));
+}
+
+bool
 MResumePoint::isObservableOperand(size_t index) const
 {
     return block()->info().isObservableSlot(index);
 }
 
 MDefinition *
 MToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
 {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -62,17 +62,16 @@ MIRType MIRTypeFromValue(const js::Value
 #define MIR_FLAG_LIST(_)                                                        \
     _(InWorklist)                                                               \
     _(EmittedAtUses)                                                            \
     _(LoopInvariant)                                                            \
     _(Commutative)                                                              \
     _(Movable)       /* Allow LICM and GVN to move this instruction */          \
     _(Lowered)       /* (Debug only) has a virtual register */                  \
     _(Guard)         /* Not removable if uses == 0 */                           \
-    _(Observed)      /* Cannot be optimized out */                              \
                                                                                 \
     /* Keep the flagged instruction in resume points and do not substitute this
      * instruction by an UndefinedValue. This might be used by call inlining
      * when a function argument is not used by the inlined instructions.
      */                                                                         \
     _(ImplicitlyUsed)                                                           \
                                                                                 \
     /* The instruction has been marked dead for lazy removal from resume
@@ -9744,22 +9743,18 @@ class MResumePoint MOZ_FINAL : public MN
     // The array may then be filled in by inherit().
     bool init(TempAllocator &alloc) {
         return operands_.init(alloc, stackDepth_);
     }
 
     // Overwrites an operand without updating its Uses.
     void setOperand(size_t index, MDefinition *operand) {
         JS_ASSERT(index < stackDepth_);
-        // Note: We do not remove the isObserved flag, as this would imply that
-        // we check the list of uses of the removed MDefinition.
         operands_[index].set(operand, this);
         operand->addUse(&operands_[index]);
-        if (!operand->isObserved() && isObservableOperand(index))
-            operand->setObserved();
     }
 
     void clearOperand(size_t index) {
         JS_ASSERT(index < stackDepth_);
         operands_[index].set(nullptr, this);
     }
 
     MUse *getUseFor(size_t index) {
@@ -9780,21 +9775,21 @@ class MResumePoint MOZ_FINAL : public MN
         return stackDepth_;
     }
     size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
         MOZ_ASSERT(u >= &operands_[0]);
         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
         return u - &operands_[0];
     }
 
+    bool isObservableOperand(MUse *u) const;
     bool isObservableOperand(size_t index) const;
 
     MDefinition *getOperand(size_t index) const {
         JS_ASSERT(index < stackDepth_);
-        MOZ_ASSERT_IF(isObservableOperand(index), operands_[index].producer()->isObserved());
         return operands_[index].producer();
     }
     jsbytecode *pc() const {
         return pc_;
     }
     uint32_t stackDepth() const {
         return stackDepth_;
     }