diff mbox

Use cmpstr and cmpstrn optabs

Message ID 87k2tglf9g.fsf@e105548-lin.cambridge.arm.com
State New
Headers show

Commit Message

Richard Sandiford July 31, 2015, 11:48 a.m. UTC
expand_builtin_strcmp has:

  if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
      || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
    {
      ...
	  machine_mode insn_mode
	    = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
          ...
	  insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
			       GEN_INT (MIN (arg1_align, arg2_align)));
      ...
    }

which is mixing the optabs interface and the CODE_FOR_foo/gen_foo
interface.  It also doesn't check the predicates of the pattern,
unlike a normal optab expansion.

This patch converts the code to do everything via the optabs interface.
This required a change to the sh.md cmpstrn pattern, where the length
predicate was "immediate_operand" but where the expander code wanted
to handle nonimmediates too.  I also removed the now-redundant
force_operand of the length in the rx.md pattern (because the
predicate is now enforced and already an operand).

The check whether "target" has insn_mode is performed by
create_output_operand so we no longer need to check it in
the builtins.c code too.

Bootstrapped & regression-tested on x86_64-linux-gnu.  Also tested by
building ft32-elf, s390x-linux-gnu, m32c-elf, rx-elf and sh4-elf
and checking that (with the appropriate target flags) the optabs
are working for various strcmp and strncmp calls.  OK to install?

Thanks,
Richard

gcc/
	* builtins.c (expand_cmpstr, expand_cmpstrn): New functions.
	(expand_builtin_strcmp, expand_builtin_strncmp): Use them.  Remove
	references to HAVE_cmpstr{,n}si and CODE_FOR_cmpstr{,n}si.
	* config/m32c/blkmov.md (cmpstrsi): Fix predicates of operands 1 and 2.
	Add predicates for operands 0 and 3.
	* config/rx/rx.md (cmpstrnsi): Remove force_operand for the length
	operand.
	* config/sh/sh.md (cmpstrnsi): Change the length predicate from
	immediate_operand to nonmemory_operand.

Comments

Kaz Kojima Aug. 1, 2015, 9:28 a.m. UTC | #1
Richard Sandiford <richard.sandiford@arm.com> wrote:
> This patch converts the code to do everything via the optabs interface.
> This required a change to the sh.md cmpstrn pattern, where the length
> predicate was "immediate_operand" but where the expander code wanted
> to handle nonimmediates too.  I also removed the now-redundant
> force_operand of the length in the rx.md pattern (because the
> predicate is now enforced and already an operand).
> 
> The check whether "target" has insn_mode is performed by
> create_output_operand so we no longer need to check it in
> the builtins.c code too.
> 
> Bootstrapped & regression-tested on x86_64-linux-gnu.  Also tested by
> building ft32-elf, s390x-linux-gnu, m32c-elf, rx-elf and sh4-elf
> and checking that (with the appropriate target flags) the optabs
> are working for various strcmp and strncmp calls.  OK to install?

SH portion looks fine.  No new failures with the patch on
sh4-unknown-linux-gnu.

Regards,
	kaz
Richard Sandiford Aug. 24, 2015, 11:17 a.m. UTC | #2
Originally posted here:

   https://gcc.gnu.org/ml/gcc-patches/2015-07/msg02660.html

Kaz approved the SH parts and reported that there were no new failures
on sh4-unknown-linux-gnu (thanks).

