I found that the strlen pass ignores stores via references.
This shows up with C++ code more than C.
A simple:
```
int g(void)
{
  std::string a="a";
  return __builtin_strlen(a.c_str());
}
```
Should be optimized to just `return 1` but does not
currently due to use of references.
The problem in the code is direct comparison with POINTER_TYPE instead
of using POINTER_TYPE_P.
This fixes the cases I found all related to strings passes. All of them
were added by Martin Sebor which makes me think this was an oversight on his
part.

Bootstrapped and tested on x86_64-linux-gnu.

        PR tree-optimization/122754
gcc/ChangeLog:

        * gimple-fold.cc (get_range_strlen_tree): Use POINTER_TYPE_P instead
        of direct comparing to POINTER_TYPE.
        * gimple-ssa-sprintf.cc (format_integer): Likewise.
        * gimple-ssa-warn-access.cc (maybe_warn_nonstring_arg): Likewise.
        * gimple-ssa-warn-restrict.cc (pass_wrestrict::check_call): Likewise.
        * tree-ssa-strlen.cc (maybe_set_strlen_range): Likewise.
        (is_strlen_related_p): Likewise.
        (strlen_pass::handle_assign): Likewise.

gcc/testsuite/ChangeLog:

        * g++.dg/tree-ssa/string-strlen-1.C: New test.

Signed-off-by: Andrew Pinski <[email protected]>
---
 gcc/gimple-fold.cc                            |  2 +-
 gcc/gimple-ssa-sprintf.cc                     |  6 +++---
 gcc/gimple-ssa-warn-access.cc                 |  2 +-
 gcc/gimple-ssa-warn-restrict.cc               |  4 ++--
 .../g++.dg/tree-ssa/string-strlen-1.C         | 20 +++++++++++++++++++
 gcc/tree-ssa-strlen.cc                        |  8 ++++----
 6 files changed, 31 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 8f72dbb929b..3fc76313622 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -1806,7 +1806,7 @@ get_range_strlen_tree (tree arg, bitmap visited, 
strlen_range_kind rkind,
             the size of the enclosing object minus the offset of
             the referenced subobject minus 1 (for the terminating nul).  */
          tree type = TREE_TYPE (base);
-         if (TREE_CODE (type) == POINTER_TYPE
+         if (POINTER_TYPE_P (type)
              || (TREE_CODE (base) != PARM_DECL && !VAR_P (base))
              || !(val = DECL_SIZE_UNIT (base)))
            val = build_all_ones_cst (size_type_node);
diff --git a/gcc/gimple-ssa-sprintf.cc b/gcc/gimple-ssa-sprintf.cc
index bcec5405242..3c2a742f512 100644
--- a/gcc/gimple-ssa-sprintf.cc
+++ b/gcc/gimple-ssa-sprintf.cc
@@ -1372,7 +1372,7 @@ format_integer (const directive &dir, tree arg, 
pointer_query &ptr_qry)
       return res;
     }
   else if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
-          || TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE)
+          || POINTER_TYPE_P (TREE_TYPE (arg)))
     /* Determine the type of the provided non-constant argument.  */
     argtype = TREE_TYPE (arg);
   else
@@ -1434,7 +1434,7 @@ format_integer (const directive &dir, tree arg, 
pointer_query &ptr_qry)
                {
                  tree type = TREE_TYPE (gimple_assign_rhs1 (def));
                  if (INTEGRAL_TYPE_P (type)
-                     || TREE_CODE (type) == POINTER_TYPE)
+                     || POINTER_TYPE_P (type))
                    argtype = type;
                }
            }
