arm-builtins.c (enum arm_type_qualifiers): Add qualifier_lane_pair_index.
[gcc.git] / gcc / combine.c
index 3ad050fecf1a76bce932f32c91e52ad25c8480b6..e226c7dd353986a69c31d65b26bb89062f2dcb4c 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987-2018 Free Software Foundation, Inc.
+   Copyright (C) 1987-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 
 This file is part of GCC.
 
@@ -99,6 +99,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "explow.h"
 #include "insn-attr.h"
 #include "rtlhooks-def.h"
 #include "explow.h"
 #include "insn-attr.h"
 #include "rtlhooks-def.h"
+#include "expr.h"
 #include "params.h"
 #include "tree-pass.h"
 #include "valtrack.h"
 #include "params.h"
 #include "tree-pass.h"
 #include "valtrack.h"
@@ -529,7 +530,7 @@ target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
 }
 
 /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
 }
 
 /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
-   PATTERN can not be split.  Otherwise, it returns an insn sequence.
+   PATTERN cannot be split.  Otherwise, it returns an insn sequence.
    This is a wrapper around split_insns which ensures that the
    reg_stat vector is made larger if the splitter creates a new
    register.  */
    This is a wrapper around split_insns which ensures that the
    reg_stat vector is made larger if the splitter creates a new
    register.  */
@@ -570,6 +571,7 @@ find_single_use_1 (rtx dest, rtx *loc)
     case SYMBOL_REF:
     CASE_CONST_ANY:
     case CLOBBER:
     case SYMBOL_REF:
     CASE_CONST_ANY:
     case CLOBBER:
+    case CLOBBER_HIGH:
       return 0;
 
     case SET:
       return 0;
 
     case SET:
@@ -1696,9 +1698,13 @@ update_rsp_from_reg_equal (reg_stat_type *rsp, rtx_insn *insn, const_rtx set,
   /* Don't call nonzero_bits if it cannot change anything.  */
   if (rsp->nonzero_bits != HOST_WIDE_INT_M1U)
     {
   /* Don't call nonzero_bits if it cannot change anything.  */
   if (rsp->nonzero_bits != HOST_WIDE_INT_M1U)
     {
-      bits = nonzero_bits (src, nonzero_bits_mode);
+      machine_mode mode = GET_MODE (x);
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && HWI_COMPUTABLE_MODE_P (mode))
+       mode = nonzero_bits_mode;
+      bits = nonzero_bits (src, mode);
       if (reg_equal && bits)
       if (reg_equal && bits)
-       bits &= nonzero_bits (reg_equal, nonzero_bits_mode);
+       bits &= nonzero_bits (reg_equal, mode);
       rsp->nonzero_bits |= bits;
     }
 
       rsp->nonzero_bits |= bits;
     }
 
@@ -1752,6 +1758,9 @@ set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
          return;
        }
 
          return;
        }
 
+      /* Should not happen as we only using pseduo registers.  */
+      gcc_assert (GET_CODE (set) != CLOBBER_HIGH);
+
       /* If this register is being initialized using itself, and the
         register is uninitialized in this basic block, and there are
         no LOG_LINKS which set the register, then part of the
       /* If this register is being initialized using itself, and the
         register is uninitialized in this basic block, and there are
         no LOG_LINKS which set the register, then part of the
@@ -1910,6 +1919,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
 
              /* We can ignore CLOBBERs.  */
            case CLOBBER:
 
              /* We can ignore CLOBBERs.  */
            case CLOBBER:
+           case CLOBBER_HIGH:
              break;
 
            case SET:
              break;
 
            case SET:
