diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index 1d88f1ff6ff3..0bf036c227d3 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -34,6 +34,7 @@ #include "llvm/Support/Visibility.h" #include "llvm/ADT/Statistic.h" #include +#include #include using namespace llvm; @@ -92,12 +93,13 @@ namespace { const X86Subtarget *Subtarget; unsigned GlobalBaseReg; + public: X86DAGToDAGISel(X86TargetMachine &TM) : SelectionDAGISel(X86Lowering), - X86Lowering(*TM.getTargetLowering()) { - Subtarget = &TM.getSubtarget(); - } + X86Lowering(*TM.getTargetLowering()), + Subtarget(&TM.getSubtarget()), + DAGSize(0), ReachibilityMatrix(NULL) {} virtual bool runOnFunction(Function &Fn) { // Make sure we re-emit a set of the global base reg if necessary @@ -115,10 +117,15 @@ namespace { virtual void EmitFunctionEntryCode(Function &Fn, MachineFunction &MF); + virtual bool IsFoldableBy(SDNode *N, SDNode *U); + // Include the pieces autogenerated from the target description. #include "X86GenDAGISel.inc" private: + void DetermineTopologicalOrdering(); + void DeterminReachibility(); + void Select(SDOperand &Result, SDOperand N); bool MatchAddress(SDOperand N, X86ISelAddressMode &AM, bool isRoot = true); @@ -173,12 +180,116 @@ namespace { /// base register. Return the virtual register that holds this value. SDOperand getGlobalBaseReg(); + /// DAGSize - Number of nodes in the DAG. + /// + unsigned DAGSize; + + /// TopOrder - Topological ordering of all nodes in the DAG. + /// + std::vector TopOrder; + + /// ReachibilityMatrix - A N x N matrix representing all pairs reachibility + /// information. One bit per potential edge. + unsigned char *ReachibilityMatrix; + + inline void setReachable(SDNode *f, SDNode *t) { + unsigned Idx = f->getNodeId() * DAGSize + t->getNodeId(); + ReachibilityMatrix[Idx / 8] |= 1 << (Idx % 8); + } + + inline bool isReachable(SDNode *f, SDNode *t) { + unsigned Idx = f->getNodeId() * DAGSize + t->getNodeId(); + return ReachibilityMatrix[Idx / 8] & (1 << (Idx % 8)); + } + #ifndef NDEBUG unsigned Indent; #endif }; } +bool X86DAGToDAGISel::IsFoldableBy(SDNode *N, SDNode *U) { + // If U use can somehow reach N through another path then U can't fold N or + // it will create a cycle. e.g. In the following diagram, U can reach N + // through X. If N is foled into into U, then X is both a predecessor and + // a successor of U. + // + // [ N ] + // ^ ^ + // | | + // / \--- + // / [X] + // | ^ + // [U]--------| + if (!ReachibilityMatrix) + DeterminReachibility(); + assert(isReachable(U, N) && "Attempting to fold a non-operand node?"); + for (SDNode::op_iterator I = U->op_begin(), E = U->op_end(); I != E; ++I) { + SDNode *P = I->Val; + if (P != N && isReachable(P, N)) + return false; + } + return true; +} + +/// DetermineTopologicalOrdering - Determine topological ordering of the nodes +/// in the DAG. +void X86DAGToDAGISel::DetermineTopologicalOrdering() { + DAGSize = CurDAG->AssignNodeIds(); + TopOrder.reserve(DAGSize); + + std::vector InDegree(DAGSize); + std::list Sources; + for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), + E = CurDAG->allnodes_end(); I != E; ++I) { + SDNode *N = I; + unsigned Degree = N->use_size(); + InDegree[N->getNodeId()] = Degree; + if (Degree == 0) + Sources.push_back(I); + } + + unsigned Order = 0; + while (!Sources.empty()) { + SDNode *N = Sources.front(); + Sources.pop_front(); + TopOrder[Order] = N; + Order++; + for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I) { + SDNode *P = I->Val; + int PId = P->getNodeId(); + unsigned Degree = InDegree[PId] - 1; + if (Degree == 0) + Sources.push_back(P); + InDegree[PId] = Degree; + } + } +} + +void X86DAGToDAGISel::DeterminReachibility() { + DetermineTopologicalOrdering(); + ReachibilityMatrix = new unsigned char[DAGSize * DAGSize]; + memset(ReachibilityMatrix, 0, DAGSize * DAGSize * sizeof(unsigned char)); + + for (unsigned i = 0; i < DAGSize; ++i) { + SDNode *N = TopOrder[i]; + setReachable(N, N); + // If N is a leaf node, there is nothing more to do. + if (N->getNumOperands() == 0) + continue; + + for (unsigned i2 = 0; ; ++i2) { + SDNode *M = TopOrder[i2]; + if (isReachable(M, N)) { + // Update reachibility from M to N's operands. + for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E;++I) + setReachable(M, I->Val); + } + if (M == N) break; + } + } +} + /// InstructionSelectBasicBlock - This callback is invoked by SelectionDAGISel /// when it has created a SelectionDAG for us to codegen. void X86DAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) { @@ -195,6 +306,10 @@ void X86DAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) { #ifndef NDEBUG DEBUG(std::cerr << "===== Instruction selection ends:\n"); #endif + if (ReachibilityMatrix) { + delete[] ReachibilityMatrix; + ReachibilityMatrix = NULL; + } CodeGenMap.clear(); HandleMap.clear(); ReplaceMap.clear();