OSDN Git Service

(try_combine): When removing REG_UNUSED note, update reg_n_deaths.
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 19 Sep 1992 19:53:26 +0000 (19:53 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 19 Sep 1992 19:53:26 +0000 (19:53 +0000)
Likewise, when making new REG_DEAD notes for distribute_notes.
(remove_death, move_deaths): Update reg_n_deaths.
(distribute_notes): When placing second REG_DEAD or REG_UNUSED note or
ignoring such a note, update reg_n_deaths.

(simplify_comparison, case ASHIFT): Fix typo.

(try_combine): The insns made by a DEFINE_SPLIT might contain a PARALLEL and
the call to recog_for_combine might add it.

(combine_instructions): Clear significant_valid at end of combine pass for
a function.
(find_split_point, case MEM): See if first operand of the PLUS that makes
up an address is complex.
(subst): Add missing arg to recursive calls when IF_THEN_ELSE is an arg
of an operator.
(subst, case IF_THEN_ELSE): Generalize code to propagate comparison result
into arms by using known_cond.
If an arm is the first operand of the comparison, make it the true arm.
Remove unneeded comparison when arms are identical.
Try to convert IF_THEN_ELSE to ABS, (neg (abs X)), [US]MIN, [US]MAX.
Convert (if_then_else (ne A 0) (OP X C) X) to (OP X (mult A C)).
(subst, case SET): If we don't have conditional moves, convert IF_THEN_ELSE
into logical operations.
(subst, case AND): Always make conditional moves, even if we don't support
them on the machine.
(known_cond, extended_count): New functions.
(gen_binary): For commutative operations, put constant last.

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

gcc/combine.c

index 8e8dd70..e082a12 100644 (file)
@@ -261,9 +261,9 @@ static enum machine_mode significant_mode;
 static char *reg_sign_bit_copies;
 
 /* Nonzero when reg_significant and reg_sign_bit_copies can be safely used.
-   It is zero while computing them.  This prevents propagating values based
-   on previously set values, which can be incorrect if a variable
-   is modified in a loop.  */
+   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 significant_valid;
 \f
@@ -355,6 +355,7 @@ static rtx expand_field_assignment ();
 static rtx make_extraction ();
 static int get_pos_from_mask ();
 static rtx force_to_mode ();
+static rtx known_cond ();
 static rtx make_field_assignment ();
 static rtx make_compound_operation ();
 static rtx apply_distributive_law ();
@@ -552,6 +553,8 @@ combine_instructions (f, nregs)
   total_merges += combine_merges;
   total_extras += combine_extras;
   total_successes += combine_successes;
+
+  significant_valid = 0;
 }
 \f
 /* Called via note_stores.  If X is a pseudo that is used in more than
@@ -1555,9 +1558,13 @@ try_combine (i3, i2, i1)
              || ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)),
                                      INSN_CUID (i2))))
        {
+         rtx i2set, i3set;
          rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1));
          newi2pat = PATTERN (XVECEXP (m_split, 0, 0));
 
+         i2set = single_set (newi2pat);
+         i3set = single_set (newi3pat);
+
          /* In case we changed the mode of I2DEST, replace it in the
             pseudo-register table here.  We can't do it above in case this
             code doesn't get executed and we do a split the other way.  */
@@ -1566,7 +1573,11 @@ try_combine (i3, i2, i1)
            SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
 
          i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
-         if (i2_code_number >= 0)
+
+         /* If I2 or I3 has multiple SETs, we won't know how to track
+            register status, so don't use these insns.  */
+
+         if (i2_code_number >= 0 && i2set && i3set)
            insn_code_number = recog_for_combine (&newi3pat, i3,
                                                  &new_i3_notes);
 
@@ -1577,13 +1588,13 @@ try_combine (i3, i2, i1)
             If so, we must show an extra use of it and update
             reg_significant.  */
 
