[PATCH] D33775: [SelectionDAG] Get rid of recursion in findNonImmUse

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 1 15:11:54 PDT 2017


Max Kazantsev via Phabricator <reviews at reviews.llvm.org> writes:
> mkazantsev created this revision.
>
> The recursive implementation of findNonImmUse may overflow stack
> on extremely long use chains. This patch replaces it with an equivalent
> iterative implementation.

LGTM.

> https://reviews.llvm.org/D33775
>
> Files:
>   lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
>
> Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
> ===================================================================
> --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
> +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
> @@ -2022,7 +2022,7 @@
>  }
>  
>  /// findNonImmUse - Return true if "Use" is a non-immediate use of "Def".
> -/// This function recursively traverses up the operand chain, ignoring
> +/// This function iteratively traverses up the operand chain, ignoring
>  /// certain nodes.
>  static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
>                            SDNode *Root, SmallPtrSetImpl<SDNode*> &Visited,
> @@ -2035,30 +2035,36 @@
>    // The Use may be -1 (unassigned) if it is a newly allocated node.  This can
>    // happen because we scan down to newly selected nodes in the case of glue
>    // uses.
> -  if ((Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1))
> -    return false;
> +  std::vector<SDNode *> WorkList;
> +  WorkList.push_back(Use);
>  
> -  // Don't revisit nodes if we already scanned it and didn't fail, we know we
> -  // won't fail if we scan it again.
> -  if (!Visited.insert(Use).second)
> -    return false;
> +  while (!WorkList.empty()) {
> +    Use = WorkList.back();
> +    WorkList.pop_back();
> +    if (Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1)
> +      continue;
>  
> -  for (const SDValue &Op : Use->op_values()) {
> -    // Ignore chain uses, they are validated by HandleMergeInputChains.
> -    if (Op.getValueType() == MVT::Other && IgnoreChains)
> +    // Don't revisit nodes if we already scanned it and didn't fail, we know we
> +    // won't fail if we scan it again.
> +    if (!Visited.insert(Use).second)
>        continue;
>  
> -    SDNode *N = Op.getNode();
> -    if (N == Def) {
> -      if (Use == ImmedUse || Use == Root)
> -        continue;  // We are not looking for immediate use.
> -      assert(N != Root);
> -      return true;
> -    }
> +    for (const SDValue &Op : Use->op_values()) {
> +      // Ignore chain uses, they are validated by HandleMergeInputChains.
> +      if (Op.getValueType() == MVT::Other && IgnoreChains)
> +        continue;
>  
> -    // Traverse up the operand chain.
> -    if (findNonImmUse(N, Def, ImmedUse, Root, Visited, IgnoreChains))
> -      return true;
> +      SDNode *N = Op.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.
> +      WorkList.push_back(N);
> +    }
>    }
>    return false;
>  }
>
>
> Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
> ===================================================================
> --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
> +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
> @@ -2022,7 +2022,7 @@
>  }
>  
>  /// findNonImmUse - Return true if "Use" is a non-immediate use of "Def".
> -/// This function recursively traverses up the operand chain, ignoring
> +/// This function iteratively traverses up the operand chain, ignoring
>  /// certain nodes.
>  static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
>                            SDNode *Root, SmallPtrSetImpl<SDNode*> &Visited,
> @@ -2035,30 +2035,36 @@
>    // The Use may be -1 (unassigned) if it is a newly allocated node.  This can
>    // happen because we scan down to newly selected nodes in the case of glue
>    // uses.
> -  if ((Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1))
> -    return false;
> +  std::vector<SDNode *> WorkList;
> +  WorkList.push_back(Use);
>  
> -  // Don't revisit nodes if we already scanned it and didn't fail, we know we
> -  // won't fail if we scan it again.
> -  if (!Visited.insert(Use).second)
> -    return false;
> +  while (!WorkList.empty()) {
> +    Use = WorkList.back();
> +    WorkList.pop_back();
> +    if (Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1)
> +      continue;
>  
> -  for (const SDValue &Op : Use->op_values()) {
> -    // Ignore chain uses, they are validated by HandleMergeInputChains.
> -    if (Op.getValueType() == MVT::Other && IgnoreChains)
> +    // Don't revisit nodes if we already scanned it and didn't fail, we know we
> +    // won't fail if we scan it again.
> +    if (!Visited.insert(Use).second)
>        continue;
>  
> -    SDNode *N = Op.getNode();
> -    if (N == Def) {
> -      if (Use == ImmedUse || Use == Root)
> -        continue;  // We are not looking for immediate use.
> -      assert(N != Root);
> -      return true;
> -    }
> +    for (const SDValue &Op : Use->op_values()) {
> +      // Ignore chain uses, they are validated by HandleMergeInputChains.
> +      if (Op.getValueType() == MVT::Other && IgnoreChains)
> +        continue;
>  
> -    // Traverse up the operand chain.
> -    if (findNonImmUse(N, Def, ImmedUse, Root, Visited, IgnoreChains))
> -      return true;
> +      SDNode *N = Op.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.
> +      WorkList.push_back(N);
> +    }
>    }
>    return false;
>  }


More information about the llvm-commits mailing list