@@ -10676,30 +10676,6 @@ fold_binary_loc (location_t loc,
return t1;
}
- /* Optimize comparisons of strlen vs zero to a compare of the
- first character of the string vs zero. To wit,
- strlen(ptr) == 0 => *ptr == 0
- strlen(ptr) != 0 => *ptr != 0
- Other cases should reduce to one of these two (or a constant)
- due to the return value of strlen being unsigned. */
- if (TREE_CODE (arg0) == CALL_EXPR
- && integer_zerop (arg1))
- {
- tree fndecl = get_callee_fndecl (arg0);
-
- if (fndecl
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
- && call_expr_nargs (arg0) == 1
- && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (arg0, 0))) == POINTER_TYPE)
- {
- tree iref = build_fold_indirect_ref_loc (loc,
- CALL_EXPR_ARG (arg0, 0));
- return fold_build2_loc (loc, code, type, iref,
- build_int_cst (TREE_TYPE (iref), 0));
- }
- }
-
/* Fold (X >> C) != 0 into X < 0 if C is one less than the width
of X. Similarly fold (X >> C) == 0 into X >= 0. */
if (TREE_CODE (arg0) == RSHIFT_EXPR
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+__attribute__((noinline, no_icf))
+_Bool f1(const char *s)
+{
+ unsigned long len = __builtin_strlen (s);
+ _Bool ret = (len == 0);
+ return ret;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
@@ -45,6 +45,8 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-chkp.h"
#include "tree-hash-traits.h"
#include "builtins.h"
+#include "tree-pretty-print.h"
+#include "tree-cfg.h"
/* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
is an index into strinfo vector, negative value stands for
@@ -1937,6 +1939,36 @@ handle_builtin_memset (gimple_stmt_iterator *gsi)
return false;
}
+static void
+replace_call_by_cmp (gimple_stmt_iterator *gsi, location_t loc,
+ tree type, tree arg1, tree arg2,
+ tree res_type, enum tree_code cmp_code)
+{
+ tree ptrtype = build_pointer_type_for_mode (char_type_node, ptr_mode, true);
+ tree off = build_int_cst (ptrtype, 0);
+ arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
+ tree tem1 = fold_const_aggregate_ref (arg1);
+ if (tem1)
+ arg1 = tem1;
+
+ if (POINTER_TYPE_P (TREE_TYPE (arg2)))
+ {
+ arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
+ tree tem2 = fold_const_aggregate_ref (arg2);
+ if (tem2)
+ arg2 = tem2;
+ }
+ else
+ gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (arg2)));
+
+ tree res = fold_convert_loc (loc, res_type,
+ fold_build2_loc (loc, cmp_code,
+ boolean_type_node,
+ arg1, arg2));
+
+ gimplify_and_update_call_from_tree (gsi, res);
+}
+
/* Handle a call to memcmp. We try to handle small comparisons by
converting them to load and compare, and replacing the call to memcmp
with a __builtin_memcmp_eq call where possible. */
@@ -1994,25 +2026,11 @@ handle_builtin_memcmp (gimple_stmt_iterator *gsi)
&& (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align)))
{
location_t loc = gimple_location (stmt2);
- tree type, off;
+ tree type;
type = build_nonstandard_integer_type (leni, 1);
gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
- tree ptrtype = build_pointer_type_for_mode (char_type_node,
- ptr_mode, true);
- off = build_int_cst (ptrtype, 0);
- arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
- arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
- tree tem1 = fold_const_aggregate_ref (arg1);
- if (tem1)
- arg1 = tem1;
- tree tem2 = fold_const_aggregate_ref (arg2);
- if (tem2)
- arg2 = tem2;
- res = fold_convert_loc (loc, TREE_TYPE (res),
- fold_build2_loc (loc, NE_EXPR,
- boolean_type_node,
- arg1, arg2));
- gimplify_and_update_call_from_tree (gsi, res);
+ replace_call_by_cmp (gsi, loc, type, arg1, arg2,
+ TREE_TYPE (res), NE_EXPR);
return false;
}
}
@@ -2302,6 +2320,41 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi)
else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
handle_pointer_plus (gsi);
}
+ /* strlen (s) eq/ne 0 -> *s eq/ne 0. */
+ else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree_code code = gimple_assign_rhs_code (stmt);
+
+ if ((code == EQ_EXPR || code == NE_EXPR) && integer_zerop (rhs2))
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ if (TREE_CODE (rhs1) == SSA_NAME)
+ {
+ gimple *def_stmt = SSA_NAME_DEF_STMT (rhs1);
+ if (gcall *call_stmt = dyn_cast<gcall *> (def_stmt))
+ {
+ tree callee = gimple_call_fndecl (call_stmt);
+ if (valid_builtin_call (call_stmt)
+ && DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN)
+ {
+ tree call_arg = gimple_call_arg (call_stmt, 0);
+ tree call_lhs = gimple_call_lhs (call_stmt);
+
+ if (has_single_use (call_lhs))
+ {
+ gimple_stmt_iterator call_gsi = gsi_for_stmt (call_stmt);
+ replace_call_by_cmp (&call_gsi, gimple_location (call_stmt),
+ TREE_TYPE (rhs2), call_arg, rhs2, TREE_TYPE (call_lhs),
+ code);
+ gimple_assign_set_rhs_with_ops (gsi, CONVERT_EXPR, call_lhs);
+ update_stmt (stmt);
+ }
+ }
+ }
+ }
+ }
+ }
else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
{
tree type = TREE_TYPE (lhs);
@@ -2505,7 +2558,7 @@ const pass_data pass_data_strlen =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_update_ssa_only_virtuals, /* todo_flags_finish */
};
class pass_strlen : public gimple_opt_pass