OSDN Git Service

* reload1.c (reg_set_luid): Fix a comment typo.
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index ef4deb9..edfd5d5 100644 (file)
@@ -1,6 +1,6 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -305,7 +305,7 @@ struct elim_table
   int from;                    /* Register number to be eliminated.  */
   int to;                      /* Register number used as replacement.  */
   int initial_offset;          /* Initial difference between values.  */
-  int can_eliminate;           /* Non-zero if this elimination can be done.  */
+  int can_eliminate;           /* Nonzero if this elimination can be done.  */
   int can_eliminate_previous;  /* Value of CAN_ELIMINATE in previous scan over
                                   insns made by reload.  */
   int offset;                  /* Current offset between the two regs.  */
@@ -354,11 +354,14 @@ static int num_eliminable_invariants;
 
 /* For each label, we record the offset of each elimination.  If we reach
    a label by more than one path and an offset differs, we cannot do the
-   elimination.  This information is indexed by the number of the label.
-   The first table is an array of flags that records whether we have yet
-   encountered a label and the second table is an array of arrays, one
-   entry in the latter array for each elimination.  */
-
+   elimination.  This information is indexed by the difference of the
+   number of the label and the first label number.  We can't offset the
+   pointer itself as this can cause problems on machines with segmented
+   memory.  The first table is an array of flags that records whether we
+   have yet encountered a label and the second table is an array of arrays,
+   one entry in the latter array for each elimination.  */
+
+static int first_label_num;
 static char *offsets_known_at;
 static int (*offsets_at)[NUM_ELIMINABLE_REGS];
 
@@ -452,8 +455,6 @@ static void move2add_note_store             PARAMS ((rtx, rtx, void *));
 static void add_auto_inc_notes         PARAMS ((rtx, rtx));
 #endif
 static void copy_eh_notes              PARAMS ((rtx, rtx));
-static HOST_WIDE_INT sext_for_mode     PARAMS ((enum machine_mode,
-                                                HOST_WIDE_INT));
 static void failed_reload              PARAMS ((rtx, int));
 static int set_reload_reg              PARAMS ((int, int));
 static void reload_cse_simplify                PARAMS ((rtx, rtx));
@@ -675,11 +676,6 @@ reload (first, global)
   struct elim_table *ep;
   basic_block bb;
 
-  /* The two pointers used to track the true location of the memory used
-     for label offsets.  */
-  char *real_known_ptr = NULL;
-  int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
-
   /* Make sure even insns with volatile mem refs are recognizable.  */
   init_recog ();
 
@@ -858,21 +854,18 @@ reload (first, global)
 
   init_elim_table ();
 
-  num_labels = max_label_num () - get_first_label_num ();
+  first_label_num = get_first_label_num ();
+  num_labels = max_label_num () - first_label_num;
 
   /* Allocate the tables used to store offset information at labels.  */
   /* We used to use alloca here, but the size of what it would try to
      allocate would occasionally cause it to exceed the stack limit and
      cause a core dump.  */
-  real_known_ptr = xmalloc (num_labels);
-  real_at_ptr
+  offsets_known_at = xmalloc (num_labels);
+  offsets_at
     = (int (*)[NUM_ELIMINABLE_REGS])
     xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
 
-  offsets_known_at = real_known_ptr - get_first_label_num ();
-  offsets_at
-    = (int (*)[NUM_ELIMINABLE_REGS]) (real_at_ptr - get_first_label_num ());
-
   /* Alter each pseudo-reg rtx to contain its hard reg number.
      Assign stack slots to the pseudos that lack hard regs or equivalents.
      Do not touch virtual registers.  */
@@ -1271,10 +1264,10 @@ reload (first, global)
     free (reg_equiv_memory_loc);
   reg_equiv_memory_loc = 0;
 
-  if (real_known_ptr)
-    free (real_known_ptr);
-  if (real_at_ptr)
-    free (real_at_ptr);
+  if (offsets_known_at)
+    free (offsets_known_at);
+  if (offsets_at)
+    free (offsets_at);
 
   free (reg_equiv_mem);
   free (reg_equiv_init);