Richard Sandiford <richard.sandiford@arm.com> writes:
> expand_builtin_strcmp has:
>
>   if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
>       || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
>     {
>       ...
> 	  machine_mode insn_mode
> 	    = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
>           ...
> 	  insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
> 			       GEN_INT (MIN (arg1_align, arg2_align)));
>       ...
>     }
>
> which is mixing the optabs interface and the CODE_FOR_foo/gen_foo
> interface.  It also doesn't check the predicates of the pattern,
> unlike a normal optab expansion.
>
> This patch converts the code to do everything via the optabs interface.
> This required a change to the sh.md cmpstrn pattern, where the length
> predicate was "immediate_operand" but where the expander code wanted
> to handle nonimmediates too.  I also removed the now-redundant
> force_operand of the length in the rx.md pattern (because the
> predicate is now enforced and already an operand).
>
> The check whether "target" has insn_mode is performed by
> create_output_operand so we no longer need to check it in
> the builtins.c code too.
>
> Bootstrapped & regression-tested on x86_64-linux-gnu.  Also tested by
> building ft32-elf, s390x-linux-gnu, m32c-elf, rx-elf and sh4-elf
> and checking that (with the appropriate target flags) the optabs
> are working for various strcmp and strncmp calls.  OK to install?
>
> Thanks,
> Richard
>
> gcc/
> 	* builtins.c (expand_cmpstr, expand_cmpstrn): New functions.
> 	(expand_builtin_strcmp, expand_builtin_strncmp): Use them.  Remove
> 	references to HAVE_cmpstr{,n}si and CODE_FOR_cmpstr{,n}si.
> 	* config/m32c/blkmov.md (cmpstrsi): Fix predicates of operands 1 and 2.
> 	Add predicates for operands 0 and 3.
> 	* config/rx/rx.md (cmpstrnsi): Remove force_operand for the length
> 	operand.
> 	* config/sh/sh.md (cmpstrnsi): Change the length predicate from
> 	immediate_operand to nonmemory_operand.
>
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index d7eb65f..f5da72b 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -4016,6 +4016,53 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
>    return NULL_RTX;
>  }
>  
> +/* Try to expand cmpstr operation ICODE with the given operands.
> +   Return the result rtx on success, otherwise return null.  */
> +
> +static rtx
> +expand_cmpstr (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
> +	       HOST_WIDE_INT align)
> +{
> +  machine_mode insn_mode = insn_data[icode].operand[0].mode;
> +
> +  if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
> +    target = NULL_RTX;
> +
> +  struct expand_operand ops[4];
> +  create_output_operand (&ops[0], target, insn_mode);
> +  create_fixed_operand (&ops[1], arg1_rtx);
> +  create_fixed_operand (&ops[2], arg2_rtx);
> +  create_integer_operand (&ops[3], align);
> +  if (maybe_expand_insn (icode, 4, ops))
> +    return ops[0].value;
> +  return NULL_RTX;
> +}
> +
> +/* Try to expand cmpstrn operation ICODE with the given operands.
> +   ARG3_TYPE is the type of ARG3_RTX.  Return the result rtx on success,
> +   otherwise return null.  */
> +
> +static rtx
> +expand_cmpstrn (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
> +		tree arg3_type, rtx arg3_rtx, HOST_WIDE_INT align)
> +{
> +  machine_mode insn_mode = insn_data[icode].operand[0].mode;
> +
> +  if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
> +    target = NULL_RTX;
> +
> +  struct expand_operand ops[5];
> +  create_output_operand (&ops[0], target, insn_mode);
> +  create_fixed_operand (&ops[1], arg1_rtx);
> +  create_fixed_operand (&ops[2], arg2_rtx);
> +  create_convert_operand_from (&ops[3], arg3_rtx, TYPE_MODE (arg3_type),
> +			       TYPE_UNSIGNED (arg3_type));
> +  create_integer_operand (&ops[4], align);
> +  if (maybe_expand_insn (icode, 5, ops))
> +    return ops[0].value;
> +  return NULL_RTX;
> +}
> +
>  /* Expand expression EXP, which is a call to the strcmp builtin.  Return NULL_RTX
>     if we failed the caller should emit a normal call, otherwise try to get
>     the result in TARGET, if convenient.  */
> @@ -4026,15 +4073,15 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
>    if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
>      return NULL_RTX;
>  
> -#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
> -  if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
> -      || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
> +  insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode);
> +  insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
> +  if (cmpstr_icode != CODE_FOR_nothing || cmpstrn_icode != CODE_FOR_nothing)
>      {
>        rtx arg1_rtx, arg2_rtx;
> -      rtx result, insn = NULL_RTX;
>        tree fndecl, fn;
>        tree arg1 = CALL_EXPR_ARG (exp, 0);
>        tree arg2 = CALL_EXPR_ARG (exp, 1);
> +      rtx result = NULL_RTX;
>  
>        unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
>        unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
> @@ -4050,33 +4097,17 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
>        arg1_rtx = get_memory_rtx (arg1, NULL);
>        arg2_rtx = get_memory_rtx (arg2, NULL);
>  
> -#ifdef HAVE_cmpstrsi
>        /* Try to call cmpstrsi.  */
> -      if (HAVE_cmpstrsi)
> -	{
> -	  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
> -#ifdef HAVE_cmpstrnsi
> +      if (cmpstr_icode != CODE_FOR_nothing)
> +	result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
> +				MIN (arg1_align, arg2_align));
> +
>        /* Try to determine at least one length and call cmpstrnsi.  */
> -      if (!insn && HAVE_cmpstrnsi)
> +      if (!result && cmpstrn_icode != CODE_FOR_nothing)
>  	{
>  	  tree len;
>  	  rtx arg3_rtx;
>  
> -	  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);
>  
> @@ -4110,30 +4141,19 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
>  	    len = len2;
>  
>  	  /* If both arguments have side effects, we cannot optimize.  */
> -	  if (!len || TREE_SIDE_EFFECTS (len))
> -	    goto do_libcall;
> -
> -	  arg3_rtx = expand_normal (len);
> -
> -	  /* 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)));
> +	  if (len && !TREE_SIDE_EFFECTS (len))
> +	    {
> +	      arg3_rtx = expand_normal (len);
> +	      result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx,
> +				       arg2_rtx, TREE_TYPE (len), arg3_rtx,
> +				       MIN (arg1_align, arg2_align));
> +	    }
>  	}
> -#endif
>  
> -      if (insn)
> +      if (result)
>  	{
> -	  machine_mode mode;
> -	  emit_insn (insn);
> -
>  	  /* Return the value in the proper mode for this function.  */
> -	  mode = TYPE_MODE (TREE_TYPE (exp));
> +	  machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
>  	  if (GET_MODE (result) == mode)
>  	    return result;
>  	  if (target == 0)
> @@ -4144,16 +4164,12 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
>  
>        /* Expand the library call ourselves using a stabilized argument
>  	 list to avoid re-evaluating the function's arguments twice.  */
> -#ifdef HAVE_cmpstrnsi
> -    do_libcall:
> -#endif
>        fndecl = get_callee_fndecl (exp);
>        fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
>        gcc_assert (TREE_CODE (fn) == CALL_EXPR);
>        CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
>        return expand_call (fn, target, target == const0_rtx);
>      }
> -#endif
>    return NULL_RTX;
>  }
>  
> @@ -4174,12 +4190,12 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
>    /* 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)
> +  insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
> +  if (cmpstrn_icode != CODE_FOR_nothing)
>    {
>      tree len, len1, len2;
>      rtx arg1_rtx, arg2_rtx, arg3_rtx;
> -    rtx result, insn;
> +    rtx result;
>      tree fndecl, fn;
>      tree arg1 = CALL_EXPR_ARG (exp, 0);
>      tree arg2 = CALL_EXPR_ARG (exp, 1);
> @@ -4187,8 +4203,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
>  
>      unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
>      unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
> -    machine_mode insn_mode
> -      = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
>  
>      len1 = c_strlen (arg1, 1);
>      len2 = c_strlen (arg2, 1);
> @@ -4234,13 +4248,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
>      if (arg1_align == 0 || arg2_align == 0)
>        return NULL_RTX;
>  
> -    /* 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.  */
>      arg1 = builtin_save_expr (arg1);
>      arg2 = builtin_save_expr (arg2);
> @@ -4249,12 +4256,11 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
>      arg1_rtx = get_memory_rtx (arg1, len);
>      arg2_rtx = get_memory_rtx (arg2, len);
>      arg3_rtx = expand_normal (len);
> -    insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
> -			  GEN_INT (MIN (arg1_align, arg2_align)));
> -    if (insn)
> +    result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx, arg2_rtx,
> +			     TREE_TYPE (len), arg3_rtx,
> +			     MIN (arg1_align, arg2_align));
> +    if (result)
>        {
> -	emit_insn (insn);
> -
>  	/* Return the value in the proper mode for this function.  */
>  	mode = TYPE_MODE (TREE_TYPE (exp));
>  	if (GET_MODE (result) == mode)
> @@ -4274,7 +4280,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
>      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
>      return expand_call (fn, target, target == const0_rtx);
>    }
> -#endif
>    return NULL_RTX;
>  }
>  
> diff --git a/gcc/config/m32c/blkmov.md b/gcc/config/m32c/blkmov.md
> index 88d0406..02ad345 100644
> --- a/gcc/config/m32c/blkmov.md
> +++ b/gcc/config/m32c/blkmov.md
> @@ -178,10 +178,10 @@
>  ;; 3 = alignment
>  
>  (define_expand "cmpstrsi"
> -  [(match_operand:HI 0 "" "")
> -   (match_operand 1 "ap_operand" "")
> -   (match_operand 2 "ap_operand" "")
> -   (match_operand 3 "" "")
> +  [(match_operand:HI 0 "register_operand" "")
> +   (match_operand 1 "memory_operand" "")
> +   (match_operand 2 "memory_operand" "")
> +   (match_operand 3 "const_int_operand" "")
>     ]
>    "TARGET_A24"
>    "if (m32c_expand_cmpstr(operands)) DONE; FAIL;"
> diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
> index 8b12475..6faf771 100644
> --- a/gcc/config/rx/rx.md
> +++ b/gcc/config/rx/rx.md
> @@ -2315,7 +2315,7 @@
>    
>      emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX));
>      emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX));
> -    emit_move_insn (len, force_operand (operands[3], NULL_RTX));
> +    emit_move_insn (len, operands[3]);
>  
>      emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2]));
>      DONE;
> diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
> index 61f6637..0885ff3 100644
> --- a/gcc/config/sh/sh.md
> +++ b/gcc/config/sh/sh.md
> @@ -12731,7 +12731,7 @@ label:
>    [(set (match_operand:SI 0 "register_operand")
>  	(compare:SI (match_operand:BLK 1 "memory_operand")
>  		    (match_operand:BLK 2 "memory_operand")))
> -   (use (match_operand:SI 3 "immediate_operand"))
> +   (use (match_operand:SI 3 "nonmemory_operand"))
>     (use (match_operand:SI 4 "immediate_operand"))]
>    "TARGET_SH1 && optimize"
>  {
Jeff Law Aug. 24, 2015, 5:24 p.m. UTC | #3
On 08/24/2015 05:17 AM, Richard Sandiford wrote:
> Originally posted here:
>
>     https://gcc.gnu.org/ml/gcc-patches/2015-07/msg02660.html
>
> Kaz approved the SH parts and reported that there were no new failures
> on sh4-unknown-linux-gnu (thanks).
Sorry, this must have slipped through the cracks.  Thanks for pinging it.


>> 	* builtins.c (expand_cmpstr, expand_cmpstrn): New functions.
>> 	(expand_builtin_strcmp, expand_builtin_strncmp): Use them.  Remove
>> 	references to HAVE_cmpstr{,n}si and CODE_FOR_cmpstr{,n}si.
>> 	* config/m32c/blkmov.md (cmpstrsi): Fix predicates of operands 1 and 2.
>> 	Add predicates for operands 0 and 3.
>> 	* config/rx/rx.md (cmpstrnsi): Remove force_operand for the length
>> 	operand.
>> 	* config/sh/sh.md (cmpstrnsi): Change the length predicate from
>> 	immediate_operand to nonmemory_operand.
OK.
jeff
diff mbox

Patch

diff --git a/gcc/builtins.c b/gcc/builtins.c
index d7eb65f..f5da72b 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -4016,6 +4016,53 @@  expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
   return NULL_RTX;
 }
 
