blob: 3542ebcbd025dad8b9b53708ae48020b8d20241d [file] [log] [blame]
//==-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
// *** instruction selector class. These functions are really methods.
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_DAGISEL_HEADER_H
#define LLVM_CODEGEN_DAGISEL_HEADER_H
/// ISelQueue - Instruction selector priority queue sorted
/// in the order of decreasing NodeId() values.
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) {
SDValue C0 = Chain->getOperand(0);
if (C0.getValueType() == MVT::Other)
return C0.getNode() != Op && IsChainCompatible(C0.getNode(), Op);
}
return true;
}
/// isel_sort - Sorting functions for the selection queue in the
/// decreasing NodeId order.
struct isel_sort : public std::binary_function<SDNode*, SDNode*, bool> {
bool operator()(const SDNode* left, const SDNode* right) const {
return left->getNodeId() < right->getNodeId();
}
};
/// 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.
void AddToISelQueue(SDValue N) DISABLE_INLINE {
int Id = N.getNode()->getNodeId();
if (Id != -1 && !isQueued(Id)) {
ISelQueue.push_back(N.getNode());
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; }
/// NodeDeleted - remove node from the selection queue.
virtual void NodeDeleted(SDNode *N, SDNode *E) {
ISelQueue.erase(std::remove(ISelQueue.begin(), ISelQueue.end(), N),
ISelQueue.end());
HadDelete = true;
}
/// NodeUpdated - Ignore updates for now.
virtual void NodeUpdated(SDNode *N) {}
};
/// UpdateQueue - update the instruction selction queue to maintain
/// the decreasing NodeId() ordering property.
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.
void ReplaceUses(SDValue F, SDValue T) DISABLE_INLINE {
ISelQueueUpdater ISQU(ISelQueue);
CurDAG->ReplaceAllUsesOfValueWith(F, T, &ISQU);
setSelected(F.getNode()->getNodeId());
UpdateQueue(ISQU);
}
/// ReplaceUses - replace all uses of the old nodes F with the use
/// of the new nodes T.
void ReplaceUses(const SDValue *F, const SDValue *T,
unsigned Num) DISABLE_INLINE {
ISelQueueUpdater ISQU(ISelQueue);
CurDAG->ReplaceAllUsesOfValuesWith(F, T, Num, &ISQU);
for (unsigned i = 0; i != Num; ++i)
setSelected(F[i].getNode()->getNodeId());
UpdateQueue(ISQU);
}
/// 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)
CurDAG->ReplaceAllUsesOfValueWith(SDValue(F, i), SDValue(T, i), &ISQU);
} 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.
void SelectRoot() {
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());
ISelQueue.push_back(CurDAG->getRoot().getNode());
// 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;
SDNode *ResNode = Select(SDValue(Node, 0));
// If node should not be replaced,
// continue with the next one.
if (ResNode == Node)
continue;
// Replace node.
if (ResNode)
ReplaceUses(Node, ResNode);
// If after the replacement this node is not used any more,
// remove this dead node.
if (Node->use_empty()) { // Don't delete EntryToken, etc.
ISelQueueUpdater ISQU(ISelQueue);
CurDAG->RemoveDeadNode(Node, &ISQU);
UpdateQueue(ISQU);
}
}
delete[] ISelQueued;
ISelQueued = NULL;
delete[] ISelSelected;
ISelSelected = NULL;
CurDAG->setRoot(Dummy.getValue());
}
#endif /* LLVM_CODEGEN_DAGISEL_HEADER_H */