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