@@ -2344,7 +2354,11 @@ cant_combine_insn_p (rtx_insn *insn)
   if (REG_P (src) && REG_P (dest)
       && ((HARD_REGISTER_P (src)
           && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src))
   if (REG_P (src) && REG_P (dest)
       && ((HARD_REGISTER_P (src)
           && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src))
-          && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (src))))
+#ifdef LEAF_REGISTERS
+          && ! LEAF_REGISTERS [REGNO (src)])
+#else
+          )
+#endif
          || (HARD_REGISTER_P (dest)
              && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (dest))
              && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (dest))))))
          || (HARD_REGISTER_P (dest)
              && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (dest))
              && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (dest))))))
@@ -2570,10 +2584,17 @@ is_parallel_of_n_reg_sets (rtx pat, int n)
        || !REG_P (SET_DEST (XVECEXP (pat, 0, i))))
       return false;
   for ( ; i < len; i++)
        || !REG_P (SET_DEST (XVECEXP (pat, 0, i))))
       return false;
   for ( ; i < len; i++)
-    if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER
-       || XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
-      return false;
-
+    switch (GET_CODE (XVECEXP (pat, 0, i)))
+      {
+      case CLOBBER:
+       if (XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
+         return false;
+       break;
+      case CLOBBER_HIGH:
+       break;
+      default:
+       return false;
+      }
   return true;
 }
 
   return true;
 }
 
@@ -2604,6 +2625,17 @@ can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n)
   return true;
 }
 
   return true;
 }
 
+/* Return whether X is just a single set, with the source
+   a general_operand.  */
+static bool
+is_just_move (rtx x)
+{
+  if (INSN_P (x))
+    x = PATTERN (x);
+
+  return (GET_CODE (x) == SET && general_operand (SET_SRC (x), VOIDmode));
+}
+
 /* Try to combine the insns I0, I1 and I2 into I3.
    Here I0, I1 and I2 appear earlier than I3.
    I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
 /* Try to combine the insns I0, I1 and I2 into I3.
    Here I0, I1 and I2 appear earlier than I3.
    I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
@@ -2668,6 +2700,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
   int swap_i2i3 = 0;
   int split_i2i3 = 0;
   int changed_i3_dest = 0;
   int swap_i2i3 = 0;
   int split_i2i3 = 0;
   int changed_i3_dest = 0;
+  bool i2_was_move = false, i3_was_move = false;
 
   int maxreg;
   rtx_insn *temp_insn;
 
   int maxreg;
   rtx_insn *temp_insn;
@@ -2848,7 +2881,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       for (i = 0; ok && i < XVECLEN (p2, 0); i++)
        {
          if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
       for (i = 0; ok && i < XVECLEN (p2, 0); i++)
        {
          if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
-              || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
+              || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER
+              || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER_HIGH)
              && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
                                          SET_DEST (XVECEXP (p2, 0, i))))
            ok = false;
              && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
                                          SET_DEST (XVECEXP (p2, 0, i))))
            ok = false;
@@ -3059,6 +3093,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
       return 0;
     }
 
+  /* Record whether i2 and i3 are trivial moves.  */
+  i2_was_move = is_just_move (i2);
+  i3_was_move = is_just_move (i3);
+
   /* Record whether I2DEST is used in I2SRC and similarly for the other
      cases.  Knowing this will help in register status updating below.  */
   i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src);
   /* Record whether I2DEST is used in I2SRC and similarly for the other
      cases.  Knowing this will help in register status updating below.  */
   i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src);
@@ -3281,7 +3319,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
                {
                  /* Replace cc_use_loc with entire new RTX.  */
                  SUBST (*cc_use_loc,
                {
                  /* Replace cc_use_loc with entire new RTX.  */
                  SUBST (*cc_use_loc,
-                        gen_rtx_fmt_ee (compare_code, compare_mode,
+                        gen_rtx_fmt_ee (compare_code, GET_MODE (*cc_use_loc),
                                         newpat_dest, const0_rtx));
                  undobuf.other_insn = cc_use_insn;
                }
                                         newpat_dest, const0_rtx));
                  undobuf.other_insn = cc_use_insn;
                }
@@ -3290,7 +3328,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
                  /* Just replace the CC reg with a new mode.  */
                  SUBST (XEXP (*cc_use_loc, 0), newpat_dest);
                  undobuf.other_insn = cc_use_insn;
                  /* Just replace the CC reg with a new mode.  */
                  SUBST (XEXP (*cc_use_loc, 0), newpat_dest);
                  undobuf.other_insn = cc_use_insn;
-               }             
+               }
            }
 
          /* Now we modify the current newpat:
            }
 
          /* Now we modify the current newpat:
@@ -4007,15 +4045,20 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
      other insns to combine, but the destination of that SET is still live.
 
      Also do this if we started with two insns and (at least) one of the
      other insns to combine, but the destination of that SET is still live.
 
      Also do this if we started with two insns and (at least) one of the
-     resulting sets is a noop; this noop will be deleted later.  */
+     resulting sets is a noop; this noop will be deleted later.
+
+     Also do this if we started with two insns neither of which was a simple
+     move.  */
 
   else if (insn_code_number < 0 && asm_noperands (newpat) < 0
           && GET_CODE (newpat) == PARALLEL
           && XVECLEN (newpat, 0) == 2
           && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
           && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
 
   else if (insn_code_number < 0 && asm_noperands (newpat) < 0
           && GET_CODE (newpat) == PARALLEL
           && XVECLEN (newpat, 0) == 2
           && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
           && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
-          && (i1 || set_noop_p (XVECEXP (newpat, 0, 0))
-                 || set_noop_p (XVECEXP (newpat, 0, 1)))
+          && (i1
+              || set_noop_p (XVECEXP (newpat, 0, 0))
+              || set_noop_p (XVECEXP (newpat, 0, 1))
+              || (!i2_was_move && !i3_was_move))
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != ZERO_EXTRACT
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != STRICT_LOW_PART
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != ZERO_EXTRACT
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != STRICT_LOW_PART
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
@@ -4035,13 +4078,15 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
         one which uses any regs/memory set in between i2 and i3 can't
         be first.  The PARALLEL might also have been pre-existing in i3,
         so we need to make sure that we won't wrongly hoist a SET to i2
         one which uses any regs/memory set in between i2 and i3 can't
         be first.  The PARALLEL might also have been pre-existing in i3,
         so we need to make sure that we won't wrongly hoist a SET to i2
-        that would conflict with a death note present in there.  */
+        that would conflict with a death note present in there, or would
+        have its dest modified between i2 and i3.  */
       if (!modified_between_p (SET_SRC (set1), i2, i3)
          && !(REG_P (SET_DEST (set1))
               && find_reg_note (i2, REG_DEAD, SET_DEST (set1)))
          && !(GET_CODE (SET_DEST (set1)) == SUBREG
               && find_reg_note (i2, REG_DEAD,
                                 SUBREG_REG (SET_DEST (set1))))
       if (!modified_between_p (SET_SRC (set1), i2, i3)
          && !(REG_P (SET_DEST (set1))
               && find_reg_note (i2, REG_DEAD, SET_DEST (set1)))
          && !(GET_CODE (SET_DEST (set1)) == SUBREG
               && find_reg_note (i2, REG_DEAD,
                                 SUBREG_REG (SET_DEST (set1))))
+         && !modified_between_p (SET_DEST (set1), i2, i3)
          && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set0))
          /* If I3 is a jump, ensure that set0 is a jump so that
             we do not create invalid RTL.  */
          && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set0))
          /* If I3 is a jump, ensure that set0 is a jump so that
             we do not create invalid RTL.  */
@@ -4057,6 +4102,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
               && !(GET_CODE (SET_DEST (set0)) == SUBREG
                    && find_reg_note (i2, REG_DEAD,
                                      SUBREG_REG (SET_DEST (set0))))
               && !(GET_CODE (SET_DEST (set0)) == SUBREG
                    && find_reg_note (i2, REG_DEAD,
                                      SUBREG_REG (SET_DEST (set0))))
