diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp | 612 |
1 files changed, 280 insertions, 332 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp b/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp index 57fc09529..cde074007 100644 --- a/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,9 @@ #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" -#include "Operations.h" +#include "DFGSSACalculator.h" +#include "DFGVariableAccessDataDump.h" +#include "JSCInlines.h" namespace JSC { namespace DFG { @@ -42,8 +44,8 @@ class SSAConversionPhase : public Phase { public: SSAConversionPhase(Graph& graph) : Phase(graph, "SSA conversion") + , m_calculator(graph) , m_insertionSet(graph) - , m_changed(false) { } @@ -51,315 +53,318 @@ public: { RELEASE_ASSERT(m_graph.m_form == ThreadedCPS); - // Figure out which SetLocal's need flushing. Need to do this while the - // Phi graph is still intact. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned nodeIndex = block->size(); nodeIndex--;) { - Node* node = block->at(nodeIndex); - if (node->op() != Flush) - continue; - addFlushedLocalOp(node); - } + m_graph.clearReplacements(); + m_graph.ensureDominators(); + + if (verbose) { + dataLog("Graph before SSA transformation:\n"); + m_graph.dump(); } - while (!m_flushedLocalOpWorklist.isEmpty()) { - Node* node = m_flushedLocalOpWorklist.takeLast(); - ASSERT(m_flushedLocalOps.contains(node)); - DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge); + + // Create a SSACalculator::Variable for every root VariableAccessData. + for (VariableAccessData& variable : m_graph.m_variableAccessData) { + if (!variable.isRoot()) + continue; + + SSACalculator::Variable* ssaVariable = m_calculator.newVariable(); + ASSERT(ssaVariable->index() == m_variableForSSAIndex.size()); + m_variableForSSAIndex.append(&variable); + m_ssaVariableForVariable.add(&variable, ssaVariable); } - // Eliminate all duplicate or self-pointing Phi edges. This means that - // we transform: - // - // p: Phi(@n1, @n2, @n3) - // - // into: - // - // p: Phi(@x) - // - // if each @ni in {@n1, @n2, @n3} is either equal to @p to is equal - // to @x, for exactly one other @x. Additionally, trivial Phis (i.e. - // p: Phi(@x)) are forwarded, so that if have an edge to such @p, we - // replace it with @x. This loop does this for Phis only; later we do - // such forwarding for Phi references found in other nodes. - // - // See Aycock and Horspool in CC'00 for a better description of what - // we're doing here. - do { - m_changed = false; - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned phiIndex = block->phis.size(); phiIndex--;) { - Node* phi = block->phis[phiIndex]; - if (phi->variableAccessData()->isCaptured()) - continue; - forwardPhiChildren(phi); - deduplicateChildren(phi); - } - } - } while (m_changed); - - // For each basic block, for each local live at the head of that block, - // figure out what node we should be referring to instead of that local. - // If it turns out to be a non-trivial Phi, make sure that we create an - // SSA Phi and Upsilons in predecessor blocks. We reuse - // BasicBlock::variablesAtHead for tracking which nodes to refer to. + // Find all SetLocals and create Defs for them. We handle SetArgument by creating a + // GetLocal, and recording the flush format. for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; - for (unsigned i = block->variablesAtHead.size(); i--;) { - Node* node = block->variablesAtHead[i]; - if (!node) + // Must process the block in forward direction because we want to see the last + // assignment for every local. + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (node->op() != SetLocal && node->op() != SetArgument) continue; VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) { - // Poison this entry in variablesAtHead because we don't - // want anyone to try to refer to it, if the variable is - // captured. - block->variablesAtHead[i] = 0; - continue; - } - - switch (node->op()) { - case Phi: - case SetArgument: - break; - case Flush: - case GetLocal: - case PhantomLocal: - node = node->child1().node(); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - RELEASE_ASSERT(node->op() == Phi || node->op() == SetArgument); - bool isFlushed = m_flushedLocalOps.contains(node); - - if (node->op() == Phi) { - Edge edge = node->children.justOneChild(); - if (edge) - node = edge.node(); // It's something from a different basic block. - else { - // It's a non-trivial Phi. - FlushFormat format = variable->flushFormat(); - NodeFlags result = resultFor(format); - UseKind useKind = useKindFor(format); - - node = m_insertionSet.insertNode(0, SpecNone, Phi, CodeOrigin()); - node->mergeFlags(result); - RELEASE_ASSERT((node->flags() & NodeResultMask) == result); - - for (unsigned j = block->predecessors.size(); j--;) { - BasicBlock* predecessor = block->predecessors[j]; - predecessor->appendNonTerminal( - m_graph, SpecNone, Upsilon, predecessor->last()->codeOrigin, - OpInfo(node), Edge(predecessor->variablesAtTail[i], useKind)); - } - - if (isFlushed) { - // Do nothing. For multiple reasons. - - // Reason #1: If the local is flushed then we don't need to bother - // with a MovHint since every path to this point in the code will - // have flushed the bytecode variable using a SetLocal and hence - // the Availability::flushedAt() will agree, and that will be - // sufficient for figuring out how to recover the variable's value. - - // Reason #2: If we had inserted a MovHint and the Phi function had - // died (because the only user of the value was the "flush" - i.e. - // some asynchronous runtime thingy) then the MovHint would turn - // into a ZombieHint, which would fool us into thinking that the - // variable is dead. - - // Reason #3: If we had inserted a MovHint then even if the Phi - // stayed alive, we would still end up generating inefficient code - // since we would be telling the OSR exit compiler to use some SSA - // value for the bytecode variable rather than just telling it that - // the value was already on the stack. - } else { - m_insertionSet.insertNode( - 0, SpecNone, MovHint, CodeOrigin(), - OpInfo(variable->local().offset()), Edge(node)); - } - } + Node* childNode; + if (node->op() == SetLocal) + childNode = node->child1().node(); + else { + ASSERT(node->op() == SetArgument); + childNode = m_insertionSet.insertNode( + nodeIndex, node->variableAccessData()->prediction(), + GetStack, node->origin, + OpInfo(m_graph.m_stackAccessData.add(variable->local(), variable->flushFormat()))); + if (!ASSERT_DISABLED) + m_argumentGetters.add(childNode); + m_argumentMapping.add(node, childNode); } - block->variablesAtHead[i] = node; + m_calculator.newDef( + m_ssaVariableForVariable.get(variable), block, childNode); } - + m_insertionSet.execute(block); } + // Decide where Phis are to be inserted. This creates the Phi's but doesn't insert them + // yet. We will later know where to insert them because SSACalculator is such a bro. + m_calculator.computePhis( + [&] (SSACalculator::Variable* ssaVariable, BasicBlock* block) -> Node* { + VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()]; + + // Prune by liveness. This doesn't buy us much other than compile times. + Node* headNode = block->variablesAtHead.operand(variable->local()); + if (!headNode) + return nullptr; + + // There is the possibiltiy of "rebirths". The SSA calculator will already prune + // rebirths for the same VariableAccessData. But it will not be able to prune + // rebirths that arose from the same local variable number but a different + // VariableAccessData. We do that pruning here. + // + // Here's an example of a rebirth that this would catch: + // + // var x; + // if (foo) { + // if (bar) { + // x = 42; + // } else { + // x = 43; + // } + // print(x); + // x = 44; + // } else { + // x = 45; + // } + // print(x); // Without this check, we'd have a Phi for x = 42|43 here. + // + // FIXME: Consider feeding local variable numbers, not VariableAccessData*'s, as + // the "variables" for SSACalculator. That would allow us to eliminate this + // special case. + // https://bugs.webkit.org/show_bug.cgi?id=136641 + if (headNode->variableAccessData() != variable) + return nullptr; + + Node* phiNode = m_graph.addNode( + variable->prediction(), Phi, block->at(0)->origin.withInvalidExit()); + FlushFormat format = variable->flushFormat(); + NodeFlags result = resultFor(format); + phiNode->mergeFlags(result); + return phiNode; + }); + if (verbose) { - dataLog("Variables at head after SSA Phi insertion:\n"); - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - dataLog(" ", *block, ": ", block->variablesAtHead, "\n"); - } + dataLog("Computed Phis, about to transform the graph.\n"); + dataLog("\n"); + dataLog("Graph:\n"); + m_graph.dump(); + dataLog("\n"); + dataLog("Mappings:\n"); + for (unsigned i = 0; i < m_variableForSSAIndex.size(); ++i) + dataLog(" ", i, ": ", VariableAccessDataDump(m_graph, m_variableForSSAIndex[i]), "\n"); + dataLog("\n"); + dataLog("SSA calculator: ", m_calculator, "\n"); } - // At this point variablesAtHead in each block refers to either: + // Do the bulk of the SSA conversion. For each block, this tracks the operand->Node + // mapping based on a combination of what the SSACalculator tells us, and us walking over + // the block in forward order. We use our own data structure, valueForOperand, for + // determining the local mapping, but we rely on SSACalculator for the non-local mapping. // - // 1) A new SSA phi in the current block. - // 2) A SetArgument, which will soon get converted into a GetArgument. - // 3) An old CPS phi in a different block. + // This does three things at once: // - // We don't have to do anything for (1) and (2), but we do need to - // do a replacement for (3). - - // Clear all replacements, since other phases may have used them. - m_graph.clearReplacements(); - - // For all of the old CPS Phis, figure out what they correspond to in SSA. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned phiIndex = block->phis.size(); phiIndex--;) { - Node* phi = block->phis[phiIndex]; - if (verbose) { - dataLog( - "Considering ", phi, ", for r", phi->local(), - ", and its replacement in ", *block, ", ", - block->variablesAtHead.operand(phi->local()), "\n"); + // - Inserts the Phis in all of the places where they need to go. We've already created + // them and they are accounted for in the SSACalculator's data structures, but we + // haven't inserted them yet, mostly because we want to insert all of a block's Phis in + // one go to amortize the cost of node insertion. + // + // - Create and insert Upsilons. + // + // - Convert all of the preexisting SSA nodes (other than the old CPS Phi nodes) into SSA + // form by replacing as follows: + // + // - MovHint has KillLocal prepended to it. + // + // - GetLocal die and get replaced with references to the node specified by + // valueForOperand. + // + // - SetLocal turns into PutStack if it's flushed, or turns into a Check otherwise. + // + // - Flush loses its children and turns into a Phantom. + // + // - PhantomLocal becomes Phantom, and its child is whatever is specified by + // valueForOperand. + // + // - SetArgument is removed. Note that GetStack nodes have already been inserted. + Operands<Node*> valueForOperand(OperandsLike, m_graph.block(0)->variablesAtHead); + for (BasicBlock* block : m_graph.blocksInPreOrder()) { + valueForOperand.clear(); + + // CPS will claim that the root block has all arguments live. But we have already done + // the first step of SSA conversion: argument locals are no longer live at head; + // instead we have GetStack nodes for extracting the values of arguments. So, we + // skip the at-head available value calculation for the root block. + if (block != m_graph.block(0)) { + for (size_t i = valueForOperand.size(); i--;) { + Node* nodeAtHead = block->variablesAtHead[i]; + if (!nodeAtHead) + continue; + + VariableAccessData* variable = nodeAtHead->variableAccessData(); + + if (verbose) + dataLog("Considering live variable ", VariableAccessDataDump(m_graph, variable), " at head of block ", *block, "\n"); + + SSACalculator::Variable* ssaVariable = m_ssaVariableForVariable.get(variable); + SSACalculator::Def* def = m_calculator.reachingDefAtHead(block, ssaVariable); + if (!def) { + // If we are required to insert a Phi, then we won't have a reaching def + // at head. + continue; + } + + Node* node = def->value(); + if (node->replacement()) { + // This will occur when a SetLocal had a GetLocal as its source. The + // GetLocal would get replaced with an actual SSA value by the time we get + // here. Note that the SSA value with which the GetLocal got replaced + // would not in turn have a replacement. + node = node->replacement(); + ASSERT(!node->replacement()); + } + if (verbose) + dataLog("Mapping: ", VirtualRegister(valueForOperand.operandForIndex(i)), " -> ", node, "\n"); + valueForOperand[i] = node; } - phi->misc.replacement = block->variablesAtHead.operand(phi->local()); - } - } - - // Now make sure that all variablesAtHead in each block points to the - // canonical SSA value. Prior to this, variablesAtHead[local] may point to - // an old CPS Phi in a different block. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (size_t i = block->variablesAtHead.size(); i--;) { - Node* node = block->variablesAtHead[i]; - if (!node) - continue; - while (node->misc.replacement) - node = node->misc.replacement; - block->variablesAtHead[i] = node; - } - } - - if (verbose) { - dataLog("Variables at head after convergence:\n"); - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - dataLog(" ", *block, ": ", block->variablesAtHead, "\n"); } - } - - // Convert operations over locals into operations over SSA nodes. - // - GetLocal over captured variables lose their phis. - // - GetLocal over uncaptured variables die and get replaced with references - // to the node specified by variablesAtHead. - // - SetLocal gets NodeMustGenerate if it's flushed, or turns into a - // Check otherwise. - // - Flush loses its children but remains, because we want to know when a - // flushed SetLocal's value is no longer needed. This also makes it simpler - // to reason about the format of a local, since we can just do a backwards - // analysis (see FlushLivenessAnalysisPhase). As part of the backwards - // analysis, we say that the type of a local can be either int32, double, - // value, or dead. - // - PhantomLocal becomes Phantom, and its child is whatever is specified - // by variablesAtHead. - // - SetArgument turns into GetArgument unless it's a captured variable. - // - Upsilons get their children fixed to refer to the true value of that local - // at the end of the block. Prior to this loop, Upsilons will refer to - // variableAtTail[operand], which may be any of Flush, PhantomLocal, GetLocal, - // SetLocal, SetArgument, or Phi. We accomplish this by setting the - // replacement pointers of all of those nodes to refer to either - // variablesAtHead[operand], or the child of the SetLocal. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned phiIndex = block->phis.size(); phiIndex--;) { - block->phis[phiIndex]->misc.replacement = - block->variablesAtHead.operand(block->phis[phiIndex]->local()); + // Insert Phis by asking the calculator what phis there are in this block. Also update + // valueForOperand with those Phis. For Phis associated with variables that are not + // flushed, we also insert a MovHint. + size_t phiInsertionPoint = 0; + for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(block)) { + VariableAccessData* variable = m_variableForSSAIndex[phiDef->variable()->index()]; + + m_insertionSet.insert(phiInsertionPoint, phiDef->value()); + valueForOperand.operand(variable->local()) = phiDef->value(); + + m_insertionSet.insertNode( + phiInsertionPoint, SpecNone, MovHint, block->at(0)->origin.withInvalidExit(), + OpInfo(variable->local().offset()), phiDef->value()->defaultEdge()); } - for (unsigned nodeIndex = block->size(); nodeIndex--;) - ASSERT(!block->at(nodeIndex)->misc.replacement); + + if (block->at(0)->origin.exitOK) + m_insertionSet.insertNode(phiInsertionPoint, SpecNone, ExitOK, block->at(0)->origin); for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { Node* node = block->at(nodeIndex); + if (verbose) { + dataLog("Processing node ", node, ":\n"); + m_graph.dump(WTF::dataFile(), " ", node); + } + m_graph.performSubstitution(node); switch (node->op()) { + case MovHint: { + m_insertionSet.insertNode( + nodeIndex, SpecNone, KillStack, node->origin, + OpInfo(node->unlinkedLocal().offset())); + node->origin.exitOK = false; // KillStack clobbers exit. + break; + } + case SetLocal: { VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured() || m_flushedLocalOps.contains(node)) - node->mergeFlags(NodeMustGenerate); - else - node->setOpAndDefaultFlags(Check); - node->misc.replacement = node->child1().node(); // Only for Upsilons. + Node* child = node->child1().node(); + + if (!!(node->flags() & NodeIsFlushed)) { + node->convertToPutStack( + m_graph.m_stackAccessData.add( + variable->local(), variable->flushFormat())); + } else + node->remove(); + + if (verbose) + dataLog("Mapping: ", variable->local(), " -> ", child, "\n"); + valueForOperand.operand(variable->local()) = child; + break; + } + + case GetStack: { + ASSERT(m_argumentGetters.contains(node)); + valueForOperand.operand(node->stackAccessData()->local) = node; break; } case GetLocal: { - // It seems tempting to just do forwardPhi(GetLocal), except that we - // could have created a new (SSA) Phi, and the GetLocal could still be - // referring to an old (CPS) Phi. Uses variablesAtHead to tell us what - // to refer to. - node->children.reset(); VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) - break; - node->convertToPhantom(); - node->misc.replacement = block->variablesAtHead.operand(variable->local()); + node->children.reset(); + + node->remove(); + if (verbose) + dataLog("Replacing node ", node, " with ", valueForOperand.operand(variable->local()), "\n"); + node->setReplacement(valueForOperand.operand(variable->local())); break; } case Flush: { node->children.reset(); - // This is only for Upsilons. An Upsilon will only refer to a Flush if - // there were no SetLocals or GetLocals in the block. - node->misc.replacement = block->variablesAtHead.operand(node->local()); + node->remove(); break; } case PhantomLocal: { + ASSERT(node->child1().useKind() == UntypedUse); VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) - break; - node->child1().setNode(block->variablesAtHead.operand(variable->local())); - node->convertToPhantom(); - // This is only for Upsilons. An Upsilon will only refer to a - // PhantomLocal if there were no SetLocals or GetLocals in the block. - node->misc.replacement = block->variablesAtHead.operand(variable->local()); + node->child1() = valueForOperand.operand(variable->local())->defaultEdge(); + node->remove(); break; } case SetArgument: { - VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) - break; - node->setOpAndDefaultFlags(GetArgument); - node->mergeFlags(resultFor(node->variableAccessData()->flushFormat())); + node->remove(); break; } - + default: break; } } + + // We want to insert Upsilons just before the end of the block. On the surface this + // seems dangerous because the Upsilon will have a checking UseKind. But, we will not + // actually be performing the check at the point of the Upsilon; the check will + // already have been performed at the point where the original SetLocal was. + NodeAndIndex terminal = block->findTerminal(); + size_t upsilonInsertionPoint = terminal.index; + NodeOrigin upsilonOrigin = terminal.node->origin; + for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { + BasicBlock* successorBlock = block->successor(successorIndex); + for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) { + Node* phiNode = phiDef->value(); + SSACalculator::Variable* ssaVariable = phiDef->variable(); + VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()]; + FlushFormat format = variable->flushFormat(); + + // We can use an unchecked use kind because the SetLocal was turned into a Check. + // We have to use an unchecked use because at least sometimes, the end of the block + // is not exitOK. + UseKind useKind = uncheckedUseKindFor(format); + + m_insertionSet.insertNode( + upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin, + OpInfo(phiNode), Edge( + valueForOperand.operand(variable->local()), + useKind)); + } + } + + m_insertionSet.execute(block); } // Free all CPS phis and reset variables vectors. @@ -368,106 +373,49 @@ public: if (!block) continue; for (unsigned phiIndex = block->phis.size(); phiIndex--;) - m_graph.m_allocator.free(block->phis[phiIndex]); + m_graph.deleteNode(block->phis[phiIndex]); block->phis.clear(); block->variablesAtHead.clear(); block->variablesAtTail.clear(); block->valuesAtHead.clear(); block->valuesAtHead.clear(); - block->ssa = adoptPtr(new BasicBlock::SSAData(block)); + block->ssa = std::make_unique<BasicBlock::SSAData>(block); } - m_graph.m_arguments.clear(); + m_graph.m_argumentFormats.resize(m_graph.m_arguments.size()); + for (unsigned i = m_graph.m_arguments.size(); i--;) { + FlushFormat format = FlushedJSValue; + + Node* node = m_argumentMapping.get(m_graph.m_arguments[i]); + + RELEASE_ASSERT(node); + format = node->stackAccessData()->format; + + m_graph.m_argumentFormats[i] = format; + m_graph.m_arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling. + } m_graph.m_form = SSA; - return true; - } -private: - void forwardPhiChildren(Node* node) - { - for (unsigned i = 0; i < AdjacencyList::Size; ++i) { - Edge& edge = node->children.child(i); - if (!edge) - break; - m_changed |= forwardPhiEdge(edge); - } - } - - Node* forwardPhi(Node* node) - { - for (;;) { - switch (node->op()) { - case Phi: { - Edge edge = node->children.justOneChild(); - if (!edge) - return node; - node = edge.node(); - break; - } - case GetLocal: - case SetLocal: - if (node->variableAccessData()->isCaptured()) - return node; - node = node->child1().node(); - break; - default: - return node; - } + if (verbose) { + dataLog("Graph after SSA transformation:\n"); + m_graph.dump(); } - } - - bool forwardPhiEdge(Edge& edge) - { - Node* newNode = forwardPhi(edge.node()); - if (newNode == edge.node()) - return false; - edge.setNode(newNode); + return true; } - - void deduplicateChildren(Node* node) - { - for (unsigned i = 0; i < AdjacencyList::Size; ++i) { - Edge edge = node->children.child(i); - if (!edge) - break; - if (edge == node) { - node->children.removeEdge(i--); - m_changed = true; - continue; - } - for (unsigned j = i + 1; j < AdjacencyList::Size; ++j) { - if (node->children.child(j) == edge) { - node->children.removeEdge(j--); - m_changed = true; - } - } - } - } - - void addFlushedLocalOp(Node* node) - { - if (m_flushedLocalOps.contains(node)) - return; - m_flushedLocalOps.add(node); - m_flushedLocalOpWorklist.append(node); - } - void addFlushedLocalEdge(Node*, Edge edge) - { - addFlushedLocalOp(edge.node()); - } - +private: + SSACalculator m_calculator; InsertionSet m_insertionSet; - HashSet<Node*> m_flushedLocalOps; - Vector<Node*> m_flushedLocalOpWorklist; - bool m_changed; + HashMap<VariableAccessData*, SSACalculator::Variable*> m_ssaVariableForVariable; + HashMap<Node*, Node*> m_argumentMapping; + HashSet<Node*> m_argumentGetters; + Vector<VariableAccessData*> m_variableForSSAIndex; }; bool performSSAConversion(Graph& graph) { - SamplingRegion samplingRegion("DFG SSA Conversion Phase"); return runPhase<SSAConversionPhase>(graph); } |