2004-04-29 Paolo Bonzini <bonzini@gnu.org>
authorbonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 29 Apr 2004 07:50:55 +0000 (07:50 +0000)
committerbonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 29 Apr 2004 07:50:55 +0000 (07:50 +0000)
        * combine.c (combine_simplify_rtx): Adjust call to use
        simplify_relational_operation.  Do not use SELECT_CC_MODE
        when a comparison already has a MODE_CC mode.
        (simplify_set): simplify_relational_operation may now
        return another relational expression.
        * cse.c (fold_rtx): simplify_relational_operation now
        takes of computing the comparison mode.
        * dojump.c (compare_from_rtx): Use simplify_relational_operation,
        remove dead code.
        (do_compare_rtx_and_jump): Likewise.
        * integrate.c (subst_constants): simplify_relational_operation
        may now return another relational expression.
        * simplify-rtx.c (simplify_gen_relational): Move most code to
        the new simplify_relational_operation and
        simplify_relational_operation_1 functions.
        (simplify_relational_operation): Rewritten.
        (simplify_relational_operation_1): New function.
        (simplify_ternary_operation): simplify_relational_operation
        may now return another relational expression.
        (simplify_rtx): Remove unnecessary temp variable.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@81282 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/combine.c
gcc/cse.c
gcc/dojump.c
gcc/integrate.c
gcc/simplify-rtx.c

index 3916f83..01c77f0 100644 (file)
@@ -1,3 +1,26 @@
+2004-04-29  Paolo Bonzini  <bonzini@gnu.org>
+
+       * combine.c (combine_simplify_rtx): Adjust call to use
+       simplify_relational_operation.  Do not use SELECT_CC_MODE
+       when a comparison already has a MODE_CC mode.
+       (simplify_set): simplify_relational_operation may now
+       return another relational expression.
+       * cse.c (fold_rtx): simplify_relational_operation now
+       takes of computing the comparison mode.
+       * dojump.c (compare_from_rtx): Use simplify_relational_operation,
+       remove dead code.
+       (do_compare_rtx_and_jump): Likewise.
+       * integrate.c (subst_constants): simplify_relational_operation
+       may now return another relational expression.
+       * simplify-rtx.c (simplify_gen_relational): Move most code to
+       the new simplify_relational_operation and
+       simplify_relational_operation_1 functions.
+       (simplify_relational_operation): Rewritten.
+       (simplify_relational_operation_1): New function.
+       (simplify_ternary_operation): simplify_relational_operation
+       may now return another relational expression.
+       (simplify_rtx): Remove unnecessary temp variable. 
+
 2004-04-29  Uros Bizjak  <uros@kss-loka.si>
 
         * reg-stack.c (swap_to_top): New function.
index 568862d..1d6093a 100644 (file)
@@ -143,13 +143,103 @@ static int max_uid_cuid;
 
 static unsigned int combine_max_regno;
 
-/* Record last point of death of (hard or pseudo) register n.  */
+struct reg_stat {
+  /* Record last point of death of (hard or pseudo) register n.  */
+  rtx                          last_death;
 
-static rtx *reg_last_death;
+  /* Record last point of modification of (hard or pseudo) register n.  */
+  rtx                          last_set;
 
-/* Record last point of modification of (hard or pseudo) register n.  */
+  /* The next group of fields allows the recording of the last value assigned
+     to (hard or pseudo) register n.  We use this information to see if an
+     operation being processed is redundant given a prior operation performed
+     on the register.  For example, an `and' with a constant is redundant if
+     all the zero bits are already known to be turned off.
 
-static rtx *reg_last_set;
+     We use an approach similar to that used by cse, but change it in the
+     following ways:
+
+     (1) We do not want to reinitialize at each label.
+     (2) It is useful, but not critical, to know the actual value assigned
+         to a register.  Often just its form is helpful.
+
+     Therefore, we maintain the following fields:
+
+     last_set_value            the last value assigned
+     last_set_label            records the value of label_tick when the
+                               register was assigned
+     last_set_table_tick       records the value of label_tick when a
+                               value using the register is assigned
+     last_set_invalid          set to nonzero when it is not valid
+                               to use the value of this register in some
+                               register's value
+
+     To understand the usage of these tables, it is important to understand
+     the distinction between the value in last_set_value being valid and
+     the register being validly contained in some other expression in the
+     table.
+
+     (The next two parameters are out of date).
+
+     reg_stat[i].last_set_value is valid if it is nonzero, and either
+     reg_n_sets[i] is 1 or reg_stat[i].last_set_label == label_tick.
+
+     Register I may validly appear in any expression returned for the value
+     of another register if reg_n_sets[i] is 1.  It may also appear in the
+     value for register J if reg_stat[j].last_set_invalid is zero, or
+     reg_stat[i].last_set_label < reg_stat[j].last_set_label.
+
+     If an expression is found in the table containing a register which may
+     not validly appear in an expression, the register is replaced by
+     something that won't match, (clobber (const_int 0)).  */
+
+  /* Record last value assigned to (hard or pseudo) register n.  */
+
+  rtx                          last_set_value;
+
+  /* Record the value of label_tick when an expression involving register n
+     is placed in last_set_value.  */
+
+  int                          last_set_table_tick;
+
+  /* Record the value of label_tick when the value for register n is placed in
+     last_set_value.  */
+
+  int                          last_set_label;
+
+  /* These fields are maintained in parallel with last_set_value and are
+     used to store the mode in which the register was last set, te bits
+     that were known to be zero when it was last set, and the number of
+     sign bits copies it was known to have when it was last set.  */
+
+  unsigned HOST_WIDE_INT       last_set_nonzero_bits;
+  char                         last_set_sign_bit_copies;
+  ENUM_BITFIELD(machine_mode)  last_set_mode : 8; 
+
+  /* Set nonzero if references to register n in expressions should not be
+     used.  last_set_invalid is set nonzero when this register is being
+     assigned to and last_set_table_tick == label_tick.  */
+
+  char                         last_set_invalid;
+
+  /* Some registers that are set more than once and used in more than one
+     basic block are nevertheless always set in similar ways.  For example,
+     a QImode register may be loaded from memory in two places on a machine
+     where byte loads zero extend.
+
+     We record in the following fields if a register has some leading bits
+     that are always equal to the sign bit, and what we know about the
+     nonzero bits of a register, specifically which bits are known to be
+     zero.
+
+     If an entry is zero, it means that we don't know anything special.  */
+
+  unsigned char                        sign_bit_copies;
+
+  unsigned HOST_WIDE_INT       nonzero_bits;
+};
+
+static struct reg_stat *reg_stat;
 
 /* Record the cuid of the last insn that invalidated memory
    (anything that writes memory, and subroutine calls, but not pushes).  */
