This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] builtin_strcmp (standard names cmpstrsi, cmpstrnsi)
- From: Adrian Straetling <straetling at de dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org, "Weigand, Ulrich" <uweigand at de dot ibm dot com>, rth at redhat dot com, m dot hayes at elec dot canterbury dot ac dot nz
- Date: Thu, 7 Jul 2005 23:32:01 +0200
- Subject: [patch] builtin_strcmp (standard names cmpstrsi, cmpstrnsi)
Hi,
trying to implement hardware support for strcmp I found
out, that the present 'cmpstr' pattern is actually a strncmp. The
middle-end will only call it if such an n is either given, or can be
deduced from a constant string that is part of the comparison.
The S/390 string compare instruction makes no use of the length
parameter, which disqualifies it for the strncmp but not for strcmp.
Unfortunately the existing 'cmpstr' pattern does not tell the backend
whether the passed length is from an strncmp call, in which case s390
would have to fail, or calculated from the middle end to support strcmp
for targets that need the length (i386/c4x).
This patch implements the folowing solution for this problem:
1: Rename the existing 'cmpstr' to 'cmpstrn' not changing the existing
semantics.
2: Add a new 'cmpstr' which not needs a length parameter, but is
otherwise equal to 'cmpstrn'.
3: For "expand_builtin_strcmp": Try 'cmpstr' if present. Afterwards try
to compute length and call 'cmpstrn' if present. Fall back to libcall if
neither worked.
Patch for s390 will follow when regtest completed.
This one bootstrapped and shows no regressions on both s390 and i686.
Ok for mainline?
Bye,
Adrian
2005-07-06 Adrian Strätling <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.
Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c.orig 2005-07-07 15:34:16.808821413 +0200
--- gcc/builtins.c 2005-07-07 16:11:14.138821413 +0200
*************** expand_builtin_memcmp (tree exp ATTRIBUT
*** 3449,3455 ****
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
! #if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi
{
tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
--- 3449,3455 ----
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
! #if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
{
tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
*************** expand_builtin_memcmp (tree exp ATTRIBUT
*** 3469,3477 ****
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;
else
#endif
return 0;
--- 3469,3477 ----
insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
else
#endif
! #ifdef HAVE_cmpstrnsi
! if (HAVE_cmpstrnsi)
! insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
else
#endif
return 0;
*************** expand_builtin_memcmp (tree exp ATTRIBUT
*** 3504,3513 ****
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)));
else
#endif
gcc_unreachable ();
--- 3504,3513 ----
GEN_INT (MIN (arg1_align, arg2_align)));
else
#endif
! #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 ();
*************** expand_builtin_strcmp (tree exp, rtx tar
*** 3558,3660 ****
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
! #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;
!
! 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;
!
! len1 = c_strlen (arg1, 1);
! len2 = c_strlen (arg2, 1);
! 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 both arguments have side effects, we cannot optimize. */
! if (!len || TREE_SIDE_EFFECTS (len))
! return 0;
! /* 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
! && 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_cmpstrsi fails. */
! arg1 = builtin_save_expr (arg1);
! arg2 = builtin_save_expr (arg2);
! 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);
! /* 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;
}
--- 3558,3691 ----
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
! /* Try to call cmpstrsi. */
! if (HAVE_cmpstrsi)
! {
! 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);
! 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;
!
! 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 (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 both arguments have side effects, we cannot optimize. */
! if (!len || TREE_SIDE_EFFECTS (len))
! return 0;
! /* Stabilize the arguments in case gen_cmpstrnsi fails. */
! arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 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);
! insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
! GEN_INT (MIN (arg1_align, arg2_align)));
! }
! #endif
! if (insn)
! {
! 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;
! }
!
! /* 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;
}
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3679,3688 ****
}
/* If c_strlen can determine an expression for one of the string
! 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 arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
--- 3710,3719 ----
}
/* If c_strlen can determine an expression for one of the string
! lengths, and it doesn't have side effects, then emit cmpstrnsi
using length MIN(strlen(string)+1, arg3). */
! #ifdef HAVE_cmpstrnsi
! if (HAVE_cmpstrnsi)
{
tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3697,3703 ****
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;
len1 = c_strlen (arg1, 1);
len2 = c_strlen (arg2, 1);
--- 3728,3734 ----
int arg2_align
= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
enum machine_mode insn_mode
! = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
len1 = c_strlen (arg1, 1);
len2 = c_strlen (arg2, 1);
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3750,3756 ****
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
! /* Stabilize the arguments in case gen_cmpstrsi fails. */
arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2);
len = builtin_save_expr (len);
--- 3781,3787 ----
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
! /* Stabilize the arguments in case gen_cmpstrnsi fails. */
arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2);
len = builtin_save_expr (len);
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3758,3765 ****
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);
--- 3789,3796 ----
arg1_rtx = get_memory_rtx (arg1);
arg2_rtx = get_memory_rtx (arg2);
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
! insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
! GEN_INT (MIN (arg1_align, arg2_align)));
if (insn)
{
emit_insn (insn);
Index: gcc/optabs.c
===================================================================
*** gcc/optabs.c.orig 2005-07-07 15:34:16.808821413 +0200
--- gcc/optabs.c 2005-07-07 15:34:21.978821413 +0200
*************** prepare_cmp_insn (rtx *px, rtx *py, enum
*** 3475,3480 ****
--- 3475,3482 ----
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;
/* Must make sure the size fits the insn's mode. */
*************** init_optabs (void)
*** 5163,5168 ****
--- 5165,5171 ----
{
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;
Index: gcc/optabs.h
===================================================================
*** gcc/optabs.h.orig 2005-07-07 15:34:16.808821413 +0200
--- gcc/optabs.h 2005-07-07 15:34:21.978821413 +0200
*************** extern enum insn_code setmem_optab[NUM_M
*** 450,455 ****
--- 450,456 ----
/* 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
Index: gcc/genopinit.c
===================================================================
*** gcc/genopinit.c.orig 2005-07-07 15:34:16.808821413 +0200
--- gcc/genopinit.c 2005-07-07 15:34:21.978821413 +0200
*************** static const char * const optabs[] =
*** 169,174 ****
--- 169,175 ----
"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$)",
Index: gcc/expr.c
===================================================================
*** gcc/expr.c.orig 2005-07-07 15:34:16.818821413 +0200
--- gcc/expr.c 2005-07-07 15:34:21.998821413 +0200
*************** enum insn_code movmem_optab[NUM_MACHINE_
*** 202,210 ****
/* 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
to perform block compares. */
enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
/* Synchronization primitives. */
--- 202,211 ----
/* 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 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. */
Index: gcc/config/i386/i386.md
===================================================================
*** gcc/config/i386/i386.md.orig 2005-07-07 15:34:16.808821413 +0200
--- gcc/config/i386/i386.md 2005-07-07 15:34:22.018821413 +0200
***************
*** 17442,17448 ****
(set_attr "memory" "store")
(set_attr "mode" "QI")])
! (define_expand "cmpstrsi"
[(set (match_operand:SI 0 "register_operand" "")
(compare:SI (match_operand:BLK 1 "general_operand" "")
(match_operand:BLK 2 "general_operand" "")))
--- 17442,17448 ----
(set_attr "memory" "store")
(set_attr "mode" "QI")])
! (define_expand "cmpstrnsi"
[(set (match_operand:SI 0 "register_operand" "")
(compare:SI (match_operand:BLK 1 "general_operand" "")
(match_operand:BLK 2 "general_operand" "")))
***************
*** 17483,17490 ****
emit_move_insn (operands[0], const0_rtx);
DONE;
}
! emit_insn (gen_cmpstrqi_nz_1 (addr1, addr2, countreg, align,
! operands[1], operands[2]));
}
else
{
--- 17483,17490 ----
emit_move_insn (operands[0], const0_rtx);
DONE;
}
! emit_insn (gen_cmpstrnqi_nz_1 (addr1, addr2, countreg, align,
! operands[1], operands[2]));
}
else
{
***************
*** 17492,17499 ****
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]));
}
outlow = gen_lowpart (QImode, out);
--- 17492,17499 ----
emit_insn (gen_cmpdi_1_rex64 (countreg, countreg));
else
emit_insn (gen_cmpsi_1 (countreg, countreg));
! emit_insn (gen_cmpstrnqi_1 (addr1, addr2, countreg, align,
! operands[1], operands[2]));
}
outlow = gen_lowpart (QImode, out);
***************
*** 17524,17530 ****
;; 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"
[(parallel [(set (reg:CC FLAGS_REG)
(compare:CC (match_operand 4 "memory_operand" "")
(match_operand 5 "memory_operand" "")))
--- 17524,17530 ----
;; 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 "cmpstrnqi_nz_1"
[(parallel [(set (reg:CC FLAGS_REG)
(compare:CC (match_operand 4 "memory_operand" "")
(match_operand 5 "memory_operand" "")))
***************
*** 17537,17543 ****
""
"")
! (define_insn "*cmpstrqi_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"))))
--- 17537,17543 ----
""
"")
! (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"))))
***************
*** 17553,17559 ****
(set_attr "mode" "QI")
(set_attr "prefix_rep" "1")])
! (define_insn "*cmpstrqi_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"))))
--- 17553,17559 ----
(set_attr "mode" "QI")
(set_attr "prefix_rep" "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"))))
***************
*** 17571,17577 ****
;; The same, but the count is not known to not be zero.
! (define_expand "cmpstrqi_1"
[(parallel [(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand 2 "register_operand" "")
(const_int 0))
--- 17571,17577 ----
;; The same, but the count is not known to not be zero.
! (define_expand "cmpstrnqi_1"
[(parallel [(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand 2 "register_operand" "")
(const_int 0))
***************
*** 17587,17593 ****
""
"")
! (define_insn "*cmpstrqi_1"
[(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand:SI 6 "register_operand" "2")
(const_int 0))
--- 17587,17593 ----
""
"")
! (define_insn "*cmpstrnqi_1"
[(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand:SI 6 "register_operand" "2")
(const_int 0))
***************
*** 17606,17612 ****
(set_attr "mode" "QI")
(set_attr "prefix_rep" "1")])
! (define_insn "*cmpstrqi_rex_1"
[(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand:DI 6 "register_operand" "2")
(const_int 0))
--- 17606,17612 ----
(set_attr "mode" "QI")
(set_attr "prefix_rep" "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))
***************
*** 17689,17697 ****
(set_attr "mode" "QI")
(set_attr "prefix_rep" "1")])
! ;; Peephole optimizations to clean up after cmpstr*. 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
;; code like this:
;;
;; repz cmpsb
--- 17689,17697 ----
(set_attr "mode" "QI")
(set_attr "prefix_rep" "1")])
! ;; 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 cmpstrn* expanders generate
;; code like this:
;;
;; repz cmpsb
***************
*** 17702,17708 ****
;;
;; The intermediate three instructions are unnecessary.
! ;; This one handles cmpstr*_nz_1...
(define_peephole2
[(parallel[
(set (reg:CC FLAGS_REG)
--- 17702,17708 ----
;;
;; The intermediate three instructions are unnecessary.
! ;; This one handles cmpstrn*_nz_1...
(define_peephole2
[(parallel[
(set (reg:CC FLAGS_REG)
***************
*** 17734,17740 ****
(clobber (match_dup 2))])]
"")
! ;; ...and this one handles cmpstr*_1.
(define_peephole2
[(parallel[
(set (reg:CC FLAGS_REG)
--- 17734,17740 ----
(clobber (match_dup 2))])]
"")
! ;; ...and this one handles cmpstrn*_1.
(define_peephole2
[(parallel[
(set (reg:CC FLAGS_REG)
Index: gcc/config/c4x/c4x.md
===================================================================
*** gcc/config/c4x/c4x.md.orig 2005-07-07 15:34:16.808821413 +0200
--- gcc/config/c4x/c4x.md 2005-07-07 15:34:22.028821413 +0200
***************
*** 5714,5720 ****
}")
! (define_insn "*cmpstrqi"
[(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"))))
--- 5714,5720 ----
}")
! (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,5737 ****
return \"\";
}")
! (define_expand "cmpstrqi"
[(parallel [(set (match_operand:QI 0 "reg_operand" "")
(compare:QI (match_operand:BLK 1 "general_operand" "")
(match_operand:BLK 2 "general_operand" "")))
--- 5731,5737 ----
return \"\";
}")
! (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" "")))
Index: gcc/doc/md.texi
===================================================================
*** gcc/doc/md.texi.orig 2005-07-07 15:54:55.828821413 +0200
--- gcc/doc/md.texi 2005-07-07 15:56:09.288821413 +0200
*************** operand.
*** 3269,3276 ****
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}}
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
--- 3269,3276 ----
The use for multiple @code{setmem@var{m}} is as for @code{movmem@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
*************** that may access an invalid page or segme
*** 3281,3286 ****
--- 3281,3305 ----
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