mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
762613be3e
commit
a666df609a
|
|
@ -1,3 +1,15 @@
|
||||||
|
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>
|
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
|
||||||
|
|
|
||||||
139
gcc/builtins.c
139
gcc/builtins.c
|
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
|
||||||
|
|
||||||
/* 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_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
|
|
||||||
GEN_INT (MIN (arg1_align, arg2_align)));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (insn)
|
|
||||||
{
|
{
|
||||||
machine_mode mode;
|
arg3_rtx = expand_normal (len);
|
||||||
emit_insn (insn);
|
result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx,
|
||||||
|
arg2_rtx, TREE_TYPE (len), arg3_rtx,
|
||||||
|
MIN (arg1_align, arg2_align));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
/* 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)
|
||||||
|
|
||||||
/* 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,
|
||||||
/* 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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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 @@
|
||||||
;; 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 @@
|
||||||
|
|
||||||
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:
|
||||||
[(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"
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue