Commit 40c1d5f8 by Adrian Straetling Committed by Ulrich Weigand

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
parent 72f93778
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> 2005-07-11 Richard Henderson <rth@redhat.com>
* config/alpha/alpha.c (alpha_gimplify_va_arg_1): Use * config/alpha/alpha.c (alpha_gimplify_va_arg_1): Use
......
...@@ -3449,7 +3449,7 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, ...@@ -3449,7 +3449,7 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
return expand_expr (result, target, mode, EXPAND_NORMAL); 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 arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
...@@ -3469,9 +3469,9 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, ...@@ -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; insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
else else
#endif #endif
#ifdef HAVE_cmpstrsi #ifdef HAVE_cmpstrnsi
if (HAVE_cmpstrsi) if (HAVE_cmpstrnsi)
insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
else else
#endif #endif
return 0; return 0;
...@@ -3504,10 +3504,10 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, ...@@ -3504,10 +3504,10 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
GEN_INT (MIN (arg1_align, arg2_align))); GEN_INT (MIN (arg1_align, arg2_align)));
else else
#endif #endif
#ifdef HAVE_cmpstrsi #ifdef HAVE_cmpstrnsi
if (HAVE_cmpstrsi) if (HAVE_cmpstrnsi)
insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align))); GEN_INT (MIN (arg1_align, arg2_align)));
else else
#endif #endif
gcc_unreachable (); gcc_unreachable ();
...@@ -3558,103 +3558,134 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) ...@@ -3558,103 +3558,134 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
return expand_expr (result, target, mode, EXPAND_NORMAL); return expand_expr (result, target, mode, EXPAND_NORMAL);
} }
#ifdef HAVE_cmpstrsi #if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
if (HAVE_cmpstrsi) if (cmpstr_optab[SImode] != CODE_FOR_nothing
{ || cmpstrn_optab[SImode] != CODE_FOR_nothing)
tree arg1 = TREE_VALUE (arglist); {
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); rtx arg1_rtx, arg2_rtx;
tree len, len1, len2; rtx result, insn = NULL_RTX;
rtx arg1_rtx, arg2_rtx, arg3_rtx; tree fndecl, fn;
rtx result, insn;
tree fndecl, fn; tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
int arg1_align int arg1_align
= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
int arg2_align int arg2_align
= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
enum machine_mode insn_mode
= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; /* If we don't have POINTER_TYPE, call the function. */
if (arg1_align == 0 || arg2_align == 0)
return 0;
len1 = c_strlen (arg1, 1); /* Stabilize the arguments in case gen_cmpstr(n)si fail. */
len2 = c_strlen (arg2, 1); arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2);
if (len1) arg1_rtx = get_memory_rtx (arg1);
len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); arg2_rtx = get_memory_rtx (arg2);
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 #ifdef HAVE_cmpstrsi
of the second, if we know it. We don't require a constant for /* Try to call cmpstrsi. */
this case; some cost analysis could be done if both are available if (HAVE_cmpstrsi)
but neither is constant. For now, assume they're equally cheap, {
unless one has side effects. If both strings have constant lengths, enum machine_mode insn_mode
use the smaller. */ = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
if (!len1) /* Make a place to write the result of the instruction. */
len = len2; result = target;
else if (!len2) if (! (result != 0
len = len1; && REG_P (result) && GET_MODE (result) == insn_mode
else if (TREE_SIDE_EFFECTS (len1)) && REGNO (result) >= FIRST_PSEUDO_REGISTER))
len = len2; result = gen_reg_rtx (insn_mode);
else if (TREE_SIDE_EFFECTS (len2))
len = len1; insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
else if (TREE_CODE (len1) != INTEGER_CST) GEN_INT (MIN (arg1_align, arg2_align)));
len = len2; }
else if (TREE_CODE (len2) != INTEGER_CST) #endif
len = len1; #if HAVE_cmpstrnsi
else if (tree_int_cst_lt (len1, len2)) /* Try to determine at least one length and call cmpstrnsi. */
len = len1; if (!insn && HAVE_cmpstrnsi)
else {
len = len2; 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 both arguments have side effects, we cannot optimize. */
if (!len || TREE_SIDE_EFFECTS (len)) if (!len || TREE_SIDE_EFFECTS (len))
return 0; return 0;
/* If we don't have POINTER_TYPE, call the function. */ /* Stabilize the arguments in case gen_cmpstrnsi fails. */
if (arg1_align == 0 || arg2_align == 0) arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
return 0;
/* Make a place to write the result of the instruction. */ /* Make a place to write the result of the instruction. */
result = target; result = target;
if (! (result != 0 if (! (result != 0
&& REG_P (result) && GET_MODE (result) == insn_mode && REG_P (result) && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER)) && REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode); result = gen_reg_rtx (insn_mode);
/* Stabilize the arguments in case gen_cmpstrsi fails. */ insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
arg1 = builtin_save_expr (arg1); GEN_INT (MIN (arg1_align, arg2_align)));
arg2 = builtin_save_expr (arg2); }
#endif
arg1_rtx = get_memory_rtx (arg1); if (insn)
arg2_rtx = get_memory_rtx (arg2); {
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); emit_insn (insn);
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. */ /* 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)
return result; return result;
if (target == 0) if (target == 0)
return convert_to_mode (mode, result, 0); return convert_to_mode (mode, result, 0);
convert_move (target, result, 0); convert_move (target, result, 0);
return target; return 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. */
arglist = build_tree_list (NULL_TREE, arg2); arglist = build_tree_list (NULL_TREE, arg2);
arglist = tree_cons (NULL_TREE, arg1, arglist); arglist = tree_cons (NULL_TREE, arg1, arglist);
fndecl = get_callee_fndecl (exp); fndecl = get_callee_fndecl (exp);
fn = build_function_call_expr (fndecl, arglist); fn = build_function_call_expr (fndecl, arglist);
if (TREE_CODE (fn) == CALL_EXPR) if (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 #endif
return 0; return 0;
} }
...@@ -3679,10 +3710,10 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) ...@@ -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 /* 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). */ using length MIN(strlen(string)+1, arg3). */
#ifdef HAVE_cmpstrsi #ifdef HAVE_cmpstrnsi
if (HAVE_cmpstrsi) if (HAVE_cmpstrnsi)
{ {
tree arg1 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
...@@ -3697,7 +3728,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) ...@@ -3697,7 +3728,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
int arg2_align int arg2_align
= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
enum machine_mode insn_mode 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); len1 = c_strlen (arg1, 1);
len2 = c_strlen (arg2, 1); len2 = c_strlen (arg2, 1);
...@@ -3750,7 +3781,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) ...@@ -3750,7 +3781,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
&& REGNO (result) >= FIRST_PSEUDO_REGISTER)) && REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode); 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); arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2); arg2 = builtin_save_expr (arg2);
len = builtin_save_expr (len); len = builtin_save_expr (len);
...@@ -3758,8 +3789,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) ...@@ -3758,8 +3789,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
arg1_rtx = get_memory_rtx (arg1); arg1_rtx = get_memory_rtx (arg1);
arg2_rtx = get_memory_rtx (arg2); arg2_rtx = get_memory_rtx (arg2);
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align))); GEN_INT (MIN (arg1_align, arg2_align)));
if (insn) if (insn)
{ {
emit_insn (insn); emit_insn (insn);
......
...@@ -5714,7 +5714,7 @@ ...@@ -5714,7 +5714,7 @@
}") }")
(define_insn "*cmpstrqi" (define_insn "*cmpstrnqi"
[(set (match_operand:QI 0 "ext_reg_operand" "=d") [(set (match_operand:QI 0 "ext_reg_operand" "=d")
(compare:QI (mem:BLK (match_operand:QI 1 "addr_reg_operand" "+a")) (compare:QI (mem:BLK (match_operand:QI 1 "addr_reg_operand" "+a"))
(mem:BLK (match_operand:QI 2 "addr_reg_operand" "+a")))) (mem:BLK (match_operand:QI 2 "addr_reg_operand" "+a"))))
...@@ -5731,7 +5731,7 @@ ...@@ -5731,7 +5731,7 @@
return \"\"; return \"\";
}") }")
(define_expand "cmpstrqi" (define_expand "cmpstrnqi"
[(parallel [(set (match_operand:QI 0 "reg_operand" "") [(parallel [(set (match_operand:QI 0 "reg_operand" "")
(compare:QI (match_operand:BLK 1 "general_operand" "") (compare:QI (match_operand:BLK 1 "general_operand" "")
(match_operand:BLK 2 "general_operand" ""))) (match_operand:BLK 2 "general_operand" "")))
......
...@@ -17446,7 +17446,7 @@ ...@@ -17446,7 +17446,7 @@
(set_attr "memory" "store") (set_attr "memory" "store")
(set_attr "mode" "QI")]) (set_attr "mode" "QI")])
(define_expand "cmpstrsi" (define_expand "cmpstrnsi"
[(set (match_operand:SI 0 "register_operand" "") [(set (match_operand:SI 0 "register_operand" "")
(compare:SI (match_operand:BLK 1 "general_operand" "") (compare:SI (match_operand:BLK 1 "general_operand" "")
(match_operand:BLK 2 "general_operand" ""))) (match_operand:BLK 2 "general_operand" "")))
...@@ -17487,8 +17487,8 @@ ...@@ -17487,8 +17487,8 @@
emit_move_insn (operands[0], const0_rtx); emit_move_insn (operands[0], const0_rtx);
DONE; DONE;
} }
emit_insn (gen_cmpstrqi_nz_1 (addr1, addr2, countreg, align, emit_insn (gen_cmpstrnqi_nz_1 (addr1, addr2, countreg, align,
operands[1], operands[2])); operands[1], operands[2]));
} }
else else
{ {
...@@ -17496,8 +17496,8 @@ ...@@ -17496,8 +17496,8 @@
emit_insn (gen_cmpdi_1_rex64 (countreg, countreg)); emit_insn (gen_cmpdi_1_rex64 (countreg, countreg));
else else
emit_insn (gen_cmpsi_1 (countreg, countreg)); emit_insn (gen_cmpsi_1 (countreg, countreg));
emit_insn (gen_cmpstrqi_1 (addr1, addr2, countreg, align, emit_insn (gen_cmpstrnqi_1 (addr1, addr2, countreg, align,
operands[1], operands[2])); operands[1], operands[2]));
} }
outlow = gen_lowpart (QImode, out); outlow = gen_lowpart (QImode, out);
...@@ -17528,7 +17528,7 @@ ...@@ -17528,7 +17528,7 @@
;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is ;; 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. ;; 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) [(parallel [(set (reg:CC FLAGS_REG)
(compare:CC (match_operand 4 "memory_operand" "") (compare:CC (match_operand 4 "memory_operand" "")
(match_operand 5 "memory_operand" ""))) (match_operand 5 "memory_operand" "")))
...@@ -17541,7 +17541,7 @@ ...@@ -17541,7 +17541,7 @@
"" ""
"") "")
(define_insn "*cmpstrqi_nz_1" (define_insn "*cmpstrnqi_nz_1"
[(set (reg:CC FLAGS_REG) [(set (reg:CC FLAGS_REG)
(compare:CC (mem:BLK (match_operand:SI 4 "register_operand" "0")) (compare:CC (mem:BLK (match_operand:SI 4 "register_operand" "0"))
(mem:BLK (match_operand:SI 5 "register_operand" "1")))) (mem:BLK (match_operand:SI 5 "register_operand" "1"))))
...@@ -17557,7 +17557,7 @@ ...@@ -17557,7 +17557,7 @@
(set_attr "mode" "QI") (set_attr "mode" "QI")
(set_attr "prefix_rep" "1")]) (set_attr "prefix_rep" "1")])
(define_insn "*cmpstrqi_nz_rex_1" (define_insn "*cmpstrnqi_nz_rex_1"
[(set (reg:CC FLAGS_REG) [(set (reg:CC FLAGS_REG)
(compare:CC (mem:BLK (match_operand:DI 4 "register_operand" "0")) (compare:CC (mem:BLK (match_operand:DI 4 "register_operand" "0"))
(mem:BLK (match_operand:DI 5 "register_operand" "1")))) (mem:BLK (match_operand:DI 5 "register_operand" "1"))))
...@@ -17575,7 +17575,7 @@ ...@@ -17575,7 +17575,7 @@
;; The same, but the count is not known to not be zero. ;; 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) [(parallel [(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand 2 "register_operand" "") (if_then_else:CC (ne (match_operand 2 "register_operand" "")
(const_int 0)) (const_int 0))
...@@ -17591,7 +17591,7 @@ ...@@ -17591,7 +17591,7 @@
"" ""
"") "")
(define_insn "*cmpstrqi_1" (define_insn "*cmpstrnqi_1"
[(set (reg:CC FLAGS_REG) [(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand:SI 6 "register_operand" "2") (if_then_else:CC (ne (match_operand:SI 6 "register_operand" "2")
(const_int 0)) (const_int 0))
...@@ -17610,7 +17610,7 @@ ...@@ -17610,7 +17610,7 @@
(set_attr "mode" "QI") (set_attr "mode" "QI")
(set_attr "prefix_rep" "1")]) (set_attr "prefix_rep" "1")])
(define_insn "*cmpstrqi_rex_1" (define_insn "*cmpstrnqi_rex_1"
[(set (reg:CC FLAGS_REG) [(set (reg:CC FLAGS_REG)
(if_then_else:CC (ne (match_operand:DI 6 "register_operand" "2") (if_then_else:CC (ne (match_operand:DI 6 "register_operand" "2")
(const_int 0)) (const_int 0))
...@@ -17693,9 +17693,9 @@ ...@@ -17693,9 +17693,9 @@
(set_attr "mode" "QI") (set_attr "mode" "QI")
(set_attr "prefix_rep" "1")]) (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. ;; 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: ;; code like this:
;; ;;
;; repz cmpsb ;; repz cmpsb
...@@ -17706,7 +17706,7 @@ ...@@ -17706,7 +17706,7 @@
;; ;;
;; The intermediate three instructions are unnecessary. ;; The intermediate three instructions are unnecessary.
;; This one handles cmpstr*_nz_1... ;; This one handles cmpstrn*_nz_1...
(define_peephole2 (define_peephole2
[(parallel[ [(parallel[
(set (reg:CC FLAGS_REG) (set (reg:CC FLAGS_REG)
...@@ -17738,7 +17738,7 @@ ...@@ -17738,7 +17738,7 @@
(clobber (match_dup 2))])] (clobber (match_dup 2))])]
"") "")
;; ...and this one handles cmpstr*_1. ;; ...and this one handles cmpstrn*_1.
(define_peephole2 (define_peephole2
[(parallel[ [(parallel[
(set (reg:CC FLAGS_REG) (set (reg:CC FLAGS_REG)
......
...@@ -3269,8 +3269,8 @@ operand. ...@@ -3269,8 +3269,8 @@ operand.
The use for multiple @code{setmem@var{m}} is as for @code{movmem@var{m}}. The use for multiple @code{setmem@var{m}} is as for @code{movmem@var{m}}.
@cindex @code{cmpstr@var{m}} instruction pattern @cindex @code{cmpstrn@var{m}} instruction pattern
@item @samp{cmpstr@var{m}} @item @samp{cmpstrn@var{m}}
String compare instruction, with five operands. Operand 0 is the output; String compare instruction, with five operands. Operand 0 is the output;
it has mode @var{m}. The remaining four operands are like the operands 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 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 ...@@ -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 effect of the instruction is to store a value in operand 0 whose sign
indicates the result of the comparison. 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 @cindex @code{cmpmem@var{m}} instruction pattern
@item @samp{cmpmem@var{m}} @item @samp{cmpmem@var{m}}
Block compare instruction, with five operands like the operands Block compare instruction, with five operands like the operands
......
...@@ -202,9 +202,10 @@ enum insn_code movmem_optab[NUM_MACHINE_MODES]; ...@@ -202,9 +202,10 @@ enum insn_code movmem_optab[NUM_MACHINE_MODES];
/* This array records the insn_code of insns to perform block sets. */ /* This array records the insn_code of insns to perform block sets. */
enum insn_code setmem_optab[NUM_MACHINE_MODES]; 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. */ to perform block compares. */
enum insn_code cmpstr_optab[NUM_MACHINE_MODES]; enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
enum insn_code cmpstrn_optab[NUM_MACHINE_MODES];
enum insn_code cmpmem_optab[NUM_MACHINE_MODES]; enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
/* Synchronization primitives. */ /* Synchronization primitives. */
......
...@@ -169,6 +169,7 @@ static const char * const optabs[] = ...@@ -169,6 +169,7 @@ static const char * const optabs[] =
"reload_out_optab[$A] = CODE_FOR_$(reload_out$a$)", "reload_out_optab[$A] = CODE_FOR_$(reload_out$a$)",
"movmem_optab[$A] = CODE_FOR_$(movmem$a$)", "movmem_optab[$A] = CODE_FOR_$(movmem$a$)",
"cmpstr_optab[$A] = CODE_FOR_$(cmpstr$a$)", "cmpstr_optab[$A] = CODE_FOR_$(cmpstr$a$)",
"cmpstrn_optab[$A] = CODE_FOR_$(cmpstrn$a$)",
"cmpmem_optab[$A] = CODE_FOR_$(cmpmem$a$)", "cmpmem_optab[$A] = CODE_FOR_$(cmpmem$a$)",
"setmem_optab[$A] = CODE_FOR_$(setmem$a$)", "setmem_optab[$A] = CODE_FOR_$(setmem$a$)",
"sync_add_optab[$A] = CODE_FOR_$(sync_add$I$a$)", "sync_add_optab[$A] = CODE_FOR_$(sync_add$I$a$)",
......
...@@ -3426,6 +3426,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size, ...@@ -3426,6 +3426,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
if (cmp_code == CODE_FOR_nothing) if (cmp_code == CODE_FOR_nothing)
cmp_code = cmpstr_optab[cmp_mode]; cmp_code = cmpstr_optab[cmp_mode];
if (cmp_code == CODE_FOR_nothing) if (cmp_code == CODE_FOR_nothing)
cmp_code = cmpstrn_optab[cmp_mode];
if (cmp_code == CODE_FOR_nothing)
continue; continue;
/* Must make sure the size fits the insn's mode. */ /* Must make sure the size fits the insn's mode. */
...@@ -5090,6 +5092,7 @@ init_optabs (void) ...@@ -5090,6 +5092,7 @@ init_optabs (void)
{ {
movmem_optab[i] = CODE_FOR_nothing; movmem_optab[i] = CODE_FOR_nothing;
cmpstr_optab[i] = CODE_FOR_nothing; cmpstr_optab[i] = CODE_FOR_nothing;
cmpstrn_optab[i] = CODE_FOR_nothing;
cmpmem_optab[i] = CODE_FOR_nothing; cmpmem_optab[i] = CODE_FOR_nothing;
setmem_optab[i] = CODE_FOR_nothing; setmem_optab[i] = CODE_FOR_nothing;
......
...@@ -450,6 +450,7 @@ extern enum insn_code setmem_optab[NUM_MACHINE_MODES]; ...@@ -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 /* These arrays record the insn_code of two different kinds of insns
to perform block compares. */ to perform block compares. */
extern enum insn_code cmpstr_optab[NUM_MACHINE_MODES]; 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]; extern enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
/* Synchronization primitives. This first set is atomic operation for /* Synchronization primitives. This first set is atomic operation for
......
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