-         if (insn_code_number >= 0 && GET_CODE (SET_DEST (newpat)) == REG
-             && GET_CODE (SET_DEST (newi2pat)) == REG
-             && REGNO (SET_DEST (newpat)) == REGNO (SET_DEST (newi2pat)))
+         if (insn_code_number >= 0 && GET_CODE (SET_DEST (i3set)) == REG
+             && GET_CODE (SET_DEST (i2set)) == REG
+             && REGNO (SET_DEST (i3set)) == REGNO (SET_DEST (i2set)))
            {
-             reg_n_sets[REGNO (SET_DEST (newpat))]++;
-             set_significant (SET_DEST (newi2pat), newi2pat);
-             set_significant (SET_DEST (newpat), newpat);
+             reg_n_sets[REGNO (SET_DEST (i2set))]++;
+             set_significant (SET_DEST (i2set), i2set);
+             set_significant (SET_DEST (i3set), i3set);
            }
        }
 
@@ -1794,9 +1805,18 @@ try_combine (i3, i2, i1)
 
          if (REG_NOTE_KIND (note) == REG_UNUSED
              && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
-           remove_note (undobuf.other_insn, note);
+           {
+             if (GET_CODE (XEXP (note, 0)) == REG)
+               reg_n_deaths[REGNO (XEXP (note, 0))]--;
+
+             remove_note (undobuf.other_insn, note);
+           }
        }
 
+      for (note = new_other_notes; note; note = XEXP (note, 1))
+       if (GET_CODE (XEXP (note, 0)) == REG)
+         reg_n_deaths[REGNO (XEXP (note, 0))]++;
+
       distribute_notes (new_other_notes, undobuf.other_insn,
                        undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
     }
@@ -1924,19 +1944,42 @@ try_combine (i3, i2, i1)
 
     /* Distribute any notes added to I2 or I3 by recog_for_combine.  We
        know these are REG_UNUSED and want them to go to the desired insn,
-       so we always pass it as i3.  */
+       so we always pass it as i3.  We have not counted the notes in 
+       reg_n_deaths yet, so we need to do so now.  */
+
     if (newi2pat && new_i2_notes)
-      distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+      {
+       for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
+         if (GET_CODE (XEXP (temp, 0)) == REG)
+           reg_n_deaths[REGNO (XEXP (temp, 0))]++;
+       
+       distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+      }
+
     if (new_i3_notes)
-      distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
+      {
+       for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
+         if (GET_CODE (XEXP (temp, 0)) == REG)
+           reg_n_deaths[REGNO (XEXP (temp, 0))]++;
+       
+       distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
+      }
 
     /* If I3DEST was used in I3SRC, it really died in I3.  We may need to
-       put a REG_DEAD note for it somewhere.  Similarly for I2 and I1.  */
+       put a REG_DEAD note for it somewhere.  Similarly for I2 and I1.
+       Show an additional death due to the REG_DEAD note we make here.  If
+       we discard it in distribute_notes, we will decrement it again.  */
 
     if (i3dest_killed)
-      distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i3dest_killed, NULL_RTX),
-                       NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
-                       NULL_RTX, NULL_RTX);
+      {
+       if (GET_CODE (i3dest_killed) == REG)
+         reg_n_deaths[REGNO (i3dest_killed)]++;
+
+       distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i3dest_killed,
+                                  NULL_RTX),
+                         NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+                         NULL_RTX, NULL_RTX);
+      }
 
     /* For I2 and I1, we have to be careful.  If NEWI2PAT exists and sets
        I2DEST or I1DEST, the death must be somewhere before I2, not I3.  If
@@ -1944,6 +1987,9 @@ try_combine (i3, i2, i1)
 
     if (i2dest_in_i2src)
       {
+       if (GET_CODE (i2dest) == REG)
+         reg_n_deaths[REGNO (i2dest)]++;
+
        if (newi2pat && reg_set_p (i2dest, newi2pat))
          distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX),
                            NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
@@ -1955,6 +2001,9 @@ try_combine (i3, i2, i1)
 
     if (i1dest_in_i1src)
       {
+       if (GET_CODE (i1dest) == REG)
+         reg_n_deaths[REGNO (i1dest)]++;
+
        if (newi2pat && reg_set_p (i1dest, newi2pat))
          distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX),
                            NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
@@ -2156,6 +2205,17 @@ find_split_point (loc, insn)
                  return split;
                }
            }
+         
+         /* If that didn't work, perhaps the first operand is complex and
+            needs to be computed separately, so make a split point there.
+            This will occur on machines that just support REG + CONST
+            and have a constant moved through some previous computation.  */
+
+         else if (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) != 'o'
+                  && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+                        && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (XEXP (x, 0), 0))))
+                            == 'o')))
+           return &XEXP (XEXP (x, 0), 0);
        }
       break;
 
