#include "ipa-prop.h"
#include "internal-fn.h"
#include "gimple-range.h"
+#include "tree-ssa-strlen.h"
/* Possible lattice values. */
typedef enum
}; // class pass_fold_builtins
+/* Optimize memcmp STMT into memcmp_eq if it is only used with
+ `== 0` or `!= 0`. */
+
+static void
+optimize_memcmp_eq (gcall *stmt)
+{
+ /* Make sure memcmp arguments are the correct type. */
+ if (gimple_call_num_args (stmt) != 3)
+ return;
+ tree arg1 = gimple_call_arg (stmt, 0);
+ tree arg2 = gimple_call_arg (stmt, 1);
+ tree len = gimple_call_arg (stmt, 2);
+
+ if (!POINTER_TYPE_P (TREE_TYPE (arg1)))
+ return;
+ if (!POINTER_TYPE_P (TREE_TYPE (arg2)))
+ return;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (len)))
+ return;
+ /* The return value of the memcmp has to be used
+ equality comparison to zero. */
+ tree res = gimple_call_lhs (stmt);
+
+ if (!res || !use_in_zero_equality (res))
+ return;
+
+ gimple_call_set_fndecl (stmt, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
+ update_stmt (stmt);
+}
+
unsigned int
pass_fold_builtins::execute (function *fun)
{
gsi_next (&i);
continue;
+ case BUILT_IN_MEMCMP:
+ optimize_memcmp_eq (as_a<gcall*>(stmt));
+ break;
+
case BUILT_IN_UNREACHABLE:
if (optimize_unreachable (i))
cfg_changed = true;
return first_use;
}
-/* 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.
- return true when call is transformed, return false otherwise. */
-
-bool
-strlen_pass::handle_builtin_memcmp ()
-{
- gcall *stmt = as_a <gcall *> (gsi_stmt (m_gsi));
- tree res = gimple_call_lhs (stmt);
-
- if (!res || !use_in_zero_equality (res))
- return false;
-
- tree arg1 = gimple_call_arg (stmt, 0);
- tree arg2 = gimple_call_arg (stmt, 1);
- tree len = gimple_call_arg (stmt, 2);
- unsigned HOST_WIDE_INT leni;
-
- if (tree_fits_uhwi_p (len)
- && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
- && pow2p_hwi (leni))
- {
- leni *= CHAR_TYPE_SIZE;
- unsigned align1 = get_pointer_alignment (arg1);
- unsigned align2 = get_pointer_alignment (arg2);
- unsigned align = MIN (align1, align2);
- scalar_int_mode mode;
- if (int_mode_for_size (leni, 1).exists (&mode)
- && (align >= leni || !targetm.slow_unaligned_access (mode, align)))
- {
- location_t loc = gimple_location (stmt);
- tree type, off;
- type = build_nonstandard_integer_type (leni, 1);
- gcc_assert (known_eq (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);
-
- /* Create unaligned types if needed. */
- tree type1 = type, type2 = type;
- if (TYPE_ALIGN (type1) > align1)
- type1 = build_aligned_type (type1, align1);
- if (TYPE_ALIGN (type2) > align2)
- type2 = build_aligned_type (type2, align2);
-
- arg1 = build2_loc (loc, MEM_REF, type1, arg1, off);
- arg2 = build2_loc (loc, MEM_REF, type2, 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 (&m_gsi, res);
- return true;
- }
- }
-
- gimple_call_set_fndecl (stmt, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
- return true;
-}
-
/* Given strinfo IDX for ARG, sets LENRNG[] to the range of lengths
of the string(s) referenced by ARG if it can be determined.
If the length cannot be determined, sets *SIZE to the size of
if (handle_builtin_memset (zero_write))
return false;
break;
- case BUILT_IN_MEMCMP:
- if (handle_builtin_memcmp ())
- return false;
- break;
case BUILT_IN_STRCMP:
case BUILT_IN_STRNCMP:
if (handle_builtin_string_cmp ())