]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/postreload.c
[C++] Protect call to copy_attributes_to_builtin (PR91505)
[thirdparty/gcc.git] / gcc / postreload.c
index 88d5234eef367da8eeb79050b1484965baa83fcd..728aa9b0ed5a18b67ea7f89bd217cd0696d85b7c 100644 (file)
@@ -1,5 +1,5 @@
 /* Perform simple optimizations to clean up the result of reload.
-   Copyright (C) 1987-2015 Free Software Foundation, Inc.
+   Copyright (C) 1987-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,43 +21,26 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "backend.h"
-#include "predict.h"
-#include "tree.h"
+#include "target.h"
 #include "rtl.h"
+#include "tree.h"
+#include "predict.h"
 #include "df.h"
-
+#include "memmodel.h"
 #include "tm_p.h"
-#include "insn-config.h"
-#include "flags.h"
-#include "alias.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
-#include "expr.h"
-#include "insn-codes.h"
 #include "optabs.h"
 #include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
+
 #include "cfgrtl.h"
 #include "cfgbuild.h"
 #include "cfgcleanup.h"
 #include "reload.h"
-#include "recog.h"
-#include "alloc-pool.h"
 #include "cselib.h"
-#include "diagnostic-core.h"
-#include "except.h"
-#include "target.h"
 #include "tree-pass.h"
 #include "dbgcnt.h"
 
-#ifndef LOAD_EXTEND_OP
-#define LOAD_EXTEND_OP(M) UNKNOWN
-#endif
-
 static int reload_cse_noop_set_p (rtx);
 static bool reload_cse_simplify (rtx_insn *, rtx);
 static void reload_cse_regs_1 (void);
@@ -107,6 +90,11 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg)
   basic_block insn_bb = BLOCK_FOR_INSN (insn);
   unsigned insn_bb_succs = EDGE_COUNT (insn_bb->succs);
 
+  /* If NO_FUNCTION_CSE has been set by the target, then we should not try
+     to cse function calls.  */
+  if (NO_FUNCTION_CSE && CALL_P (insn))
+    return false;
+
   if (GET_CODE (body) == SET)
     {
       int count = 0;
@@ -120,10 +108,6 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg)
 
       if (!count && reload_cse_noop_set_p (body))
        {
-         rtx value = SET_DEST (body);
-         if (REG_P (value)
-             && ! REG_FUNCTION_VALUE_P (value))
-           value = 0;
          if (check_for_inc_dec (insn))
            delete_insn_and_edges (insn);
          /* We're done with this insn.  */
@@ -149,6 +133,8 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg)
          for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
            {
              rtx part = XVECEXP (body, 0, i);
+             /* asms can only have full clobbers, not clobber_highs.  */
+             gcc_assert (GET_CODE (part) != CLOBBER_HIGH);
              if (GET_CODE (part) == CLOBBER && REG_P (XEXP (part, 0)))
                cselib_invalidate_rtx (XEXP (part, 0));
            }
@@ -171,7 +157,9 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg)
                  value = SET_DEST (part);
                }
            }
-         else if (GET_CODE (part) != CLOBBER)
+         else if (GET_CODE (part) != CLOBBER
+                  && GET_CODE (part) != CLOBBER_HIGH
+                  && GET_CODE (part) != USE)
            break;
        }
 
@@ -276,8 +264,7 @@ reload_cse_simplify_set (rtx set, rtx_insn *insn)
      generating an extend instruction instead of a reg->reg copy.  Thus
      the destination must be a register that we can widen.  */
   if (MEM_P (src)
-      && GET_MODE_BITSIZE (GET_MODE (src)) < BITS_PER_WORD
-      && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != UNKNOWN
+      && (extend_op = load_extend_op (GET_MODE (src))) != UNKNOWN
       && !REG_P (SET_DEST (set)))
     return 0;
 