+/* Try to expand cmpstr operation ICODE with the given operands.
+   Return the result rtx on success, otherwise return null.  */
+
+static rtx
+expand_cmpstr (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
+	       HOST_WIDE_INT align)
+{
+  machine_mode insn_mode = insn_data[icode].operand[0].mode;
+
+  if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
+    target = NULL_RTX;
+
+  struct expand_operand ops[4];
+  create_output_operand (&ops[0], target, insn_mode);
+  create_fixed_operand (&ops[1], arg1_rtx);
+  create_fixed_operand (&ops[2], arg2_rtx);
+  create_integer_operand (&ops[3], align);
+  if (maybe_expand_insn (icode, 4, ops))
+    return ops[0].value;
+  return NULL_RTX;
+}
+
+/* Try to expand cmpstrn operation ICODE with the given operands.
+   ARG3_TYPE is the type of ARG3_RTX.  Return the result rtx on success,
+   otherwise return null.  */
+
+static rtx
+expand_cmpstrn (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
+		tree arg3_type, rtx arg3_rtx, HOST_WIDE_INT align)
+{
+  machine_mode insn_mode = insn_data[icode].operand[0].mode;
+
+  if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
+    target = NULL_RTX;
+
+  struct expand_operand ops[5];
+  create_output_operand (&ops[0], target, insn_mode);
+  create_fixed_operand (&ops[1], arg1_rtx);
+  create_fixed_operand (&ops[2], arg2_rtx);
+  create_convert_operand_from (&ops[3], arg3_rtx, TYPE_MODE (arg3_type),
+			       TYPE_UNSIGNED (arg3_type));
+  create_integer_operand (&ops[4], align);
+  if (maybe_expand_insn (icode, 5, ops))
+    return ops[0].value;
+  return NULL_RTX;
+}
+
 /* Expand expression EXP, which is a call to the strcmp builtin.  Return NULL_RTX
    if we failed the caller should emit a normal call, otherwise try to get
    the result in TARGET, if convenient.  */
