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>
* 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,
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,9 +3504,9 @@ 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,
#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
......@@ -3558,25 +3558,61 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
#ifdef HAVE_cmpstrsi
if (HAVE_cmpstrsi)
#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
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));
tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx;
rtx result, insn;
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;
len1 = c_strlen (arg1, 1);
len2 = c_strlen (arg2, 1);
/* 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);
......@@ -3611,9 +3647,8 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
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;
/* 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;
......@@ -3622,15 +3657,11 @@ expand_builtin_strcmp (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. */
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,
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));
}
#endif
if (insn)
{
emit_insn (insn);
......@@ -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,7 +3789,7 @@ 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,
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));
if (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,7 +17487,7 @@
emit_move_insn (operands[0], const0_rtx);
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]));
}
else
......@@ -17496,7 +17496,7 @@
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,
emit_insn (gen_cmpstrnqi_1 (addr1, addr2, countreg, align,
operands[1], operands[2]));
}
......@@ -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$)",
......
......@@ -3426,6 +3426,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
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. */
......@@ -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
......
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