@@ -197,110 +287,23 @@ static basic_block this_basic_block;
    those blocks as starting points.  */
 static sbitmap refresh_blocks;
 \f
-/* The next group of arrays allows the recording of the last value assigned
-   to (hard or pseudo) register n.  We use this information to see if an
-   operation being processed is redundant given a prior operation performed
-   on the register.  For example, an `and' with a constant is redundant if
-   all the zero bits are already known to be turned off.
-
-   We use an approach similar to that used by cse, but change it in the
-   following ways:
-
-   (1) We do not want to reinitialize at each label.
-   (2) It is useful, but not critical, to know the actual value assigned
-       to a register.  Often just its form is helpful.
-
-   Therefore, we maintain the following arrays:
-
-   reg_last_set_value          the last value assigned
-   reg_last_set_label          records the value of label_tick when the
-                               register was assigned
-   reg_last_set_table_tick     records the value of label_tick when a
-                               value using the register is assigned
-   reg_last_set_invalid                set to nonzero when it is not valid
-                               to use the value of this register in some
-                               register's value
-
-   To understand the usage of these tables, it is important to understand
-   the distinction between the value in reg_last_set_value being valid
-   and the register being validly contained in some other expression in the
-   table.
-
-   Entry I in reg_last_set_value is valid if it is nonzero, and either
-   reg_n_sets[i] is 1 or reg_last_set_label[i] == label_tick.
-
-   Register I may validly appear in any expression returned for the value
-   of another register if reg_n_sets[i] is 1.  It may also appear in the
-   value for register J if reg_last_set_label[i] < reg_last_set_label[j] or
-   reg_last_set_invalid[j] is zero.
-
-   If an expression is found in the table containing a register which may
-   not validly appear in an expression, the register is replaced by
-   something that won't match, (clobber (const_int 0)).
-
-   reg_last_set_invalid[i] is set nonzero when register I is being assigned
-   to and reg_last_set_table_tick[i] == label_tick.  */
-
-/* Record last value assigned to (hard or pseudo) register n.  */
-
-static rtx *reg_last_set_value;
-
-/* Record the value of label_tick when the value for register n is placed in
-   reg_last_set_value[n].  */
-
-static int *reg_last_set_label;
-
-/* Record the value of label_tick when an expression involving register n
-   is placed in reg_last_set_value.  */
-
-static int *reg_last_set_table_tick;
-
-/* Set nonzero if references to register n in expressions should not be
-   used.  */
-
-static char *reg_last_set_invalid;
-
 /* Incremented for each label.  */
 
 static int label_tick;
 
-/* Some registers that are set more than once and used in more than one
-   basic block are nevertheless always set in similar ways.  For example,
-   a QImode register may be loaded from memory in two places on a machine
-   where byte loads zero extend.
-
-   We record in the following array what we know about the nonzero
-   bits of a register, specifically which bits are known to be zero.
-
-   If an entry is zero, it means that we don't know anything special.  */
-
-static unsigned HOST_WIDE_INT *reg_nonzero_bits;
-
-/* Mode used to compute significance in reg_nonzero_bits.  It is the largest
-   integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
+/* Mode used to compute significance in reg_stat[].nonzero_bits.  It is the
+   largest integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
 
 static enum machine_mode nonzero_bits_mode;
 
-/* Nonzero if we know that a register has some leading bits that are always
-   equal to the sign bit.  */
-
-static unsigned char *reg_sign_bit_copies;
-
-/* Nonzero when reg_nonzero_bits and reg_sign_bit_copies can be safely used.
-   It is zero while computing them and after combine has completed.  This
-   former test prevents propagating values based on previously set values,
-   which can be incorrect if a variable is modified in a loop.  */
+/* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can
+   be safely used.  It is zero while computing them and after combine has
+   completed.  This former test prevents propagating values based on
+   previously set values, which can be incorrect if a variable is modified
+   in a loop.  */
 
 static int nonzero_sign_valid;
 
-/* These arrays are maintained in parallel with reg_last_set_value
-   and are used to store the mode in which the register was last set,
-   the bits that were known to be zero when it was last set, and the
-   number of sign bits copies it was known to have when it was last set.  */
-
-static enum machine_mode *reg_last_set_mode;
-static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits;
-static char *reg_last_set_sign_bit_copies;
 \f
 /* Record one modification to rtl structure
    to be undone by storing old_contents into *where.
@@ -336,7 +339,7 @@ static int n_occurrences;
 
 static void do_SUBST (rtx *, rtx);
 static void do_SUBST_INT (int *, int);
-static void init_reg_last_arrays (void);
+static void init_reg_last (void);
 static void setup_incoming_promotions (void);
 static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
 static int cant_combine_insn_p (rtx);
@@ -523,20 +526,7 @@ combine_instructions (rtx f, unsigned int nregs)
      See comments in gen_lowpart_for_combine.  */
   gen_lowpart = gen_lowpart_for_combine;
 
-  reg_nonzero_bits = xcalloc (nregs, sizeof (unsigned HOST_WIDE_INT));
-  reg_sign_bit_copies = xcalloc (nregs, sizeof (unsigned char));
-
-  reg_last_death = xmalloc (nregs * sizeof (rtx));
-  reg_last_set = xmalloc (nregs * sizeof (rtx));
-  reg_last_set_value = xmalloc (nregs * sizeof (rtx));
-  reg_last_set_table_tick = xmalloc (nregs * sizeof (int));
-  reg_last_set_label = xmalloc (nregs * sizeof (int));
-  reg_last_set_invalid = xmalloc (nregs * sizeof (char));
-  reg_last_set_mode = xmalloc (nregs * sizeof (enum machine_mode));
-  reg_last_set_nonzero_bits = xmalloc (nregs * sizeof (HOST_WIDE_INT));
-  reg_last_set_sign_bit_copies = xmalloc (nregs * sizeof (char));
-
-  init_reg_last_arrays ();
+  reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
 
   init_recog_no_volatile ();
 