@@ -1355,7 +1348,7 @@ maybe_fix_stack_asms ()
 
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
 
              if (c == '\0' || c == ',' || c == '#')
                {
@@ -1363,6 +1356,7 @@ maybe_fix_stack_asms ()
                     class, and reset the class.  */
                  IOR_HARD_REG_SET (allowed, reg_class_contents[cls]);
                  cls = NO_REGS;
+                 p++;
                  if (c == '#')
                    do {
                      c = *p++;
@@ -1393,13 +1387,14 @@ maybe_fix_stack_asms ()
                  break;
 
                default:
-                 if (EXTRA_ADDRESS_CONSTRAINT (c))
+                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
                    cls = (int) reg_class_subunion[cls]
                      [(int) MODE_BASE_REG_CLASS (VOIDmode)];
                  else
                    cls = (int) reg_class_subunion[cls]
-                     [(int) REG_CLASS_FROM_LETTER (c)];
+                     [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
                }
+             p += CONSTRAINT_LEN (c, p);
            }
        }
       /* Those of the registers which are clobbered, but allowed by the
@@ -2079,9 +2074,10 @@ alter_reg (i, from_reg)
 
       /* If we have a decl for the original register, set it for the
         memory.  If this is a shared MEM, make a copy.  */
-      if (REGNO_DECL (i))
+      if (REG_EXPR (regno_reg_rtx[i])
+         && TREE_CODE_CLASS (TREE_CODE (REG_EXPR (regno_reg_rtx[i]))) == 'd')
        {
-         rtx decl = DECL_RTL_IF_SET (REGNO_DECL (i));
+         rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i]));
 
          /* We can do this only for the DECLs home pseudo, not for
             any copies of it, since otherwise when the stack slot
@@ -2092,7 +2088,7 @@ alter_reg (i, from_reg)
              if (from_reg != -1 && spill_stack_slot[from_reg] == x)
                x = copy_rtx (x);
 
-             set_mem_expr (x, REGNO_DECL (i));
+             set_mem_attrs_from_reg (x, regno_reg_rtx[i]);
            }
        }
 
@@ -2157,13 +2153,13 @@ set_label_offsets (x, insn, initial_p)
         we guessed wrong, we will suppress an elimination that might have
         been possible had we been able to guess correctly.  */
 
-      if (! offsets_known_at[CODE_LABEL_NUMBER (x)])
+      if (! offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num])
        {
          for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
-           offsets_at[CODE_LABEL_NUMBER (x)][i]
+           offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
              = (initial_p ? reg_eliminate[i].initial_offset
                 : reg_eliminate[i].offset);
-         offsets_known_at[CODE_LABEL_NUMBER (x)] = 1;
+         offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num] = 1;
        }
 
       /* Otherwise, if this is the definition of a label and it is
@@ -2180,7 +2176,7 @@ set_label_offsets (x, insn, initial_p)
           where the offsets disagree.  */
 
        for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