+              && !modified_between_p (SET_DEST (set0), i2, i3)
               && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set1))
               /* If I3 is a jump, ensure that set1 is a jump so that
                  we do not create invalid RTL.  */
               && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set1))
               /* If I3 is a jump, ensure that set1 is a jump so that
                  we do not create invalid RTL.  */
@@ -4908,7 +4954,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
        }
 
       /* If we have a PLUS whose second operand is a constant and the
        }
 
       /* If we have a PLUS whose second operand is a constant and the
-        address is not valid, perhaps will can split it up using
+        address is not valid, perhaps we can split it up using
         the machine-specific way to split large constants.  We use
         the first pseudo-reg (one of the virtual regs) as a placeholder;
         it will not remain in the result.  */
         the machine-specific way to split large constants.  We use
         the first pseudo-reg (one of the virtual regs) as a placeholder;
         it will not remain in the result.  */
@@ -4923,7 +4969,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
 
          /* This should have produced two insns, each of which sets our
             placeholder.  If the source of the second is a valid address,
 
          /* This should have produced two insns, each of which sets our
             placeholder.  If the source of the second is a valid address,
-            we can make put both sources together and make a split point
+            we can put both sources together and make a split point
             in the middle.  */
 
          if (seq
             in the middle.  */
 
          if (seq
@@ -4964,14 +5010,51 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
                }
            }
 
                }
            }
 
+         /* If that didn't work and we have a nested plus, like:
+            ((REG1 * CONST1) + REG2) + CONST2 and (REG1 + REG2) + CONST2
+            is valid address, try to split (REG1 * CONST1).  */
+         if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+             && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+             && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+             && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SUBREG
+                   && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+                                                        0), 0)))))
+           {
+             rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 0);
+             XEXP (XEXP (XEXP (x, 0), 0), 0) = reg;
+             if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                              MEM_ADDR_SPACE (x)))
+               {
+                 XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+                 return &XEXP (XEXP (XEXP (x, 0), 0), 0);
+               }
+             XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+           }
+         else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+                  && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+                  && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+                  && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == SUBREG
+                        && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+                                                             0), 1)))))
+           {
+             rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 1);
+             XEXP (XEXP (XEXP (x, 0), 0), 1) = reg;
+             if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                              MEM_ADDR_SPACE (x)))
+               {
+                 XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+                 return &XEXP (XEXP (XEXP (x, 0), 0), 1);
+               }
+             XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+           }
+
          /* 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.  */
          /* 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 (!OBJECT_P (XEXP (XEXP (x, 0), 0))
-                  && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
-                        && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
+         if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
+             && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+                   && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
            return &XEXP (XEXP (x, 0), 0);
        }
 
            return &XEXP (XEXP (x, 0), 0);
        }
 
@@ -5904,8 +5987,9 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
            && known_eq (subreg_lowpart_offset (int_mode, int_op0_mode),
                         SUBREG_BYTE (x))
            && HWI_COMPUTABLE_MODE_P (int_op0_mode)
            && known_eq (subreg_lowpart_offset (int_mode, int_op0_mode),
                         SUBREG_BYTE (x))
            && HWI_COMPUTABLE_MODE_P (int_op0_mode)
-           && (nonzero_bits (SUBREG_REG (x), int_op0_mode)
-               & GET_MODE_MASK (int_mode)) == 0)
+           && ((nonzero_bits (SUBREG_REG (x), int_op0_mode)
+                & GET_MODE_MASK (int_mode)) == 0)
+           && !side_effects_p (SUBREG_REG (x)))
          return CONST0_RTX (int_mode);
       }
 
          return CONST0_RTX (int_mode);
       }
 
@@ -5978,8 +6062,11 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
                              GET_MODE_MASK (mode), 0));
 
       /* We can truncate a constant value and return it.  */
                              GET_MODE_MASK (mode), 0));
 
       /* We can truncate a constant value and return it.  */
-      if (CONST_INT_P (XEXP (x, 0)))
-       return gen_int_mode (INTVAL (XEXP (x, 0)), mode);
+      {
+       poly_int64 c;
+       if (poly_int_rtx_p (XEXP (x, 0), &c))
+         return gen_int_mode (c, mode);
+      }
 
       /* Similarly to what we do in simplify-rtx.c, a truncate of a register
         whose value is a comparison can be replaced with a subreg if
 
       /* Similarly to what we do in simplify-rtx.c, a truncate of a register
         whose value is a comparison can be replaced with a subreg if
@@ -6455,7 +6542,7 @@ simplify_if_then_else (rtx x)
                          pc_rtx, pc_rtx, 0, 0, 0);
       if (reg_mentioned_p (from, false_rtx))
        false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
                          pc_rtx, pc_rtx, 0, 0, 0);
       if (reg_mentioned_p (from, false_rtx))
        false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
-                                  from, false_val),
+                                      from, false_val),
                           pc_rtx, pc_rtx, 0, 0, 0);
 
       SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
                           pc_rtx, pc_rtx, 0, 0, 0);
 
       SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
@@ -8700,6 +8787,7 @@ force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
   int next_select = just_select || code == XOR || code == NOT || code == NEG;
   unsigned HOST_WIDE_INT fuller_mask;
   rtx op0, op1, temp;
   int next_select = just_select || code == XOR || code == NOT || code == NEG;
   unsigned HOST_WIDE_INT fuller_mask;
   rtx op0, op1, temp;
+  poly_int64 const_op0;
 
   /* When we have an arithmetic operation, or a shift whose count we
      do not know, we need to assume that all bits up to the highest-order
 
   /* When we have an arithmetic operation, or a shift whose count we
      do not know, we need to assume that all bits up to the highest-order
@@ -8823,8 +8911,8 @@ force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
     case MINUS:
       /* If X is (minus C Y) where C's least set bit is larger than any bit
         in the mask, then we may replace with (neg Y).  */
     case MINUS:
       /* If X is (minus C Y) where C's least set bit is larger than any bit
         in the mask, then we may replace with (neg Y).  */