@@ -551,8 +541,8 @@ combine_instructions (rtx f, unsigned int nregs)
 
   nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
 
-  /* Don't use reg_nonzero_bits when computing it.  This can cause problems
-     when, for example, we have j <<= 1 in a loop.  */
+  /* Don't use reg_stat[].nonzero_bits when computing it.  This can cause
+     problems when, for example, we have j <<= 1 in a loop.  */
 
   nonzero_sign_valid = 0;
 
@@ -605,7 +595,7 @@ combine_instructions (rtx f, unsigned int nregs)
   label_tick = 1;
   last_call_cuid = 0;
   mem_last_set = 0;
-  init_reg_last_arrays ();
+  init_reg_last ();
   setup_incoming_promotions ();
 
   FOR_EACH_BB (this_basic_block)
@@ -768,17 +758,7 @@ combine_instructions (rtx f, unsigned int nregs)
 
   /* Clean up.  */
   sbitmap_free (refresh_blocks);
-  free (reg_nonzero_bits);
-  free (reg_sign_bit_copies);
-  free (reg_last_death);
-  free (reg_last_set);
-  free (reg_last_set_value);
-  free (reg_last_set_table_tick);
-  free (reg_last_set_label);
-  free (reg_last_set_invalid);
-  free (reg_last_set_mode);
-  free (reg_last_set_nonzero_bits);
-  free (reg_last_set_sign_bit_copies);
+  free (reg_stat);
   free (uid_cuid);
 
   {
@@ -805,22 +785,14 @@ combine_instructions (rtx f, unsigned int nregs)
   return new_direct_jump_p;
 }
 
-/* Wipe the reg_last_xxx arrays in preparation for another pass.  */
+/* Wipe the last_xxx fields of reg_stat in preparation for another pass.  */
 
 static void
-init_reg_last_arrays (void)
+init_reg_last (void)
 {
-  unsigned int nregs = combine_max_regno;
-
-  memset (reg_last_death, 0, nregs * sizeof (rtx));
-  memset (reg_last_set, 0, nregs * sizeof (rtx));
-  memset (reg_last_set_value, 0, nregs * sizeof (rtx));
-  memset (reg_last_set_table_tick, 0, nregs * sizeof (int));
-  memset (reg_last_set_label, 0, nregs * sizeof (int));
-  memset (reg_last_set_invalid, 0, nregs * sizeof (char));
-  memset (reg_last_set_mode, 0, nregs * sizeof (enum machine_mode));
-  memset (reg_last_set_nonzero_bits, 0, nregs * sizeof (HOST_WIDE_INT));
-  memset (reg_last_set_sign_bit_copies, 0, nregs * sizeof (char));
+  unsigned int i;
+  for (i = 0; i < combine_max_regno; i++)
+    memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies));
 }
 \f
 /* Set up any promoted values for incoming argument registers.  */
@@ -878,8 +850,8 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
     {
       if (set == 0 || GET_CODE (set) == CLOBBER)
        {
-         reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
-         reg_sign_bit_copies[REGNO (x)] = 1;
+         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         reg_stat[REGNO (x)].sign_bit_copies = 1;
          return;
        }
 
@@ -901,7 +873,7 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
 #ifdef SHORT_IMMEDIATES_SIGN_EXTEND
          /* If X is narrower than a word and SRC is a non-negative
             constant that would appear negative in the mode of X,
-            sign-extend it for use in reg_nonzero_bits because some
+            sign-extend it for use in reg_stat[].nonzero_bits because some
             machines (maybe most) will actually do the sign-extension
             and this is the conservative approach.
 
@@ -920,18 +892,18 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
 #endif
 
          /* Don't call nonzero_bits if it cannot change anything.  */
-         if (reg_nonzero_bits[REGNO (x)] != ~(unsigned HOST_WIDE_INT) 0)
-           reg_nonzero_bits[REGNO (x)]
+         if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
+           reg_stat[REGNO (x)].nonzero_bits
              |= nonzero_bits (src, nonzero_bits_mode);
          num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
-         if (reg_sign_bit_copies[REGNO (x)] == 0
-             || reg_sign_bit_copies[REGNO (x)] > num)
-           reg_sign_bit_copies[REGNO (x)] = num;
+         if (reg_stat[REGNO (x)].sign_bit_copies == 0
+             || reg_stat[REGNO (x)].sign_bit_copies > num)
+           reg_stat[REGNO (x)].sign_bit_copies = num;
        }
       else
        {
-         reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
-         reg_sign_bit_copies[REGNO (x)] = 1;
+         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         reg_stat[REGNO (x)].sign_bit_copies = 1;
        }
     }
 }
@@ -1101,7 +1073,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
         does not use any registers whose values alter in between.  However,
         If the insns are adjacent, a use can't cross a set even though we
         think it might (this can happen for a sequence of insns each setting
-        the same destination; reg_last_set of that register might point to
+        the same destination; last_set of that register might point to
         a NOTE).  If INSN has a REG_EQUIV note, the register is always
         equivalent to the memory so the substitution is valid even if there
         are intervening stores.  Also, don't move a volatile asm or
@@ -2331,18 +2303,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
           && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
                 (GET_CODE (temp) == REG
-                 && reg_nonzero_bits[REGNO (temp)] != 0
+                 && reg_stat[REGNO (temp)].nonzero_bits != 0
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                 && (reg_nonzero_bits[REGNO (temp)]
+                 && (reg_stat[REGNO (temp)].nonzero_bits
                      != GET_MODE_MASK (word_mode))))
           && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
                 && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
                     (GET_CODE (temp) == REG
-                     && reg_nonzero_bits[REGNO (temp)] != 0
+                     && reg_stat[REGNO (temp)].nonzero_bits != 0
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                     && (reg_nonzero_bits[REGNO (temp)]
+                     && (reg_stat[REGNO (temp)].nonzero_bits
                          != GET_MODE_MASK (word_mode)))))
           && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
                                         SET_SRC (XVECEXP (newpat, 0, 1)))
@@ -2783,9 +2755,10 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          REG_N_SETS (regno)--;
       }
 
