summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/builtins.c235
-rw-r--r--gcc/config/c4x/c4x.md4
-rw-r--r--gcc/config/i386/i386.md30
-rw-r--r--gcc/doc/md.texi23
-rw-r--r--gcc/expr.c3
-rw-r--r--gcc/genopinit.c1
-rw-r--r--gcc/optabs.c3
-rw-r--r--gcc/optabs.h1
9 files changed, 193 insertions, 122 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f44b1f4e2b7..0ab6fdebde2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/builtins.c b/gcc/builtins.c
index f308f530c35..b032fc43784 100644
--- a/gcc/builtins.c
+++ b/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);
}
-#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;
+#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;
- len1 = c_strlen (arg1, 1);
- len2 = c_strlen (arg2, 1);
+ /* Stabilize the arguments in case gen_cmpstr(n)si fail. */
+ arg1 = builtin_save_expr (arg1);
+ arg2 = builtin_save_expr (arg2);
- if (len1)
- len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
- if (len2)
- len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
+ arg1_rtx = get_memory_rtx (arg1);
+ arg2_rtx = get_memory_rtx (arg2);
- /* 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;
+#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;
+ /* 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;
+ /* 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);
+ /* 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);
+ insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
+ GEN_INT (MIN (arg1_align, arg2_align)));
+ }
+#endif
- 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);
+ 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;
- }
+ /* 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);
- }
+ /* 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);
diff --git a/gcc/config/c4x/c4x.md b/gcc/config/c4x/c4x.md
index f37a49bc36f..5054383e520 100644
--- a/gcc/config/c4x/c4x.md
+++ b/gcc/config/c4x/c4x.md
@@ -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" "")))
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index c0823b608d8..d3a085b9f97 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -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)
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 84be6e44049..5af0d55e10b 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -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
diff --git a/gcc/expr.c b/gcc/expr.c
index d778b59c95d..01f890fa6a5 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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. */
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 409ed08903b..8bf574743e9 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -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$)",
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 60c491870a8..2f981abf19b 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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;
diff --git a/gcc/optabs.h b/gcc/optabs.h
index bba0a5ce821..71f198abf58 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -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
OpenPOWER on IntegriCloud