-         if (offsets_at[CODE_LABEL_NUMBER (x)][i]
+         if (offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
              != (initial_p ? reg_eliminate[i].initial_offset
                  : reg_eliminate[i].offset))
            reg_eliminate[i].can_eliminate = 0;
@@ -2542,6 +2538,10 @@ eliminate_regs (x, mem_mode, insn)
     case ABS:
     case SQRT:
     case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
       new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
       if (new != XEXP (x, 0))
        return gen_rtx_fmt_e (code, GET_MODE (x), new);
@@ -2773,6 +2773,10 @@ elimination_effects (x, mem_mode)
     case ABS:
     case SQRT:
     case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
       elimination_effects (XEXP (x, 0), mem_mode);
       return;
 
@@ -3388,7 +3392,7 @@ static void
 set_initial_label_offsets ()
 {
   rtx x;
-  memset ((char *) &offsets_known_at[get_first_label_num ()], 0, num_labels);
+  memset (offsets_known_at, 0, num_labels);
 
   for (x = forced_labels; x; x = XEXP (x, 1))
     if (XEXP (x, 0))
@@ -3409,7 +3413,8 @@ set_offsets_for_label (insn)
   num_not_at_initial_offset = 0;
   for (i = 0, ep = reg_eliminate; i < NUM_ELIMINABLE_REGS; ep++, i++)
     {
-      ep->offset = ep->previous_offset = offsets_at[label_nr][i];
+      ep->offset = ep->previous_offset
+                = offsets_at[label_nr - first_label_num][i];
       if (ep->can_eliminate && ep->offset != ep->initial_offset)
        num_not_at_initial_offset++;
     }
@@ -3840,7 +3845,7 @@ reload_as_needed (live_known)
 
   for (chain = reload_insn_chain; chain; chain = chain->next)
     {
-      rtx prev;
+      rtx prev = 0;
       rtx insn = chain->insn;
       rtx old_next = NEXT_INSN (insn);
 
@@ -3935,6 +3940,7 @@ reload_as_needed (live_known)
              if (asm_noperands (PATTERN (insn)) >= 0)
                for (p = NEXT_INSN (prev); p != next; p = NEXT_INSN (p))
                  if (p != insn && INSN_P (p)
+                     && GET_CODE (PATTERN (p)) != USE
                      && (recog_memoized (p) < 0
                          || (extract_insn (p), ! constrain_operands (1))))
                    {
@@ -3982,7 +3988,7 @@ reload_as_needed (live_known)
                                            REGNO (rld[i].reg_rtx))
                      /* Make sure it is the inc/dec pseudo, and not
                         some other (e.g. output operand) pseudo.  */
-                     && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+                     && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
                          == REGNO (XEXP (in_reg, 0))))
 
                    {
@@ -4049,7 +4055,7 @@ reload_as_needed (live_known)
                                                 REGNO (rld[i].reg_rtx))
                           /* Make sure it is the inc/dec pseudo, and not
                              some other (e.g. output operand) pseudo.  */
-                          && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+                          && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
                               == REGNO (XEXP (in_reg, 0))))
                    {
                      SET_HARD_REG_BIT (reg_is_output_reload,
@@ -5498,7 +5504,7 @@ choose_reload_regs (chain)
 #ifdef CANNOT_CHANGE_MODE_CLASS
                      (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg),
                                                  need_mode)
-                      ||
+                      &&
 #endif
                      (GET_MODE_SIZE (GET_MODE (last_reg))
                       >= GET_MODE_SIZE (need_mode))
@@ -5935,7 +5941,7 @@ choose_reload_regs (chain)
     if (reload_override_in[j])
       rld[j].in = reload_override_in[j];
 
-  /* If this reload won't be done because it has been cancelled or is
+  /* If this reload won't be done because it has been canceled or is
      optional and not inherited, clear reload_reg_rtx so other
      routines (such as subst_reloads) don't get confused.  */
   for (j = 0; j < n_reloads; j++)
@@ -6258,7 +6264,7 @@ emit_input_reload_insns (chain, rl, old, j)
         or memory.  */
 
       if (oldequiv != 0
-         && ((REGNO_REG_CLASS (regno) != rl->class
+         && (((enum reg_class) REGNO_REG_CLASS (regno) != rl->class
               && (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
                                       rl->class)
                   >= MEMORY_MOVE_COST (mode, rl->class, 1)))
@@ -6314,7 +6320,7 @@ emit_input_reload_insns (chain, rl, old, j)
      must always be a REG here.  */
 
   if (GET_MODE (reloadreg) != mode)
-    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+    reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
   while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
     oldequiv = SUBREG_REG (oldequiv);
   if (GET_MODE (oldequiv) != VOIDmode
@@ -6563,8 +6569,8 @@ emit_input_reload_insns (chain, rl, old, j)
                        oldequiv = old, real_oldequiv = real_old;
                      else
                        second_reload_reg
-                         = gen_rtx_REG (new_mode,
-                                        REGNO (second_reload_reg));
+                         = reload_adjust_reg_for_mode (second_reload_reg,
+                                                       new_mode);
                    }
                }
            }
@@ -6686,7 +6692,7 @@ emit_output_reload_insns (chain, rl, j)
     }
 
   if (GET_MODE (reloadreg) != mode)
-    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+    reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
 
@@ -6727,7 +6733,7 @@ emit_output_reload_insns (chain, rl, j)
                = rld[secondary_reload].secondary_out_icode;
 
              if (GET_MODE (reloadreg) != mode)
-               reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+               reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
              if (tertiary_icode != CODE_FOR_nothing)
                {
@@ -7608,6 +7614,11 @@ delete_output_reload (insn, j, last_reload_reg)
   rtx i1;
   rtx substed;
 
+  /* It is possible that this reload has been only used to set another reload
+     we eliminated earlier and thus deleted this instruction too.  */
+  if (INSN_DELETED_P (output_reload_insn))
+    return;
+
   /* Get the raw pseudo-register referred to.  */
 
   while (GET_CODE (reg) == SUBREG)
@@ -7689,7 +7700,7 @@ delete_output_reload (insn, j, last_reload_reg)
 
   /* The caller has already checked that REG dies or is set in INSN.
      It has also checked that we are optimizing, and thus some
-     inaccurancies in the debugging information are acceptable.
+     inaccuracies in the debugging information are acceptable.
      So we could just delete output_reload_insn.  But in some cases
      we can improve the debugging information without sacrificing
      optimization - maybe even improving the code: See if the pseudo
@@ -7891,7 +7902,7 @@ delete_address_reloads_1 (dead_insn, x, current_insn)
                  return;
              /* ??? We can't finish the loop here, because dst might be
                 allocated to a pseudo in this block if no reload in this
-                block needs any of the clsses containing DST - see
+                block needs any of the classes containing DST - see
                 spill_hard_reg.  There is no easy way to tell this, so we
                 have to scan till the end of the basic block.  */
            }
@@ -8014,6 +8025,9 @@ static int
 reload_cse_noop_set_p (set)
      rtx set;
 {
+  if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
+    return 0;
+
   return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
 }
 
@@ -8270,7 +8284,13 @@ reload_cse_simplify_set (set, insn)
        {
 #ifdef LOAD_EXTEND_OP
          if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
-             && extend_op != NIL)
+             && extend_op != NIL
+#ifdef CANNOT_CHANGE_MODE_CLASS
+             && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+                                           word_mode,
+                                           REGNO_REG_CLASS (REGNO (SET_DEST (set))))
+#endif
+             )
            {
              rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
              ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
@@ -8413,7 +8433,7 @@ reload_cse_simplify_operands (insn, testreg)
          p = constraints[i];
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
 
              switch (c)
                {
@@ -8437,7 +8457,9 @@ reload_cse_simplify_operands (insn, testreg)
 
                default:
                  class
-                   = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER ((unsigned char) c)];
+                   = (reg_class_subunion
+                      [(int) class]
+                      [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
                  break;
 
                case ',': case '\0':
@@ -8457,6 +8479,7 @@ reload_cse_simplify_operands (insn, testreg)
                  j++;
                  break;
                }
+             p += CONSTRAINT_LEN (c, p);
 
              if (c == '\0')
                break;
@@ -8530,7 +8553,7 @@ reload_cse_simplify_operands (insn, testreg)
 \f
 /* If reload couldn't use reg+reg+offset addressing, try to use reg+reg
    addressing now.
-   This code might also be useful when reload gave up on reg+reg addresssing
+   This code might also be useful when reload gave up on reg+reg addressing
    because of clashes between the return register and INDEX_REG_CLASS.  */
 
 /* The maximum number of uses of a register we can keep track of to
@@ -8551,7 +8574,7 @@ struct reg_use { rtx insn, *usep; };
    last, of these uses.
    STORE_RUID is always meaningful if we only want to use a value in a
    register in a different place: it denotes the next insn in the insn
-   stream (i.e. the last ecountered) that sets or clobbers the register.  */
+   stream (i.e. the last encountered) that sets or clobbers the register.  */
 static struct
   {
     struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
@@ -9042,7 +9065,7 @@ reload_combine_note_use (xp, insn)
    use move2add_last_label_luid to note where the label is and then
    later disable any optimization that would cross it.
    reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if
-   reg_set_luid[n] is greater than last_label_luid[n] .  */
+   reg_set_luid[n] is greater than move2add_last_label_luid.  */
 static int reg_set_luid[FIRST_PSEUDO_REGISTER];
 
 /* If reg_base_reg[n] is negative, register n has been set to
@@ -9054,7 +9077,7 @@ static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
 static int reg_base_reg[FIRST_PSEUDO_REGISTER];
 static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
 
-/* move2add_luid is linearily increased while scanning the instructions
+/* move2add_luid is linearly increased while scanning the instructions
    from first to last.  It is used to set reg_set_luid in
    reload_cse_move2add and move2add_note_store.  */
 static int move2add_luid;
@@ -9063,25 +9086,6 @@ static int move2add_luid;
    invalidate all previously collected reg_offset data.  */
 static int move2add_last_label_luid;
 
-/* Generate a CONST_INT and force it in the range of MODE.  */
-
-static HOST_WIDE_INT
-sext_for_mode (mode, value)
-     enum machine_mode mode;
-     HOST_WIDE_INT value;
-{
-  HOST_WIDE_INT cval = value & GET_MODE_MASK (mode);
-  int width = GET_MODE_BITSIZE (mode);
-
-  /* If MODE is narrower than HOST_WIDE_INT and CVAL is a negative number,
-     sign extend it.  */
-  if (width > 0 && width < HOST_BITS_PER_WIDE_INT
-      && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
-    cval |= (HOST_WIDE_INT) -1 << width;
-
-  return cval;
-}
-
 /* ??? We don't know how zero / sign extension is handled, hence we
    can't go from a narrower to a wider mode.  */
 #define MODES_OK_FOR_MOVE2ADD(OUTMODE, INMODE) \
@@ -9138,14 +9142,19 @@ reload_cse_move2add (first)
                 to
                                  (set (REGX) (CONST_INT A))
                                  ...
-                                 (set (REGX) (plus (REGX) (CONST_INT B-A)))  */
+                                 (set (REGX) (plus (REGX) (CONST_INT B-A)))
+                or
+                                 (set (REGX) (CONST_INT A))
+                                 ...
+                                 (set (STRICT_LOW_PART (REGX)) (CONST_INT B))
+             */
 
              if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
                {
-                 int success = 0;
-                 rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
-                                                       INTVAL (src)
-                                                       - reg_offset[regno]));
+                 rtx new_src =
+                   GEN_INT (trunc_int_for_mode (INTVAL (src)
+                                                - reg_offset[regno],
+                                                GET_MODE (reg)));
                  /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
                     use (set (reg) (reg)) instead.
                     We don't delete this insn, nor do we convert it into a
@@ -9153,11 +9162,48 @@ reload_cse_move2add (first)
                     value flag.  jump2 already knows how to get rid of
                     no-op moves.  */
                  if (new_src == const0_rtx)
-                   success = validate_change (insn, &SET_SRC (pat), reg, 0);
+                   validate_change (insn, &SET_SRC (pat), reg, 0);
                  else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
                           && have_add2_insn (reg, new_src))
-                   success = validate_change (insn, &PATTERN (insn),
-                                              gen_add2_insn (reg, new_src), 0);
+                   {
+                     rtx newpat = gen_add2_insn (reg, new_src);
+                     if (INSN_P (newpat) && NEXT_INSN (newpat) == NULL_RTX)
+                       newpat = PATTERN (newpat);
+                     /* If it was the first insn of a sequence or
+                        some other emitted insn, validate_change will
+                        reject it.  */
+                     validate_change (insn, &PATTERN (insn),
+                                      newpat, 0);
+                   }
+                 else
+                   {
+                     enum machine_mode narrow_mode;
+                     for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+                          narrow_mode != GET_MODE (reg);
+                          narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
+                       {
+                         if (have_insn_for (STRICT_LOW_PART, narrow_mode)
+                             && ((reg_offset[regno]
+                                  & ~GET_MODE_MASK (narrow_mode))
+                                 == (INTVAL (src)
+                                     & ~GET_MODE_MASK (narrow_mode))))
+                           {
+                             rtx narrow_reg = gen_rtx_REG (narrow_mode,
+                                                           REGNO (reg));
+                             rtx narrow_src =
+                               GEN_INT (trunc_int_for_mode (INTVAL (src),
+                                                            narrow_mode));
+                             rtx new_set =
+                               gen_rtx_SET (VOIDmode,
+                                            gen_rtx_STRICT_LOW_PART (VOIDmode,
+                                                                     narrow_reg),
+                                            narrow_src);
+                             if (validate_change (insn, &PATTERN (insn),
+                                                  new_set, 0))
+                               break;
+                           }
+                       }
+                   }
                  reg_set_luid[regno] = move2add_luid;
                  reg_mode[regno] = GET_MODE (reg);
                  reg_offset[regno] = INTVAL (src);
@@ -9170,7 +9216,7 @@ reload_cse_move2add (first)
                                  (set (REGX) (REGY))
                                  (set (REGX) (PLUS (REGX) (CONST_INT B)))
                 to
-                                 (REGX) (REGY))
+                                 (set (REGX) (REGY))
                                  (set (REGX) (PLUS (REGX) (CONST_INT A)))
                                  ...
                                  (set (REGX) (plus (REGX) (CONST_INT B-A)))  */
@@ -9194,10 +9240,11 @@ reload_cse_move2add (first)
                      HOST_WIDE_INT added_offset = INTVAL (src3);
                      HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
                      HOST_WIDE_INT regno_offset = reg_offset[regno];
-                     rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
-                                                           added_offset
-                                                           + base_offset
-                                                           - regno_offset));
+                     rtx new_src =
+                       GEN_INT (trunc_int_for_mode (added_offset
+                                                    + base_offset
+                                                    - regno_offset,
+                                                    GET_MODE (reg)));
                      int success = 0;
 
                      if (new_src == const0_rtx)
