builtins.c: (expand_builtin_memcmp, expand_builtin_strncmp): s/cmpstrsi/cmpstrnsi
2005-07-12 Adrian Straetling <straetling@de.ibm.com> * builtins.c: (expand_builtin_memcmp, expand_builtin_strncmp): s/cmpstrsi/cmpstrnsi (expand_builtin_strcmp): Rewrite to support both 'cmpstrsi' and 'cmpstrnsi'. * optabs.c: (prepare_cmp_insn): Add availability of 'cmpstrn'. (init_optabs): Initialize cmpstrn_optab. * optabs.h: (enum insn_code cmpstrn_optab): Declare. * genopinit.c: (optabs[]): Add 'cmpstrn' to initialisation. * expr.c: (enum insn_code cmpstrn_optab): Declare. * config/i386/i386.md: s/cmpstr/cmpstrn * config/c4x/c4x.md: s/cmpstr/cmpstrn * doc/md.texi: Update documentation. From-SVN: r101916
This commit is contained in:
parent
72f9377893
commit
40c1d5f854
9 changed files with 190 additions and 119 deletions
|
@ -1,3 +1,18 @@
|
|||
2005-07-12 Adrian Straetling <straetling@de.ibm.com>
|
||||
|
||||
* builtins.c: (expand_builtin_memcmp, expand_builtin_strncmp):
|
||||
s/cmpstrsi/cmpstrnsi
|
||||
(expand_builtin_strcmp): Rewrite to support both 'cmpstrsi' and
|
||||
'cmpstrnsi'.
|
||||
* optabs.c: (prepare_cmp_insn): Add availability of 'cmpstrn'.
|
||||
(init_optabs): Initialize cmpstrn_optab.
|
||||
* optabs.h: (enum insn_code cmpstrn_optab): Declare.
|
||||
* genopinit.c: (optabs[]): Add 'cmpstrn' to initialisation.
|
||||
* expr.c: (enum insn_code cmpstrn_optab): Declare.
|
||||
* config/i386/i386.md: s/cmpstr/cmpstrn
|
||||
* config/c4x/c4x.md: s/cmpstr/cmpstrn
|
||||
* doc/md.texi: Update documentation.
|
||||
|
||||
2005-07-11 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* config/alpha/alpha.c (alpha_gimplify_va_arg_1): Use
|
||||
|
|
229
gcc/builtins.c
229
gcc/builtins.c
|
@ -3449,7 +3449,7 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
|
|||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
#if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi
|
||||
#if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
|
||||
{
|
||||
tree arg1 = TREE_VALUE (arglist);
|
||||
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
|
@ -3469,9 +3469,9 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
|
|||
insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_cmpstrsi
|
||||
if (HAVE_cmpstrsi)
|
||||
insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
|
||||
#ifdef HAVE_cmpstrnsi
|
||||
if (HAVE_cmpstrnsi)
|
||||
insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
|
||||
else
|
||||
#endif
|
||||
return 0;
|
||||
|
@ -3504,10 +3504,10 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
|
|||
GEN_INT (MIN (arg1_align, arg2_align)));
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_cmpstrsi
|
||||
if (HAVE_cmpstrsi)
|
||||
insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
|
||||
GEN_INT (MIN (arg1_align, arg2_align)));
|
||||
#ifdef HAVE_cmpstrnsi
|
||||
if (HAVE_cmpstrnsi)
|
||||
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
|
||||
GEN_INT (MIN (arg1_align, arg2_align)));
|
||||
else
|
||||
#endif
|
||||
gcc_unreachable ();
|
||||
|
@ -3558,103 +3558,134 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
|
|||
return expand_expr (result, target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
|
||||
if (cmpstr_optab[SImode] != CODE_FOR_nothing
|
||||
|| cmpstrn_optab[SImode] != CODE_FOR_nothing)
|
||||
{
|
||||
rtx arg1_rtx, arg2_rtx;
|
||||
rtx result, insn = NULL_RTX;
|
||||
tree fndecl, fn;
|
||||
|
||||
tree arg1 = TREE_VALUE (arglist);
|
||||
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
int arg1_align
|
||||
= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
|
||||
int arg2_align
|
||||
= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
|
||||
|
||||
/* If we don't have POINTER_TYPE, call the function. */
|
||||
if (arg1_align == 0 || arg2_align == 0)
|
||||
return 0;
|
||||
|
||||
/* Stabilize the arguments in case gen_cmpstr(n)si fail. */
|
||||
arg1 = builtin_save_expr (arg1);
|
||||
arg2 = builtin_save_expr (arg2);
|
||||
|
||||
arg1_rtx = get_memory_rtx (arg1);
|
||||
arg2_rtx = get_memory_rtx (arg2);
|
||||
|
||||
#ifdef HAVE_cmpstrsi
|
||||
if (HAVE_cmpstrsi)
|
||||
{
|
||||
tree arg1 = TREE_VALUE (arglist);
|
||||
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
tree len, len1, len2;
|
||||
rtx arg1_rtx, arg2_rtx, arg3_rtx;
|
||||
rtx result, insn;
|
||||
tree fndecl, fn;
|
||||
/* Try to call cmpstrsi. */
|
||||
if (HAVE_cmpstrsi)
|
||||
{
|
||||
enum machine_mode insn_mode
|
||||
= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
|
||||
|
||||
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;
|
||||
/* 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);
|
||||
|
||||
len1 = c_strlen (arg1, 1);
|
||||
len2 = c_strlen (arg2, 1);
|
||||
insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
|
||||
GEN_INT (MIN (arg1_align, arg2_align)));
|
||||
}
|
||||
#endif
|
||||
#if HAVE_cmpstrnsi
|
||||
/* Try to determine at least one length and call cmpstrnsi. */
|
||||
if (!insn && HAVE_cmpstrnsi)
|
||||
{
|
||||
tree len;
|
||||
rtx arg3_rtx;
|
||||
|
||||
if (len1)
|
||||
len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
|
||||
if (len2)
|
||||
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
|
||||
enum machine_mode insn_mode
|
||||
= insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
|
||||
tree len1 = c_strlen (arg1, 1);
|
||||
tree len2 = c_strlen (arg2, 1);
|
||||
|
||||
/* 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)
|
||||
len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
|
||||
if (len2)
|
||||
len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
|
||||
|
||||
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 strings have constant lengths,
|
||||
use the smaller. */
|
||||
|
||||
/* If both arguments have side effects, we cannot optimize. */
|
||||
if (!len || TREE_SIDE_EFFECTS (len))
|
||||
return 0;
|
||||
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 POINTER_TYPE, call the function. */
|
||||
if (arg1_align == 0 || arg2_align == 0)
|
||||
return 0;
|
||||
/* If both arguments have side effects, we cannot optimize. */
|
||||
if (!len || TREE_SIDE_EFFECTS (len))
|
||||
return 0;
|
||||
|
||||
/* 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. */
|
||||
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
|
||||
|
||||
/* Stabilize the arguments in case gen_cmpstrsi fails. */
|
||||
arg1 = builtin_save_expr (arg1);
|
||||
arg2 = builtin_save_expr (arg2);
|
||||
/* 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);
|
||||
|
||||
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)
|
||||
{
|
||||
emit_insn (insn);
|
||||
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
|
||||
GEN_INT (MIN (arg1_align, arg2_align)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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;
|
||||
}
|
||||
if (insn)
|
||||
{
|
||||
emit_insn (insn);
|
||||
|
||||
/* Expand the library call ourselves using a stabilized argument
|
||||
list to avoid re-evaluating the function's arguments twice. */
|
||||
arglist = build_tree_list (NULL_TREE, arg2);
|
||||
arglist = tree_cons (NULL_TREE, arg1, arglist);
|
||||
fndecl = get_callee_fndecl (exp);
|
||||
fn = build_function_call_expr (fndecl, arglist);
|
||||
if (TREE_CODE (fn) == CALL_EXPR)
|
||||
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
|
||||
return expand_call (fn, target, target == const0_rtx);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Expand the library call ourselves using a stabilized argument
|
||||
list to avoid re-evaluating the function's arguments twice. */
|
||||
arglist = build_tree_list (NULL_TREE, arg2);
|
||||
arglist = tree_cons (NULL_TREE, arg1, arglist);
|
||||
fndecl = get_callee_fndecl (exp);
|
||||
fn = build_function_call_expr (fndecl, arglist);
|
||||
if (TREE_CODE (fn) == CALL_EXPR)
|
||||
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
|
||||
return expand_call (fn, target, target == const0_rtx);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -3679,10 +3710,10 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
|
|||
}
|
||||
|
||||
/* If c_strlen can determine an expression for one of the string
|
||||
lengths, and it doesn't have side effects, then emit cmpstrsi
|
||||
lengths, and it doesn't have side effects, then emit cmpstrnsi
|
||||
using length MIN(strlen(string)+1, arg3). */
|
||||
#ifdef HAVE_cmpstrsi
|
||||
if (HAVE_cmpstrsi)
|
||||
#ifdef HAVE_cmpstrnsi
|
||||
if (HAVE_cmpstrnsi)
|
||||
{
|
||||
tree arg1 = TREE_VALUE (arglist);
|
||||
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
|
||||
|
@ -3697,7 +3728,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
|
|||
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;
|
||||
= insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
|
||||
|
||||
len1 = c_strlen (arg1, 1);
|
||||
len2 = c_strlen (arg2, 1);
|
||||
|
@ -3750,7 +3781,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
|
|||
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
|
||||
result = gen_reg_rtx (insn_mode);
|
||||
|
||||
/* Stabilize the arguments in case gen_cmpstrsi fails. */
|
||||
/* Stabilize the arguments in case gen_cmpstrnsi fails. */
|
||||
arg1 = builtin_save_expr (arg1);
|
||||
arg2 = builtin_save_expr (arg2);
|
||||
len = builtin_save_expr (len);
|
||||
|
@ -3758,8 +3789,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode 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)));
|
||||
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
|
||||
GEN_INT (MIN (arg1_align, arg2_align)));
|
||||
if (insn)
|
||||
{
|
||||
emit_insn (insn);
|
||||
|
|
|
@ -5714,7 +5714,7 @@
|
|||
}")
|
||||
|
||||
|
||||
(define_insn "*cmpstrqi"
|
||||
(define_insn "*cmpstrnqi"
|
||||
[(set (match_operand:QI 0 "ext_reg_operand" "=d")
|
||||
(compare:QI (mem:BLK (match_operand:QI 1 "addr_reg_operand" "+a"))
|
||||
(mem:BLK (match_operand:QI 2 "addr_reg_operand" "+a"))))
|
||||
|
@ -5731,7 +5731,7 @@
|
|||
return \"\";
|
||||
}")
|
||||
|
||||
(define_expand "cmpstrqi"
|
||||
(define_expand "cmpstrnqi"
|
||||
[(parallel [(set (match_operand:QI 0 "reg_operand" "")
|
||||
(compare:QI (match_operand:BLK 1 "general_operand" "")
|
||||
(match_operand:BLK 2 "general_operand" "")))
|
||||
|
|
|
@ -17446,7 +17446,7 @@
|
|||
(set_attr "memory" "store")
|
||||
(set_attr "mode" "QI")])
|
||||
|
||||
(define_expand "cmpstrsi"
|
||||
(define_expand "cmpstrnsi"
|
||||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(compare:SI (match_operand:BLK 1 "general_operand" "")
|
||||
(match_operand:BLK 2 "general_operand" "")))
|
||||
|
@ -17487,8 +17487,8 @@
|
|||
emit_move_insn (operands[0], const0_rtx);
|
||||
DONE;
|
||||
}
|
||||
emit_insn (gen_cmpstrqi_nz_1 (addr1, addr2, countreg, align,
|
||||
operands[1], operands[2]));
|
||||
emit_insn (gen_cmpstrnqi_nz_1 (addr1, addr2, countreg, align,
|
||||
operands[1], operands[2]));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -17496,8 +17496,8 @@
|
|||
emit_insn (gen_cmpdi_1_rex64 (countreg, countreg));
|
||||
else
|
||||
emit_insn (gen_cmpsi_1 (countreg, countreg));
|
||||
emit_insn (gen_cmpstrqi_1 (addr1, addr2, countreg, align,
|
||||
operands[1], operands[2]));
|
||||
emit_insn (gen_cmpstrnqi_1 (addr1, addr2, countreg, align,
|
||||
operands[1], operands[2]));
|
||||
}
|
||||
|
||||
outlow = gen_lowpart (QImode, out);
|
||||
|
@ -17528,7 +17528,7 @@
|
|||
;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is
|
||||
;; zero. Emit extra code to make sure that a zero-length compare is EQ.
|
||||
|
||||
(define_expand "cmpstrqi_nz_1"
|
||||
(define_expand "cmpstrnqi_nz_1"
|
||||
[(parallel [(set (reg:CC FLAGS_REG)
|
||||
(compare:CC (match_operand 4 "memory_operand" "")
|
||||
(match_operand 5 "memory_operand" "")))
|
||||
|
@ -17541,7 +17541,7 @@
|
|||
""
|
||||
"")
|
||||
|
||||
(define_insn "*cmpstrqi_nz_1"
|
||||
(define_insn "*cmpstrnqi_nz_1"
|
||||
[(set (reg:CC FLAGS_REG)
|
||||
(compare:CC (mem:BLK (match_operand:SI 4 "register_operand" "0"))
|
||||
(mem:BLK (match_operand:SI 5 "register_operand" "1"))))
|
||||
|
@ -17557,7 +17557,7 @@
|
|||
(set_attr "mode" "QI")
|
||||
(set_attr "prefix_rep" "1")])
|
||||
|
||||
(define_insn "*cmpstrqi_nz_rex_1"
|
||||
(define_insn "*cmpstrnqi_nz_rex_1"
|
||||
[(set (reg:CC FLAGS_REG)
|
||||
(compare:CC (mem:BLK (match_operand:DI 4 "register_operand" "0"))
|
||||
(mem:BLK (match_operand:DI 5 "register_operand" "1"))))
|
||||
|
@ -17575,7 +17575,7 @@
|
|||
|
||||
;; The same, but the count is not known to not be zero.
|
||||
|
||||
(define_expand "cmpstrqi_1"
|
||||
(define_expand "cmpstrnqi_1"
|
||||
[(parallel [(set (reg:CC FLAGS_REG)
|
||||
(if_then_else:CC (ne (match_operand 2 "register_operand" "")
|
||||
(const_int 0))
|
||||
|
@ -17591,7 +17591,7 @@
|
|||
""
|
||||
"")
|
||||
|
||||
(define_insn "*cmpstrqi_1"
|
||||
(define_insn "*cmpstrnqi_1"
|
||||
[(set (reg:CC FLAGS_REG)
|
||||
(if_then_else:CC (ne (match_operand:SI 6 "register_operand" "2")
|
||||
(const_int 0))
|
||||
|
@ -17610,7 +17610,7 @@
|
|||
(set_attr "mode" "QI")
|
||||
(set_attr "prefix_rep" "1")])
|
||||
|
||||
(define_insn "*cmpstrqi_rex_1"
|
||||
(define_insn "*cmpstrnqi_rex_1"
|
||||
[(set (reg:CC FLAGS_REG)
|
||||
(if_then_else:CC (ne (match_operand:DI 6 "register_operand" "2")
|
||||
(const_int 0))
|
||||
|
@ -17693,9 +17693,9 @@
|
|||
(set_attr "mode" "QI")
|
||||
(set_attr "prefix_rep" "1")])
|
||||
|
||||
;; Peephole optimizations to clean up after cmpstr*. This should be
|
||||
;; Peephole optimizations to clean up after cmpstrn*. This should be
|
||||
;; handled in combine, but it is not currently up to the task.
|
||||
;; When used for their truth value, the cmpstr* expanders generate
|
||||
;; When used for their truth value, the cmpstrn* expanders generate
|
||||
;; code like this:
|
||||
;;
|
||||
;; repz cmpsb
|
||||
|
@ -17706,7 +17706,7 @@
|
|||
;;
|
||||
;; The intermediate three instructions are unnecessary.
|
||||
|
||||
;; This one handles cmpstr*_nz_1...
|
||||
;; This one handles cmpstrn*_nz_1...
|
||||
(define_peephole2
|
||||
[(parallel[
|
||||
(set (reg:CC FLAGS_REG)
|
||||
|
@ -17738,7 +17738,7 @@
|
|||
(clobber (match_dup 2))])]
|
||||
"")
|
||||
|
||||
;; ...and this one handles cmpstr*_1.
|
||||
;; ...and this one handles cmpstrn*_1.
|
||||
(define_peephole2
|
||||
[(parallel[
|
||||
(set (reg:CC FLAGS_REG)
|
||||
|
|
|
@ -3269,8 +3269,8 @@ operand.
|
|||
|
||||
The use for multiple @code{setmem@var{m}} is as for @code{movmem@var{m}}.
|
||||
|
||||
@cindex @code{cmpstr@var{m}} instruction pattern
|
||||
@item @samp{cmpstr@var{m}}
|
||||
@cindex @code{cmpstrn@var{m}} instruction pattern
|
||||
@item @samp{cmpstrn@var{m}}
|
||||
String compare instruction, with five operands. Operand 0 is the output;
|
||||
it has mode @var{m}. The remaining four operands are like the operands
|
||||
of @samp{movmem@var{m}}. The two memory blocks specified are compared
|
||||
|
@ -3281,6 +3281,25 @@ that may access an invalid page or segment and cause a fault. The
|
|||
effect of the instruction is to store a value in operand 0 whose sign
|
||||
indicates the result of the comparison.
|
||||
|
||||
@cindex @code{cmpstr@var{m}} instruction pattern
|
||||
@item @samp{cmpstr@var{m}}
|
||||
String compare instruction, without known maximum length. Operand 0 is the
|
||||
output; it has mode @var{m}. The second and third operand are the blocks of
|
||||
memory to be compared; both are @code{mem:BLK} with an address in mode
|
||||
@code{Pmode}.
|
||||
|
||||
The fourth operand is the known shared alignment of the source and
|
||||
destination, in the form of a @code{const_int} rtx. Thus, if the
|
||||
compiler knows that both source and destination are word-aligned,
|
||||
it may provide the value 4 for this operand.
|
||||
|
||||
The two memory blocks specified are compared byte by byte in lexicographic
|
||||
order starting at the beginning of each string. The instruction is not allowed
|
||||
to prefetch more than one byte at a time since either string may end in the
|
||||
first byte and reading past that may access an invalid page or segment and
|
||||
cause a fault. The effect of the instruction is to store a value in operand 0
|
||||
whose sign indicates the result of the comparison.
|
||||
|
||||
@cindex @code{cmpmem@var{m}} instruction pattern
|
||||
@item @samp{cmpmem@var{m}}
|
||||
Block compare instruction, with five operands like the operands
|
||||
|
|
|
@ -202,9 +202,10 @@ enum insn_code movmem_optab[NUM_MACHINE_MODES];
|
|||
/* This array records the insn_code of insns to perform block sets. */
|
||||
enum insn_code setmem_optab[NUM_MACHINE_MODES];
|
||||
|
||||
/* These arrays record the insn_code of two different kinds of insns
|
||||
/* These arrays record the insn_code of three different kinds of insns
|
||||
to perform block compares. */
|
||||
enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
|
||||
enum insn_code cmpstrn_optab[NUM_MACHINE_MODES];
|
||||
enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
|
||||
|
||||
/* Synchronization primitives. */
|
||||
|
|
|
@ -169,6 +169,7 @@ static const char * const optabs[] =
|
|||
"reload_out_optab[$A] = CODE_FOR_$(reload_out$a$)",
|
||||
"movmem_optab[$A] = CODE_FOR_$(movmem$a$)",
|
||||
"cmpstr_optab[$A] = CODE_FOR_$(cmpstr$a$)",
|
||||
"cmpstrn_optab[$A] = CODE_FOR_$(cmpstrn$a$)",
|
||||
"cmpmem_optab[$A] = CODE_FOR_$(cmpmem$a$)",
|
||||
"setmem_optab[$A] = CODE_FOR_$(setmem$a$)",
|
||||
"sync_add_optab[$A] = CODE_FOR_$(sync_add$I$a$)",
|
||||
|
|
|
@ -3425,6 +3425,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
|
|||
cmp_code = cmpmem_optab[cmp_mode];
|
||||
if (cmp_code == CODE_FOR_nothing)
|
||||
cmp_code = cmpstr_optab[cmp_mode];
|
||||
if (cmp_code == CODE_FOR_nothing)
|
||||
cmp_code = cmpstrn_optab[cmp_mode];
|
||||
if (cmp_code == CODE_FOR_nothing)
|
||||
continue;
|
||||
|
||||
|
@ -5090,6 +5092,7 @@ init_optabs (void)
|
|||
{
|
||||
movmem_optab[i] = CODE_FOR_nothing;
|
||||
cmpstr_optab[i] = CODE_FOR_nothing;
|
||||
cmpstrn_optab[i] = CODE_FOR_nothing;
|
||||
cmpmem_optab[i] = CODE_FOR_nothing;
|
||||
setmem_optab[i] = CODE_FOR_nothing;
|
||||
|
||||
|
|
|
@ -450,6 +450,7 @@ extern enum insn_code setmem_optab[NUM_MACHINE_MODES];
|
|||
/* These arrays record the insn_code of two different kinds of insns
|
||||
to perform block compares. */
|
||||
extern enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
|
||||
extern enum insn_code cmpstrn_optab[NUM_MACHINE_MODES];
|
||||
extern enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
|
||||
|
||||
/* Synchronization primitives. This first set is atomic operation for
|
||||
|
|
Loading…
Add table
Reference in a new issue