2008-05-14 10:17:11 +00:00
|
|
|
//==-llvm/CodeGen/DAGISelHeader.h - Common DAG ISel definitions -*- C++ -*-==//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file provides definitions of the common, target-independent methods and
|
|
|
|
// data, which is used by SelectionDAG-based instruction selectors.
|
|
|
|
//
|
|
|
|
// *** NOTE: This file is #included into the middle of the target
|
2008-10-28 18:47:37 +00:00
|
|
|
// instruction selector class. These functions are really methods.
|
|
|
|
// This is a little awkward, but it allows this code to be shared
|
|
|
|
// by all the targets while still being able to call into
|
|
|
|
// target-specific code without using a virtual function call.
|
|
|
|
//
|
2008-05-14 10:17:11 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CODEGEN_DAGISEL_HEADER_H
|
|
|
|
#define LLVM_CODEGEN_DAGISEL_HEADER_H
|
|
|
|
|
|
|
|
/// ISelQueue - Instruction selector priority queue sorted
|
2008-09-30 18:30:35 +00:00
|
|
|
/// in the order of decreasing NodeId() values.
|
2008-05-14 10:17:11 +00:00
|
|
|
std::vector<SDNode*> ISelQueue;
|
|
|
|
|
|
|
|
/// Keep track of nodes which have already been added to queue.
|
|
|
|
unsigned char *ISelQueued;
|
|
|
|
|
|
|
|
/// Keep track of nodes which have already been selected.
|
|
|
|
unsigned char *ISelSelected;
|
|
|
|
|
|
|
|
/// IsChainCompatible - Returns true if Chain is Op or Chain does
|
|
|
|
/// not reach Op.
|
|
|
|
static bool IsChainCompatible(SDNode *Chain, SDNode *Op) {
|
|
|
|
if (Chain->getOpcode() == ISD::EntryToken)
|
|
|
|
return true;
|
|
|
|
else if (Chain->getOpcode() == ISD::TokenFactor)
|
|
|
|
return false;
|
|
|
|
else if (Chain->getNumOperands() > 0) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue C0 = Chain->getOperand(0);
|
2008-05-14 10:17:11 +00:00
|
|
|
if (C0.getValueType() == MVT::Other)
|
2008-08-28 21:40:38 +00:00
|
|
|
return C0.getNode() != Op && IsChainCompatible(C0.getNode(), Op);
|
2008-05-14 10:17:11 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isel_sort - Sorting functions for the selection queue in the
|
2008-09-30 18:30:35 +00:00
|
|
|
/// decreasing NodeId order.
|
2008-05-14 10:17:11 +00:00
|
|
|
struct isel_sort : public std::binary_function<SDNode*, SDNode*, bool> {
|
|
|
|
bool operator()(const SDNode* left, const SDNode* right) const {
|
2008-09-30 18:30:35 +00:00
|
|
|
return left->getNodeId() < right->getNodeId();
|
2008-05-14 10:17:11 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// setQueued - marks the node with a given NodeId() as element of the
|
|
|
|
/// instruction selection queue.
|
|
|
|
inline void setQueued(int Id) {
|
|
|
|
ISelQueued[Id / 8] |= 1 << (Id % 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isSelected - checks if the node with a given NodeId() is
|
|
|
|
/// in the instruction selection queue already.
|
|
|
|
inline bool isQueued(int Id) {
|
|
|
|
return ISelQueued[Id / 8] & (1 << (Id % 8));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// setSelected - marks the node with a given NodeId() as selected.
|
|
|
|
inline void setSelected(int Id) {
|
|
|
|
ISelSelected[Id / 8] |= 1 << (Id % 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isSelected - checks if the node with a given NodeId() is
|
|
|
|
/// selected already.
|
|
|
|
inline bool isSelected(int Id) {
|
|
|
|
return ISelSelected[Id / 8] & (1 << (Id % 8));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// AddToISelQueue - adds a node to the instruction
|
|
|
|
/// selection queue.
|
2008-07-27 21:46:04 +00:00
|
|
|
void AddToISelQueue(SDValue N) DISABLE_INLINE {
|
2008-08-28 21:40:38 +00:00
|
|
|
int Id = N.getNode()->getNodeId();
|
2008-05-14 10:17:11 +00:00
|
|
|
if (Id != -1 && !isQueued(Id)) {
|
2008-08-28 21:40:38 +00:00
|
|
|
ISelQueue.push_back(N.getNode());
|
2008-05-14 10:17:11 +00:00
|
|
|
std::push_heap(ISelQueue.begin(), ISelQueue.end(), isel_sort());
|
|
|
|
setQueued(Id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ISelQueueUpdater - helper class to handle updates of the
|
|
|
|
/// instruciton selection queue.
|
|
|
|
class VISIBILITY_HIDDEN ISelQueueUpdater :
|
|
|
|
public SelectionDAG::DAGUpdateListener {
|
|
|
|
std::vector<SDNode*> &ISelQueue;
|
|
|
|
bool HadDelete; // Indicate if any deletions were done.
|
|
|
|
public:
|
|
|
|
explicit ISelQueueUpdater(std::vector<SDNode*> &isq)
|
|
|
|
: ISelQueue(isq), HadDelete(false) {}
|
|
|
|
|
|
|
|
bool hadDelete() const { return HadDelete; }
|
2008-06-11 11:42:12 +00:00
|
|
|
|
2008-05-14 10:17:11 +00:00
|
|
|
/// NodeDeleted - remove node from the selection queue.
|
2008-06-11 11:42:12 +00:00
|
|
|
virtual void NodeDeleted(SDNode *N, SDNode *E) {
|
2008-05-14 10:17:11 +00:00
|
|
|
ISelQueue.erase(std::remove(ISelQueue.begin(), ISelQueue.end(), N),
|
|
|
|
ISelQueue.end());
|
|
|
|
HadDelete = true;
|
|
|
|
}
|
2008-06-11 11:42:12 +00:00
|
|
|
|
2008-05-14 10:17:11 +00:00
|
|
|
/// NodeUpdated - Ignore updates for now.
|
|
|
|
virtual void NodeUpdated(SDNode *N) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// UpdateQueue - update the instruction selction queue to maintain
|
2008-09-30 18:30:35 +00:00
|
|
|
/// the decreasing NodeId() ordering property.
|
2008-05-14 10:17:11 +00:00
|
|
|
inline void UpdateQueue(const ISelQueueUpdater &ISQU) {
|
|
|
|
if (ISQU.hadDelete())
|
|
|
|
std::make_heap(ISelQueue.begin(), ISelQueue.end(),isel_sort());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// ReplaceUses - replace all uses of the old node F with the use
|
|
|
|
/// of the new node T.
|
2008-07-27 21:46:04 +00:00
|
|
|
void ReplaceUses(SDValue F, SDValue T) DISABLE_INLINE {
|
2008-05-14 10:17:11 +00:00
|
|
|
ISelQueueUpdater ISQU(ISelQueue);
|
|
|
|
CurDAG->ReplaceAllUsesOfValueWith(F, T, &ISQU);
|
2008-08-28 21:40:38 +00:00
|
|
|
setSelected(F.getNode()->getNodeId());
|
2008-05-14 10:17:11 +00:00
|
|
|
UpdateQueue(ISQU);
|
|
|
|
}
|
|
|
|
|
2008-07-17 19:10:17 +00:00
|
|
|
/// ReplaceUses - replace all uses of the old nodes F with the use
|
|
|
|
/// of the new nodes T.
|
2008-07-27 21:46:04 +00:00
|
|
|
void ReplaceUses(const SDValue *F, const SDValue *T,
|
2008-07-17 19:10:17 +00:00
|
|
|
unsigned Num) DISABLE_INLINE {
|
|
|
|
ISelQueueUpdater ISQU(ISelQueue);
|
|
|
|
CurDAG->ReplaceAllUsesOfValuesWith(F, T, Num, &ISQU);
|
|
|
|
for (unsigned i = 0; i != Num; ++i)
|
2008-08-28 21:40:38 +00:00
|
|
|
setSelected(F[i].getNode()->getNodeId());
|
2008-07-17 19:10:17 +00:00
|
|
|
UpdateQueue(ISQU);
|
|
|
|
}
|
|
|
|
|
2008-05-14 10:17:11 +00:00
|
|
|
/// ReplaceUses - replace all uses of the old node F with the use
|
|
|
|
/// of the new node T.
|
|
|
|
void ReplaceUses(SDNode *F, SDNode *T) DISABLE_INLINE {
|
|
|
|
unsigned FNumVals = F->getNumValues();
|
|
|
|
unsigned TNumVals = T->getNumValues();
|
|
|
|
ISelQueueUpdater ISQU(ISelQueue);
|
|
|
|
if (FNumVals != TNumVals) {
|
|
|
|
for (unsigned i = 0, e = std::min(FNumVals, TNumVals); i < e; ++i)
|
2008-07-27 21:46:04 +00:00
|
|
|
CurDAG->ReplaceAllUsesOfValueWith(SDValue(F, i), SDValue(T, i), &ISQU);
|
2008-05-14 10:17:11 +00:00
|
|
|
} else {
|
|
|
|
CurDAG->ReplaceAllUsesWith(F, T, &ISQU);
|
|
|
|
}
|
|
|
|
setSelected(F->getNodeId());
|
|
|
|
UpdateQueue(ISQU);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// SelectRoot - Top level entry to DAG instruction selector.
|
|
|
|
/// Selects instructions starting at the root of the current DAG.
|
2008-10-27 21:56:29 +00:00
|
|
|
void SelectRoot(SelectionDAG &DAG) {
|
2008-05-14 10:17:11 +00:00
|
|
|
SelectRootInit();
|
|
|
|
unsigned NumBytes = (DAGSize + 7) / 8;
|
|
|
|
ISelQueued = new unsigned char[NumBytes];
|
|
|
|
ISelSelected = new unsigned char[NumBytes];
|
|
|
|
memset(ISelQueued, 0, NumBytes);
|
|
|
|
memset(ISelSelected, 0, NumBytes);
|
|
|
|
|
|
|
|
// Create a dummy node (which is not added to allnodes), that adds
|
|
|
|
// a reference to the root node, preventing it from being deleted,
|
|
|
|
// and tracking any changes of the root.
|
|
|
|
HandleSDNode Dummy(CurDAG->getRoot());
|
2008-08-28 21:40:38 +00:00
|
|
|
ISelQueue.push_back(CurDAG->getRoot().getNode());
|
2008-05-14 10:17:11 +00:00
|
|
|
|
|
|
|
// Select pending nodes from the instruction selection queue
|
|
|
|
// until no more nodes are left for selection.
|
|
|
|
while (!ISelQueue.empty()) {
|
|
|
|
SDNode *Node = ISelQueue.front();
|
|
|
|
std::pop_heap(ISelQueue.begin(), ISelQueue.end(), isel_sort());
|
|
|
|
ISelQueue.pop_back();
|
|
|
|
// Skip already selected nodes.
|
|
|
|
if (isSelected(Node->getNodeId()))
|
|
|
|
continue;
|
2008-10-31 16:12:56 +00:00
|
|
|
#if 0
|
2008-10-27 21:56:29 +00:00
|
|
|
DAG.setSubgraphColor(Node, "red");
|
2008-10-28 17:23:13 +00:00
|
|
|
#endif
|
2008-07-27 21:46:04 +00:00
|
|
|
SDNode *ResNode = Select(SDValue(Node, 0));
|
2008-05-14 10:17:11 +00:00
|
|
|
// If node should not be replaced,
|
|
|
|
// continue with the next one.
|
|
|
|
if (ResNode == Node)
|
|
|
|
continue;
|
|
|
|
// Replace node.
|
2008-10-27 21:56:29 +00:00
|
|
|
if (ResNode) {
|
2008-10-31 16:12:56 +00:00
|
|
|
#if 0
|
2008-10-27 21:56:29 +00:00
|
|
|
DAG.setSubgraphColor(ResNode, "yellow");
|
|
|
|
DAG.setSubgraphColor(ResNode, "black");
|
2008-10-28 17:23:13 +00:00
|
|
|
#endif
|
2008-05-14 10:17:11 +00:00
|
|
|
ReplaceUses(Node, ResNode);
|
2008-10-27 21:56:29 +00:00
|
|
|
}
|
2008-05-14 10:17:11 +00:00
|
|
|
// If after the replacement this node is not used any more,
|
|
|
|
// remove this dead node.
|
|
|
|
if (Node->use_empty()) { // Don't delete EntryToken, etc.
|
2008-07-17 18:41:20 +00:00
|
|
|
ISelQueueUpdater ISQU(ISelQueue);
|
|
|
|
CurDAG->RemoveDeadNode(Node, &ISQU);
|
|
|
|
UpdateQueue(ISQU);
|
2008-05-14 10:17:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] ISelQueued;
|
|
|
|
ISelQueued = NULL;
|
|
|
|
delete[] ISelSelected;
|
|
|
|
ISelSelected = NULL;
|
2008-08-21 16:36:34 +00:00
|
|
|
CurDAG->setRoot(Dummy.getValue());
|
2008-05-14 10:17:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* LLVM_CODEGEN_DAGISEL_HEADER_H */
|