@@ -4026,15 +4073,15 @@  expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
-#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
-  if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
-      || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
+  insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode);
+  insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
+  if (cmpstr_icode != CODE_FOR_nothing || cmpstrn_icode != CODE_FOR_nothing)
     {
       rtx arg1_rtx, arg2_rtx;
-      rtx result, insn = NULL_RTX;
       tree fndecl, fn;
       tree arg1 = CALL_EXPR_ARG (exp, 0);
       tree arg2 = CALL_EXPR_ARG (exp, 1);
+      rtx result = NULL_RTX;
 
       unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
       unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
@@ -4050,33 +4097,17 @@  expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
       arg1_rtx = get_memory_rtx (arg1, NULL);
       arg2_rtx = get_memory_rtx (arg2, NULL);
 
-#ifdef HAVE_cmpstrsi
       /* Try to call cmpstrsi.  */
-      if (HAVE_cmpstrsi)
-	{
-	  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
-#ifdef HAVE_cmpstrnsi
+      if (cmpstr_icode != CODE_FOR_nothing)
+	result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
+				MIN (arg1_align, arg2_align));
+
       /* Try to determine at least one length and call cmpstrnsi.  */
-      if (!insn && HAVE_cmpstrnsi)
+      if (!result && cmpstrn_icode != CODE_FOR_nothing)
 	{
 	  tree len;
 	  rtx arg3_rtx;
 
-	  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);
 
@@ -4110,30 +4141,19 @@  expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
 	    len = len2;
 
 	  /* If both arguments have side effects, we cannot optimize.  */
-	  if (!len || TREE_SIDE_EFFECTS (len))
-	    goto do_libcall;
-
-	  arg3_rtx = expand_normal (len);
-
-	  /* 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)));
+	  if (len && !TREE_SIDE_EFFECTS (len))
+	    {
+	      arg3_rtx = expand_normal (len);
+	      result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx,
+				       arg2_rtx, TREE_TYPE (len), arg3_rtx,
+				       MIN (arg1_align, arg2_align));
+	    }
 	}
-#endif
 
-      if (insn)
+      if (result)
 	{
-	  machine_mode mode;
-	  emit_insn (insn);
-
 	  /* Return the value in the proper mode for this function.  */
-	  mode = TYPE_MODE (TREE_TYPE (exp));
+	  machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
 	  if (GET_MODE (result) == mode)
 	    return result;
 	  if (target == 0)
@@ -4144,16 +4164,12 @@  expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
 
       /* Expand the library call ourselves using a stabilized argument
 	 list to avoid re-evaluating the function's arguments twice.  */
-#ifdef HAVE_cmpstrnsi
-    do_libcall:
-#endif
       fndecl = get_callee_fndecl (exp);
       fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
       gcc_assert (TREE_CODE (fn) == CALL_EXPR);
       CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
       return expand_call (fn, target, target == const0_rtx);
     }