-    /* Update reg_nonzero_bits et al for any changes that may have been made
-       to this insn.  The order of set_nonzero_bits_and_sign_copies() is
-       important.  Because newi2pat can affect nonzero_bits of newpat */
+    /* Update reg_stat[].nonzero_bits et al for any changes that may have
+       been made to this insn.  The order of
+       set_nonzero_bits_and_sign_copies() is important.  Because newi2pat
+       can affect nonzero_bits of newpat */
     if (newi2pat)
       note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
     note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
@@ -4994,23 +4967,23 @@ simplify_set (rtx x)
       rtx op0, op1, tmp;
       int other_changed = 0;
       enum machine_mode compare_mode = GET_MODE (dest);
-      enum machine_mode tmp_mode;
 
       if (GET_CODE (src) == COMPARE)
        op0 = XEXP (src, 0), op1 = XEXP (src, 1);
       else
        op0 = src, op1 = const0_rtx;
 
-      /* Check whether the comparison is known at compile time.  */
-      if (GET_MODE (op0) != VOIDmode)
-       tmp_mode = GET_MODE (op0);
-      else if (GET_MODE (op1) != VOIDmode)
-       tmp_mode = GET_MODE (op1);
+      tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode,
+                                          op0, op1);
+      if (!tmp)
+        new_code = old_code;
+      else if (!CONSTANT_P (tmp))
+        {
+          new_code = GET_CODE (tmp);
+          op0 = XEXP (tmp, 0);
+          op1 = XEXP (tmp, 1);
+        }
       else
-       tmp_mode = compare_mode;
-      tmp = simplify_const_relational_operation (old_code, tmp_mode,
-                                                op0, op1);
-      if (tmp != NULL_RTX)
        {
          rtx pat = PATTERN (other_insn);
          undobuf.other_insn = other_insn;
@@ -5031,12 +5004,15 @@ simplify_set (rtx x)
        }
 
       /* Simplify our comparison, if possible.  */
-      new_code = simplify_comparison (old_code, &op0, &op1);
+      new_code = simplify_comparison (new_code, &op0, &op1);
 
 #ifdef SELECT_CC_MODE
       /* If this machine has CC modes other than CCmode, check to see if we
         need to use a different CC mode here.  */
-      compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+      if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+       compare_mode = GET_MODE (op0);
+      else
+       compare_mode = SELECT_CC_MODE (new_code, op0, op1);
 
 #ifndef HAVE_cc0
       /* If the mode changed, we have to change SET_DEST, the mode in the
@@ -8168,17 +8144,17 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
         value.  Otherwise, use the previously-computed global nonzero bits
         for this register.  */
 
-      if (reg_last_set_value[REGNO (x)] != 0
-         && (reg_last_set_mode[REGNO (x)] == mode
-             || (GET_MODE_CLASS (reg_last_set_mode[REGNO (x)]) == MODE_INT
+      if (reg_stat[REGNO (x)].last_set_value != 0
+         && (reg_stat[REGNO (x)].last_set_mode == mode
+             || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
                  && GET_MODE_CLASS (mode) == MODE_INT))
-         && (reg_last_set_label[REGNO (x)] == label_tick
+         && (reg_stat[REGNO (x)].last_set_label == label_tick
              || (REGNO (x) >= FIRST_PSEUDO_REGISTER
                  && REG_N_SETS (REGNO (x)) == 1
                  && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
                                        REGNO (x))))
-         && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
-       return reg_last_set_nonzero_bits[REGNO (x)] & nonzero;
+         && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
+       return reg_stat[REGNO (x)].last_set_nonzero_bits & nonzero;
 
       tem = get_last_value (x);
 
@@ -8187,8 +8163,8 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
 #ifdef SHORT_IMMEDIATES_SIGN_EXTEND
          /* If X is narrower than MODE and TEM is a non-negative
             constant that would appear negative in the mode of X,
-            sign-extend it for use in reg_nonzero_bits because some
-            machines (maybe most) will actually do the sign-extension
+            sign-extend it for use in reg_stat[].nonzero_bits because
+            some machines (maybe most) will actually do the sign-extension
             and this is the conservative approach.
 
             ??? For 2.5, try to tighten up the MD files in this regard
@@ -8206,9 +8182,9 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
 #endif
          return nonzero_bits_with_known (tem, mode) & nonzero;
        }
-      else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
+      else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
        {
-         unsigned HOST_WIDE_INT mask = reg_nonzero_bits[REGNO (x)];
+         unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
 
          if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width)
            /* We don't know anything about the upper bits.  */
@@ -8664,23 +8640,23 @@ num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x,
        return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
 #endif
 
-      if (reg_last_set_value[REGNO (x)] != 0
-         && reg_last_set_mode[REGNO (x)] == mode
-         && (reg_last_set_label[REGNO (x)] == label_tick
+      if (reg_stat[REGNO (x)].last_set_value != 0
+         && reg_stat[REGNO (x)].last_set_mode == mode
+         && (reg_stat[REGNO (x)].last_set_label == label_tick
              || (REGNO (x) >= FIRST_PSEUDO_REGISTER
                  && REG_N_SETS (REGNO (x)) == 1
                  && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
                                        REGNO (x))))
-         && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
-       return reg_last_set_sign_bit_copies[REGNO (x)];
+         && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
+       return reg_stat[REGNO (x)].last_set_sign_bit_copies;
 
       tem = get_last_value (x);
       if (tem != 0)
        return num_sign_bit_copies_with_known (tem, mode);
 
-      if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0
+      if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
          && GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth)
-       return reg_sign_bit_copies[REGNO (x)];
+       return reg_stat[REGNO (x)].sign_bit_copies;
       break;
 
     case MEM:
@@ -11364,7 +11340,7 @@ reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1)
 }
 \f
 /* Utility function for following routine.  Called when X is part of a value
-   being stored into reg_last_set_value.  Sets reg_last_set_table_tick
+   being stored into last_set_value.  Sets last_set_table_tick
    for each register mentioned.  Similar to mention_regs in cse.c  */
 
 static void
@@ -11383,7 +11359,7 @@ update_table_tick (rtx x)
       unsigned int r;
 
       for (r = regno; r < endregno; r++)
-       reg_last_set_table_tick[r] = label_tick;
+       reg_stat[r].last_set_table_tick = label_tick;
 
       return;
     }
@@ -11431,8 +11407,9 @@ update_table_tick (rtx x)
 
 /* Record that REG is set to VALUE in insn INSN.  If VALUE is zero, we
    are saying that the register is clobbered and we no longer know its
-   value.  If INSN is zero, don't update reg_last_set; this is only permitted
-   with VALUE also zero and is used to invalidate the register.  */
+   value.  If INSN is zero, don't update reg_stat[].last_set; this is
+   only permitted with VALUE also zero and is used to invalidate the
+   register.  */
 
 static void
 record_value_for_reg (rtx reg, rtx insn, rtx value)
@@ -11476,13 +11453,13 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
   for (i = regno; i < endregno; i++)
     {
       if (insn)
-       reg_last_set[i] = insn;
+       reg_stat[i].last_set = insn;
 
-      reg_last_set_value[i] = 0;
-      reg_last_set_mode[i] = 0;
-      reg_last_set_nonzero_bits[i] = 0;
-      reg_last_set_sign_bit_copies[i] = 0;
-      reg_last_death[i] = 0;
+      reg_stat[i].last_set_value = 0;
+      reg_stat[i].last_set_mode = 0;
+      reg_stat[i].last_set_nonzero_bits = 0;
+      reg_stat[i].last_set_sign_bit_copies = 0;
+      reg_stat[i].last_death = 0;
     }
 
   /* Mark registers that are being referenced in this value.  */
@@ -11498,40 +11475,40 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
 
   for (i = regno; i < endregno; i++)
     {
-      reg_last_set_label[i] = label_tick;
-      if (value && reg_last_set_table_tick[i] == label_tick)
-       reg_last_set_invalid[i] = 1;
+      reg_stat[i].last_set_label = label_tick;
+      if (value && reg_stat[i].last_set_table_tick == label_tick)
+       reg_stat[i].last_set_invalid = 1;
       else
-       reg_last_set_invalid[i] = 0;
+       reg_stat[i].last_set_invalid = 0;
     }
 
   /* The value being assigned might refer to X (like in "x++;").  In that
      case, we must replace it with (clobber (const_int 0)) to prevent
      infinite loops.  */
   if (value && ! get_last_value_validate (&value, insn,
-                                         reg_last_set_label[regno], 0))
+                                         reg_stat[regno].last_set_label, 0))
     {
       value = copy_rtx (value);
       if (! get_last_value_validate (&value, insn,
-                                    reg_last_set_label[regno], 1))
+                                    reg_stat[regno].last_set_label, 1))
        value = 0;
     }
 
   /* For the main register being modified, update the value, the mode, the
      nonzero bits, and the number of sign bit copies.  */
 
