Commit 2be3b5ce by Roger Sayle Committed by Roger Sayle

re PR rtl-optimization/10339 ([sparc,ppc,ppc64] Invalid optimization: replacing strncmp by memcmp)


	PR optimization/10339
	* builtins.c (expand_builtin_strcmp): Try to emit cmpstrsi insn
	directly instead of unsafely transforming call into a memcmp.
	(expand_builtin_strncmp): Likewise.

From-SVN: r65985
parent d8c30611
2003-04-23 Roger Sayle <roger@eyesopen.com>
PR optimization/10339
* builtins.c (expand_builtin_strcmp): Try to emit cmpstrsi insn
directly instead of unsafely transforming call into a memcmp.
(expand_builtin_strncmp): Likewise.
2003-04-22 Roger Sayle <roger@eyesopen.com>
* alias.c (mark_constant_function): Check for constancy and
......
......@@ -2715,7 +2715,7 @@ expand_builtin_bzero (exp)
return result;
}
/* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
/* Expand expression EXP, which is a call to the memcmp built-in function.
ARGLIST is the argument list for this call. Return 0 if we failed and the
caller should emit a normal call, otherwise try to get the result in
TARGET, if convenient (and in mode MODE, if that's convenient). */
......@@ -2852,7 +2852,7 @@ expand_builtin_strcmp (exp, target, mode)
enum machine_mode mode;
{
tree arglist = TREE_OPERAND (exp, 1);
tree arg1, arg2, len, len2, fn;
tree arg1, arg2;
const char *p1, *p2;
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
......@@ -2888,49 +2888,88 @@ expand_builtin_strcmp (exp, target, mode)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
len = c_strlen (arg1);
len2 = c_strlen (arg2);
#ifdef HAVE_cmpstrsi
if (HAVE_cmpstrsi)
{
tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx;
rtx result, insn;
if (len)
len = size_binop (PLUS_EXPR, ssize_int (1), len);
int arg1_align
= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
int arg2_align
= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
enum machine_mode insn_mode
= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
if (len2)
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
len1 = c_strlen (arg1);
len2 = c_strlen (arg2);
if (len1)
len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
if (len2)
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
/* If we don't have a constant length for the first, use the length
of the second, if we know it. We don't require a constant for
this case; some cost analysis could be done if both are available
but neither is constant. For now, assume they're equally cheap,
unless one has side effects. If both strings have constant lengths,
use the smaller. */
if (!len1)
len = len2;
else if (!len2)
len = len1;
else if (TREE_SIDE_EFFECTS (len1))
len = len2;
else if (TREE_SIDE_EFFECTS (len2))
len = len1;
else if (TREE_CODE (len1) != INTEGER_CST)
len = len2;
else if (TREE_CODE (len2) != INTEGER_CST)
len = len1;
else if (tree_int_cst_lt (len1, len2))
len = len1;
else
len = len2;
/* If we don't have a constant length for the first, use the length
of the second, if we know it. We don't require a constant for
this case; some cost analysis could be done if both are available
but neither is constant. For now, assume they're equally cheap
unless one has side effects.
/* If both arguments have side effects, we cannot optimize. */
if (!len || TREE_SIDE_EFFECTS (len))
return 0;
If both strings have constant lengths, use the smaller. This
could arise if optimization results in strcpy being called with
two fixed strings, or if the code was machine-generated. We should
add some code to the `memcmp' handler below to deal with such
situations, someday. */
/* If we don't have POINTER_TYPE, call the function. */
if (arg1_align == 0 || arg2_align == 0)
return 0;
if (!len || TREE_CODE (len) != INTEGER_CST)
{
if (len2 && !TREE_SIDE_EFFECTS (len2))
len = len2;
else if (len == 0)
return 0;
}
else if (len2 && TREE_CODE (len2) == INTEGER_CST
&& tree_int_cst_lt (len2, len))
len = len2;
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
&& GET_CODE (result) == REG && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
/* If both arguments have side effects, we cannot optimize. */
if (TREE_SIDE_EFFECTS (len))
return 0;
arg1_rtx = get_memory_rtx (arg1);
arg2_rtx = get_memory_rtx (arg2);
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));
if (!insn)
return 0;
fn = implicit_built_in_decls[BUILT_IN_MEMCMP];
if (!fn)
return 0;
emit_insn (insn);
chainon (arglist, build_tree_list (NULL_TREE, len));
return expand_expr (build_function_call_expr (fn, arglist),
target, mode, EXPAND_NORMAL);
/* Return the value in the proper mode for this function. */
mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE (result) == mode)
return result;
if (target == 0)
return convert_to_mode (mode, result, 0);
convert_move (target, result, 0);
return target;
}
#endif
return 0;
}
/* Expand expression EXP, which is a call to the strncmp builtin. Return 0
......@@ -2944,7 +2983,6 @@ expand_builtin_strncmp (exp, target, mode)
enum machine_mode mode;
{
tree arglist = TREE_OPERAND (exp, 1);
tree fn, newarglist, len = 0;
tree arg1, arg2, arg3;
const char *p1, *p2;
......@@ -2998,41 +3036,93 @@ expand_builtin_strncmp (exp, target, mode)
}
/* If c_strlen can determine an expression for one of the string
lengths, and it doesn't have side effects, then call
expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3). */
/* Perhaps one of the strings is really constant, if so prefer
that constant length over the other string's length. */
if (p1)
len = c_strlen (arg1);
else if (p2)
len = c_strlen (arg2);
/* If we still don't have a len, try either string arg as long
as they don't have side effects. */
if (!len && !TREE_SIDE_EFFECTS (arg1))
len = c_strlen (arg1);
if (!len && !TREE_SIDE_EFFECTS (arg2))
len = c_strlen (arg2);
/* If we still don't have a length, punt. */
if (!len)
return 0;
lengths, and it doesn't have side effects, then emit cmpstrsi
using length MIN(strlen(string)+1, arg3). */
#ifdef HAVE_cmpstrsi
if (HAVE_cmpstrsi)
{
tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx;
rtx result, insn;
fn = implicit_built_in_decls[BUILT_IN_MEMCMP];
if (!fn)
return 0;
int arg1_align
= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
int arg2_align
= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
enum machine_mode insn_mode
= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
/* Add one to the string length. */
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
len1 = c_strlen (arg1);
len2 = c_strlen (arg2);
if (len1)
len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
if (len2)
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
/* If we don't have a constant length for the first, use the length
of the second, if we know it. We don't require a constant for
this case; some cost analysis could be done if both are available
but neither is constant. For now, assume they're equally cheap,
unless one has side effects. If both strings have constant lengths,
use the smaller. */
if (!len1)
len = len2;
else if (!len2)
len = len1;
else if (TREE_SIDE_EFFECTS (len1))
len = len2;
else if (TREE_SIDE_EFFECTS (len2))
len = len1;
else if (TREE_CODE (len1) != INTEGER_CST)
len = len2;
else if (TREE_CODE (len2) != INTEGER_CST)
len = len1;
else if (tree_int_cst_lt (len1, len2))
len = len1;
else
len = len2;
/* The actual new length parameter is MIN(len,arg3). */
len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
/* If both arguments have side effects, we cannot optimize. */
if (!len || TREE_SIDE_EFFECTS (len))
return 0;
newarglist = build_tree_list (NULL_TREE, len);
newarglist = tree_cons (NULL_TREE, arg2, newarglist);
newarglist = tree_cons (NULL_TREE, arg1, newarglist);
return expand_expr (build_function_call_expr (fn, newarglist),
target, mode, EXPAND_NORMAL);
/* The actual new length parameter is MIN(len,arg3). */
len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
/* If we don't have POINTER_TYPE, call the function. */
if (arg1_align == 0 || arg2_align == 0)
return 0;
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
&& GET_CODE (result) == REG && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
arg1_rtx = get_memory_rtx (arg1);
arg2_rtx = get_memory_rtx (arg2);
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));
if (!insn)
return 0;
emit_insn (insn);
/* Return the value in the proper mode for this function. */
mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE (result) == mode)
return result;
if (target == 0)
return convert_to_mode (mode, result, 0);
convert_move (target, result, 0);
return target;
}
#endif
return 0;
}
/* Expand expression EXP, which is a call to the strcat builtin.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment