зеркало из https://github.com/mozilla/gecko-dev.git
749 строки
25 KiB
C++
749 строки
25 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.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "Fundamentals.h"
|
|
#include "Pool.h"
|
|
#include "ControlNodes.h"
|
|
#include "ControlNodeScheduler.h"
|
|
#include "FastBitSet.h"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// LoopHierarchySet
|
|
|
|
//
|
|
// Create a new set of LoopHierachyNodes. Allocate the LoopHierarchyNode array of
|
|
// length nLoops and the indexes array of length nNodes in the given pool.
|
|
//
|
|
LoopHierarchySet::LoopHierarchySet(Pool& pool, LoopHierarchyNode* nodesArray, Uint32 nNodes) : nodes(nodesArray)
|
|
{
|
|
indexes = new(pool) Int32[nNodes];
|
|
nextFree = 0;
|
|
|
|
fill(indexes, &indexes[nNodes], -1);
|
|
}
|
|
|
|
//
|
|
// Return the set's element corresponding to the ControlNode dfsNum equals nodeIndex.
|
|
//
|
|
LoopHierarchyNode& LoopHierarchySet::operator [] (const Uint32 nodeIndex)
|
|
{
|
|
Int32 index = indexes[nodeIndex];
|
|
|
|
// If index is -1 then this node is not part of the set yet.
|
|
if (index == -1) {
|
|
index = nextFree++;
|
|
indexes[nodeIndex] = index;
|
|
}
|
|
|
|
return nodes[index];
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ControlNodeScheduler
|
|
|
|
//
|
|
// Return true if node is ready. We will call a node N ready if each of its
|
|
// incoming edges E: A->N are long.
|
|
//
|
|
inline bool nodeIsReady(ControlNode& node)
|
|
{
|
|
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i))
|
|
if (!predecessors.get(i).longFlag)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Return true if node is ready with respect to 'respect'. We will call a node N
|
|
// ready with respect to node P if, for each of N's incoming edges E: A->N, either
|
|
// E is long or A equals P.
|
|
//
|
|
inline bool nodeIsReadyWithRespectTo(ControlNode& node, ControlNode& respect)
|
|
{
|
|
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i)) {
|
|
ControlEdge& edge = predecessors.get(i);
|
|
if (!edge.longFlag && (&edge.getSource() != &respect))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Schedule the working nodes in loopToSchedule.
|
|
//
|
|
void ControlNodeScheduler::scheduleLoop(LoopHierarchyNode& loopToSchedule)
|
|
{
|
|
#if defined(DEBUG_SCHEDULER)
|
|
fprintf(stdout, "ControlNodeScheduler: Will schedule loop headed by N%d\n", loopToSchedule.header);
|
|
#endif
|
|
|
|
//
|
|
// Determine the nodes in a region.
|
|
//
|
|
|
|
FastBitSet& REG = loopToSchedule.nodes; // REG is the region of nodes contained in this loop.
|
|
FastBitSet Rlocal(nNodes); // Rlocal is the set of nodes in REG that are not contained in any subloop of REG.
|
|
FastBitSet Rsubheaders(nNodes); // Rsubheaders is the set of headers of immediate subloops of REG.
|
|
FastBitSet Rcombined(nNodes); // Rcombined is the union of Rlocal and Rsubheaders.
|
|
FastBitSet R(nNodes); // R is the intersection of Rcombined and the set of all working nodes.
|
|
FastBitSet RR(nNodes); // RR is the intersection of REG and the set of all working nodes.
|
|
|
|
Rlocal = REG;
|
|
DoublyLinkedList<LoopHierarchyNode>& subLoops = loopToSchedule.getSuccessors();
|
|
for (DoublyLinkedList<LoopHierarchyNode>::iterator i = subLoops.begin(); !subLoops.done(i); i = subLoops.advance(i)) {
|
|
LoopHierarchyNode& subLoop = subLoops.get(i);
|
|
Rsubheaders.set(subLoop.header);
|
|
Rlocal -= subLoop.nodes;
|
|
}
|
|
|
|
Rcombined = Rlocal;
|
|
Rcombined |= Rsubheaders;
|
|
|
|
R = Rcombined;
|
|
RR = REG;
|
|
|
|
FastBitSet nonWorkingNodes(nNodes);
|
|
for (Int32 j = REG.firstOne(); j != -1; j = REG.nextOne(j))
|
|
if (!dfsList[j]->workingNode)
|
|
nonWorkingNodes.set(j);
|
|
|
|
R -= nonWorkingNodes;
|
|
RR -= nonWorkingNodes;
|
|
|
|
//
|
|
// Initialize long edge flag for each edge E: A->B for which at least one of A or B is in R
|
|
//
|
|
|
|
Uint32 generation = ControlNode::getNextGeneration();
|
|
|
|
for (Int32 j = R.firstOne(); j != -1; j = R.nextOne(j)) {
|
|
ControlNode& node = *dfsList[j];
|
|
|
|
ControlEdge* limit = node.getSuccessorsEnd();
|
|
for (ControlEdge* edge = node.getSuccessorsBegin(); edge != limit; edge++)
|
|
if (edge->getTarget().generation != generation)
|
|
initializeLongEdgeFlag(*edge, loopToSchedule, RR, Rlocal);
|
|
|
|
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p)) {
|
|
ControlEdge& edge = predecessors.get(p);
|
|
if (edge.getSource().generation != generation)
|
|
initializeLongEdgeFlag(edge, loopToSchedule, RR, Rlocal);
|
|
}
|
|
|
|
node.generation = generation;
|
|
}
|
|
|
|
//
|
|
// Linear scheduling.
|
|
//
|
|
|
|
FastBitSet W(nNodes); // W is the set of nodes in the region remaining to be scheduled.
|
|
W = R; // Initially W contains all nodes in R except the loop header.
|
|
W.clear(loopToSchedule.header); //
|
|
|
|
Clique** cliqueStack = new(pool) Clique*[nNodes]; // Stack of Cliques waiting to be scheduled.
|
|
Clique** cliqueStackPointer = cliqueStack; // Stack pointer.
|
|
|
|
Int32 P = loopToSchedule.header; // P is the last node scheduled. It is initially the loop header.
|
|
Int32 N; // Next node to schedule.
|
|
|
|
Clique* currentClique = new(pool) Clique();
|
|
currentClique->addLast(scheduledNodes[P]); // The loop header is always the first node of the first clique.
|
|
nodesAlreadyScheduled.set(P);
|
|
|
|
loopToSchedule.cliques.addLast(*currentClique);
|
|
|
|
while (!W.empty() || (cliqueStackPointer != cliqueStack)) {
|
|
// Alternative 1.
|
|
// If there exists a node N in W such that there exists at least one short edge from P to N
|
|
// and node N is ready with respect to P, then we pick any such node N to be the next node.
|
|
ControlNode& nodeP = *dfsList[P];
|
|
|
|
ControlEdge* limit = nodeP.getSuccessorsEnd();
|
|
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++) {
|
|
ControlNode& target = edge->getTarget();
|
|
if (!edge->longFlag && nodeIsReadyWithRespectTo(target, nodeP) && W.test(target.dfsNum)) {
|
|
N = target.dfsNum;
|
|
goto foundNextNode;
|
|
}
|
|
}
|
|
|
|
// Alternative 2.
|
|
// Otherwise, if the stack isn't empty, we pop a clique Ck from the stack, make it become the next clique of
|
|
// this region, make every edge from P to any node A remaining in W into a long edge, set P to be the
|
|
// last node of Ck, and continue with alternative 1 above.
|
|
if (cliqueStackPointer != cliqueStack) {
|
|
Clique* nextClique = *--cliqueStackPointer;
|
|
loopToSchedule.cliques.addLast(*nextClique);
|
|
|
|
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++)
|
|
if (W.test(edge->getTarget().dfsNum))
|
|
edge->longFlag = true;
|
|
|
|
P = nextClique->last().dfsNum;
|
|
currentClique = nextClique;
|
|
continue;
|
|
}
|
|
|
|
// Alternative 3.
|
|
// Otherwise, there must exist a node N in W such that node N is ready with respect to P.
|
|
// We pick any such node N to be the next node.
|
|
for (N = W.firstOne(); N != -1; N = W.nextOne(N))
|
|
if (nodeIsReadyWithRespectTo(*dfsList[N], *dfsList[P]))
|
|
goto foundNextNode;
|
|
|
|
PR_ASSERT(false); // Shouldn't happen.
|
|
|
|
foundNextNode:
|
|
|
|
|
|
// After we have picked node N, we remove N from the set W and make every edge
|
|
// from P to any node A remaining in W into a long edge.
|
|
W.clear(N);
|
|
|
|
for (ControlEdge* e = nodeP.getSuccessorsBegin(); e != limit; e++)
|
|
if (W.test(e->getTarget().dfsNum))
|
|
e->longFlag = true;
|
|
|
|
// If N is not the header of a subloop.
|
|
if (!Rsubheaders.test(N)) {
|
|
ControlNode& nodeN = *dfsList[N];
|
|
bool nodePhasEdgeToNodeN = false;
|
|
|
|
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++) {
|
|
if (&edge->getTarget() == &nodeN) {
|
|
// If there exists some edge from P to N then we append node N to the current
|
|
// clique in our region's schedule
|
|
nodePhasEdgeToNodeN = true;
|
|
currentClique->addLast(scheduledNodes[N]);
|
|
nodesAlreadyScheduled.set(N);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!nodePhasEdgeToNodeN) {
|
|
// There is node edge from P to N. We start a new clique in this region
|
|
// and make N this clique's first node.
|
|
Clique* newClique = new(pool) Clique();
|
|
|
|
newClique->addLast(scheduledNodes[N]);
|
|
loopToSchedule.cliques.addLast(*newClique);
|
|
nodesAlreadyScheduled.set(N);
|
|
currentClique = newClique;
|
|
}
|
|
|
|
P = N;
|
|
} else { // N is the header of a subloop.
|
|
LoopHierarchyNode* subLoop = NULL;
|
|
|
|
// Find the clique of the subloop that contains node N.
|
|
DoublyLinkedList<LoopHierarchyNode>& subLoops = loopToSchedule.getSuccessors();
|
|
for (DoublyLinkedList<LoopHierarchyNode>::iterator i = subLoops.begin(); !subLoops.done(i); i = subLoops.advance(i)) {
|
|
subLoop = &subLoops.get(i);
|
|
if (subLoop->header == N)
|
|
break;
|
|
}
|
|
PR_ASSERT(subLoop);
|
|
|
|
Clique* subLoopClique = NULL;
|
|
for (DoublyLinkedList<Clique>::iterator c = subLoop->cliques.begin(); !subLoop->cliques.done(c); c = subLoop->cliques.advance(c)) {
|
|
bool foundClique = false;
|
|
subLoopClique = &subLoop->cliques.get(c);
|
|
|
|
for (DoublyLinkedList<ScheduledNode>::iterator n = subLoopClique->begin(); !subLoopClique->done(n); n = subLoopClique->advance(n))
|
|
if (subLoopClique->get(n).dfsNum == N) {
|
|
foundClique = true;
|
|
break;
|
|
}
|
|
|
|
if (foundClique)
|
|
break;
|
|
}
|
|
PR_ASSERT(subLoopClique);
|
|
|
|
ControlNode& nodeN = *dfsList[N];
|
|
bool nodePhasEdgeToNodeN = false;
|
|
|
|
// If N is the first node of the subloop's clique and there exists some edge from P to N then we append
|
|
// the entire clique to the current clique. Otherwise, we start a new clique and make the subloop's
|
|
// clique become this new clique's beginning.
|
|
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++)
|
|
if (&edge->getTarget() == &nodeN) {
|
|
nodePhasEdgeToNodeN = true;
|
|
break;
|
|
}
|
|
|
|
if (!((subLoopClique->first().dfsNum == N) && nodePhasEdgeToNodeN)) {
|
|
currentClique = new(pool) Clique();
|
|
loopToSchedule.cliques.addLast(*currentClique);
|
|
}
|
|
|
|
for (DoublyLinkedList<ScheduledNode>::iterator s = subLoopClique->begin(); !subLoopClique->done(s);) {
|
|
ScheduledNode& node = subLoopClique->get(s);
|
|
s = subLoopClique->advance(s);
|
|
node.remove();
|
|
currentClique->addLast(node);
|
|
}
|
|
|
|
subLoopClique->remove();
|
|
|
|
// If the subloop contained more than one clique, we push all remaining cliques onto the stack.
|
|
// We are carefull to keep the scheduling order.
|
|
for (DoublyLinkedList<Clique>::iterator t = subLoop->cliques.end(); !subLoop->cliques.done(t);) {
|
|
Clique& slc = subLoop->cliques.get(t);
|
|
t = subLoop->cliques.retreat(t);
|
|
|
|
slc.remove();
|
|
*cliqueStackPointer++ = &slc;
|
|
}
|
|
|
|
// The last node scheduled is the last node of the current clique.
|
|
P = currentClique->last().dfsNum;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Loop scheduling
|
|
//
|
|
|
|
// Find the last clique in this region such that the last node N of this clique satisfies the following properties:
|
|
// 1.There exists an edge from N to H.
|
|
// 2.There are no short edges E: N->A for which A is outside R.
|
|
// 3.N is not a switch node.
|
|
// 4.N is not H.
|
|
for (DoublyLinkedList<Clique>::iterator c = loopToSchedule.cliques.end(); !loopToSchedule.cliques.done(c); c = loopToSchedule.cliques.retreat(c)) {
|
|
Clique& clique = loopToSchedule.cliques.get(c);
|
|
ControlNode& lastNode = *dfsList[clique.last().dfsNum];
|
|
|
|
bool hasEdgeToHeader = false;
|
|
bool noShortEdgeOutsiteR = true;
|
|
|
|
ControlEdge* limit = lastNode.getSuccessorsEnd();
|
|
for (ControlEdge* edge = lastNode.getSuccessorsBegin(); edge != limit; edge++) {
|
|
if (edge->getTarget().dfsNum == loopToSchedule.header)
|
|
hasEdgeToHeader = true;
|
|
if (!edge->longFlag && R.test(edge->getTarget().dfsNum))
|
|
noShortEdgeOutsiteR = false;
|
|
}
|
|
|
|
if (hasEdgeToHeader && noShortEdgeOutsiteR && (!lastNode.hasControlKind(ckSwitch)) && (lastNode.dfsNum != loopToSchedule.header)) {
|
|
// We found this clique. We remove the last node N of this clique and prepend it to this
|
|
// subloop's first clique. Now as long as this clique ends with some node N' that satisfies
|
|
// all of the properties below, we remove N' from the end of this clique and prepend it
|
|
// to this subloop's first clique.
|
|
//
|
|
// 1.There are no short edges E: N'->A for which A is outside R.
|
|
// 2.N' is not a switch node.
|
|
// 3.N' is not the loop's header.
|
|
ScheduledNode& sNode = scheduledNodes[lastNode.dfsNum];
|
|
sNode.remove();
|
|
loopToSchedule.cliques.first().addFirst(sNode);
|
|
|
|
for (DoublyLinkedList<ScheduledNode>::iterator n = clique.end(); !clique.done(n);) {
|
|
ControlNode& node = *dfsList[clique.get(n).dfsNum];
|
|
n = clique.retreat(n);
|
|
|
|
bool noShortEdgeOutsiteR = true;
|
|
ControlEdge* limit = node.getSuccessorsEnd();
|
|
for (ControlEdge* edge = node.getSuccessorsBegin(); edge != limit; edge++)
|
|
if (!edge->longFlag && R.test(edge->getTarget().dfsNum)) {
|
|
noShortEdgeOutsiteR = false;
|
|
break;
|
|
}
|
|
if (noShortEdgeOutsiteR && (!node.hasControlKind(ckSwitch)) && (node.dfsNum != loopToSchedule.header)) {
|
|
// The condition is satisfied.
|
|
ScheduledNode& sNode = scheduledNodes[lastNode.dfsNum];
|
|
sNode.remove();
|
|
loopToSchedule.cliques.first().addFirst(sNode);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (clique.empty())
|
|
clique.remove();
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if defined(DEBUG_SCHEDULER)
|
|
fprintf(stdout, "done scheduled nodes: [ ");
|
|
for (DoublyLinkedList<Clique>::iterator x = loopToSchedule.cliques.begin(); !loopToSchedule.cliques.done(x); x = loopToSchedule.cliques.advance(x)) {
|
|
fprintf(stdout, "[ ");
|
|
Clique& clique = loopToSchedule.cliques.get(x);
|
|
for (DoublyLinkedList<ScheduledNode>::iterator z = clique.begin(); !clique.done(z); z = clique.advance(z))
|
|
fprintf(stdout, "N%d ", clique.get(z).dfsNum);
|
|
fprintf(stdout, "] ");
|
|
}
|
|
fprintf(stdout, "]\n");
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Set the long edge flag to the given edge in region.
|
|
//
|
|
void ControlNodeScheduler::initializeLongEdgeFlag(ControlEdge& edge, LoopHierarchyNode& inLoop, FastBitSet& RR, FastBitSet& Rlocal)
|
|
{
|
|
Int32 A = edge.getSource().dfsNum;
|
|
|
|
if (!RR.test(A)) { // Condition 1 - A is outside RR.
|
|
edge.longFlag = true;
|
|
return;
|
|
}
|
|
|
|
Int32 B = edge.getTarget().dfsNum;
|
|
|
|
if (A >= B) { // Condition 3 - edge is a backward edge.
|
|
edge.longFlag = true;
|
|
return;
|
|
}
|
|
|
|
if (edge.getSource().hasControlKind(ckSwitch)) { // Condition 4 - A is a switch node.
|
|
edge.longFlag = true;
|
|
return;
|
|
}
|
|
|
|
if (!Rlocal.test(A)) { // Condition 5 - A is in a subloop.
|
|
|
|
DoublyLinkedList<LoopHierarchyNode>& subLoops = inLoop.getSuccessors();
|
|
for (DoublyLinkedList<LoopHierarchyNode>::iterator l = subLoops.begin(); !subLoops.done(l); l = subLoops.advance(l)) {
|
|
|
|
LoopHierarchyNode& subLoop = subLoops.get(l);
|
|
if (subLoop.nodes.test(A)) { // subLoop is the largest inLoop's subloop that contains A.
|
|
for (DoublyLinkedList<Clique>::iterator c = subLoop.cliques.begin(); !subLoop.cliques.done(c); c = subLoop.cliques.advance(c))
|
|
if (subLoop.cliques.get(c).last().dfsNum == A) { // A is the last node of this clique.
|
|
edge.longFlag = false;
|
|
return;
|
|
}
|
|
|
|
// If we get there then A is not the last node of some cliques
|
|
edge.longFlag = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Rlocal.test(B)) { // Condition 6 - B is in a subloop.
|
|
|
|
DoublyLinkedList<LoopHierarchyNode>& subLoops = inLoop.getSuccessors();
|
|
for (DoublyLinkedList<LoopHierarchyNode>::iterator l = subLoops.begin(); !subLoops.done(l); l = subLoops.advance(l)) {
|
|
|
|
LoopHierarchyNode& subLoop = subLoops.get(l);
|
|
if (subLoop.nodes.test(B)) { // subLoop is the largest inLoop's subloop that contains B.
|
|
for (DoublyLinkedList<Clique>::iterator c = subLoop.cliques.begin(); !subLoop.cliques.done(c); c = subLoop.cliques.advance(c))
|
|
if (subLoop.cliques.get(c).last().dfsNum == B) { // B is the last node of this clique.
|
|
edge.longFlag = false;
|
|
return;
|
|
}
|
|
|
|
// If we get there then B is not the last node of some cliques
|
|
edge.longFlag = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Condition 2 - edge is any exception or return edge.
|
|
switch (edge.getSource().getControlKind()) {
|
|
case ckCatch: case ckEnd:
|
|
edge.longFlag = true;
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (edge.getTarget().getControlKind()) {
|
|
case ckCatch: case ckEnd:
|
|
edge.longFlag = true;
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
edge.longFlag = false; // Condition 7.
|
|
}
|
|
|
|
//
|
|
// Fill the dominatorsMatrix with the dominators of all the nodes in this graph.
|
|
// Each row is a bitset of the dominators' dfsNum for the ControlNode which dfsNum is the row index.
|
|
// dominatorsMatrix must have (nNodes + 1) rows & nNodes columns. (One extra row is used for
|
|
// temporary calculations).
|
|
//
|
|
void ControlNodeScheduler::findDominators()
|
|
{
|
|
// Initially each ControlNode is dominated by all the other ControlNodes.
|
|
dominatorsMatrix.set();
|
|
|
|
// The Begin Node is initialized independently as it is only dominated by itself.
|
|
dominatorsMatrix.clearRow(0);
|
|
dominatorsMatrix.set(0, 0);
|
|
|
|
bool changed; // loop condition.
|
|
|
|
do {
|
|
changed = false;
|
|
|
|
for (Uint32 n = 1; n < nNodes; n++) {
|
|
dominatorsMatrix.setRow(nNodes);
|
|
|
|
// The dominators of a ControlNode are the intersection of the dominators of its
|
|
// predecessors plus itself.
|
|
const DoublyLinkedList<ControlEdge>& predecessors = dfsList[n]->getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i))
|
|
dominatorsMatrix.andRows(predecessors.get(i).getSource().dfsNum, nNodes);
|
|
dominatorsMatrix.set(nNodes, n);
|
|
|
|
if (!dominatorsMatrix.compareRows(nNodes, n)) {
|
|
changed = true;
|
|
dominatorsMatrix.copyRows(nNodes, n);
|
|
}
|
|
}
|
|
} while(changed);
|
|
}
|
|
|
|
//
|
|
// Find the loop headers in the given array of ControlNodes & return the number
|
|
// of headers found.
|
|
//
|
|
Uint32 ControlNodeScheduler::findLoopHeaders()
|
|
{
|
|
Uint32 nLoopHeaders = 0; // Number of loop headers in this graph.
|
|
|
|
findDominators();
|
|
|
|
for (Uint32 n = 0; n < nNodes; n++) {
|
|
ControlNode& node = *dfsList[n];
|
|
Uint32 nodeIndex = node.dfsNum;
|
|
|
|
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i)) {
|
|
Uint32 predecessorIndex = predecessors.get(i).getSource().dfsNum;
|
|
|
|
// A loop header is a node with an incoming backward edge. This edge's source must be dominated
|
|
// by itself (called regular backward edge).
|
|
if ((predecessorIndex >= nodeIndex) && dominatorsMatrix.test(predecessorIndex, nodeIndex)) {
|
|
loopHeaders.set(nodeIndex);
|
|
nLoopHeaders++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!loopHeaders.test(0)) {
|
|
// The begin node is always considered to be a loop header (even if it's not).
|
|
loopHeaders.set(0);
|
|
nLoopHeaders++;
|
|
}
|
|
|
|
return nLoopHeaders;
|
|
}
|
|
|
|
//
|
|
// Build the LoopHierarchyTree, find the nodes for each loop and return the top of the tree.
|
|
//
|
|
LoopHierarchyNode& ControlNodeScheduler::buildLoopHierarchyTree()
|
|
{
|
|
Uint32* nodeStack = new(pool) Uint32[nNodes]; // Stack of nodes to look at.
|
|
|
|
Uint32 nLoopHeaders = findLoopHeaders();
|
|
|
|
LoopHierarchyNode* loopNodes = new(pool) LoopHierarchyNode[nLoopHeaders];
|
|
LoopHierarchySet loopSet(pool, loopNodes, nNodes); // Set of the loop headers in this graph.
|
|
|
|
// If the BeginNode is considered to be a loop then its body
|
|
// contains all the nodes in this graph.
|
|
LoopHierarchyNode& beginNode = loopSet[0];
|
|
beginNode.header = 0;
|
|
beginNode.nodes.sizeTo(pool, nNodes);
|
|
beginNode.nodes.set(0, nNodes - 1);
|
|
|
|
for (Int32 h = loopHeaders.nextOne(0); h != -1; h = loopHeaders.nextOne(h)) {
|
|
//
|
|
// Place this loop in the tree.
|
|
//
|
|
|
|
FastBitSet dominators(dominatorsMatrix.getRow(h), nNodes);
|
|
|
|
Int32 parent = h;
|
|
|
|
do // parent must be a loop header && this node must be included in the parent's loop nodes.
|
|
parent = dominators.previousOne(parent);
|
|
while (!(loopHeaders.test(parent) && loopSet[parent].nodes.test(h)));
|
|
|
|
loopSet[parent].addSuccessor(loopSet[h]);
|
|
|
|
//
|
|
// Find this loop's nodes.
|
|
//
|
|
|
|
Uint32* stackPointer = nodeStack;
|
|
LoopHierarchyNode& loop = loopSet[h];
|
|
|
|
// Initialize the loop header's variables.
|
|
loop.header = h;
|
|
loop.nodes.sizeToAndClear(pool, nNodes);
|
|
loop.nodes.set(h);
|
|
|
|
// Push the tails of this loop. Each tail must be dominated by the loop header.
|
|
const DoublyLinkedList<ControlEdge>& headerPredecessors = dfsList[h]->getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = headerPredecessors.begin(); !headerPredecessors.done(i); i = headerPredecessors.advance(i)) {
|
|
Uint32 predecessorIndex = headerPredecessors.get(i).getSource().dfsNum;
|
|
|
|
if ((predecessorIndex > Uint32(h)) && dominatorsMatrix.test(predecessorIndex, h)) {
|
|
loop.nodes.set(predecessorIndex);
|
|
*stackPointer++ = predecessorIndex;
|
|
}
|
|
}
|
|
|
|
while (stackPointer != nodeStack) {
|
|
Uint32 n = *--stackPointer;
|
|
|
|
const DoublyLinkedList<ControlEdge>& predecessors = dfsList[n]->getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i)) {
|
|
Uint32 predecessorIndex = predecessors.get(i).getSource().dfsNum;
|
|
if (!loop.nodes.test(predecessorIndex)) {
|
|
loop.nodes.set(predecessorIndex);
|
|
*stackPointer++ = predecessorIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return loopSet[0];
|
|
}
|
|
|
|
//
|
|
// Return an array of scheduled nodes. This array has nNodes elements.
|
|
//
|
|
ControlNode** ControlNodeScheduler::getScheduledNodes()
|
|
{
|
|
// Initialize the ScheduledNodes.
|
|
scheduledNodes = new(pool) ScheduledNode[nNodes];
|
|
for (Uint32 i = 0; i < nNodes; i++) {
|
|
ScheduledNode& node = scheduledNodes[i];
|
|
node.dfsNum = i;
|
|
}
|
|
|
|
nodesAlreadyScheduled.sizeToAndClear(nNodes);
|
|
|
|
//
|
|
// Determine main nodes (called working nodes).
|
|
//
|
|
|
|
Uint32 generation = ControlNode::getNextGeneration();
|
|
Uint32* nodeStack = new(pool) Uint32[nNodes]; // Stack of nodes to look at.
|
|
Uint32* stackPointer = nodeStack;
|
|
*stackPointer++ = 0; // Push the beginNode.
|
|
|
|
while (stackPointer != nodeStack) {
|
|
Uint32 n = *--stackPointer;
|
|
ControlNode& node = *dfsList[n];
|
|
|
|
node.workingNode = true;
|
|
|
|
ControlEdge* limit = node.getSuccessorsEnd();
|
|
for (ControlEdge* edge = node.getSuccessorsBegin(); edge != limit; edge++) {
|
|
ControlNode& successor = edge->getTarget();
|
|
|
|
if (successor.generation != generation) {
|
|
switch(successor.getControlKind()) {
|
|
case ckCatch:
|
|
case ckEnd:
|
|
// We are not following the exception edges.
|
|
break;
|
|
|
|
default:
|
|
successor.generation = generation;
|
|
*stackPointer++ = successor.dfsNum;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Schedule the loops from the inside out.
|
|
//
|
|
|
|
struct EdgeStack
|
|
{
|
|
DoublyLinkedList<LoopHierarchyNode>* linkedList;
|
|
DoublyLinkedList<LoopHierarchyNode>::iterator position;
|
|
};
|
|
|
|
LoopHierarchyNode& top = buildLoopHierarchyTree();
|
|
|
|
EdgeStack *edgeStack = new(pool) EdgeStack[nNodes];
|
|
DoublyLinkedList<LoopHierarchyNode> edgeToBeginNodeList;
|
|
edgeToBeginNodeList.addLast(top);
|
|
|
|
DoublyLinkedList<LoopHierarchyNode>* currentList = &edgeToBeginNodeList;
|
|
DoublyLinkedList<LoopHierarchyNode>::iterator currentIterator = edgeToBeginNodeList.begin();
|
|
EdgeStack *edgeStackPointer = edgeStack;
|
|
|
|
while (true) {
|
|
if (currentList->done(currentIterator)) {
|
|
if (edgeStackPointer == edgeStack)
|
|
break;
|
|
|
|
--edgeStackPointer;
|
|
currentList = edgeStackPointer->linkedList;
|
|
currentIterator = edgeStackPointer->position;
|
|
|
|
// At this point all the loops below this one in the loop hierarchy tree have
|
|
// been scheduled.
|
|
LoopHierarchyNode& loopToSchedule = currentList->get(currentIterator->prev);
|
|
|
|
scheduleLoop(loopToSchedule);
|
|
} else {
|
|
LoopHierarchyNode& loop = currentList->get(currentIterator);
|
|
currentIterator = currentList->advance(currentIterator);
|
|
|
|
edgeStackPointer->linkedList = currentList;
|
|
edgeStackPointer->position = currentIterator;
|
|
edgeStackPointer++;
|
|
|
|
currentList = &loop.getSuccessors();
|
|
currentIterator = currentList->begin();
|
|
}
|
|
}
|
|
|
|
|
|
// FIXME: need to schedule the remaining nodes (exceptions).
|
|
|
|
// Summarize the scheduling.
|
|
ControlNode** result = new(pool) ControlNode*[nNodes];
|
|
ControlNode** ptr = result;
|
|
|
|
for (DoublyLinkedList<Clique>::iterator c = top.cliques.begin(); !top.cliques.done(c); c = top.cliques.advance(c)) {
|
|
Clique& clique = top.cliques.get(c);
|
|
for (DoublyLinkedList<ScheduledNode>::iterator s = clique.begin(); !clique.done(s); s = clique.advance(s))
|
|
*ptr++ = dfsList[clique.get(s).dfsNum];
|
|
}
|
|
|
|
// Add the endNode.
|
|
*ptr++ = dfsList[nNodes - 1];
|
|
|
|
PR_ASSERT(ptr == &result[nNodes]);
|
|
|
|
return result;
|
|
}
|