@@ -9207,16 +9254,22 @@ reload_cse_move2add (first)
                      else if ((rtx_cost (new_src, PLUS)
                                < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
                               && have_add2_insn (reg, new_src))
-                       success
-                         = validate_change (next, &PATTERN (next),
-                                            gen_add2_insn (reg, new_src), 0);
+                       {
+                         rtx newpat = gen_add2_insn (reg, new_src);
+                         if (INSN_P (newpat)
+                             && NEXT_INSN (newpat) == NULL_RTX)
+                           newpat = PATTERN (newpat);
+                         success
+                           = validate_change (next, &PATTERN (next),
+                                              newpat, 0);
+                       }
                      if (success)
                        delete_insn (insn);
                      insn = next;
                      reg_mode[regno] = GET_MODE (reg);
-                     reg_offset[regno] = sext_for_mode (GET_MODE (reg),
-                                                        added_offset
-                                                        + base_offset);
+                     reg_offset[regno] =
+                       trunc_int_for_mode (added_offset + base_offset,
+                                           GET_MODE (reg));
                      continue;
                    }
                }
@@ -9286,7 +9339,8 @@ move2add_note_store (dst, set, data)
 
   regno += REGNO (dst);
 
-  if (HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
+  if (SCALAR_INT_MODE_P (mode)
+      && HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
       && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
       && GET_CODE (SET_DEST (set)) != SIGN_EXTRACT
       && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
@@ -9381,9 +9435,9 @@ move2add_note_store (dst, set, data)
       reg_base_reg[regno] = reg_base_reg[base_regno];
 
       /* Compute the sum of the offsets or constants.  */
-      reg_offset[regno] = sext_for_mode (dst_mode,
-                                        offset
-                                        + reg_offset[base_regno]);
+      reg_offset[regno] = trunc_int_for_mode (offset
+                                             + reg_offset[base_regno],
+                                             dst_mode);
     }
   else
     {
@@ -9499,7 +9553,7 @@ fixup_abnormal_edges ()
                     If it's placed after a trapping call (i.e. that
                     call is the last insn anyway), we have no fallthru
                     edge.  Simply delete this use and don't try to insert
-                    on the non-existant edge.  */
+                    on the non-existent edge.  */
                  if (GET_CODE (PATTERN (insn)) != USE)
                    {
                      /* We're not deleting it, we're moving it.  */
@@ -9514,6 +9568,14 @@ fixup_abnormal_edges ()
            }
        }
     }
+  /* We've possibly turned single trapping insn into multiple ones.  */
+  if (flag_non_call_exceptions)
+    {
+      sbitmap blocks;
+      blocks = sbitmap_alloc (last_basic_block);
+      sbitmap_ones (blocks);
+      find_many_sub_basic_blocks (blocks);
+    }
   if (inserted)
     commit_edge_insertions ();
 }