-  reg_last_set_value[regno] = value;
+  reg_stat[regno].last_set_value = value;
 
   if (value)
     {
       enum machine_mode mode = GET_MODE (reg);
       subst_low_cuid = INSN_CUID (insn);
-      reg_last_set_mode[regno] = mode;
+      reg_stat[regno].last_set_mode = mode;
       if (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        mode = nonzero_bits_mode;
-      reg_last_set_nonzero_bits[regno] = nonzero_bits (value, mode);
-      reg_last_set_sign_bit_copies[regno]
+      reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode);
+      reg_stat[regno].last_set_sign_bit_copies
        = num_sign_bit_copies (value, GET_MODE (reg));
     }
 }
@@ -11576,11 +11553,11 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
    for the things done by INSN.  This is the last thing done in processing
    INSN in the combiner loop.
 
-   We update reg_last_set, reg_last_set_value, reg_last_set_mode,
-   reg_last_set_nonzero_bits, reg_last_set_sign_bit_copies, reg_last_death,
-   and also the similar information mem_last_set (which insn most recently
-   modified memory) and last_call_cuid (which insn was the most recent
-   subroutine call).  */
+   We update reg_stat[], in particular fields last_set, last_set_value,
+   last_set_mode, last_set_nonzero_bits, last_set_sign_bit_copies,
+   last_death, and also the similar information mem_last_set (which insn
+   most recently modified memory) and last_call_cuid (which insn was the
+   most recent subroutine call).  */
 
 static void
 record_dead_and_set_regs (rtx insn)
@@ -11600,7 +11577,7 @@ record_dead_and_set_regs (rtx insn)
                       : 1);
 
          for (i = regno; i < endregno; i++)
-           reg_last_death[i] = insn;
+           reg_stat[i].last_death = insn;
        }
       else if (REG_NOTE_KIND (link) == REG_INC)
        record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
@@ -11611,11 +11588,11 @@ record_dead_and_set_regs (rtx insn)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
          {
-           reg_last_set_value[i] = 0;
-           reg_last_set_mode[i] = 0;
-           reg_last_set_nonzero_bits[i] = 0;
-           reg_last_set_sign_bit_copies[i] = 0;
-           reg_last_death[i] = 0;
+           reg_stat[i].last_set_value = 0;
+           reg_stat[i].last_set_mode = 0;
+           reg_stat[i].last_set_nonzero_bits = 0;
+           reg_stat[i].last_set_sign_bit_copies = 0;
+           reg_stat[i].last_death = 0;
          }
 
       last_call_cuid = mem_last_set = INSN_CUID (insn);
@@ -11663,10 +11640,10 @@ record_promoted_value (rtx insn, rtx subreg)
          continue;
        }
 
-      if (reg_last_set[regno] == insn)
+      if (reg_stat[regno].last_set == insn)
        {
          if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
-           reg_last_set_nonzero_bits[regno] &= GET_MODE_MASK (mode);
+           reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
        }
 
       if (GET_CODE (SET_SRC (set)) == REG)
@@ -11736,14 +11713,14 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
       unsigned int j;
 
       for (j = regno; j < endregno; j++)