-#endif
   return NULL_RTX;
 }
 
@@ -4174,12 +4190,12 @@  expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
   /* 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)
+  insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
+  if (cmpstrn_icode != CODE_FOR_nothing)
   {
     tree len, len1, len2;
     rtx arg1_rtx, arg2_rtx, arg3_rtx;
-    rtx result, insn;
+    rtx result;
     tree fndecl, fn;
     tree arg1 = CALL_EXPR_ARG (exp, 0);
     tree arg2 = CALL_EXPR_ARG (exp, 1);
@@ -4187,8 +4203,6 @@  expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
 
     unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
     unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
-    machine_mode insn_mode
-      = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
 
     len1 = c_strlen (arg1, 1);
     len2 = c_strlen (arg2, 1);
@@ -4234,13 +4248,6 @@  expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     if (arg1_align == 0 || arg2_align == 0)
       return NULL_RTX;
 
-    /* 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.  */
     arg1 = builtin_save_expr (arg1);
     arg2 = builtin_save_expr (arg2);
@@ -4249,12 +4256,11 @@  expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     arg1_rtx = get_memory_rtx (arg1, len);
     arg2_rtx = get_memory_rtx (arg2, len);
     arg3_rtx = expand_normal (len);
-    insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
-			  GEN_INT (MIN (arg1_align, arg2_align)));
-    if (insn)
+    result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx, arg2_rtx,
+			     TREE_TYPE (len), arg3_rtx,
+			     MIN (arg1_align, arg2_align));
+    if (result)
       {
-	emit_insn (insn);
-
 	/* Return the value in the proper mode for this function.  */
 	mode = TYPE_MODE (TREE_TYPE (exp));
 	if (GET_MODE (result) == mode)
@@ -4274,7 +4280,6 @@  expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
     return expand_call (fn, target, target == const0_rtx);
   }