@@ -2622,10 +2682,10 @@ subst (x, from, to, in_dest, unique_copy)
       rtx cond = XEXP (XEXP (x, 0), 0);
       rtx t_arm = subst (gen_binary (code, mode, XEXP (XEXP (x, 0), 1),
                                     XEXP (x, 1)),
-                        pc_rtx, pc_rtx, 0);
+                        pc_rtx, pc_rtx, 0, 0);
       rtx f_arm = subst (gen_binary (code, mode, XEXP (XEXP (x, 0), 2),
                                     XEXP (x, 1)),
-                        pc_rtx, pc_rtx, 0);
+                        pc_rtx, pc_rtx, 0, 0);
 
 
       x = gen_rtx (IF_THEN_ELSE, mode, cond, t_arm, f_arm);
@@ -2638,9 +2698,9 @@ subst (x, from, to, in_dest, unique_copy)
     {
       rtx cond = XEXP (XEXP (x, 0), 0);
       rtx t_arm = subst (gen_unary (code, mode, XEXP (XEXP (x, 0), 1)),
-                        pc_rtx, pc_rtx, 0);
+                        pc_rtx, pc_rtx, 0, 0);
       rtx f_arm = subst (gen_unary (code, mode, XEXP (XEXP (x, 0), 2)),
-                        pc_rtx, pc_rtx, 0);
+                        pc_rtx, pc_rtx, 0, 0);
 
       x = gen_rtx_combine (IF_THEN_ELSE, mode, cond, t_arm, f_arm);
       goto restart;
@@ -3306,56 +3366,73 @@ subst (x, from, to, in_dest, unique_copy)
       break;
          
     case IF_THEN_ELSE:
-      /* If we are testing a register for equality see if that register is
-        used in one of the arms.  If so, and we know something about its
-        value in that arm, try to simplify it.  */
+      /* Sometimes we can simplify the arm of an IF_THEN_ELSE if a register
+        used in it is being compared against certain values.  Get the
+        true and false comparisons and see if that says anything about the
+        value of each arm.  */
 
