gecko-dev/ef/Compiler/PrimitiveGraph/ControlGraph.cpp
1999-11-02 06:38:29 +00:00

829 lines
28 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "ControlGraph.h"
#include "GraphUtils.h"
#if defined(DEBUG) && (defined(WIN32) || defined(USE_MESA)) && defined(IGVISUALIZE)
#include "IGVisualizer.h"
#endif
#include <math.h>
// ----------------------------------------------------------------------------
// ControlGraph
#ifdef _WIN32
#pragma warning(disable: 4355)
#endif
//
// Create a new ControlGraph that contains only the BEGIN and END nodes.
// The graph has nArguments incoming arguments whose kinds are given by argumentKinds.
// If hasSelfArgument is true, the first argument is the 'this' argument.
// The graph initially has nMonitorSlots slots allocated for MEnter/MExit pairs.
// The graph starts with no control or data edges.
//
ControlGraph::ControlGraph(Pool &pool, uint nArguments, const ValueKind *argumentKinds, bool hasSelfArgument, Uint32 nMonitorSlots):
pool(pool),
nMonitorSlots(nMonitorSlots),
beginNode(*this),
endNode(*this),
returnNode(0),
recycleBuffer(0),
dfsList(0),
lndList(0)
{
beginNode.setControlBegin(nArguments, argumentKinds, hasSelfArgument, 0);
// asharma - fix this! - bci needs to be set properly here.
endNode.setControlEnd(0);
controlNodes.addFirst(beginNode);
controlNodes.addLast(endNode);
}
#ifdef _WIN32
#pragma warning(default: 4355)
#endif
//
// Create a new ControlNode in this graph and return it. The ControlNode
// will have no ControlExtra; the caller is responsible for creating that.
//
ControlNode &ControlGraph::newControlNode()
{
ControlNode *cn;
if (recycleBuffer) {
cn = recycleBuffer;
recycleBuffer = 0;
} else
cn = new(pool) ControlNode(*this);
controlNodes.addLast(*cn);
return *cn;
}
//
// Assign a unique producerNumber to each outgoing data edge in the ControlGraph.
// The first number assigned will be base; return the last number assigned + 1.
//
Uint32 ControlGraph::assignProducerNumbers(Uint32 base)
{
for (DoublyLinkedList<ControlNode>::iterator ci = controlNodes.begin(); !controlNodes.done(ci); ci = controlNodes.advance(ci)) {
ControlNode &cn = controlNodes.get(ci);
DoublyLinkedList<PhiNode> &phn = cn.getPhiNodes();
for (DoublyLinkedList<PhiNode>::iterator phi = phn.begin(); !phn.done(phi); phi = phn.advance(phi))
base = phn.get(phi).assignProducerNumbers(base);
DoublyLinkedList<Primitive> &prn = cn.getPrimitives();
for (DoublyLinkedList<Primitive>::iterator pri = prn.begin(); !prn.done(pri); pri = prn.advance(pri))
base = prn.get(pri).assignProducerNumbers(base);
}
return base;
}
class ControlDFSHelper
{
public:
typedef ControlEdge Successor;
typedef ControlNode *NodeRef;
bool hasBackEdges; // True if the graph contains a cycle
private:
ControlNode **dfsList; // Alias to dfsList from the ControlGraph
public:
ControlDFSHelper(ControlNode **dfsList): hasBackEdges(false), dfsList(dfsList) {}
static Successor *getSuccessorsBegin(NodeRef n) {return n->getSuccessorsBegin();}
static Successor *getSuccessorsEnd(NodeRef n) {return n->getSuccessorsEnd();}
static bool isNull(Successor &) {return false;}
static NodeRef getNodeRef(const Successor& s) {return &s.getTarget();}
static bool isMarked(NodeRef n) {return n->dfsNum != ControlNode::unmarked;}
static bool isUnvisited(NodeRef n) {return n->dfsNum == ControlNode::unvisited;}
static bool isNumbered(NodeRef n) {return n->dfsNum >= 0;}
static void setMarked(NodeRef n) {n->dfsNum = ControlNode::unvisited;}
static void setVisited(NodeRef n) {n->dfsNum = ControlNode::unnumbered;}
void setNumbered(NodeRef n, Int32 i) {assert(i >= 0); n->dfsNum = i; dfsList[i] = n;}
void notePredecessor(NodeRef) {}
void noteIncomingBackwardEdge(NodeRef) {hasBackEdges = true;}
};
//
// Initialize the dfsNum field of each ControlNode in this ControlGraph
// to the ControlNode's serial number. Also set up dfsList so that
// if n is ControlNode c's dfsNum, then dfsList[n] = &c.
//
#include "NativeFormatter.h"
void ControlGraph::dfsSearch()
{
// Initialize the ControlNodes' dfsNum fields.
Uint32 maxNControlNodes = 0;
for (DoublyLinkedList<ControlNode>::iterator i = controlNodes.begin(); !controlNodes.done(i); i = controlNodes.advance(i)) {
controlNodes.get(i).dfsNum = ControlNode::unmarked;
maxNControlNodes++;
}
// Count the ControlNodes reachable from beginNode.
dfsList = new(pool) ControlNode *[maxNControlNodes];
ControlDFSHelper dfsHelper(dfsList);
ControlEdge beginEdge;
ControlEdge endEdge;
beginEdge.setTarget(beginNode);
endEdge.setTarget(endNode);
SearchStackEntry<ControlEdge> *searchStack = new SearchStackEntry<ControlEdge>[maxNControlNodes];
nNodes = graphSearchWithEnd(dfsHelper, beginEdge, endEdge, maxNControlNodes, searchStack);
// Now do the actual depth-first search.
depthFirstSearchWithEnd(dfsHelper, beginEdge, endEdge, nNodes, searchStack);
hasBackEdges = dfsHelper.hasBackEdges;
#ifndef WIN32 // ***** Visual C++ has a bug in the code for delete[].
delete[] searchStack;
#endif
}
#include "CodeGenerator.h"
struct LoopSearchDepthInfo
{
Uint32 begin;
Uint32 count;
};
void ControlGraph::lndSearch()
{
Uint32 i;
if (!dfsListIsValid())
dfsSearch();
lndList = new(pool) ControlNode *[nNodes];
// Initialize the control node's depth info.
for (i = 0; i < nNodes; i++)
{
dfsList[i]->loopId = 0;
dfsList[i]->loopDepth = 0;
lndList[i] = dfsList[i];
}
if (!hasBackEdges)
return;
LoopSearchDepthInfo *depthInfo = new LoopSearchDepthInfo[nNodes + 1];
for (i = 1; i < nNodes + 1; i++) depthInfo[i].count = 0;
depthInfo[0].begin = 0;
depthInfo[0].count = nNodes;
ControlNode** stack = new ControlNode *[nNodes];
#ifdef DEBUG
ControlNode** stackEnd = &stack[nNodes];
#endif
Uint32 loopId = 1;
for (Uint32 n = 0; n < nNodes; n++)
{
ControlNode* node = dfsList[n];
ControlEdge* successors_limit = node->getSuccessorsEnd();
for (ControlEdge* successor = node->getSuccessorsBegin(); successor != successors_limit; successor++)
if (successor->getTarget().dfsNum < node->dfsNum) // retreating edge.
{
ControlNode** sp = stack;
depthInfo[successor->getTarget().loopDepth++].count--;
depthInfo[successor->getTarget().loopDepth].count++;
successor->getTarget().loopId = ++loopId;
depthInfo[node->loopDepth++].count--;
depthInfo[node->loopDepth].count++;
node->loopId = loopId;
*sp++ = node; // push the first element on the stack.
while (sp != stack)
{
const DoublyLinkedList<ControlEdge>& predecessors = (*--sp)->getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator predecessor = predecessors.begin();
!predecessors.done(predecessor);
predecessor = predecessors.advance(predecessor))
{
ControlNode &prev_node = predecessors.get(predecessor).getSource();
if (prev_node.loopId != loopId)
{
depthInfo[prev_node.loopDepth].count--;
prev_node.loopDepth++;
depthInfo[prev_node.loopDepth].count++;
prev_node.loopId = loopId;
*sp++ = &prev_node;
#ifdef DEBUG
assert(sp < stackEnd);
#endif
}
}
}
}
}
// summarize
for(Uint32 d = 1; d < nNodes + 1; d++)
depthInfo[d].begin = depthInfo[d - 1].begin + depthInfo[d - 1].count;
for(Int32 j = nNodes - 1; j >= 0; j--)
{
ControlNode* node = dfsList[j];
lndList[depthInfo[node->loopDepth].begin++] = node;
node->nVisited = (float) pow(10.0, (int) node->loopDepth);
}
delete[] stack;
delete[] depthInfo;
}
#ifdef DEBUG_LOG
//
// Print a ControlGraph for debugging purposes.
//
void ControlGraph::print(LogModuleObject &f)
{
dfsSearch();
Uint32 nProducers = assignProducerNumbers(1) - 1;
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("ControlGraph %p (%d producers)\n", this, nProducers));
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("beginNode: "));
beginNode.printRef(f);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\nendNode: "));
endNode.printRef(f);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\nreturnNode: "));
if (returnNode)
returnNode->printRef(f);
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("none"));
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\nControl nodes:\n\n"));
for (Uint32 i = 0; i != nNodes; i++)
dfsList[i]->printPretty(f, 4);
bool printedHeader = false;
for (DoublyLinkedList<ControlNode>::iterator j = controlNodes.begin(); !controlNodes.done(j); j = controlNodes.advance(j)) {
ControlNode &cn = controlNodes.get(j);
if (cn.dfsNum < 0) {
if (!printedHeader) {
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Unreachable control nodes:\n\n"));
printedHeader = true;
}
cn.printPretty(f, 4);
}
}
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("End ControlGraph\n\n"));
}
#endif
// ----------------------------------------------------------------------------
// Control flow builders and utilities
//
// Return input coerced to a variable. If input is already a variable, return
// its variable. If it is a constant, allocate a PrimConst node in the given
// control node with the constant's value and return that PrimConst.
//
DataNode &makeVariable(const VariableOrConstant &input, ControlNode &cn,
Uint32 bci)
{
if (input.isConstant()) {
PrimConst &primConst = *new(cn.getPrimitivePool())
PrimConst(input.getKind(), input.getConstant(), bci);
cn.appendPrimitive(primConst);
return primConst;
} else
return input.getVariable();
}
//
// This method follows a variable's value backwards through a phi node.
//
// Edge e is one of the incoming edges of node cn. input is a variable or
// constant available in cn. If input is a constant, return it unchanged;
// if it is a variable, return the VariableOrConstant representing its value
// in e's source. The result may be different from input when node cn
// contains a phi node that outputs input.
//
// Note that the returned value is a reference and may change if input or
// one of the phi node's inputs changes.
//
const VariableOrConstant &followVariableBack(const VariableOrConstant &input, ControlNode &cn, ControlEdge &e)
{
assert(&e.getTarget() == &cn);
if (input.isVariable()) {
DataNode &inputVar = input.getVariable();
if (inputVar.hasCategory(pcPhi) && inputVar.getContainer() == &cn)
return inputVar.nthInput(cn.getPredecessors().index(e));
}
return input;
}
//
// Make a control flow merge of nPredecessors predecessor control nodes into a
// new control node. Return the new control node, which may be the incoming
// control node if nPredecessors is 1.
// The caller is responsible for creating any phi nodes in the new control node;
// joinDataFlows is a convenient way of creating such phi nodes.
//
ControlNode &joinControlFlows(uint nPredecessors, ControlNode *const*predecessors, ControlGraph &cg)
{
#ifdef DEBUG
assert(nPredecessors != 0);
// Make sure that none of the predecessors is null.
for (uint i = 0; i != nPredecessors; i++)
assert(predecessors[i]);
#endif
if (nPredecessors == 1)
return *predecessors[0];
ControlNode &cn = cg.newControlNode();
while (nPredecessors--) {
ControlNode &pred = **predecessors++;
pred.setControlBlock();
cn.addPredecessor(pred.getNormalSuccessor());
}
return cn;
}
//
// Merge a set of variables (inputs) into a single variable (output) on a
// control flow merge entering node cn. This usually generates a phi node
// with the given inputs and output inside cn, but it might just return one
// of the inputs if all of the inputs are the same.
// The inputs must be given in the same order as the predecessors were added
// to cn; the i-th input must be generated by the i-th predecessor.
//
// nPredecessors==1 is a special case to match the optimization inside joinControlFlows:
// if nPredecessors is 1, then the input is simply copied to the output and
// it is guaranteed that no phi nodes will be created in this case.
//
void joinDataFlows(uint nPredecessors, ControlNode &cn, const VariableOrConstant *inputs, VariableOrConstant &output)
{
assert(nPredecessors != 0);
if (nPredecessors != 1) {
assert(cn.getPredecessors().lengthIs(nPredecessors));
const VariableOrConstant *inputsLimit = inputs + nPredecessors;
ValueKind kind = inputs->getKind();
#ifdef DEBUG
// Assert that all inputs have the same kind.
for (const VariableOrConstant *i = inputs + 1; i != inputsLimit; i++)
assert(i->hasKind(kind));
#endif
// Are all of the inputs the same?
for (const VariableOrConstant *input = inputs + 1; input != inputsLimit; input++)
if (*input != *inputs) {
// At least one input is different. Generate a phi node.
Pool &pool = cn.getPrimitivePool();
PhiNode &phiNode = *new(pool) PhiNode(nPredecessors, kind, pool);
DoublyLinkedList<ControlEdge>::iterator pred = cn.getPredecessors().begin();
for (input = inputs; input != inputsLimit; input++) {
// asharma - fix me
phiNode.addInput(makeVariable(*input, cn.getPredecessors().get(pred).getSource(), 0), pool);
pred = cn.getPredecessors().advance(pred);
}
cn.addPhiNode(phiNode);
output.setVariable(phiNode);
return;
}
}
// All of the inputs are the same. Just return the first one.
output = inputs[0];
}
//
// cn is a control node that recently acquired an additional predecessor p via
// addPredecessor; that predecessor is now cn's last predecessor.
// consumer is a DataConsumer in cn or one of its control descendants that
// consumes a variable live at the entry to cn.
//
// This method adds or modifies the phi nodes in cn as appropriate so that:
// if control comes into cn via one of its original predecessors, consumer
// will have its original value;
// if control comes into cn from its last predecessor p, consumer will have
// the value given by newSource (which must originate in p or one of its
// control ancestors).
//
// consumer may or may not have a phi node in cn; if it does, then that phi
// node should not have an input corresponding to predecessor p; this method
// will add such an input.
//
// addDataFlow or a similar method should be called on every variable live on
// entry to an existing control node that just acquired a new predecessor.
//
void addDataFlow(ControlNode &cn, DataConsumer &consumer, const VariableOrConstant &newSource)
{
assert(newSource.hasKind(consumer.getKind()));
// If consumer is a phi node inside cn, set dn to that phi node;
// if not, set dn to nil.
DataNode *dn = 0;
if (consumer.isVariable()) {
dn = &consumer.getVariable();
if (!(dn->hasCategory(pcPhi) && dn->getContainer() == &cn))
dn = 0;
}
if (dn || consumer != newSource) {
Pool &pool = cn.getPrimitivePool();
// asharma - fix me
DataNode &newSourceVar = makeVariable(newSource, cn.getPredecessors().last().getSource(), 0);
if (dn)
// We already have a phi node in cn for this variable. Add that last input.
PhiNode::cast(*dn).addInput(newSourceVar, pool);
else {
// We don't have a phi node in cn for this variable.
// We shall create one.
Uint32 nPredecessors = cn.getPredecessors().length();
PhiNode &phiNode = *new(pool) PhiNode(nPredecessors, consumer.getKind(), pool);
DoublyLinkedList<ControlEdge>::iterator pred = cn.getPredecessors().begin();
while (--nPredecessors) {
// asharma - fix me
phiNode.addInput(makeVariable(consumer, cn.getPredecessors().get(pred).getSource(), 0), pool);
pred = cn.getPredecessors().advance(pred);
}
phiNode.addInput(newSourceVar, pool);
cn.addPhiNode(phiNode);
consumer.clear();
consumer.setVariable(phiNode);
}
}
}
//
// cn is a control node with an incoming edge e. consumer is a DataConsumer
// in cn or one of its control descendants that consumes a variable live at the
// entry to cn.
//
// This method adds or modifies the phi nodes in cn as appropriate so that:
// if control comes into cn via an edge other than e, consumer will have
// the same value it does now;
// if control comes into cn via edge e, consumer will have the value given
// by newSource.
//
// consumer may or may not have a phi node in cn; if it does, then that phi
// node should have an input corresponding to edge e.
//
void changeDataFlow(ControlNode &cn, ControlEdge &e, DataConsumer &consumer, const VariableOrConstant &newSource)
{
assert(&e.getTarget() == &cn && newSource.hasKind(consumer.getKind()));
// If consumer is a phi node inside cn, set dn to that phi node;
// if not, set dn to nil.
DataNode *dn = 0;
if (consumer.isVariable()) {
dn = &consumer.getVariable();
if (!(dn->hasCategory(pcPhi) && dn->getContainer() == &cn))
dn = 0;
}
if (dn || consumer != newSource) {
// asharma - fix me
DataNode &newSourceVar = makeVariable(newSource, e.getSource(), 0);
Uint32 eIndex = cn.getPredecessors().index(e);
if (dn) {
// We already have a phi node in cn for this variable.
DataConsumer &input = PhiNode::cast(*dn).nthInput(eIndex);
input.clear();
input = newSource;
} else {
// We don't have a phi node in cn for this variable.
// We shall create one.
Pool &pool = cn.getPrimitivePool();
Uint32 nPredecessors = cn.getPredecessors().length();
assert(eIndex < nPredecessors);
PhiNode &phiNode = *new(pool) PhiNode(nPredecessors, consumer.getKind(), pool);
DoublyLinkedList<ControlEdge>::iterator pred = cn.getPredecessors().begin();
for (Uint32 i = 0; i != nPredecessors; i++) {
// asharma - fix me
phiNode.addInput(i == eIndex ? newSourceVar : makeVariable(consumer, cn.getPredecessors().get(pred).getSource(), 0), pool);
pred = cn.getPredecessors().advance(pred);
}
cn.addPhiNode(phiNode);
consumer.clear();
consumer.setVariable(phiNode);
}
}
}
//
// Return a ControlNode appropriate for placing new DataNodes that should be
// executed immediately after all of this ControlNode's DataNodes if this
// ControlNode's execution leaves along the successor edge with the given number.
// The returned ControlNode may be a new ControlNode spliced into the control
// graph between this ControlNode and its given successor, or it may be an
// existing ControlNode -- either this one or its successor -- if that existing
// ControlNode can be legally used to hold the extra DataNodes.
//
// The edge with the given successorNumber should not be an exception or return edge.
//
ControlNode &obtainSuccessorSite(ControlNode &cn, Uint32 successorNumber)
{
assert(successorNumber < cn.nNormalSuccessors());
switch (cn.getControlKind()) {
case ckBlock:
return cn; // We can add more DataNodes to the end of this node.
case ckBegin:
case ckIf:
case ckSwitch:
case ckExc:
case ckAExc:
case ckCatch:
{
ControlEdge &successorEdge = cn.nthSuccessor(successorNumber);
ControlNode &successor = successorEdge.getTarget();
assert(hasNormalInputs(successor.getControlKind()));
if (successor.getPredecessors().lengthIs(1))
// The successor has only one input, so we can add more DataNodes to its beginning.
return successor;
else {
// Make an intermediate block node and insert it between cn and
// its designated successor.
ControlGraph &cg = cn.controlGraph;
ControlNode &intermediate = cg.newControlNode();
intermediate.setControlBlock();
intermediate.getNormalSuccessor().substituteTarget(successorEdge);
intermediate.addPredecessor(successorEdge);
return intermediate;
}
}
case ckNone:
case ckEnd:
case ckThrow:
case ckReturn:
break; // These nodes have no normal successors.
}
trespass("Bad control node");
return cn;
}
//
// Return a ControlNode appropriate for placing new DataNodes that should be
// executed immediately after all of this ControlNode's DataNodes if this
// ControlNode's execution leaves along the successor edge with the given number.
// Unlike obtainSuccessorSite, the returned ControlNode has no kind (although it may
// have existing phi nodes and primitives). The caller should set that
// ControlNode's kind and set its normal successor to successor by calling
// successor->addPredecessor(..., *where) using the where value returned from
// this method.
//
// This method disengages successor's phi nodes; the caller should reengage them
// after calling addPredecessor as above.
//
// The returned ControlNode may be a new ControlNode spliced into the control
// graph between this ControlNode and its given successor, or it may be the
// given ControlNode if it can be legally used.
//
ControlNode &insertControlNodeAfter(ControlNode &cn, ControlNode *&successor, DoublyLinkedList<ControlEdge>::iterator &where,
Uint32 successorNumber)
{
assert(successorNumber < cn.nNormalSuccessors());
ControlEdge &successorEdge = cn.nthSuccessor(successorNumber);
successor = &successorEdge.getTarget();
successor->disengagePhis();
switch (cn.getControlKind()) {
case ckBlock:
where = cn.clearControlKindOne();
return cn; // We can add more DataNodes to the end of this node.
case ckBegin:
case ckIf:
case ckSwitch:
case ckExc:
case ckAExc:
case ckCatch:
{
// Make an intermediate block node and insert it between cn and
// its designated successor.
ControlNode &intermediate = cn.controlGraph.newControlNode();
where = successorEdge.clearTarget();
intermediate.addPredecessor(successorEdge);
return intermediate;
}
case ckNone:
case ckEnd:
case ckThrow:
case ckReturn:
break; // These nodes have no normal successors.
}
trespass("Bad control node");
return cn;
}
//
// Insert a new ControlNode immediately before ControlNode cn and return the new
// ControlNode. The returned ControlNode has no kind (although it may
// have existing phi nodes, which are moved there from ControlNode cn).
// The caller should set that ControlNode's kind and optionally set its normal
// successor(s) to point to ControlNode cn. The modified cn is guaranteed to
// have no phi nodes, so the caller can call addPredecessor on cn with impunity.
//
// Any incoming control edges pointing to cn are moved to the new control node.
// It is the caller's responsibility to ensure that that new control node can
// accept these edges (i.e., if cn is an aexc node and the new control node cannot
// accept backward edges, the control graph may become inconsistent).
//
ControlNode &insertControlNodeBefore(ControlNode &cn)
{
ControlNode &newNode = cn.controlGraph.newControlNode();
DoublyLinkedList<PhiNode> &phiNodes = cn.getPhiNodes();
cn.disengagePhis();
newNode.disengagePhis();
// Move all predecessors from cn to the newNode.
const DoublyLinkedList<ControlEdge> &predecessors = cn.getPredecessors();
DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin();
while (!predecessors.done(i)) {
ControlEdge &e = predecessors.get(i);
i = predecessors.advance(i);
e.clearTarget();
newNode.addPredecessor(e);
}
// Move all phi nodes from cn to the newNode.
DoublyLinkedList<PhiNode>::iterator j = phiNodes.begin();
while (!phiNodes.done(j)) {
PhiNode &phi = phiNodes.get(j);
j = phiNodes.advance(j);
newNode.movePhiNode(phi);
}
newNode.reengagePhis();
cn.reengagePhis();
return newNode;
}
class InsertControlNodeBeforeIteratee: public Function2<bool, DataConsumer &, ControlEdge &>
{
Function1<bool, ControlEdge &> &f; // Test function passed into insertControlNodeBefore
ControlNode &newNode; // New control node being created by insertControlNodeBefore
const Uint32 nTrueEdges; // Number of true edges
VariableOrConstant uniqueInput; // If all inputs for which f is true seen so far are the same, the value of that input
Uint32 nUniqueInputs; // Number of times uniqueInput has been seen.
PhiNode *builtPhi; // Phi node being build if inputs for which f is true are not all the same
public:
InsertControlNodeBeforeIteratee(Function1<bool, ControlEdge &> &f, ControlNode &newNode, Uint32 nTrueEdges):
f(f), newNode(newNode), nTrueEdges(nTrueEdges), nUniqueInputs(0), builtPhi(0) {}
bool operator()(DataConsumer &input, ControlEdge &e);
DataNode &getInput();
};
//
// Return true if this input to the phi node should be removed.
// As a side effect keep track of the removed inputs and build a new
// phi node for the new control node that insertControlNodeBefore is creating.
//
bool InsertControlNodeBeforeIteratee::operator()(DataConsumer &input, ControlEdge &e)
{
if (!f(e))
return false;
Pool &pool = newNode.getPrimitivePool();
if (!builtPhi) {
if (nUniqueInputs == 0) {
uniqueInput = input;
nUniqueInputs = 1;
return true;
}
if (uniqueInput == input) {
nUniqueInputs++;
return true;
}
assert(nUniqueInputs > 0 && nUniqueInputs < nTrueEdges);
builtPhi = new(pool) PhiNode(nTrueEdges, input.getKind(), pool);
while (nUniqueInputs--)
builtPhi->addInput(uniqueInput.getVariable(), pool);
newNode.addPhiNode(*builtPhi);
}
builtPhi->addInput(input.getVariable(), pool);
return true;
}
//
// Return the phi node or the unique input encountered by calls to this iterator.
//
inline DataNode &InsertControlNodeBeforeIteratee::getInput()
{
if (builtPhi)
return *builtPhi;
assert(nUniqueInputs);
return uniqueInput.getVariable();
}
//
// Insert a new ControlNode immediately before some incoming edges into ControlNode cn
// and return the new ControlNode. This function calls f on each edge coming into cn
// and only relocates the edges for which f returns true. If f returns false for all
// edges coming into cn, this function does nothing and returns nil; if f returns true
// for at least one edge, this function creates and returns one new ControlNode shared
// among all the edges for which f returned true. The returned ControlNode has no kind
// (although it may have existing phi nodes if cn had phi nodes).
//
// The caller should set that ControlNode's kind and set one of its successors to
// point to ControlNode cn by calling addPredecessor once on cn. The caller should
// then call reengagePhis on cn (but not if this function returned nil). This function
// may construct phi nodes inside cn that assume that the edge from the new ControlNode
// to cn will be the last edge, so it is important to call addPredecessor once on cn to
// add that edge before making other predecessor modifications on cn.
//
// Any incoming control edges pointing to cn for which f returned true are moved to the
// new control node. It is the caller's responsibility to ensure that that new control
// node can accept these edges (i.e., if cn is an aexc node and the new control node
// cannot accept backward edges, the control graph may become inconsistent).
//
// Function f should have no side effects and the order in which it is called is not
// guaranteed.
//
ControlNode *insertControlNodeBefore(ControlNode &cn, Function1<bool, ControlEdge &> &f)
{
const DoublyLinkedList<ControlEdge> &predecessors = cn.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i))
if (f(predecessors.get(i))) {
// We have at least one edge for which f returned true.
// Disengage cn's phis and create the new control node.
ControlNode &newNode = cn.controlGraph.newControlNode();
DoublyLinkedList<PhiNode> &phiNodes = cn.getPhiNodes();
cn.disengagePhis();
newNode.disengagePhis();
// Count the edges for which f returned true.
DoublyLinkedList<ControlEdge>::iterator k = i;
Uint32 nTrueEdges = 0;
do {
if (f(predecessors.get(k)))
nTrueEdges++;
k = predecessors.advance(k);
} while (!predecessors.done(k));
// Split all phi nodes between cn and the newNode.
DoublyLinkedList<PhiNode>::iterator j = phiNodes.begin();
while (!phiNodes.done(j)) {
PhiNode &phi = phiNodes.get(j);
j = phiNodes.advance(j);
InsertControlNodeBeforeIteratee iter(f, newNode, nTrueEdges);
phi.removeSomeInputs(iter);
phi.addInput(iter.getInput(), cn.getPrimitivePool());
}
// Move the predecessors for which f returns true from cn to the newNode.
do {
ControlEdge &e = predecessors.get(i);
i = predecessors.advance(i);
if (f(e)) {
e.clearTarget();
newNode.addPredecessor(e);
}
} while (!predecessors.done(i));
newNode.reengagePhis();
return &newNode;
}
return 0;
}