public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Bugfix: Additional parameter for canonicalize comparison
@ 2012-12-12 11:23 Andreas Krebbel
  2012-12-19  9:53 ` [PING] " Andreas Krebbel
  0 siblings, 1 reply; 6+ messages in thread
From: Andreas Krebbel @ 2012-12-12 11:23 UTC (permalink / raw)
  To: rearnsha; +Cc: gcc-patches

Hi Richard,

is the attached patch ok for ARM?

Bye,

-Andreas-

2012-12-12  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* target.def: Define canonicalize_comparison hook.
	* targhooks.h (default_canonicalize_comparison): New prototype.
	* targhooks.c (default_canonicalize_comparison): New function.
	* doc/tm.texi: Add documentation for the new target hook.
	* doc/tm.texi.in: Likewise.
	* combine.c (try_combine): Adjust to use the target hook.
	* config/alpha/alpha.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/alpha/alpha.c (alpha_canonicalize_comparison): New
	function.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/arm/arm-protos.h (arm_canonicalize_comparison): Remove
	prototype.
	* config/arm/arm.c (arm_canonicalize_comparison): Add new
	parameter.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/arm/arm.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/s390/s390-protos.h (s390_canonicalize_comparison): Remove
	prototype.
	* config/s390/s390.c (s390_canonicalize_comparison): Add new
	parameter.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/s390/s390.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/sh/sh-protos.h (sh_canonicalize_comparison): Remove
	prototype.
	* config/sh/sh.c (sh_canonicalize_comparison): Add new prototype.  New
	function overloading the old one.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/sh/sh.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/spu/spu.c (spu_canonicalize_comparison): New function.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/spu/spu.h (CANONICALIZE_COMPARISON): Remove macro
	definition.

---
 gcc/combine.c                 |   19 ++++++-!!!
 gcc/config/alpha/alpha.c      |   27 ++++++++++++++++
 gcc/config/alpha/alpha.h      |   20 ------------
 gcc/config/arm/arm-protos.h   |    1 
 gcc/config/arm/arm.c          |   68 ++-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 gcc/config/arm/arm.h          |    3 -
 gcc/config/s390/s390-protos.h |    1 
 gcc/config/s390/s390.c        |   13 +++!!!!!
 gcc/config/s390/s390.h        |    4 --
 gcc/config/sh/sh-protos.h     |    2 -
 gcc/config/sh/sh.c            |   34 +++++++++++!!!!!!!!!!
 gcc/config/sh/sh.h            |    4 --
 gcc/config/spu/spu.c          |   17 ++++++++++
 gcc/config/spu/spu.h          |   12 -------
 gcc/doc/tm.texi               |   20 !!!!!!!!!!!!
 gcc/doc/tm.texi.in            |   20 !!!!!!!!!!!!
 gcc/target.def                |    8 ++++
 gcc/targhooks.h               |    2 +
 18 files changed, 94 insertions(+), 50 deletions(-), 131 modifications(!)

Index: gcc/combine.c
===================================================================
*** gcc/combine.c.orig
--- gcc/combine.c
*************** static rtx gen_lowpart_or_truncate (enum
*** 494,499 ****
--- 494,510 ----
  static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
  
  \f
+ /* Convenience wrapper for the canonicalize_comparison target hook.
+    Target hooks cannot use enum rtx_code.  */
+ static inline void
+ target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
+ 				bool op0_preserve_value)
+ {
+   int code_int = (int)*code;
+   targetm.canonicalize_comparison (&code_int, op0, op1, op0_preserve_value);
+   *code = (enum rtx_code)code_int;
+ }
+ 
  /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
     PATTERN can not be split.  Otherwise, it returns an insn sequence.
     This is a wrapper around split_insns which ensures that the
*************** try_combine (rtx i3, rtx i2, rtx i1, rtx
*** 2944,2952 ****
  	  compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
  	  compare_code = simplify_compare_const (compare_code,
  						 op0, &op1);
! #ifdef CANONICALIZE_COMPARISON
! 	  CANONICALIZE_COMPARISON (compare_code, op0, op1);
! #endif
  	}
  
        /* Do the rest only if op1 is const0_rtx, which may be the
--- 2955,2961 ----
  	  compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
  	  compare_code = simplify_compare_const (compare_code,
  						 op0, &op1);
! 	  target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
  	}
  
        /* Do the rest only if op1 is const0_rtx, which may be the
*************** simplify_comparison (enum rtx_code code,
*** 11959,11969 ****
  	    }
  	}
  
- #ifdef CANONICALIZE_COMPARISON
    /* If this machine only supports a subset of valid comparisons, see if we
       can convert an unsupported one into a supported one.  */
!   CANONICALIZE_COMPARISON (code, op0, op1);
! #endif
  
    *pop0 = op0;
    *pop1 = op1;
--- 11968,11976 ----
  	    }
  	}
  
    /* If this machine only supports a subset of valid comparisons, see if we
       can convert an unsupported one into a supported one.  */
!   target_canonicalize_comparison (&code, &op0, &op1, 0);
  
    *pop0 = op0;
    *pop1 = op1;
Index: gcc/config/alpha/alpha.c
===================================================================
*** gcc/config/alpha/alpha.c.orig
--- gcc/config/alpha/alpha.c
*************** alpha_conditional_register_usage (void)
*** 9683,9688 ****
--- 9683,9712 ----
      for (i = 32; i < 63; i++)
        fixed_regs[i] = call_used_regs[i] = 1;
  }
+ 
+ /* Canonicalize a comparison from one we don't have to one we do have.  */
+ 
+ static void
+ alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ 			       bool op0_preserve_value)
+ {
+   if (!op0_preserve_value
+       && (*code == GE || *code == GT || *code == GEU || *code == GTU)
+       && (REG_P (*op1) || *op1 == const0_rtx))
+     {
+       rtx tem = *op0;
+       *op0 = *op1;
+       *op1 = tem;
+       *code = (int)swap_condition ((enum rtx_code)*code);
+     }
+ 
+   if ((*code == LT || *code == LTU)
+       && CONST_INT_P (*op1) && INTVAL (*op1) == 256)
+     {
+       *code = *code == LT ? LE : LEU;
+       *op1 = GEN_INT (255);
+     }
+ }
  \f
  /* Initialize the GCC target structure.  */
  #if TARGET_ABI_OPEN_VMS
*************** alpha_conditional_register_usage (void)
*** 9850,9855 ****
--- 9874,9882 ----
  #undef TARGET_CONDITIONAL_REGISTER_USAGE
  #define TARGET_CONDITIONAL_REGISTER_USAGE alpha_conditional_register_usage
  
+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  \f
Index: gcc/config/alpha/alpha.h
===================================================================
*** gcc/config/alpha/alpha.h.orig
--- gcc/config/alpha/alpha.h
*************** do {									     \
*** 922,947 ****
  #define FLOAT_STORE_FLAG_VALUE(MODE) \
    REAL_VALUE_ATOF ((TARGET_FLOAT_VAX ? "0.5" : "2.0"), (MODE))
  
- /* Canonicalize a comparison from one we don't have to one we do have.  */
- 
- #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
-   do {									\
-     if (((CODE) == GE || (CODE) == GT || (CODE) == GEU || (CODE) == GTU) \
- 	&& (REG_P (OP1) || (OP1) == const0_rtx))		\
-       {									\
- 	rtx tem = (OP0);						\
- 	(OP0) = (OP1);							\
- 	(OP1) = tem;							\
- 	(CODE) = swap_condition (CODE);					\
-       }									\
-     if (((CODE) == LT || (CODE) == LTU)					\
- 	&& CONST_INT_P (OP1) && INTVAL (OP1) == 256)			\
-       {									\
- 	(CODE) = (CODE) == LT ? LE : LEU;				\
- 	(OP1) = GEN_INT (255);						\
-       }									\
-   } while (0)
- 
  /* Specify the machine mode that pointers have.
     After generation of rtl, the compiler makes no further distinction
     between pointers and any other objects of this machine mode.  */
--- 922,927 ----
Index: gcc/config/arm/arm-protos.h
===================================================================
*** gcc/config/arm/arm-protos.h.orig
--- gcc/config/arm/arm-protos.h
*************** extern int const_ok_for_op (HOST_WIDE_IN
*** 53,59 ****
  extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
  extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
  			       HOST_WIDE_INT, rtx, rtx, int);
- extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *, rtx *);
  extern int legitimate_pic_operand_p (rtx);
  extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
  extern rtx legitimize_tls_address (rtx, rtx);
--- 53,58 ----
Index: gcc/config/arm/arm.c
===================================================================
*** gcc/config/arm/arm.c.orig
--- gcc/config/arm/arm.c
*************** static int arm_cortex_a5_branch_cost (bo
*** 269,275 ****
  
  static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
  					     const unsigned char *sel);
! 
  \f
  /* Table of machine attributes.  */
  static const struct attribute_spec arm_attribute_table[] =
--- 269,276 ----
  
  static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
  					     const unsigned char *sel);
! static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
! 					 bool op0_preserve_value);
  \f
  /* Table of machine attributes.  */
  static const struct attribute_spec arm_attribute_table[] =
*************** static const struct attribute_spec arm_a
*** 626,631 ****
--- 627,636 ----
  #define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
    arm_vectorize_vec_perm_const_ok
  
+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON \
+   arm_canonicalize_comparison
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  \f
  /* Obstack for minipool constant handling.  */
*************** arm_gen_constant (enum rtx_code code, en
*** 3543,3550 ****
     This can be done for a few constant compares, where we can make the
     immediate value easier to load.  */
  
! enum rtx_code
! arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
  {
    enum machine_mode mode;
    unsigned HOST_WIDE_INT i, maxval;
--- 3548,3556 ----
     This can be done for a few constant compares, where we can make the
     immediate value easier to load.  */
  
! static void
! arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
! 			     bool op0_preserve_value)
  {
    enum machine_mode mode;
    unsigned HOST_WIDE_INT i, maxval;
*************** arm_canonicalize_comparison (enum rtx_co
*** 3563,3577 ****
      {
        rtx tem;
  
!       if (code == GT || code == LE
! 	  || (!TARGET_ARM && (code == GTU || code == LEU)))
  	{
  	  /* Missing comparison.  First try to use an available
  	     comparison.  */
  	  if (CONST_INT_P (*op1))
  	    {
  	      i = INTVAL (*op1);
! 	      switch (code)
  		{
  		case GT:
  		case LE:
--- 3569,3583 ----
      {
        rtx tem;
  
!       if (*code == GT || *code == LE
! 	  || (!TARGET_ARM && (*code == GTU || *code == LEU)))
  	{
  	  /* Missing comparison.  First try to use an available
  	     comparison.  */
  	  if (CONST_INT_P (*op1))
  	    {
  	      i = INTVAL (*op1);
! 	      switch (*code)
  		{
  		case GT:
  		case LE:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3579,3585 ****
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      return code == GT ? GE : LT;
  		    }
  		  break;
  		case GTU:
--- 3585,3592 ----
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      *code = *code == GT ? GE : LT;
! 		      return;
  		    }
  		  break;
  		case GTU:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3588,3594 ****
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      return code == GTU ? GEU : LTU;
  		    }
  		  break;
  		default:
--- 3595,3602 ----
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      *code = *code == GTU ? GEU : LTU;
! 		      return;
  		    }
  		  break;
  		default:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3597,3615 ****
  	    }
  
  	  /* If that did not work, reverse the condition.  */
! 	  tem = *op0;
! 	  *op0 = *op1;
! 	  *op1 = tem;
! 	  return swap_condition (code);
  	}
! 
!       return code;
      }
  
    /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
       with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
       to facilitate possible combining with a cmp into 'ands'.  */
!   if (mode == SImode
        && GET_CODE (*op0) == ZERO_EXTEND
        && GET_CODE (XEXP (*op0, 0)) == SUBREG
        && GET_MODE (XEXP (*op0, 0)) == QImode
--- 3605,3626 ----
  	    }
  
  	  /* If that did not work, reverse the condition.  */
! 	  if (!op0_preserve_value)
! 	    {
! 	      tem = *op0;
! 	      *op0 = *op1;
! 	      *op1 = tem;
! 	      *code = (int)swap_condition ((enum rtx_code)*code);
! 	    }
  	}
!       return;
      }
  
    /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
       with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
       to facilitate possible combining with a cmp into 'ands'.  */
!   if (!op0_preserve_value
!       && mode == SImode
        && GET_CODE (*op0) == ZERO_EXTEND
        && GET_CODE (XEXP (*op0, 0)) == SUBREG
        && GET_MODE (XEXP (*op0, 0)) == QImode
*************** arm_canonicalize_comparison (enum rtx_co
*** 3624,3638 ****
    if (!CONST_INT_P (*op1)
        || const_ok_for_arm (INTVAL (*op1))
        || const_ok_for_arm (- INTVAL (*op1)))
!     return code;
  
    i = INTVAL (*op1);
  
!   switch (code)
      {
      case EQ:
      case NE:
!       return code;
  
      case GT:
      case LE:
--- 3635,3649 ----
    if (!CONST_INT_P (*op1)
        || const_ok_for_arm (INTVAL (*op1))
        || const_ok_for_arm (- INTVAL (*op1)))
!     return;
  
    i = INTVAL (*op1);
  
!   switch (*code)
      {
      case EQ:
      case NE:
!       return;
  
      case GT:
      case LE:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3640,3646 ****
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  return code == GT ? GE : LT;
  	}
        break;
  
--- 3651,3658 ----
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  *code = *code == GT ? GE : LT;
! 	  return;
  	}
        break;
  
*************** arm_canonicalize_comparison (enum rtx_co
*** 3650,3656 ****
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  return code == GE ? GT : LE;
  	}
        break;
  
--- 3662,3669 ----
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  *code = *code == GE ? GT : LE;
! 	  return;
  	}
        break;
  
*************** arm_canonicalize_comparison (enum rtx_co
*** 3660,3666 ****
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  return code == GTU ? GEU : LTU;
  	}
        break;
  
--- 3673,3680 ----
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  *code = *code == GTU ? GEU : LTU;
! 	  return;
  	}
        break;
  
*************** arm_canonicalize_comparison (enum rtx_co
*** 3670,3684 ****
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  return code == GEU ? GTU : LEU;
  	}
        break;
  
      default:
        gcc_unreachable ();
      }
- 
-   return code;
  }
  
  
--- 3684,3697 ----
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  *code = *code == GEU ? GTU : LEU;
! 	  return;
  	}
        break;
  
      default:
        gcc_unreachable ();
      }
  }
  
  
*************** bool
*** 26979,26985 ****
  arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
  {
    enum rtx_code code = GET_CODE (*comparison);
!   enum rtx_code canonical_code;
    enum machine_mode mode = (GET_MODE (*op1) == VOIDmode) 
      ? GET_MODE (*op2) : GET_MODE (*op1);
  
--- 26992,26998 ----
  arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
  {
    enum rtx_code code = GET_CODE (*comparison);
!   int code_int;
    enum machine_mode mode = (GET_MODE (*op1) == VOIDmode) 
      ? GET_MODE (*op2) : GET_MODE (*op1);
  
*************** arm_validize_comparison (rtx *comparison
*** 26988,26995 ****
    if (code == UNEQ || code == LTGT)
      return false;
  
!   canonical_code = arm_canonicalize_comparison (code, op1, op2);
!   PUT_CODE (*comparison, canonical_code);
  
    switch (mode)
      {
--- 27001,27009 ----
    if (code == UNEQ || code == LTGT)
      return false;
  
!   code_int = (int)code;
!   arm_canonicalize_comparison (&code_int, op1, op2, 0);
!   PUT_CODE (*comparison, (enum rtx_code)code_int);
  
    switch (mode)
      {
Index: gcc/config/arm/arm.h
===================================================================
*** gcc/config/arm/arm.h.orig
--- gcc/config/arm/arm.h
*************** extern int making_const_table;
*** 2078,2086 ****
     ? reverse_condition_maybe_unordered (code) \
     : reverse_condition (code))
  
- #define CANONICALIZE_COMPARISON(CODE, OP0, OP1)				\
-   (CODE) = arm_canonicalize_comparison (CODE, &(OP0), &(OP1))
- 
  /* The arm5 clz instruction returns 32.  */
  #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
  #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
--- 2078,2083 ----
Index: gcc/config/s390/s390-protos.h
===================================================================
*** gcc/config/s390/s390-protos.h.orig
--- gcc/config/s390/s390-protos.h
*************** extern int tls_symbolic_operand (rtx);
*** 58,64 ****
  extern bool s390_match_ccmode (rtx, enum machine_mode);
  extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
  extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
- extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx *);
  extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
  extern void s390_emit_jump (rtx, rtx);
  extern bool symbolic_reference_mentioned_p (rtx);
--- 58,63 ----
Index: gcc/config/s390/s390.c
===================================================================
*** gcc/config/s390/s390.c.orig
--- gcc/config/s390/s390.c
*************** s390_select_ccmode (enum rtx_code code, 
*** 745,753 ****
  /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
     that we can implement more efficiently.  */
  
! void
! s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
  {
    /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
    if ((*code == EQ || *code == NE)
        && *op1 == const0_rtx
--- 745,757 ----
  /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
     that we can implement more efficiently.  */
  
! static void
! s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
! 			      bool op0_preserve_value)
  {
+   if (op0_preserve_value)
+     return;
+ 
    /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
    if ((*code == EQ || *code == NE)
        && *op1 == const0_rtx
*************** s390_canonicalize_comparison (enum rtx_c
*** 894,900 ****
    if (MEM_P (*op0) && REG_P (*op1))
      {
        rtx tem = *op0; *op0 = *op1; *op1 = tem;
!       *code = swap_condition (*code);
      }
  }
  
--- 898,904 ----
    if (MEM_P (*op0) && REG_P (*op1))
      {
        rtx tem = *op0; *op0 = *op1; *op1 = tem;
!       *code = (int)swap_condition ((enum rtx_code)*code);
      }
  }
  
*************** s390_loop_unroll_adjust (unsigned nunrol
*** 11071,11076 ****
--- 11075,11083 ----
  #undef TARGET_UNWIND_WORD_MODE
  #define TARGET_UNWIND_WORD_MODE s390_unwind_word_mode
  
+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON s390_canonicalize_comparison
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  #include "gt-s390.h"
Index: gcc/config/s390/s390.h
===================================================================
*** gcc/config/s390/s390.h.orig
--- gcc/config/s390/s390.h
*************** do {									\
*** 720,729 ****
     return the mode to be used for the comparison.  */
  #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
  
- /* Canonicalize a comparison from one we don't have to one we do have.  */
- #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
-   s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
- 
  /* Relative costs of operations.  */
  
  /* A C expression for the cost of a branch instruction.  A value of 1
--- 720,725 ----
Index: gcc/config/sh/sh-protos.h
===================================================================
*** gcc/config/sh/sh-protos.h.orig
--- gcc/config/sh/sh-protos.h
*************** extern bool sh_expand_t_scc (rtx *);
*** 159,166 ****
  extern rtx sh_gen_truncate (enum machine_mode, rtx, int);
  extern bool sh_vector_mode_supported_p (enum machine_mode);
  extern bool sh_cfun_trap_exit_p (void);
- extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
- 					enum machine_mode mode = VOIDmode);
  extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem);
  extern int sh_eval_treg_value (rtx op);
  
--- 159,164 ----
Index: gcc/config/sh/sh.c
===================================================================
*** gcc/config/sh/sh.c.orig
--- gcc/config/sh/sh.c
*************** static int max_mov_insn_displacement (en
*** 314,319 ****
--- 314,322 ----
  static int mov_insn_alignment_mask (enum machine_mode, bool);
  static HOST_WIDE_INT disp_addr_displacement (rtx);
  static bool sequence_insn_p (rtx);
+ static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool);
+ static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
+ 					enum machine_mode, bool);
  
  static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
  \f
*************** static const struct attribute_spec sh_at
*** 586,591 ****
--- 589,597 ----
  #undef TARGET_LEGITIMATE_CONSTANT_P
  #define TARGET_LEGITIMATE_CONSTANT_P	sh_legitimate_constant_p
  
+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON	sh_canonicalize_comparison
+ 
  /* Machine-specific symbol_ref flags.  */
  #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
  
*************** prepare_move_operands (rtx operands[], e
*** 1909,1920 ****
      }
  }
  
! /* Implement the CANONICALIZE_COMPARISON macro for the combine pass.
!    This function is also re-used to canonicalize comparisons in cbranch
!    pattern expanders.  */
! void
  sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
! 			    enum machine_mode mode)
  {
    /* When invoked from within the combine pass the mode is not specified,
       so try to get it from one of the operands.  */
--- 1915,1928 ----
      }
  }
  
! /* Implement the canonicalize_comparison target hook for the combine
!    pass.  For the target hook this function is invoked via
!    sh_canonicalize_comparison.  This function is also re-used to
!    canonicalize comparisons in cbranch pattern expanders.  */
! static void
  sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
! 			    enum machine_mode mode,
! 			    bool op0_preserve_value ATTRIBUTE_UNUSED)
  {
    /* When invoked from within the combine pass the mode is not specified,
       so try to get it from one of the operands.  */
*************** sh_canonicalize_comparison (enum rtx_cod
*** 2008,2013 ****
--- 2016,2034 ----
      }
  }
  
+ /* This function implements the canonicalize_comparison target hook.
+    This wrapper around the internally used sh_canonicalize_comparison
+    function is needed to do the enum rtx_code <-> int conversion.
+    Target hooks cannot use enum rtx_code in its definition.  */
+ static void
+ sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ 			    bool op0_preserve_value)
+ {
+   enum rtx_code tmp_code = (enum rtx_code)*code;
+   sh_canonicalize_comparison (tmp_code, *op0, *op1,
+ 			      VOIDmode, op0_preserve_value);
+   *code = (int)tmp_code;
+ }
  enum rtx_code
  prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
  			  enum rtx_code comparison)
*************** prepare_cbranch_operands (rtx *operands,
*** 2021,2027 ****
    else
      scratch = operands[4];
  
!   sh_canonicalize_comparison (comparison, operands[1], operands[2], mode);
  
    /* Notice that this function is also invoked after reload by
       the cbranchdi4_i pattern, through expand_cbranchdi4.  */
--- 2042,2049 ----
    else
      scratch = operands[4];
  
!   sh_canonicalize_comparison (comparison, operands[1], operands[2],
! 			      mode, false);
  
    /* Notice that this function is also invoked after reload by
       the cbranchdi4_i pattern, through expand_cbranchdi4.  */
Index: gcc/config/sh/sh.h
===================================================================
*** gcc/config/sh/sh.h.orig
--- gcc/config/sh/sh.h
*************** struct sh_args {
*** 1873,1882 ****
     more compact code.  */
  #define SHIFT_COUNT_TRUNCATED (0)
  
- /* CANONICALIZE_COMPARISON macro for the combine pass.  */
- #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
-   sh_canonicalize_comparison ((CODE), (OP0), (OP1))
- 
  /* All integers have the same format so truncation is easy.  */
  /* But SHmedia must sign-extend DImode when truncating to SImode.  */
  #define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) \
--- 1873,1878 ----
Index: gcc/config/spu/spu.c
===================================================================
*** gcc/config/spu/spu.c.orig
--- gcc/config/spu/spu.c
*************** spu_output_mi_thunk (FILE *file, tree th
*** 7095,7100 ****
--- 7095,7114 ----
    final_end_function ();
  }
  
+ /* Canonicalize a comparison from one we don't have to one we do have.  */
+ static void
+ spu_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ 			     bool op0_preserve_value)
+ {
+   if (!op0_preserve_value
+       && (*code == LE || *code == LT || *code == LEU || *code == LTU))
+     {
+       rtx tem = *op0;
+       *op0 = *op1;
+       *op1 = tem;
+       *code = (int)swap_condition ((enum rtx_code)*code);
+     }
+ }
  \f
  /*  Table of machine attributes.  */
  static const struct attribute_spec spu_attribute_table[] =
*************** static const struct attribute_spec spu_a
*** 7308,7313 ****
--- 7322,7330 ----
  #undef TARGET_DELAY_VARTRACK
  #define TARGET_DELAY_VARTRACK true
  
+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  #include "gt-spu.h"
Index: gcc/config/spu/spu.h
===================================================================
*** gcc/config/spu/spu.h.orig
--- gcc/config/spu/spu.h
*************** do {									\
*** 520,537 ****
  
  #define NO_IMPLICIT_EXTERN_C 1
  
- /* Canonicalize a comparison from one we don't have to one we do have.  */
- #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
-   do {                                                                    \
-     if (((CODE) == LE || (CODE) == LT || (CODE) == LEU || (CODE) == LTU)) \
-       {                                                                   \
-         rtx tem = (OP0);                                                  \
-         (OP0) = (OP1);                                                    \
-         (OP1) = tem;                                                      \
-         (CODE) = swap_condition (CODE);                                   \
-       }                                                                   \
-   } while (0)
- 
  
  /* Address spaces.  */
  #define ADDR_SPACE_EA	1
--- 520,525 ----
Index: gcc/doc/tm.texi.in
===================================================================
*** gcc/doc/tm.texi.in.orig
--- gcc/doc/tm.texi.in
*************** You should define this macro if and only
*** 5928,5952 ****
  in @file{@var{machine}-modes.def}.
  @end defmac
  
! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.
  
! On such machines, define this macro to be a C statement to do any
! required conversions.  @var{code} is the initial comparison code
! and @var{op0} and @var{op1} are the left and right operands of the
! comparison, respectively.  You should modify @var{code}, @var{op0}, and
! @var{op1} as required.
  
  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.
  
! You need not define this macro if it would never change the comparison
! code or operands.
! @end defmac
  
  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a
--- 5928,5954 ----
  in @file{@var{machine}-modes.def}.
  @end defmac
  
! @hook TARGET_CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.
  
! On such machines, implement this hook to do any required conversions.
! @var{code} is the initial comparison code and @var{op0} and @var{op1}
! are the left and right operands of the comparison, respectively.  If
! @var{op0_preserve_value} is @code{true} the implementation is not
! allowed to change the value of @var{op0} since the value might be used
! in RTXs which aren't comparisons.  E.g. the implementation is not
! allowed to swap operands in that case.
  
  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.
  
! You need not to implement this hook if it would never change the
! comparison code or operands.
! @end deftypefn
  
  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a
Index: gcc/target.def
===================================================================
*** gcc/target.def.orig
--- gcc/target.def
*************** DEFHOOK
*** 2877,2882 ****
--- 2877,2890 ----
   enum unwind_info_type, (void),
   default_debug_unwind_info)
  
+ /* The code parameter should be of type enum rtx_code but this is not
+    defined at this time.  */
+ DEFHOOK
+ (canonicalize_comparison,
+  "",
+  void, (int *code, rtx *op0, rtx *op1, bool op0_preserve_value),
+  default_canonicalize_comparison)
+ 
  DEFHOOKPOD
  (atomic_test_and_set_trueval,
   "This value should be set if the result written by\
Index: gcc/targhooks.h
===================================================================
*** gcc/targhooks.h.orig
--- gcc/targhooks.h
*************** extern unsigned char default_class_max_n
*** 179,184 ****
--- 179,186 ----
  
  extern enum unwind_info_type default_debug_unwind_info (void);
  
+ extern bool default_canonicalize_comparison (int *, rtx *, rtx *, bool);
+ 
  extern int default_label_align_after_barrier_max_skip (rtx);
  extern int default_loop_align_max_skip (rtx);
  extern int default_label_align_max_skip (rtx);
Index: gcc/doc/tm.texi
===================================================================
*** gcc/doc/tm.texi.orig
--- gcc/doc/tm.texi
*************** You should define this macro if and only
*** 6024,6048 ****
  in @file{@var{machine}-modes.def}.
  @end defmac
  
! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.
  
! On such machines, define this macro to be a C statement to do any
! required conversions.  @var{code} is the initial comparison code
! and @var{op0} and @var{op1} are the left and right operands of the
! comparison, respectively.  You should modify @var{code}, @var{op0}, and
! @var{op1} as required.
  
  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.
  
! You need not define this macro if it would never change the comparison
! code or operands.
! @end defmac
  
  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a
--- 6024,6050 ----
  in @file{@var{machine}-modes.def}.
  @end defmac
  
! @deftypefn {Target Hook} void TARGET_CANONICALIZE_COMPARISON (int *@var{code}, rtx *@var{op0}, rtx *@var{op1}, bool @var{op0_preserve_value}) (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.
  
! On such machines, implement this hook to do any required conversions.
! @var{code} is the initial comparison code and @var{op0} and @var{op1}
! are the left and right operands of the comparison, respectively.  If
! @var{op0_preserve_value} is @code{true} the implementation is not
! allowed to change the value of @var{op0} since the value might be used
! in RTXs which aren't comparisons.  E.g. the implementation is not
! allowed to swap operands in that case.
  
  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.
  
! You need not to implement this hook if it would never change the
! comparison code or operands.
! @end deftypefn
  
  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PING] Bugfix: Additional parameter for canonicalize comparison
  2012-12-12 11:23 [PATCH] Bugfix: Additional parameter for canonicalize comparison Andreas Krebbel
@ 2012-12-19  9:53 ` Andreas Krebbel
  2012-12-19 11:34   ` Richard Earnshaw
  0 siblings, 1 reply; 6+ messages in thread
From: Andreas Krebbel @ 2012-12-19  9:53 UTC (permalink / raw)
  To: nickc, richard.earnshaw, paul, ramana.radhakrishnan, gcc-patches

Hi,

are the ARM parts of the patch below ok for mainline?

I did a compile test with a cross.

Bye,

-Andreas-


-------- Original Message --------
Subject: [PATCH] Bugfix: Additional parameter for canonicalize comparison
Date: Wed, 12 Dec 2012 12:23:14 +0100
From: Andreas Krebbel <krebbel@linux.vnet.ibm.com>
To: rearnsha@arm.com
CC: gcc-patches@gcc.gnu.org

Hi Richard,

is the attached patch ok for ARM?

Bye,

-Andreas-

2012-12-12  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* target.def: Define canonicalize_comparison hook.
	* targhooks.h (default_canonicalize_comparison): New prototype.
	* targhooks.c (default_canonicalize_comparison): New function.
	* doc/tm.texi: Add documentation for the new target hook.
	* doc/tm.texi.in: Likewise.
	* combine.c (try_combine): Adjust to use the target hook.
	* config/alpha/alpha.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/alpha/alpha.c (alpha_canonicalize_comparison): New
	function.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/arm/arm-protos.h (arm_canonicalize_comparison): Remove
	prototype.
	* config/arm/arm.c (arm_canonicalize_comparison): Add new
	parameter.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/arm/arm.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/s390/s390-protos.h (s390_canonicalize_comparison): Remove
	prototype.
	* config/s390/s390.c (s390_canonicalize_comparison): Add new
	parameter.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/s390/s390.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/sh/sh-protos.h (sh_canonicalize_comparison): Remove
	prototype.
	* config/sh/sh.c (sh_canonicalize_comparison): Add new prototype.  New
	function overloading the old one.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/sh/sh.h (CANONICALIZE_COMPARISON): Remove macro
	definition.
	* config/spu/spu.c (spu_canonicalize_comparison): New function.
	(TARGET_CANONICALIZE_COMPARISON): New macro definition.
	* config/spu/spu.h (CANONICALIZE_COMPARISON): Remove macro
	definition.

---
 gcc/combine.c                 |   19 ++++++-!!!
 gcc/config/alpha/alpha.c      |   27 ++++++++++++++++
 gcc/config/alpha/alpha.h      |   20 ------------
 gcc/config/arm/arm-protos.h   |    1
 gcc/config/arm/arm.c          |   68 ++-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 gcc/config/arm/arm.h          |    3 -
 gcc/config/s390/s390-protos.h |    1
 gcc/config/s390/s390.c        |   13 +++!!!!!
 gcc/config/s390/s390.h        |    4 --
 gcc/config/sh/sh-protos.h     |    2 -
 gcc/config/sh/sh.c            |   34 +++++++++++!!!!!!!!!!
 gcc/config/sh/sh.h            |    4 --
 gcc/config/spu/spu.c          |   17 ++++++++++
 gcc/config/spu/spu.h          |   12 -------
 gcc/doc/tm.texi               |   20 !!!!!!!!!!!!
 gcc/doc/tm.texi.in            |   20 !!!!!!!!!!!!
 gcc/target.def                |    8 ++++
 gcc/targhooks.h               |    2 +
 18 files changed, 94 insertions(+), 50 deletions(-), 131 modifications(!)

Index: gcc/combine.c
===================================================================
*** gcc/combine.c.orig
--- gcc/combine.c
*************** static rtx gen_lowpart_or_truncate (enum
*** 494,499 ****
--- 494,510 ----
  static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;

  \f
+ /* Convenience wrapper for the canonicalize_comparison target hook.
+    Target hooks cannot use enum rtx_code.  */
+ static inline void
+ target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
+ 				bool op0_preserve_value)
+ {
+   int code_int = (int)*code;
+   targetm.canonicalize_comparison (&code_int, op0, op1, op0_preserve_value);
+   *code = (enum rtx_code)code_int;
+ }
+
  /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
     PATTERN can not be split.  Otherwise, it returns an insn sequence.
     This is a wrapper around split_insns which ensures that the
*************** try_combine (rtx i3, rtx i2, rtx i1, rtx
*** 2944,2952 ****
  	  compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
  	  compare_code = simplify_compare_const (compare_code,
  						 op0, &op1);
! #ifdef CANONICALIZE_COMPARISON
! 	  CANONICALIZE_COMPARISON (compare_code, op0, op1);
! #endif
  	}

        /* Do the rest only if op1 is const0_rtx, which may be the
--- 2955,2961 ----
  	  compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
  	  compare_code = simplify_compare_const (compare_code,
  						 op0, &op1);
! 	  target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
  	}

        /* Do the rest only if op1 is const0_rtx, which may be the
*************** simplify_comparison (enum rtx_code code,
*** 11959,11969 ****
  	    }
  	}

- #ifdef CANONICALIZE_COMPARISON
    /* If this machine only supports a subset of valid comparisons, see if we
       can convert an unsupported one into a supported one.  */
!   CANONICALIZE_COMPARISON (code, op0, op1);
! #endif

    *pop0 = op0;
    *pop1 = op1;
--- 11968,11976 ----
  	    }
  	}

    /* If this machine only supports a subset of valid comparisons, see if we
       can convert an unsupported one into a supported one.  */
!   target_canonicalize_comparison (&code, &op0, &op1, 0);

    *pop0 = op0;
    *pop1 = op1;
Index: gcc/config/alpha/alpha.c
===================================================================
*** gcc/config/alpha/alpha.c.orig
--- gcc/config/alpha/alpha.c
*************** alpha_conditional_register_usage (void)
*** 9683,9688 ****
--- 9683,9712 ----
      for (i = 32; i < 63; i++)
        fixed_regs[i] = call_used_regs[i] = 1;
  }
+
+ /* Canonicalize a comparison from one we don't have to one we do have.  */
+
+ static void
+ alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ 			       bool op0_preserve_value)
+ {
+   if (!op0_preserve_value
+       && (*code == GE || *code == GT || *code == GEU || *code == GTU)
+       && (REG_P (*op1) || *op1 == const0_rtx))
+     {
+       rtx tem = *op0;
+       *op0 = *op1;
+       *op1 = tem;
+       *code = (int)swap_condition ((enum rtx_code)*code);
+     }
+
+   if ((*code == LT || *code == LTU)
+       && CONST_INT_P (*op1) && INTVAL (*op1) == 256)
+     {
+       *code = *code == LT ? LE : LEU;
+       *op1 = GEN_INT (255);
+     }
+ }
  \f
  /* Initialize the GCC target structure.  */
  #if TARGET_ABI_OPEN_VMS
*************** alpha_conditional_register_usage (void)
*** 9850,9855 ****
--- 9874,9882 ----
  #undef TARGET_CONDITIONAL_REGISTER_USAGE
  #define TARGET_CONDITIONAL_REGISTER_USAGE alpha_conditional_register_usage

+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison
+
  struct gcc_target targetm = TARGET_INITIALIZER;

  \f
Index: gcc/config/alpha/alpha.h
===================================================================
*** gcc/config/alpha/alpha.h.orig
--- gcc/config/alpha/alpha.h
*************** do {									     \
*** 922,947 ****
  #define FLOAT_STORE_FLAG_VALUE(MODE) \
    REAL_VALUE_ATOF ((TARGET_FLOAT_VAX ? "0.5" : "2.0"), (MODE))

- /* Canonicalize a comparison from one we don't have to one we do have.  */
-
- #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
-   do {									\
-     if (((CODE) == GE || (CODE) == GT || (CODE) == GEU || (CODE) == GTU) \
- 	&& (REG_P (OP1) || (OP1) == const0_rtx))		\
-       {									\
- 	rtx tem = (OP0);						\
- 	(OP0) = (OP1);							\
- 	(OP1) = tem;							\
- 	(CODE) = swap_condition (CODE);					\
-       }									\
-     if (((CODE) == LT || (CODE) == LTU)					\
- 	&& CONST_INT_P (OP1) && INTVAL (OP1) == 256)			\
-       {									\
- 	(CODE) = (CODE) == LT ? LE : LEU;				\
- 	(OP1) = GEN_INT (255);						\
-       }									\
-   } while (0)
-
  /* Specify the machine mode that pointers have.
     After generation of rtl, the compiler makes no further distinction
     between pointers and any other objects of this machine mode.  */
--- 922,927 ----
Index: gcc/config/arm/arm-protos.h
===================================================================
*** gcc/config/arm/arm-protos.h.orig
--- gcc/config/arm/arm-protos.h
*************** extern int const_ok_for_op (HOST_WIDE_IN
*** 53,59 ****
  extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
  extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
  			       HOST_WIDE_INT, rtx, rtx, int);
- extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *, rtx *);
  extern int legitimate_pic_operand_p (rtx);
  extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
  extern rtx legitimize_tls_address (rtx, rtx);
--- 53,58 ----
Index: gcc/config/arm/arm.c
===================================================================
*** gcc/config/arm/arm.c.orig
--- gcc/config/arm/arm.c
*************** static int arm_cortex_a5_branch_cost (bo
*** 269,275 ****

  static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
  					     const unsigned char *sel);
!
  \f
  /* Table of machine attributes.  */
  static const struct attribute_spec arm_attribute_table[] =
--- 269,276 ----

  static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
  					     const unsigned char *sel);
! static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
! 					 bool op0_preserve_value);
  \f
  /* Table of machine attributes.  */
  static const struct attribute_spec arm_attribute_table[] =
*************** static const struct attribute_spec arm_a
*** 626,631 ****
--- 627,636 ----
  #define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
    arm_vectorize_vec_perm_const_ok

+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON \
+   arm_canonicalize_comparison
+
  struct gcc_target targetm = TARGET_INITIALIZER;
  \f
  /* Obstack for minipool constant handling.  */
*************** arm_gen_constant (enum rtx_code code, en
*** 3543,3550 ****
     This can be done for a few constant compares, where we can make the
     immediate value easier to load.  */

! enum rtx_code
! arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
  {
    enum machine_mode mode;
    unsigned HOST_WIDE_INT i, maxval;
--- 3548,3556 ----
     This can be done for a few constant compares, where we can make the
     immediate value easier to load.  */

! static void
! arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
! 			     bool op0_preserve_value)
  {
    enum machine_mode mode;
    unsigned HOST_WIDE_INT i, maxval;
*************** arm_canonicalize_comparison (enum rtx_co
*** 3563,3577 ****
      {
        rtx tem;

!       if (code == GT || code == LE
! 	  || (!TARGET_ARM && (code == GTU || code == LEU)))
  	{
  	  /* Missing comparison.  First try to use an available
  	     comparison.  */
  	  if (CONST_INT_P (*op1))
  	    {
  	      i = INTVAL (*op1);
! 	      switch (code)
  		{
  		case GT:
  		case LE:
--- 3569,3583 ----
      {
        rtx tem;

!       if (*code == GT || *code == LE
! 	  || (!TARGET_ARM && (*code == GTU || *code == LEU)))
  	{
  	  /* Missing comparison.  First try to use an available
  	     comparison.  */
  	  if (CONST_INT_P (*op1))
  	    {
  	      i = INTVAL (*op1);
! 	      switch (*code)
  		{
  		case GT:
  		case LE:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3579,3585 ****
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      return code == GT ? GE : LT;
  		    }
  		  break;
  		case GTU:
--- 3585,3592 ----
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      *code = *code == GT ? GE : LT;
! 		      return;
  		    }
  		  break;
  		case GTU:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3588,3594 ****
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      return code == GTU ? GEU : LTU;
  		    }
  		  break;
  		default:
--- 3595,3602 ----
  		      && arm_const_double_by_immediates (GEN_INT (i + 1)))
  		    {
  		      *op1 = GEN_INT (i + 1);
! 		      *code = *code == GTU ? GEU : LTU;
! 		      return;
  		    }
  		  break;
  		default:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3597,3615 ****
  	    }

  	  /* If that did not work, reverse the condition.  */
! 	  tem = *op0;
! 	  *op0 = *op1;
! 	  *op1 = tem;
! 	  return swap_condition (code);
  	}
!
!       return code;
      }

    /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
       with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
       to facilitate possible combining with a cmp into 'ands'.  */
!   if (mode == SImode
        && GET_CODE (*op0) == ZERO_EXTEND
        && GET_CODE (XEXP (*op0, 0)) == SUBREG
        && GET_MODE (XEXP (*op0, 0)) == QImode
--- 3605,3626 ----
  	    }

  	  /* If that did not work, reverse the condition.  */
! 	  if (!op0_preserve_value)
! 	    {
! 	      tem = *op0;
! 	      *op0 = *op1;
! 	      *op1 = tem;
! 	      *code = (int)swap_condition ((enum rtx_code)*code);
! 	    }
  	}
!       return;
      }

    /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
       with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
       to facilitate possible combining with a cmp into 'ands'.  */
!   if (!op0_preserve_value
!       && mode == SImode
        && GET_CODE (*op0) == ZERO_EXTEND
        && GET_CODE (XEXP (*op0, 0)) == SUBREG
        && GET_MODE (XEXP (*op0, 0)) == QImode
*************** arm_canonicalize_comparison (enum rtx_co
*** 3624,3638 ****
    if (!CONST_INT_P (*op1)
        || const_ok_for_arm (INTVAL (*op1))
        || const_ok_for_arm (- INTVAL (*op1)))
!     return code;

    i = INTVAL (*op1);

!   switch (code)
      {
      case EQ:
      case NE:
!       return code;

      case GT:
      case LE:
--- 3635,3649 ----
    if (!CONST_INT_P (*op1)
        || const_ok_for_arm (INTVAL (*op1))
        || const_ok_for_arm (- INTVAL (*op1)))
!     return;

    i = INTVAL (*op1);

!   switch (*code)
      {
      case EQ:
      case NE:
!       return;

      case GT:
      case LE:
*************** arm_canonicalize_comparison (enum rtx_co
*** 3640,3646 ****
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  return code == GT ? GE : LT;
  	}
        break;

--- 3651,3658 ----
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  *code = *code == GT ? GE : LT;
! 	  return;
  	}
        break;

*************** arm_canonicalize_comparison (enum rtx_co
*** 3650,3656 ****
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  return code == GE ? GT : LE;
  	}
        break;

--- 3662,3669 ----
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  *code = *code == GE ? GT : LE;
! 	  return;
  	}
        break;

*************** arm_canonicalize_comparison (enum rtx_co
*** 3660,3666 ****
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  return code == GTU ? GEU : LTU;
  	}
        break;

--- 3673,3680 ----
  	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
  	{
  	  *op1 = GEN_INT (i + 1);
! 	  *code = *code == GTU ? GEU : LTU;
! 	  return;
  	}
        break;

*************** arm_canonicalize_comparison (enum rtx_co
*** 3670,3684 ****
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  return code == GEU ? GTU : LEU;
  	}
        break;

      default:
        gcc_unreachable ();
      }
-
-   return code;
  }


--- 3684,3697 ----
  	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
  	{
  	  *op1 = GEN_INT (i - 1);
! 	  *code = *code == GEU ? GTU : LEU;
! 	  return;
  	}
        break;

      default:
        gcc_unreachable ();
      }
  }


*************** bool
*** 26979,26985 ****
  arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
  {
    enum rtx_code code = GET_CODE (*comparison);
!   enum rtx_code canonical_code;
    enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
      ? GET_MODE (*op2) : GET_MODE (*op1);

--- 26992,26998 ----
  arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
  {
    enum rtx_code code = GET_CODE (*comparison);
!   int code_int;
    enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
      ? GET_MODE (*op2) : GET_MODE (*op1);

*************** arm_validize_comparison (rtx *comparison
*** 26988,26995 ****
    if (code == UNEQ || code == LTGT)
      return false;

!   canonical_code = arm_canonicalize_comparison (code, op1, op2);
!   PUT_CODE (*comparison, canonical_code);

    switch (mode)
      {
--- 27001,27009 ----
    if (code == UNEQ || code == LTGT)
      return false;

!   code_int = (int)code;
!   arm_canonicalize_comparison (&code_int, op1, op2, 0);
!   PUT_CODE (*comparison, (enum rtx_code)code_int);

    switch (mode)
      {
Index: gcc/config/arm/arm.h
===================================================================
*** gcc/config/arm/arm.h.orig
--- gcc/config/arm/arm.h
*************** extern int making_const_table;
*** 2078,2086 ****
     ? reverse_condition_maybe_unordered (code) \
     : reverse_condition (code))

- #define CANONICALIZE_COMPARISON(CODE, OP0, OP1)				\
-   (CODE) = arm_canonicalize_comparison (CODE, &(OP0), &(OP1))
-
  /* The arm5 clz instruction returns 32.  */
  #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
  #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
--- 2078,2083 ----
Index: gcc/config/s390/s390-protos.h
===================================================================
*** gcc/config/s390/s390-protos.h.orig
--- gcc/config/s390/s390-protos.h
*************** extern int tls_symbolic_operand (rtx);
*** 58,64 ****
  extern bool s390_match_ccmode (rtx, enum machine_mode);
  extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
  extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
- extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx *);
  extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
  extern void s390_emit_jump (rtx, rtx);
  extern bool symbolic_reference_mentioned_p (rtx);
--- 58,63 ----
Index: gcc/config/s390/s390.c
===================================================================
*** gcc/config/s390/s390.c.orig
--- gcc/config/s390/s390.c
*************** s390_select_ccmode (enum rtx_code code,
*** 745,753 ****
  /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
     that we can implement more efficiently.  */

! void
! s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
  {
    /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
    if ((*code == EQ || *code == NE)
        && *op1 == const0_rtx
--- 745,757 ----
  /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
     that we can implement more efficiently.  */

! static void
! s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
! 			      bool op0_preserve_value)
  {
+   if (op0_preserve_value)
+     return;
+
    /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
    if ((*code == EQ || *code == NE)
        && *op1 == const0_rtx
*************** s390_canonicalize_comparison (enum rtx_c
*** 894,900 ****
    if (MEM_P (*op0) && REG_P (*op1))
      {
        rtx tem = *op0; *op0 = *op1; *op1 = tem;
!       *code = swap_condition (*code);
      }
  }

--- 898,904 ----
    if (MEM_P (*op0) && REG_P (*op1))
      {
        rtx tem = *op0; *op0 = *op1; *op1 = tem;
!       *code = (int)swap_condition ((enum rtx_code)*code);
      }
  }

*************** s390_loop_unroll_adjust (unsigned nunrol
*** 11071,11076 ****
--- 11075,11083 ----
  #undef TARGET_UNWIND_WORD_MODE
  #define TARGET_UNWIND_WORD_MODE s390_unwind_word_mode

+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON s390_canonicalize_comparison
+
  struct gcc_target targetm = TARGET_INITIALIZER;

  #include "gt-s390.h"
Index: gcc/config/s390/s390.h
===================================================================
*** gcc/config/s390/s390.h.orig
--- gcc/config/s390/s390.h
*************** do {									\
*** 720,729 ****
     return the mode to be used for the comparison.  */
  #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))

- /* Canonicalize a comparison from one we don't have to one we do have.  */
- #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
-   s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
-
  /* Relative costs of operations.  */

  /* A C expression for the cost of a branch instruction.  A value of 1
--- 720,725 ----
Index: gcc/config/sh/sh-protos.h
===================================================================
*** gcc/config/sh/sh-protos.h.orig
--- gcc/config/sh/sh-protos.h
*************** extern bool sh_expand_t_scc (rtx *);
*** 159,166 ****
  extern rtx sh_gen_truncate (enum machine_mode, rtx, int);
  extern bool sh_vector_mode_supported_p (enum machine_mode);
  extern bool sh_cfun_trap_exit_p (void);
- extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
- 					enum machine_mode mode = VOIDmode);
  extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem);
  extern int sh_eval_treg_value (rtx op);

--- 159,164 ----
Index: gcc/config/sh/sh.c
===================================================================
*** gcc/config/sh/sh.c.orig
--- gcc/config/sh/sh.c
*************** static int max_mov_insn_displacement (en
*** 314,319 ****
--- 314,322 ----
  static int mov_insn_alignment_mask (enum machine_mode, bool);
  static HOST_WIDE_INT disp_addr_displacement (rtx);
  static bool sequence_insn_p (rtx);
+ static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool);
+ static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
+ 					enum machine_mode, bool);

  static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
  \f
*************** static const struct attribute_spec sh_at
*** 586,591 ****
--- 589,597 ----
  #undef TARGET_LEGITIMATE_CONSTANT_P
  #define TARGET_LEGITIMATE_CONSTANT_P	sh_legitimate_constant_p

+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON	sh_canonicalize_comparison
+
  /* Machine-specific symbol_ref flags.  */
  #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)

*************** prepare_move_operands (rtx operands[], e
*** 1909,1920 ****
      }
  }

! /* Implement the CANONICALIZE_COMPARISON macro for the combine pass.
!    This function is also re-used to canonicalize comparisons in cbranch
!    pattern expanders.  */
! void
  sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
! 			    enum machine_mode mode)
  {
    /* When invoked from within the combine pass the mode is not specified,
       so try to get it from one of the operands.  */
--- 1915,1928 ----
      }
  }

! /* Implement the canonicalize_comparison target hook for the combine
!    pass.  For the target hook this function is invoked via
!    sh_canonicalize_comparison.  This function is also re-used to
!    canonicalize comparisons in cbranch pattern expanders.  */
! static void
  sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
! 			    enum machine_mode mode,
! 			    bool op0_preserve_value ATTRIBUTE_UNUSED)
  {
    /* When invoked from within the combine pass the mode is not specified,
       so try to get it from one of the operands.  */
*************** sh_canonicalize_comparison (enum rtx_cod
*** 2008,2013 ****
--- 2016,2034 ----
      }
  }

+ /* This function implements the canonicalize_comparison target hook.
+    This wrapper around the internally used sh_canonicalize_comparison
+    function is needed to do the enum rtx_code <-> int conversion.
+    Target hooks cannot use enum rtx_code in its definition.  */
+ static void
+ sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ 			    bool op0_preserve_value)
+ {
+   enum rtx_code tmp_code = (enum rtx_code)*code;
+   sh_canonicalize_comparison (tmp_code, *op0, *op1,
+ 			      VOIDmode, op0_preserve_value);
+   *code = (int)tmp_code;
+ }
  enum rtx_code
  prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
  			  enum rtx_code comparison)
*************** prepare_cbranch_operands (rtx *operands,
*** 2021,2027 ****
    else
      scratch = operands[4];

!   sh_canonicalize_comparison (comparison, operands[1], operands[2], mode);

    /* Notice that this function is also invoked after reload by
       the cbranchdi4_i pattern, through expand_cbranchdi4.  */
--- 2042,2049 ----
    else
      scratch = operands[4];

!   sh_canonicalize_comparison (comparison, operands[1], operands[2],
! 			      mode, false);

    /* Notice that this function is also invoked after reload by
       the cbranchdi4_i pattern, through expand_cbranchdi4.  */
Index: gcc/config/sh/sh.h
===================================================================
*** gcc/config/sh/sh.h.orig
--- gcc/config/sh/sh.h
*************** struct sh_args {
*** 1873,1882 ****
     more compact code.  */
  #define SHIFT_COUNT_TRUNCATED (0)

- /* CANONICALIZE_COMPARISON macro for the combine pass.  */
- #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
-   sh_canonicalize_comparison ((CODE), (OP0), (OP1))
-
  /* All integers have the same format so truncation is easy.  */
  /* But SHmedia must sign-extend DImode when truncating to SImode.  */
  #define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) \
--- 1873,1878 ----
Index: gcc/config/spu/spu.c
===================================================================
*** gcc/config/spu/spu.c.orig
--- gcc/config/spu/spu.c
*************** spu_output_mi_thunk (FILE *file, tree th
*** 7095,7100 ****
--- 7095,7114 ----
    final_end_function ();
  }

+ /* Canonicalize a comparison from one we don't have to one we do have.  */
+ static void
+ spu_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ 			     bool op0_preserve_value)
+ {
+   if (!op0_preserve_value
+       && (*code == LE || *code == LT || *code == LEU || *code == LTU))
+     {
+       rtx tem = *op0;
+       *op0 = *op1;
+       *op1 = tem;
+       *code = (int)swap_condition ((enum rtx_code)*code);
+     }
+ }
  \f
  /*  Table of machine attributes.  */
  static const struct attribute_spec spu_attribute_table[] =
*************** static const struct attribute_spec spu_a
*** 7308,7313 ****
--- 7322,7330 ----
  #undef TARGET_DELAY_VARTRACK
  #define TARGET_DELAY_VARTRACK true

+ #undef TARGET_CANONICALIZE_COMPARISON
+ #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
+
  struct gcc_target targetm = TARGET_INITIALIZER;

  #include "gt-spu.h"
Index: gcc/config/spu/spu.h
===================================================================
*** gcc/config/spu/spu.h.orig
--- gcc/config/spu/spu.h
*************** do {									\
*** 520,537 ****

  #define NO_IMPLICIT_EXTERN_C 1

- /* Canonicalize a comparison from one we don't have to one we do have.  */
- #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
-   do {                                                                    \
-     if (((CODE) == LE || (CODE) == LT || (CODE) == LEU || (CODE) == LTU)) \
-       {                                                                   \
-         rtx tem = (OP0);                                                  \
-         (OP0) = (OP1);                                                    \
-         (OP1) = tem;                                                      \
-         (CODE) = swap_condition (CODE);                                   \
-       }                                                                   \
-   } while (0)
-

  /* Address spaces.  */
  #define ADDR_SPACE_EA	1
--- 520,525 ----
Index: gcc/doc/tm.texi.in
===================================================================
*** gcc/doc/tm.texi.in.orig
--- gcc/doc/tm.texi.in
*************** You should define this macro if and only
*** 5928,5952 ****
  in @file{@var{machine}-modes.def}.
  @end defmac

! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.

! On such machines, define this macro to be a C statement to do any
! required conversions.  @var{code} is the initial comparison code
! and @var{op0} and @var{op1} are the left and right operands of the
! comparison, respectively.  You should modify @var{code}, @var{op0}, and
! @var{op1} as required.

  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.

! You need not define this macro if it would never change the comparison
! code or operands.
! @end defmac

  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a
--- 5928,5954 ----
  in @file{@var{machine}-modes.def}.
  @end defmac

! @hook TARGET_CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.

! On such machines, implement this hook to do any required conversions.
! @var{code} is the initial comparison code and @var{op0} and @var{op1}
! are the left and right operands of the comparison, respectively.  If
! @var{op0_preserve_value} is @code{true} the implementation is not
! allowed to change the value of @var{op0} since the value might be used
! in RTXs which aren't comparisons.  E.g. the implementation is not
! allowed to swap operands in that case.

  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.

! You need not to implement this hook if it would never change the
! comparison code or operands.
! @end deftypefn

  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a
Index: gcc/target.def
===================================================================
*** gcc/target.def.orig
--- gcc/target.def
*************** DEFHOOK
*** 2877,2882 ****
--- 2877,2890 ----
   enum unwind_info_type, (void),
   default_debug_unwind_info)

+ /* The code parameter should be of type enum rtx_code but this is not
+    defined at this time.  */
+ DEFHOOK
+ (canonicalize_comparison,
+  "",
+  void, (int *code, rtx *op0, rtx *op1, bool op0_preserve_value),
+  default_canonicalize_comparison)
+
  DEFHOOKPOD
  (atomic_test_and_set_trueval,
   "This value should be set if the result written by\
Index: gcc/targhooks.h
===================================================================
*** gcc/targhooks.h.orig
--- gcc/targhooks.h
*************** extern unsigned char default_class_max_n
*** 179,184 ****
--- 179,186 ----

  extern enum unwind_info_type default_debug_unwind_info (void);

+ extern bool default_canonicalize_comparison (int *, rtx *, rtx *, bool);
+
  extern int default_label_align_after_barrier_max_skip (rtx);
  extern int default_loop_align_max_skip (rtx);
  extern int default_label_align_max_skip (rtx);
Index: gcc/doc/tm.texi
===================================================================
*** gcc/doc/tm.texi.orig
--- gcc/doc/tm.texi
*************** You should define this macro if and only
*** 6024,6048 ****
  in @file{@var{machine}-modes.def}.
  @end defmac

! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.

! On such machines, define this macro to be a C statement to do any
! required conversions.  @var{code} is the initial comparison code
! and @var{op0} and @var{op1} are the left and right operands of the
! comparison, respectively.  You should modify @var{code}, @var{op0}, and
! @var{op1} as required.

  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.

! You need not define this macro if it would never change the comparison
! code or operands.
! @end defmac

  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a
--- 6024,6050 ----
  in @file{@var{machine}-modes.def}.
  @end defmac

! @deftypefn {Target Hook} void TARGET_CANONICALIZE_COMPARISON (int *@var{code}, rtx *@var{op0}, rtx
*@var{op1}, bool @var{op0_preserve_value}) (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
  On some machines not all possible comparisons are defined, but you can
  convert an invalid comparison into a valid one.  For example, the Alpha
  does not have a @code{GT} comparison, but you can use an @code{LT}
  comparison instead and swap the order of the operands.

! On such machines, implement this hook to do any required conversions.
! @var{code} is the initial comparison code and @var{op0} and @var{op1}
! are the left and right operands of the comparison, respectively.  If
! @var{op0_preserve_value} is @code{true} the implementation is not
! allowed to change the value of @var{op0} since the value might be used
! in RTXs which aren't comparisons.  E.g. the implementation is not
! allowed to swap operands in that case.

  GCC will not assume that the comparison resulting from this macro is
  valid but will see if the resulting insn matches a pattern in the
  @file{md} file.

! You need not to implement this hook if it would never change the
! comparison code or operands.
! @end deftypefn

  @defmac REVERSIBLE_CC_MODE (@var{mode})
  A C expression whose value is one if it is always safe to reverse a



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PING] Bugfix: Additional parameter for canonicalize comparison
  2012-12-19  9:53 ` [PING] " Andreas Krebbel
