Rationalize DFG DCE handling of nodes that perform checks that propagate through AI
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Apr 2015 18:31:26 +0000 (18:31 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Apr 2015 18:31:26 +0000 (18:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144186

Reviewed by Geoffrey Garen.

If I do ArithAdd(Int32Use, Int32Use, CheckOverflow) then AI will prove that this returns
Int32. We may later perform code simplifications based on the proof that this is Int32, and
we may kill all DFG users of this ArithAdd. Then we may prove that there is no exit site at
which the ArithAdd is live. This seems like it is sufficient to then kill the ArithAdd,
except that we still need the overflow check!

Previously we mishandled this:

- In places where we want the overflow check we need to use MustGenerate(@ArithAdd) as a hack
  to keep it alive. That's dirty and it's just indicative of a deeper issue.

- Our MovHint removal doesn't do Phantom canonicalization which essentially makes it
  powerless. This was sort of hiding the bug.

- Nodes that have checks that AI leverages should always be NodeMustGenerate. You can't kill
  something that you are relying on for subsequent simplifications.

This fixes MovHint removal to also canonicalize Phantoms. This also adds ModeMustGenerate to
nodes that may perform checks that are used by AI to guarantee the result type. As a result,
we no longer need the weird MustGenerate node.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArgumentsEliminationPhase.cpp:
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDCEPhase.cpp:
(JSC::DFG::DCEPhase::run):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::tryToRelaxRepresentation):
* dfg/DFGIntegerCheckCombiningPhase.cpp:
(JSC::DFG::IntegerCheckCombiningPhase::handleBlock):
(JSC::DFG::IntegerCheckCombiningPhase::insertMustAdd): Deleted.
* dfg/DFGMayExit.cpp:
(JSC::DFG::mayExit):
* dfg/DFGNode.h:
(JSC::DFG::Node::willHaveCodeGenOrOSR):
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
* dfg/DFGPhantomCanonicalizationPhase.cpp:
(JSC::DFG::PhantomCanonicalizationPhase::run):
* dfg/DFGPhantomRemovalPhase.cpp:
(JSC::DFG::PhantomRemovalPhase::run):
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGTypeCheckHoistingPhase.cpp:
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
* dfg/DFGVarargsForwardingPhase.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
* tests/stress/fold-based-on-int32-proof-mul-branch.js: Added.
(foo):
* tests/stress/fold-based-on-int32-proof-mul.js: Added.
(foo):
* tests/stress/fold-based-on-int32-proof-or-zero.js: Added.
(foo):
* tests/stress/fold-based-on-int32-proof.js: Added.
(foo):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183401 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDCEPhase.cpp
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGIntegerCheckCombiningPhase.cpp
Source/JavaScriptCore/dfg/DFGMayExit.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
Source/JavaScriptCore/dfg/DFGPhantomCanonicalizationPhase.cpp
Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp
Source/JavaScriptCore/dfg/DFGPlan.cpp
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-mul-branch.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-mul.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-or-zero.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof.js [new file with mode: 0644]

index 5f1bb20..7791609 100644 (file)
@@ -1,3 +1,84 @@
+2015-04-24  Filip Pizlo  <fpizlo@apple.com>
+
+        Rationalize DFG DCE handling of nodes that perform checks that propagate through AI
+        https://bugs.webkit.org/show_bug.cgi?id=144186
+
+        Reviewed by Geoffrey Garen.
+        
+        If I do ArithAdd(Int32Use, Int32Use, CheckOverflow) then AI will prove that this returns
+        Int32. We may later perform code simplifications based on the proof that this is Int32, and
+        we may kill all DFG users of this ArithAdd. Then we may prove that there is no exit site at
+        which the ArithAdd is live. This seems like it is sufficient to then kill the ArithAdd,
+        except that we still need the overflow check!
+
+        Previously we mishandled this:
+
+        - In places where we want the overflow check we need to use MustGenerate(@ArithAdd) as a hack
+          to keep it alive. That's dirty and it's just indicative of a deeper issue.
+
+        - Our MovHint removal doesn't do Phantom canonicalization which essentially makes it
+          powerless. This was sort of hiding the bug.
+
+        - Nodes that have checks that AI leverages should always be NodeMustGenerate. You can't kill
+          something that you are relying on for subsequent simplifications.
+        
+        This fixes MovHint removal to also canonicalize Phantoms. This also adds ModeMustGenerate to
+        nodes that may perform checks that are used by AI to guarantee the result type. As a result,
+        we no longer need the weird MustGenerate node.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGArgumentsEliminationPhase.cpp:
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDCEPhase.cpp:
+        (JSC::DFG::DCEPhase::run):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::tryToRelaxRepresentation):
+        * dfg/DFGIntegerCheckCombiningPhase.cpp:
+        (JSC::DFG::IntegerCheckCombiningPhase::handleBlock):
+        (JSC::DFG::IntegerCheckCombiningPhase::insertMustAdd): Deleted.
+        * dfg/DFGMayExit.cpp:
+        (JSC::DFG::mayExit):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::willHaveCodeGenOrOSR):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        (JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
+        * dfg/DFGPhantomCanonicalizationPhase.cpp:
+        (JSC::DFG::PhantomCanonicalizationPhase::run):
+        * dfg/DFGPhantomRemovalPhase.cpp:
+        (JSC::DFG::PhantomRemovalPhase::run):
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGTypeCheckHoistingPhase.cpp:
+        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
+        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
+        * dfg/DFGVarargsForwardingPhase.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        * tests/stress/fold-based-on-int32-proof-mul-branch.js: Added.
+        (foo):
+        * tests/stress/fold-based-on-int32-proof-mul.js: Added.
+        (foo):
+        * tests/stress/fold-based-on-int32-proof-or-zero.js: Added.
+        (foo):
+        * tests/stress/fold-based-on-int32-proof.js: Added.
+        (foo):
+
 2015-04-26  Ryosuke Niwa  <rniwa@webkit.org>
 
         Class body ending with a semicolon throws a SyntaxError
index 8316af1..a8c0796 100644 (file)
@@ -2080,7 +2080,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case ProfileType:
     case ProfileControlFlow:
     case Phantom:
-    case MustGenerate:
     case CountExecution:
     case CheckTierUpInLoop:
     case CheckTierUpAtReturn:
index 2f6f3cf..a974f13 100644 (file)
@@ -161,7 +161,6 @@ private:
 
                 case Phantom:
                 case Check:
-                case MustGenerate:
                 case MovHint:
                 case PutHint:
                     break;
index 2029298..d38579e 100644 (file)
@@ -115,7 +115,6 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         
     case Identity:
     case Phantom:
-    case MustGenerate:
     case Check:
     case ExtractOSREntryLocal:
     case CheckStructureImmediate:
index 97e0c57..7fe8868 100644 (file)
@@ -71,7 +71,7 @@ public:
             cleanVariables(m_graph.m_arguments);
         }
         