-      if (CONST_INT_P (XEXP (x, 0))
-         && least_bit_hwi (UINTVAL (XEXP (x, 0))) > mask)
+      if (poly_int_rtx_p (XEXP (x, 0), &const_op0)
+         && (unsigned HOST_WIDE_INT) known_alignment (const_op0) > mask)
        {
          x = simplify_gen_unary (NEG, xmode, XEXP (x, 1), xmode);
          return force_to_mode (x, mode, mask, next_select);
        {
          x = simplify_gen_unary (NEG, xmode, XEXP (x, 1), xmode);
          return force_to_mode (x, mode, mask, next_select);
@@ -9294,6 +9382,7 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 
          if (COMPARISON_P (cond0)
              && COMPARISON_P (cond1)
 
          if (COMPARISON_P (cond0)
              && COMPARISON_P (cond1)
+             && SCALAR_INT_MODE_P (mode)
              && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
              && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
@@ -9474,12 +9563,12 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
          if (COMPARISON_P (x))
            {
              if (comparison_dominates_p (cond, code))
          if (COMPARISON_P (x))
            {
              if (comparison_dominates_p (cond, code))
-               return const_true_rtx;
+               return VECTOR_MODE_P (GET_MODE (x)) ? x : const_true_rtx;
 
              code = reversed_comparison_code (x, NULL);
              if (code != UNKNOWN
                  && comparison_dominates_p (cond, code))
 
              code = reversed_comparison_code (x, NULL);
              if (code != UNKNOWN
                  && comparison_dominates_p (cond, code))
-               return const0_rtx;
+               return CONST0_RTX (GET_MODE (x));
              else
                return x;
            }
              else
                return x;
            }
@@ -9522,7 +9611,7 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
          /* We must simplify subreg here, before we lose track of the
             original inner_mode.  */
          new_rtx = simplify_subreg (GET_MODE (x), r,
          /* We must simplify subreg here, before we lose track of the
             original inner_mode.  */
          new_rtx = simplify_subreg (GET_MODE (x), r,
-                                inner_mode, SUBREG_BYTE (x));
+                                    inner_mode, SUBREG_BYTE (x));
          if (new_rtx)
            return new_rtx;
          else
          if (new_rtx)
            return new_rtx;
          else
@@ -9547,7 +9636,7 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
          /* We must simplify the zero_extend here, before we lose
             track of the original inner_mode.  */
          new_rtx = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
          /* We must simplify the zero_extend here, before we lose
             track of the original inner_mode.  */
          new_rtx = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
-                                         r, inner_mode);
+                                             r, inner_mode);
          if (new_rtx)
            return new_rtx;
          else
          if (new_rtx)
            return new_rtx;
          else
@@ -10145,6 +10234,7 @@ simplify_and_const_int (rtx x, scalar_int_mode mode, rtx varop,
 \f
 /* Given a REG X of mode XMODE, compute which bits in X can be nonzero.
    We don't care about bits outside of those defined in MODE.
 \f
 /* Given a REG X of mode XMODE, compute which bits in X can be nonzero.
    We don't care about bits outside of those defined in MODE.
+   We DO care about all the bits in MODE, even if XMODE is smaller than MODE.
 
    For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
    a shift, AND, or zero_extract, we can do better.  */
 
    For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
    a shift, AND, or zero_extract, we can do better.  */
@@ -10165,7 +10255,8 @@ reg_nonzero_bits_for_combine (const_rtx x, scalar_int_mode xmode,
   rsp = &reg_stat[REGNO (x)];
   if (rsp->last_set_value != 0
       && (rsp->last_set_mode == mode
   rsp = &reg_stat[REGNO (x)];
   if (rsp->last_set_value != 0
       && (rsp->last_set_mode == mode
-         || (GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
+         || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+             && GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
              && GET_MODE_CLASS (mode) == MODE_INT))
       && ((rsp->last_set_label >= label_tick_ebb_start
           && rsp->last_set_label < label_tick)
              && GET_MODE_CLASS (mode) == MODE_INT))
       && ((rsp->last_set_label >= label_tick_ebb_start
           && rsp->last_set_label < label_tick)
@@ -13288,10 +13379,20 @@ record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
               && subreg_lowpart_p (SET_DEST (setter)))
        record_value_for_reg (dest, record_dead_insn,
                              WORD_REGISTER_OPERATIONS
               && subreg_lowpart_p (SET_DEST (setter)))
        record_value_for_reg (dest, record_dead_insn,
                              WORD_REGISTER_OPERATIONS
+                             && word_register_operation_p (SET_SRC (setter))
                              && paradoxical_subreg_p (SET_DEST (setter))
                              ? SET_SRC (setter)
                              : gen_lowpart (GET_MODE (dest),
                                             SET_SRC (setter)));
                              && paradoxical_subreg_p (SET_DEST (setter))
                              ? SET_SRC (setter)
                              : gen_lowpart (GET_MODE (dest),
                                             SET_SRC (setter)));
+      else if (GET_CODE (setter) == CLOBBER_HIGH)
+       {
+         reg_stat_type *rsp = &reg_stat[REGNO (dest)];
+         if (rsp->last_set_value
+             && reg_is_clobbered_by_clobber_high
+                  (REGNO (dest), GET_MODE (rsp->last_set_value),
+                   XEXP (setter, 0)))
+           record_value_for_reg (dest, NULL, NULL_RTX);
+       }
       else
        record_value_for_reg (dest, record_dead_insn, NULL_RTX);
     }
       else
        record_value_for_reg (dest, record_dead_insn, NULL_RTX);
     }
@@ -13712,6 +13813,7 @@ get_last_value (const_rtx x)
 
 static unsigned int reg_dead_regno, reg_dead_endregno;
 static int reg_dead_flag;
 
 static unsigned int reg_dead_regno, reg_dead_endregno;
 static int reg_dead_flag;
+rtx reg_dead_reg;
 
 /* Function called via note_stores from reg_dead_at_p.
 
 
 /* Function called via note_stores from reg_dead_at_p.
 
@@ -13726,6 +13828,10 @@ reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
   if (!REG_P (dest))
     return;
 
   if (!REG_P (dest))
     return;
 
+  if (GET_CODE (x) == CLOBBER_HIGH
+      && !reg_is_clobbered_by_clobber_high (reg_dead_reg, XEXP (x, 0)))
+    return;
+
   regno = REGNO (dest);
   endregno = END_REGNO (dest);
   if (reg_dead_endregno > regno && reg_dead_regno < endregno)
   regno = REGNO (dest);
   endregno = END_REGNO (dest);
   if (reg_dead_endregno > regno && reg_dead_regno < endregno)
@@ -13749,6 +13855,7 @@ reg_dead_at_p (rtx reg, rtx_insn *insn)
   /* Set variables for reg_dead_at_p_1.  */
   reg_dead_regno = REGNO (reg);
   reg_dead_endregno = END_REGNO (reg);
   /* Set variables for reg_dead_at_p_1.  */
   reg_dead_regno = REGNO (reg);
   reg_dead_endregno = END_REGNO (reg);
+  reg_dead_reg = reg;
 
   reg_dead_flag = 0;
 
 
   reg_dead_flag = 0;
 
@@ -14877,11 +14984,52 @@ dump_combine_total_stats (FILE *file)
      total_attempts, total_merges, total_extras, total_successes);
 }
 \f
      total_attempts, total_merges, total_extras, total_successes);
 }
 \f