-       if (reg_last_set_invalid[j]
+       if (reg_stat[j].last_set_invalid
            /* If this is a pseudo-register that was only set once and not
               live at the beginning of the function, it is always valid.  */
            || (! (regno >= FIRST_PSEUDO_REGISTER
                   && REG_N_SETS (regno) == 1
                   && (! REGNO_REG_SET_P
                       (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))
-               && reg_last_set_label[j] > tick))
+               && reg_stat[j].last_set_label > tick))
          {
            if (replace)
              *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
@@ -11835,7 +11812,7 @@ get_last_value (rtx x)
     return 0;
 
   regno = REGNO (x);
-  value = reg_last_set_value[regno];
+  value = reg_stat[regno].last_set_value;
 
   /* If we don't have a value, or if it isn't for this basic block and
      it's either a hard register, set more than once, or it's a live
@@ -11848,7 +11825,7 @@ get_last_value (rtx x)
      block.  */
 
   if (value == 0
-      || (reg_last_set_label[regno] != label_tick
+      || (reg_stat[regno].last_set_label != label_tick
          && (regno < FIRST_PSEUDO_REGISTER
              || REG_N_SETS (regno) != 1
              || (REGNO_REG_SET_P
@@ -11857,20 +11834,20 @@ get_last_value (rtx x)
 
   /* If the value was set in a later insn than the ones we are processing,
      we can't use it even if the register was only set once.  */
-  if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid)
+  if (INSN_CUID (reg_stat[regno].last_set) >= subst_low_cuid)
     return 0;
 
   /* If the value has all its registers valid, return it.  */
-  if (get_last_value_validate (&value, reg_last_set[regno],
-                              reg_last_set_label[regno], 0))
+  if (get_last_value_validate (&value, reg_stat[regno].last_set,
+                              reg_stat[regno].last_set_label, 0))
     return value;
 
   /* Otherwise, make a copy and replace any invalid register with
      (clobber (const_int 0)).  If that fails for some reason, return 0.  */
 
   value = copy_rtx (value);
-  if (get_last_value_validate (&value, reg_last_set[regno],
-                              reg_last_set_label[regno], 1))
+  if (get_last_value_validate (&value, reg_stat[regno].last_set,
+                              reg_stat[regno].last_set_label, 1))
     return value;
 
   return 0;
@@ -11899,8 +11876,8 @@ use_crosses_set_p (rtx x, int from_cuid)
        return 1;
 #endif
       for (; regno < endreg; regno++)
-       if (reg_last_set[regno]
-           && INSN_CUID (reg_last_set[regno]) > from_cuid)
+       if (reg_stat[regno].last_set
+           && INSN_CUID (reg_stat[regno].last_set) > from_cuid)
          return 1;
       return 0;
     }
@@ -12160,7 +12137,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
   if (code == REG)
     {
       unsigned int regno = REGNO (x);
-      rtx where_dead = reg_last_death[regno];
+      rtx where_dead = reg_stat[regno].last_death;
       rtx before_dead, after_dead;
 
       /* Don't move the register if it gets killed in between from and to.  */
@@ -12187,7 +12164,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
          rtx note = remove_death (regno, where_dead);
 
          /* It is possible for the call above to return 0.  This can occur
-            when reg_last_death points to I2 or I1 that we combined with.
+            when last_death points to I2 or I1 that we combined with.
             In that case make a new note.
 
             We must also check for the case where X is a hard register
@@ -12794,14 +12771,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                  || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
                {
                  /* Unless the register previously died in PLACE, clear
-                    reg_last_death.  [I no longer understand why this is
+                    last_death.  [I no longer understand why this is
                     being done.] */
-                 if (reg_last_death[regno] != place)
-                   reg_last_death[regno] = 0;
+                 if (reg_stat[regno].last_death != place)
+                   reg_stat[regno].last_death = 0;
                  place = 0;
                }
              else
-               reg_last_death[regno] = place;
+               reg_stat[regno].last_death = place;
 
              /* If this is a death note for a hard reg that is occupying
                 multiple registers, ensure that we are still using all
index 0a7281e..e155db9 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -3924,21 +3924,11 @@ fold_rtx (rtx x, rtx insn)
            }
        }
 
-      new = simplify_relational_operation (code, mode,
-                                          (mode_arg0 != VOIDmode
-                                           ? mode_arg0
-                                           : (GET_MODE (const_arg0
-                                                        ? const_arg0
-                                                        : folded_arg0)
-                                              != VOIDmode)
-                                           ? GET_MODE (const_arg0
-                                                       ? const_arg0
-                                                       : folded_arg0)
-                                           : GET_MODE (const_arg1
-                                                       ? const_arg1
-                                                       : folded_arg1)),
-                                          const_arg0 ? const_arg0 : folded_arg0,
-                                          const_arg1 ? const_arg1 : folded_arg1);
+      {
+       rtx op0 = const_arg0 ? const_arg0 : folded_arg0;
+       rtx op1 = const_arg1 ? const_arg1 : folded_arg1;
+        new = simplify_relational_operation (code, mode, mode_arg0, op0, op1);
+      }
       break;
 
     case RTX_BIN_ARITH:
index eb98e76..7f76c5e 100644 (file)
@@ -820,7 +820,6 @@ rtx
 compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
                  enum machine_mode mode, rtx size)
 {
-  enum rtx_code ucode;
   rtx tem;
 
   /* If one operand is constant, make it the second one.  Only do this
@@ -842,32 +841,19 @@ compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 
   do_pending_stack_adjust ();
 
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
-  if (tem != 0)
-    return tem;
-
-#if 0
-  /* There's no need to do this now that combine.c can eliminate lots of
-     sign extensions.  This can be less efficient in certain cases on other
-     machines.  */
-
-  /* If this is a signed equality comparison, we can do it as an
-     unsigned comparison since zero-extension is cheaper than sign
-     extension and comparisons with zero are done as unsigned.  This is
-     the case even on machines that can do fast sign extension, since
-     zero-extension is easier to combine with other operations than
-     sign-extension is.  If we are comparing against a constant, we must
-     convert it to what it would look like unsigned.  */
-  if ((code == EQ || code == NE) && ! unsignedp
-      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
+  code = unsignedp ? unsigned_condition (code) : code;
+  if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
+                                                op0, op1)))
     {
-      if (GET_CODE (op1) == CONST_INT
-          && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
-        op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
-      unsignedp = 1;
+      if (CONSTANT_P (tem))
+       return tem;
+
+      code = GET_CODE (tem);
+      mode = GET_MODE (tem);
+      op0 = XEXP (tem, 0);
+      op1 = XEXP (tem, 1);
+      unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
     }
-#endif
 
   emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
 
@@ -889,7 +875,6 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
                         enum machine_mode mode, rtx size, rtx if_false_label,
                         rtx if_true_label)
 {
-  enum rtx_code ucode;
   rtx tem;
   int dummy_true_label = 0;
 
@@ -921,44 +906,25 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 
   do_pending_stack_adjust ();
 
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
-  if (tem != 0)
+  code = unsignedp ? unsigned_condition (code) : code;
+  if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
+                                                op0, op1)))
     {
-      if (tem == const_true_rtx)
-        {
-          if (if_true_label)
-            emit_jump (if_true_label);
-        }
-      else
-        {
-          if (if_false_label)
-            emit_jump (if_false_label);
-        }
-      return;
-    }
+      if (CONSTANT_P (tem))
+       {
+         rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode))
+                     ? if_false_label : if_true_label;
+         if (label)
+           emit_jump (label);
+         return;
+       }
 