-      if ((GET_CODE (XEXP (x, 0)) == EQ || GET_CODE (XEXP (x, 0)) == NE)
+      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && reversible_comparison_p (XEXP (x, 0))
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG)
        {
-         /* Get the value being compared and the value it has on the equal
-            branch.  */
          HOST_WIDE_INT sig;
          rtx from = XEXP (XEXP (x, 0), 0);
-         rtx val_if_eq = XEXP (XEXP (x, 0), 1);
-         rtx val_if_ne = from;
-         int is_eq = (GET_CODE (XEXP (x, 0)) == EQ);
+         enum rtx_code true_code = GET_CODE (XEXP (x, 0));
+         enum rtx_code false_code = reverse_condition (true_code);
+         rtx true_val = XEXP (XEXP (x, 0), 1);
+         rtx false_val = true_val;
+         rtx true_arm = XEXP (x, 1);
+         rtx false_arm = XEXP (x, 2);
+         int swapped = 0;
+
+         /* If FALSE_CODE is EQ, swap the codes and arms.  */
+
+         if (false_code == EQ)
+           {
+             swapped = 1, true_code = EQ, false_code = NE;
+             true_arm = XEXP (x, 2), false_arm = XEXP (x, 1);
+           }
 
-         /* If we are comparing against zero and the expressiond being tested
-            has only a single significant bit, that is it's value when it is 
-            not equal to zero.  Simplilarly if it is known to be -1 or 0.  */
+         /* If we are comparing against zero and the expression being tested
+            has only a single significant bit, that is its value when it is 
+            not equal to zero.  Similarly if it is known to be -1 or 0.  */
 
-         if (val_if_eq == const0_rtx
+         if (true_code == EQ && true_val == const0_rtx
              && exact_log2 (sig = significant_bits (from,
                                                     GET_MODE (from))) >= 0)
-           val_if_ne = GEN_INT (sig);
-         else if (val_if_eq == const0_rtx
+           false_code = EQ, false_val = GEN_INT (sig);
+         else if (true_code == EQ && true_val == const0_rtx
                   && (num_sign_bit_copies (from, GET_MODE (from))
                       == GET_MODE_BITSIZE (GET_MODE (from))))
-           val_if_ne = constm1_rtx;
+           false_code = EQ, false_val = constm1_rtx;
 
          /* Now simplify an arm if we know the value of the register
             in the branch and it is used in the arm.  Be carefull due to
             the potential of locally-shared RTL.  */
 
-         if ((is_eq || val_if_ne != from)
-             && reg_mentioned_p (from, XEXP (x, 1)))
-           SUBST (XEXP (x, 1), subst (copy_rtx (XEXP (x, 1)), from,
-                                      is_eq ? val_if_eq : val_if_ne, 0));
-
-         if ((! is_eq || val_if_ne != from)
-             && reg_mentioned_p (from, XEXP (x, 2)))
-           SUBST (XEXP (x, 2), subst (XEXP (x, 2), from,
-                                      is_eq ? val_if_ne : val_if_eq, 0));
+         if (reg_mentioned_p (from, true_arm))
+           true_arm = subst (known_cond (copy_rtx (true_arm), true_code,
+                                         from, true_val),
+                             pc_rtx, pc_rtx, 0, 0);
+         if (reg_mentioned_p (from, false_arm))
+           false_arm = subst (known_cond (copy_rtx (false_arm), false_code,
+                                          from, false_val),
+                              pc_rtx, pc_rtx, 0, 0);
+
+         SUBST (XEXP (x, 1), swapped ? false_arm : true_arm);
+         SUBST (XEXP (x, 2), swapped ? true_arm : false_arm);
        }
       
       /* If we have (if_then_else FOO (pc) (label_ref BAR)) and FOO can be
         reversed, do so to avoid needing two sets of patterns for
         subtract-and-branch insns.  Similarly if we have a constant in that
-        position.  */
-      if ((XEXP (x, 1) == pc_rtx || GET_CODE (XEXP (x, 1)) == CONST_INT)
-         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && reversible_comparison_p (XEXP (x, 0)))
+        position or if the third operand is the same as the first operand
+        of the comparison.  */
+
+      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && reversible_comparison_p (XEXP (x, 0))
+         && (XEXP (x, 1) == pc_rtx || GET_CODE (XEXP (x, 1)) == CONST_INT
+             || rtx_equal_p (XEXP (x, 2), XEXP (XEXP (x, 0), 0))))
        {
          SUBST (XEXP (x, 0),
                 gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
@@ -3366,6 +3443,147 @@ subst (x, from, to, in_dest, unique_copy)
          SUBST (XEXP (x, 1), XEXP (x, 2));
          SUBST (XEXP (x, 2), temp);
        }
+
+      /* If the two arms are identical, we don't need the comparison.  */
+
+      if (rtx_equal_p (XEXP (x, 1), XEXP (x, 2))
+         && ! side_effects_p (XEXP (x, 0)))
+       return XEXP (x, 1);
+
+      /* Look for cases where we have (abs x) or (neg (abs X)).  */
+
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && GET_CODE (XEXP (x, 2)) == NEG
+         && rtx_equal_p (XEXP (x, 1), XEXP (XEXP (x, 2), 0))
+         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && rtx_equal_p (XEXP (x, 1), XEXP (XEXP (x, 0), 0))
+         && ! side_effects_p (XEXP (x, 1)))
+       switch (GET_CODE (XEXP (x, 0)))
+         {
+         case GT:
+         case GE:
+           x = gen_unary (ABS, mode, XEXP (x, 1));
+           goto restart;
+         case LT:
+         case LE:
+           x = gen_unary (NEG, mode, gen_unary (ABS, mode, XEXP (x, 1)));
+           goto restart;
+         }
+
+      /* Look for MIN or MAX.  */
+
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
+         && rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 2))
+         && ! side_effects_p (XEXP (x, 0)))
+       switch (GET_CODE (XEXP (x, 0)))
+         {
+         case GE:
+         case GT:
+           x = gen_binary (SMAX, mode, XEXP (x, 1), XEXP (x, 2));
+           goto restart;
+         case LE:
+         case LT:
+           x = gen_binary (SMIN, mode, XEXP (x, 1), XEXP (x, 2));
+           goto restart;
+         case GEU:
+         case GTU:
+           x = gen_binary (UMAX, mode, XEXP (x, 1), XEXP (x, 2));
+           goto restart;
+         case LEU:
+         case LTU:
+           x = gen_binary (UMIN, mode, XEXP (x, 1), XEXP (x, 2));
+           goto restart;
+         }
+
+      /* If we have something like (if_then_else (ne A 0) (OP X C) X),
+        A is known to be either 0 or 1, and OP is an identity when its
+        second operand is zero, this can be done as (OP X (mult A C)).
+        Similarly if A is known to be 0 or -1 and also similarly if we have
+        a ZERO_EXTEND or SIGN_EXTEND as long as X is already extended (so
+        we don't destroy it).  */
+
+      if (mode != VOIDmode
+         && (GET_CODE (XEXP (x, 0)) == EQ || GET_CODE (XEXP (x, 0)) == NE)
+         && XEXP (XEXP (x, 0), 1) == const0_rtx
+         && (significant_bits (XEXP (XEXP (x, 0), 0), mode) == 1
+             || (num_sign_bit_copies (XEXP (XEXP (x, 0), 0), mode)
+                 == GET_MODE_BITSIZE (mode))))
+       {
+         rtx nz = make_compound_operation (GET_CODE (XEXP (x, 0)) == NE
+                                           ? XEXP (x, 1) : XEXP (x, 2));
+         rtx z = GET_CODE (XEXP (x, 0)) == NE ? XEXP (x, 2) : XEXP (x, 1);
+         rtx dir = (significant_bits (XEXP (XEXP (x, 0), 0), mode) == 1
+                    ? const1_rtx : constm1_rtx);
+         rtx c = 0;
+         enum machine_mode m = mode;
+         enum rtx_code op, extend_op = NULL;
+
+         if ((GET_CODE (nz) == PLUS || GET_CODE (nz) == MINUS
+              || GET_CODE (nz) == IOR || GET_CODE (nz) == XOR
+              || GET_CODE (nz) == ASHIFT
+              || GET_CODE (nz) == LSHIFTRT || GET_CODE (nz) == ASHIFTRT)
+             && rtx_equal_p (XEXP (nz, 0), z))
+           c = XEXP (nz, 1), op = GET_CODE (nz);
+         else if (GET_CODE (nz) == SIGN_EXTEND
+                  && (GET_CODE (XEXP (nz, 0)) == PLUS
+                      || GET_CODE (XEXP (nz, 0)) == MINUS
+                      || GET_CODE (XEXP (nz, 0)) == IOR
+                      || GET_CODE (XEXP (nz, 0)) == XOR
+                      || GET_CODE (XEXP (nz, 0)) == ASHIFT
+                      || GET_CODE (XEXP (nz, 0)) == LSHIFTRT
+                      || GET_CODE (XEXP (nz, 0)) == ASHIFTRT)
+                  && GET_CODE (XEXP (XEXP (nz, 0), 0)) == SUBREG
+                  && subreg_lowpart_p (XEXP (XEXP (nz, 0), 0))
+                  && rtx_equal_p (SUBREG_REG (XEXP (XEXP (nz, 0), 0)), z)
+                  && (num_sign_bit_copies (z, GET_MODE (z))
+                      >= (GET_MODE_BITSIZE (mode)
+                          - GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (nz, 0), 0))))))
+           {
+             c = XEXP (XEXP (nz, 0), 1);
+             op = GET_CODE (XEXP (nz, 0));
+             extend_op = SIGN_EXTEND;
+             m = GET_MODE (XEXP (nz, 0));
+           }
+         else if (GET_CODE (nz) == ZERO_EXTEND
+                  && (GET_CODE (XEXP (nz, 0)) == PLUS
+                      || GET_CODE (XEXP (nz, 0)) == MINUS
+                      || GET_CODE (XEXP (nz, 0)) == IOR
+                      || GET_CODE (XEXP (nz, 0)) == XOR
+                      || GET_CODE (XEXP (nz, 0)) == ASHIFT
+                      || GET_CODE (XEXP (nz, 0)) == LSHIFTRT
+                      || GET_CODE (XEXP (nz, 0)) == ASHIFTRT)
+                  && GET_CODE (XEXP (XEXP (nz, 0), 0)) == SUBREG
+                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+                  && subreg_lowpart_p (XEXP (XEXP (nz, 0), 0))
+                  && rtx_equal_p (SUBREG_REG (XEXP (XEXP (nz, 0), 0)), z)
+                  && ((significant_bits (z, GET_MODE (z))
+                       & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (nz, 0), 0))))
+                      == 0))
+           {
+             c = XEXP (XEXP (nz, 0), 1);
+             op = GET_CODE (XEXP (nz, 0));
+             extend_op = ZERO_EXTEND;
+             m = GET_MODE (XEXP (nz, 0));
+           }
+
+         if (c && ! side_effects_p (c) && ! side_effects_p (z))
+           {
+             temp
+               = gen_binary (MULT, m,
+                             gen_lowpart_for_combine (m,
+                                                      XEXP (XEXP (x, 0), 0)),
+                             gen_binary (MULT, m, c, dir));
+
+             temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp);
+
+             if (extend_op != NULL)
+               temp = gen_unary (extend_op, mode, temp);
+
+             return temp;
+           }
+       }
       break;
          
     case ZERO_EXTRACT:
@@ -3571,6 +3789,56 @@ subst (x, from, to, in_dest, unique_copy)
                                             XEXP (SET_SRC (x), 0)));
 #endif
 
+#ifndef HAVE_conditional_move
+
+      /* If we don't have a conditional move, SET_SRC is an IF_THEN_ELSE,
+        and we are comparing an item known to be 0 or -1 against 0, use a
+        logical operation instead. Check for one of the arms being an IOR
+        of the other arm with some value.  We compute three terms to be
+        IOR'ed together.  In practice, at most two will be nonzero.  Then
+        we do the IOR's.  */
+
+      if (GET_CODE (SET_SRC (x)) == IF_THEN_ELSE
+         && (GET_CODE (XEXP (SET_SRC (x), 0)) == EQ
+             || GET_CODE (XEXP (SET_SRC (x), 0)) == NE)
+         && XEXP (XEXP (SET_SRC (x), 0), 1) == const0_rtx
+         && (num_sign_bit_copies (XEXP (XEXP (SET_SRC (x), 0), 0),
+                                  GET_MODE (XEXP (XEXP (SET_SRC (x), 0), 0)))
+             == GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (SET_SRC (x), 0), 0))))
+         && ! side_effects_p (SET_SRC (x)))
+       {
+         rtx true = (GET_CODE (XEXP (SET_SRC (x), 0)) == NE
+                     ? XEXP (SET_SRC (x), 1) : XEXP (SET_SRC (x), 2));
+         rtx false = (GET_CODE (XEXP (SET_SRC (x), 0)) == NE
+                      ? XEXP (SET_SRC (x), 2) : XEXP (SET_SRC (x), 1));
+         rtx term1 = const0_rtx, term2, term3;
+
+         if (GET_CODE (true) == IOR && rtx_equal_p (XEXP (true, 0), false))
+           term1 = false, true = XEXP (true, 1), false = const0_rtx;
+         else if (GET_CODE (true) == IOR
+                  && rtx_equal_p (XEXP (true, 1), false))
+           term1 = false, true = XEXP (true, 0), false = const0_rtx;
+         else if (GET_CODE (false) == IOR
+                  && rtx_equal_p (XEXP (false, 0), true))
+           term1 = true, false = XEXP (false, 1), true = const0_rtx;
+         else if (GET_CODE (false) == IOR
+                  && rtx_equal_p (XEXP (false, 1), true))
+           term1 = true, false = XEXP (false, 0), true = const0_rtx;
+
+         term2 = gen_binary (AND, GET_MODE (SET_SRC (x)),
+                             XEXP (XEXP (SET_SRC (x), 0), 0), true);
+         term3 = gen_binary (AND, GET_MODE (SET_SRC (x)),
+                             gen_unary (NOT, GET_MODE (SET_SRC (x)),
+                                        XEXP (XEXP (SET_SRC (x), 0), 0)),
+                             false);
+
+         SUBST (SET_SRC (x),
+                gen_binary (IOR, GET_MODE (SET_SRC (x)),
+                            gen_binary (IOR, GET_MODE (SET_SRC (x)),
+                                        term1, term2),
+                            term3));
+       }
+#endif
       break;
 
     case AND:
@@ -3646,13 +3914,15 @@ subst (x, from, to, in_dest, unique_copy)
          goto restart;
        }
 
-#ifdef HAVE_conditional_move
-
       /* If we have (and A B) with A not an object but that is known to
         be -1 or 0, this is equivalent to the expression
         (if_then_else (ne A (const_int 0)) B (const_int 0))
         We make this conversion because it may allow further
-        simplifications and then allow use of conditional move insns.  */
+        simplifications and then allow use of conditional move insns.
+        If the machine doesn't have condition moves, code in case SET
+        will convert the IF_THEN_ELSE back to the logical operation.
+        We build the IF_THEN_ELSE here in case further simplification
+        is possible (e.g., we can convert it to ABS).  */
 
       if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
          && ! (GET_CODE (XEXP (x, 0)) == SUBREG
@@ -3670,7 +3940,6 @@ subst (x, from, to, in_dest, unique_copy)
                                XEXP (x, 1), const0_rtx);
          goto restart;
        }
-#endif
 
       /* In the following group of tests (and those in case IOR below),
         we start with some combination of logical operations and apply
@@ -4932,6 +5201,96 @@ force_to_mode (x, mode, bits, reg)
   return gen_lowpart_for_combine (mode, x);
 }
 \f
+/* Return the value of expression X given the fact that condition COND
+   is known to be true when applied to REG as its first operand and VAL
+   as its second.  X is known to not be shared and so can be modified in
+   place.
+
+   We only handle the simplest cases, and specifically those cases that
+   arise with IF_THEN_ELSE expressions.  */
+
+static rtx
+known_cond (x, cond, reg, val)
+     rtx x;
+     enum rtx_code cond;
+     rtx reg, val;
+{
+  enum rtx_code code = GET_CODE (x);
+  rtx new, temp;
+  char *fmt;
+  int i, j;
+
+  if (side_effects_p (x))
+    return x;
+
+  if (cond == EQ && rtx_equal_p (x, reg))
+    return val;
+
+  /* If X is (abs REG) and we know something about REG's relationship
+     with zero, we may be able to simplify this.  */
+
+  if (code == ABS && rtx_equal_p (XEXP (x, 0), reg) && val == const0_rtx)
+    switch (cond)
+      {
+      case GE:  case GT:  case EQ:
+       return XEXP (x, 0);
+      case LT:  case LE:
+       return gen_unary (NEG, GET_MODE (XEXP (x, 0)), XEXP (x, 0));
+      }
+
+  /* The only other cases we handle are MIN, MAX, and comparisons if the
+     operands are the same as REG and VAL.  */
+
+  else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
+    {
+      if (rtx_equal_p (XEXP (x, 0), val))
+       cond = swap_condition (cond), temp = val, val = reg, reg = temp;
+
+      if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
+       {
+         if (GET_RTX_CLASS (code) == '<')
+           return (comparison_dominates_p (cond, code) ? const_true_rtx
+                   : (comparison_dominates_p (cond,
+                                              reverse_condition (code))
+                      ? const0_rtx : x));
+
+         else if (code == SMAX || code == SMIN
+                  || code == UMIN || code == UMAX)
+           {
+             int unsignedp = (code == UMIN || code == UMAX);
+
+             if (code == SMAX || code == UMAX)
+               cond = reverse_condition (cond);
+
+             switch (cond)
+               {
+               case GE:   case GT:
+                 return unsignedp ? x : XEXP (x, 1);
+               case LE:   case LT:
+                 return unsignedp ? x : XEXP (x, 0);
+               case GEU:  case GTU:
+                 return unsignedp ? XEXP (x, 1) : x;
+               case LEU:  case LTU:
+                 return unsignedp ? XEXP (x, 0) : x;
+               }
+           }
+       }
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       SUBST (XEXP (x, i), known_cond (XEXP (x, i), cond, reg, val));
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         SUBST (XVECEXP (x, i, j), known_cond (XVECEXP (x, i, j),
+                                               cond, reg, val));
+    }
+
+  return x;
+}
+\f
 /* See if X, a SET operation, can be rewritten as a bit-field assignment.
    Return that assignment if so.
 
@@ -5984,6 +6343,32 @@ num_sign_bit_copies (x, mode)
   return sig == GET_MODE_MASK (mode) ? 1 : bitwidth - floor_log2 (sig) - 1;
 }
 \f
+/* Return the number of "extended" bits there are in X, when interpreted
+   as a quantity in MODE whose signedness is indicated by UNSIGNEDP.  For
+   unsigned quantities, this is the number of high-order zero bits.
+   For signed quantities, this is the number of copies of the sign bit
+   minus 1.  In both case, this function returns the number of "spare"
+   bits.  For example, if two quantities for which this function returns
+   at least 1 are added, the addition is known not to overflow.
+
+   This function will always return 0 unless called during combine, which
+   implies that it must be called from a define_split.  */
+
+int
+extended_count (x, mode, unsignedp)
+     rtx x;
+     enum machine_mode mode;
+     int unsignedp;
+{
+  if (significant_valid == 0)
+    return 0;
+
+  return (unsignedp
+         ? (GET_MODE_BITSIZE (mode) - 1
+            - floor_log2 (significant_bits (x, mode)))
+         : num_sign_bit_copies (x, mode) - 1);
+}
+\f
 /* This function is called from `simplify_shift_const' to merge two
    outer operations.  Specifically, we have already found that we need
    to perform operation *POP0 with constant *PCONST0 at the outermost
@@ -7047,6 +7432,12 @@ gen_binary (code, mode, op0, op1)
      rtx op0, op1;
 {
   rtx result;
+  rtx tem;
+
+  if (GET_RTX_CLASS (code) == 'c'
+      && (GET_CODE (op0) == CONST_INT
+         || (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)))
+    tem = op0, op0 = op1, op1 = tem;
 
   if (GET_RTX_CLASS (code) == '<') 
     {
@@ -7804,8 +8195,7 @@ simplify_comparison (code, pop0, pop1)
              && ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
                  < HOST_BITS_PER_WIDE_INT)
              && ((const_op
-                  &  ~ (((HOST_WIDE_INT) 1
-                         << INTVAL (XEXP (op0, 1))) - 1)) == 0)
+                  &  ((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1) == 0)
              && mode_width <= HOST_BITS_PER_WIDE_INT
              && (significant_bits (XEXP (op0, 0), mode)
                  & ~ (mask >> (INTVAL (XEXP (op0, 1))
@@ -8479,7 +8869,10 @@ remove_death (regno, insn)
   register rtx note = find_regno_note (insn, REG_DEAD, regno);
 
   if (note)
-    remove_note (insn, note);
+    {
+      reg_n_deaths[regno]--;
+      remove_note (insn, note);
+    }
 
   return note;
 }
@@ -8524,6 +8917,8 @@ move_deaths (x, from_cuid, to_insn, pnotes)
            }
          else
            *pnotes = gen_rtx (EXPR_LIST, REG_DEAD, x, *pnotes);
+
+         reg_n_deaths[regno]++;
        }
 
       return;
@@ -8960,10 +9355,21 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
          XEXP (note, 1) = REG_NOTES (place);
          REG_NOTES (place) = note;
        }
+      else if ((REG_NOTE_KIND (note) == REG_DEAD
+               || REG_NOTE_KIND (note) == REG_UNUSED)
+              && GET_CODE (XEXP (note, 0)) == REG)
+       reg_n_deaths[REGNO (XEXP (note, 0))]--;
 
       if (place2)
-       REG_NOTES (place2) = gen_rtx (GET_CODE (note), REG_NOTE_KIND (note),
-                                     XEXP (note, 0), REG_NOTES (place2));
+       {
+         if ((REG_NOTE_KIND (note) == REG_DEAD
+              || REG_NOTE_KIND (note) == REG_UNUSED)
+             && GET_CODE (XEXP (note, 0)) == REG)
+           reg_n_deaths[REGNO (XEXP (note, 0))]++;
+
+         REG_NOTES (place2) = gen_rtx (GET_CODE (note), REG_NOTE_KIND (note),
+                                       XEXP (note, 0), REG_NOTES (place2));
+       }
     }
 }
 \f