Ignore:
Timestamp:
Apr 28, 2015, 12:27:23 PM (10 years ago)
Author:
[email protected]
Message:

DFG should not use or preserve Phantoms during transformations
https://bugs.webkit.org/show_bug.cgi?id=143736

Reviewed by Geoffrey Garen.

Since http://trac.webkit.org/changeset/183207 and http://trac.webkit.org/changeset/183406, it is
no longer necessary to preserve Phantoms during transformations. They are still useful just
before FixupPhase to support backwards propagation analyses. They are still inserted late in the
game in the DFG backend. But transformations don't need to worry about them. Inside a basic
block, we can be sure that so long as the IR pinpoints the place where the value becomes
available in a bytecode register (using MovHint) and so long as there is a SetLocal anytime some
other block would need the value (either for OSR or for DFG execution), then we don't need any
liveness markers.

So, this removes any places where we inserted Phantoms just for liveness during transformation
and it replaces convertToPhantom() with remove(), which just converts the node to a Check. A
Check node only keeps its children so long as those children have checks.

The fact that we no longer convertToPhantom() means that we have to be more careful when
constant-folding GetLocal. Previously we would convertToPhantom() and use the fact that
Phantom(Phi) was a valid construct. It's not valid anymore. So, when constant folding encounters
a GetLocal it needs to insert a PhantomLocal directly. This allows us to simplify
Graph::convertToConstant() a bit. Luckily, none of the other users of this method would see
GetLocals.

The only Phantom-like cruft left over after this patch is:

  • Phantoms before FixupPhase. I kind of like these. It means that before FixupPhase, we can do backwards analyses and rely on the fact that the users of a node in DFG IR are a superset of the users of the original local's live range in bytecode. This is essential for supporting our BackwardsPropagationPhase, which is an important optimization for things like asm.js.


  • PhantomLocals and GetLocals being NodeMustGenerate. See discussion in https://bugs.webkit.org/show_bug.cgi?id=144086. It appears that this is not as evil as the alternatives. The best long-term plan is to simply ditch the ThreadedCPS IR entirely and have the DFG use SSA. For now, so long as any new DFG optimizations we add are block-local and treat GetLocal/SetLocal conservatively, this should all be sound.


This change should be perf-neutral although it does reduce the total work that the compiler
does.

(JSC::DFG::AdjacencyList::justChecks):

  • dfg/DFGArgumentsEliminationPhase.cpp:
  • dfg/DFGBasicBlock.cpp:

(JSC::DFG::BasicBlock::replaceTerminal):

  • dfg/DFGBasicBlock.h:

(JSC::DFG::BasicBlock::findTerminal):

  • dfg/DFGCFGSimplificationPhase.cpp:

(JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
(JSC::DFG::CFGSimplificationPhase::mergeBlocks):

  • dfg/DFGCPSRethreadingPhase.cpp:

(JSC::DFG::CPSRethreadingPhase::CPSRethreadingPhase):
(JSC::DFG::CPSRethreadingPhase::clearVariables):
(JSC::DFG::CPSRethreadingPhase::canonicalizeFlushOrPhantomLocalFor):
(JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock):

  • dfg/DFGCSEPhase.cpp:
  • dfg/DFGCleanUpPhase.cpp: Copied from Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp.

(JSC::DFG::CleanUpPhase::CleanUpPhase):
(JSC::DFG::CleanUpPhase::run):
(JSC::DFG::performCleanUp):
(JSC::DFG::PhantomRemovalPhase::PhantomRemovalPhase): Deleted.
(JSC::DFG::PhantomRemovalPhase::run): Deleted.
(JSC::DFG::performPhantomRemoval): Deleted.

  • dfg/DFGCleanUpPhase.h: Copied from Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.h.
  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::addBaseCheck):
(JSC::DFG::ConstantFoldingPhase::fixUpsilons):

  • dfg/DFGDCEPhase.cpp:

(JSC::DFG::DCEPhase::run):
(JSC::DFG::DCEPhase::fixupBlock):
(JSC::DFG::DCEPhase::cleanVariables):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupBlock):
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::convertStringAddUse):
(JSC::DFG::FixupPhase::attemptToMakeFastStringAdd):
(JSC::DFG::FixupPhase::checkArray):
(JSC::DFG::FixupPhase::fixIntConvertingEdge):
(JSC::DFG::FixupPhase::fixIntOrBooleanEdge):
(JSC::DFG::FixupPhase::fixDoubleOrBooleanEdge):
(JSC::DFG::FixupPhase::injectTypeConversionsInBlock):
(JSC::DFG::FixupPhase::tryToRelaxRepresentation):
(JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
(JSC::DFG::FixupPhase::addRequiredPhantom): Deleted.
(JSC::DFG::FixupPhase::addPhantomsIfNecessary): Deleted.

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::convertToConstant):
(JSC::DFG::Graph::mergeRelevantToOSR): Deleted.

  • dfg/DFGGraph.h:
  • dfg/DFGInsertionSet.h:

(JSC::DFG::InsertionSet::insertCheck):

  • dfg/DFGIntegerCheckCombiningPhase.cpp:

(JSC::DFG::IntegerCheckCombiningPhase::handleBlock):

  • dfg/DFGLICMPhase.cpp:

(JSC::DFG::LICMPhase::attemptHoist):

  • dfg/DFGNode.cpp:

(JSC::DFG::Node::remove):

  • dfg/DFGNode.h:

(JSC::DFG::Node::replaceWith):
(JSC::DFG::Node::convertToPhantom): Deleted.
(JSC::DFG::Node::convertToCheck): Deleted.
(JSC::DFG::Node::willHaveCodeGenOrOSR): Deleted.

  • dfg/DFGNodeFlags.h:
  • dfg/DFGNodeType.h:
  • dfg/DFGObjectAllocationSinkingPhase.cpp:

(JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations):
(JSC::DFG::ObjectAllocationSinkingPhase::handleNode):

  • dfg/DFGPhantomCanonicalizationPhase.cpp: Removed.
  • dfg/DFGPhantomCanonicalizationPhase.h: Removed.
  • dfg/DFGPhantomRemovalPhase.cpp: Removed.
  • dfg/DFGPhantomRemovalPhase.h: Removed.
  • dfg/DFGPlan.cpp:

(JSC::DFG::Plan::compileInThreadImpl):

  • dfg/DFGPutStackSinkingPhase.cpp:
  • dfg/DFGResurrectionForValidationPhase.cpp: Removed.
  • dfg/DFGResurrectionForValidationPhase.h: Removed.
  • dfg/DFGSSAConversionPhase.cpp:

(JSC::DFG::SSAConversionPhase::run):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):

  • dfg/DFGStoreBarrierElisionPhase.cpp:

(JSC::DFG::StoreBarrierElisionPhase::elideBarrier):

  • dfg/DFGStrengthReductionPhase.cpp:

(JSC::DFG::StrengthReductionPhase::handleNode):
(JSC::DFG::StrengthReductionPhase::convertToIdentityOverChild):

  • dfg/DFGValidate.cpp:

(JSC::DFG::Validate::validate):
(JSC::DFG::Validate::validateCPS):
(JSC::DFG::Validate::validateSSA):

  • dfg/DFGVarargsForwardingPhase.cpp:
  • ftl/FTLLink.cpp:

(JSC::FTL::link):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileNoOp):
(JSC::FTL::LowerDFGToLLVM::compilePhantom): Deleted.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp

    r183401 r183497  
    5151        m_graph.computeRefCounts();
    5252       
    53         if (m_graph.m_form == SSA) {
    54             for (BasicBlock* block : m_graph.blocksInPreOrder())
    55                 fixupBlock(block);
    56            
    57             // This is like cleanVariables, but has a much simpler approach to GetLocal.
    58             for (unsigned i = m_graph.m_arguments.size(); i--;) {
    59                 Node* node = m_graph.m_arguments[i];
    60                 if (!node)
    61                     continue;
    62                 if (node->op() != Phantom && node->op() != Check && node->shouldGenerate())
    63                     continue;
    64                 m_graph.m_arguments[i] = nullptr;
    65             }
    66         } else {
    67             RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
    68            
    69             for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
    70                 fixupBlock(m_graph.block(blockIndex));
    71             cleanVariables(m_graph.m_arguments);
    72         }
     53        for (BasicBlock* block : m_graph.blocksInPreOrder())
     54            fixupBlock(block);
    7355       
     56        cleanVariables(m_graph.m_arguments);
     57
    7458        // Just do a basic Phantom/Check clean-up.
    7559        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
     
    10589        if (!block)
    10690            return;
    107        
    108         switch (m_graph.m_form) {
    109         case SSA:
    110             break;
    111            
    112         case ThreadedCPS: {
    113             // Clean up variable links for the block. We need to do this before the actual DCE
    114             // because we need to see GetLocals, so we can bypass them in situations where the
    115             // vars-at-tail point to a GetLocal, the GetLocal is dead, but the Phi it points
    116             // to is alive.
    117            
     91
     92        if (m_graph.m_form == ThreadedCPS) {
    11893            for (unsigned phiIndex = 0; phiIndex < block->phis.size(); ++phiIndex) {
    119                 if (!block->phis[phiIndex]->shouldGenerate()) {
    120                     // FIXME: We could actually free nodes here. Except that it probably
    121                     // doesn't matter, since we don't add any nodes after this phase.
    122                     // https://bugs.webkit.org/show_bug.cgi?id=126239
     94                Node* phi = block->phis[phiIndex];
     95                if (!phi->shouldGenerate()) {
     96                    m_graph.m_allocator.free(phi);
    12397                    block->phis[phiIndex--] = block->phis.last();
    12498                    block->phis.removeLast();
     
    128102            cleanVariables(block->variablesAtHead);
    129103            cleanVariables(block->variablesAtTail);
    130             break;
    131         }
    132            
    133         default:
    134             RELEASE_ASSERT_NOT_REACHED();
    135             return;
    136104        }
    137105
     
    142110                continue;
    143111               
    144             switch (node->op()) {
    145             case MovHint:
    146             case ZombieHint:
    147                 // These are not killable. (They once were.)
    148                 RELEASE_ASSERT_NOT_REACHED();
     112            if (node->flags() & NodeHasVarArgs) {
     113                for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) {
     114                    Edge edge = m_graph.m_varArgChildren[childIdx];
     115                   
     116                    if (!edge || edge.willNotHaveCheck())
     117                        continue;
     118                   
     119                    m_insertionSet.insertNode(indexInBlock, SpecNone, Check, node->origin, edge);
     120                }
    149121               
    150             default: {
    151                 if (node->flags() & NodeHasVarArgs) {
    152                     for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) {
    153                         Edge edge = m_graph.m_varArgChildren[childIdx];
    154 
    155                         if (!edge || edge.isProved() || edge.willNotHaveCheck())
    156                             continue;
    157 
    158                         m_insertionSet.insertNode(indexInBlock, SpecNone, Check, node->origin, edge);
    159                     }
    160 
    161                     node->convertToPhantom();
    162                     node->children.reset();
    163                     node->setRefCount(1);
    164                     break;
    165                 }
    166 
    167                 node->convertToCheck();
    168                 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
    169                     Edge edge = node->children.child(i);
    170                     if (!edge)
    171                         continue;
    172                     if (edge.isProved() || edge.willNotHaveCheck())
    173                         node->children.removeEdge(i--);
    174                 }
     122                node->setOpAndDefaultFlags(Check);
     123                node->children.reset();
    175124                node->setRefCount(1);
    176                 break;
    177             } }
     125                continue;
     126            }
     127           
     128            node->remove();
     129            node->setRefCount(1);
    178130        }
    179131
     
    188140            if (!node)
    189141                continue;
    190             if (node->op() != Phantom && node->op() != Check && node->shouldGenerate())
     142            if (node->op() != Check && node->shouldGenerate())
    191143                continue;
    192             if (node->op() == GetLocal) {
    193                 node = node->child1().node();
    194                
    195                 ASSERT(node->op() == Phi || node->op() == SetArgument);
    196                
    197                 if (node->shouldGenerate()) {
    198                     variables[i] = node;
    199                     continue;
    200                 }
    201             }
    202             variables[i] = 0;
     144            variables[i] = nullptr;
    203145        }
    204146    }
Note: See TracChangeset for help on using the changeset viewer.