DFGSSAConversionPhase.cpp [plain text]
#include "config.h"
#include "DFGSSAConversionPhase.h"
#if ENABLE(DFG_JIT)
#include "DFGBasicBlockInlines.h"
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGPhase.h"
#include "JSCInlines.h"
namespace JSC { namespace DFG {
class SSAConversionPhase : public Phase {
static const bool verbose = false;
static const bool dumpGraph = false;
public:
SSAConversionPhase(Graph& graph)
: Phase(graph, "SSA conversion")
, m_insertionSet(graph)
, m_changed(false)
{
}
bool run()
{
RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
if (dumpGraph) {
dataLog("Graph dump at top of SSA conversion:\n");
m_graph.dump();
}
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);
Operands<bool> nonTrivialPhis(OperandsLike, m_graph.block(0)->variablesAtHead);
for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
nonTrivialPhis.fill(false);
for (unsigned i = block->phis.size(); i--;) {
Node* phi = block->phis[i];
if (!phi->children.justOneChild())
nonTrivialPhis.operand(phi->local()) = true;
}
for (unsigned i = block->variablesAtHead.size(); i--;) {
Node* node = block->variablesAtHead[i];
if (!node)
continue;
if (verbose)
dataLog("At block #", blockIndex, " for operand r", block->variablesAtHead.operandForIndex(i), " have node ", node, "\n");
VariableAccessData* variable = node->variableAccessData();
if (variable->isCaptured()) {
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 = !!(node->flags() & NodeIsFlushed);
if (node->op() == Phi) {
if (!nonTrivialPhis.operand(node->local())) {
Edge edge = node->children.justOneChild();
ASSERT(edge);
if (verbose)
dataLog(" One child: ", edge, ", ", RawPointer(edge.node()), "\n");
node = edge.node(); } else {
if (verbose)
dataLog(" Non-trivial.\n");
FlushFormat format = variable->flushFormat();
NodeFlags result = resultFor(format);
UseKind useKind = useKindFor(format);
node = m_insertionSet.insertNode(0, SpecNone, Phi, NodeOrigin());
if (verbose)
dataLog(" Inserted new node: ", node, "\n");
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()->origin,
OpInfo(node), Edge(predecessor->variablesAtTail[i], useKind));
}
if (isFlushed) {
} else {
m_insertionSet.insertNode(
0, SpecNone, MovHint, NodeOrigin(),
OpInfo(variable->local().offset()), node->defaultEdge());
}
}
}
block->variablesAtHead[i] = node;
}
m_insertionSet.execute(block);
}
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");
}
}
m_graph.clearReplacements();
if (dumpGraph) {
dataLog("Graph just before identifying replacements:\n");
m_graph.dump();
}
for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
if (verbose)
dataLog("Dealing with block #", blockIndex, "\n");
for (unsigned phiIndex = block->phis.size(); phiIndex--;) {
Node* phi = block->phis[phiIndex];
if (verbose) {
dataLog(
"Considering ", phi, " (", RawPointer(phi), "), for r",
phi->local(), ", and its replacement in ", *block, ", ",
block->variablesAtHead.operand(phi->local()), "\n");
}
ASSERT(phi != block->variablesAtHead.operand(phi->local()));
phi->misc.replacement = block->variablesAtHead.operand(phi->local());
}
}
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) {
ASSERT(node != 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");
}
}
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());
}
for (unsigned nodeIndex = block->size(); nodeIndex--;)
ASSERT(!block->at(nodeIndex)->misc.replacement);
for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
Node* node = block->at(nodeIndex);
m_graph.performSubstitution(node);
switch (node->op()) {
case SetLocal: {
VariableAccessData* variable = node->variableAccessData();
if (variable->isCaptured() || !!(node->flags() & NodeIsFlushed))
node->mergeFlags(NodeMustGenerate);
else
node->setOpAndDefaultFlags(Check);
node->misc.replacement = node->child1().node(); break;
}
case GetLocal: {
node->children.reset();
VariableAccessData* variable = node->variableAccessData();
if (variable->isCaptured())
break;
node->convertToPhantom();
node->misc.replacement = block->variablesAtHead.operand(variable->local());
break;
}
case Flush: {
node->children.reset();
node->convertToPhantom();
node->misc.replacement = block->variablesAtHead.operand(node->local());
break;
}
case PhantomLocal: {
ASSERT(node->child1().useKind() == UntypedUse);
VariableAccessData* variable = node->variableAccessData();
if (variable->isCaptured()) {
node->children.reset();
} else {
node->child1() =
block->variablesAtHead.operand(variable->local())->defaultEdge();
}
node->convertToPhantom();
node->misc.replacement = block->variablesAtHead.operand(variable->local());
break;
}
case SetArgument: {
VariableAccessData* variable = node->variableAccessData();
if (variable->isCaptured())
break;
node->setOpAndDefaultFlags(GetArgument);
node->setResult(resultFor(node->variableAccessData()->flushFormat()));
break;
}
default:
break;
}
}
}
for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
for (unsigned phiIndex = block->phis.size(); phiIndex--;)
m_graph.m_allocator.free(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));
}
m_graph.m_arguments.clear();
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;
}
}
}
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;
}
}
}
}
InsertionSet m_insertionSet;
bool m_changed;
};
bool performSSAConversion(Graph& graph)
{
SamplingRegion samplingRegion("DFG SSA Conversion Phase");
return runPhase<SSAConversionPhase>(graph);
}
} }
#endif // ENABLE(DFG_JIT)