@@ -1443,7 +1443,7 @@ format_integer (const directive &dir, tree arg, 
pointer_query &ptr_qry)
 
   if (!argmin)
     {
-      if (TREE_CODE (argtype) == POINTER_TYPE)
+      if (POINTER_TYPE_P (argtype))
        {
          argmin = build_int_cst (pointer_sized_int_node, 0);
          argmax = build_all_ones_cst (pointer_sized_int_node);
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index abfb8685ce7..d12f797f36b 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -554,7 +554,7 @@ maybe_warn_nonstring_arg (tree fndecl, GimpleOrTree exp)
       if (!argtype)
        break;
 
-      if (TREE_CODE (argtype) != POINTER_TYPE)
+      if (!POINTER_TYPE_P (argtype))
        continue;
 
       argtype = TREE_TYPE (argtype);
diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc
index e48fe1eb841..0b383cced44 100644
--- a/gcc/gimple-ssa-warn-restrict.cc
+++ b/gcc/gimple-ssa-warn-restrict.cc
@@ -1998,8 +1998,8 @@ pass_wrestrict::check_call (gimple *call)
   /* DST, SRC, or DSTWR can also have the wrong type in a call to
      a function declared without a prototype.  Avoid checking such
      invalid calls.  */
-  if (TREE_CODE (TREE_TYPE (dst)) != POINTER_TYPE
-      || (src && TREE_CODE (TREE_TYPE (src)) != POINTER_TYPE)
+  if (!POINTER_TYPE_P (TREE_TYPE (dst))
+      || (src && !POINTER_TYPE_P (TREE_TYPE (src)))
       || (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr))))
     return;
 
diff --git a/gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C
new file mode 100644
index 00000000000..fb7f9200f25
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C
@@ -0,0 +1,20 @@
+// { dg-do compile } */
+// { dg-additional-options "-fdump-tree-optimized -O2" }
+// { dg-skip-if "requires hosted libstdc++ for string" { ! hostedlib } }
+// PR tree-optimization/122754
+
+#include <string>
+
+int g(void)
+{
+  std::string a="a";
+  return __builtin_strlen(a.c_str());
+}
+
+// This should be optimized to just `return 1` without any
+// references to struct string or any other variables.
+
+// { dg-final { scan-tree-dump-not "strlen " "optimized" } }
+// { dg-final { scan-tree-dump-not "struct string" "optimized" } }
+// { dg-final { scan-tree-dump "return 1" "optimized" } }
+
diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
index bb6561cde03..b9457c988ac 100644
--- a/gcc/tree-ssa-strlen.cc
+++ b/gcc/tree-ssa-strlen.cc
@@ -1997,7 +1997,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
                  if (tree size = DECL_SIZE_UNIT (base))
                    if (size
                        && TREE_CODE (size) == INTEGER_CST
-                       && TREE_CODE (TREE_TYPE (base)) != POINTER_TYPE)
+                       && !POINTER_TYPE_P (TREE_TYPE (base)))
                      max = wi::to_wide (size);
                }
            }
@@ -2792,7 +2792,7 @@ strlen_pass::handle_builtin_strncat (built_in_function)
 bool
 is_strlen_related_p (tree src, tree len)
 {
-  if (TREE_CODE (TREE_TYPE (len)) == POINTER_TYPE
+  if (POINTER_TYPE_P (TREE_TYPE (len))
       && operand_equal_p (src, len, 0))
     return true;
 
@@ -2853,7 +2853,7 @@ is_strlen_related_p (tree src, tree len)
   tree rhs1 = gimple_assign_rhs1 (lendef);
   tree rhstype = TREE_TYPE (rhs1);
 
-  if ((TREE_CODE (rhstype) == POINTER_TYPE && code == POINTER_PLUS_EXPR)
+  if ((POINTER_TYPE_P (rhstype) && code == POINTER_PLUS_EXPR)
       || (INTEGRAL_TYPE_P (rhstype)
          && (code == BIT_AND_EXPR
              || code == NOP_EXPR)))
@@ -5746,7 +5746,7 @@ strlen_pass::handle_assign (tree lhs, tree rhs, bool 
*zero_write)
        {
          tree ref = TREE_OPERAND (lhs, i);
          type = TREE_TYPE (ref);
-         if (TREE_CODE (type) == POINTER_TYPE)
+         if (POINTER_TYPE_P (type))
            type = TREE_TYPE (type);
          if (TREE_CODE (type) == ARRAY_TYPE)
            type = TREE_TYPE (type);
-- 
2.43.0

Reply via email to