Optimize SelectionDAG's AssignTopologicalOrder even further.

Completely eliminate the TopOrder std::vector. Instead, sort
the AllNodes list in place. This also eliminates the need to
call AllNodes.size(), a linear-time operation, before
performing the sort.

Also, eliminate the Sources temporary std::vector, since it
essentially duplicates the sorted result as it is being
built.

This also changes the direction of the topological sort
from bottom-up to top-down. The AllNodes list starts out in
roughly top-down order, so this reduces the amount of
reordering needed. Top-down is also more convenient for
Legalize, and ISel needed only minor adjustments.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@56867 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman 2008-09-30 18:30:35 +00:00
parent 21420dfae1
commit f06c835f76
6 changed files with 78 additions and 44 deletions

View File

@ -18,7 +18,7 @@
#define LLVM_CODEGEN_DAGISEL_HEADER_H #define LLVM_CODEGEN_DAGISEL_HEADER_H
/// ISelQueue - Instruction selector priority queue sorted /// ISelQueue - Instruction selector priority queue sorted
/// in the order of increasing NodeId() values. /// in the order of decreasing NodeId() values.
std::vector<SDNode*> ISelQueue; std::vector<SDNode*> ISelQueue;
/// Keep track of nodes which have already been added to queue. /// Keep track of nodes which have already been added to queue.
@ -43,10 +43,10 @@ static bool IsChainCompatible(SDNode *Chain, SDNode *Op) {
} }
/// isel_sort - Sorting functions for the selection queue in the /// isel_sort - Sorting functions for the selection queue in the
/// increasing NodeId order. /// decreasing NodeId order.
struct isel_sort : public std::binary_function<SDNode*, SDNode*, bool> { struct isel_sort : public std::binary_function<SDNode*, SDNode*, bool> {
bool operator()(const SDNode* left, const SDNode* right) const { bool operator()(const SDNode* left, const SDNode* right) const {
return (left->getNodeId() > right->getNodeId()); return left->getNodeId() < right->getNodeId();
} }
}; };
@ -108,7 +108,7 @@ class VISIBILITY_HIDDEN ISelQueueUpdater :
}; };
/// UpdateQueue - update the instruction selction queue to maintain /// UpdateQueue - update the instruction selction queue to maintain
/// the increasing NodeId() ordering property. /// the decreasing NodeId() ordering property.
inline void UpdateQueue(const ISelQueueUpdater &ISQU) { inline void UpdateQueue(const ISelQueueUpdater &ISQU) {
if (ISQU.hadDelete()) if (ISQU.hadDelete())
std::make_heap(ISelQueue.begin(), ISelQueue.end(),isel_sort()); std::make_heap(ISelQueue.begin(), ISelQueue.end(),isel_sort());

View File

@ -663,10 +663,10 @@ public:
unsigned Num, unsigned Num,
DAGUpdateListener *UpdateListener = 0); DAGUpdateListener *UpdateListener = 0);
/// AssignTopologicalOrder - Assign a unique node id for each node in the DAG /// AssignTopologicalOrder - Topological-sort the AllNodes list and a
/// based on their topological order. It returns the maximum id and a vector /// assign a unique node id for each node in the DAG based on their
/// of the SDNodes* in assigned order by reference. /// topological order. Returns the number of nodes.
unsigned AssignTopologicalOrder(std::vector<SDNode*> &TopOrder); unsigned AssignTopologicalOrder();
/// isCommutativeBinOp - Returns true if the opcode is a commutative binary /// isCommutativeBinOp - Returns true if the opcode is a commutative binary
/// operation. /// operation.

View File

@ -48,7 +48,6 @@ public:
AliasAnalysis *AA; AliasAnalysis *AA;
GCFunctionInfo *GFI; GCFunctionInfo *GFI;
bool Fast; bool Fast;
std::vector<SDNode*> TopOrder;
static char ID; static char ID;
explicit SelectionDAGISel(TargetLowering &tli, bool fast = false); explicit SelectionDAGISel(TargetLowering &tli, bool fast = false);
@ -67,7 +66,7 @@ public:
virtual void InstructionSelectPostProcessing() {} virtual void InstructionSelectPostProcessing() {}
void SelectRootInit() { void SelectRootInit() {
DAGSize = CurDAG->AssignTopologicalOrder(TopOrder); DAGSize = CurDAG->AssignTopologicalOrder();
} }
/// SelectInlineAsmMemoryOperand - Select the specified address as a target /// SelectInlineAsmMemoryOperand - Select the specified address as a target

View File

