Checks for strlen(s) == 0 could be rewritten as *s == 0 in the simple
case, but in complex cases (such as those involving variable
assignment), the optimization wouldn't be implemented. Fix this
by moving it over to forwprop from fold-const. Although, since
this currently only runs when PROP_last_full_fold is set, the
original code is kept in as well.
Bootstrapped and tested on x86_64-pc-linux-gnu
PR tree-optimization/92408
gcc/ChangeLog:
* tree-ssa-forwprop.cc (optimize_strlen_comp): Rewrite
strlen(s) == 0 as *s == 0 and strlen(s) != 0 as *s != 0.
* tree-ssa-forwprop.cc (simplify_builtin_call): Added call to
optimize_strlen_comp.
gcc/testsuite/ChangeLog:
+ gcc.dg/pr92408.c: New test.
Signed-off-by: Ashley Chekhova <[email protected]>
---
gcc/testsuite/gcc.dg/pr92408.c | 60 ++++++++++++++++++++++++++++++++++
gcc/tree-ssa-forwprop.cc | 46 ++++++++++++++++++++++++++
2 files changed, 106 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr92408.c
diff --git a/gcc/testsuite/gcc.dg/pr92408.c b/gcc/testsuite/gcc.dg/pr92408.c
new file mode 100644
index 00000000000..f7adc7153cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr92408.c
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+
+/* { dg-options "-O2 -fdump-tree-forwprop2 -fdump-tree-optimized" } */
+
+/*
+ Two different checks are used here to ensure that this optimization
+ doesn't occur before PROP_last_full_fold is set.
+*/
+
+/* { dg-final { scan-tree-dump-times "\\*s" 1 "forwprop2" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_strlen" 3 "forwprop2" }
} */
+
+/* { dg-final { scan-tree-dump-times "\\*s" 3 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_strlen" 1 "optimized" }
} */
+
+typedef __SIZE_TYPE__ size_t;
+void a (void);
+void b (void);
+
+void modified1 (const char *s)
+{
+ if (__builtin_strlen (s)) // folded to if (*s)
+ a ();
+}
+
+void modified2 (const char *s)
+{
+ /*
+ folded to
+ __SIZE_TYPE__ n = (*s);
+ */
+ __SIZE_TYPE__ n = __builtin_strlen (s);
+ if (n)
+ a ();
+}
+
+void unaffected1 (const char *s)
+{
+ /*
+ this shouldn't be folded.
+ */
+ __SIZE_TYPE__ n = __builtin_strlen (s);
+ if (n)
+ a ();
+ if (n > 5)
+ b ();
+}
+
+void modified3 (const char *s)
+{
+ /*
+ folded to
+ __SIZE_TYPE__ n = (*s);
+ */
+ __SIZE_TYPE__ n = __builtin_strlen (s);
+ if (n)
+ a ();
+ if (!n)
+ b ();
+}
\ No newline at end of file
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 9bb001d2f63..1db6bf8ccd8 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -2454,6 +2454,50 @@ optimize_stack_restore (gimple_stmt_iterator
*gsi, gimple *call)
return true;
}
+
+/* Optimize
+ (strlen(s) == 0)
+ into
+ (*s == 0)
+
+ and do the same with
+ (strlen(s) != 0)
+ into
+ (*s != 0)
+*/
+
+
+static bool
+optimize_strlen_comp (gimple_stmt_iterator *gsi, gimple *call)
+{
+ if (!fold_before_rtl_expansion_p ())
+ return false;
+
+ tree lhs = gimple_call_lhs (call);
+
+ if (lhs == NULL_TREE || use_in_zero_equality (lhs, true) == NULL)
+ return false;
+
+ /* The string passed to strlen. */
+ tree ptr = gimple_call_arg (call, 0);
+
+ /* Dereference the string. */
+ tree deref = build_simple_mem_ref (ptr);
+
+ /* Perform a type conversion if necessary. */
+ if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (deref)))
+ {
+ deref = fold_convert_loc (gimple_location (call),
+ TREE_TYPE (lhs),
+ deref);
+ }
+
+ /* Replace the original call to strlen with the dereference we just
built. */
+ gimplify_and_update_call_from_tree (gsi, deref);
+
+ return true;
+}
+
/* *GSI_P is a GIMPLE_CALL to a builtin function.
Optimize
memcpy (p, "abcd", 4);
@@ -2485,6 +2529,8 @@ simplify_builtin_call (gimple_stmt_iterator
*gsi_p, tree callee2, bool full_walk
switch (DECL_FUNCTION_CODE (callee2))
{
+ case BUILT_IN_STRLEN:
+ return optimize_strlen_comp (gsi_p, as_a<gcall*>(stmt2));
case BUILT_IN_STACK_RESTORE:
return optimize_stack_restore (gsi_p, as_a<gcall*>(stmt2));
case BUILT_IN_MEMCMP:
--
2.53.0