⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 112040 in webkit


Ignore:
Timestamp:
Mar 25, 2012, 4:50:24 PM (15 years ago)
Author:
fpizlo@apple.com
Message:

DFG int-to-double conversion should be revealed to CSE
​https://bugs.webkit.org/show_bug.cgi?id=82135

Reviewed by Oliver Hunt.

This introduces the notion of an Int32ToDouble node, which is injected
into the graph anytime we know that we have a double use of a node that
was predicted integer. The Int32ToDouble simplifies double speculation
on integers by skipping the path that would unbox doubles, if we know
that the value is already proven to be an integer. It allows integer to
double conversions to be subjected to common subexpression elimination
(CSE) by allowing the CSE phase to see where these conversions are
occurring. Finally, it allows us to see when a constant is being used
as both a double and an integer. This is a bit odd, since it means that
sometimes a double use of a constant will not refer directly to the
constant. This should not cause problems, for now, but it may require
some canonizalization in the future if we want to support strength
reductions of double operations based on constants.

To allow injection of nodes into the graph, this change introduces the
DFG::InsertionSet, which is a way of lazily inserting elements into a
list. This allows the FixupPhase to remain O(N) despite performing
multiple injections in a single basic block. Without the InsertionSet,
each injection would require performing an insertion into a vector,
which is O(N), leading to O(N2) performance overall. With the
InsertionSet, each injection simply records what insertion would have
been performed, and all insertions are performed at once (via
InsertionSet::execute) after processing of a basic block is completed.

(JSC::isActionableIntMutableArrayPrediction):
(JSC):
(JSC::isActionableFloatMutableArrayPrediction):
(JSC::isActionableTypedMutableArrayPrediction):
(JSC::isActionableMutableArrayPrediction):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::performNodeCSE):

  • dfg/DFGCommon.h:

(JSC::DFG::useKindToString):
(DFG):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::run):
(JSC::DFG::FixupPhase::fixupBlock):
(FixupPhase):
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixDoubleEdge):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGInsertionSet.h: Added.

(DFG):
(Insertion):
(JSC::DFG::Insertion::Insertion):
(JSC::DFG::Insertion::index):
(JSC::DFG::Insertion::element):
(InsertionSet):
(JSC::DFG::InsertionSet::InsertionSet):
(JSC::DFG::InsertionSet::append):
(JSC::DFG::InsertionSet::execute):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::computeValueRecoveryFor):
(JSC::DFG::SpeculativeJIT::compileValueToInt32):
(JSC::DFG::SpeculativeJIT::compileInt32ToDouble):
(DFG):

  • dfg/DFGSpeculativeJIT.h:

(SpeculativeJIT):
(JSC::DFG::IntegerOperand::IntegerOperand):
(JSC::DFG::DoubleOperand::DoubleOperand):
(JSC::DFG::JSValueOperand::JSValueOperand):
(JSC::DFG::StorageOperand::StorageOperand):
(JSC::DFG::SpeculateIntegerOperand::SpeculateIntegerOperand):
(JSC::DFG::SpeculateStrictInt32Operand::SpeculateStrictInt32Operand):
(JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
(JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

Location:
trunk/Source/JavaScriptCore
Files:
1 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r112039 r112040  
     12012-03-25  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG int-to-double conversion should be revealed to CSE
     4        https://bugs.webkit.org/show_bug.cgi?id=82135
     5
     6        Reviewed by Oliver Hunt.
     7       
     8        This introduces the notion of an Int32ToDouble node, which is injected
     9        into the graph anytime we know that we have a double use of a node that
     10        was predicted integer. The Int32ToDouble simplifies double speculation
     11        on integers by skipping the path that would unbox doubles, if we know
     12        that the value is already proven to be an integer. It allows integer to
     13        double conversions to be subjected to common subexpression elimination
     14        (CSE) by allowing the CSE phase to see where these conversions are
     15        occurring. Finally, it allows us to see when a constant is being used
     16        as both a double and an integer. This is a bit odd, since it means that
     17        sometimes a double use of a constant will not refer directly to the
     18        constant. This should not cause problems, for now, but it may require
     19        some canonizalization in the future if we want to support strength
     20        reductions of double operations based on constants.
     21       
     22        To allow injection of nodes into the graph, this change introduces the
     23        DFG::InsertionSet, which is a way of lazily inserting elements into a
     24        list. This allows the FixupPhase to remain O(N) despite performing
     25        multiple injections in a single basic block. Without the InsertionSet,
     26        each injection would require performing an insertion into a vector,
     27        which is O(N), leading to O(N^2) performance overall. With the
     28        InsertionSet, each injection simply records what insertion would have
     29        been performed, and all insertions are performed at once (via
     30        InsertionSet::execute) after processing of a basic block is completed.
     31
     32        * JavaScriptCore.xcodeproj/project.pbxproj:
     33        * bytecode/PredictedType.h:
     34        (JSC::isActionableIntMutableArrayPrediction):
     35        (JSC):
     36        (JSC::isActionableFloatMutableArrayPrediction):
     37        (JSC::isActionableTypedMutableArrayPrediction):
     38        (JSC::isActionableMutableArrayPrediction):
     39        * dfg/DFGAbstractState.cpp:
     40        (JSC::DFG::AbstractState::execute):
     41        * dfg/DFGCSEPhase.cpp:
     42        (JSC::DFG::CSEPhase::performNodeCSE):
     43        * dfg/DFGCommon.h:
     44        (JSC::DFG::useKindToString):
     45        (DFG):
     46        * dfg/DFGFixupPhase.cpp:
     47        (JSC::DFG::FixupPhase::run):
     48        (JSC::DFG::FixupPhase::fixupBlock):
     49        (FixupPhase):
     50        (JSC::DFG::FixupPhase::fixupNode):
     51        (JSC::DFG::FixupPhase::fixDoubleEdge):
     52        * dfg/DFGGraph.cpp:
     53        (JSC::DFG::Graph::dump):
     54        * dfg/DFGInsertionSet.h: Added.
     55        (DFG):
     56        (Insertion):
     57        (JSC::DFG::Insertion::Insertion):
     58        (JSC::DFG::Insertion::index):
     59        (JSC::DFG::Insertion::element):
     60        (InsertionSet):
     61        (JSC::DFG::InsertionSet::InsertionSet):
     62        (JSC::DFG::InsertionSet::append):
     63        (JSC::DFG::InsertionSet::execute):
     64        * dfg/DFGNodeType.h:
     65        (DFG):
     66        * dfg/DFGPredictionPropagationPhase.cpp:
     67        (JSC::DFG::PredictionPropagationPhase::propagate):
     68        * dfg/DFGSpeculativeJIT.cpp:
     69        (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor):
     70        (JSC::DFG::SpeculativeJIT::compileValueToInt32):
     71        (JSC::DFG::SpeculativeJIT::compileInt32ToDouble):
     72        (DFG):
     73        * dfg/DFGSpeculativeJIT.h:
     74        (SpeculativeJIT):
     75        (JSC::DFG::IntegerOperand::IntegerOperand):
     76        (JSC::DFG::DoubleOperand::DoubleOperand):
     77        (JSC::DFG::JSValueOperand::JSValueOperand):
     78        (JSC::DFG::StorageOperand::StorageOperand):
     79        (JSC::DFG::SpeculateIntegerOperand::SpeculateIntegerOperand):
     80        (JSC::DFG::SpeculateStrictInt32Operand::SpeculateStrictInt32Operand):
     81        (JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand):
     82        (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
     83        (JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand):
     84        * dfg/DFGSpeculativeJIT32_64.cpp:
     85        (JSC::DFG::SpeculativeJIT::compile):
     86        * dfg/DFGSpeculativeJIT64.cpp:
     87        (JSC::DFG::SpeculativeJIT::compile):
     88
    1892012-03-25  Filip Pizlo  <fpizlo@apple.com>
    290
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r112039 r112040  
    7575                0F2BDC15151C5D4D00CD8910 /* DFGFixupPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC12151C5D4A00CD8910 /* DFGFixupPhase.cpp */; };
    7676                0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
     77                0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
    7778                0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC2B151FDE8B00CD8910 /* Operands.h */; settings = {ATTRIBUTES = (Private, ); }; };
    7879                0F2C556F14738F3100121E4F /* DFGCodeBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */; settings = {ATTRIBUTES = (Private, ); }; };
    … …  
    725726                0F2BDC12151C5D4A00CD8910 /* DFGFixupPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGFixupPhase.cpp; path = dfg/DFGFixupPhase.cpp; sourceTree = "<group>"; };
    726727                0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFixupPhase.h; path = dfg/DFGFixupPhase.h; sourceTree = "<group>"; };
     728                0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInsertionSet.h; path = dfg/DFGInsertionSet.h; sourceTree = "<group>"; };
    727729                0F2BDC2B151FDE8B00CD8910 /* Operands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Operands.h; sourceTree = "<group>"; };
    728730                0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGCodeBlocks.cpp; sourceTree = "<group>"; };
    … …  
    19951997                                86EC9DB71328DF82002B2AD7 /* DFGGraph.cpp */,
    19961998                                86EC9DB81328DF82002B2AD7 /* DFGGraph.h */,
     1999                                0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */,
    19972000                                86EC9DBB1328DF82002B2AD7 /* DFGJITCompiler.cpp */,
    19982001                                86EC9DBC1328DF82002B2AD7 /* DFGJITCompiler.h */,
    … …  
    25012504                                0FA581BC150E953000B9A2D9 /* DFGNodeType.h in Headers */,
    25022505                                0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */,
     2506                                0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */,
    25032507                                0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */,
    25042508                        );
  • trunk/Source/JavaScriptCore/bytecode/PredictedType.h

    r110631 r112040  
    160160}
    161161
    162 inline bool isActionableMutableArrayPrediction(PredictedType value)
    163 {
    164     return isArrayPrediction(value)
    165         || isByteArrayPrediction(value)
     162inline bool isActionableIntMutableArrayPrediction(PredictedType value)
     163{
     164    return isByteArrayPrediction(value)
    166165#if CPU(X86) || CPU(X86_64)
    167166        || isInt8ArrayPrediction(value)
    … …  
    172171        || isUint8ClampedArrayPrediction(value)
    173172        || isUint16ArrayPrediction(value)
    174         || isUint32ArrayPrediction(value)
     173        || isUint32ArrayPrediction(value);
     174}
     175
     176inline bool isActionableFloatMutableArrayPrediction(PredictedType value)
     177{
     178    return false
    175179#if CPU(X86) || CPU(X86_64)
    176180        || isFloat32ArrayPrediction(value)
    177181#endif
    178182        || isFloat64ArrayPrediction(value);
     183}
     184
     185inline bool isActionableTypedMutableArrayPrediction(PredictedType value)
     186{
     187    return isActionableIntMutableArrayPrediction(value)
     188        || isActionableFloatMutableArrayPrediction(value);
     189}
     190
     191inline bool isActionableMutableArrayPrediction(PredictedType value)
     192{
     193    return isArrayPrediction(value)
     194        || isActionableTypedMutableArrayPrediction(value);
    179195}
    180196
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp

    r112013 r112040  
    301301        forNode(nodeIndex).set(PredictInt32);
    302302        break;
     303       
     304    case Int32ToDouble:
     305        forNode(node.child1()).filter(PredictNumber);
     306        forNode(nodeIndex).set(PredictDouble);
     307        break;
    303308           
    304309    case ValueAdd:
  • trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp

    r111254 r112040  
    588588        case StringCharAt:
    589589        case StringCharCodeAt:
     590        case Int32ToDouble:
    590591            setReplacement(pureCSE(node));
    591592            break;
  • trunk/Source/JavaScriptCore/dfg/DFGCommon.h

    r111974 r112040  
    9898enum UseKind {
    9999    UntypedUse,
     100    DoubleUse,
    100101    LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements.
    101102};
     103
     104inline const char* useKindToString(UseKind useKind)
     105{
     106    switch (useKind) {
     107    case UntypedUse:
     108        return "";
     109    case DoubleUse:
     110        return "d";
     111    default:
     112        ASSERT_NOT_REACHED();
     113        return 0;
     114    }
     115}
    102116
    103117} } // namespace JSC::DFG
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r111974 r112040  
    3030
    3131#include "DFGGraph.h"
     32#include "DFGInsertionSet.h"
    3233#include "DFGPhase.h"
    3334
    … …  
    4344    void run()
    4445    {
    45         for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
     46        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
     47            fixupBlock(m_graph.m_blocks[blockIndex].get());
     48    }
     49
     50private:
     51    void fixupBlock(BasicBlock* block)
     52    {
     53        for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
     54            m_compileIndex = block->at(m_indexInBlock);
    4655            fixupNode(m_graph[m_compileIndex]);
    47     }
    48 
    49 private:
     56        }
     57        m_insertionSet.execute(*block);
     58    }
     59   
    5060    void fixupNode(Node& node)
    5161    {
    … …  
    153163        }
    154164           
     165        case CompareEq:
     166        case CompareLess:
     167        case CompareLessEq:
     168        case CompareGreater:
     169        case CompareGreaterEq:
     170        case CompareStrictEq: {
     171            if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]))
     172                break;
     173            if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()]))
     174                break;
     175            fixDoubleEdge(0);
     176            fixDoubleEdge(1);
     177            break;
     178        }
     179           
     180        case LogicalNot: {
     181            if (m_graph[node.child1()].shouldSpeculateInteger())
     182                break;
     183            if (!m_graph[node.child1()].shouldSpeculateNumber())
     184                break;
     185            fixDoubleEdge(0);
     186            break;
     187        }
     188           
     189        case Branch: {
     190            if (m_graph[node.child1()].shouldSpeculateInteger())
     191                break;
     192            if (!m_graph[node.child1()].shouldSpeculateNumber())
     193                break;
     194            fixDoubleEdge(0);
     195            break;
     196        }
     197           
     198        case SetLocal: {
     199            if (m_graph.isCaptured(node.local()))
     200                break;
     201            if (!node.variableAccessData()->shouldUseDoubleFormat())
     202                break;
     203            fixDoubleEdge(0);
     204            break;
     205        }
     206           
     207        case ArithAdd:
     208        case ValueAdd: {
     209            if (m_graph.addShouldSpeculateInteger(node))
     210                break;
     211            if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()]))
     212                break;
     213            fixDoubleEdge(0);
     214            fixDoubleEdge(1);
     215            break;
     216        }
     217           
     218        case ArithSub: {
     219            if (m_graph.addShouldSpeculateInteger(node)
     220                && node.canSpeculateInteger())
     221                break;
     222            fixDoubleEdge(0);
     223            fixDoubleEdge(1);
     224            break;
     225        }
     226           
     227        case ArithNegate: {
     228            if (m_graph.negateShouldSpeculateInteger(node))
     229                break;
     230            fixDoubleEdge(0);
     231            break;
     232        }
     233           
     234        case ArithMin:
     235        case ArithMax:
     236        case ArithMul:
     237        case ArithDiv:
     238        case ArithMod: {
     239            if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])
     240                && node.canSpeculateInteger())
     241                break;
     242            fixDoubleEdge(0);
     243            fixDoubleEdge(1);
     244            break;
     245        }
     246           
     247        case ArithAbs: {
     248            if (m_graph[node.child1()].shouldSpeculateInteger()
     249                && node.canSpeculateInteger())
     250                break;
     251            fixDoubleEdge(0);
     252            break;
     253        }
     254           
     255        case ArithSqrt: {
     256            fixDoubleEdge(0);
     257            break;
     258        }
     259           
     260        case PutByVal: {
     261            if (!m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction())
     262                break;
     263            if (!m_graph[node.child2()].shouldSpeculateInteger())
     264                break;
     265            if (isActionableIntMutableArrayPrediction(m_graph[node.child1()].prediction())) {
     266                if (m_graph[node.child3()].isConstant())
     267                    break;
     268                if (m_graph[node.child3()].shouldSpeculateInteger())
     269                    break;
     270                fixDoubleEdge(2);
     271                break;
     272            }
     273            if (isActionableFloatMutableArrayPrediction(m_graph[node.child1()].prediction())) {
     274                fixDoubleEdge(2);
     275                break;
     276            }
     277            break;
     278        }
     279           
    155280        default:
    156281            break;
    … …  
    158283
    159284#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
     285        if (!(node.flags() & NodeHasVarArgs)) {
     286            dataLog("new children: ");
     287            node.dumpChildren(WTF::dataFile());
     288        }
    160289        dataLog("\n");
    161290#endif
    … …  
    180309    }
    181310   
     311    void fixDoubleEdge(unsigned childIndex)
     312    {
     313        Node& source = m_graph[m_compileIndex];
     314        Edge& edge = source.children.child(childIndex);
     315       
     316        if (!m_graph[edge].shouldSpeculateInteger()) {
     317            edge.setUseKind(DoubleUse);
     318            return;
     319        }
     320       
     321        NodeIndex resultIndex = (NodeIndex)m_graph.size();
     322       
     323#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
     324        dataLog("(replacing @%u->@%u with @%u->@%u) ",
     325                m_compileIndex, edge.index(), m_compileIndex, resultIndex);
     326#endif
     327       
     328        // Fix the edge up here because it's a reference that will be clobbered by
     329        // the append() below.
     330        NodeIndex oldIndex = edge.index();
     331        edge = Edge(resultIndex, DoubleUse);
     332
     333        m_graph.append(Node(Int32ToDouble, source.codeOrigin, oldIndex));
     334        m_insertionSet.append(m_indexInBlock, resultIndex);
     335       
     336        Node& int32ToDouble = m_graph[resultIndex];
     337        int32ToDouble.predict(PredictDouble);
     338        int32ToDouble.ref();
     339    }
     340   
     341    unsigned m_indexInBlock;
    182342    NodeIndex m_compileIndex;
     343    InsertionSet<NodeIndex> m_insertionSet;
    183344};
    184345   
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r112015 r112040  
    164164            else
    165165                hasPrinted = true;
    166             dataLog("@%u%s", m_varArgChildren[childIdx].index(), predictionToAbbreviatedString(at(childIdx).prediction()));
     166            dataLog("%s@%u%s",
     167                    useKindToString(m_varArgChildren[childIdx].useKind()),
     168                    m_varArgChildren[childIdx].index(),
     169                    predictionToAbbreviatedString(at(childIdx).prediction()));
    167170        }
    168171    } else {
    169         if (!!node.child1())
    170             dataLog("@%u%s", node.child1().index(), predictionToAbbreviatedString(at(node.child1()).prediction()));
    171         if (!!node.child2())
    172             dataLog(", @%u%s", node.child2().index(), predictionToAbbreviatedString(at(node.child2()).prediction()));
    173         if (!!node.child3())
    174             dataLog(", @%u%s", node.child3().index(), predictionToAbbreviatedString(at(node.child3()).prediction()));
     172        if (!!node.child1()) {
     173            dataLog("%s@%u%s",
     174                    useKindToString(node.child1().useKind()),
     175                    node.child1().index(),
     176                    predictionToAbbreviatedString(at(node.child1()).prediction()));
     177        }
     178        if (!!node.child2()) {
     179            dataLog(", %s@%u%s",
     180                    useKindToString(node.child2().useKind()),
     181                    node.child2().index(),
     182                    predictionToAbbreviatedString(at(node.child2()).prediction()));
     183        }
     184        if (!!node.child3()) {
     185            dataLog(", %s@%u%s",
     186                    useKindToString(node.child3().useKind()),
     187                    node.child3().index(),
     188                    predictionToAbbreviatedString(at(node.child3()).prediction()));
     189        }
    175190        hasPrinted = !!node.child1();
    176191    }
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r111129 r112040  
    7676    /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
    7777    macro(UInt32ToNumber, NodeResultNumber) \
     78    /* Used to cast known integers to doubles, so as to separate the double form */\
     79    /* of the value from the integer form. */\
     80    macro(Int32ToDouble, NodeResultNumber) \
    7881    \
    7982    /* Nodes for arithmetic operations. */\
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r112015 r112040  
    570570        case GetFloat32ArrayLength:
    571571        case GetFloat64ArrayLength:
    572         case GetStringLength: {
     572        case GetStringLength:
     573        case Int32ToDouble: {
    573574            // This node should never be visible at this stage of compilation. It is
    574575            // inserted by fixup(), which follows this phase.
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r112013 r112040  
    12851285            // There are four possibilities:
    12861286            //
     1287            // Int32ToDouble: We can use this in place of the original node, but
     1288            //    we'd rather not; so we use it only if it is the only remaining
     1289            //    live version.
     1290            //
    12871291            // ValueToInt32: If the only remaining live version of the value is
    12881292            //    ValueToInt32, then we can use it.
    … …  
    13071311       
    13081312            if (!found) {
     1313                NodeIndex int32ToDoubleIndex = NoNode;
    13091314                NodeIndex valueToInt32Index = NoNode;
    13101315                NodeIndex uint32ToNumberIndex = NoNode;
    … …  
    13201325                        continue;
    13211326                    switch (node.op()) {
     1327                    case Int32ToDouble:
     1328                        int32ToDoubleIndex = info.nodeIndex();
     1329                        break;
    13221330                    case ValueToInt32:
    13231331                        valueToInt32Index = info.nodeIndex();
    … …  
    13321340           
    13331341                NodeIndex nodeIndexToUse;
    1334                 if (valueToInt32Index != NoNode)
     1342                if (int32ToDoubleIndex != NoNode)
     1343                    nodeIndexToUse = int32ToDoubleIndex;
     1344                else if (valueToInt32Index != NoNode)
    13351345                    nodeIndexToUse = valueToInt32Index;
    13361346                else if (uint32ToNumberIndex != NoNode)
    … …  
    15381548        case GeneratedOperandDouble: {
    15391549            GPRTemporary result(this);
    1540             SpeculateDoubleOperand op1(this, node.child1());
     1550            DoubleOperand op1(this, node.child1());
    15411551            FPRReg fpr = op1.fpr();
    15421552            GPRReg gpr = result.gpr();
    … …  
    16731683    m_jit.move(op1.gpr(), result.gpr());
    16741684    integerResult(result.gpr(), m_compileIndex, op1.format());
     1685}
     1686
     1687void SpeculativeJIT::compileInt32ToDouble(Node& node)
     1688{
     1689#if USE(JSVALUE64)
     1690    // On JSVALUE64 we have a way of loading double constants in a more direct manner
     1691    // than a int->double conversion. On 32_64, unfortunately, we currently don't have
     1692    // any such mechanism - though we could have it, if we just provisioned some memory
     1693    // in CodeBlock for the double form of integer constants.
     1694    if (at(node.child1()).hasConstant()) {
     1695        ASSERT(isInt32Constant(node.child1().index()));
     1696        FPRTemporary result(this);
     1697        GPRTemporary temp(this);
     1698        m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(node.child1().index())))), temp.gpr());
     1699        m_jit.movePtrToDouble(temp.gpr(), result.fpr());
     1700        doubleResult(result.fpr(), m_compileIndex);
     1701        return;
     1702    }
     1703#endif
     1704   
     1705    if (isInt32Prediction(m_state.forNode(node.child1()).m_type)) {
     1706        SpeculateIntegerOperand op1(this, node.child1());
     1707        FPRTemporary result(this);
     1708        m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
     1709        doubleResult(result.fpr(), m_compileIndex);
     1710        return;
     1711    }
     1712   
     1713    JSValueOperand op1(this, node.child1());
     1714    FPRTemporary result(this);
     1715   
     1716#if USE(JSVALUE64)
     1717    GPRTemporary temp(this);
     1718
     1719    GPRReg op1GPR = op1.gpr();
     1720    GPRReg tempGPR = temp.gpr();
     1721    FPRReg resultFPR = result.fpr();
     1722   
     1723    JITCompiler::Jump isInteger = m_jit.branchPtr(
     1724        MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister);
     1725   
     1726    speculationCheck(
     1727        BadType, JSValueRegs(op1GPR), node.child1(),
     1728        m_jit.branchTestPtr(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
     1729   
     1730    m_jit.move(op1GPR, tempGPR);
     1731    unboxDouble(tempGPR, resultFPR);
     1732    JITCompiler::Jump done = m_jit.jump();
     1733   
     1734    isInteger.link(&m_jit);
     1735    m_jit.convertInt32ToDouble(op1GPR, resultFPR);
     1736    done.link(&m_jit);
     1737#else
     1738    FPRTemporary temp(this);
     1739   
     1740    GPRReg op1TagGPR = op1.tagGPR();
     1741    GPRReg op1PayloadGPR = op1.payloadGPR();
     1742    FPRReg tempFPR = temp.fpr();
     1743    FPRReg resultFPR = result.fpr();
     1744   
     1745    JITCompiler::Jump isInteger = m_jit.branch32(
     1746        MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag));
     1747   
     1748    speculationCheck(
     1749        BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node.child1(),
     1750        m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
     1751   
     1752    unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR);
     1753    JITCompiler::Jump done = m_jit.jump();
     1754   
     1755    isInteger.link(&m_jit);
     1756    m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR);
     1757    done.link(&m_jit);
     1758#endif
     1759   
     1760    doubleResult(resultFPR, m_compileIndex);
    16751761}
    16761762
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r111906 r112040  
    17331733    void compileValueToInt32(Node&);
    17341734    void compileUInt32ToNumber(Node&);
     1735    void compileInt32ToDouble(Node&);
    17351736    void compileGetByValOnByteArray(Node&);
    17361737    void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
    … …  
    19851986    {
    19861987        ASSERT(m_jit);
     1988        ASSERT(use.useKind() != DoubleUse);
    19871989        if (jit->isFilled(m_index))
    19881990            gpr();
    … …  
    20342036    {
    20352037        ASSERT(m_jit);
     2038       
     2039        // This is counter-intuitive but correct. DoubleOperand is intended to
     2040        // be used only when you're a node that is happy to accept an untyped
     2041        // value, but will special-case for doubles (using DoubleOperand) if the
     2042        // value happened to already be represented as a double. The implication
     2043        // is that you will not try to force the value to become a double if it
     2044        // is not one already.
     2045        ASSERT(use.useKind() != DoubleUse);
     2046       
    20362047        if (jit->isFilledDouble(m_index))
    20372048            fpr();
    … …  
    20792090    {
    20802091        ASSERT(m_jit);
     2092        ASSERT(use.useKind() != DoubleUse);
    20812093#if USE(JSVALUE64)
    20822094        if (jit->isFilled(m_index))
    … …  
    21892201    {
    21902202        ASSERT(m_jit);
     2203        ASSERT(use.useKind() != DoubleUse);
    21912204        if (jit->isFilled(m_index))
    21922205            gpr();
    … …  
    23612374    {
    23622375        ASSERT(m_jit);
     2376        ASSERT(use.useKind() != DoubleUse);
    23632377        if (jit->isFilled(m_index))
    23642378            gpr();
    … …  
    24052419    {
    24062420        ASSERT(m_jit);
     2421        ASSERT(use.useKind() != DoubleUse);
    24072422        if (jit->isFilled(m_index))
    24082423            gpr();
    … …  
    24462461    {
    24472462        ASSERT(m_jit);
     2463        ASSERT(use.useKind() == DoubleUse);
    24482464        if (jit->isFilled(m_index))
    24492465            fpr();
    … …  
    24822498    {
    24832499        ASSERT(m_jit);
     2500        ASSERT(use.useKind() != DoubleUse);
    24842501        if (jit->isFilled(m_index))
    24852502            gpr();
    … …  
    25232540    {
    25242541        ASSERT(m_jit);
     2542        ASSERT(use.useKind() != DoubleUse);
    25252543        if (jit->isFilled(m_index))
    25262544            gpr();
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r111649 r112040  
    18791879        break;
    18801880    }
     1881       
     1882    case Int32ToDouble: {
     1883        compileInt32ToDouble(node);
     1884        break;
     1885    }
    18811886
    18821887    case ValueAdd:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r112018 r112040  
    19661966        break;
    19671967    }
     1968       
     1969    case Int32ToDouble: {
     1970        compileInt32ToDouble(node);
     1971        break;
     1972    }
    19681973
    19691974    case ValueAdd:
Note: See TracChangeset for help on using the changeset viewer.