+/* Make pseudo-to-pseudo copies after every hard-reg-to-pseudo-copy, because
+   the reg-to-reg copy can usefully combine with later instructions, but we
+   do not want to combine the hard reg into later instructions, for that
+   restricts register allocation.  */
+static void
+make_more_copies (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+        {
+          if (!NONDEBUG_INSN_P (insn))
+            continue;
+
+         rtx set = single_set (insn);
+         if (!set)
+           continue;
+
+         rtx dest = SET_DEST (set);
+         if (!(REG_P (dest) && !HARD_REGISTER_P (dest)))
+             continue;
+
+         rtx src = SET_SRC (set);
+         if (!(REG_P (src) && HARD_REGISTER_P (src)))
+           continue;
+         if (TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src)))
+           continue;
+
+         rtx new_reg = gen_reg_rtx (GET_MODE (dest));
+         rtx_insn *new_insn = gen_move_insn (new_reg, src);
+         SET_SRC (set) = new_reg;
+         emit_insn_before (new_insn, insn);
+         df_insn_rescan (insn);
+       }
+    }
+}
+
 /* Try combining insns through substitution.  */
 static unsigned int
 rest_of_handle_combine (void)
 {
 /* Try combining insns through substitution.  */
 static unsigned int
 rest_of_handle_combine (void)
 {
-  int rebuild_jump_labels_after_combine;
+  make_more_copies ();
 
   df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN);
   df_note_add_problem ();
 
   df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN);
   df_note_add_problem ();
@@ -14890,7 +15038,7 @@ rest_of_handle_combine (void)
   regstat_init_n_sets_and_refs ();
   reg_n_sets_max = max_reg_num ();
 
   regstat_init_n_sets_and_refs ();
   reg_n_sets_max = max_reg_num ();
 
-  rebuild_jump_labels_after_combine
+  int rebuild_jump_labels_after_combine
     = combine_instructions (get_insns (), max_reg_num ());
 
   /* Combining insns may have turned an indirect jump into a
     = combine_instructions (get_insns (), max_reg_num ());
 
   /* Combining insns may have turned an indirect jump into a