@@ -311,13 +298,13 @@ reload_cse_simplify_set (rtx set, rtx_insn *insn)
              switch (extend_op)
                {
                case ZERO_EXTEND:
-                 result = wide_int::from (std::make_pair (this_rtx,
-                                                          GET_MODE (src)),
+                 result = wide_int::from (rtx_mode_t (this_rtx,
+                                                      GET_MODE (src)),
                                           BITS_PER_WORD, UNSIGNED);
                  break;
                case SIGN_EXTEND:
-                 result = wide_int::from (std::make_pair (this_rtx,
-                                                          GET_MODE (src)),
+                 result = wide_int::from (rtx_mode_t (this_rtx,
+                                                      GET_MODE (src)),
                                           BITS_PER_WORD, SIGNED);
                  break;
                default:
@@ -350,14 +337,9 @@ reload_cse_simplify_set (rtx set, rtx_insn *insn)
              && REG_P (this_rtx)
              && !REG_P (SET_SRC (set))))
        {
-         if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
-             && extend_op != UNKNOWN
-#ifdef CANNOT_CHANGE_MODE_CLASS
-             && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
-                                           word_mode,
-                                           REGNO_REG_CLASS (REGNO (SET_DEST (set))))
-#endif
-             )
+         if (extend_op != UNKNOWN
+             && REG_CAN_CHANGE_MODE_P (REGNO (SET_DEST (set)),
+                                       GET_MODE (SET_DEST (set)), word_mode))
            {
              rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
              ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
@@ -426,17 +408,18 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
       CLEAR_HARD_REG_SET (equiv_regs[i]);
 
       /* cselib blows up on CODE_LABELs.  Trying to fix that doesn't seem
-        right, so avoid the problem here.  Likewise if we have a constant
-         and the insn pattern doesn't tell us the mode we need.  */
+        right, so avoid the problem here.  Similarly NOTE_INSN_DELETED_LABEL.
+        Likewise if we have a constant and the insn pattern doesn't tell us
+        the mode we need.  */
       if (LABEL_P (recog_data.operand[i])
+         || (NOTE_P (recog_data.operand[i])
+             && NOTE_KIND (recog_data.operand[i]) == NOTE_INSN_DELETED_LABEL)
          || (CONSTANT_P (recog_data.operand[i])
              && recog_data.operand_mode[i] == VOIDmode))
        continue;
 
       op = recog_data.operand[i];
-      if (MEM_P (op)
-         && GET_MODE_BITSIZE (GET_MODE (op)) < BITS_PER_WORD
-         && LOAD_EXTEND_OP (GET_MODE (op)) != UNKNOWN)
+      if (MEM_P (op) && load_extend_op (GET_MODE (op)) != UNKNOWN)
        {
          rtx set = single_set (insn);
 
@@ -453,15 +436,13 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
                   || GET_CODE (SET_SRC (set)) == ZERO_EXTEND
                   || GET_CODE (SET_SRC (set)) == SIGN_EXTEND)
            ; /* Continue ordinary processing.  */
-#ifdef CANNOT_CHANGE_MODE_CLASS
          /* If the register cannot change mode to word_mode, it follows that
             it cannot have been used in word_mode.  */
          else if (REG_P (SET_DEST (set))
-                  && CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
-                                               word_mode,
-                                               REGNO_REG_CLASS (REGNO (SET_DEST (set)))))
+                  && !REG_CAN_CHANGE_MODE_P (REGNO (SET_DEST (set)),
+                                             GET_MODE (SET_DEST (set)),
+                                             word_mode))
            ; /* Continue ordinary processing.  */