@ -280,11 +280,10 @@ void SelectionDAGLegalize::LegalizeDAG() {
// practice however, this causes us to run out of stack space on large basic // practice however, this causes us to run out of stack space on large basic
// blocks. To avoid this problem, compute an ordering of the nodes where each // blocks. To avoid this problem, compute an ordering of the nodes where each
// node is only legalized after all of its operands are legalized. // node is only legalized after all of its operands are legalized.
std::vector<SDNode *> TopOrder; DAG.AssignTopologicalOrder();
unsigned N = DAG.AssignTopologicalOrder(TopOrder); for (SelectionDAG::allnodes_iterator I = DAG.allnodes_begin(),
for (unsigned i = N; i != 0; --i) E = prior(DAG.allnodes_end()); I != next(E); ++I)
HandleOp(SDValue(TopOrder[i-1], 0)); HandleOp(SDValue(I, 0));
TopOrder.clear();
// Finally, it's possible the root changed. Get the new root. // Finally, it's possible the root changed. Get the new root.
SDValue OldRoot = DAG.getRoot(); SDValue OldRoot = DAG.getRoot();

View File

@ -587,7 +587,7 @@ void SelectionDAG::DeleteNode(SDNode *N) {
void SelectionDAG::DeleteNodeNotInCSEMaps(SDNode *N) { void SelectionDAG::DeleteNodeNotInCSEMaps(SDNode *N) {
// Drop all of the operands and decrement used nodes use counts. // Drop all of the operands and decrement used node's use counts.
for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I) for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I)
I->getVal()->removeUser(std::distance(N->op_begin(), I), N); I->getVal()->removeUser(std::distance(N->op_begin(), I), N);
if (N->OperandsNeedDelete) if (N->OperandsNeedDelete)
@ -4569,38 +4569,74 @@ void SelectionDAG::ReplaceAllUsesOfValuesWith(const SDValue *From,
/// AssignTopologicalOrder - Assign a unique node id for each node in the DAG /// AssignTopologicalOrder - Assign a unique node id for each node in the DAG
/// based on their topological order. It returns the maximum id and a vector /// based on their topological order. It returns the maximum id and a vector
/// of the SDNodes* in assigned order by reference. /// of the SDNodes* in assigned order by reference.
unsigned SelectionDAG::AssignTopologicalOrder(std::vector<SDNode*> &TopOrder) { unsigned SelectionDAG::AssignTopologicalOrder() {
unsigned DAGSize = AllNodes.size();
std::vector<SDNode*> Sources;
for (allnodes_iterator I = allnodes_begin(),E = allnodes_end(); I != E; ++I){ unsigned DAGSize = 0;
SDNode *N = I;
unsigned Degree = N->use_size();
// Temporarily use the Node Id as scratch space for the degree count.
N->setNodeId(Degree);
if (Degree == 0)
Sources.push_back(N);
}
TopOrder.clear(); // SortedPos tracks the progress of the algorithm. Nodes before it are
TopOrder.reserve(DAGSize); // sorted, nodes after it are unsorted. When the algorithm completes
int Id = 0; // it is at the end of the list.
while (!Sources.empty()) { allnodes_iterator SortedPos = allnodes_begin();
SDNode *N = Sources.back();
Sources.pop_back(); // Visit all the nodes. Add nodes with no operands to the TopOrder result
TopOrder.push_back(N); // array immediately. Annotate nodes that do have operands with their
N->setNodeId(Id++); // operand count. Before we do this, the Node Id fields of the nodes
for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I) { // may contain arbitrary values. After, the Node Id fields for nodes
SDNode *P = I->getVal(); // before SortedPos will contain the topological sort index, and the
unsigned Degree = P->getNodeId(); // Node Id fields for nodes At SortedPos and after will contain the
--Degree; // count of outstanding operands.
P->setNodeId(Degree); for (allnodes_iterator I = allnodes_begin(),E = allnodes_end(); I != E; ) {
if (Degree == 0) SDNode *N = I++;
Sources.push_back(P); unsigned Degree = N->getNumOperands();
if (Degree == 0) {
// A node with no uses, add it to the result array immediately.
N->setNodeId(DAGSize++);
allnodes_iterator Q = N;
if (Q != SortedPos)
SortedPos = AllNodes.insert(SortedPos, AllNodes.remove(Q));
++SortedPos;
} else {
// Temporarily use the Node Id as scratch space for the degree count.
N->setNodeId(Degree);
} }
} }
return Id; // Visit all the nodes. As we iterate, moves nodes into sorted order,
// such that by the time the end is reached all nodes will be sorted.
for (allnodes_iterator I = allnodes_begin(),E = allnodes_end(); I != E; ++I) {
SDNode *N = I;
for (SDNode::use_iterator UI = N->use_begin(), UE = N->use_end();
UI != UE; ++UI) {
SDNode *P = *UI;
unsigned Degree = P->getNodeId();
--Degree;
if (Degree == 0) {
// All of P's operands are sorted, so P may sorted now.
P->setNodeId(DAGSize++);
if (P != SortedPos)
SortedPos = AllNodes.insert(SortedPos, AllNodes.remove(P));
++SortedPos;
} else {
// Update P's outstanding operand count.
P->setNodeId(Degree);
}
}
}
assert(SortedPos == AllNodes.end() &&
"Topological sort incomplete!");
assert(AllNodes.front().getOpcode() == ISD::EntryToken &&
"First node in topological sort is not the entry token!");
assert(AllNodes.front().getNodeId() == 0 &&
"First node in topological sort has non-zero id!");
assert(AllNodes.front().getNumOperands() == 0 &&
"First node in topological sort has operands!");
assert(AllNodes.back().getNodeId() == (int)DAGSize-1 &&
"Last node in topologic sort has unexpected id!");
assert(AllNodes.back().use_empty() &&
"Last node in topologic sort has users!");
assert(DAGSize == allnodes_size() && "TopOrder result count mismatch!");
return DAGSize;
} }

View File

@ -269,7 +269,7 @@ static void findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
SDNode *Root, bool &found, SDNode *Root, bool &found,
SmallPtrSet<SDNode*, 16> &Visited) { SmallPtrSet<SDNode*, 16> &Visited) {
if (found || if (found ||
Use->getNodeId() > Def->getNodeId() || Use->getNodeId() < Def->getNodeId() ||
!Visited.insert(Use)) !Visited.insert(Use))
return; return;