From c1c6ef8f74fc550f29cfec1f2fb699dd8c2fb94e Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Fri, 8 May 2009 18:51:58 +0000 Subject: [PATCH] Factor out cycle-finder code and make it generic. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71241 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/SelectionDAGISel.h | 6 +- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 116 ++++++++++++++++++ lib/Target/X86/X86ISelDAGToDAG.cpp | 108 +--------------- 3 files changed, 120 insertions(+), 110 deletions(-) diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index 05a047563a7..d2c0dc420f8 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -88,10 +88,8 @@ public: /// U can be folded during instruction selection that starts at Root and /// folding N is profitable. virtual - bool IsLegalAndProfitableToFold(SDNode *N, SDNode *U, SDNode *Root) const { - return true; - } - + bool IsLegalAndProfitableToFold(SDNode *N, SDNode *U, SDNode *Root) const; + /// CreateTargetHazardRecognizer - Return a newly allocated hazard recognizer /// to use for this target when scheduling the DAG. virtual ScheduleHazardRecognizer *CreateTargetHazardRecognizer(); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 4c934cd1293..5f5aa7b0ab6 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1203,4 +1203,120 @@ SelectInlineAsmMemoryOperands(std::vector &Ops) { Ops.push_back(InOps.back()); } +/// findFlagUse - Return use of MVT::Flag value produced by the specified +/// SDNode. +/// +static SDNode *findFlagUse(SDNode *N) { + unsigned FlagResNo = N->getNumValues()-1; + for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) { + SDUse &Use = I.getUse(); + if (Use.getResNo() == FlagResNo) + return Use.getUser(); + } + return NULL; +} + +/// findNonImmUse - Return true if "Use" is a non-immediate use of "Def". +/// This function recursively traverses up the operand chain, ignoring +/// certain nodes. +static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse, + SDNode *Root, + SmallPtrSet &Visited) { + if (Use->getNodeId() < Def->getNodeId() || + !Visited.insert(Use)) + return false; + + for (unsigned i = 0, e = Use->getNumOperands(); i != e; ++i) { + SDNode *N = Use->getOperand(i).getNode(); + if (N == Def) { + if (Use == ImmedUse || Use == Root) + continue; // We are not looking for immediate use. + assert(N != Root); + return true; + } + + // Traverse up the operand chain. + if (findNonImmUse(N, Def, ImmedUse, Root, Visited)) + return true; + } + return false; +} + +/// isNonImmUse - Start searching from Root up the DAG to check is Def can +/// be reached. Return true if that's the case. However, ignore direct uses +/// by ImmedUse (which would be U in the example illustrated in +/// IsLegalAndProfitableToFold) and by Root (which can happen in the store +/// case). +/// FIXME: to be really generic, we should allow direct use by any node +/// that is being folded. But realisticly since we only fold loads which +/// have one non-chain use, we only need to watch out for load/op/store +/// and load/op/cmp case where the root (store / cmp) may reach the load via +/// its chain operand. +static inline bool isNonImmUse(SDNode *Root, SDNode *Def, SDNode *ImmedUse) { + SmallPtrSet Visited; + return findNonImmUse(Root, Def, ImmedUse, Root, Visited); +} + +/// IsLegalAndProfitableToFold - Returns true if the specific operand node N of +/// U can be folded during instruction selection that starts at Root and +/// folding N is profitable. +bool SelectionDAGISel::IsLegalAndProfitableToFold(SDNode *N, SDNode *U, + SDNode *Root) const { + if (OptLevel == CodeGenOpt::None) return false; + + // If Root use can somehow reach N through a path that that doesn't contain + // U then folding N would create a cycle. e.g. In the following + // diagram, Root can reach N through X. If N is folded into into Root, then + // X is both a predecessor and a successor of U. + // + // [N*] // + // ^ ^ // + // / \ // + // [U*] [X]? // + // ^ ^ // + // \ / // + // \ / // + // [Root*] // + // + // * indicates nodes to be folded together. + // + // If Root produces a flag, then it gets (even more) interesting. Since it + // will be "glued" together with its flag use in the scheduler, we need to + // check if it might reach N. + // + // [N*] // + // ^ ^ // + // / \ // + // [U*] [X]? // + // ^ ^ // + // \ \ // + // \ | // + // [Root*] | // + // ^ | // + // f | // + // | / // + // [Y] / // + // ^ / // + // f / // + // | / // + // [FU] // + // + // If FU (flag use) indirectly reaches N (the load), and Root folds N + // (call it Fold), then X is a predecessor of FU and a successor of + // Fold. But since Fold and FU are flagged together, this will create + // a cycle in the scheduling graph. + + MVT VT = Root->getValueType(Root->getNumValues()-1); + while (VT == MVT::Flag) { + SDNode *FU = findFlagUse(Root); + if (FU == NULL) + break; + Root = FU; + VT = Root->getValueType(Root->getNumValues()-1); + } + + return !isNonImmUse(Root, N, U); +} + + char SelectionDAGISel::ID = 0; diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index ceac594bdbf..f12b138abbf 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -249,60 +249,6 @@ namespace { }; } -/// findFlagUse - Return use of MVT::Flag value produced by the specified -/// SDNode. -/// -static SDNode *findFlagUse(SDNode *N) { - unsigned FlagResNo = N->getNumValues()-1; - for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) { - SDUse &Use = I.getUse(); - if (Use.getResNo() == FlagResNo) - return Use.getUser(); - } - return NULL; -} - -/// findNonImmUse - Return true if "Use" is a non-immediate use of "Def". -/// This function recursively traverses up the operand chain, ignoring -/// certain nodes. -static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse, - SDNode *Root, - SmallPtrSet &Visited) { - if (Use->getNodeId() < Def->getNodeId() || - !Visited.insert(Use)) - return false; - - for (unsigned i = 0, e = Use->getNumOperands(); i != e; ++i) { - SDNode *N = Use->getOperand(i).getNode(); - if (N == Def) { - if (Use == ImmedUse || Use == Root) - continue; // We are not looking for immediate use. - assert(N != Root); - return true; - } - - // Traverse up the operand chain. - if (findNonImmUse(N, Def, ImmedUse, Root, Visited)) - return true; - } - return false; -} - -/// isNonImmUse - Start searching from Root up the DAG to check is Def can -/// be reached. Return true if that's the case. However, ignore direct uses -/// by ImmedUse (which would be U in the example illustrated in -/// IsLegalAndProfitableToFold) and by Root (which can happen in the store -/// case). -/// FIXME: to be really generic, we should allow direct use by any node -/// that is being folded. But realisticly since we only fold loads which -/// have one non-chain use, we only need to watch out for load/op/store -/// and load/op/cmp case where the root (store / cmp) may reach the load via -/// its chain operand. -static inline bool isNonImmUse(SDNode *Root, SDNode *Def, SDNode *ImmedUse) { - SmallPtrSet Visited; - return findNonImmUse(Root, Def, ImmedUse, Root, Visited); -} - bool X86DAGToDAGISel::IsLegalAndProfitableToFold(SDNode *N, SDNode *U, SDNode *Root) const { @@ -351,58 +297,8 @@ bool X86DAGToDAGISel::IsLegalAndProfitableToFold(SDNode *N, SDNode *U, } } - // If Root use can somehow reach N through a path that that doesn't contain - // U then folding N would create a cycle. e.g. In the following - // diagram, Root can reach N through X. If N is folded into into Root, then - // X is both a predecessor and a successor of U. - // - // [N*] // - // ^ ^ // - // / \ // - // [U*] [X]? // - // ^ ^ // - // \ / // - // \ / // - // [Root*] // - // - // * indicates nodes to be folded together. - // - // If Root produces a flag, then it gets (even more) interesting. Since it - // will be "glued" together with its flag use in the scheduler, we need to - // check if it might reach N. - // - // [N*] // - // ^ ^ // - // / \ // - // [U*] [X]? // - // ^ ^ // - // \ \ // - // \ | // - // [Root*] | // - // ^ | // - // f | // - // | / // - // [Y] / // - // ^ / // - // f / // - // | / // - // [FU] // - // - // If FU (flag use) indirectly reaches N (the load), and Root folds N - // (call it Fold), then X is a predecessor of FU and a successor of - // Fold. But since Fold and FU are flagged together, this will create - // a cycle in the scheduling graph. - - MVT VT = Root->getValueType(Root->getNumValues()-1); - while (VT == MVT::Flag) { - SDNode *FU = findFlagUse(Root); - if (FU == NULL) - break; - Root = FU; - VT = Root->getValueType(Root->getNumValues()-1); - } - - return !isNonImmUse(Root, N, U); + // Proceed to 'generic' cycle finder code + return SelectionDAGISel::IsLegalAndProfitableToFold(N, U, Root); } /// MoveBelowTokenFactor - Replace TokenFactor operand with load's chain operand