-#endif
          /* If this is a straight load, make the extension explicit.  */
          else if (REG_P (SET_DEST (set))
                   && recog_data.n_operands == 2
@@ -469,7 +450,7 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
                   && SET_DEST (set) == recog_data.operand[1-i])
            {
              validate_change (insn, recog_data.operand_loc[i],
-                              gen_rtx_fmt_e (LOAD_EXTEND_OP (GET_MODE (op)),
+                              gen_rtx_fmt_e (load_extend_op (GET_MODE (op)),
                                              word_mode, op),
                               1);
              validate_change (insn, recog_data.operand_loc[1-i],
@@ -689,7 +670,8 @@ struct reg_use
    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 encountered) that sets or clobbers the register.
-   REAL_STORE_RUID is similar, but clobbers are ignored when updating it.  */
+   REAL_STORE_RUID is similar, but clobbers are ignored when updating it.
+   EXPR is the expression used when storing the register.  */
 static struct
   {
     struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
@@ -699,6 +681,7 @@ static struct
     int real_store_ruid;
     int use_ruid;
     bool all_offsets_match;
+    rtx expr;
   } reg_state[FIRST_PSEUDO_REGISTER];
 
 /* Reverse linear uid.  This is increased in reload_combine while scanning
@@ -858,7 +841,7 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx_insn *from, rtx_insn *to)
     {
       rtx t;
 
-      if (!DEBUG_INSN_P (insn))
+      if (!DEBUG_BIND_INSN_P (insn))
        continue;
       
       t = INSN_VAR_LOCATION_LOC (insn);
@@ -1075,7 +1058,6 @@ static bool
 reload_combine_recognize_pattern (rtx_insn *insn)
 {
   rtx set, reg, src;
-  unsigned int regno;
 
   set = single_set (insn);
   if (set == NULL_RTX)
@@ -1086,7 +1068,20 @@ reload_combine_recognize_pattern (rtx_insn *insn)
   if (!REG_P (reg) || REG_NREGS (reg) != 1)
     return false;
 
-  regno = REGNO (reg);
+  unsigned int regno = REGNO (reg);
+  machine_mode mode = GET_MODE (reg);
+
+  if (reg_state[regno].use_index < 0
+      || reg_state[regno].use_index >= RELOAD_COMBINE_MAX_USES)
+    return false;
+
+  for (int i = reg_state[regno].use_index;
+       i < RELOAD_COMBINE_MAX_USES; i++)
+    {
+      struct reg_use *use = reg_state[regno].reg_use + i;
+      if (GET_MODE (*use->usep) != mode)
+       return false;
+    }
 
   /* Look for (set (REGX) (CONST_INT))
      (set (REGX) (PLUS (REGX) (REGY)))
@@ -1108,8 +1103,6 @@ reload_combine_recognize_pattern (rtx_insn *insn)
       && REG_P (XEXP (src, 1))
       && rtx_equal_p (XEXP (src, 0), reg)
       && !rtx_equal_p (XEXP (src, 1), reg)
-      && reg_state[regno].use_index >= 0
-      && reg_state[regno].use_index < RELOAD_COMBINE_MAX_USES
       && last_label_ruid < reg_state[regno].use_ruid)
     {
       rtx base = XEXP (src, 1);
@@ -1145,7 +1138,7 @@ reload_combine_recognize_pattern (rtx_insn *insn)
                  && (call_used_regs[i] || df_regs_ever_live_p (i))
                  && (!frame_pointer_needed || i != HARD_FRAME_POINTER_REGNUM)
                  && !fixed_regs[i] && !global_regs[i]
-                 && hard_regno_nregs[i][GET_MODE (reg)] == 1
+                 && hard_regno_nregs (i, GET_MODE (reg)) == 1
                  && targetm.hard_regno_scratch_ok (i))
                {
                  index_reg = gen_rtx_REG (GET_MODE (reg), i);
@@ -1169,11 +1162,13 @@ reload_combine_recognize_pattern (rtx_insn *insn)
             value in PREV, the constant loading instruction.  */
          validate_change (prev, &SET_DEST (prev_set), index_reg, 1);
          if (reg_state[regno].offset != const0_rtx)
-           validate_change (prev,
-                            &SET_SRC (prev_set),
-                            GEN_INT (INTVAL (SET_SRC (prev_set))
-                                     + INTVAL (reg_state[regno].offset)),
-                            1);
+           {
+             HOST_WIDE_INT c
+               = trunc_int_for_mode (UINTVAL (SET_SRC (prev_set))
+                                     + UINTVAL (reg_state[regno].offset),
+                                     GET_MODE (index_reg));
+             validate_change (prev, &SET_SRC (prev_set), GEN_INT (c), 1);
+           }
 
          /* Now for every use of REG that we have recorded, replace REG
             with REG_SUM.  */
@@ -1206,10 +1201,11 @@ reload_combine_recognize_pattern (rtx_insn *insn)
              /* Delete the reg-reg addition.  */
              delete_insn (insn);
 
-             if (reg_state[regno].offset != const0_rtx)
-               /* Previous REG_EQUIV / REG_EQUAL notes for PREV
-                  are now invalid.  */
-               remove_reg_equal_equiv_notes (prev);
+             if (reg_state[regno].offset != const0_rtx
+                 /* Previous REG_EQUIV / REG_EQUAL notes for PREV
+                    are now invalid.  */
+                 && remove_reg_equal_equiv_notes (prev))
+               df_notes_rescan (prev);
 
              reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
              return true;
@@ -1350,6 +1346,10 @@ reload_combine (void)
            {
              rtx setuse = XEXP (link, 0);
              rtx usage_rtx = XEXP (setuse, 0);
+             /* We could support CLOBBER_HIGH and treat it in the same way as
+                HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet.  */
+             gcc_assert (GET_CODE (setuse) != CLOBBER_HIGH);
+
              if ((GET_CODE (setuse) == USE || GET_CODE (setuse) == CLOBBER)
                  && REG_P (usage_rtx))
                {
@@ -1461,7 +1461,7 @@ reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
   if (GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
       || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
     {
-      for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
+      for (i = end_hard_regno (mode, regno) - 1; i >= regno; i--)
        {
          reg_state[i].use_index = -1;
          reg_state[i].store_ruid = reload_combine_ruid;
@@ -1470,7 +1470,7 @@ reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
     }
   else
     {
-      for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
+      for (i = end_hard_regno (mode, regno) - 1; i >= regno; i--)
        {
          reg_state[i].store_ruid = reload_combine_ruid;
          if (GET_CODE (set) == SET)
@@ -1525,6 +1525,10 @@ reload_combine_note_use (rtx *xp, rtx_insn *insn, int ruid, rtx containing_mem)
        }
       break;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P (SET_DEST (x)));
+      return;
+
     case PLUS:
       /* We are interested in (plus (reg) (const_int)) .  */
       if (!REG_P (XEXP (x, 0))
@@ -1700,22 +1704,24 @@ move2add_record_sym_value (rtx reg, rtx sym, rtx off)
 /* Check if REGNO contains a valid value in MODE.  */
 
 static bool
-move2add_valid_value_p (int regno, machine_mode mode)
+move2add_valid_value_p (int regno, scalar_int_mode mode)
 {
   if (reg_set_luid[regno] <= move2add_last_label_luid)
     return false;
 
   if (mode != reg_mode[regno])
     {
-      if (!MODES_OK_FOR_MOVE2ADD (mode, reg_mode[regno]))
+      scalar_int_mode old_mode;
+      if (!is_a <scalar_int_mode> (reg_mode[regno], &old_mode)
+         || !MODES_OK_FOR_MOVE2ADD (mode, old_mode))
        return false;
       /* The value loaded into regno in reg_mode[regno] is also valid in
         mode after truncation only if (REG:mode regno) is the lowpart of
         (REG:reg_mode[regno] regno).  Now, for big endian, the starting
         regno of the lowpart might be different.  */
-      int s_off = subreg_lowpart_offset (mode, reg_mode[regno]);
-      s_off = subreg_regno_offset (regno, reg_mode[regno], s_off, mode);
-      if (s_off != 0)
+      poly_int64 s_off = subreg_lowpart_offset (mode, old_mode);
+      s_off = subreg_regno_offset (regno, old_mode, s_off, mode);
+      if (maybe_ne (s_off, 0))
        /* We could in principle adjust regno, check reg_mode[regno] to be
           BLKmode, and return s_off to the caller (vs. -1 for failure),
           but we currently have no callers that could make use of this
@@ -1723,27 +1729,27 @@ move2add_valid_value_p (int regno, machine_mode mode)
        return false;
     }
 
-  for (int i = hard_regno_nregs[regno][mode] - 1; i > 0; i--)
-    if (reg_mode[regno + i] != BLKmode)
+  for (int i = end_hard_regno (mode, regno) - 1; i > regno; i--)
+    if (reg_mode[i] != BLKmode)
       return false;
   return true;
 }
 
-/* This function is called with INSN that sets REG to (SYM + OFF),
-   while REG is known to already have value (SYM + offset).
+/* This function is called with INSN that sets REG (of mode MODE)
+   to (SYM + OFF), while REG is known to already have value (SYM + offset).
    This function tries to change INSN into an add instruction
    (set (REG) (plus (REG) (OFF - offset))) using the known value.
    It also updates the information about REG's known value.
    Return true if we made a change.  */
 
 static bool
-move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx_insn *insn)
+move2add_use_add2_insn (scalar_int_mode mode, rtx reg, rtx sym, rtx off,
+                       rtx_insn *insn)
 {
   rtx pat = PATTERN (insn);
   rtx src = SET_SRC (pat);
   int regno = REGNO (reg);
-  rtx new_src = gen_int_mode (UINTVAL (off) - reg_offset[regno],
-                             GET_MODE (reg));
+  rtx new_src = gen_int_mode (UINTVAL (off) - reg_offset[regno], mode);
   bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
   bool changed = false;
 
@@ -1765,7 +1771,7 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx_insn *insn)
   else
     {
       struct full_rtx_costs oldcst, newcst;
-      rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
+      rtx tem = gen_rtx_PLUS (mode, reg, new_src);
 
       get_full_set_rtx_cost (pat, &oldcst);
       SET_SRC (pat) = tem;
@@ -1775,13 +1781,10 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx_insn *insn)
       if (costs_lt_p (&newcst, &oldcst, speed)
          && have_add2_insn (reg, new_src))
        changed = validate_change (insn, &SET_SRC (pat), tem, 0);       
-      else if (sym == NULL_RTX && GET_MODE (reg) != BImode)
+      else if (sym == NULL_RTX && mode != BImode)
        {
-         machine_mode narrow_mode;
-         for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-              narrow_mode != VOIDmode
-                && narrow_mode != GET_MODE (reg);
-              narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
+         scalar_int_mode narrow_mode;
+         FOR_EACH_MODE_UNTIL (narrow_mode, mode)
            {
              if (have_insn_for (STRICT_LOW_PART, narrow_mode)
                  && ((reg_offset[regno] & ~GET_MODE_MASK (narrow_mode))
@@ -1811,9 +1814,9 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx_insn *insn)
 }
 
 
-/* This function is called with INSN that sets REG to (SYM + OFF),
-   but REG doesn't have known value (SYM + offset).  This function
-   tries to find another register which is known to already have
+/* This function is called with INSN that sets REG (of mode MODE) to
+   (SYM + OFF), but REG doesn't have known value (SYM + offset).  This
+   function tries to find another register which is known to already have
    value (SYM + offset) and change INSN into an add instruction
    (set (REG) (plus (the found register) (OFF - offset))) if such
    a register is found.  It also updates the information about
@@ -1821,7 +1824,8 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx_insn *insn)
    Return true iff we made a change.  */
 
 static bool
-move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx_insn *insn)
+move2add_use_add3_insn (scalar_int_mode mode, rtx reg, rtx sym, rtx off,
+                       rtx_insn *insn)
 {
   rtx pat = PATTERN (insn);
   rtx src = SET_SRC (pat);
@@ -1840,7 +1844,7 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx_insn *insn)
   SET_SRC (pat) = plus_expr;
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (move2add_valid_value_p (i, GET_MODE (reg))
+    if (move2add_valid_value_p (i, mode)
        && reg_base_reg[i] < 0
        && reg_symbol_ref[i] != NULL_RTX
        && rtx_equal_p (sym, reg_symbol_ref[i]))
@@ -1930,8 +1934,10 @@ reload_cse_move2add (rtx_insn *first)
       pat = PATTERN (insn);
       /* For simplicity, we only perform this optimization on
         straightforward SETs.  */
+      scalar_int_mode mode;
       if (GET_CODE (pat) == SET
-         && REG_P (SET_DEST (pat)))
+         && REG_P (SET_DEST (pat))
+         && is_a <scalar_int_mode> (GET_MODE (SET_DEST (pat)), &mode))
        {
          rtx reg = SET_DEST (pat);
          int regno = REGNO (reg);
@@ -1939,7 +1945,7 @@ reload_cse_move2add (rtx_insn *first)
 
          /* Check if we have valid information on the contents of this
             register in the mode of REG.  */
-         if (move2add_valid_value_p (regno, GET_MODE (reg))
+         if (move2add_valid_value_p (regno, mode)
               && dbg_cnt (cse2_move2add))
            {
              /* Try to transform (set (REGX) (CONST_INT A))
@@ -1959,7 +1965,8 @@ reload_cse_move2add (rtx_insn *first)
                  && reg_base_reg[regno] < 0
                  && reg_symbol_ref[regno] == NULL_RTX)
                {
-                 changed |= move2add_use_add2_insn (reg, NULL_RTX, src, insn);
+                 changed |= move2add_use_add2_insn (mode, reg, NULL_RTX,
+                                                    src, insn);
                  continue;
                }
 
@@ -1976,7 +1983,7 @@ reload_cse_move2add (rtx_insn *first)
              else if (REG_P (src)
                       && reg_set_luid[regno] == reg_set_luid[REGNO (src)]
                       && reg_base_reg[regno] == reg_base_reg[REGNO (src)]
-                      && move2add_valid_value_p (REGNO (src), GET_MODE (reg)))
+                      && move2add_valid_value_p (REGNO (src), mode))
                {
                  rtx_insn *next = next_nonnote_nondebug_insn (insn);
                  rtx set = NULL_RTX;
@@ -1996,7 +2003,7 @@ reload_cse_move2add (rtx_insn *first)
                        gen_int_mode (added_offset
                                      + base_offset
                                      - regno_offset,
-                                     GET_MODE (reg));
+                                     mode);
                      bool success = false;
                      bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
 
@@ -2008,11 +2015,11 @@ reload_cse_move2add (rtx_insn *first)
                        {
                          rtx old_src = SET_SRC (set);
                          struct full_rtx_costs oldcst, newcst;
-                         rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
+                         rtx tem = gen_rtx_PLUS (mode, reg, new_src);
 
                          get_full_set_rtx_cost (set, &oldcst);
                          SET_SRC (set) = tem;
-                         get_full_set_src_cost (tem, GET_MODE (reg), &newcst);
+                         get_full_set_src_cost (tem, mode, &newcst);
                          SET_SRC (set) = old_src;
                          costs_add_n_insns (&oldcst, 1);
 
@@ -2032,7 +2039,7 @@ reload_cse_move2add (rtx_insn *first)
                      move2add_record_mode (reg);
                      reg_offset[regno]
                        = trunc_int_for_mode (added_offset + base_offset,
-                                             GET_MODE (reg));
+                                             mode);
                      continue;
                    }
                }
@@ -2068,16 +2075,16 @@ reload_cse_move2add (rtx_insn *first)
 
              /* If the reg already contains the value which is sum of
                 sym and some constant value, we can use an add2 insn.  */
-             if (move2add_valid_value_p (regno, GET_MODE (reg))
+             if (move2add_valid_value_p (regno, mode)
                  && reg_base_reg[regno] < 0
                  && reg_symbol_ref[regno] != NULL_RTX
                  && rtx_equal_p (sym, reg_symbol_ref[regno]))
-               changed |= move2add_use_add2_insn (reg, sym, off, insn);
+               changed |= move2add_use_add2_insn (mode, reg, sym, off, insn);
 
              /* Otherwise, we have to find a register whose value is sum
                 of sym and some constant value.  */
              else
-               changed |= move2add_use_add3_insn (reg, sym, off, insn);
+               changed |= move2add_use_add3_insn (mode, reg, sym, off, insn);
 
              continue;
            }
@@ -2141,6 +2148,9 @@ reload_cse_move2add (rtx_insn *first)
            {
              rtx setuse = XEXP (link, 0);
              rtx usage_rtx = XEXP (setuse, 0);
+             /* CALL_INSN_FUNCTION_USAGEs can only have full clobbers, not
+                clobber_highs.  */
+             gcc_assert (GET_CODE (setuse) != CLOBBER_HIGH);
              if (GET_CODE (setuse) == CLOBBER
                  && REG_P (usage_rtx))
                {
@@ -2165,7 +2175,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
 {
   rtx_insn *insn = (rtx_insn *) data;
   unsigned int regno = 0;
-  machine_mode mode = GET_MODE (dst);
+  scalar_int_mode mode;
 
   /* Some targets do argument pushes without adding REG_INC notes.  */
 
@@ -2185,8 +2195,10 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
   else
     return;
 
-  if (SCALAR_INT_MODE_P (mode)
-      && GET_CODE (set) == SET)
+  if (!is_a <scalar_int_mode> (GET_MODE (dst), &mode))
+    goto invalidate;
+
+  if (GET_CODE (set) == SET)
     {
       rtx note, sym = NULL_RTX;
       rtx off;
@@ -2213,8 +2225,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
        }
     }
 
-  if (SCALAR_INT_MODE_P (mode)
-      && GET_CODE (set) == SET
+  if (GET_CODE (set) == SET
       && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
       && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
     {
@@ -2302,6 +2313,13 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
 
       move2add_record_mode (dst);
     }
+  else if (GET_CODE (set) == CLOBBER_HIGH)
+    {
+      /* Only invalidate if actually clobbered.  */
+      if (reg_mode[regno] == BLKmode
+         || reg_is_clobbered_by_clobber_high (regno, reg_mode[regno], dst))
+        goto invalidate;
+    }
   else
     {
     invalidate: