[PATCH 2/6] combine: If recog fails, try again with zero_ext{ract,end} simplified

Kyrill Tkachov kyrylo.tkachov@arm.com
Tue May 12 08:25:00 GMT 2015


Hi Segher,

On 10/05/15 17:13, Segher Boessenkool wrote:
> Combine has its own ideas of what is "canonical" RTL, forcing all
> backends to have special patterns in their machine description for the
> "more simplified" patterns combine often creates, even though the
> backend already has patterns for a more general form.  Backends that
> do not implement those patterns get less well optimised code.
>
> This patch lifts that burden for two cases: combine often converts
> an AND (with, say, 0xff) to a ZERO_EXTEND of a SUBREG; and an LSHIFTRT
> followed by an AND to a ZERO_EXTRACT.  This is perfectly helpful for
> e.g. MEMs, but not nice if you have instructions to do more generic
> masking (like PowerPC rlwinm, and similar on some other archs).
>
> With this patch, if recog_for_combine fails, and there are any
> ZERO_EXT* in the pattern to be matched, it tries again with those
> expressed as AND etc.  If that also fails it rolls back the changes,
> because it might still match after e.g. splitting, and we want to
> try the ZERO_EXT* for that as well.
>
> Tested on powerpc-linux, before and after removing many patterns
> from the machine description, and checked that the only changes in
> the bootstrapped compiler are new and removed functions.


Does this patch means we can remove any patterns in
the backend that look like:

-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-       (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r")
-                        (match_operand:SI 2 "const_int_operand" "i")
-                        (match_operand:SI 3 "const_int_operand" "i")))]


as long as we have an equivalent and-with-mask pattern?

Thanks,
Kyrill


>
> I'll also test on x86_64-linux before committing.
>
>
> Segher
>
>
> 2015-05-10  Segher Boessenkool   <segher@kernel.crashing.org>
>
> 	* combine.c (recog_for_combine_1): New function, factored out
> 	from recog_for_combine.
> 	(change_zero_ext): New function.
> 	(recog_for_combine): If recog fails, try again with the pattern
> 	modified by change_zero_ext; if that still fails, restore the
> 	pattern.
>
> ---
>   gcc/combine.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
>   1 file changed, 107 insertions(+), 13 deletions(-)
>
> diff --git a/gcc/combine.c b/gcc/combine.c
> index 1e4d65e..896d9d2 100644
> --- a/gcc/combine.c
> +++ b/gcc/combine.c
> @@ -10849,21 +10849,11 @@ simplify_shift_const (rtx x, enum rtx_code code, machine_mode result_mode,
>   }
>   
>   

> -/* Like recog, but we receive the address of a pointer to a new pattern.
> -   We try to match the rtx that the pointer points to.
> -   If that fails, we may try to modify or replace the pattern,
> -   storing the replacement into the same pointer object.
> -
> -   Modifications include deletion or addition of CLOBBERs.
> -
> -   PNOTES is a pointer to a location where any REG_UNUSED notes added for
> -   the CLOBBERs are placed.
> -
> -   The value is the final insn code from the pattern ultimately matched,
> -   or -1.  */
> +/* A subroutine of recog_for_combine.  See there for arguments and
> +   return value.  */
>   
>   static int
> -recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
> +recog_for_combine_1 (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
>   {
>     rtx pat = *pnewpat;
>     rtx pat_without_clobbers;
> @@ -11010,6 +11000,110 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
>   
>     return insn_code_number;
>   }
> +
> +/* Change every ZERO_EXTRACT and ZERO_EXTEND of a SUBREG that can be
> +   expressed as an AND and maybe an LSHIFTRT, to that formulation.
> +   Return whether anything was so changed.  */
> +
> +static bool
> +change_zero_ext (rtx *src)
> +{
> +  bool changed = false;
> +
> +  subrtx_ptr_iterator::array_type array;
> +  FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST)
> +    {
> +      rtx x = **iter;
> +      machine_mode mode = GET_MODE (x);
> +      int size;
> +
> +      if (GET_CODE (x) == ZERO_EXTRACT
> +	  && CONST_INT_P (XEXP (x, 1))
> +	  && CONST_INT_P (XEXP (x, 2))
> +	  && GET_MODE (XEXP (x, 0)) == mode)
> +	{
> +	  size = INTVAL (XEXP (x, 1));
> +
> +	  int start = INTVAL (XEXP (x, 2));
> +	  if (BITS_BIG_ENDIAN)
> +	    start = GET_MODE_PRECISION (mode) - size - start;
> +
> +	  x = gen_rtx_LSHIFTRT (mode, XEXP (x, 0), GEN_INT (start));
> +	}
> +      else if (GET_CODE (x) == ZERO_EXTEND
> +	       && GET_CODE (XEXP (x, 0)) == SUBREG
> +	       && GET_MODE (SUBREG_REG (XEXP (x, 0))) == mode
> +	       && subreg_lowpart_p (XEXP (x, 0)))
> +	{
> +	  size = GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)));
> +	  x = SUBREG_REG (XEXP (x, 0));
> +	}
> +      else
> +	continue;
> +
> +      unsigned HOST_WIDE_INT mask = 1;
> +      mask <<= size;
> +      mask--;
> +
> +      x = gen_rtx_AND (mode, x, GEN_INT (mask));
> +
> +      SUBST (**iter, x);
> +      changed = true;
> +    }
> +
> +  return changed;
> +}
> +
> +/* Like recog, but we receive the address of a pointer to a new pattern.
> +   We try to match the rtx that the pointer points to.
> +   If that fails, we may try to modify or replace the pattern,
> +   storing the replacement into the same pointer object.
> +
> +   Modifications include deletion or addition of CLOBBERs.  If the
> +   instruction will still not match, we change ZERO_EXTEND and ZERO_EXTRACT
> +   to the equivalent AND and perhaps LSHIFTRT patterns, and try with that
> +   (and undo if that fails).
> +
> +   PNOTES is a pointer to a location where any REG_UNUSED notes added for
> +   the CLOBBERs are placed.
> +
> +   The value is the final insn code from the pattern ultimately matched,
> +   or -1.  */
> +
> +static int
> +recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
> +{
> +  rtx pat = PATTERN (insn);
> +  int insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes);
> +  if (insn_code_number >= 0 || check_asm_operands (pat))
> +    return insn_code_number;
> +
> +  void *marker = get_undo_marker ();
> +  bool changed = false;
> +
> +  if (GET_CODE (pat) == SET)
> +    changed = change_zero_ext (&SET_SRC (pat));
> +  else if (GET_CODE (pat) == PARALLEL)
> +    {
> +      int i;
> +      for (i = 0; i < XVECLEN (pat, 0); i++)
> +	{
> +	  rtx set = XVECEXP (pat, 0, i);
> +	  if (GET_CODE (set) == SET)
> +	    changed |= change_zero_ext (&SET_SRC (set));
> +	}
> +    }
> +
> +  if (changed)
> +    {
> +      insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes);
> +
> +      if (insn_code_number < 0)
> +	undo_to_marker (marker);
> +    }
> +
> +  return insn_code_number;
> +}
>   

>   /* Like gen_lowpart_general but for use by combine.  In combine it
>      is not possible to create any new pseudoregs.  However, it is



More information about the Gcc-patches mailing list