Arithmetic use inference should be procedure-global and should run in tandem
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Mar 2012 01:05:54 +0000 (01:05 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Mar 2012 01:05:54 +0000 (01:05 +0000)
with type propagation
https://bugs.webkit.org/show_bug.cgi?id=80819
<rdar://problem/11034006>

Reviewed by Gavin Barraclough.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* dfg/DFGArithNodeFlagsInferencePhase.cpp: Removed.
* dfg/DFGArithNodeFlagsInferencePhase.h: Removed.
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::isNotNegZero):
(PredictionPropagationPhase):
(JSC::DFG::PredictionPropagationPhase::isNotZero):
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::mergeDefaultArithFlags):
* dfg/DFGVariableAccessData.h:
(JSC::DFG::VariableAccessData::VariableAccessData):
(JSC::DFG::VariableAccessData::flags):
(VariableAccessData):
(JSC::DFG::VariableAccessData::mergeFlags):

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

Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp [deleted file]
Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.h [deleted file]
Source/JavaScriptCore/dfg/DFGDriver.cpp
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGVariableAccessData.h

index 08e4c71..d208688 100644 (file)
@@ -58,7 +58,6 @@ SET(JavaScriptCore_SOURCES
     bytecompiler/NodesCodegen.cpp
 
     dfg/DFGAbstractState.cpp
-    dfg/DFGArithNodeFlagsInferencePhase.cpp
     dfg/DFGAssemblyHelpers.cpp
     dfg/DFGByteCodeParser.cpp
     dfg/DFGCapabilities.cpp
index e312a03..cf25bc3 100644 (file)
@@ -1,5 +1,34 @@
 2012-03-12  Filip Pizlo  <fpizlo@apple.com>
 
+        Arithmetic use inference should be procedure-global and should run in tandem
+        with type propagation
+        https://bugs.webkit.org/show_bug.cgi?id=80819
+        <rdar://problem/11034006>
+
+        Reviewed by Gavin Barraclough.
+        
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * dfg/DFGArithNodeFlagsInferencePhase.cpp: Removed.
+        * dfg/DFGArithNodeFlagsInferencePhase.h: Removed.
+        * dfg/DFGDriver.cpp:
+        (JSC::DFG::compile):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::isNotNegZero):
+        (PredictionPropagationPhase):
+        (JSC::DFG::PredictionPropagationPhase::isNotZero):
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (JSC::DFG::PredictionPropagationPhase::mergeDefaultArithFlags):
+        * dfg/DFGVariableAccessData.h:
+        (JSC::DFG::VariableAccessData::VariableAccessData):
+        (JSC::DFG::VariableAccessData::flags):
+        (VariableAccessData):
+        (JSC::DFG::VariableAccessData::mergeFlags):
+
+2012-03-12  Filip Pizlo  <fpizlo@apple.com>
+
         Node::op and Node::flags should be private
         https://bugs.webkit.org/show_bug.cgi?id=80824
         <rdar://problem/11033435>
index 702066a..3693e22 100644 (file)
@@ -142,8 +142,6 @@ javascriptcore_sources += \
        Source/JavaScriptCore/dfg/DFGAbstractState.cpp \
        Source/JavaScriptCore/dfg/DFGAbstractState.h \
        Source/JavaScriptCore/dfg/DFGAbstractValue.h \
-       Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp \
-       Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.h \
        Source/JavaScriptCore/dfg/DFGAssemblyHelpers.cpp \
        Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h \
        Source/JavaScriptCore/dfg/DFGBasicBlock.h \
index 8943b01..ef76c0f 100644 (file)
                0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; };
                0FF922D414F46B410041A24E /* LLIntOffsetsExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */; };
-               0FFFC95514EF909A00C72532 /* DFGArithNodeFlagsInferencePhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94914EF909500C72532 /* DFGArithNodeFlagsInferencePhase.cpp */; };
-               0FFFC95614EF909C00C72532 /* DFGArithNodeFlagsInferencePhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94A14EF909500C72532 /* DFGArithNodeFlagsInferencePhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */; };
                0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94D14EF909500C72532 /* DFGCSEPhase.cpp */; };
                0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
                0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; };
                0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; };
-               0FFFC94914EF909500C72532 /* DFGArithNodeFlagsInferencePhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArithNodeFlagsInferencePhase.cpp; path = dfg/DFGArithNodeFlagsInferencePhase.cpp; sourceTree = "<group>"; };
-               0FFFC94A14EF909500C72532 /* DFGArithNodeFlagsInferencePhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArithNodeFlagsInferencePhase.h; path = dfg/DFGArithNodeFlagsInferencePhase.h; sourceTree = "<group>"; };
                0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFAPhase.cpp; path = dfg/DFGCFAPhase.cpp; sourceTree = "<group>"; };
                0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFAPhase.h; path = dfg/DFGCFAPhase.h; sourceTree = "<group>"; };
                0FFFC94D14EF909500C72532 /* DFGCSEPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCSEPhase.cpp; path = dfg/DFGCSEPhase.cpp; sourceTree = "<group>"; };
                86EC9DB31328DF44002B2AD7 /* dfg */ = {
                        isa = PBXGroup;
                        children = (
-                               0FFFC94914EF909500C72532 /* DFGArithNodeFlagsInferencePhase.cpp */,
-                               0FFFC94A14EF909500C72532 /* DFGArithNodeFlagsInferencePhase.h */,
                                0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */,
                                0F62016E143FCD2F0068B77C /* DFGAbstractState.h */,
                                0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */,
                                0F9FC8C414E1B60000D52AE0 /* PolymorphicPutByIdList.h in Headers */,
                                0F9FC8C514E1B60400D52AE0 /* PutKind.h in Headers */,
                                BCBE2CAE14E985AA000593AD /* GCAssertions.h in Headers */,
-                               0FFFC95614EF909C00C72532 /* DFGArithNodeFlagsInferencePhase.h in Headers */,
                                0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */,
                                0FFFC95A14EF90A900C72532 /* DFGCSEPhase.h in Headers */,
                                0FFFC95C14EF90AF00C72532 /* DFGPhase.h in Headers */,
                                C2B916C514DA040C00CBAC86 /* MarkedAllocator.cpp in Sources */,
                                0F9FC8D014E612D800D52AE0 /* DataLog.cpp in Sources */,
                                0F9FC8C314E1B5FE00D52AE0 /* PolymorphicPutByIdList.cpp in Sources */,
-                               0FFFC95514EF909A00C72532 /* DFGArithNodeFlagsInferencePhase.cpp in Sources */,
                                0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */,
                                0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */,
                                0FFFC95B14EF90AD00C72532 /* DFGPhase.cpp in Sources */,
index 942906f..b1caeb7 100644 (file)
@@ -86,7 +86,6 @@ SOURCES += \
     debugger/Debugger.cpp \
     dfg/DFGAbstractState.cpp \
     dfg/DFGAssemblyHelpers.cpp \
-    dfg/DFGArithNodeFlagsInferencePhase.cpp \
     dfg/DFGByteCodeParser.cpp \
     dfg/DFGCapabilities.cpp \
     dfg/DFGCFAPhase.cpp \
diff --git a/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp b/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
deleted file mode 100644 (file)
index 02d9191..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#include "config.h"
-#include "DFGArithNodeFlagsInferencePhase.h"
-
-#if ENABLE(DFG_JIT)
-
-#include "DFGGraph.h"
-#include "DFGPhase.h"
-
-namespace JSC { namespace DFG {
-
-class ArithNodeFlagsInferencePhase : public Phase {
-public:
-    ArithNodeFlagsInferencePhase(Graph& graph)
-        : Phase(graph, "arithmetic node flags inference")
-    {
-    }
-    
-    void run()
-    {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        m_count = 0;
-#endif
-        do {
-            m_changed = false;
-            
-            // Up here we start with a backward pass because we suspect that to be
-            // more profitable.
-            propagateBackward();
-            if (!m_changed)
-                break;
-            
-            m_changed = false;
-            propagateForward();
-        } while (m_changed);
-    }
-    
-private:
-    bool isNotNegZero(NodeIndex nodeIndex)
-    {
-        if (!m_graph.isNumberConstant(nodeIndex))
-            return false;
-        double value = m_graph.valueOfNumberConstant(nodeIndex);
-        return !value && 1.0 / value < 0.0;
-    }
-    
-    bool isNotZero(NodeIndex nodeIndex)
-    {
-        if (!m_graph.isNumberConstant(nodeIndex))
-            return false;
-        return !!m_graph.valueOfNumberConstant(nodeIndex);
-    }
-    
-    void propagate(Node& node)
-    {
-        if (!node.shouldGenerate())
-            return;
-        
-        NodeType op = node.op();
-        NodeFlags flags = node.flags();
-        
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("   %s @%u: %s ", Graph::opName(op), m_compileIndex, arithNodeFlagsAsString(flags));
-#endif
-        
-        flags &= NodeUsedAsMask;
-        
-        bool changed = false;
-        
-        switch (op) {
-        case ValueToInt32:
-        case BitAnd:
-        case BitOr:
-        case BitXor:
-        case BitLShift:
-        case BitRShift:
-        case BitURShift: {
-            // These operations are perfectly happy with truncated integers,
-            // so we don't want to propagate anything.
-            break;
-        }
-            
-        case UInt32ToNumber: {
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-            break;
-        }
-            
-        case ArithAdd:
-        case ValueAdd: {
-            if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
-                flags &= ~NodeNeedsNegZero;
-            
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
-            break;
-        }
-            
-        case ArithSub: {
-            if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
-                flags &= ~NodeNeedsNegZero;
-            
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
-            break;
-        }
-            
-        case ArithNegate: {
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-            break;
-        }
-            
-        case ArithMul:
-        case ArithDiv: {
-            // As soon as a multiply happens, we can easily end up in the part
-            // of the double domain where the point at which you do truncation
-            // can change the outcome. So, ArithMul always checks for overflow
-            // no matter what, and always forces its inputs to check as well.
-            
-            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
-            break;
-        }
-            
-        case ArithMin:
-        case ArithMax: {
-            flags |= NodeUsedAsNumber;
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
-            break;
-        }
-            
-        case ArithAbs: {
-            flags &= ~NodeNeedsNegZero;
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-            break;
-        }
-            
-        case PutByVal: {
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
-            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
-            changed |= m_graph[node.child3()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
-            break;
-        }
-            
-        case GetByVal: {
-            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
-            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
-            break;
-        }
-            
-        default:
-            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
-            if (node.flags() & NodeHasVarArgs) {
-                for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
-                    changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeArithNodeFlags(flags);
-            } else {
-                if (!node.child1())
-                    break;
-                changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
-                if (!node.child2())
-                    break;
-                changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
-                if (!node.child3())
-                    break;
-                changed |= m_graph[node.child3()].mergeArithNodeFlags(flags);
-            }
-            break;
-        }
-
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("%s\n", changed ? "CHANGED" : "");
-#endif
-        
-        m_changed |= changed;
-    }
-    
-    void propagateForward()
-    {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("Propagating arithmetic node flags forward [%u]\n", ++m_count);
-#endif
-        for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
-            propagate(m_graph[m_compileIndex]);
-    }
-    
-    void propagateBackward()
-    {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("Propagating arithmetic node flags backward [%u]\n", ++m_count);
-#endif
-        for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
-            propagate(m_graph[m_compileIndex]);
-    }
-    
-    NodeIndex m_compileIndex;
-    bool m_changed;
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-    unsigned m_count;
-#endif
-};
-
-void performArithNodeFlagsInference(Graph& graph)
-{
-    runPhase<ArithNodeFlagsInferencePhase>(graph);
-}
-
-} } // namespace JSC::DFG
-
-#endif // ENABLE(DFG_JIT)
-
diff --git a/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.h b/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.h
deleted file mode 100644 (file)
index 64546e2..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#ifndef DFGArithNodeFlagsInferencePhase_h
-#define DFGArithNodeFlagsInferencePhase_h
-
-#include <wtf/Platform.h>
-
-#if ENABLE(DFG_JIT)
-
-namespace JSC { namespace DFG {
-
-class Graph;
-
-// Determine which arithmetic nodes' results are only used in a context that
-// truncates to integer anyway. This is great for optimizing away checks for
-// overflow and negative zero. NB the way this phase integrates into the rest
-// of the DFG makes it non-optional. Instead of proving that a node is only
-// used in integer context, it actually does the opposite: finds nodes that
-// are used in non-integer contexts. Hence failing to run this phase will make
-// the compiler assume that all nodes are just used as integers!
-
-void performArithNodeFlagsInference(Graph&);
-
-} } // namespace JSC::DFG::Phase
-
-#endif // ENABLE(DFG_JIT)
-
-#endif // DFGArithNodeFlagsInferencePhase_h
index a0af3e6..1e1bf5c 100644 (file)
@@ -28,7 +28,6 @@
 
 #if ENABLE(DFG_JIT)
 
-#include "DFGArithNodeFlagsInferencePhase.h"
 #include "DFGByteCodeParser.h"
 #include "DFGCFAPhase.h"
 #include "DFGCSEPhase.h"
@@ -60,7 +59,6 @@ inline bool compile(CompileMode compileMode, JSGlobalData& globalData, CodeBlock
         dfg.predictArgumentTypes();
 
     performRedundantPhiElimination(dfg);
-    performArithNodeFlagsInference(dfg);
     performPredictionPropagation(dfg);
     performCSE(dfg);
     performVirtualRegisterAllocation(dfg);
index 7a814fd..1de81d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -100,17 +100,35 @@ private:
         return m_graph[m_compileIndex].predict(prediction);
     }
     
+    bool isNotNegZero(NodeIndex nodeIndex)
+    {
+        if (!m_graph.isNumberConstant(nodeIndex))
+            return false;
+        double value = m_graph.valueOfNumberConstant(nodeIndex);
+        return !value && 1.0 / value < 0.0;
+    }
+    
+    bool isNotZero(NodeIndex nodeIndex)
+    {
+        if (!m_graph.isNumberConstant(nodeIndex))
+            return false;
+        return !!m_graph.valueOfNumberConstant(nodeIndex);
+    }
+    
     void propagate(Node& node)
     {
         if (!node.shouldGenerate())
             return;
         
         NodeType op = node.op();
+        NodeFlags flags = node.flags();
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("   %s @%u: ", Graph::opName(op), m_compileIndex);
+        dataLog("   %s @%u: %s ", Graph::opName(op), m_compileIndex, arithNodeFlagsAsString(flags));
 #endif
         
+        flags &= NodeUsedAsMask;
+        
         bool changed = false;
         
         switch (op) {
@@ -121,14 +139,26 @@ private:
         }
             
         case GetLocal: {
-            PredictedType prediction = node.variableAccessData()->prediction();
+            VariableAccessData* variableAccessData = node.variableAccessData();
+            PredictedType prediction = variableAccessData->prediction();
             if (prediction)
                 changed |= mergePrediction(prediction);
+            
+            changed |= variableAccessData->mergeFlags(flags);
             break;
         }
             
         case SetLocal: {
-            changed |= node.variableAccessData()->predict(m_graph[node.child1()].prediction());
+            VariableAccessData* variableAccessData = node.variableAccessData();
+            changed |= variableAccessData->predict(m_graph[node.child1()].prediction());
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(variableAccessData->flags());
+            break;
+        }
+            
+        case Flush: {
+            // Make sure that the analysis knows that flushed locals escape.
+            VariableAccessData* variableAccessData = node.variableAccessData();
+            variableAccessData->mergeFlags(NodeUsedAsNumber | NodeNeedsNegZero);
             break;
         }
             
@@ -143,15 +173,22 @@ private:
             break;
         }
             
-        case ArrayPop:
+        case ArrayPop: {
+            if (node.getHeapPrediction())
+                changed |= mergePrediction(node.getHeapPrediction());
+            break;
+        }
+
         case ArrayPush: {
             if (node.getHeapPrediction())
                 changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
 
         case StringCharCodeAt: {
             changed |= mergePrediction(PredictInt32);
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
 
@@ -165,6 +202,8 @@ private:
                 else
                     changed |= mergePrediction(PredictDouble);
             }
+            
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -173,6 +212,8 @@ private:
                 changed |= setPrediction(PredictInt32);
             else
                 changed |= setPrediction(PredictNumber);
+            
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
             break;
         }
 
@@ -192,10 +233,34 @@ private:
                 } else
                     changed |= mergePrediction(PredictString | PredictInt32 | PredictDouble);
             }
+            
+            if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
+                flags &= ~NodeNeedsNegZero;
+            
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+            break;
+        }
+            
+        case ArithAdd: {
+            PredictedType left = m_graph[node.child1()].prediction();
+            PredictedType right = m_graph[node.child2()].prediction();
+            
+            if (left && right) {
+                if (m_graph.addShouldSpeculateInteger(node))
+                    changed |= mergePrediction(PredictInt32);
+                else
+                    changed |= mergePrediction(PredictDouble);
+            }
+            
+            if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
+                flags &= ~NodeNeedsNegZero;
+            
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
             break;
         }
             
-        case ArithAdd:
         case ArithSub: {
             PredictedType left = m_graph[node.child1()].prediction();
             PredictedType right = m_graph[node.child2()].prediction();
@@ -206,6 +271,12 @@ private:
                 else
                     changed |= mergePrediction(PredictDouble);
             }
+
+            if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
+                flags &= ~NodeNeedsNegZero;
+            
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
             break;
         }
             
@@ -216,11 +287,29 @@ private:
                 else
                     changed |= mergePrediction(PredictDouble);
             }
+
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
             break;
             
-        case ArithMul:
         case ArithMin:
-        case ArithMax:
+        case ArithMax: {
+            PredictedType left = m_graph[node.child1()].prediction();
+            PredictedType right = m_graph[node.child2()].prediction();
+            
+            if (left && right) {
+                if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags()))
+                    changed |= mergePrediction(PredictInt32);
+                else
+                    changed |= mergePrediction(PredictDouble);
+            }
+
+            flags |= NodeUsedAsNumber;
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+            break;
+        }
+            
+        case ArithMul:
         case ArithDiv: {
             PredictedType left = m_graph[node.child1()].prediction();
             PredictedType right = m_graph[node.child2()].prediction();
@@ -231,11 +320,21 @@ private:
                 else
                     changed |= mergePrediction(PredictDouble);
             }
+
+            // As soon as a multiply happens, we can easily end up in the part
+            // of the double domain where the point at which you do truncation
+            // can change the outcome. So, ArithMul always checks for overflow
+            // no matter what, and always forces its inputs to check as well.
+            
+            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
             break;
         }
             
         case ArithSqrt: {
             changed |= setPrediction(PredictDouble);
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -247,6 +346,9 @@ private:
                 else
                     changed |= setPrediction(PredictDouble);
             }
+
+            flags &= ~NodeNeedsNegZero;
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
             break;
         }
             
@@ -259,6 +361,7 @@ private:
         case CompareStrictEq:
         case InstanceOf: {
             changed |= setPrediction(PredictBoolean);
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -283,12 +386,14 @@ private:
                 if (isArray || isString || isByteArray || isInt8Array || isInt16Array || isInt32Array || isUint8Array || isUint8ClampedArray || isUint16Array || isUint32Array || isFloat32Array || isFloat64Array)
                     changed |= mergePrediction(PredictInt32);
             }
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
         case GetByIdFlush:
             if (node.getHeapPrediction())
                 changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
             
         case GetByVal: {
@@ -296,18 +401,23 @@ private:
                 changed |= mergePrediction(PredictDouble);
             else if (node.getHeapPrediction())
                 changed |= mergePrediction(node.getHeapPrediction());
+
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
             break;
         }
             
         case GetPropertyStorage: 
         case GetIndexedPropertyStorage: {
             changed |= setPrediction(PredictOther);
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
 
         case GetByOffset: {
             if (node.getHeapPrediction())
                 changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -315,6 +425,7 @@ private:
         case Construct: {
             if (node.getHeapPrediction())
                 changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -327,6 +438,7 @@ private:
                 }
                 changed |= mergePrediction(prediction);
             }
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -339,6 +451,7 @@ private:
             
         case PutGlobalVar: {
             changed |= m_graph.predictGlobalVar(node.varNumber(), m_graph[node.child1()].prediction());
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -366,12 +479,14 @@ private:
         case CreateThis:
         case NewObject: {
             changed |= setPrediction(PredictFinalObject);
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
         case NewArray:
         case NewArrayBuffer: {
             changed |= setPrediction(PredictArray);
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -383,6 +498,7 @@ private:
         case StringCharAt:
         case StrCat: {
             changed |= setPrediction(PredictString);
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -403,6 +519,7 @@ private:
                 } else
                     changed |= mergePrediction(child);
             }
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
             break;
         }
             
@@ -436,7 +553,10 @@ private:
             break;
         }
         
-        case Flush:
+        case PutByVal:
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags | NodeUsedAsNumber);
+            changed |= m_graph[node.child3()].mergeArithNodeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
             break;
 
 #ifndef NDEBUG
