Currently, we give up in fold_strstr_to_strncmp() if the length of the
the second argument to strstr() isn't known to us by the time we hit
that function. However, we can instead insert a strlen() in ourselves
and continue trying to fold strstr() into strlen()+strncmp().
PR tree-optimization/96601
gcc/ChangeLog:
* tree-ssa-strlen.cc (fold_strstr_to_strncmp): If arg1_len == NULL,
insert a strlen() for strstr()'s arg1 and use it as arg1_len.
gcc/testsuite/ChangeLog:
* gcc.dg/strlenopt-30.c: Modify test.
Signed-off-by: Hamza Mahfooz <someguy@effective-light.com>
---
Please push this for me if you think it looks good. Since, I don't have
write access to the repository.
---
gcc/testsuite/gcc.dg/strlenopt-30.c | 5 +-
gcc/tree-ssa-strlen.cc | 81 ++++++++++++++++-------------
2 files changed, 45 insertions(+), 41 deletions(-)
@@ -38,9 +38,6 @@ void f5(char *s)
foo_f5();
}
-/* Do not perform transform, since strlen (t)
- is unknown. */
-
__attribute__((no_icf))
_Bool f6(char *s, char *t)
{
@@ -60,4 +57,4 @@ _Bool f7(char *s)
return (t1 == s);
}
-/* { dg-final { scan-tree-dump-times "__builtin_strncmp" 5 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_strncmp" 6 "strlen1" } } */
@@ -5273,6 +5273,7 @@ fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
tree arg1 = gimple_call_arg (call_stmt, 1);
tree arg1_len = NULL_TREE;
int idx = get_stridx (arg1, call_stmt);
+ gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
if (idx)
{
@@ -5286,51 +5287,57 @@ fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
}
}
- if (arg1_len != NULL_TREE)
+ if (arg1_len == NULL_TREE)
{
- gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
- tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
+ tree strlen_decl = builtin_decl_explicit (BUILT_IN_STRLEN);
+ gcall *strlen_call = gimple_build_call (strlen_decl, 1, arg1);
+ tree strlen_lhs = make_ssa_name (size_type_node, strlen_call);
+
+ gimple_call_set_lhs (strlen_call, strlen_lhs);
+ gimple_set_vuse (strlen_call, gimple_vuse (call_stmt));
+ gsi_insert_before (&gsi, strlen_call, GSI_SAME_STMT);
+ arg1_len = strlen_lhs;
+ }
+ else if (!is_gimple_val (arg1_len))
+ {
+ tree arg1_len_tmp = make_ssa_name (TREE_TYPE (arg1_len));
+ gassign *arg1_stmt = gimple_build_assign (arg1_len_tmp,
+ arg1_len);
+ gsi_insert_before (&gsi, arg1_stmt, GSI_SAME_STMT);
+ arg1_len = arg1_len_tmp;
+ }
- if (!is_gimple_val (arg1_len))
+ tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
+ gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
+ arg0, arg1, arg1_len);
+ tree strncmp_lhs = make_ssa_name (integer_type_node);
+ gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
+ gimple_call_set_lhs (strncmp_call, strncmp_lhs);
+ gsi_remove (&gsi, true);
+ gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
+ tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
+
+ if (is_gimple_assign (stmt))
+ {
+ if (gimple_assign_rhs_code (stmt) == COND_EXPR)
{
- tree arg1_len_tmp = make_ssa_name (TREE_TYPE (arg1_len));
- gassign *arg1_stmt = gimple_build_assign (arg1_len_tmp,
- arg1_len);
- gsi_insert_before (&gsi, arg1_stmt, GSI_SAME_STMT);
- arg1_len = arg1_len_tmp;
- }
-
- gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
- arg0, arg1, arg1_len);
- tree strncmp_lhs = make_ssa_name (integer_type_node);
- gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
- gimple_call_set_lhs (strncmp_call, strncmp_lhs);
- gsi_remove (&gsi, true);
- gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
- tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
-
- if (is_gimple_assign (stmt))
- {
- if (gimple_assign_rhs_code (stmt) == COND_EXPR)
- {
- tree cond = gimple_assign_rhs1 (stmt);
- TREE_OPERAND (cond, 0) = strncmp_lhs;
- TREE_OPERAND (cond, 1) = zero;
- }
- else
- {
- gimple_assign_set_rhs1 (stmt, strncmp_lhs);
- gimple_assign_set_rhs2 (stmt, zero);
- }
+ tree cond = gimple_assign_rhs1 (stmt);
+ TREE_OPERAND (cond, 0) = strncmp_lhs;
+ TREE_OPERAND (cond, 1) = zero;
}
else
{
- gcond *cond = as_a<gcond *> (stmt);
- gimple_cond_set_lhs (cond, strncmp_lhs);
- gimple_cond_set_rhs (cond, zero);
+ gimple_assign_set_rhs1 (stmt, strncmp_lhs);
+ gimple_assign_set_rhs2 (stmt, zero);
}
- update_stmt (stmt);
}
+ else
+ {
+ gcond *cond = as_a<gcond *> (stmt);
+ gimple_cond_set_lhs (cond, strncmp_lhs);
+ gimple_cond_set_rhs (cond, zero);
+ }
+ update_stmt (stmt);
}
}
}