-#if 0
-  /* There's no need to do this now that combine.c can eliminate lots of
-     sign extensions.  This can be less efficient in certain cases on other
-     machines.  */
-
-  /* If this is a signed equality comparison, we can do it as an
-     unsigned comparison since zero-extension is cheaper than sign
-     extension and comparisons with zero are done as unsigned.  This is
-     the case even on machines that can do fast sign extension, since
-     zero-extension is easier to combine with other operations than
-     sign-extension is.  If we are comparing against a constant, we must
-     convert it to what it would look like unsigned.  */
-  if ((code == EQ || code == NE) && ! unsignedp
-      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
-    {
-      if (GET_CODE (op1) == CONST_INT
-          && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
-        op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
-      unsignedp = 1;
+      code = GET_CODE (tem);
+      mode = GET_MODE (tem);
+      op0 = XEXP (tem, 0);
+      op1 = XEXP (tem, 1);
+      unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
     }
-#endif
 
   if (! if_true_label)
     {
index 567cd93..3a58f2c 100644 (file)
@@ -2738,6 +2738,7 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly)
 
          if (op_mode == VOIDmode)
            op_mode = GET_MODE (XEXP (x, 1));
+
          new = simplify_relational_operation (code, GET_MODE (x), op_mode,
                                               XEXP (x, 0), XEXP (x, 1));
          break;
@@ -2766,15 +2767,18 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly)
              {
                /* We have compare of two VOIDmode constants for which
                   we recorded the comparison mode.  */
-               rtx temp =
-                 simplify_const_relational_operation (GET_CODE (op0),
-                                                      map->compare_mode,
-                                                      XEXP (op0, 0),
-                                                      XEXP (op0, 1));
-
-               if (temp == const0_rtx)
+               rtx tem =
+                 simplify_gen_relational (GET_CODE (op0), GET_MODE (op0),
+                                          map->compare_mode, XEXP (op0, 0),
+                                          XEXP (op0, 1));
+
+               if (GET_CODE (tem) != CONST_INT)
+                 new = simplify_ternary_operation (code, GET_MODE (x),
+                                                   op0_mode, tem, XEXP (x, 1),
+                                                   XEXP (x, 2));
+               else if (tem == const0_rtx)
                  new = XEXP (x, 2);
-               else if (temp == const1_rtx)
+               else
                  new = XEXP (x, 1);
              }
          }
index b6340e5..5895bb9 100644 (file)
@@ -58,6 +58,8 @@ static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode,
                                  unsigned int);
 static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
                                           rtx, rtx);
+static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
+                                           enum machine_mode, rtx, rtx);
 \f
 /* Negate a CONST_INT rtx, truncating (because a conversion from a
    maximally negative number can overflow).  */
@@ -221,10 +223,9 @@ simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
 
   return gen_rtx_fmt_eee (code, mode, op0, op1, op2);
 }
-\f
+
 /* Likewise, for relational operations.
-   CMP_MODE specifies mode comparison is done in.
-  */
+   CMP_MODE specifies mode comparison is done in.  */
 
 rtx
 simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
@@ -232,46 +233,9 @@ simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
 {
   rtx tem;
 
-  if (cmp_mode == VOIDmode)
-    cmp_mode = GET_MODE (op0);
-  if (cmp_mode == VOIDmode)
-    cmp_mode = GET_MODE (op1);
-
-  if (cmp_mode != VOIDmode)
-    {
-      tem = simplify_relational_operation (code, mode, cmp_mode, op0, op1);
-      if (tem)
-       return tem;
-    }
-
-  /* For the following tests, ensure const0_rtx is op1.  */
-  if (swap_commutative_operands_p (op0, op1)
-      || (op0 == const0_rtx && op1 != const0_rtx))
-    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
-
-  /* If op0 is a compare, extract the comparison arguments from it.  */
-  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
-    return simplify_gen_relational (code, mode, VOIDmode,
-                                   XEXP (op0, 0), XEXP (op0, 1));
-
-  /* If op0 is a comparison, extract the comparison arguments form it.  */
-  if (COMPARISON_P (op0) && op1 == const0_rtx)
-    {
-      if (code == NE)
-       {
-         if (GET_MODE (op0) == mode)
-           return op0;
-         return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
-                                         XEXP (op0, 0), XEXP (op0, 1));
-       }
-      else if (code == EQ)
-       {
-         enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
-         if (new != UNKNOWN)
-           return simplify_gen_relational (new, mode, VOIDmode,
-                                           XEXP (op0, 0), XEXP (op0, 1));
-        }
-    }
+  if (0 != (tem = simplify_relational_operation (code, mode, cmp_mode,
+                                                op0, op1)))
+    return tem;
 
   return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
@@ -1201,7 +1165,6 @@ simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
 
    Don't use this for relational operations such as EQ or LT.
    Use simplify_relational_operation instead.  */
-
 rtx
 simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
                           rtx op0, rtx op1)