@ 2012-12-19 11:34   ` Richard Earnshaw
  2012-12-19 14:04     ` Richard Biener
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Earnshaw @ 2012-12-19 11:34 UTC (permalink / raw)
  To: Andreas Krebbel; +Cc: nickc, paul, Ramana Radhakrishnan, gcc-patches

On 19/12/12 09:53, Andreas Krebbel wrote:
> Hi,
>
> are the ARM parts of the patch below ok for mainline?
>

Yes.

Sorry for the delay.

R.

> I did a compile test with a cross.
>
> Bye,
>
> -Andreas-
>
>
> -------- Original Message --------
> Subject: [PATCH] Bugfix: Additional parameter for canonicalize comparison
> Date: Wed, 12 Dec 2012 12:23:14 +0100
> From: Andreas Krebbel <krebbel@linux.vnet.ibm.com>
> To: rearnsha@arm.com
> CC: gcc-patches@gcc.gnu.org
>
> Hi Richard,
>
> is the attached patch ok for ARM?
>
> Bye,
>
> -Andreas-
>
> 2012-12-12  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
>
>          * target.def: Define canonicalize_comparison hook.
>          * targhooks.h (default_canonicalize_comparison): New prototype.
>          * targhooks.c (default_canonicalize_comparison): New function.
>          * doc/tm.texi: Add documentation for the new target hook.
>          * doc/tm.texi.in: Likewise.
>          * combine.c (try_combine): Adjust to use the target hook.
>          * config/alpha/alpha.h (CANONICALIZE_COMPARISON): Remove macro
>          definition.
>          * config/alpha/alpha.c (alpha_canonicalize_comparison): New
>          function.
>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>          * config/arm/arm-protos.h (arm_canonicalize_comparison): Remove
>          prototype.
>          * config/arm/arm.c (arm_canonicalize_comparison): Add new
>          parameter.
>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>          * config/arm/arm.h (CANONICALIZE_COMPARISON): Remove macro
>          definition.
>          * config/s390/s390-protos.h (s390_canonicalize_comparison): Remove
>          prototype.
>          * config/s390/s390.c (s390_canonicalize_comparison): Add new
>          parameter.
>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>          * config/s390/s390.h (CANONICALIZE_COMPARISON): Remove macro
>          definition.
>          * config/sh/sh-protos.h (sh_canonicalize_comparison): Remove
>          prototype.
>          * config/sh/sh.c (sh_canonicalize_comparison): Add new prototype.  New
>          function overloading the old one.
>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>          * config/sh/sh.h (CANONICALIZE_COMPARISON): Remove macro
>          definition.
>          * config/spu/spu.c (spu_canonicalize_comparison): New function.
>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>          * config/spu/spu.h (CANONICALIZE_COMPARISON): Remove macro
>          definition.
>
> ---
>   gcc/combine.c                 |   19 ++++++-!!!
>   gcc/config/alpha/alpha.c      |   27 ++++++++++++++++
>   gcc/config/alpha/alpha.h      |   20 ------------
>   gcc/config/arm/arm-protos.h   |    1
>   gcc/config/arm/arm.c          |   68 ++-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>   gcc/config/arm/arm.h          |    3 -
>   gcc/config/s390/s390-protos.h |    1
>   gcc/config/s390/s390.c        |   13 +++!!!!!
>   gcc/config/s390/s390.h        |    4 --
>   gcc/config/sh/sh-protos.h     |    2 -
>   gcc/config/sh/sh.c            |   34 +++++++++++!!!!!!!!!!
>   gcc/config/sh/sh.h            |    4 --
>   gcc/config/spu/spu.c          |   17 ++++++++++
>   gcc/config/spu/spu.h          |   12 -------
>   gcc/doc/tm.texi               |   20 !!!!!!!!!!!!
>   gcc/doc/tm.texi.in            |   20 !!!!!!!!!!!!
>   gcc/target.def                |    8 ++++
>   gcc/targhooks.h               |    2 +
>   18 files changed, 94 insertions(+), 50 deletions(-), 131 modifications(!)
>
> Index: gcc/combine.c
> ===================================================================
> *** gcc/combine.c.orig
> --- gcc/combine.c
> *************** static rtx gen_lowpart_or_truncate (enum
> *** 494,499 ****
> --- 494,510 ----
>    static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
>
>
> + /* Convenience wrapper for the canonicalize_comparison target hook.
> +    Target hooks cannot use enum rtx_code.  */
> + static inline void
> + target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
> +                               bool op0_preserve_value)
> + {
> +   int code_int = (int)*code;
> +   targetm.canonicalize_comparison (&code_int, op0, op1, op0_preserve_value);
> +   *code = (enum rtx_code)code_int;
> + }
> +
>    /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
>       PATTERN can not be split.  Otherwise, it returns an insn sequence.
>       This is a wrapper around split_insns which ensures that the
> *************** try_combine (rtx i3, rtx i2, rtx i1, rtx
> *** 2944,2952 ****
>            compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
>            compare_code = simplify_compare_const (compare_code,
>                                                   op0, &op1);
> ! #ifdef CANONICALIZE_COMPARISON
> !         CANONICALIZE_COMPARISON (compare_code, op0, op1);
> ! #endif
>          }
>
>          /* Do the rest only if op1 is const0_rtx, which may be the
> --- 2955,2961 ----
>            compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
>            compare_code = simplify_compare_const (compare_code,
>                                                   op0, &op1);
> !         target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
>          }
>
>          /* Do the rest only if op1 is const0_rtx, which may be the
> *************** simplify_comparison (enum rtx_code code,
> *** 11959,11969 ****
>              }
>          }
>
> - #ifdef CANONICALIZE_COMPARISON
>      /* If this machine only supports a subset of valid comparisons, see if we
>         can convert an unsupported one into a supported one.  */
> !   CANONICALIZE_COMPARISON (code, op0, op1);
> ! #endif
>
>      *pop0 = op0;
>      *pop1 = op1;
> --- 11968,11976 ----
>              }
>          }
>
>      /* If this machine only supports a subset of valid comparisons, see if we
>         can convert an unsupported one into a supported one.  */
> !   target_canonicalize_comparison (&code, &op0, &op1, 0);
>
>      *pop0 = op0;
>      *pop1 = op1;
> Index: gcc/config/alpha/alpha.c
> ===================================================================
> *** gcc/config/alpha/alpha.c.orig
> --- gcc/config/alpha/alpha.c
> *************** alpha_conditional_register_usage (void)
> *** 9683,9688 ****
> --- 9683,9712 ----
>        for (i = 32; i < 63; i++)
>          fixed_regs[i] = call_used_regs[i] = 1;
>    }
> +
> + /* Canonicalize a comparison from one we don't have to one we do have.  */
> +
> + static void
> + alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
> +                              bool op0_preserve_value)
> + {
> +   if (!op0_preserve_value
> +       && (*code == GE || *code == GT || *code == GEU || *code == GTU)
> +       && (REG_P (*op1) || *op1 == const0_rtx))
> +     {
> +       rtx tem = *op0;
> +       *op0 = *op1;
> +       *op1 = tem;
> +       *code = (int)swap_condition ((enum rtx_code)*code);
> +     }
> +
> +   if ((*code == LT || *code == LTU)
> +       && CONST_INT_P (*op1) && INTVAL (*op1) == 256)
> +     {
> +       *code = *code == LT ? LE : LEU;
> +       *op1 = GEN_INT (255);
> +     }
> + }
>
>    /* Initialize the GCC target structure.  */
>    #if TARGET_ABI_OPEN_VMS
> *************** alpha_conditional_register_usage (void)
> *** 9850,9855 ****
> --- 9874,9882 ----
>    #undef TARGET_CONDITIONAL_REGISTER_USAGE
>    #define TARGET_CONDITIONAL_REGISTER_USAGE alpha_conditional_register_usage
>
> + #undef TARGET_CANONICALIZE_COMPARISON
> + #define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison
> +
>    struct gcc_target targetm = TARGET_INITIALIZER;
>
>
> Index: gcc/config/alpha/alpha.h
> ===================================================================
> *** gcc/config/alpha/alpha.h.orig
> --- gcc/config/alpha/alpha.h
> *************** do {                                                                         \
> *** 922,947 ****
>    #define FLOAT_STORE_FLAG_VALUE(MODE) \
>      REAL_VALUE_ATOF ((TARGET_FLOAT_VAX ? "0.5" : "2.0"), (MODE))
>
> - /* Canonicalize a comparison from one we don't have to one we do have.  */
> -
> - #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
> -   do {                                                                        \
> -     if (((CODE) == GE || (CODE) == GT || (CODE) == GEU || (CODE) == GTU) \
> -       && (REG_P (OP1) || (OP1) == const0_rtx))                \
> -       {                                                                       \
> -       rtx tem = (OP0);                                                \
> -       (OP0) = (OP1);                                                  \
> -       (OP1) = tem;                                                    \
> -       (CODE) = swap_condition (CODE);                                 \
> -       }                                                                       \
> -     if (((CODE) == LT || (CODE) == LTU)                                       \
> -       && CONST_INT_P (OP1) && INTVAL (OP1) == 256)                    \
> -       {                                                                       \
> -       (CODE) = (CODE) == LT ? LE : LEU;                               \
> -       (OP1) = GEN_INT (255);                                          \
> -       }                                                                       \
> -   } while (0)
> -
>    /* Specify the machine mode that pointers have.
>       After generation of rtl, the compiler makes no further distinction
>       between pointers and any other objects of this machine mode.  */
> --- 922,927 ----
> Index: gcc/config/arm/arm-protos.h
> ===================================================================
> *** gcc/config/arm/arm-protos.h.orig
> --- gcc/config/arm/arm-protos.h
> *************** extern int const_ok_for_op (HOST_WIDE_IN
> *** 53,59 ****
>    extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
>    extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
>                                 HOST_WIDE_INT, rtx, rtx, int);
> - extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *, rtx *);
>    extern int legitimate_pic_operand_p (rtx);
>    extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
>    extern rtx legitimize_tls_address (rtx, rtx);
> --- 53,58 ----
> Index: gcc/config/arm/arm.c
> ===================================================================
> *** gcc/config/arm/arm.c.orig
> --- gcc/config/arm/arm.c
> *************** static int arm_cortex_a5_branch_cost (bo
> *** 269,275 ****
>
>    static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
>                                               const unsigned char *sel);
> !
>
>    /* Table of machine attributes.  */
>    static const struct attribute_spec arm_attribute_table[] =
> --- 269,276 ----
>
>    static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
>                                               const unsigned char *sel);
> ! static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
> !                                        bool op0_preserve_value);
>
>    /* Table of machine attributes.  */
>    static const struct attribute_spec arm_attribute_table[] =
> *************** static const struct attribute_spec arm_a
> *** 626,631 ****
> --- 627,636 ----
>    #define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
>      arm_vectorize_vec_perm_const_ok
>
> + #undef TARGET_CANONICALIZE_COMPARISON
> + #define TARGET_CANONICALIZE_COMPARISON \
> +   arm_canonicalize_comparison
> +
>    struct gcc_target targetm = TARGET_INITIALIZER;
>
>    /* Obstack for minipool constant handling.  */
> *************** arm_gen_constant (enum rtx_code code, en
> *** 3543,3550 ****
>       This can be done for a few constant compares, where we can make the
>       immediate value easier to load.  */
>
> ! enum rtx_code
> ! arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
>    {
>      enum machine_mode mode;
>      unsigned HOST_WIDE_INT i, maxval;
> --- 3548,3556 ----
>       This can be done for a few constant compares, where we can make the
>       immediate value easier to load.  */
>
> ! static void
> ! arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
> !                            bool op0_preserve_value)
>    {
>      enum machine_mode mode;
>      unsigned HOST_WIDE_INT i, maxval;
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3563,3577 ****
>        {
>          rtx tem;
>
> !       if (code == GT || code == LE
> !         || (!TARGET_ARM && (code == GTU || code == LEU)))
>          {
>            /* Missing comparison.  First try to use an available
>               comparison.  */
>            if (CONST_INT_P (*op1))
>              {
>                i = INTVAL (*op1);
> !             switch (code)
>                  {
>                  case GT:
>                  case LE:
> --- 3569,3583 ----
>        {
>          rtx tem;
>
> !       if (*code == GT || *code == LE
> !         || (!TARGET_ARM && (*code == GTU || *code == LEU)))
>          {
>            /* Missing comparison.  First try to use an available
>               comparison.  */
>            if (CONST_INT_P (*op1))
>              {
>                i = INTVAL (*op1);
> !             switch (*code)
>                  {
>                  case GT:
>                  case LE:
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3579,3585 ****
>                        && arm_const_double_by_immediates (GEN_INT (i + 1)))
>                      {
>                        *op1 = GEN_INT (i + 1);
> !                     return code == GT ? GE : LT;
>                      }
>                    break;
>                  case GTU:
> --- 3585,3592 ----
>                        && arm_const_double_by_immediates (GEN_INT (i + 1)))
>                      {
>                        *op1 = GEN_INT (i + 1);
> !                     *code = *code == GT ? GE : LT;
> !                     return;
>                      }
>                    break;
>                  case GTU:
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3588,3594 ****
>                        && arm_const_double_by_immediates (GEN_INT (i + 1)))
>                      {
>                        *op1 = GEN_INT (i + 1);
> !                     return code == GTU ? GEU : LTU;
>                      }
>                    break;
>                  default:
> --- 3595,3602 ----
>                        && arm_const_double_by_immediates (GEN_INT (i + 1)))
>                      {
>                        *op1 = GEN_INT (i + 1);
> !                     *code = *code == GTU ? GEU : LTU;
> !                     return;
>                      }
>                    break;
>                  default:
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3597,3615 ****
>              }
>
>            /* If that did not work, reverse the condition.  */
> !         tem = *op0;
> !         *op0 = *op1;
> !         *op1 = tem;
> !         return swap_condition (code);
>          }
> !
> !       return code;
>        }
>
>      /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
>         with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
>         to facilitate possible combining with a cmp into 'ands'.  */
> !   if (mode == SImode
>          && GET_CODE (*op0) == ZERO_EXTEND
>          && GET_CODE (XEXP (*op0, 0)) == SUBREG
>          && GET_MODE (XEXP (*op0, 0)) == QImode
> --- 3605,3626 ----
>              }
>
>            /* If that did not work, reverse the condition.  */
> !         if (!op0_preserve_value)
> !           {
> !             tem = *op0;
> !             *op0 = *op1;
> !             *op1 = tem;
> !             *code = (int)swap_condition ((enum rtx_code)*code);
> !           }
>          }
> !       return;
>        }
>
>      /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
>         with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
>         to facilitate possible combining with a cmp into 'ands'.  */
> !   if (!op0_preserve_value
> !       && mode == SImode
>          && GET_CODE (*op0) == ZERO_EXTEND
>          && GET_CODE (XEXP (*op0, 0)) == SUBREG
>          && GET_MODE (XEXP (*op0, 0)) == QImode
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3624,3638 ****
>      if (!CONST_INT_P (*op1)
>          || const_ok_for_arm (INTVAL (*op1))
>          || const_ok_for_arm (- INTVAL (*op1)))
> !     return code;
>
>      i = INTVAL (*op1);
>
> !   switch (code)
>        {
>        case EQ:
>        case NE:
> !       return code;
>
>        case GT:
>        case LE:
> --- 3635,3649 ----
>      if (!CONST_INT_P (*op1)
>          || const_ok_for_arm (INTVAL (*op1))
>          || const_ok_for_arm (- INTVAL (*op1)))
> !     return;
>
>      i = INTVAL (*op1);
>
> !   switch (*code)
>        {
>        case EQ:
>        case NE:
> !       return;
>
>        case GT:
>        case LE:
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3640,3646 ****
>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>          {
>            *op1 = GEN_INT (i + 1);
> !         return code == GT ? GE : LT;
>          }
>          break;
>
> --- 3651,3658 ----
>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>          {
>            *op1 = GEN_INT (i + 1);
> !         *code = *code == GT ? GE : LT;
> !         return;
>          }
>          break;
>
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3650,3656 ****
>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>          {
>            *op1 = GEN_INT (i - 1);
> !         return code == GE ? GT : LE;
>          }
>          break;
>
> --- 3662,3669 ----
>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>          {
>            *op1 = GEN_INT (i - 1);
> !         *code = *code == GE ? GT : LE;
> !         return;
>          }
>          break;
>
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3660,3666 ****
>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>          {
>            *op1 = GEN_INT (i + 1);
> !         return code == GTU ? GEU : LTU;
>          }
>          break;
>
> --- 3673,3680 ----
>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>          {
>            *op1 = GEN_INT (i + 1);
> !         *code = *code == GTU ? GEU : LTU;
> !         return;
>          }
>          break;
>
> *************** arm_canonicalize_comparison (enum rtx_co
> *** 3670,3684 ****
>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>          {
>            *op1 = GEN_INT (i - 1);
> !         return code == GEU ? GTU : LEU;
>          }
>          break;
>
>        default:
>          gcc_unreachable ();
>        }
> -
> -   return code;
>    }
>
>
> --- 3684,3697 ----
>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>          {
>            *op1 = GEN_INT (i - 1);
> !         *code = *code == GEU ? GTU : LEU;
> !         return;
>          }
>          break;
>
>        default:
>          gcc_unreachable ();
>        }
>    }
>
>
> *************** bool
> *** 26979,26985 ****
>    arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
>    {
>      enum rtx_code code = GET_CODE (*comparison);
> !   enum rtx_code canonical_code;
>      enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
>        ? GET_MODE (*op2) : GET_MODE (*op1);
>
> --- 26992,26998 ----
>    arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
>    {
>      enum rtx_code code = GET_CODE (*comparison);
> !   int code_int;
>      enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
>        ? GET_MODE (*op2) : GET_MODE (*op1);
>
> *************** arm_validize_comparison (rtx *comparison
> *** 26988,26995 ****
>      if (code == UNEQ || code == LTGT)
>        return false;
>
> !   canonical_code = arm_canonicalize_comparison (code, op1, op2);
> !   PUT_CODE (*comparison, canonical_code);
>
>      switch (mode)
>        {
> --- 27001,27009 ----
>      if (code == UNEQ || code == LTGT)
>        return false;
>
> !   code_int = (int)code;
> !   arm_canonicalize_comparison (&code_int, op1, op2, 0);
> !   PUT_CODE (*comparison, (enum rtx_code)code_int);
>
>      switch (mode)
>        {
> Index: gcc/config/arm/arm.h
> ===================================================================
> *** gcc/config/arm/arm.h.orig
> --- gcc/config/arm/arm.h
> *************** extern int making_const_table;
> *** 2078,2086 ****
>       ? reverse_condition_maybe_unordered (code) \
>       : reverse_condition (code))
>
> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1)                               \
> -   (CODE) = arm_canonicalize_comparison (CODE, &(OP0), &(OP1))
> -
>    /* The arm5 clz instruction returns 32.  */
>    #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
>    #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
> --- 2078,2083 ----
> Index: gcc/config/s390/s390-protos.h
> ===================================================================
> *** gcc/config/s390/s390-protos.h.orig
> --- gcc/config/s390/s390-protos.h
> *************** extern int tls_symbolic_operand (rtx);
> *** 58,64 ****
>    extern bool s390_match_ccmode (rtx, enum machine_mode);
>    extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
>    extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
> - extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx *);
>    extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
>    extern void s390_emit_jump (rtx, rtx);
>    extern bool symbolic_reference_mentioned_p (rtx);
> --- 58,63 ----
> Index: gcc/config/s390/s390.c
> ===================================================================
> *** gcc/config/s390/s390.c.orig
> --- gcc/config/s390/s390.c
> *************** s390_select_ccmode (enum rtx_code code,
> *** 745,753 ****
>    /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
>       that we can implement more efficiently.  */
>
> ! void
> ! s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
>    {
>      /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
>      if ((*code == EQ || *code == NE)
>          && *op1 == const0_rtx
> --- 745,757 ----
>    /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
>       that we can implement more efficiently.  */
>
> ! static void
> ! s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
> !                             bool op0_preserve_value)
>    {
> +   if (op0_preserve_value)
> +     return;
> +
>      /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
>      if ((*code == EQ || *code == NE)
>          && *op1 == const0_rtx
> *************** s390_canonicalize_comparison (enum rtx_c
> *** 894,900 ****
>      if (MEM_P (*op0) && REG_P (*op1))
>        {
>          rtx tem = *op0; *op0 = *op1; *op1 = tem;
> !       *code = swap_condition (*code);
>        }
>    }
>
> --- 898,904 ----
>      if (MEM_P (*op0) && REG_P (*op1))
>        {
>          rtx tem = *op0; *op0 = *op1; *op1 = tem;
> !       *code = (int)swap_condition ((enum rtx_code)*code);
>        }
>    }
>
> *************** s390_loop_unroll_adjust (unsigned nunrol
> *** 11071,11076 ****
> --- 11075,11083 ----
>    #undef TARGET_UNWIND_WORD_MODE
>    #define TARGET_UNWIND_WORD_MODE s390_unwind_word_mode
>
> + #undef TARGET_CANONICALIZE_COMPARISON
> + #define TARGET_CANONICALIZE_COMPARISON s390_canonicalize_comparison
> +
>    struct gcc_target targetm = TARGET_INITIALIZER;
>
>    #include "gt-s390.h"
> Index: gcc/config/s390/s390.h
> ===================================================================
> *** gcc/config/s390/s390.h.orig
> --- gcc/config/s390/s390.h
> *************** do {                                                                    \
> *** 720,729 ****
>       return the mode to be used for the comparison.  */
>    #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
>
> - /* Canonicalize a comparison from one we don't have to one we do have.  */
> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
> -   s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
> -
>    /* Relative costs of operations.  */
>
>    /* A C expression for the cost of a branch instruction.  A value of 1
> --- 720,725 ----
> Index: gcc/config/sh/sh-protos.h
> ===================================================================
> *** gcc/config/sh/sh-protos.h.orig
> --- gcc/config/sh/sh-protos.h
> *************** extern bool sh_expand_t_scc (rtx *);
> *** 159,166 ****
>    extern rtx sh_gen_truncate (enum machine_mode, rtx, int);
>    extern bool sh_vector_mode_supported_p (enum machine_mode);
>    extern bool sh_cfun_trap_exit_p (void);
> - extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
> -                                       enum machine_mode mode = VOIDmode);
>    extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem);
>    extern int sh_eval_treg_value (rtx op);
>
> --- 159,164 ----
> Index: gcc/config/sh/sh.c
> ===================================================================
> *** gcc/config/sh/sh.c.orig
> --- gcc/config/sh/sh.c
> *************** static int max_mov_insn_displacement (en
> *** 314,319 ****
> --- 314,322 ----
>    static int mov_insn_alignment_mask (enum machine_mode, bool);
>    static HOST_WIDE_INT disp_addr_displacement (rtx);
>    static bool sequence_insn_p (rtx);
> + static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool);
> + static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
> +                                       enum machine_mode, bool);
>
>    static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
>
> *************** static const struct attribute_spec sh_at
> *** 586,591 ****
> --- 589,597 ----
>    #undef TARGET_LEGITIMATE_CONSTANT_P
>    #define TARGET_LEGITIMATE_CONSTANT_P  sh_legitimate_constant_p
>
> + #undef TARGET_CANONICALIZE_COMPARISON
> + #define TARGET_CANONICALIZE_COMPARISON        sh_canonicalize_comparison
> +
>    /* Machine-specific symbol_ref flags.  */
>    #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
>
> *************** prepare_move_operands (rtx operands[], e
> *** 1909,1920 ****
>        }
>    }
>
> ! /* Implement the CANONICALIZE_COMPARISON macro for the combine pass.
> !    This function is also re-used to canonicalize comparisons in cbranch
> !    pattern expanders.  */
> ! void
>    sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
> !                           enum machine_mode mode)
>    {
>      /* When invoked from within the combine pass the mode is not specified,
>         so try to get it from one of the operands.  */
> --- 1915,1928 ----
>        }
>    }
>
> ! /* Implement the canonicalize_comparison target hook for the combine
> !    pass.  For the target hook this function is invoked via
> !    sh_canonicalize_comparison.  This function is also re-used to
> !    canonicalize comparisons in cbranch pattern expanders.  */
> ! static void
>    sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
> !                           enum machine_mode mode,
> !                           bool op0_preserve_value ATTRIBUTE_UNUSED)
>    {
>      /* When invoked from within the combine pass the mode is not specified,
>         so try to get it from one of the operands.  */
> *************** sh_canonicalize_comparison (enum rtx_cod
> *** 2008,2013 ****
> --- 2016,2034 ----
>        }
>    }
>
> + /* This function implements the canonicalize_comparison target hook.
> +    This wrapper around the internally used sh_canonicalize_comparison
> +    function is needed to do the enum rtx_code <-> int conversion.
> +    Target hooks cannot use enum rtx_code in its definition.  */
> + static void
> + sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
> +                           bool op0_preserve_value)
> + {
> +   enum rtx_code tmp_code = (enum rtx_code)*code;
> +   sh_canonicalize_comparison (tmp_code, *op0, *op1,
> +                             VOIDmode, op0_preserve_value);
> +   *code = (int)tmp_code;
> + }
>    enum rtx_code
>    prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
>                            enum rtx_code comparison)
> *************** prepare_cbranch_operands (rtx *operands,
> *** 2021,2027 ****
>      else
>        scratch = operands[4];
>
> !   sh_canonicalize_comparison (comparison, operands[1], operands[2], mode);
>
>      /* Notice that this function is also invoked after reload by
>         the cbranchdi4_i pattern, through expand_cbranchdi4.  */
> --- 2042,2049 ----
>      else
>        scratch = operands[4];
>
> !   sh_canonicalize_comparison (comparison, operands[1], operands[2],
> !                             mode, false);
>
>      /* Notice that this function is also invoked after reload by
>         the cbranchdi4_i pattern, through expand_cbranchdi4.  */
> Index: gcc/config/sh/sh.h
> ===================================================================
> *** gcc/config/sh/sh.h.orig
> --- gcc/config/sh/sh.h
> *************** struct sh_args {
> *** 1873,1882 ****
>       more compact code.  */
>    #define SHIFT_COUNT_TRUNCATED (0)
>
> - /* CANONICALIZE_COMPARISON macro for the combine pass.  */
> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
> -   sh_canonicalize_comparison ((CODE), (OP0), (OP1))
> -
>    /* All integers have the same format so truncation is easy.  */
>    /* But SHmedia must sign-extend DImode when truncating to SImode.  */
>    #define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) \
> --- 1873,1878 ----
> Index: gcc/config/spu/spu.c
> ===================================================================
> *** gcc/config/spu/spu.c.orig
> --- gcc/config/spu/spu.c
> *************** spu_output_mi_thunk (FILE *file, tree th
> *** 7095,7100 ****
> --- 7095,7114 ----
>      final_end_function ();
>    }
>
> + /* Canonicalize a comparison from one we don't have to one we do have.  */
> + static void
> + spu_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
> +                            bool op0_preserve_value)
> + {
> +   if (!op0_preserve_value
> +       && (*code == LE || *code == LT || *code == LEU || *code == LTU))
> +     {
> +       rtx tem = *op0;
> +       *op0 = *op1;
> +       *op1 = tem;
> +       *code = (int)swap_condition ((enum rtx_code)*code);
> +     }
> + }
>
>    /*  Table of machine attributes.  */
>    static const struct attribute_spec spu_attribute_table[] =
> *************** static const struct attribute_spec spu_a
> *** 7308,7313 ****
> --- 7322,7330 ----
>    #undef TARGET_DELAY_VARTRACK
>    #define TARGET_DELAY_VARTRACK true
>
> + #undef TARGET_CANONICALIZE_COMPARISON
> + #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
> +
>    struct gcc_target targetm = TARGET_INITIALIZER;
>
>    #include "gt-spu.h"
> Index: gcc/config/spu/spu.h
> ===================================================================
> *** gcc/config/spu/spu.h.orig
> --- gcc/config/spu/spu.h
> *************** do {                                                                    \
> *** 520,537 ****
>
>    #define NO_IMPLICIT_EXTERN_C 1
>
> - /* Canonicalize a comparison from one we don't have to one we do have.  */
> - #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
> -   do {                                                                    \
> -     if (((CODE) == LE || (CODE) == LT || (CODE) == LEU || (CODE) == LTU)) \
> -       {                                                                   \
> -         rtx tem = (OP0);                                                  \
> -         (OP0) = (OP1);                                                    \
> -         (OP1) = tem;                                                      \
> -         (CODE) = swap_condition (CODE);                                   \
> -       }                                                                   \
> -   } while (0)
> -
>
>    /* Address spaces.  */
>    #define ADDR_SPACE_EA 1
> --- 520,525 ----
> Index: gcc/doc/tm.texi.in
> ===================================================================
> *** gcc/doc/tm.texi.in.orig
> --- gcc/doc/tm.texi.in
> *************** You should define this macro if and only
> *** 5928,5952 ****
>    in @file{@var{machine}-modes.def}.
>    @end defmac
>
> ! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
>    On some machines not all possible comparisons are defined, but you can
>    convert an invalid comparison into a valid one.  For example, the Alpha
>    does not have a @code{GT} comparison, but you can use an @code{LT}
>    comparison instead and swap the order of the operands.
>
> ! On such machines, define this macro to be a C statement to do any
> ! required conversions.  @var{code} is the initial comparison code
> ! and @var{op0} and @var{op1} are the left and right operands of the
> ! comparison, respectively.  You should modify @var{code}, @var{op0}, and
> ! @var{op1} as required.
>
>    GCC will not assume that the comparison resulting from this macro is
>    valid but will see if the resulting insn matches a pattern in the
>    @file{md} file.
>
> ! You need not define this macro if it would never change the comparison
> ! code or operands.
> ! @end defmac
>
>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>    A C expression whose value is one if it is always safe to reverse a
> --- 5928,5954 ----
>    in @file{@var{machine}-modes.def}.
>    @end defmac
>
> ! @hook TARGET_CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
>    On some machines not all possible comparisons are defined, but you can
>    convert an invalid comparison into a valid one.  For example, the Alpha
>    does not have a @code{GT} comparison, but you can use an @code{LT}
>    comparison instead and swap the order of the operands.
>
> ! On such machines, implement this hook to do any required conversions.
> ! @var{code} is the initial comparison code and @var{op0} and @var{op1}
> ! are the left and right operands of the comparison, respectively.  If
> ! @var{op0_preserve_value} is @code{true} the implementation is not
> ! allowed to change the value of @var{op0} since the value might be used
> ! in RTXs which aren't comparisons.  E.g. the implementation is not
> ! allowed to swap operands in that case.
>
>    GCC will not assume that the comparison resulting from this macro is
>    valid but will see if the resulting insn matches a pattern in the
>    @file{md} file.
>
> ! You need not to implement this hook if it would never change the
> ! comparison code or operands.
> ! @end deftypefn
>
>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>    A C expression whose value is one if it is always safe to reverse a
> Index: gcc/target.def
> ===================================================================
> *** gcc/target.def.orig
> --- gcc/target.def
> *************** DEFHOOK
> *** 2877,2882 ****
> --- 2877,2890 ----
>     enum unwind_info_type, (void),
>     default_debug_unwind_info)
>
> + /* The code parameter should be of type enum rtx_code but this is not
> +    defined at this time.  */
> + DEFHOOK
> + (canonicalize_comparison,
> +  "",
> +  void, (int *code, rtx *op0, rtx *op1, bool op0_preserve_value),
> +  default_canonicalize_comparison)
> +
>    DEFHOOKPOD
>    (atomic_test_and_set_trueval,
>     "This value should be set if the result written by\
> Index: gcc/targhooks.h
> ===================================================================
> *** gcc/targhooks.h.orig
> --- gcc/targhooks.h
> *************** extern unsigned char default_class_max_n
> *** 179,184 ****
> --- 179,186 ----
>
>    extern enum unwind_info_type default_debug_unwind_info (void);
>
> + extern bool default_canonicalize_comparison (int *, rtx *, rtx *, bool);
> +
>    extern int default_label_align_after_barrier_max_skip (rtx);
>    extern int default_loop_align_max_skip (rtx);
>    extern int default_label_align_max_skip (rtx);
> Index: gcc/doc/tm.texi
> ===================================================================
> *** gcc/doc/tm.texi.orig
> --- gcc/doc/tm.texi
> *************** You should define this macro if and only
> *** 6024,6048 ****
>    in @file{@var{machine}-modes.def}.
>    @end defmac
>
> ! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
>    On some machines not all possible comparisons are defined, but you can
>    convert an invalid comparison into a valid one.  For example, the Alpha
>    does not have a @code{GT} comparison, but you can use an @code{LT}
>    comparison instead and swap the order of the operands.
>
> ! On such machines, define this macro to be a C statement to do any
> ! required conversions.  @var{code} is the initial comparison code
> ! and @var{op0} and @var{op1} are the left and right operands of the
> ! comparison, respectively.  You should modify @var{code}, @var{op0}, and
> ! @var{op1} as required.
>
>    GCC will not assume that the comparison resulting from this macro is
>    valid but will see if the resulting insn matches a pattern in the
>    @file{md} file.
>
> ! You need not define this macro if it would never change the comparison
> ! code or operands.
> ! @end defmac
>
>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>    A C expression whose value is one if it is always safe to reverse a
> --- 6024,6050 ----
>    in @file{@var{machine}-modes.def}.
>    @end defmac
>
> ! @deftypefn {Target Hook} void TARGET_CANONICALIZE_COMPARISON (int *@var{code}, rtx *@var{op0}, rtx
> *@var{op1}, bool @var{op0_preserve_value}) (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
>    On some machines not all possible comparisons are defined, but you can
>    convert an invalid comparison into a valid one.  For example, the Alpha
>    does not have a @code{GT} comparison, but you can use an @code{LT}
>    comparison instead and swap the order of the operands.
>
> ! On such machines, implement this hook to do any required conversions.
> ! @var{code} is the initial comparison code and @var{op0} and @var{op1}
> ! are the left and right operands of the comparison, respectively.  If
> ! @var{op0_preserve_value} is @code{true} the implementation is not
> ! allowed to change the value of @var{op0} since the value might be used
> ! in RTXs which aren't comparisons.  E.g. the implementation is not
> ! allowed to swap operands in that case.
>
>    GCC will not assume that the comparison resulting from this macro is
>    valid but will see if the resulting insn matches a pattern in the
>    @file{md} file.
>
> ! You need not to implement this hook if it would never change the
> ! comparison code or operands.
> ! @end deftypefn
>
>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>    A C expression whose value is one if it is always safe to reverse a
>
>
>
>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PING] Bugfix: Additional parameter for canonicalize comparison
  2012-12-19 11:34   ` Richard Earnshaw
@ 2012-12-19 14:04     ` Richard Biener
  2012-12-19 14:05       ` Richard Biener
  2012-12-19 18:57       ` Jan-Benedict Glaw
  0 siblings, 2 replies; 6+ messages in thread
From: Richard Biener @ 2012-12-19 14:04 UTC (permalink / raw)
  To: Richard Earnshaw
  Cc: Andreas Krebbel, nickc, paul, Ramana Radhakrishnan, gcc-patches

On Wed, Dec 19, 2012 at 12:34 PM, Richard Earnshaw <rearnsha@arm.com> wrote:
> On 19/12/12 09:53, Andreas Krebbel wrote:
>>
>> Hi,
>>
>> are the ARM parts of the patch below ok for mainline?
>>
>
> Yes.
>
> Sorry for the delay.

I think this broke bootstrap on x86_64:

/space/rguenther/src/svn/trunk/gcc/config/i386/i386.c: At global scope:
/space/rguenther/src/svn/trunk/gcc/config/i386/i386.c:42503: error:
invalid conversion from 'bool (*)(int*, rtx_def**, rtx_def**, bool)'
to 'void (*)(int*, rtx_def**, rtx_def**, bool)'
make[3]: *** [i386.o] Error 1

or maybe even everywhere.  Yeah, bool vs. void return value in the default
implementation.

Please fix.

Richard.

> R.
>
>
>> I did a compile test with a cross.
>>
>> Bye,
>>
>> -Andreas-
>>
>>
>> -------- Original Message --------
>> Subject: [PATCH] Bugfix: Additional parameter for canonicalize comparison
>> Date: Wed, 12 Dec 2012 12:23:14 +0100
>> From: Andreas Krebbel <krebbel@linux.vnet.ibm.com>
>> To: rearnsha@arm.com
>> CC: gcc-patches@gcc.gnu.org
>>
>> Hi Richard,
>>
>> is the attached patch ok for ARM?
>>
>> Bye,
>>
>> -Andreas-
>>
>> 2012-12-12  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
>>
>>          * target.def: Define canonicalize_comparison hook.
>>          * targhooks.h (default_canonicalize_comparison): New prototype.
>>          * targhooks.c (default_canonicalize_comparison): New function.
>>          * doc/tm.texi: Add documentation for the new target hook.
>>          * doc/tm.texi.in: Likewise.
>>          * combine.c (try_combine): Adjust to use the target hook.
>>          * config/alpha/alpha.h (CANONICALIZE_COMPARISON): Remove macro
>>          definition.
>>          * config/alpha/alpha.c (alpha_canonicalize_comparison): New
>>          function.
>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>          * config/arm/arm-protos.h (arm_canonicalize_comparison): Remove
>>          prototype.
>>          * config/arm/arm.c (arm_canonicalize_comparison): Add new
>>          parameter.
>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>          * config/arm/arm.h (CANONICALIZE_COMPARISON): Remove macro
>>          definition.
>>          * config/s390/s390-protos.h (s390_canonicalize_comparison):
>> Remove
>>          prototype.
>>          * config/s390/s390.c (s390_canonicalize_comparison): Add new
>>          parameter.
>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>          * config/s390/s390.h (CANONICALIZE_COMPARISON): Remove macro
>>          definition.
>>          * config/sh/sh-protos.h (sh_canonicalize_comparison): Remove
>>          prototype.
>>          * config/sh/sh.c (sh_canonicalize_comparison): Add new prototype.
>> New
>>          function overloading the old one.
>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>          * config/sh/sh.h (CANONICALIZE_COMPARISON): Remove macro
>>          definition.
>>          * config/spu/spu.c (spu_canonicalize_comparison): New function.
>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>          * config/spu/spu.h (CANONICALIZE_COMPARISON): Remove macro
>>          definition.
>>
>> ---
>>   gcc/combine.c                 |   19 ++++++-!!!
>>   gcc/config/alpha/alpha.c      |   27 ++++++++++++++++
>>   gcc/config/alpha/alpha.h      |   20 ------------
>>   gcc/config/arm/arm-protos.h   |    1
>>   gcc/config/arm/arm.c          |   68
>> ++-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>   gcc/config/arm/arm.h          |    3 -
>>   gcc/config/s390/s390-protos.h |    1
>>   gcc/config/s390/s390.c        |   13 +++!!!!!
>>   gcc/config/s390/s390.h        |    4 --
>>   gcc/config/sh/sh-protos.h     |    2 -
>>   gcc/config/sh/sh.c            |   34 +++++++++++!!!!!!!!!!
>>   gcc/config/sh/sh.h            |    4 --
>>   gcc/config/spu/spu.c          |   17 ++++++++++
>>   gcc/config/spu/spu.h          |   12 -------
>>   gcc/doc/tm.texi               |   20 !!!!!!!!!!!!
>>   gcc/doc/tm.texi.in            |   20 !!!!!!!!!!!!
>>   gcc/target.def                |    8 ++++
>>   gcc/targhooks.h               |    2 +
>>   18 files changed, 94 insertions(+), 50 deletions(-), 131
>> modifications(!)
>>
>> Index: gcc/combine.c
>> ===================================================================
>> *** gcc/combine.c.orig
>> --- gcc/combine.c
>> *************** static rtx gen_lowpart_or_truncate (enum
>> *** 494,499 ****
>> --- 494,510 ----
>>    static const struct rtl_hooks combine_rtl_hooks =
>> RTL_HOOKS_INITIALIZER;
>>
>>
>> + /* Convenience wrapper for the canonicalize_comparison target hook.
>> +    Target hooks cannot use enum rtx_code.  */
>> + static inline void
>> + target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
>> +                               bool op0_preserve_value)
>> + {
>> +   int code_int = (int)*code;
>> +   targetm.canonicalize_comparison (&code_int, op0, op1,
>> op0_preserve_value);
>> +   *code = (enum rtx_code)code_int;
>> + }
>> +
>>    /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
>>       PATTERN can not be split.  Otherwise, it returns an insn sequence.
>>       This is a wrapper around split_insns which ensures that the
>> *************** try_combine (rtx i3, rtx i2, rtx i1, rtx
>> *** 2944,2952 ****
>>            compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
>>            compare_code = simplify_compare_const (compare_code,
>>                                                   op0, &op1);
>> ! #ifdef CANONICALIZE_COMPARISON
>> !         CANONICALIZE_COMPARISON (compare_code, op0, op1);
>> ! #endif
>>          }
>>
>>          /* Do the rest only if op1 is const0_rtx, which may be the
>> --- 2955,2961 ----
>>            compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
>>            compare_code = simplify_compare_const (compare_code,
>>                                                   op0, &op1);
>> !         target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
>>          }
>>
>>          /* Do the rest only if op1 is const0_rtx, which may be the
>> *************** simplify_comparison (enum rtx_code code,
>> *** 11959,11969 ****
>>              }
>>          }
>>
>> - #ifdef CANONICALIZE_COMPARISON
>>      /* If this machine only supports a subset of valid comparisons, see
>> if we
>>         can convert an unsupported one into a supported one.  */
>> !   CANONICALIZE_COMPARISON (code, op0, op1);
>> ! #endif
>>
>>      *pop0 = op0;
>>      *pop1 = op1;
>> --- 11968,11976 ----
>>              }
>>          }
>>
>>      /* If this machine only supports a subset of valid comparisons, see
>> if we
>>         can convert an unsupported one into a supported one.  */
>> !   target_canonicalize_comparison (&code, &op0, &op1, 0);
>>
>>      *pop0 = op0;
>>      *pop1 = op1;
>> Index: gcc/config/alpha/alpha.c
>> ===================================================================
>> *** gcc/config/alpha/alpha.c.orig
>> --- gcc/config/alpha/alpha.c
>> *************** alpha_conditional_register_usage (void)
>> *** 9683,9688 ****
>> --- 9683,9712 ----
>>        for (i = 32; i < 63; i++)
>>          fixed_regs[i] = call_used_regs[i] = 1;
>>    }
>> +
>> + /* Canonicalize a comparison from one we don't have to one we do have.
>> */
>> +
>> + static void
>> + alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>> +                              bool op0_preserve_value)
>> + {
>> +   if (!op0_preserve_value
>> +       && (*code == GE || *code == GT || *code == GEU || *code == GTU)
>> +       && (REG_P (*op1) || *op1 == const0_rtx))
>> +     {
>> +       rtx tem = *op0;
>> +       *op0 = *op1;
>> +       *op1 = tem;
>> +       *code = (int)swap_condition ((enum rtx_code)*code);
>> +     }
>> +
>> +   if ((*code == LT || *code == LTU)
>> +       && CONST_INT_P (*op1) && INTVAL (*op1) == 256)
>> +     {
>> +       *code = *code == LT ? LE : LEU;
>> +       *op1 = GEN_INT (255);
>> +     }
>> + }
>>
>>    /* Initialize the GCC target structure.  */
>>    #if TARGET_ABI_OPEN_VMS
>> *************** alpha_conditional_register_usage (void)
>> *** 9850,9855 ****
>> --- 9874,9882 ----
>>    #undef TARGET_CONDITIONAL_REGISTER_USAGE
>>    #define TARGET_CONDITIONAL_REGISTER_USAGE
>> alpha_conditional_register_usage
>>
>> + #undef TARGET_CANONICALIZE_COMPARISON
>> + #define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison
>> +
>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>
>>
>> Index: gcc/config/alpha/alpha.h
>> ===================================================================
>> *** gcc/config/alpha/alpha.h.orig
>> --- gcc/config/alpha/alpha.h
>> *************** do {
>> \
>> *** 922,947 ****
>>    #define FLOAT_STORE_FLAG_VALUE(MODE) \
>>      REAL_VALUE_ATOF ((TARGET_FLOAT_VAX ? "0.5" : "2.0"), (MODE))
>>
>> - /* Canonicalize a comparison from one we don't have to one we do have.
>> */
>> -
>> - #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
>> -   do {
>> \
>> -     if (((CODE) == GE || (CODE) == GT || (CODE) == GEU || (CODE) == GTU)
>> \
>> -       && (REG_P (OP1) || (OP1) == const0_rtx))                \
>> -       {
>> \
>> -       rtx tem = (OP0);                                                \
>> -       (OP0) = (OP1);                                                  \
>> -       (OP1) = tem;                                                    \
>> -       (CODE) = swap_condition (CODE);                                 \
>> -       }
>> \
>> -     if (((CODE) == LT || (CODE) == LTU)
>> \
>> -       && CONST_INT_P (OP1) && INTVAL (OP1) == 256)                    \
>> -       {
>> \
>> -       (CODE) = (CODE) == LT ? LE : LEU;                               \
>> -       (OP1) = GEN_INT (255);                                          \
>> -       }
>> \
>> -   } while (0)
>> -
>>    /* Specify the machine mode that pointers have.
>>       After generation of rtl, the compiler makes no further distinction
>>       between pointers and any other objects of this machine mode.  */
>> --- 922,927 ----
>> Index: gcc/config/arm/arm-protos.h
>> ===================================================================
>> *** gcc/config/arm/arm-protos.h.orig
>> --- gcc/config/arm/arm-protos.h
>> *************** extern int const_ok_for_op (HOST_WIDE_IN
>> *** 53,59 ****
>>    extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
>>    extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
>>                                 HOST_WIDE_INT, rtx, rtx, int);
>> - extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *, rtx *);
>>    extern int legitimate_pic_operand_p (rtx);
>>    extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
>>    extern rtx legitimize_tls_address (rtx, rtx);
>> --- 53,58 ----
>> Index: gcc/config/arm/arm.c
>> ===================================================================
>> *** gcc/config/arm/arm.c.orig
>> --- gcc/config/arm/arm.c
>> *************** static int arm_cortex_a5_branch_cost (bo
>> *** 269,275 ****
>>
>>    static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
>>                                               const unsigned char *sel);
>> !
>>
>>    /* Table of machine attributes.  */
>>    static const struct attribute_spec arm_attribute_table[] =
>> --- 269,276 ----
>>
>>    static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
>>                                               const unsigned char *sel);
>> ! static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>> !                                        bool op0_preserve_value);
>>
>>    /* Table of machine attributes.  */
>>    static const struct attribute_spec arm_attribute_table[] =
>> *************** static const struct attribute_spec arm_a
>> *** 626,631 ****
>> --- 627,636 ----
>>    #define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
>>      arm_vectorize_vec_perm_const_ok
>>
>> + #undef TARGET_CANONICALIZE_COMPARISON
>> + #define TARGET_CANONICALIZE_COMPARISON \
>> +   arm_canonicalize_comparison
>> +
>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>
>>    /* Obstack for minipool constant handling.  */
>> *************** arm_gen_constant (enum rtx_code code, en
>> *** 3543,3550 ****
>>       This can be done for a few constant compares, where we can make the
>>       immediate value easier to load.  */
>>
>> ! enum rtx_code
>> ! arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
>>    {
>>      enum machine_mode mode;
>>      unsigned HOST_WIDE_INT i, maxval;
>> --- 3548,3556 ----
>>       This can be done for a few constant compares, where we can make the
>>       immediate value easier to load.  */
>>
>> ! static void
>> ! arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>> !                            bool op0_preserve_value)
>>    {
>>      enum machine_mode mode;
>>      unsigned HOST_WIDE_INT i, maxval;
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3563,3577 ****
>>        {
>>          rtx tem;
>>
>> !       if (code == GT || code == LE
>> !         || (!TARGET_ARM && (code == GTU || code == LEU)))
>>          {
>>            /* Missing comparison.  First try to use an available
>>               comparison.  */
>>            if (CONST_INT_P (*op1))
>>              {
>>                i = INTVAL (*op1);
>> !             switch (code)
>>                  {
>>                  case GT:
>>                  case LE:
>> --- 3569,3583 ----
>>        {
>>          rtx tem;
>>
>> !       if (*code == GT || *code == LE
>> !         || (!TARGET_ARM && (*code == GTU || *code == LEU)))
>>          {
>>            /* Missing comparison.  First try to use an available
>>               comparison.  */
>>            if (CONST_INT_P (*op1))
>>              {
>>                i = INTVAL (*op1);
>> !             switch (*code)
>>                  {
>>                  case GT:
>>                  case LE:
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3579,3585 ****
>>                        && arm_const_double_by_immediates (GEN_INT (i +
>> 1)))
>>                      {
>>                        *op1 = GEN_INT (i + 1);
>> !                     return code == GT ? GE : LT;
>>                      }
>>                    break;
>>                  case GTU:
>> --- 3585,3592 ----
>>                        && arm_const_double_by_immediates (GEN_INT (i +
>> 1)))
>>                      {
>>                        *op1 = GEN_INT (i + 1);
>> !                     *code = *code == GT ? GE : LT;
>> !                     return;
>>                      }
>>                    break;
>>                  case GTU:
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3588,3594 ****
>>                        && arm_const_double_by_immediates (GEN_INT (i +
>> 1)))
>>                      {
>>                        *op1 = GEN_INT (i + 1);
>> !                     return code == GTU ? GEU : LTU;
>>                      }
>>                    break;
>>                  default:
>> --- 3595,3602 ----
>>                        && arm_const_double_by_immediates (GEN_INT (i +
>> 1)))
>>                      {
>>                        *op1 = GEN_INT (i + 1);
>> !                     *code = *code == GTU ? GEU : LTU;
>> !                     return;
>>                      }
>>                    break;
>>                  default:
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3597,3615 ****
>>              }
>>
>>            /* If that did not work, reverse the condition.  */
>> !         tem = *op0;
>> !         *op0 = *op1;
>> !         *op1 = tem;
>> !         return swap_condition (code);
>>          }
>> !
>> !       return code;
>>        }
>>
>>      /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
>>         with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
>>         to facilitate possible combining with a cmp into 'ands'.  */
>> !   if (mode == SImode
>>          && GET_CODE (*op0) == ZERO_EXTEND
>>          && GET_CODE (XEXP (*op0, 0)) == SUBREG
>>          && GET_MODE (XEXP (*op0, 0)) == QImode
>> --- 3605,3626 ----
>>              }
>>
>>            /* If that did not work, reverse the condition.  */
>> !         if (!op0_preserve_value)
>> !           {
>> !             tem = *op0;
>> !             *op0 = *op1;
>> !             *op1 = tem;
>> !             *code = (int)swap_condition ((enum rtx_code)*code);
>> !           }
>>          }
>> !       return;
>>        }
>>
>>      /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
>>         with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
>>         to facilitate possible combining with a cmp into 'ands'.  */
>> !   if (!op0_preserve_value
>> !       && mode == SImode
>>          && GET_CODE (*op0) == ZERO_EXTEND
>>          && GET_CODE (XEXP (*op0, 0)) == SUBREG
>>          && GET_MODE (XEXP (*op0, 0)) == QImode
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3624,3638 ****
>>      if (!CONST_INT_P (*op1)
>>          || const_ok_for_arm (INTVAL (*op1))
>>          || const_ok_for_arm (- INTVAL (*op1)))
>> !     return code;
>>
>>      i = INTVAL (*op1);
>>
>> !   switch (code)
>>        {
>>        case EQ:
>>        case NE:
>> !       return code;
>>
>>        case GT:
>>        case LE:
>> --- 3635,3649 ----
>>      if (!CONST_INT_P (*op1)
>>          || const_ok_for_arm (INTVAL (*op1))
>>          || const_ok_for_arm (- INTVAL (*op1)))
>> !     return;
>>
>>      i = INTVAL (*op1);
>>
>> !   switch (*code)
>>        {
>>        case EQ:
>>        case NE:
>> !       return;
>>
>>        case GT:
>>        case LE:
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3640,3646 ****
>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>          {
>>            *op1 = GEN_INT (i + 1);
>> !         return code == GT ? GE : LT;
>>          }
>>          break;
>>
>> --- 3651,3658 ----
>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>          {
>>            *op1 = GEN_INT (i + 1);
>> !         *code = *code == GT ? GE : LT;
>> !         return;
>>          }
>>          break;
>>
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3650,3656 ****
>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>          {
>>            *op1 = GEN_INT (i - 1);
>> !         return code == GE ? GT : LE;
>>          }
>>          break;
>>
>> --- 3662,3669 ----
>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>          {
>>            *op1 = GEN_INT (i - 1);
>> !         *code = *code == GE ? GT : LE;
>> !         return;
>>          }
>>          break;
>>
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3660,3666 ****
>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>          {
>>            *op1 = GEN_INT (i + 1);
>> !         return code == GTU ? GEU : LTU;
>>          }
>>          break;
>>
>> --- 3673,3680 ----
>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>          {
>>            *op1 = GEN_INT (i + 1);
>> !         *code = *code == GTU ? GEU : LTU;
>> !         return;
>>          }
>>          break;
>>
>> *************** arm_canonicalize_comparison (enum rtx_co
>> *** 3670,3684 ****
>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>          {
>>            *op1 = GEN_INT (i - 1);
>> !         return code == GEU ? GTU : LEU;
>>          }
>>          break;
>>
>>        default:
>>          gcc_unreachable ();
>>        }
>> -
>> -   return code;
>>    }
>>
>>
>> --- 3684,3697 ----
>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>          {
>>            *op1 = GEN_INT (i - 1);
>> !         *code = *code == GEU ? GTU : LEU;
>> !         return;
>>          }
>>          break;
>>
>>        default:
>>          gcc_unreachable ();
>>        }
>>    }
>>
>>
>> *************** bool
>> *** 26979,26985 ****
>>    arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
>>    {
>>      enum rtx_code code = GET_CODE (*comparison);
>> !   enum rtx_code canonical_code;
>>      enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
>>        ? GET_MODE (*op2) : GET_MODE (*op1);
>>
>> --- 26992,26998 ----
>>    arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
>>    {
>>      enum rtx_code code = GET_CODE (*comparison);
>> !   int code_int;
>>      enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
>>        ? GET_MODE (*op2) : GET_MODE (*op1);
>>
>> *************** arm_validize_comparison (rtx *comparison
>> *** 26988,26995 ****
>>      if (code == UNEQ || code == LTGT)
>>        return false;
>>
>> !   canonical_code = arm_canonicalize_comparison (code, op1, op2);
>> !   PUT_CODE (*comparison, canonical_code);
>>
>>      switch (mode)
>>        {
>> --- 27001,27009 ----
>>      if (code == UNEQ || code == LTGT)
>>        return false;
>>
>> !   code_int = (int)code;
>> !   arm_canonicalize_comparison (&code_int, op1, op2, 0);
>> !   PUT_CODE (*comparison, (enum rtx_code)code_int);
>>
>>      switch (mode)
>>        {
>> Index: gcc/config/arm/arm.h
>> ===================================================================
>> *** gcc/config/arm/arm.h.orig
>> --- gcc/config/arm/arm.h
>> *************** extern int making_const_table;
>> *** 2078,2086 ****
>>       ? reverse_condition_maybe_unordered (code) \
>>       : reverse_condition (code))
>>
>> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1)
>> \
>> -   (CODE) = arm_canonicalize_comparison (CODE, &(OP0), &(OP1))
>> -
>>    /* The arm5 clz instruction returns 32.  */
>>    #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
>>    #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
>> --- 2078,2083 ----
>> Index: gcc/config/s390/s390-protos.h
>> ===================================================================
>> *** gcc/config/s390/s390-protos.h.orig
>> --- gcc/config/s390/s390-protos.h
>> *************** extern int tls_symbolic_operand (rtx);
>> *** 58,64 ****
>>    extern bool s390_match_ccmode (rtx, enum machine_mode);
>>    extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
>>    extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
>> - extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx
>> *);
>>    extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
>>    extern void s390_emit_jump (rtx, rtx);
>>    extern bool symbolic_reference_mentioned_p (rtx);
>> --- 58,63 ----
>> Index: gcc/config/s390/s390.c
>> ===================================================================
>> *** gcc/config/s390/s390.c.orig
>> --- gcc/config/s390/s390.c
>> *************** s390_select_ccmode (enum rtx_code code,
>> *** 745,753 ****
>>    /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
>>       that we can implement more efficiently.  */
>>
>> ! void
>> ! s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
>>    {
>>      /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
>>      if ((*code == EQ || *code == NE)
>>          && *op1 == const0_rtx
>> --- 745,757 ----
>>    /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
>>       that we can implement more efficiently.  */
>>
>> ! static void
>> ! s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>> !                             bool op0_preserve_value)
>>    {
>> +   if (op0_preserve_value)
>> +     return;
>> +
>>      /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
>>      if ((*code == EQ || *code == NE)
>>          && *op1 == const0_rtx
>> *************** s390_canonicalize_comparison (enum rtx_c
>> *** 894,900 ****
>>      if (MEM_P (*op0) && REG_P (*op1))
>>        {
>>          rtx tem = *op0; *op0 = *op1; *op1 = tem;
>> !       *code = swap_condition (*code);
>>        }
>>    }
>>
>> --- 898,904 ----
>>      if (MEM_P (*op0) && REG_P (*op1))
>>        {
>>          rtx tem = *op0; *op0 = *op1; *op1 = tem;
>> !       *code = (int)swap_condition ((enum rtx_code)*code);
>>        }
>>    }
>>
>> *************** s390_loop_unroll_adjust (unsigned nunrol
>> *** 11071,11076 ****
>> --- 11075,11083 ----
>>    #undef TARGET_UNWIND_WORD_MODE
>>    #define TARGET_UNWIND_WORD_MODE s390_unwind_word_mode
>>
>> + #undef TARGET_CANONICALIZE_COMPARISON
>> + #define TARGET_CANONICALIZE_COMPARISON s390_canonicalize_comparison
>> +
>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>
>>    #include "gt-s390.h"
>> Index: gcc/config/s390/s390.h
>> ===================================================================
>> *** gcc/config/s390/s390.h.orig
>> --- gcc/config/s390/s390.h
>> *************** do {
>> \
>> *** 720,729 ****
>>       return the mode to be used for the comparison.  */
>>    #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
>>
>> - /* Canonicalize a comparison from one we don't have to one we do have.
>> */
>> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
>> -   s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
>> -
>>    /* Relative costs of operations.  */
>>
>>    /* A C expression for the cost of a branch instruction.  A value of 1
>> --- 720,725 ----
>> Index: gcc/config/sh/sh-protos.h
>> ===================================================================
>> *** gcc/config/sh/sh-protos.h.orig
>> --- gcc/config/sh/sh-protos.h
>> *************** extern bool sh_expand_t_scc (rtx *);
>> *** 159,166 ****
>>    extern rtx sh_gen_truncate (enum machine_mode, rtx, int);
>>    extern bool sh_vector_mode_supported_p (enum machine_mode);
>>    extern bool sh_cfun_trap_exit_p (void);
>> - extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
>> -                                       enum machine_mode mode =
>> VOIDmode);
>>    extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem);
>>    extern int sh_eval_treg_value (rtx op);
>>
>> --- 159,164 ----
>> Index: gcc/config/sh/sh.c
>> ===================================================================
>> *** gcc/config/sh/sh.c.orig
>> --- gcc/config/sh/sh.c
>> *************** static int max_mov_insn_displacement (en
>> *** 314,319 ****
>> --- 314,322 ----
>>    static int mov_insn_alignment_mask (enum machine_mode, bool);
>>    static HOST_WIDE_INT disp_addr_displacement (rtx);
>>    static bool sequence_insn_p (rtx);
>> + static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool);
>> + static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
>> +                                       enum machine_mode, bool);
>>
>>    static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
>>
>> *************** static const struct attribute_spec sh_at
>> *** 586,591 ****
>> --- 589,597 ----
>>    #undef TARGET_LEGITIMATE_CONSTANT_P
>>    #define TARGET_LEGITIMATE_CONSTANT_P  sh_legitimate_constant_p
>>
>> + #undef TARGET_CANONICALIZE_COMPARISON
>> + #define TARGET_CANONICALIZE_COMPARISON        sh_canonicalize_comparison
>> +
>>    /* Machine-specific symbol_ref flags.  */
>>    #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
>>
>> *************** prepare_move_operands (rtx operands[], e
>> *** 1909,1920 ****
>>        }
>>    }
>>
>> ! /* Implement the CANONICALIZE_COMPARISON macro for the combine pass.
>> !    This function is also re-used to canonicalize comparisons in cbranch
>> !    pattern expanders.  */
>> ! void
>>    sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
>> !                           enum machine_mode mode)
>>    {
>>      /* When invoked from within the combine pass the mode is not
>> specified,
>>         so try to get it from one of the operands.  */
>> --- 1915,1928 ----
>>        }
>>    }
>>
>> ! /* Implement the canonicalize_comparison target hook for the combine
>> !    pass.  For the target hook this function is invoked via
>> !    sh_canonicalize_comparison.  This function is also re-used to
>> !    canonicalize comparisons in cbranch pattern expanders.  */
>> ! static void
>>    sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
>> !                           enum machine_mode mode,
>> !                           bool op0_preserve_value ATTRIBUTE_UNUSED)
>>    {
>>      /* When invoked from within the combine pass the mode is not
>> specified,
>>         so try to get it from one of the operands.  */
>> *************** sh_canonicalize_comparison (enum rtx_cod
>> *** 2008,2013 ****
>> --- 2016,2034 ----
>>        }
>>    }
>>
>> + /* This function implements the canonicalize_comparison target hook.
>> +    This wrapper around the internally used sh_canonicalize_comparison
>> +    function is needed to do the enum rtx_code <-> int conversion.
>> +    Target hooks cannot use enum rtx_code in its definition.  */
>> + static void
>> + sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>> +                           bool op0_preserve_value)
>> + {
>> +   enum rtx_code tmp_code = (enum rtx_code)*code;
>> +   sh_canonicalize_comparison (tmp_code, *op0, *op1,
>> +                             VOIDmode, op0_preserve_value);
>> +   *code = (int)tmp_code;
>> + }
>>    enum rtx_code
>>    prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
>>                            enum rtx_code comparison)
>> *************** prepare_cbranch_operands (rtx *operands,
>> *** 2021,2027 ****
>>      else
>>        scratch = operands[4];
>>
>> !   sh_canonicalize_comparison (comparison, operands[1], operands[2],
>> mode);
>>
>>      /* Notice that this function is also invoked after reload by
>>         the cbranchdi4_i pattern, through expand_cbranchdi4.  */
>> --- 2042,2049 ----
>>      else
>>        scratch = operands[4];
>>
>> !   sh_canonicalize_comparison (comparison, operands[1], operands[2],
>> !                             mode, false);
>>
>>      /* Notice that this function is also invoked after reload by
>>         the cbranchdi4_i pattern, through expand_cbranchdi4.  */
>> Index: gcc/config/sh/sh.h
>> ===================================================================
>> *** gcc/config/sh/sh.h.orig
>> --- gcc/config/sh/sh.h
>> *************** struct sh_args {
>> *** 1873,1882 ****
>>       more compact code.  */
>>    #define SHIFT_COUNT_TRUNCATED (0)
>>
>> - /* CANONICALIZE_COMPARISON macro for the combine pass.  */
>> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
>> -   sh_canonicalize_comparison ((CODE), (OP0), (OP1))
>> -
>>    /* All integers have the same format so truncation is easy.  */
>>    /* But SHmedia must sign-extend DImode when truncating to SImode.  */
>>    #define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) \
>> --- 1873,1878 ----
>> Index: gcc/config/spu/spu.c
>> ===================================================================
>> *** gcc/config/spu/spu.c.orig
>> --- gcc/config/spu/spu.c
>> *************** spu_output_mi_thunk (FILE *file, tree th
>> *** 7095,7100 ****
>> --- 7095,7114 ----
>>      final_end_function ();
>>    }
>>
>> + /* Canonicalize a comparison from one we don't have to one we do have.
>> */
>> + static void
>> + spu_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>> +                            bool op0_preserve_value)
>> + {
>> +   if (!op0_preserve_value
>> +       && (*code == LE || *code == LT || *code == LEU || *code == LTU))
>> +     {
>> +       rtx tem = *op0;
>> +       *op0 = *op1;
>> +       *op1 = tem;
>> +       *code = (int)swap_condition ((enum rtx_code)*code);
>> +     }
>> + }
>>
>>    /*  Table of machine attributes.  */
>>    static const struct attribute_spec spu_attribute_table[] =
>> *************** static const struct attribute_spec spu_a
>> *** 7308,7313 ****
>> --- 7322,7330 ----
>>    #undef TARGET_DELAY_VARTRACK
>>    #define TARGET_DELAY_VARTRACK true
>>
>> + #undef TARGET_CANONICALIZE_COMPARISON
>> + #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
>> +
>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>
>>    #include "gt-spu.h"
>> Index: gcc/config/spu/spu.h
>> ===================================================================
>> *** gcc/config/spu/spu.h.orig
>> --- gcc/config/spu/spu.h
>> *************** do {
>> \
>> *** 520,537 ****
>>
>>    #define NO_IMPLICIT_EXTERN_C 1
>>
>> - /* Canonicalize a comparison from one we don't have to one we do have.
>> */
>> - #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
>> -   do {
>> \
>> -     if (((CODE) == LE || (CODE) == LT || (CODE) == LEU || (CODE) ==
>> LTU)) \
>> -       {
>> \
>> -         rtx tem = (OP0);
>> \
>> -         (OP0) = (OP1);
>> \
>> -         (OP1) = tem;
>> \
>> -         (CODE) = swap_condition (CODE);
>> \
>> -       }
>> \
>> -   } while (0)
>> -
>>
>>    /* Address spaces.  */
>>    #define ADDR_SPACE_EA 1
>> --- 520,525 ----
>> Index: gcc/doc/tm.texi.in
>> ===================================================================
>> *** gcc/doc/tm.texi.in.orig
>> --- gcc/doc/tm.texi.in
>> *************** You should define this macro if and only
>> *** 5928,5952 ****
>>    in @file{@var{machine}-modes.def}.
>>    @end defmac
>>
>> ! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
>>    On some machines not all possible comparisons are defined, but you can
>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>    comparison instead and swap the order of the operands.
>>
>> ! On such machines, define this macro to be a C statement to do any
>> ! required conversions.  @var{code} is the initial comparison code
>> ! and @var{op0} and @var{op1} are the left and right operands of the
>> ! comparison, respectively.  You should modify @var{code}, @var{op0}, and
>> ! @var{op1} as required.
>>
>>    GCC will not assume that the comparison resulting from this macro is
>>    valid but will see if the resulting insn matches a pattern in the
>>    @file{md} file.
>>
>> ! You need not define this macro if it would never change the comparison
>> ! code or operands.
>> ! @end defmac
>>
>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>    A C expression whose value is one if it is always safe to reverse a
>> --- 5928,5954 ----
>>    in @file{@var{machine}-modes.def}.
>>    @end defmac
>>
>> ! @hook TARGET_CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1},
>> @var{op0_preserve_value})
>>    On some machines not all possible comparisons are defined, but you can
>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>    comparison instead and swap the order of the operands.
>>
>> ! On such machines, implement this hook to do any required conversions.
>> ! @var{code} is the initial comparison code and @var{op0} and @var{op1}
>> ! are the left and right operands of the comparison, respectively.  If
>> ! @var{op0_preserve_value} is @code{true} the implementation is not
>> ! allowed to change the value of @var{op0} since the value might be used
>> ! in RTXs which aren't comparisons.  E.g. the implementation is not
>> ! allowed to swap operands in that case.
>>
>>    GCC will not assume that the comparison resulting from this macro is
>>    valid but will see if the resulting insn matches a pattern in the
>>    @file{md} file.
>>
>> ! You need not to implement this hook if it would never change the
>> ! comparison code or operands.
>> ! @end deftypefn
>>
>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>    A C expression whose value is one if it is always safe to reverse a
>> Index: gcc/target.def
>> ===================================================================
>> *** gcc/target.def.orig
>> --- gcc/target.def
>> *************** DEFHOOK
>> *** 2877,2882 ****
>> --- 2877,2890 ----
>>     enum unwind_info_type, (void),
>>     default_debug_unwind_info)
>>
>> + /* The code parameter should be of type enum rtx_code but this is not
>> +    defined at this time.  */
>> + DEFHOOK
>> + (canonicalize_comparison,
>> +  "",
>> +  void, (int *code, rtx *op0, rtx *op1, bool op0_preserve_value),
>> +  default_canonicalize_comparison)
>> +
>>    DEFHOOKPOD
>>    (atomic_test_and_set_trueval,
>>     "This value should be set if the result written by\
>> Index: gcc/targhooks.h
>> ===================================================================
>> *** gcc/targhooks.h.orig
>> --- gcc/targhooks.h
>> *************** extern unsigned char default_class_max_n
>> *** 179,184 ****
>> --- 179,186 ----
>>
>>    extern enum unwind_info_type default_debug_unwind_info (void);
>>
>> + extern bool default_canonicalize_comparison (int *, rtx *, rtx *, bool);
>> +
>>    extern int default_label_align_after_barrier_max_skip (rtx);
>>    extern int default_loop_align_max_skip (rtx);
>>    extern int default_label_align_max_skip (rtx);
>> Index: gcc/doc/tm.texi
>> ===================================================================
>> *** gcc/doc/tm.texi.orig
>> --- gcc/doc/tm.texi
>> *************** You should define this macro if and only
>> *** 6024,6048 ****
>>    in @file{@var{machine}-modes.def}.
>>    @end defmac
>>
>> ! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
>>    On some machines not all possible comparisons are defined, but you can
>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>    comparison instead and swap the order of the operands.
>>
>> ! On such machines, define this macro to be a C statement to do any
>> ! required conversions.  @var{code} is the initial comparison code
>> ! and @var{op0} and @var{op1} are the left and right operands of the
>> ! comparison, respectively.  You should modify @var{code}, @var{op0}, and
>> ! @var{op1} as required.
>>
>>    GCC will not assume that the comparison resulting from this macro is
>>    valid but will see if the resulting insn matches a pattern in the
>>    @file{md} file.
>>
>> ! You need not define this macro if it would never change the comparison
>> ! code or operands.
>> ! @end defmac
>>
>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>    A C expression whose value is one if it is always safe to reverse a
>> --- 6024,6050 ----
>>    in @file{@var{machine}-modes.def}.
>>    @end defmac
>>
>> ! @deftypefn {Target Hook} void TARGET_CANONICALIZE_COMPARISON (int
>> *@var{code}, rtx *@var{op0}, rtx
>> *@var{op1}, bool @var{op0_preserve_value}) (@var{code}, @var{op0},
>> @var{op1}, @var{op0_preserve_value})
>>    On some machines not all possible comparisons are defined, but you can
>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>    comparison instead and swap the order of the operands.
>>
>> ! On such machines, implement this hook to do any required conversions.
>> ! @var{code} is the initial comparison code and @var{op0} and @var{op1}
>> ! are the left and right operands of the comparison, respectively.  If
>> ! @var{op0_preserve_value} is @code{true} the implementation is not
>> ! allowed to change the value of @var{op0} since the value might be used
>> ! in RTXs which aren't comparisons.  E.g. the implementation is not
>> ! allowed to swap operands in that case.
>>
>>    GCC will not assume that the comparison resulting from this macro is
>>    valid but will see if the resulting insn matches a pattern in the
>>    @file{md} file.
>>
>> ! You need not to implement this hook if it would never change the
>> ! comparison code or operands.
>> ! @end deftypefn
>>
>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>    A C expression whose value is one if it is always safe to reverse a
>>
>>
>>
>>
>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PING] Bugfix: Additional parameter for canonicalize comparison
  2012-12-19 14:04     ` Richard Biener
@ 2012-12-19 14:05       ` Richard Biener
  2012-12-19 18:57       ` Jan-Benedict Glaw
  1 sibling, 0 replies; 6+ messages in thread
From: Richard Biener @ 2012-12-19 14:05 UTC (permalink / raw)
  To: Richard Earnshaw
  Cc: Andreas Krebbel, nickc, paul, Ramana Radhakrishnan, gcc-patches

On Wed, Dec 19, 2012 at 3:04 PM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Wed, Dec 19, 2012 at 12:34 PM, Richard Earnshaw <rearnsha@arm.com> wrote:
>> On 19/12/12 09:53, Andreas Krebbel wrote:
>>>
>>> Hi,
>>>
>>> are the ARM parts of the patch below ok for mainline?
>>>
>>
>> Yes.
>>
>> Sorry for the delay.
>
> I think this broke bootstrap on x86_64:
>
> /space/rguenther/src/svn/trunk/gcc/config/i386/i386.c: At global scope:
> /space/rguenther/src/svn/trunk/gcc/config/i386/i386.c:42503: error:
> invalid conversion from 'bool (*)(int*, rtx_def**, rtx_def**, bool)'
> to 'void (*)(int*, rtx_def**, rtx_def**, bool)'
> make[3]: *** [i386.o] Error 1
>
> or maybe even everywhere.  Yeah, bool vs. void return value in the default
> implementation.
>
> Please fix.

I also can't find a definition of default_canonicalize_comparison - did you
forget to commit a part of the patch?

Thanks,
Richard.

> Richard.
>
>> R.
>>
>>
>>> I did a compile test with a cross.
>>>
>>> Bye,
>>>
>>> -Andreas-
>>>
>>>
>>> -------- Original Message --------
>>> Subject: [PATCH] Bugfix: Additional parameter for canonicalize comparison
>>> Date: Wed, 12 Dec 2012 12:23:14 +0100
>>> From: Andreas Krebbel <krebbel@linux.vnet.ibm.com>
>>> To: rearnsha@arm.com
>>> CC: gcc-patches@gcc.gnu.org
>>>
>>> Hi Richard,
>>>
>>> is the attached patch ok for ARM?
>>>
>>> Bye,
>>>
>>> -Andreas-
>>>
>>> 2012-12-12  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
>>>
>>>          * target.def: Define canonicalize_comparison hook.
>>>          * targhooks.h (default_canonicalize_comparison): New prototype.
>>>          * targhooks.c (default_canonicalize_comparison): New function.
>>>          * doc/tm.texi: Add documentation for the new target hook.
>>>          * doc/tm.texi.in: Likewise.
>>>          * combine.c (try_combine): Adjust to use the target hook.
>>>          * config/alpha/alpha.h (CANONICALIZE_COMPARISON): Remove macro
>>>          definition.
>>>          * config/alpha/alpha.c (alpha_canonicalize_comparison): New
>>>          function.
>>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>>          * config/arm/arm-protos.h (arm_canonicalize_comparison): Remove
>>>          prototype.
>>>          * config/arm/arm.c (arm_canonicalize_comparison): Add new
>>>          parameter.
>>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>>          * config/arm/arm.h (CANONICALIZE_COMPARISON): Remove macro
>>>          definition.
>>>          * config/s390/s390-protos.h (s390_canonicalize_comparison):
>>> Remove
>>>          prototype.
>>>          * config/s390/s390.c (s390_canonicalize_comparison): Add new
>>>          parameter.
>>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>>          * config/s390/s390.h (CANONICALIZE_COMPARISON): Remove macro
>>>          definition.
>>>          * config/sh/sh-protos.h (sh_canonicalize_comparison): Remove
>>>          prototype.
>>>          * config/sh/sh.c (sh_canonicalize_comparison): Add new prototype.
>>> New
>>>          function overloading the old one.
>>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>>          * config/sh/sh.h (CANONICALIZE_COMPARISON): Remove macro
>>>          definition.
>>>          * config/spu/spu.c (spu_canonicalize_comparison): New function.
>>>          (TARGET_CANONICALIZE_COMPARISON): New macro definition.
>>>          * config/spu/spu.h (CANONICALIZE_COMPARISON): Remove macro
>>>          definition.
>>>
>>> ---
>>>   gcc/combine.c                 |   19 ++++++-!!!
>>>   gcc/config/alpha/alpha.c      |   27 ++++++++++++++++
>>>   gcc/config/alpha/alpha.h      |   20 ------------
>>>   gcc/config/arm/arm-protos.h   |    1
>>>   gcc/config/arm/arm.c          |   68
>>> ++-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>   gcc/config/arm/arm.h          |    3 -
>>>   gcc/config/s390/s390-protos.h |    1
>>>   gcc/config/s390/s390.c        |   13 +++!!!!!
>>>   gcc/config/s390/s390.h        |    4 --
>>>   gcc/config/sh/sh-protos.h     |    2 -
>>>   gcc/config/sh/sh.c            |   34 +++++++++++!!!!!!!!!!
>>>   gcc/config/sh/sh.h            |    4 --
>>>   gcc/config/spu/spu.c          |   17 ++++++++++
>>>   gcc/config/spu/spu.h          |   12 -------
>>>   gcc/doc/tm.texi               |   20 !!!!!!!!!!!!
>>>   gcc/doc/tm.texi.in            |   20 !!!!!!!!!!!!
>>>   gcc/target.def                |    8 ++++
>>>   gcc/targhooks.h               |    2 +
>>>   18 files changed, 94 insertions(+), 50 deletions(-), 131
>>> modifications(!)
>>>
>>> Index: gcc/combine.c
>>> ===================================================================
>>> *** gcc/combine.c.orig
>>> --- gcc/combine.c
>>> *************** static rtx gen_lowpart_or_truncate (enum
>>> *** 494,499 ****
>>> --- 494,510 ----
>>>    static const struct rtl_hooks combine_rtl_hooks =
>>> RTL_HOOKS_INITIALIZER;
>>>
>>>
>>> + /* Convenience wrapper for the canonicalize_comparison target hook.
>>> +    Target hooks cannot use enum rtx_code.  */
>>> + static inline void
>>> + target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
>>> +                               bool op0_preserve_value)
>>> + {
>>> +   int code_int = (int)*code;
>>> +   targetm.canonicalize_comparison (&code_int, op0, op1,
>>> op0_preserve_value);
>>> +   *code = (enum rtx_code)code_int;
>>> + }
>>> +
>>>    /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
>>>       PATTERN can not be split.  Otherwise, it returns an insn sequence.
>>>       This is a wrapper around split_insns which ensures that the
>>> *************** try_combine (rtx i3, rtx i2, rtx i1, rtx
>>> *** 2944,2952 ****
>>>            compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
>>>            compare_code = simplify_compare_const (compare_code,
>>>                                                   op0, &op1);
>>> ! #ifdef CANONICALIZE_COMPARISON
>>> !         CANONICALIZE_COMPARISON (compare_code, op0, op1);
>>> ! #endif
>>>          }
>>>
>>>          /* Do the rest only if op1 is const0_rtx, which may be the
>>> --- 2955,2961 ----
>>>            compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
>>>            compare_code = simplify_compare_const (compare_code,
>>>                                                   op0, &op1);
>>> !         target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
>>>          }
>>>
>>>          /* Do the rest only if op1 is const0_rtx, which may be the
>>> *************** simplify_comparison (enum rtx_code code,
>>> *** 11959,11969 ****
>>>              }
>>>          }
>>>
>>> - #ifdef CANONICALIZE_COMPARISON
>>>      /* If this machine only supports a subset of valid comparisons, see
>>> if we
>>>         can convert an unsupported one into a supported one.  */
>>> !   CANONICALIZE_COMPARISON (code, op0, op1);
>>> ! #endif
>>>
>>>      *pop0 = op0;
>>>      *pop1 = op1;
>>> --- 11968,11976 ----
>>>              }
>>>          }
>>>
>>>      /* If this machine only supports a subset of valid comparisons, see
>>> if we
>>>         can convert an unsupported one into a supported one.  */
>>> !   target_canonicalize_comparison (&code, &op0, &op1, 0);
>>>
>>>      *pop0 = op0;
>>>      *pop1 = op1;
>>> Index: gcc/config/alpha/alpha.c
>>> ===================================================================
>>> *** gcc/config/alpha/alpha.c.orig
>>> --- gcc/config/alpha/alpha.c
>>> *************** alpha_conditional_register_usage (void)
>>> *** 9683,9688 ****
>>> --- 9683,9712 ----
>>>        for (i = 32; i < 63; i++)
>>>          fixed_regs[i] = call_used_regs[i] = 1;
>>>    }
>>> +
>>> + /* Canonicalize a comparison from one we don't have to one we do have.
>>> */
>>> +
>>> + static void
>>> + alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>>> +                              bool op0_preserve_value)
>>> + {
>>> +   if (!op0_preserve_value
>>> +       && (*code == GE || *code == GT || *code == GEU || *code == GTU)
>>> +       && (REG_P (*op1) || *op1 == const0_rtx))
>>> +     {
>>> +       rtx tem = *op0;
>>> +       *op0 = *op1;
>>> +       *op1 = tem;
>>> +       *code = (int)swap_condition ((enum rtx_code)*code);
>>> +     }
>>> +
>>> +   if ((*code == LT || *code == LTU)
>>> +       && CONST_INT_P (*op1) && INTVAL (*op1) == 256)
>>> +     {
>>> +       *code = *code == LT ? LE : LEU;
>>> +       *op1 = GEN_INT (255);
>>> +     }
>>> + }
>>>
>>>    /* Initialize the GCC target structure.  */
>>>    #if TARGET_ABI_OPEN_VMS
>>> *************** alpha_conditional_register_usage (void)
>>> *** 9850,9855 ****
>>> --- 9874,9882 ----
>>>    #undef TARGET_CONDITIONAL_REGISTER_USAGE
>>>    #define TARGET_CONDITIONAL_REGISTER_USAGE
>>> alpha_conditional_register_usage
>>>
>>> + #undef TARGET_CANONICALIZE_COMPARISON
>>> + #define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison
>>> +
>>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>>
>>>
>>> Index: gcc/config/alpha/alpha.h
>>> ===================================================================
>>> *** gcc/config/alpha/alpha.h.orig
>>> --- gcc/config/alpha/alpha.h
>>> *************** do {
>>> \
>>> *** 922,947 ****
>>>    #define FLOAT_STORE_FLAG_VALUE(MODE) \
>>>      REAL_VALUE_ATOF ((TARGET_FLOAT_VAX ? "0.5" : "2.0"), (MODE))
>>>
>>> - /* Canonicalize a comparison from one we don't have to one we do have.
>>> */
>>> -
>>> - #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
>>> -   do {
>>> \
>>> -     if (((CODE) == GE || (CODE) == GT || (CODE) == GEU || (CODE) == GTU)
>>> \
>>> -       && (REG_P (OP1) || (OP1) == const0_rtx))                \
>>> -       {
>>> \
>>> -       rtx tem = (OP0);                                                \
>>> -       (OP0) = (OP1);                                                  \
>>> -       (OP1) = tem;                                                    \
>>> -       (CODE) = swap_condition (CODE);                                 \
>>> -       }
>>> \
>>> -     if (((CODE) == LT || (CODE) == LTU)
>>> \
>>> -       && CONST_INT_P (OP1) && INTVAL (OP1) == 256)                    \
>>> -       {
>>> \
>>> -       (CODE) = (CODE) == LT ? LE : LEU;                               \
>>> -       (OP1) = GEN_INT (255);                                          \
>>> -       }
>>> \
>>> -   } while (0)
>>> -
>>>    /* Specify the machine mode that pointers have.
>>>       After generation of rtl, the compiler makes no further distinction
>>>       between pointers and any other objects of this machine mode.  */
>>> --- 922,927 ----
>>> Index: gcc/config/arm/arm-protos.h
>>> ===================================================================
>>> *** gcc/config/arm/arm-protos.h.orig
>>> --- gcc/config/arm/arm-protos.h
>>> *************** extern int const_ok_for_op (HOST_WIDE_IN
>>> *** 53,59 ****
>>>    extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
>>>    extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
>>>                                 HOST_WIDE_INT, rtx, rtx, int);
>>> - extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *, rtx *);
>>>    extern int legitimate_pic_operand_p (rtx);
>>>    extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
>>>    extern rtx legitimize_tls_address (rtx, rtx);
>>> --- 53,58 ----
>>> Index: gcc/config/arm/arm.c
>>> ===================================================================
>>> *** gcc/config/arm/arm.c.orig
>>> --- gcc/config/arm/arm.c
>>> *************** static int arm_cortex_a5_branch_cost (bo
>>> *** 269,275 ****
>>>
>>>    static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
>>>                                               const unsigned char *sel);
>>> !
>>>
>>>    /* Table of machine attributes.  */
>>>    static const struct attribute_spec arm_attribute_table[] =
>>> --- 269,276 ----
>>>
>>>    static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
>>>                                               const unsigned char *sel);
>>> ! static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>>> !                                        bool op0_preserve_value);
>>>
>>>    /* Table of machine attributes.  */
>>>    static const struct attribute_spec arm_attribute_table[] =
>>> *************** static const struct attribute_spec arm_a
>>> *** 626,631 ****
>>> --- 627,636 ----
>>>    #define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
>>>      arm_vectorize_vec_perm_const_ok
>>>
>>> + #undef TARGET_CANONICALIZE_COMPARISON
>>> + #define TARGET_CANONICALIZE_COMPARISON \
>>> +   arm_canonicalize_comparison
>>> +
>>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>>
>>>    /* Obstack for minipool constant handling.  */
>>> *************** arm_gen_constant (enum rtx_code code, en
>>> *** 3543,3550 ****
>>>       This can be done for a few constant compares, where we can make the
>>>       immediate value easier to load.  */
>>>
>>> ! enum rtx_code
>>> ! arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
>>>    {
>>>      enum machine_mode mode;
>>>      unsigned HOST_WIDE_INT i, maxval;
>>> --- 3548,3556 ----
>>>       This can be done for a few constant compares, where we can make the
>>>       immediate value easier to load.  */
>>>
>>> ! static void
>>> ! arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>>> !                            bool op0_preserve_value)
>>>    {
>>>      enum machine_mode mode;
>>>      unsigned HOST_WIDE_INT i, maxval;
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3563,3577 ****
>>>        {
>>>          rtx tem;
>>>
>>> !       if (code == GT || code == LE
>>> !         || (!TARGET_ARM && (code == GTU || code == LEU)))
>>>          {
>>>            /* Missing comparison.  First try to use an available
>>>               comparison.  */
>>>            if (CONST_INT_P (*op1))
>>>              {
>>>                i = INTVAL (*op1);
>>> !             switch (code)
>>>                  {
>>>                  case GT:
>>>                  case LE:
>>> --- 3569,3583 ----
>>>        {
>>>          rtx tem;
>>>
>>> !       if (*code == GT || *code == LE
>>> !         || (!TARGET_ARM && (*code == GTU || *code == LEU)))
>>>          {
>>>            /* Missing comparison.  First try to use an available
>>>               comparison.  */
>>>            if (CONST_INT_P (*op1))
>>>              {
>>>                i = INTVAL (*op1);
>>> !             switch (*code)
>>>                  {
>>>                  case GT:
>>>                  case LE:
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3579,3585 ****
>>>                        && arm_const_double_by_immediates (GEN_INT (i +
>>> 1)))
>>>                      {
>>>                        *op1 = GEN_INT (i + 1);
>>> !                     return code == GT ? GE : LT;
>>>                      }
>>>                    break;
>>>                  case GTU:
>>> --- 3585,3592 ----
>>>                        && arm_const_double_by_immediates (GEN_INT (i +
>>> 1)))
>>>                      {
>>>                        *op1 = GEN_INT (i + 1);
>>> !                     *code = *code == GT ? GE : LT;
>>> !                     return;
>>>                      }
>>>                    break;
>>>                  case GTU:
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3588,3594 ****
>>>                        && arm_const_double_by_immediates (GEN_INT (i +
>>> 1)))
>>>                      {
>>>                        *op1 = GEN_INT (i + 1);
>>> !                     return code == GTU ? GEU : LTU;
>>>                      }
>>>                    break;
>>>                  default:
>>> --- 3595,3602 ----
>>>                        && arm_const_double_by_immediates (GEN_INT (i +
>>> 1)))
>>>                      {
>>>                        *op1 = GEN_INT (i + 1);
>>> !                     *code = *code == GTU ? GEU : LTU;
>>> !                     return;
>>>                      }
>>>                    break;
>>>                  default:
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3597,3615 ****
>>>              }
>>>
>>>            /* If that did not work, reverse the condition.  */
>>> !         tem = *op0;
>>> !         *op0 = *op1;
>>> !         *op1 = tem;
>>> !         return swap_condition (code);
>>>          }
>>> !
>>> !       return code;
>>>        }
>>>
>>>      /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
>>>         with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
>>>         to facilitate possible combining with a cmp into 'ands'.  */
>>> !   if (mode == SImode
>>>          && GET_CODE (*op0) == ZERO_EXTEND
>>>          && GET_CODE (XEXP (*op0, 0)) == SUBREG
>>>          && GET_MODE (XEXP (*op0, 0)) == QImode
>>> --- 3605,3626 ----
>>>              }
>>>
>>>            /* If that did not work, reverse the condition.  */
>>> !         if (!op0_preserve_value)
>>> !           {
>>> !             tem = *op0;
>>> !             *op0 = *op1;
>>> !             *op1 = tem;
>>> !             *code = (int)swap_condition ((enum rtx_code)*code);
>>> !           }
>>>          }
>>> !       return;
>>>        }
>>>
>>>      /* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
>>>         with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
>>>         to facilitate possible combining with a cmp into 'ands'.  */
>>> !   if (!op0_preserve_value
>>> !       && mode == SImode
>>>          && GET_CODE (*op0) == ZERO_EXTEND
>>>          && GET_CODE (XEXP (*op0, 0)) == SUBREG
>>>          && GET_MODE (XEXP (*op0, 0)) == QImode
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3624,3638 ****
>>>      if (!CONST_INT_P (*op1)
>>>          || const_ok_for_arm (INTVAL (*op1))
>>>          || const_ok_for_arm (- INTVAL (*op1)))
>>> !     return code;
>>>
>>>      i = INTVAL (*op1);
>>>
>>> !   switch (code)
>>>        {
>>>        case EQ:
>>>        case NE:
>>> !       return code;
>>>
>>>        case GT:
>>>        case LE:
>>> --- 3635,3649 ----
>>>      if (!CONST_INT_P (*op1)
>>>          || const_ok_for_arm (INTVAL (*op1))
>>>          || const_ok_for_arm (- INTVAL (*op1)))
>>> !     return;
>>>
>>>      i = INTVAL (*op1);
>>>
>>> !   switch (*code)
>>>        {
>>>        case EQ:
>>>        case NE:
>>> !       return;
>>>
>>>        case GT:
>>>        case LE:
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3640,3646 ****
>>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>>          {
>>>            *op1 = GEN_INT (i + 1);
>>> !         return code == GT ? GE : LT;
>>>          }
>>>          break;
>>>
>>> --- 3651,3658 ----
>>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>>          {
>>>            *op1 = GEN_INT (i + 1);
>>> !         *code = *code == GT ? GE : LT;
>>> !         return;
>>>          }
>>>          break;
>>>
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3650,3656 ****
>>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>>          {
>>>            *op1 = GEN_INT (i - 1);
>>> !         return code == GE ? GT : LE;
>>>          }
>>>          break;
>>>
>>> --- 3662,3669 ----
>>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>>          {
>>>            *op1 = GEN_INT (i - 1);
>>> !         *code = *code == GE ? GT : LE;
>>> !         return;
>>>          }
>>>          break;
>>>
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3660,3666 ****
>>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>>          {
>>>            *op1 = GEN_INT (i + 1);
>>> !         return code == GTU ? GEU : LTU;
>>>          }
>>>          break;
>>>
>>> --- 3673,3680 ----
>>>            && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
>>>          {
>>>            *op1 = GEN_INT (i + 1);
>>> !         *code = *code == GTU ? GEU : LTU;
>>> !         return;
>>>          }
>>>          break;
>>>
>>> *************** arm_canonicalize_comparison (enum rtx_co
>>> *** 3670,3684 ****
>>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>>          {
>>>            *op1 = GEN_INT (i - 1);
>>> !         return code == GEU ? GTU : LEU;
>>>          }
>>>          break;
>>>
>>>        default:
>>>          gcc_unreachable ();
>>>        }
>>> -
>>> -   return code;
>>>    }
>>>
>>>
>>> --- 3684,3697 ----
>>>            && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
>>>          {
>>>            *op1 = GEN_INT (i - 1);
>>> !         *code = *code == GEU ? GTU : LEU;
>>> !         return;
>>>          }
>>>          break;
>>>
>>>        default:
>>>          gcc_unreachable ();
>>>        }
>>>    }
>>>
>>>
>>> *************** bool
>>> *** 26979,26985 ****
>>>    arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
>>>    {
>>>      enum rtx_code code = GET_CODE (*comparison);
>>> !   enum rtx_code canonical_code;
>>>      enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
>>>        ? GET_MODE (*op2) : GET_MODE (*op1);
>>>
>>> --- 26992,26998 ----
>>>    arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
>>>    {
>>>      enum rtx_code code = GET_CODE (*comparison);
>>> !   int code_int;
>>>      enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
>>>        ? GET_MODE (*op2) : GET_MODE (*op1);
>>>
>>> *************** arm_validize_comparison (rtx *comparison
>>> *** 26988,26995 ****
>>>      if (code == UNEQ || code == LTGT)
>>>        return false;
>>>
>>> !   canonical_code = arm_canonicalize_comparison (code, op1, op2);
>>> !   PUT_CODE (*comparison, canonical_code);
>>>
>>>      switch (mode)
>>>        {
>>> --- 27001,27009 ----
>>>      if (code == UNEQ || code == LTGT)
>>>        return false;
>>>
>>> !   code_int = (int)code;
>>> !   arm_canonicalize_comparison (&code_int, op1, op2, 0);
>>> !   PUT_CODE (*comparison, (enum rtx_code)code_int);
>>>
>>>      switch (mode)
>>>        {
>>> Index: gcc/config/arm/arm.h
>>> ===================================================================
>>> *** gcc/config/arm/arm.h.orig
>>> --- gcc/config/arm/arm.h
>>> *************** extern int making_const_table;
>>> *** 2078,2086 ****
>>>       ? reverse_condition_maybe_unordered (code) \
>>>       : reverse_condition (code))
>>>
>>> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1)
>>> \
>>> -   (CODE) = arm_canonicalize_comparison (CODE, &(OP0), &(OP1))
>>> -
>>>    /* The arm5 clz instruction returns 32.  */
>>>    #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
>>>    #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE)  ((VALUE) = 32, 1)
>>> --- 2078,2083 ----
>>> Index: gcc/config/s390/s390-protos.h
>>> ===================================================================
>>> *** gcc/config/s390/s390-protos.h.orig
>>> --- gcc/config/s390/s390-protos.h
>>> *************** extern int tls_symbolic_operand (rtx);
>>> *** 58,64 ****
>>>    extern bool s390_match_ccmode (rtx, enum machine_mode);
>>>    extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
>>>    extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
>>> - extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx
>>> *);
>>>    extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
>>>    extern void s390_emit_jump (rtx, rtx);
>>>    extern bool symbolic_reference_mentioned_p (rtx);
>>> --- 58,63 ----
>>> Index: gcc/config/s390/s390.c
>>> ===================================================================
>>> *** gcc/config/s390/s390.c.orig
>>> --- gcc/config/s390/s390.c
>>> *************** s390_select_ccmode (enum rtx_code code,
>>> *** 745,753 ****
>>>    /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
>>>       that we can implement more efficiently.  */
>>>
>>> ! void
>>> ! s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
>>>    {
>>>      /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
>>>      if ((*code == EQ || *code == NE)
>>>          && *op1 == const0_rtx
>>> --- 745,757 ----
>>>    /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
>>>       that we can implement more efficiently.  */
>>>
>>> ! static void
>>> ! s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>>> !                             bool op0_preserve_value)
>>>    {
>>> +   if (op0_preserve_value)
>>> +     return;
>>> +
>>>      /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
>>>      if ((*code == EQ || *code == NE)
>>>          && *op1 == const0_rtx
>>> *************** s390_canonicalize_comparison (enum rtx_c
>>> *** 894,900 ****
>>>      if (MEM_P (*op0) && REG_P (*op1))
>>>        {
>>>          rtx tem = *op0; *op0 = *op1; *op1 = tem;
>>> !       *code = swap_condition (*code);
>>>        }
>>>    }
>>>
>>> --- 898,904 ----
>>>      if (MEM_P (*op0) && REG_P (*op1))
>>>        {
>>>          rtx tem = *op0; *op0 = *op1; *op1 = tem;
>>> !       *code = (int)swap_condition ((enum rtx_code)*code);
>>>        }
>>>    }
>>>
>>> *************** s390_loop_unroll_adjust (unsigned nunrol
>>> *** 11071,11076 ****
>>> --- 11075,11083 ----
>>>    #undef TARGET_UNWIND_WORD_MODE
>>>    #define TARGET_UNWIND_WORD_MODE s390_unwind_word_mode
>>>
>>> + #undef TARGET_CANONICALIZE_COMPARISON
>>> + #define TARGET_CANONICALIZE_COMPARISON s390_canonicalize_comparison
>>> +
>>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>>
>>>    #include "gt-s390.h"
>>> Index: gcc/config/s390/s390.h
>>> ===================================================================
>>> *** gcc/config/s390/s390.h.orig
>>> --- gcc/config/s390/s390.h
>>> *************** do {
>>> \
>>> *** 720,729 ****
>>>       return the mode to be used for the comparison.  */
>>>    #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
>>>
>>> - /* Canonicalize a comparison from one we don't have to one we do have.
>>> */
>>> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
>>> -   s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
>>> -
>>>    /* Relative costs of operations.  */
>>>
>>>    /* A C expression for the cost of a branch instruction.  A value of 1
>>> --- 720,725 ----
>>> Index: gcc/config/sh/sh-protos.h
>>> ===================================================================
>>> *** gcc/config/sh/sh-protos.h.orig
>>> --- gcc/config/sh/sh-protos.h
>>> *************** extern bool sh_expand_t_scc (rtx *);
>>> *** 159,166 ****
>>>    extern rtx sh_gen_truncate (enum machine_mode, rtx, int);
>>>    extern bool sh_vector_mode_supported_p (enum machine_mode);
>>>    extern bool sh_cfun_trap_exit_p (void);
>>> - extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
>>> -                                       enum machine_mode mode =
>>> VOIDmode);
>>>    extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem);
>>>    extern int sh_eval_treg_value (rtx op);
>>>
>>> --- 159,164 ----
>>> Index: gcc/config/sh/sh.c
>>> ===================================================================
>>> *** gcc/config/sh/sh.c.orig
>>> --- gcc/config/sh/sh.c
>>> *************** static int max_mov_insn_displacement (en
>>> *** 314,319 ****
>>> --- 314,322 ----
>>>    static int mov_insn_alignment_mask (enum machine_mode, bool);
>>>    static HOST_WIDE_INT disp_addr_displacement (rtx);
>>>    static bool sequence_insn_p (rtx);
>>> + static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool);
>>> + static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
>>> +                                       enum machine_mode, bool);
>>>
>>>    static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
>>>
>>> *************** static const struct attribute_spec sh_at
>>> *** 586,591 ****
>>> --- 589,597 ----
>>>    #undef TARGET_LEGITIMATE_CONSTANT_P
>>>    #define TARGET_LEGITIMATE_CONSTANT_P  sh_legitimate_constant_p
>>>
>>> + #undef TARGET_CANONICALIZE_COMPARISON
>>> + #define TARGET_CANONICALIZE_COMPARISON        sh_canonicalize_comparison
>>> +
>>>    /* Machine-specific symbol_ref flags.  */
>>>    #define SYMBOL_FLAG_FUNCVEC_FUNCTION    (SYMBOL_FLAG_MACH_DEP << 0)
>>>
>>> *************** prepare_move_operands (rtx operands[], e
>>> *** 1909,1920 ****
>>>        }
>>>    }
>>>
>>> ! /* Implement the CANONICALIZE_COMPARISON macro for the combine pass.
>>> !    This function is also re-used to canonicalize comparisons in cbranch
>>> !    pattern expanders.  */
>>> ! void
>>>    sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
>>> !                           enum machine_mode mode)
>>>    {
>>>      /* When invoked from within the combine pass the mode is not
>>> specified,
>>>         so try to get it from one of the operands.  */
>>> --- 1915,1928 ----
>>>        }
>>>    }
>>>
>>> ! /* Implement the canonicalize_comparison target hook for the combine
>>> !    pass.  For the target hook this function is invoked via
>>> !    sh_canonicalize_comparison.  This function is also re-used to
>>> !    canonicalize comparisons in cbranch pattern expanders.  */
>>> ! static void
>>>    sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
>>> !                           enum machine_mode mode,
>>> !                           bool op0_preserve_value ATTRIBUTE_UNUSED)
>>>    {
>>>      /* When invoked from within the combine pass the mode is not
>>> specified,
>>>         so try to get it from one of the operands.  */
>>> *************** sh_canonicalize_comparison (enum rtx_cod
>>> *** 2008,2013 ****
>>> --- 2016,2034 ----
>>>        }
>>>    }
>>>
>>> + /* This function implements the canonicalize_comparison target hook.
>>> +    This wrapper around the internally used sh_canonicalize_comparison
>>> +    function is needed to do the enum rtx_code <-> int conversion.
>>> +    Target hooks cannot use enum rtx_code in its definition.  */
>>> + static void
>>> + sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>>> +                           bool op0_preserve_value)
>>> + {
>>> +   enum rtx_code tmp_code = (enum rtx_code)*code;
>>> +   sh_canonicalize_comparison (tmp_code, *op0, *op1,
>>> +                             VOIDmode, op0_preserve_value);
>>> +   *code = (int)tmp_code;
>>> + }
>>>    enum rtx_code
>>>    prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
>>>                            enum rtx_code comparison)
>>> *************** prepare_cbranch_operands (rtx *operands,
>>> *** 2021,2027 ****
>>>      else
>>>        scratch = operands[4];
>>>
>>> !   sh_canonicalize_comparison (comparison, operands[1], operands[2],
>>> mode);
>>>
>>>      /* Notice that this function is also invoked after reload by
>>>         the cbranchdi4_i pattern, through expand_cbranchdi4.  */
>>> --- 2042,2049 ----
>>>      else
>>>        scratch = operands[4];
>>>
>>> !   sh_canonicalize_comparison (comparison, operands[1], operands[2],
>>> !                             mode, false);
>>>
>>>      /* Notice that this function is also invoked after reload by
>>>         the cbranchdi4_i pattern, through expand_cbranchdi4.  */
>>> Index: gcc/config/sh/sh.h
>>> ===================================================================
>>> *** gcc/config/sh/sh.h.orig
>>> --- gcc/config/sh/sh.h
>>> *************** struct sh_args {
>>> *** 1873,1882 ****
>>>       more compact code.  */
>>>    #define SHIFT_COUNT_TRUNCATED (0)
>>>
>>> - /* CANONICALIZE_COMPARISON macro for the combine pass.  */
>>> - #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
>>> -   sh_canonicalize_comparison ((CODE), (OP0), (OP1))
>>> -
>>>    /* All integers have the same format so truncation is easy.  */
>>>    /* But SHmedia must sign-extend DImode when truncating to SImode.  */
>>>    #define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) \
>>> --- 1873,1878 ----
>>> Index: gcc/config/spu/spu.c
>>> ===================================================================
>>> *** gcc/config/spu/spu.c.orig
>>> --- gcc/config/spu/spu.c
>>> *************** spu_output_mi_thunk (FILE *file, tree th
>>> *** 7095,7100 ****
>>> --- 7095,7114 ----
>>>      final_end_function ();
>>>    }
>>>
>>> + /* Canonicalize a comparison from one we don't have to one we do have.
>>> */
>>> + static void
>>> + spu_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
>>> +                            bool op0_preserve_value)
>>> + {
>>> +   if (!op0_preserve_value
>>> +       && (*code == LE || *code == LT || *code == LEU || *code == LTU))
>>> +     {
>>> +       rtx tem = *op0;
>>> +       *op0 = *op1;
>>> +       *op1 = tem;
>>> +       *code = (int)swap_condition ((enum rtx_code)*code);
>>> +     }
>>> + }
>>>
>>>    /*  Table of machine attributes.  */
>>>    static const struct attribute_spec spu_attribute_table[] =
>>> *************** static const struct attribute_spec spu_a
>>> *** 7308,7313 ****
>>> --- 7322,7330 ----
>>>    #undef TARGET_DELAY_VARTRACK
>>>    #define TARGET_DELAY_VARTRACK true
>>>
>>> + #undef TARGET_CANONICALIZE_COMPARISON
>>> + #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
>>> +
>>>    struct gcc_target targetm = TARGET_INITIALIZER;
>>>
>>>    #include "gt-spu.h"
>>> Index: gcc/config/spu/spu.h
>>> ===================================================================
>>> *** gcc/config/spu/spu.h.orig
>>> --- gcc/config/spu/spu.h
>>> *************** do {
>>> \
>>> *** 520,537 ****
>>>
>>>    #define NO_IMPLICIT_EXTERN_C 1
>>>
>>> - /* Canonicalize a comparison from one we don't have to one we do have.
>>> */
>>> - #define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
>>> -   do {
>>> \
>>> -     if (((CODE) == LE || (CODE) == LT || (CODE) == LEU || (CODE) ==
>>> LTU)) \
>>> -       {
>>> \
>>> -         rtx tem = (OP0);
>>> \
>>> -         (OP0) = (OP1);
>>> \
>>> -         (OP1) = tem;
>>> \
>>> -         (CODE) = swap_condition (CODE);
>>> \
>>> -       }
>>> \
>>> -   } while (0)
>>> -
>>>
>>>    /* Address spaces.  */
>>>    #define ADDR_SPACE_EA 1
>>> --- 520,525 ----
>>> Index: gcc/doc/tm.texi.in
>>> ===================================================================
>>> *** gcc/doc/tm.texi.in.orig
>>> --- gcc/doc/tm.texi.in
>>> *************** You should define this macro if and only
>>> *** 5928,5952 ****
>>>    in @file{@var{machine}-modes.def}.
>>>    @end defmac
>>>
>>> ! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
>>>    On some machines not all possible comparisons are defined, but you can
>>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>>    comparison instead and swap the order of the operands.
>>>
>>> ! On such machines, define this macro to be a C statement to do any
>>> ! required conversions.  @var{code} is the initial comparison code
>>> ! and @var{op0} and @var{op1} are the left and right operands of the
>>> ! comparison, respectively.  You should modify @var{code}, @var{op0}, and
>>> ! @var{op1} as required.
>>>
>>>    GCC will not assume that the comparison resulting from this macro is
>>>    valid but will see if the resulting insn matches a pattern in the
>>>    @file{md} file.
>>>
>>> ! You need not define this macro if it would never change the comparison
>>> ! code or operands.
>>> ! @end defmac
>>>
>>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>>    A C expression whose value is one if it is always safe to reverse a
>>> --- 5928,5954 ----
>>>    in @file{@var{machine}-modes.def}.
>>>    @end defmac
>>>
>>> ! @hook TARGET_CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1},
>>> @var{op0_preserve_value})
>>>    On some machines not all possible comparisons are defined, but you can
>>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>>    comparison instead and swap the order of the operands.
>>>
>>> ! On such machines, implement this hook to do any required conversions.
>>> ! @var{code} is the initial comparison code and @var{op0} and @var{op1}
>>> ! are the left and right operands of the comparison, respectively.  If
>>> ! @var{op0_preserve_value} is @code{true} the implementation is not
>>> ! allowed to change the value of @var{op0} since the value might be used
>>> ! in RTXs which aren't comparisons.  E.g. the implementation is not
>>> ! allowed to swap operands in that case.
>>>
>>>    GCC will not assume that the comparison resulting from this macro is
>>>    valid but will see if the resulting insn matches a pattern in the
>>>    @file{md} file.
>>>
>>> ! You need not to implement this hook if it would never change the
>>> ! comparison code or operands.
>>> ! @end deftypefn
>>>
>>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>>    A C expression whose value is one if it is always safe to reverse a
>>> Index: gcc/target.def
>>> ===================================================================
>>> *** gcc/target.def.orig
>>> --- gcc/target.def
>>> *************** DEFHOOK
>>> *** 2877,2882 ****
>>> --- 2877,2890 ----
>>>     enum unwind_info_type, (void),
>>>     default_debug_unwind_info)
>>>
>>> + /* The code parameter should be of type enum rtx_code but this is not
>>> +    defined at this time.  */
>>> + DEFHOOK
>>> + (canonicalize_comparison,
>>> +  "",
>>> +  void, (int *code, rtx *op0, rtx *op1, bool op0_preserve_value),
>>> +  default_canonicalize_comparison)
>>> +
>>>    DEFHOOKPOD
>>>    (atomic_test_and_set_trueval,
>>>     "This value should be set if the result written by\
>>> Index: gcc/targhooks.h
>>> ===================================================================
>>> *** gcc/targhooks.h.orig
>>> --- gcc/targhooks.h
>>> *************** extern unsigned char default_class_max_n
>>> *** 179,184 ****
>>> --- 179,186 ----
>>>
>>>    extern enum unwind_info_type default_debug_unwind_info (void);
>>>
>>> + extern bool default_canonicalize_comparison (int *, rtx *, rtx *, bool);
>>> +
>>>    extern int default_label_align_after_barrier_max_skip (rtx);
>>>    extern int default_loop_align_max_skip (rtx);
>>>    extern int default_label_align_max_skip (rtx);
>>> Index: gcc/doc/tm.texi
>>> ===================================================================
>>> *** gcc/doc/tm.texi.orig
>>> --- gcc/doc/tm.texi
>>> *************** You should define this macro if and only
>>> *** 6024,6048 ****
>>>    in @file{@var{machine}-modes.def}.
>>>    @end defmac
>>>
>>> ! @defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
>>>    On some machines not all possible comparisons are defined, but you can
>>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>>    comparison instead and swap the order of the operands.
>>>
>>> ! On such machines, define this macro to be a C statement to do any
>>> ! required conversions.  @var{code} is the initial comparison code
>>> ! and @var{op0} and @var{op1} are the left and right operands of the
>>> ! comparison, respectively.  You should modify @var{code}, @var{op0}, and
>>> ! @var{op1} as required.
>>>
>>>    GCC will not assume that the comparison resulting from this macro is
>>>    valid but will see if the resulting insn matches a pattern in the
>>>    @file{md} file.
>>>
>>> ! You need not define this macro if it would never change the comparison
>>> ! code or operands.
>>> ! @end defmac
>>>
>>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>>    A C expression whose value is one if it is always safe to reverse a
>>> --- 6024,6050 ----
>>>    in @file{@var{machine}-modes.def}.
>>>    @end defmac
>>>
>>> ! @deftypefn {Target Hook} void TARGET_CANONICALIZE_COMPARISON (int
>>> *@var{code}, rtx *@var{op0}, rtx
>>> *@var{op1}, bool @var{op0_preserve_value}) (@var{code}, @var{op0},
>>> @var{op1}, @var{op0_preserve_value})
>>>    On some machines not all possible comparisons are defined, but you can
>>>    convert an invalid comparison into a valid one.  For example, the Alpha
>>>    does not have a @code{GT} comparison, but you can use an @code{LT}
>>>    comparison instead and swap the order of the operands.
>>>
>>> ! On such machines, implement this hook to do any required conversions.
>>> ! @var{code} is the initial comparison code and @var{op0} and @var{op1}
>>> ! are the left and right operands of the comparison, respectively.  If
>>> ! @var{op0_preserve_value} is @code{true} the implementation is not
>>> ! allowed to change the value of @var{op0} since the value might be used
>>> ! in RTXs which aren't comparisons.  E.g. the implementation is not
>>> ! allowed to swap operands in that case.
>>>
>>>    GCC will not assume that the comparison resulting from this macro is
>>>    valid but will see if the resulting insn matches a pattern in the
>>>    @file{md} file.
>>>
>>> ! You need not to implement this hook if it would never change the
>>> ! comparison code or operands.
>>> ! @end deftypefn
>>>
>>>    @defmac REVERSIBLE_CC_MODE (@var{mode})
>>>    A C expression whose value is one if it is always safe to reverse a
>>>
>>>
>>>
>>>
>>
>>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PING] Bugfix: Additional parameter for canonicalize comparison
  2012-12-19 14:04     ` Richard Biener
  2012-12-19 14:05       ` Richard Biener
@ 2012-12-19 18:57       ` Jan-Benedict Glaw
  1 sibling, 0 replies; 6+ messages in thread
From: Jan-Benedict Glaw @ 2012-12-19 18:57 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Earnshaw, Andreas Krebbel, nickc, paul,
	Ramana Radhakrishnan, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1298 bytes --]