@@ -452,7 +572,6 @@ private:
         case ThrowReferenceError:
         case ForceOSRExit:
         case SetArgument:
-        case PutByVal:
         case PutByValAlias:
         case PutById:
         case PutByIdDirect:
@@ -461,6 +580,7 @@ private:
         case PutStructure:
         case PutByOffset:
         case TearOffActivation:
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
             
         // These gets ignored because it doesn't do anything.
@@ -474,6 +594,7 @@ private:
             break;
 #else
         default:
+            changed |= mergeDefaultArithFlags(node, flags);
             break;
 #endif
         }
@@ -485,6 +606,27 @@ private:
         m_changed |= changed;
     }
     
+    bool mergeDefaultArithFlags(Node& node, NodeFlags flags)
+    {
+        bool changed = false;
+        flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+        if (node.flags() & NodeHasVarArgs) {
+            for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
+                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeArithNodeFlags(flags);
+        } else {
+            if (!node.child1())
+                return changed;
+            changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+            if (!node.child2())
+                return changed;
+            changed |= m_graph[node.child2()].mergeArithNodeFlags(flags);
+            if (!node.child3())
+                return changed;
+            changed |= m_graph[node.child3()].mergeArithNodeFlags(flags);
+        }
+        return changed;
+    }
+    
     void propagateForward()
     {
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
index bd626f9..98f79b9 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef DFGVariableAccessData_h
 #define DFGVariableAccessData_h
 
+#include "DFGNodeFlags.h"
 #include "DFGOperands.h"
 #include "PredictedType.h"
 #include "VirtualRegister.h"
@@ -41,6 +42,7 @@ public:
     VariableAccessData()
         : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min()))
         , m_prediction(PredictNone)
+        , m_flags(0)
         , m_shouldUseDoubleFormat(false)
     {
         clearVotes();
@@ -49,6 +51,7 @@ public:
     VariableAccessData(VirtualRegister local)
         : m_local(local)
         , m_prediction(PredictNone)
+        , m_flags(0)
         , m_shouldUseDoubleFormat(false)
     {
         clearVotes();
@@ -130,6 +133,17 @@ public:
         return true;
     }
     
+    NodeFlags flags() const { return m_flags; }
+    
+    bool mergeFlags(NodeFlags newFlags)
+    {
+        newFlags |= m_flags;
+        if (newFlags == m_flags)
+            return false;
+        m_flags = newFlags;
+        return true;
+    }
+    
 private:
     // This is slightly space-inefficient, since anything we're unified with
     // will have the same operand and should have the same prediction. But
@@ -138,6 +152,7 @@ private:
 
     VirtualRegister m_local;
     PredictedType m_prediction;
+    NodeFlags m_flags;
     
     float m_votes[2];
     bool m_shouldUseDoubleFormat;