Commit a666df60 by Richard Sandiford Committed by Richard Sandiford

builtins.c (expand_cmpstr, [...]): New functions.

gcc/
	* builtins.c (expand_cmpstr, expand_cmpstrn): New functions.
	(expand_builtin_strcmp, expand_builtin_strncmp): Use them.  Remove
	references to HAVE_cmpstr{,n}si and CODE_FOR_cmpstr{,n}si.
	* config/m32c/blkmov.md (cmpstrsi): Fix predicates of operands 1 and 2.
	Add predicates for operands 0 and 3.
	* config/rx/rx.md (cmpstrnsi): Remove force_operand for the length
	operand.
	* config/sh/sh.md (cmpstrnsi): Change the length predicate from
	immediate_operand to nonmemory_operand.

From-SVN: r227140
parent 762613be
2015-08-24 Richard Sandiford <richard.sandiford@arm.com> 2015-08-24 Richard Sandiford <richard.sandiford@arm.com>
* builtins.c (expand_cmpstr, expand_cmpstrn): New functions.
(expand_builtin_strcmp, expand_builtin_strncmp): Use them. Remove
references to HAVE_cmpstr{,n}si and CODE_FOR_cmpstr{,n}si.
* config/m32c/blkmov.md (cmpstrsi): Fix predicates of operands 1 and 2.
Add predicates for operands 0 and 3.
* config/rx/rx.md (cmpstrnsi): Remove force_operand for the length
operand.
* config/sh/sh.md (cmpstrnsi): Change the length predicate from
immediate_operand to nonmemory_operand.
2015-08-24 Richard Sandiford <richard.sandiford@arm.com>
* df-scan.c (df_insn_info_init_fields): New function, split out * df-scan.c (df_insn_info_init_fields): New function, split out
from... from...
(df_insn_create_insn_record): ...here. (df_insn_create_insn_record): ...here.
......
...@@ -3917,6 +3917,53 @@ expand_builtin_bzero (tree exp) ...@@ -3917,6 +3917,53 @@ expand_builtin_bzero (tree exp)
const0_rtx, VOIDmode, exp); const0_rtx, VOIDmode, exp);
} }
/* Try to expand cmpstr operation ICODE with the given operands.
Return the result rtx on success, otherwise return null. */
static rtx
expand_cmpstr (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
HOST_WIDE_INT align)
{
machine_mode insn_mode = insn_data[icode].operand[0].mode;
if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
target = NULL_RTX;
struct expand_operand ops[4];
create_output_operand (&ops[0], target, insn_mode);
create_fixed_operand (&ops[1], arg1_rtx);
create_fixed_operand (&ops[2], arg2_rtx);
create_integer_operand (&ops[3], align);
if (maybe_expand_insn (icode, 4, ops))
return ops[0].value;
return NULL_RTX;
}
/* Try to expand cmpstrn operation ICODE with the given operands.
ARG3_TYPE is the type of ARG3_RTX. Return the result rtx on success,
otherwise return null. */
static rtx
expand_cmpstrn (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
tree arg3_type, rtx arg3_rtx, HOST_WIDE_INT align)
{
machine_mode insn_mode = insn_data[icode].operand[0].mode;
if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
target = NULL_RTX;
struct expand_operand ops[5];
create_output_operand (&ops[0], target, insn_mode);
create_fixed_operand (&ops[1], arg1_rtx);
create_fixed_operand (&ops[2], arg2_rtx);
create_convert_operand_from (&ops[3], arg3_rtx, TYPE_MODE (arg3_type),
TYPE_UNSIGNED (arg3_type));
create_integer_operand (&ops[4], align);
if (maybe_expand_insn (icode, 5, ops))
return ops[0].value;
return NULL_RTX;
}
/* Expand expression EXP, which is a call to the memcmp built-in function. /* Expand expression EXP, which is a call to the memcmp built-in function.
Return NULL_RTX if we failed and the caller should emit a normal call, Return NULL_RTX if we failed and the caller should emit a normal call,
otherwise try to get the result in TARGET, if convenient (and in mode otherwise try to get the result in TARGET, if convenient (and in mode
...@@ -4019,15 +4066,15 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) ...@@ -4019,15 +4066,15 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return NULL_RTX; return NULL_RTX;
#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode);
if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
|| direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing) if (cmpstr_icode != CODE_FOR_nothing || cmpstrn_icode != CODE_FOR_nothing)
{ {
rtx arg1_rtx, arg2_rtx; rtx arg1_rtx, arg2_rtx;
rtx result, insn = NULL_RTX;
tree fndecl, fn; tree fndecl, fn;
tree arg1 = CALL_EXPR_ARG (exp, 0); tree arg1 = CALL_EXPR_ARG (exp, 0);
tree arg2 = CALL_EXPR_ARG (exp, 1); tree arg2 = CALL_EXPR_ARG (exp, 1);
rtx result = NULL_RTX;
unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT; unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT; unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
...@@ -4043,33 +4090,17 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) ...@@ -4043,33 +4090,17 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
arg1_rtx = get_memory_rtx (arg1, NULL); arg1_rtx = get_memory_rtx (arg1, NULL);
arg2_rtx = get_memory_rtx (arg2, NULL); arg2_rtx = get_memory_rtx (arg2, NULL);
#ifdef HAVE_cmpstrsi
/* Try to call cmpstrsi. */ /* Try to call cmpstrsi. */
if (HAVE_cmpstrsi) if (cmpstr_icode != CODE_FOR_nothing)
{ result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
machine_mode insn_mode MIN (arg1_align, arg2_align));
= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
&& REG_P (result) && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));
}
#endif
#ifdef HAVE_cmpstrnsi
/* Try to determine at least one length and call cmpstrnsi. */ /* Try to determine at least one length and call cmpstrnsi. */
if (!insn && HAVE_cmpstrnsi) if (!result && cmpstrn_icode != CODE_FOR_nothing)
{ {
tree len; tree len;
rtx arg3_rtx; rtx arg3_rtx;
machine_mode insn_mode
= insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
tree len1 = c_strlen (arg1, 1); tree len1 = c_strlen (arg1, 1);
tree len2 = c_strlen (arg2, 1); tree len2 = c_strlen (arg2, 1);
...@@ -4103,30 +4134,19 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) ...@@ -4103,30 +4134,19 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
len = len2; len = len2;
/* If both arguments have side effects, we cannot optimize. */ /* If both arguments have side effects, we cannot optimize. */
if (!len || TREE_SIDE_EFFECTS (len)) if (len && !TREE_SIDE_EFFECTS (len))
goto do_libcall; {
arg3_rtx = expand_normal (len);
arg3_rtx = expand_normal (len); result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx,
arg2_rtx, TREE_TYPE (len), arg3_rtx,
/* Make a place to write the result of the instruction. */ MIN (arg1_align, arg2_align));
result = target; }
if (! (result != 0
&& REG_P (result) && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));
} }
#endif
if (insn) if (result)
{ {
machine_mode mode;
emit_insn (insn);
/* Return the value in the proper mode for this function. */ /* Return the value in the proper mode for this function. */
mode = TYPE_MODE (TREE_TYPE (exp)); machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE (result) == mode) if (GET_MODE (result) == mode)
return result; return result;
if (target == 0) if (target == 0)
...@@ -4137,16 +4157,12 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) ...@@ -4137,16 +4157,12 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
/* Expand the library call ourselves using a stabilized argument /* Expand the library call ourselves using a stabilized argument
list to avoid re-evaluating the function's arguments twice. */ list to avoid re-evaluating the function's arguments twice. */
#ifdef HAVE_cmpstrnsi
do_libcall:
#endif
fndecl = get_callee_fndecl (exp); fndecl = get_callee_fndecl (exp);
fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2); fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
gcc_assert (TREE_CODE (fn) == CALL_EXPR); gcc_assert (TREE_CODE (fn) == CALL_EXPR);
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_call (fn, target, target == const0_rtx); return expand_call (fn, target, target == const0_rtx);
} }
#endif
return NULL_RTX; return NULL_RTX;
} }
...@@ -4167,12 +4183,12 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, ...@@ -4167,12 +4183,12 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
/* 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 emit cmpstrnsi lengths, and it doesn't have side effects, then emit cmpstrnsi
using length MIN(strlen(string)+1, arg3). */ using length MIN(strlen(string)+1, arg3). */
#ifdef HAVE_cmpstrnsi insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
if (HAVE_cmpstrnsi) if (cmpstrn_icode != CODE_FOR_nothing)
{ {
tree len, len1, len2; tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx; rtx arg1_rtx, arg2_rtx, arg3_rtx;
rtx result, insn; rtx result;
tree fndecl, fn; tree fndecl, fn;
tree arg1 = CALL_EXPR_ARG (exp, 0); tree arg1 = CALL_EXPR_ARG (exp, 0);
tree arg2 = CALL_EXPR_ARG (exp, 1); tree arg2 = CALL_EXPR_ARG (exp, 1);
...@@ -4180,8 +4196,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, ...@@ -4180,8 +4196,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT; unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT; unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
machine_mode insn_mode
= insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
len1 = c_strlen (arg1, 1); len1 = c_strlen (arg1, 1);
len2 = c_strlen (arg2, 1); len2 = c_strlen (arg2, 1);
...@@ -4227,13 +4241,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, ...@@ -4227,13 +4241,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
if (arg1_align == 0 || arg2_align == 0) if (arg1_align == 0 || arg2_align == 0)
return NULL_RTX; return NULL_RTX;
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
&& REG_P (result) && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
/* Stabilize the arguments in case gen_cmpstrnsi fails. */ /* Stabilize the arguments in case gen_cmpstrnsi fails. */
arg1 = builtin_save_expr (arg1); arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2); arg2 = builtin_save_expr (arg2);
...@@ -4242,12 +4249,11 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, ...@@ -4242,12 +4249,11 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
arg1_rtx = get_memory_rtx (arg1, len); arg1_rtx = get_memory_rtx (arg1, len);
arg2_rtx = get_memory_rtx (arg2, len); arg2_rtx = get_memory_rtx (arg2, len);
arg3_rtx = expand_normal (len); arg3_rtx = expand_normal (len);
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx, arg2_rtx,
GEN_INT (MIN (arg1_align, arg2_align))); TREE_TYPE (len), arg3_rtx,
if (insn) MIN (arg1_align, arg2_align));
if (result)
{ {
emit_insn (insn);
/* Return the value in the proper mode for this function. */ /* Return the value in the proper mode for this function. */
mode = TYPE_MODE (TREE_TYPE (exp)); mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE (result) == mode) if (GET_MODE (result) == mode)
...@@ -4267,7 +4273,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, ...@@ -4267,7 +4273,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_call (fn, target, target == const0_rtx); return expand_call (fn, target, target == const0_rtx);
} }
#endif
return NULL_RTX; return NULL_RTX;
} }
......
...@@ -178,10 +178,10 @@ ...@@ -178,10 +178,10 @@
;; 3 = alignment ;; 3 = alignment
(define_expand "cmpstrsi" (define_expand "cmpstrsi"
[(match_operand:HI 0 "" "") [(match_operand:HI 0 "register_operand" "")
(match_operand 1 "ap_operand" "") (match_operand 1 "memory_operand" "")
(match_operand 2 "ap_operand" "") (match_operand 2 "memory_operand" "")
(match_operand 3 "" "") (match_operand 3 "const_int_operand" "")
] ]
"TARGET_A24" "TARGET_A24"
"if (m32c_expand_cmpstr(operands)) DONE; FAIL;" "if (m32c_expand_cmpstr(operands)) DONE; FAIL;"
......
...@@ -2315,7 +2315,7 @@ ...@@ -2315,7 +2315,7 @@
emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX)); emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX));
emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX)); emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX));
emit_move_insn (len, force_operand (operands[3], NULL_RTX)); emit_move_insn (len, operands[3]);
emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2]));
DONE; DONE;
......
...@@ -12731,7 +12731,7 @@ label: ...@@ -12731,7 +12731,7 @@ label:
[(set (match_operand:SI 0 "register_operand") [(set (match_operand:SI 0 "register_operand")
(compare:SI (match_operand:BLK 1 "memory_operand") (compare:SI (match_operand:BLK 1 "memory_operand")
(match_operand:BLK 2 "memory_operand"))) (match_operand:BLK 2 "memory_operand")))
(use (match_operand:SI 3 "immediate_operand")) (use (match_operand:SI 3 "nonmemory_operand"))
(use (match_operand:SI 4 "immediate_operand"))] (use (match_operand:SI 4 "immediate_operand"))]
"TARGET_SH1 && optimize" "TARGET_SH1 && optimize"
{ {
......
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