On Wed, 2012-12-19 15:04:02 +0100, Richard Biener <richard.guenther@gmail.com> wrote:
> On Wed, Dec 19, 2012 at 12:34 PM, Richard Earnshaw <rearnsha@arm.com> wrote:
> > On 19/12/12 09:53, Andreas Krebbel wrote:
> >>
> >> Hi,
> >>
> >> are the ARM parts of the patch below ok for mainline?
> >>
> >
> > Yes.
> >
> > Sorry for the delay.
> 
> I think this broke bootstrap on x86_64:
> 
> /space/rguenther/src/svn/trunk/gcc/config/i386/i386.c: At global scope:
> /space/rguenther/src/svn/trunk/gcc/config/i386/i386.c:42503: error:
> invalid conversion from 'bool (*)(int*, rtx_def**, rtx_def**, bool)'
> to 'void (*)(int*, rtx_def**, rtx_def**, bool)'
> make[3]: *** [i386.o] Error 1
> 
> or maybe even everywhere.  Yeah, bool vs. void return value in the default
> implementation.

My build robot already found aarch64-elf, avr, bfin-elf and frv-linux
broken by this. Probably every target affected that use the default
function.

MfG, JBG

-- 
      Jan-Benedict Glaw      jbglaw@lug-owl.de              +49-172-7608481
Signature of:           Ich hatte in letzter Zeit ein bißchen viel Realitycheck.
the second  :               Langsam möchte ich mal wieder weiterträumen können.
                             -- Maximilian Wilhelm (18. Mai 2005, #lug-owl.de)

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2012-12-19 18:57 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-12 11:23 [PATCH] Bugfix: Additional parameter for canonicalize comparison Andreas Krebbel
2012-12-19  9:53 ` [PING] " Andreas Krebbel
2012-12-19 11:34   ` Richard Earnshaw
2012-12-19 14:04     ` Richard Biener
2012-12-19 14:05       ` Richard Biener
2012-12-19 18:57       ` Jan-Benedict Glaw

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).