@@ -2662,10 +2625,102 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
 }
 
 /* Like simplify_binary_operation except used for relational operators.
-   MODE is the mode of the operands, not that of the result.  If MODE
-   is VOIDmode, both operands must also be VOIDmode and we compare the
-   operands in "infinite precision".
+   MODE is the mode of the result. If MODE is VOIDmode, both operands must
+   also be VOIDmode.
+
+   CMP_MODE specifies in which mode the comparison is done in, so it is
+   the mode of the operands.  If CMP_MODE is VOIDmode, it is taken from
+   the operands or, if both are VOIDmode, the operands are compared in
+   "infinite precision".  */
+rtx
+simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
+                              enum machine_mode cmp_mode, rtx op0, rtx op1)
+{
+  rtx tem, trueop0, trueop1;
+
+  if (cmp_mode == VOIDmode)
+    cmp_mode = GET_MODE (op0);
+  if (cmp_mode == VOIDmode)
+    cmp_mode = GET_MODE (op1);
+
+  tem = simplify_const_relational_operation (code, cmp_mode, op0, op1);
+  if (tem)
+    {
+#ifdef FLOAT_STORE_FLAG_VALUE
+      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+       {
+          if (tem == const0_rtx)
+            return CONST0_RTX (mode);
+          else if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+           {
+             REAL_VALUE_TYPE val;
+             val = FLOAT_STORE_FLAG_VALUE (mode);
+             return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
+           }
+       }
+#endif
+
+      return tem;
+    }
+
+  /* For the following tests, ensure const0_rtx is op1.  */
+  if (swap_commutative_operands_p (op0, op1)
+      || (op0 == const0_rtx && op1 != const0_rtx))
+    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
+
+  /* If op0 is a compare, extract the comparison arguments from it.  */
+  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
+    return simplify_relational_operation (code, mode, VOIDmode,
+                                         XEXP (op0, 0), XEXP (op0, 1));
+
+  if (mode == VOIDmode
+      || GET_MODE_CLASS (cmp_mode) == MODE_CC
+      || CC0_P (op0))
+    return NULL_RTX;
+
+  trueop0 = avoid_constant_pool_reference (op0);
+  trueop1 = avoid_constant_pool_reference (op1);
+  return simplify_relational_operation_1 (code, mode, cmp_mode,
+                                         trueop0, trueop1);
+}
+
+/* This part of simplify_relational_operation is only used when CMP_MODE
+   is not in class MODE_CC (i.e. it is a real comparison).
+
+   MODE is the mode of the result, while CMP_MODE specifies in which
+   mode the comparison is done in, so it is the mode of the operands.  */
+rtx
+simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
+                                enum machine_mode cmp_mode, rtx op0, rtx op1)
+{
+  if (GET_CODE (op1) == CONST_INT)
+    {
+      if (INTVAL (op1) == 0 && COMPARISON_P (op0))
+       {
+         /* If op0 is a comparison, extract the comparison arguments form it.  */
+         if (code == NE)
+           {
+             if (GET_MODE (op0) == cmp_mode)
+               return simplify_rtx (op0);
+             else
+               return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
+                                               XEXP (op0, 0), XEXP (op0, 1));
+           }
+         else if (code == EQ)
+           {
+             enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
+             if (new != UNKNOWN)
+               return simplify_gen_relational (new, mode, VOIDmode,
+                                               XEXP (op0, 0), XEXP (op0, 1));
+           }
+       }
+    }
 
+  return NULL_RTX;
+}
+
+/* Check if the given comparison (done in the given MODE) is actually a
+   tautology or a contradiction.
    If no simplification is possible, this function returns zero.
    Otherwise, it returns either const_true_rtx or const0_rtx.  */
 
@@ -2954,36 +3009,6 @@ simplify_const_relational_operation (enum rtx_code code,
       abort ();
     }
 }
-
-/* Like simplify_binary_operation except used for relational operators.
-   MODE is the mode of the result, and CMP_MODE is the mode of the operands.
-   If CMP_MODE is VOIDmode, both operands must also be VOIDmode and we
-   compare the operands in "infinite precision".  */
-
-rtx
-simplify_relational_operation (enum rtx_code code,
-                              enum machine_mode mode ATTRIBUTE_UNUSED,
-                              enum machine_mode cmp_mode, rtx op0, rtx op1)
-{
-  rtx tmp;
-
-  tmp = simplify_const_relational_operation (code, cmp_mode, op0, op1);
-  if (tmp)
-    {
-#ifdef FLOAT_STORE_FLAG_VALUE
-      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
-       {
-         if (tmp == const0_rtx)
-           return CONST0_RTX (mode);
-         return CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE (mode),
-                                              mode);
-       }
-#endif
-      return tmp;
-    }
-
-  return NULL_RTX;
-}
 \f
 /* Simplify CODE, an operation with result mode MODE and three operands,
    OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
@@ -3078,20 +3103,6 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
                                        ? GET_MODE (XEXP (op0, 1))
                                        : GET_MODE (XEXP (op0, 0)));
          rtx temp;
-         if (cmp_mode == VOIDmode)
-           cmp_mode = op0_mode;
-         temp = simplify_const_relational_operation (GET_CODE (op0),
-                                                     cmp_mode,
-                                                     XEXP (op0, 0),
-                                                     XEXP (op0, 1));
-
-         /* See if any simplifications were possible.  */
-         if (temp == const0_rtx)
-           return op2;
-         else if (temp == const_true_rtx)
-           return op1;
-         else if (temp)
-           abort ();
 
          /* Look for happy constants in op1 and op2.  */
          if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
@@ -3112,7 +3123,23 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
              else
                break;
 
-             return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1));
+             return simplify_gen_relational (code, op0_mode, cmp_mode,
+                                             XEXP (op0, 0), XEXP (op0, 1));
+           }
+
+         if (cmp_mode == VOIDmode)
+           cmp_mode = op0_mode;
+         temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
+                                               cmp_mode, XEXP (op0, 0),
+                                               XEXP (op0, 1));
+
+         /* See if any simplifications were possible.  */
+         if (temp)
+           {
+             if (GET_CODE (temp) == CONST_INT)
+               return temp == const0_rtx ? op2 : op1;
+             else if (temp)
+               return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2);
            }
        }
       break;
@@ -3721,7 +3748,6 @@ simplify_rtx (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
-  rtx temp;
 
   switch (GET_RTX_CLASS (code))
     {
@@ -3745,13 +3771,13 @@ simplify_rtx (rtx x)
 
     case RTX_COMPARE:
     case RTX_COMM_COMPARE:
-      temp = simplify_relational_operation (code, mode,
-                                           ((GET_MODE (XEXP (x, 0))
-                                             != VOIDmode)
-                                            ? GET_MODE (XEXP (x, 0))
-                                            : GET_MODE (XEXP (x, 1))),
-                                           XEXP (x, 0), XEXP (x, 1));
-      return temp;
+      return simplify_relational_operation (code, mode,
+                                            ((GET_MODE (XEXP (x, 0))
+                                             != VOIDmode)
+                                            ? GET_MODE (XEXP (x, 0))
+                                            : GET_MODE (XEXP (x, 1))),
+                                            XEXP (x, 0),
+                                            XEXP (x, 1));
 
     case RTX_EXTRA:
       if (code == SUBREG)