-#endif
   return NULL_RTX;
 }
 
diff --git a/gcc/config/m32c/blkmov.md b/gcc/config/m32c/blkmov.md
index 88d0406..02ad345 100644
--- a/gcc/config/m32c/blkmov.md
+++ b/gcc/config/m32c/blkmov.md
@@ -178,10 +178,10 @@ 
 ;; 3 = alignment
 
 (define_expand "cmpstrsi"
-  [(match_operand:HI 0 "" "")
-   (match_operand 1 "ap_operand" "")
-   (match_operand 2 "ap_operand" "")
-   (match_operand 3 "" "")
+  [(match_operand:HI 0 "register_operand" "")
+   (match_operand 1 "memory_operand" "")
+   (match_operand 2 "memory_operand" "")
+   (match_operand 3 "const_int_operand" "")
    ]
   "TARGET_A24"
   "if (m32c_expand_cmpstr(operands)) DONE; FAIL;"
diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
index 8b12475..6faf771 100644
--- a/gcc/config/rx/rx.md
+++ b/gcc/config/rx/rx.md
@@ -2315,7 +2315,7 @@ 
   
     emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX));
     emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX));
-    emit_move_insn (len, force_operand (operands[3], NULL_RTX));
+    emit_move_insn (len, operands[3]);
 
     emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2]));
     DONE;
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 61f6637..0885ff3 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -12731,7 +12731,7 @@  label:
   [(set (match_operand:SI 0 "register_operand")
 	(compare:SI (match_operand:BLK 1 "memory_operand")
 		    (match_operand:BLK 2 "memory_operand")))
-   (use (match_operand:SI 3 "immediate_operand"))
+   (use (match_operand:SI 3 "nonmemory_operand"))
    (use (match_operand:SI 4 "immediate_operand"))]
   "TARGET_SH1 && optimize"
 {