-        // Just do a basic MustGenerate/Phantom/Check clean-up.
+        // Just do a basic Phantom/Check clean-up.
         for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
             BasicBlock* block = m_graph.block(blockIndex);
             if (!block)
@@ -82,7 +82,6 @@ public:
                 Node* node = block->at(sourceIndex++);
                 switch (node->op()) {
                 case Check:
-                case MustGenerate:
                 case Phantom:
                     if (node->children.isEmpty())
                         continue;
index eafe633..4871f0a 100644 (file)
@@ -55,7 +55,6 @@ bool doesGC(Graph& graph, Node* node)
     case MovHint:
     case ZombieHint:
     case Phantom:
-    case MustGenerate:
     case Upsilon:
     case Phi:
     case Flush:
index e9ca28b..f74ecbd 100644 (file)
@@ -1033,7 +1033,6 @@ private:
         case ConstantStoragePointer:
         case DoubleAsInt32:
         case ValueToInt32:
-        case MustGenerate: // MustGenerate would be trivial to handle but anyway we assert that we won't see it here yet.
         case DoubleRep:
         case ValueRep:
         case Int52Rep:
@@ -2018,7 +2017,6 @@ private:
         case MovHint:
         case Phantom:
         case Check:
-        case MustGenerate:
             DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, fixEdgeRepresentation);
             break;
             
index 607ae8c..6dd9565 100644 (file)
@@ -236,12 +236,12 @@ private:
                 switch (data.m_key.m_kind) {
                 case Addition: {
                     if (range.m_minBound < 0) {
-                        insertMustAdd(
+                        insertAdd(
                             nodeIndex, NodeOrigin(range.m_minOrigin, node->origin.forExit),
                             data.m_key.m_source, range.m_minBound);
                     }
                     if (range.m_maxBound > 0) {
-                        insertMustAdd(
+                        insertAdd(
                             nodeIndex, NodeOrigin(range.m_maxOrigin, node->origin.forExit),
                             data.m_key.m_source, range.m_maxBound);
                     }
@@ -385,15 +385,6 @@ private:
                 nodeIndex, origin, jsNumber(addend), source.useKind()));
     }
     
-    Node* insertMustAdd(
-        unsigned nodeIndex, NodeOrigin origin, Edge source, int32_t addend)
-    {
-        Node* result = insertAdd(nodeIndex, origin, source, addend);
-        m_insertionSet.insertNode(
-            nodeIndex, SpecNone, MustGenerate, origin, result->defaultEdge());
-        return result;
-    }
-    
     typedef std::unordered_map<RangeKey, Range, HashMethod<RangeKey>> RangeMap;
     RangeMap m_map;
     
index a7b425a..22ff607 100644 (file)
@@ -85,7 +85,6 @@ bool mayExit(Graph& graph, Node* node)
     case Flush:
     case Phantom:
     case Check:
-    case MustGenerate:
     case GetLocal:
     case LoopHint:
     case Phi:
@@ -105,6 +104,9 @@ bool mayExit(Graph& graph, Node* node)
     case Jump:
     case Branch:
     case Unreachable:
+    case DoubleRep:
+    case Int52Rep:
+    case ValueRep:
         break;
         
     default:
index e835444..de7dd58 100644 (file)
@@ -1554,7 +1554,6 @@ struct Node {
         case ZombieHint:
             return true;
         case Phantom:
-        case MustGenerate:
             return child1().useKindUnchecked() != UntypedUse || child2().useKindUnchecked() != UntypedUse || child3().useKindUnchecked() != UntypedUse;
         default:
             return shouldGenerate();
index abab2a6..521d13d 100644 (file)
@@ -71,7 +71,6 @@ namespace JSC { namespace DFG {
     macro(MovHint, NodeMustGenerate) \
     macro(ZombieHint, NodeMustGenerate) \
     macro(Phantom, NodeMustGenerate) \
-    macro(MustGenerate, NodeMustGenerate) /* Utility node for making soem not-usually-NodeMustGenerate node become like NodeMustGenerate. */ \
     macro(Check, NodeMustGenerate) /* Used if we want just a type check but not liveness. Non-checking uses will be removed. */\
     macro(Upsilon, NodeRelevantToOSR) \
     macro(Phi, NodeRelevantToOSR) \
@@ -130,16 +129,22 @@ namespace JSC { namespace DFG {
     /* Bogus type asserting node. Useful for testing, disappears during Fixup. */\
     macro(FiatInt52, NodeResultJS) \
     \
-    /* Nodes for arithmetic operations. */\
-    macro(ArithAdd, NodeResultNumber) \
+    /* Nodes for arithmetic operations. Note that if they do checks other than just type checks, */\
+    /* then they are MustGenerate. This is probably stricter than it needs to be - for example */\
+    /* they won't do checks if they are speculated double. Also, we could kill these if we do it */\
+    /* before AI starts eliminating downstream operations based on proofs, for example in the */\
+    /* case of "var tmp = a + b; return (tmp | 0) == tmp;". If a, b are speculated integer then */\
+    /* this is only true if we do the overflow check - hence the need to keep it alive. More */\
+    /* generally, we need to keep alive any operation whose checks cause filtration in AI. */\
+    macro(ArithAdd, NodeResultNumber | NodeMustGenerate) \
     macro(ArithClz32, NodeResultInt32) \
-    macro(ArithSub, NodeResultNumber) \
-    macro(ArithNegate, NodeResultNumber) \
-    macro(ArithMul, NodeResultNumber) \
+    macro(ArithSub, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithNegate, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithMul, NodeResultNumber | NodeMustGenerate) \
     macro(ArithIMul, NodeResultInt32) \
-    macro(ArithDiv, NodeResultNumber) \
-    macro(ArithMod, NodeResultNumber) \
-    macro(ArithAbs, NodeResultNumber) \
+    macro(ArithDiv, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithMod, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithAbs, NodeResultNumber | NodeMustGenerate) \
     macro(ArithMin, NodeResultNumber) \
     macro(ArithMax, NodeResultNumber) \
     macro(ArithFRound, NodeResultNumber) \
index c98a82d..4bc2c0d 100644 (file)
@@ -797,7 +797,6 @@ private:
         case MovHint:
         case Phantom:
         case Check:
-        case MustGenerate:
         case StoreBarrier:
         case StoreBarrierWithNullCheck:
         case PutHint:
index 91184b1..3b3717d 100644 (file)
@@ -38,7 +38,6 @@
 namespace JSC { namespace DFG {
 
 static const NodeFlags NodeNeedsPhantom = NodeMiscFlag1;
-static const NodeFlags NodeNeedsMustGenerate = NodeMiscFlag2;
 
 class PhantomCanonicalizationPhase : public Phase {
 public:
@@ -51,7 +50,7 @@ public:
     {
         ASSERT(m_graph.m_form == SSA);
         
-        m_graph.clearFlagsOnAllNodes(NodeNeedsPhantom | NodeNeedsMustGenerate | NodeRelevantToOSR);
+        m_graph.clearFlagsOnAllNodes(NodeNeedsPhantom | NodeRelevantToOSR);
         m_graph.mergeRelevantToOSR();
         
         for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
@@ -63,13 +62,11 @@ public:
             unsigned targetIndex = 0;
             while (sourceIndex < block->size()) {
                 Node* node = block->at(sourceIndex++);
-                if (node->op() == MustGenerate || node->op() == Phantom || node->op() == Check) {
+                if (node->op() == Phantom || node->op() == Check) {
                     for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
                         Edge edge = node->children.child(i);
                         if (!edge)
                             break;
-                        if (node->op() == MustGenerate)
-                            edge->mergeFlags(NodeNeedsMustGenerate);
                         if ((edge->flags() & NodeRelevantToOSR) && node->op() == Phantom) {
                             // A Phantom on a node that is RelevantToOSR means that we need to keep
                             // a Phantom on this node instead of just having a Check.
@@ -101,10 +98,7 @@ public:
             
             for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
                 Node* node = block->at(nodeIndex);
-                if (node->flags() & NodeNeedsMustGenerate) {
-                    insertionSet.insertNode(
-                        nodeIndex + 1, SpecNone, MustGenerate, node->origin, node->defaultEdge());
-                } else if (node->flags() & NodeNeedsPhantom) {
+                if (node->flags() & NodeNeedsPhantom) {
                     insertionSet.insertNode(
                         nodeIndex + 1, SpecNone, Phantom, node->origin, node->defaultEdge());
                 }
index b843eed..2844c84 100644 (file)
@@ -147,14 +147,6 @@ public:
                     break;
                 }
                     
-                case MustGenerate: {
-                    if (node->children.isEmpty()) {
-                        m_graph.m_allocator.free(node);
-                        continue;
-                    }
-                    break;
-                }
-                    
                 default:
                     break;
                 }
index 0b618dc..d6129fc 100644 (file)
@@ -395,8 +395,10 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
         performCFA(dfg);
         if (Options::validateFTLOSRExitLiveness())
             performResurrectionForValidation(dfg);
-        if (Options::enableMovHintRemoval())
+        if (Options::enableMovHintRemoval()) {
             performMovHintRemoval(dfg);
+            performPhantomCanonicalization(dfg);
+        }
         performDCE(dfg); // We rely on this to kill dead code that won't be recognized as dead by LLVM.
         performStackLayout(dfg);
         performLivenessAnalysis(dfg);
index 533af1b..9df30f1 100644 (file)
@@ -535,7 +535,6 @@ private:
         case InvalidationPoint:
         case CheckInBounds:
         case ValueToInt32:
-        case MustGenerate:
         case DoubleRep:
         case ValueRep:
         case Int52Rep:
index dc08c43..aa5a71c 100644 (file)
@@ -125,7 +125,6 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case MovHint:
     case ZombieHint:
     case Phantom:
-    case MustGenerate:
     case Upsilon:
     case Phi:
     case Flush:
index 7dd2660..d4556c4 100644 (file)
@@ -4621,7 +4621,6 @@ void SpeculativeJIT::compile(Node* node)
         break;
 
     case Phantom:
-    case MustGenerate:
     case Check:
         DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
         noResult(node);
index 3007b4b..e852f72 100644 (file)
@@ -4338,7 +4338,6 @@ void SpeculativeJIT::compile(Node* node)
         break;
 
     case Phantom:
-    case MustGenerate:
     case Check:
         DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
         noResult(node);
index 2f008a4..5cdeb61 100644 (file)
@@ -244,7 +244,6 @@ private:
                 case GetIndexedPropertyStorage:
                 case GetTypedArrayByteOffset:
                 case Phantom:
-                case MustGenerate:
                 case MovHint:
                 case MultiGetByOffset:
                 case MultiPutByOffset:
@@ -337,7 +336,6 @@ private:
                 case GetArrayLength:
                 case GetIndexedPropertyStorage:
                 case Phantom:
-                case MustGenerate:
                 case MovHint:
                 case MultiGetByOffset:
                 case MultiPutByOffset:
index 62e30ed..c9d90d4 100644 (file)
@@ -92,7 +92,6 @@ private:
             switch (node->op()) {
             case Phantom:
             case Check:
-            case MustGenerate:
             case MovHint:
             case PutHint:
             case LoadVarargs:
@@ -214,7 +213,6 @@ private:
             switch (node->op()) {
             case Phantom:
             case Check:
-            case MustGenerate:
             case MovHint:
             case PutHint:
                 // We don't need to change anything with these.
index ee7575d..28f54c8 100644 (file)
@@ -52,7 +52,6 @@ inline CapabilityLevel canCompile(Node* node)
     case MovHint:
     case ZombieHint:
     case Phantom:
-    case MustGenerate:
     case Flush:
     case PhantomLocal:
     case SetArgument:
index 970dcc2..f51f2f6 100644 (file)
@@ -464,7 +464,6 @@ private:
             compilePutStack();
             break;
         case Phantom:
-        case MustGenerate:
         case Check:
             compilePhantom();
             break;
diff --git a/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-mul-branch.js b/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-mul-branch.js
new file mode 100644 (file)
index 0000000..4d1883d
--- /dev/null
@@ -0,0 +1,17 @@
+function foo(a, b) {
+    var value = DFGTrue() ? -0 : "foo";
+    if (a * b == value)
+        return [DFGTrue(), true];
+    return [DFGTrue(), false];
+}
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(1, 1);
+    if (result[1] !== false)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(-1, 0);
+if (result[1] !== true && result[0])
+    throw "Error: bad result at end: " + result;
diff --git a/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-mul.js b/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-mul.js
new file mode 100644 (file)
index 0000000..94fa137
--- /dev/null
@@ -0,0 +1,14 @@
+function foo(a, b) {
+    return a * b === -0;
+}
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(1, 1);
+    if (result !== false)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(-1, 0);
+if (result !== true)
+    throw "Error: bad result at end: " + result;
diff --git a/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-or-zero.js b/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof-or-zero.js
new file mode 100644 (file)
index 0000000..b28ed69
--- /dev/null
@@ -0,0 +1,15 @@
+function foo(a, b) {
+    var c = a + b;
+    return (c | 0) == c;
+}
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(1, 1);
+    if (result !== true)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(1073741824, 1073741824);
+if (result !== false)
+    throw "Error: bad result at end: " + result;
diff --git a/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof.js b/Source/JavaScriptCore/tests/stress/fold-based-on-int32-proof.js
new file mode 100644 (file)
index 0000000..f9a2ee5
--- /dev/null
@@ -0,0 +1,14 @@
+function foo(a, b) {
+    return a + b === 2147483648;
+}
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(1, 1);
+    if (result !== false)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(1073741824, 1073741824);
+if (result !== true)
+    throw "Error: bad result at end: " + result;