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> 2003-04-22 Roger Sayle <roger@eyesopen.com>
* alias.c (mark_constant_function): Check for constancy and * alias.c (mark_constant_function): Check for constancy and
......
...@@ -2715,7 +2715,7 @@ expand_builtin_bzero (exp) ...@@ -2715,7 +2715,7 @@ expand_builtin_bzero (exp)
return result; 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 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 caller should emit a normal call, otherwise try to get the result in
TARGET, if convenient (and in mode MODE, if that's convenient). */ TARGET, if convenient (and in mode MODE, if that's convenient). */
...@@ -2852,7 +2852,7 @@ expand_builtin_strcmp (exp, target, mode) ...@@ -2852,7 +2852,7 @@ expand_builtin_strcmp (exp, target, mode)
enum machine_mode mode; enum machine_mode mode;
{ {
tree arglist = TREE_OPERAND (exp, 1); tree arglist = TREE_OPERAND (exp, 1);
tree arg1, arg2, len, len2, fn; tree arg1, arg2;
const char *p1, *p2; const char *p1, *p2;
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
...@@ -2888,49 +2888,88 @@ expand_builtin_strcmp (exp, target, mode) ...@@ -2888,49 +2888,88 @@ expand_builtin_strcmp (exp, target, mode)
return expand_expr (result, target, mode, EXPAND_NORMAL); return expand_expr (result, target, mode, EXPAND_NORMAL);
} }
len = c_strlen (arg1); #ifdef HAVE_cmpstrsi
len2 = c_strlen (arg2); if (HAVE_cmpstrsi)
{
tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx;
rtx result, insn;
if (len) int arg1_align
len = size_binop (PLUS_EXPR, ssize_int (1), len); = 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) len1 = c_strlen (arg1);
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); 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 /* If both arguments have side effects, we cannot optimize. */
of the second, if we know it. We don't require a constant for if (!len || TREE_SIDE_EFFECTS (len))
this case; some cost analysis could be done if both are available return 0;
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. This /* If we don't have POINTER_TYPE, call the function. */
could arise if optimization results in strcpy being called with if (arg1_align == 0 || arg2_align == 0)
two fixed strings, or if the code was machine-generated. We should return 0;
add some code to the `memcmp' handler below to deal with such
situations, someday. */
if (!len || TREE_CODE (len) != INTEGER_CST) /* Make a place to write the result of the instruction. */
{ result = target;
if (len2 && !TREE_SIDE_EFFECTS (len2)) if (! (result != 0
len = len2; && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
else if (len == 0) && REGNO (result) >= FIRST_PSEUDO_REGISTER))
return 0; result = gen_reg_rtx (insn_mode);
}
else if (len2 && TREE_CODE (len2) == INTEGER_CST
&& tree_int_cst_lt (len2, len))
len = len2;
/* If both arguments have side effects, we cannot optimize. */ arg1_rtx = get_memory_rtx (arg1);
if (TREE_SIDE_EFFECTS (len)) arg2_rtx = get_memory_rtx (arg2);
return 0; 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]; emit_insn (insn);
if (!fn)
return 0;
chainon (arglist, build_tree_list (NULL_TREE, len)); /* Return the value in the proper mode for this function. */
return expand_expr (build_function_call_expr (fn, arglist), mode = TYPE_MODE (TREE_TYPE (exp));
target, mode, EXPAND_NORMAL); 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 /* Expand expression EXP, which is a call to the strncmp builtin. Return 0
...@@ -2944,7 +2983,6 @@ expand_builtin_strncmp (exp, target, mode) ...@@ -2944,7 +2983,6 @@ expand_builtin_strncmp (exp, target, mode)
enum machine_mode mode; enum machine_mode mode;
{ {
tree arglist = TREE_OPERAND (exp, 1); tree arglist = TREE_OPERAND (exp, 1);
tree fn, newarglist, len = 0;
tree arg1, arg2, arg3; tree arg1, arg2, arg3;
const char *p1, *p2; const char *p1, *p2;
...@@ -2998,41 +3036,93 @@ expand_builtin_strncmp (exp, target, mode) ...@@ -2998,41 +3036,93 @@ expand_builtin_strncmp (exp, target, mode)
} }
/* If c_strlen can determine an expression for one of the string /* If c_strlen can determine an expression for one of the string
lengths, and it doesn't have side effects, then call lengths, and it doesn't have side effects, then emit cmpstrsi
expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3). */ using length MIN(strlen(string)+1, arg3). */
#ifdef HAVE_cmpstrsi
/* Perhaps one of the strings is really constant, if so prefer if (HAVE_cmpstrsi)
that constant length over the other string's length. */ {
if (p1) tree len, len1, len2;
len = c_strlen (arg1); rtx arg1_rtx, arg2_rtx, arg3_rtx;
else if (p2) rtx result, insn;
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;
fn = implicit_built_in_decls[BUILT_IN_MEMCMP]; int arg1_align
if (!fn) = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
return 0; 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. */ len1 = c_strlen (arg1);
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); 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). */ /* If both arguments have side effects, we cannot optimize. */
len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3)); if (!len || TREE_SIDE_EFFECTS (len))
return 0;
newarglist = build_tree_list (NULL_TREE, len); /* The actual new length parameter is MIN(len,arg3). */
newarglist = tree_cons (NULL_TREE, arg2, newarglist); len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
newarglist = tree_cons (NULL_TREE, arg1, newarglist);
return expand_expr (build_function_call_expr (fn, newarglist), /* If we don't have POINTER_TYPE, call the function. */
target, mode, EXPAND_NORMAL); 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. /* 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