aboutsummaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch')
-rw-r--r--meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch1500
1 files changed, 1500 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch
new file mode 100644
index 0000000000..cec7f57d47
--- /dev/null
+++ b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch
@@ -0,0 +1,1500 @@
+2010-11-16 Chung-Lin Tang <cltang@codesourcery.com>
+
+ 2010-07-21 Richard Henderson <rth@redhat.com>
+
+ gcc/
+ * config/i386/i386.c (setup_incoming_varargs_64): Emit a simple
+ comparison for avoiding xmm register saves. Emit the xmm register
+ saves explicitly.
+ * config/i386/i386.md (UNSPEC_SSE_PROLOGUE_SAVE): Remove.
+ (UNSPEC_SSE_PROLOGUE_SAVE_LOW): Remove.
+ (sse_prologue_save, sse_prologue_save_insn1, sse_prologue_save_insn):
+ Remove patterns and the associated splitters.
+
+ 2010-07-22 Richard Henderson <rth@redhat.com>
+
+ gcc/
+ PR target/45027
+ * config/i386/i386.c (setup_incoming_varargs_64): Force the use
+ of V4SFmode for the SSE saves; increase stack alignment if needed.
+
+2010-11-16 Chung-Lin Tang <cltang@codesourcery.com>
+
+ Re-merge, backport from mainline:
+
+ 2010-07-15 Bernd Schmidt <bernds@codesourcery.com>
+
+ gcc/
+ * postreload.c (last_label_ruid, first_index_reg, last_index_reg):
+ New static variables.
+ (reload_combine_recognize_pattern): New static function, broken out
+ of reload_combine.
+ (reload_combine): Use it. Only initialize first_index_reg and
+ last_index_reg once.
+
+ 2010-07-17 Bernd Schmidt <bernds@codesourcery.com>
+
+ PR target/42235
+ gcc/
+ * postreload.c (reload_cse_move2add): Return bool, true if anything.
+ changed. All callers changed.
+ (move2add_use_add2_insn): Likewise.
+ (move2add_use_add3_insn): Likewise.
+ (reload_cse_regs): If reload_cse_move2add changed anything, rerun
+ reload_combine.
+ (RELOAD_COMBINE_MAX_USES): Bump to 16.
+ (last_jump_ruid): New static variable.
+ (struct reg_use): New members CONTAINING_MEM and RUID.
+ (reg_state): New members ALL_OFFSETS_MATCH and REAL_STORE_RUID.
+ (reload_combine_split_one_ruid, reload_combine_split_ruids,
+ reload_combine_purge_insn_uses, reload_combine_closest_single_use
+ reload_combine_purge_reg_uses_after_ruid,
+ reload_combine_recognize_const_pattern): New static functions.
+ (reload_combine_recognize_pattern): Verify that ALL_OFFSETS_MATCH
+ is true for our reg and that we have available index regs.
+ (reload_combine_note_use): New args RUID and CONTAINING_MEM. All
+ callers changed. Use them to initialize fields in struct reg_use.
+ (reload_combine): Initialize last_jump_ruid. Be careful when to
+ take PREV_INSN of the scanned insn. Update REAL_STORE_RUID fields.
+ Call reload_combine_recognize_const_pattern.
+ (reload_combine_note_store): Update REAL_STORE_RUID field.
+
+ gcc/testsuite/
+ * gcc.target/arm/pr42235.c: New test.
+
+ 2010-07-19 Bernd Schmidt <bernds@codesourcery.com>
+
+ gcc/
+ * postreload.c (reload_combine_closest_single_use): Ignore the
+ number of uses for DEBUG_INSNs.
+ (fixup_debug_insns): New static function.
+ (reload_combine_recognize_const_pattern): Use it. Don't let the
+ main loop be affected by DEBUG_INSNs.
+ Really disallow moving adds past a jump insn.
+ (reload_combine_recognize_pattern): Don't update use_ruid here.
+ (reload_combine_note_use): Do it here.
+ (reload_combine): Use control_flow_insn_p rather than JUMP_P.
+
+ 2010-07-20 Bernd Schmidt <bernds@codesourcery.com>
+
+ gcc/
+ * postreload.c (fixup_debug_insns): Remove arg REGNO. New args
+ FROM and TO. All callers changed. Don't look for tracked uses,
+ just scan the RTL for DEBUG_INSNs and substitute.
+ (reload_combine_recognize_pattern): Call fixup_debug_insns.
+ (reload_combine): Ignore DEBUG_INSNs.
+
+ 2010-07-22 Bernd Schmidt <bernds@codesourcery.com>
+
+ PR bootstrap/44970
+ PR middle-end/45009
+ gcc/
+ * postreload.c: Include "target.h".
+ (reload_combine_closest_single_use): Don't take DEBUG_INSNs
+ into account.
+ (fixup_debug_insns): Don't copy the rtx.
+ (reload_combine_recognize_const_pattern): DEBUG_INSNs can't have uses.
+ Don't copy when replacing. Call fixup_debug_insns in the case where
+ we merged one add with another.
+ (reload_combine_recognize_pattern): Fail if there aren't any uses.
+ Try harder to determine whether we're picking a valid index register.
+ Don't set store_ruid for an insn we're going to scan in the
+ next iteration.
+ (reload_combine): Remove unused code.
+ (reload_combine_note_use): When updating use information for
+ an old insn, ignore a use that occurs after store_ruid.
+ * Makefile.in (postreload.o): Update dependencies.
+
+ 2010-07-27 Bernd Schmidt <bernds@codesourcery.com>
+
+ gcc/
+ * postreload.c (reload_combine_recognize_const_pattern): Move test
+ for limiting the insn movement to the right scope.
+
+ 2010-07-27 Bernd Schmidt <bernds@codesourcery.com>
+
+ gcc/
+ * postreload.c (try_replace_in_use): New static function.
+ (reload_combine_recognize_const_pattern): Use it here. Allow
+ substituting into a final add insn, and substituting into a memory
+ reference in an insn that sets the reg.
+
+=== modified file 'gcc/Makefile.in'
+--- old/gcc/Makefile.in 2010-11-11 11:34:59 +0000
++++ new/gcc/Makefile.in 2010-11-16 18:05:53 +0000
+@@ -3157,7 +3157,7 @@
+ $(RTL_H) $(REAL_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) \
+ hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) $(RECOG_H) output.h \
+ $(FUNCTION_H) $(TOPLEV_H) cselib.h $(TM_P_H) $(EXCEPT_H) $(TREE_H) $(MACHMODE_H) \
+- $(OBSTACK_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H)
++ $(OBSTACK_H) $(TARGET_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H)
+ postreload-gcse.o : postreload-gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+ $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
+ $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h $(TOPLEV_H) \
+
+=== modified file 'gcc/config/i386/i386.c'
+--- old/gcc/config/i386/i386.c 2010-09-30 20:24:54 +0000
++++ new/gcc/config/i386/i386.c 2010-11-16 18:05:53 +0000
+@@ -6737,12 +6737,8 @@
+ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum)
+ {
+ rtx save_area, mem;
+- rtx label;
+- rtx label_ref;
+- rtx tmp_reg;
+- rtx nsse_reg;
+ alias_set_type set;
+- int i;
++ int i, max;
+
+ /* GPR size of varargs save area. */
+ if (cfun->va_list_gpr_size)
+@@ -6752,7 +6748,7 @@
+
+ /* FPR size of varargs save area. We don't need it if we don't pass
+ anything in SSE registers. */
+- if (cum->sse_nregs && cfun->va_list_fpr_size)
++ if (TARGET_SSE && cfun->va_list_fpr_size)
+ ix86_varargs_fpr_size = X86_64_SSE_REGPARM_MAX * 16;
+ else
+ ix86_varargs_fpr_size = 0;
+@@ -6763,10 +6759,11 @@
+ save_area = frame_pointer_rtx;
+ set = get_varargs_alias_set ();
+
+- for (i = cum->regno;
+- i < X86_64_REGPARM_MAX
+- && i < cum->regno + cfun->va_list_gpr_size / UNITS_PER_WORD;
+- i++)
++ max = cum->regno + cfun->va_list_gpr_size / UNITS_PER_WORD;
++ if (max > X86_64_REGPARM_MAX)
++ max = X86_64_REGPARM_MAX;
++
++ for (i = cum->regno; i < max; i++)
+ {
+ mem = gen_rtx_MEM (Pmode,
+ plus_constant (save_area, i * UNITS_PER_WORD));
+@@ -6778,62 +6775,42 @@
+
+ if (ix86_varargs_fpr_size)
+ {
+- /* Stack must be aligned to 16byte for FP register save area. */
+- if (crtl->stack_alignment_needed < 128)
+- crtl->stack_alignment_needed = 128;
++ enum machine_mode smode;
++ rtx label, test;
+
+ /* Now emit code to save SSE registers. The AX parameter contains number
+- of SSE parameter registers used to call this function. We use
+- sse_prologue_save insn template that produces computed jump across
+- SSE saves. We need some preparation work to get this working. */
++ of SSE parameter registers used to call this function, though all we
++ actually check here is the zero/non-zero status. */
+
+ label = gen_label_rtx ();
+- label_ref = gen_rtx_LABEL_REF (Pmode, label);
+-
+- /* Compute address to jump to :
+- label - eax*4 + nnamed_sse_arguments*4 Or
+- label - eax*5 + nnamed_sse_arguments*5 for AVX. */
+- tmp_reg = gen_reg_rtx (Pmode);
+- nsse_reg = gen_reg_rtx (Pmode);
+- emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, AX_REG)));
+- emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
+- gen_rtx_MULT (Pmode, nsse_reg,
+- GEN_INT (4))));
+-
+- /* vmovaps is one byte longer than movaps. */
+- if (TARGET_AVX)
+- emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
+- gen_rtx_PLUS (Pmode, tmp_reg,
+- nsse_reg)));
+-
+- if (cum->sse_regno)
+- emit_move_insn
+- (nsse_reg,
+- gen_rtx_CONST (DImode,
+- gen_rtx_PLUS (DImode,
+- label_ref,
+- GEN_INT (cum->sse_regno
+- * (TARGET_AVX ? 5 : 4)))));
+- else
+- emit_move_insn (nsse_reg, label_ref);
+- emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg));
+-
+- /* Compute address of memory block we save into. We always use pointer
+- pointing 127 bytes after first byte to store - this is needed to keep
+- instruction size limited by 4 bytes (5 bytes for AVX) with one
+- byte displacement. */
+- tmp_reg = gen_reg_rtx (Pmode);
+- emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
+- plus_constant (save_area,
+- ix86_varargs_gpr_size + 127)));
+- mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127));
+- MEM_NOTRAP_P (mem) = 1;
+- set_mem_alias_set (mem, set);
+- set_mem_align (mem, BITS_PER_WORD);
+-
+- /* And finally do the dirty job! */
+- emit_insn (gen_sse_prologue_save (mem, nsse_reg,
+- GEN_INT (cum->sse_regno), label));
++ test = gen_rtx_EQ (VOIDmode, gen_rtx_REG (QImode, AX_REG), const0_rtx);
++ emit_jump_insn (gen_cbranchqi4 (test, XEXP (test, 0), XEXP (test, 1),
++ label));
++
++ /* ??? If !TARGET_SSE_TYPELESS_STORES, would we perform better if
++ we used movdqa (i.e. TImode) instead? Perhaps even better would
++ be if we could determine the real mode of the data, via a hook
++ into pass_stdarg. Ignore all that for now. */
++ smode = V4SFmode;
++ if (crtl->stack_alignment_needed < GET_MODE_ALIGNMENT (smode))
++ crtl->stack_alignment_needed = GET_MODE_ALIGNMENT (smode);
++
++ max = cum->sse_regno + cfun->va_list_fpr_size / 16;
++ if (max > X86_64_SSE_REGPARM_MAX)
++ max = X86_64_SSE_REGPARM_MAX;
++
++ for (i = cum->sse_regno; i < max; ++i)
++ {
++ mem = plus_constant (save_area, i * 16 + ix86_varargs_gpr_size);
++ mem = gen_rtx_MEM (smode, mem);
++ MEM_NOTRAP_P (mem) = 1;
++ set_mem_alias_set (mem, set);
++ set_mem_align (mem, GET_MODE_ALIGNMENT (smode));
++
++ emit_move_insn (mem, gen_rtx_REG (smode, SSE_REGNO (i)));
++ }
++
++ emit_label (label);
+ }
+ }
+
+
+=== modified file 'gcc/config/i386/i386.md'
+--- old/gcc/config/i386/i386.md 2010-10-22 04:56:41 +0000
++++ new/gcc/config/i386/i386.md 2010-11-27 15:24:12 +0000
+@@ -80,7 +80,6 @@
+ ; Prologue support
+ (UNSPEC_STACK_ALLOC 11)
+ (UNSPEC_SET_GOT 12)
+- (UNSPEC_SSE_PROLOGUE_SAVE 13)
+ (UNSPEC_REG_SAVE 14)
+ (UNSPEC_DEF_CFA 15)
+ (UNSPEC_SET_RIP 16)
+@@ -20252,74 +20251,6 @@
+ { return ASM_SHORT "0x0b0f"; }
+ [(set_attr "length" "2")])
+
+-(define_expand "sse_prologue_save"
+- [(parallel [(set (match_operand:BLK 0 "" "")
+- (unspec:BLK [(reg:DI XMM0_REG)
+- (reg:DI XMM1_REG)
+- (reg:DI XMM2_REG)
+- (reg:DI XMM3_REG)
+- (reg:DI XMM4_REG)
+- (reg:DI XMM5_REG)
+- (reg:DI XMM6_REG)
+- (reg:DI XMM7_REG)] UNSPEC_SSE_PROLOGUE_SAVE))
+- (use (match_operand:DI 1 "register_operand" ""))
+- (use (match_operand:DI 2 "immediate_operand" ""))
+- (use (label_ref:DI (match_operand 3 "" "")))])]
+- "TARGET_64BIT"
+- "")
+-
+-(define_insn "*sse_prologue_save_insn"
+- [(set (mem:BLK (plus:DI (match_operand:DI 0 "register_operand" "R")
+- (match_operand:DI 4 "const_int_operand" "n")))
+- (unspec:BLK [(reg:DI XMM0_REG)
+- (reg:DI XMM1_REG)
+- (reg:DI XMM2_REG)
+- (reg:DI XMM3_REG)
+- (reg:DI XMM4_REG)
+- (reg:DI XMM5_REG)
+- (reg:DI XMM6_REG)
+- (reg:DI XMM7_REG)] UNSPEC_SSE_PROLOGUE_SAVE))
+- (use (match_operand:DI 1 "register_operand" "r"))
+- (use (match_operand:DI 2 "const_int_operand" "i"))
+- (use (label_ref:DI (match_operand 3 "" "X")))]
+- "TARGET_64BIT
+- && INTVAL (operands[4]) + X86_64_SSE_REGPARM_MAX * 16 - 16 < 128
+- && INTVAL (operands[4]) + INTVAL (operands[2]) * 16 >= -128"
+-{
+- int i;
+- operands[0] = gen_rtx_MEM (Pmode,
+- gen_rtx_PLUS (Pmode, operands[0], operands[4]));
+- /* VEX instruction with a REX prefix will #UD. */
+- if (TARGET_AVX && GET_CODE (XEXP (operands[0], 0)) != PLUS)
+- gcc_unreachable ();
+-
+- output_asm_insn ("jmp\t%A1", operands);
+- for (i = X86_64_SSE_REGPARM_MAX - 1; i >= INTVAL (operands[2]); i--)
+- {
+- operands[4] = adjust_address (operands[0], DImode, i*16);
+- operands[5] = gen_rtx_REG (TImode, SSE_REGNO (i));
+- PUT_MODE (operands[4], TImode);
+- if (GET_CODE (XEXP (operands[0], 0)) != PLUS)
+- output_asm_insn ("rex", operands);
+- output_asm_insn ("%vmovaps\t{%5, %4|%4, %5}", operands);
+- }
+- (*targetm.asm_out.internal_label) (asm_out_file, "L",
+- CODE_LABEL_NUMBER (operands[3]));
+- return "";
+-}
+- [(set_attr "type" "other")
+- (set_attr "length_immediate" "0")
+- (set_attr "length_address" "0")
+- (set (attr "length")
+- (if_then_else
+- (eq (symbol_ref "TARGET_AVX") (const_int 0))
+- (const_string "34")
+- (const_string "42")))
+- (set_attr "memory" "store")
+- (set_attr "modrm" "0")
+- (set_attr "prefix" "maybe_vex")
+- (set_attr "mode" "DI")])
+-
+ (define_expand "prefetch"
+ [(prefetch (match_operand 0 "address_operand" "")
+ (match_operand:SI 1 "const_int_operand" "")
+
+=== modified file 'gcc/postreload.c'
+--- old/gcc/postreload.c 2010-11-08 22:08:43 +0000
++++ new/gcc/postreload.c 2010-11-16 18:05:53 +0000
+@@ -44,6 +44,7 @@
+ #include "toplev.h"
+ #include "except.h"
+ #include "tree.h"
++#include "target.h"
+ #include "timevar.h"
+ #include "tree-pass.h"
+ #include "df.h"
+@@ -56,10 +57,10 @@
+ static int reload_cse_simplify_operands (rtx, rtx);
+
+ static void reload_combine (void);
+-static void reload_combine_note_use (rtx *, rtx);
++static void reload_combine_note_use (rtx *, rtx, int, rtx);
+ static void reload_combine_note_store (rtx, const_rtx, void *);
+
+-static void reload_cse_move2add (rtx);
++static bool reload_cse_move2add (rtx);
+ static void move2add_note_store (rtx, const_rtx, void *);
+
+ /* Call cse / combine like post-reload optimization phases.
+@@ -67,11 +68,16 @@
+ void
+ reload_cse_regs (rtx first ATTRIBUTE_UNUSED)
+ {
++ bool moves_converted;
+ reload_cse_regs_1 (first);
+ reload_combine ();
+- reload_cse_move2add (first);
++ moves_converted = reload_cse_move2add (first);
+ if (flag_expensive_optimizations)
+- reload_cse_regs_1 (first);
++ {
++ if (moves_converted)
++ reload_combine ();
++ reload_cse_regs_1 (first);
++ }
+ }
+
+ /* See whether a single set SET is a noop. */
+@@ -660,30 +666,43 @@
+
+ /* The maximum number of uses of a register we can keep track of to
+ replace them with reg+reg addressing. */
+-#define RELOAD_COMBINE_MAX_USES 6
++#define RELOAD_COMBINE_MAX_USES 16
+
+-/* INSN is the insn where a register has been used, and USEP points to the
+- location of the register within the rtl. */
+-struct reg_use { rtx insn, *usep; };
++/* Describes a recorded use of a register. */
++struct reg_use
++{
++ /* The insn where a register has been used. */
++ rtx insn;
++ /* Points to the memory reference enclosing the use, if any, NULL_RTX
++ otherwise. */
++ rtx containing_mem;
++ /* Location of the register withing INSN. */
++ rtx *usep;
++ /* The reverse uid of the insn. */
++ int ruid;
++};
+
+ /* If the register is used in some unknown fashion, USE_INDEX is negative.
+ If it is dead, USE_INDEX is RELOAD_COMBINE_MAX_USES, and STORE_RUID
+- indicates where it becomes live again.
++ indicates where it is first set or clobbered.
+ Otherwise, USE_INDEX is the index of the last encountered use of the
+- register (which is first among these we have seen since we scan backwards),
+- OFFSET contains the constant offset that is added to the register in
+- all encountered uses, and USE_RUID indicates the first encountered, i.e.
+- last, of these uses.
++ register (which is first among these we have seen since we scan backwards).
++ USE_RUID indicates the first encountered, i.e. last, of these uses.
++ If ALL_OFFSETS_MATCH is true, all encountered uses were inside a PLUS
++ with a constant offset; OFFSET contains this constant in that case.
+ 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. */
++ stream (i.e. the last encountered) that sets or clobbers the register.
++ REAL_STORE_RUID is similar, but clobbers are ignored when updating it. */
+ static struct
+ {
+ struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
++ rtx offset;
+ int use_index;
+- rtx offset;
+ int store_ruid;
++ int real_store_ruid;
+ int use_ruid;
++ bool all_offsets_match;
+ } reg_state[FIRST_PSEUDO_REGISTER];
+
+ /* Reverse linear uid. This is increased in reload_combine while scanning
+@@ -691,42 +710,548 @@
+ and the store_ruid / use_ruid fields in reg_state. */
+ static int reload_combine_ruid;
+
++/* The RUID of the last label we encountered in reload_combine. */
++static int last_label_ruid;
++
++/* The RUID of the last jump we encountered in reload_combine. */
++static int last_jump_ruid;
++
++/* The register numbers of the first and last index register. A value of
++ -1 in LAST_INDEX_REG indicates that we've previously computed these
++ values and found no suitable index registers. */
++static int first_index_reg = -1;
++static int last_index_reg;
++
+ #define LABEL_LIVE(LABEL) \
+ (label_live[CODE_LABEL_NUMBER (LABEL) - min_labelno])
+
++/* Subroutine of reload_combine_split_ruids, called to fix up a single
++ ruid pointed to by *PRUID if it is higher than SPLIT_RUID. */
++
++static inline void
++reload_combine_split_one_ruid (int *pruid, int split_ruid)
++{
++ if (*pruid > split_ruid)
++ (*pruid)++;
++}
++
++/* Called when we insert a new insn in a position we've already passed in
++ the scan. Examine all our state, increasing all ruids that are higher
++ than SPLIT_RUID by one in order to make room for a new insn. */
++
++static void
++reload_combine_split_ruids (int split_ruid)
++{
++ unsigned i;
++
++ reload_combine_split_one_ruid (&reload_combine_ruid, split_ruid);
++ reload_combine_split_one_ruid (&last_label_ruid, split_ruid);
++ reload_combine_split_one_ruid (&last_jump_ruid, split_ruid);
++
++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
++ {
++ int j, idx = reg_state[i].use_index;
++ reload_combine_split_one_ruid (&reg_state[i].use_ruid, split_ruid);
++ reload_combine_split_one_ruid (&reg_state[i].store_ruid, split_ruid);
++ reload_combine_split_one_ruid (&reg_state[i].real_store_ruid,
++ split_ruid);
++ if (idx < 0)
++ continue;
++ for (j = idx; j < RELOAD_COMBINE_MAX_USES; j++)
++ {
++ reload_combine_split_one_ruid (&reg_state[i].reg_use[j].ruid,
++ split_ruid);
++ }
++ }
++}
++
++/* Called when we are about to rescan a previously encountered insn with
++ reload_combine_note_use after modifying some part of it. This clears all
++ information about uses in that particular insn. */
++
++static void
++reload_combine_purge_insn_uses (rtx insn)
++{
++ unsigned i;
++
++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
++ {
++ int j, k, idx = reg_state[i].use_index;
++ if (idx < 0)
++ continue;
++ j = k = RELOAD_COMBINE_MAX_USES;
++ while (j-- > idx)
++ {
++ if (reg_state[i].reg_use[j].insn != insn)
++ {
++ k--;
++ if (k != j)
++ reg_state[i].reg_use[k] = reg_state[i].reg_use[j];
++ }
++ }
++ reg_state[i].use_index = k;
++ }
++}
++
++/* Called when we need to forget about all uses of REGNO after an insn
++ which is identified by RUID. */
++
++static void
++reload_combine_purge_reg_uses_after_ruid (unsigned regno, int ruid)
++{
++ int j, k, idx = reg_state[regno].use_index;
++ if (idx < 0)
++ return;
++ j = k = RELOAD_COMBINE_MAX_USES;
++ while (j-- > idx)
++ {
++ if (reg_state[regno].reg_use[j].ruid >= ruid)
++ {
++ k--;
++ if (k != j)
++ reg_state[regno].reg_use[k] = reg_state[regno].reg_use[j];
++ }
++ }
++ reg_state[regno].use_index = k;
++}
++
++/* Find the use of REGNO with the ruid that is highest among those
++ lower than RUID_LIMIT, and return it if it is the only use of this
++ reg in the insn. Return NULL otherwise. */
++
++static struct reg_use *
++reload_combine_closest_single_use (unsigned regno, int ruid_limit)
++{
++ int i, best_ruid = 0;
++ int use_idx = reg_state[regno].use_index;
++ struct reg_use *retval;
++
++ if (use_idx < 0)
++ return NULL;
++ retval = NULL;
++ for (i = use_idx; i < RELOAD_COMBINE_MAX_USES; i++)
++ {
++ struct reg_use *use = reg_state[regno].reg_use + i;
++ int this_ruid = use->ruid;
++ if (this_ruid >= ruid_limit)
++ continue;
++ if (this_ruid > best_ruid)
++ {
++ best_ruid = this_ruid;
++ retval = use;
++ }
++ else if (this_ruid == best_ruid)
++ retval = NULL;
++ }
++ if (last_label_ruid >= best_ruid)
++ return NULL;
++ return retval;
++}
++
++/* After we've moved an add insn, fix up any debug insns that occur
++ between the old location of the add and the new location. REG is
++ the destination register of the add insn; REPLACEMENT is the
++ SET_SRC of the add. FROM and TO specify the range in which we
++ should make this change on debug insns. */
++
++static void
++fixup_debug_insns (rtx reg, rtx replacement, rtx from, rtx to)
++{
++ rtx insn;
++ for (insn = from; insn != to; insn = NEXT_INSN (insn))
++ {
++ rtx t;
++
++ if (!DEBUG_INSN_P (insn))
++ continue;
++
++ t = INSN_VAR_LOCATION_LOC (insn);
++ t = simplify_replace_rtx (t, reg, replacement);
++ validate_change (insn, &INSN_VAR_LOCATION_LOC (insn), t, 0);
++ }
++}
++
++/* Subroutine of reload_combine_recognize_const_pattern. Try to replace REG
++ with SRC in the insn described by USE, taking costs into account. Return
++ true if we made the replacement. */
++
++static bool
++try_replace_in_use (struct reg_use *use, rtx reg, rtx src)
++{
++ rtx use_insn = use->insn;
++ rtx mem = use->containing_mem;
++ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_insn));
++
++ if (mem != NULL_RTX)
++ {
++ addr_space_t as = MEM_ADDR_SPACE (mem);
++ rtx oldaddr = XEXP (mem, 0);
++ rtx newaddr = NULL_RTX;
++ int old_cost = address_cost (oldaddr, GET_MODE (mem), as, speed);
++ int new_cost;
++
++ newaddr = simplify_replace_rtx (oldaddr, reg, src);
++ if (memory_address_addr_space_p (GET_MODE (mem), newaddr, as))
++ {
++ XEXP (mem, 0) = newaddr;
++ new_cost = address_cost (newaddr, GET_MODE (mem), as, speed);
++ XEXP (mem, 0) = oldaddr;
++ if (new_cost <= old_cost
++ && validate_change (use_insn,
++ &XEXP (mem, 0), newaddr, 0))
++ return true;
++ }
++ }
++ else
++ {
++ rtx new_set = single_set (use_insn);
++ if (new_set
++ && REG_P (SET_DEST (new_set))
++ && GET_CODE (SET_SRC (new_set)) == PLUS
++ && REG_P (XEXP (SET_SRC (new_set), 0))
++ && CONSTANT_P (XEXP (SET_SRC (new_set), 1)))
++ {
++ rtx new_src;
++ int old_cost = rtx_cost (SET_SRC (new_set), SET, speed);
++
++ gcc_assert (rtx_equal_p (XEXP (SET_SRC (new_set), 0), reg));
++ new_src = simplify_replace_rtx (SET_SRC (new_set), reg, src);
++
++ if (rtx_cost (new_src, SET, speed) <= old_cost
++ && validate_change (use_insn, &SET_SRC (new_set),
++ new_src, 0))
++ return true;
++ }
++ }
++ return false;
++}
++
++/* Called by reload_combine when scanning INSN. This function tries to detect
++ patterns where a constant is added to a register, and the result is used
++ in an address.
++ Return true if no further processing is needed on INSN; false if it wasn't
++ recognized and should be handled normally. */
++
++static bool
++reload_combine_recognize_const_pattern (rtx insn)
++{
++ int from_ruid = reload_combine_ruid;
++ rtx set, pat, reg, src, addreg;
++ unsigned int regno;
++ struct reg_use *use;
++ bool must_move_add;
++ rtx add_moved_after_insn = NULL_RTX;
++ int add_moved_after_ruid = 0;
++ int clobbered_regno = -1;
++
++ set = single_set (insn);
++ if (set == NULL_RTX)
++ return false;
++
++ reg = SET_DEST (set);
++ src = SET_SRC (set);
++ if (!REG_P (reg)
++ || hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] != 1
++ || GET_MODE (reg) != Pmode
++ || reg == stack_pointer_rtx)
++ return false;
++
++ regno = REGNO (reg);
++
++ /* We look for a REG1 = REG2 + CONSTANT insn, followed by either
++ uses of REG1 inside an address, or inside another add insn. If
++ possible and profitable, merge the addition into subsequent
++ uses. */
++ if (GET_CODE (src) != PLUS
++ || !REG_P (XEXP (src, 0))
++ || !CONSTANT_P (XEXP (src, 1)))
++ return false;
++
++ addreg = XEXP (src, 0);
++ must_move_add = rtx_equal_p (reg, addreg);
++
++ pat = PATTERN (insn);
++ if (must_move_add && set != pat)
++ {
++ /* We have to be careful when moving the add; apart from the
++ single_set there may also be clobbers. Recognize one special
++ case, that of one clobber alongside the set (likely a clobber
++ of the CC register). */
++ gcc_assert (GET_CODE (PATTERN (insn)) == PARALLEL);
++ if (XVECLEN (pat, 0) != 2 || XVECEXP (pat, 0, 0) != set
++ || GET_CODE (XVECEXP (pat, 0, 1)) != CLOBBER
++ || !REG_P (XEXP (XVECEXP (pat, 0, 1), 0)))
++ return false;
++ clobbered_regno = REGNO (XEXP (XVECEXP (pat, 0, 1), 0));
++ }
++
++ do
++ {
++ use = reload_combine_closest_single_use (regno, from_ruid);
++
++ if (use)
++ /* Start the search for the next use from here. */
++ from_ruid = use->ruid;
++
++ if (use && GET_MODE (*use->usep) == Pmode)
++ {
++ bool delete_add = false;
++ rtx use_insn = use->insn;
++ int use_ruid = use->ruid;
++
++ /* Avoid moving the add insn past a jump. */
++ if (must_move_add && use_ruid <= last_jump_ruid)
++ break;
++
++ /* If the add clobbers another hard reg in parallel, don't move
++ it past a real set of this hard reg. */
++ if (must_move_add && clobbered_regno >= 0
++ && reg_state[clobbered_regno].real_store_ruid >= use_ruid)
++ break;
++
++ gcc_assert (reg_state[regno].store_ruid <= use_ruid);
++ /* Avoid moving a use of ADDREG past a point where it is stored. */
++ if (reg_state[REGNO (addreg)].store_ruid > use_ruid)
++ break;
++
++ /* We also must not move the addition past an insn that sets
++ the same register, unless we can combine two add insns. */
++ if (must_move_add && reg_state[regno].store_ruid == use_ruid)
++ {
++ if (use->containing_mem == NULL_RTX)
++ delete_add = true;
++ else
++ break;
++ }
++
++ if (try_replace_in_use (use, reg, src))
++ {
++ reload_combine_purge_insn_uses (use_insn);
++ reload_combine_note_use (&PATTERN (use_insn), use_insn,
++ use_ruid, NULL_RTX);
++
++ if (delete_add)
++ {
++ fixup_debug_insns (reg, src, insn, use_insn);
++ delete_insn (insn);
++ return true;
++ }
++ if (must_move_add)
++ {
++ add_moved_after_insn = use_insn;
++ add_moved_after_ruid = use_ruid;
++ }
++ continue;
++ }
++ }
++ /* If we get here, we couldn't handle this use. */
++ if (must_move_add)
++ break;
++ }
++ while (use);
++
++ if (!must_move_add || add_moved_after_insn == NULL_RTX)
++ /* Process the add normally. */
++ return false;
++
++ fixup_debug_insns (reg, src, insn, add_moved_after_insn);
++
++ reorder_insns (insn, insn, add_moved_after_insn);
++ reload_combine_purge_reg_uses_after_ruid (regno, add_moved_after_ruid);
++ reload_combine_split_ruids (add_moved_after_ruid - 1);
++ reload_combine_note_use (&PATTERN (insn), insn,
++ add_moved_after_ruid, NULL_RTX);
++ reg_state[regno].store_ruid = add_moved_after_ruid;
++
++ return true;
++}
++
++/* Called by reload_combine when scanning INSN. Try to detect a pattern we
++ can handle and improve. Return true if no further processing is needed on
++ INSN; false if it wasn't recognized and should be handled normally. */
++
++static bool
++reload_combine_recognize_pattern (rtx insn)
++{
++ rtx set, reg, src;
++ unsigned int regno;
++
++ set = single_set (insn);
++ if (set == NULL_RTX)
++ return false;
++
++ reg = SET_DEST (set);
++ src = SET_SRC (set);
++ if (!REG_P (reg)
++ || hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] != 1)
++ return false;
++
++ regno = REGNO (reg);
++
++ /* Look for (set (REGX) (CONST_INT))
++ (set (REGX) (PLUS (REGX) (REGY)))
++ ...
++ ... (MEM (REGX)) ...
++ and convert it to
++ (set (REGZ) (CONST_INT))
++ ...
++ ... (MEM (PLUS (REGZ) (REGY)))... .
++
++ First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
++ and that we know all uses of REGX before it dies.
++ Also, explicitly check that REGX != REGY; our life information
++ does not yet show whether REGY changes in this insn. */
++
++ if (GET_CODE (src) == PLUS
++ && reg_state[regno].all_offsets_match
++ && last_index_reg != -1
++ && 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);
++ rtx prev = prev_nonnote_insn (insn);
++ rtx prev_set = prev ? single_set (prev) : NULL_RTX;
++ rtx index_reg = NULL_RTX;
++ rtx reg_sum = NULL_RTX;
++ int i;
++
++ /* Now we need to set INDEX_REG to an index register (denoted as
++ REGZ in the illustration above) and REG_SUM to the expression
++ register+register that we want to use to substitute uses of REG
++ (typically in MEMs) with. First check REG and BASE for being
++ index registers; we can use them even if they are not dead. */
++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
++ || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
++ REGNO (base)))
++ {
++ index_reg = reg;
++ reg_sum = src;
++ }
++ else
++ {
++ /* Otherwise, look for a free index register. Since we have
++ checked above that neither REG nor BASE are index registers,
++ if we find anything at all, it will be different from these
++ two registers. */
++ for (i = first_index_reg; i <= last_index_reg; i++)
++ {
++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i)
++ && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
++ && reg_state[i].store_ruid <= reg_state[regno].use_ruid
++ && (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
++ && targetm.hard_regno_scratch_ok (i))
++ {
++ index_reg = gen_rtx_REG (GET_MODE (reg), i);
++ reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
++ break;
++ }
++ }
++ }
++
++ /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
++ (REGY), i.e. BASE, is not clobbered before the last use we'll
++ create. */
++ if (reg_sum
++ && prev_set
++ && CONST_INT_P (SET_SRC (prev_set))
++ && rtx_equal_p (SET_DEST (prev_set), reg)
++ && (reg_state[REGNO (base)].store_ruid
++ <= reg_state[regno].use_ruid))
++ {
++ /* Change destination register and, if necessary, the constant
++ 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);
++
++ /* Now for every use of REG that we have recorded, replace REG
++ with REG_SUM. */
++ for (i = reg_state[regno].use_index;
++ i < RELOAD_COMBINE_MAX_USES; i++)
++ validate_unshare_change (reg_state[regno].reg_use[i].insn,
++ reg_state[regno].reg_use[i].usep,
++ /* Each change must have its own
++ replacement. */
++ reg_sum, 1);
++
++ if (apply_change_group ())
++ {
++ struct reg_use *lowest_ruid = NULL;
++
++ /* For every new use of REG_SUM, we have to record the use
++ of BASE therein, i.e. operand 1. */
++ for (i = reg_state[regno].use_index;
++ i < RELOAD_COMBINE_MAX_USES; i++)
++ {
++ struct reg_use *use = reg_state[regno].reg_use + i;
++ reload_combine_note_use (&XEXP (*use->usep, 1), use->insn,
++ use->ruid, use->containing_mem);
++ if (lowest_ruid == NULL || use->ruid < lowest_ruid->ruid)
++ lowest_ruid = use;
++ }
++
++ fixup_debug_insns (reg, reg_sum, insn, lowest_ruid->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);
++
++ reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
++ return true;
++ }
++ }
++ }
++ return false;
++}
++
+ static void
+ reload_combine (void)
+ {
+- rtx insn, set;
+- int first_index_reg = -1;
+- int last_index_reg = 0;
++ rtx insn, prev;
+ int i;
+ basic_block bb;
+ unsigned int r;
+- int last_label_ruid;
+ int min_labelno, n_labels;
+ HARD_REG_SET ever_live_at_start, *label_live;
+
+- /* If reg+reg can be used in offsetable memory addresses, the main chunk of
+- reload has already used it where appropriate, so there is no use in
+- trying to generate it now. */
+- if (double_reg_address_ok && INDEX_REG_CLASS != NO_REGS)
+- return;
+-
+ /* To avoid wasting too much time later searching for an index register,
+ determine the minimum and maximum index register numbers. */
+- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
+- {
+- if (first_index_reg == -1)
+- first_index_reg = r;
+-
+- last_index_reg = r;
+- }
+-
+- /* If no index register is available, we can quit now. */
+- if (first_index_reg == -1)
+- return;
++ if (INDEX_REG_CLASS == NO_REGS)
++ last_index_reg = -1;
++ else if (first_index_reg == -1 && last_index_reg == 0)
++ {
++ for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
++ {
++ if (first_index_reg == -1)
++ first_index_reg = r;
++
++ last_index_reg = r;
++ }
++
++ /* If no index register is available, we can quit now. Set LAST_INDEX_REG
++ to -1 so we'll know to quit early the next time we get here. */
++ if (first_index_reg == -1)
++ {
++ last_index_reg = -1;
++ return;
++ }
++ }
+
+ /* Set up LABEL_LIVE and EVER_LIVE_AT_START. The register lifetime
+ information is a bit fuzzy immediately after reload, but it's
+@@ -753,20 +1278,23 @@
+ }
+
+ /* Initialize last_label_ruid, reload_combine_ruid and reg_state. */
+- last_label_ruid = reload_combine_ruid = 0;
++ last_label_ruid = last_jump_ruid = reload_combine_ruid = 0;
+ for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+ {
+- reg_state[r].store_ruid = reload_combine_ruid;
++ reg_state[r].store_ruid = 0;
++ reg_state[r].real_store_ruid = 0;
+ if (fixed_regs[r])
+ reg_state[r].use_index = -1;
+ else
+ reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
+ }
+
+- for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
++ for (insn = get_last_insn (); insn; insn = prev)
+ {
+ rtx note;
+
++ prev = PREV_INSN (insn);
++
+ /* We cannot do our optimization across labels. Invalidating all the use
+ information we have would be costly, so we just note where the label
+ is and then later disable any optimization that would cross it. */
+@@ -777,141 +1305,17 @@
+ if (! fixed_regs[r])
+ reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
+
+- if (! INSN_P (insn))
++ if (! NONDEBUG_INSN_P (insn))
+ continue;
+
+ reload_combine_ruid++;
+
+- /* Look for (set (REGX) (CONST_INT))
+- (set (REGX) (PLUS (REGX) (REGY)))
+- ...
+- ... (MEM (REGX)) ...
+- and convert it to
+- (set (REGZ) (CONST_INT))
+- ...
+- ... (MEM (PLUS (REGZ) (REGY)))... .
+-
+- First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
+- and that we know all uses of REGX before it dies.
+- Also, explicitly check that REGX != REGY; our life information
+- does not yet show whether REGY changes in this insn. */
+- set = single_set (insn);
+- if (set != NULL_RTX
+- && REG_P (SET_DEST (set))
+- && (hard_regno_nregs[REGNO (SET_DEST (set))]
+- [GET_MODE (SET_DEST (set))]
+- == 1)
+- && GET_CODE (SET_SRC (set)) == PLUS
+- && REG_P (XEXP (SET_SRC (set), 1))
+- && rtx_equal_p (XEXP (SET_SRC (set), 0), SET_DEST (set))
+- && !rtx_equal_p (XEXP (SET_SRC (set), 1), SET_DEST (set))
+- && last_label_ruid < reg_state[REGNO (SET_DEST (set))].use_ruid)
+- {
+- rtx reg = SET_DEST (set);
+- rtx plus = SET_SRC (set);
+- rtx base = XEXP (plus, 1);
+- rtx prev = prev_nonnote_nondebug_insn (insn);
+- rtx prev_set = prev ? single_set (prev) : NULL_RTX;
+- unsigned int regno = REGNO (reg);
+- rtx index_reg = NULL_RTX;
+- rtx reg_sum = NULL_RTX;
+-
+- /* Now we need to set INDEX_REG to an index register (denoted as
+- REGZ in the illustration above) and REG_SUM to the expression
+- register+register that we want to use to substitute uses of REG
+- (typically in MEMs) with. First check REG and BASE for being
+- index registers; we can use them even if they are not dead. */
+- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
+- || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
+- REGNO (base)))
+- {
+- index_reg = reg;
+- reg_sum = plus;
+- }
+- else
+- {
+- /* Otherwise, look for a free index register. Since we have
+- checked above that neither REG nor BASE are index registers,
+- if we find anything at all, it will be different from these
+- two registers. */
+- for (i = first_index_reg; i <= last_index_reg; i++)
+- {
+- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
+- i)
+- && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
+- && reg_state[i].store_ruid <= reg_state[regno].use_ruid
+- && hard_regno_nregs[i][GET_MODE (reg)] == 1)
+- {
+- index_reg = gen_rtx_REG (GET_MODE (reg), i);
+- reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
+- break;
+- }
+- }
+- }
+-
+- /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
+- (REGY), i.e. BASE, is not clobbered before the last use we'll
+- create. */
+- if (reg_sum
+- && prev_set
+- && CONST_INT_P (SET_SRC (prev_set))
+- && rtx_equal_p (SET_DEST (prev_set), reg)
+- && reg_state[regno].use_index >= 0
+- && (reg_state[REGNO (base)].store_ruid
+- <= reg_state[regno].use_ruid))
+- {
+- int i;
+-
+- /* Change destination register and, if necessary, the constant
+- 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);
+-
+- /* Now for every use of REG that we have recorded, replace REG
+- with REG_SUM. */
+- for (i = reg_state[regno].use_index;
+- i < RELOAD_COMBINE_MAX_USES; i++)
+- validate_unshare_change (reg_state[regno].reg_use[i].insn,
+- reg_state[regno].reg_use[i].usep,
+- /* Each change must have its own
+- replacement. */
+- reg_sum, 1);
+-
+- if (apply_change_group ())
+- {
+- /* For every new use of REG_SUM, we have to record the use
+- of BASE therein, i.e. operand 1. */
+- for (i = reg_state[regno].use_index;
+- i < RELOAD_COMBINE_MAX_USES; i++)
+- reload_combine_note_use
+- (&XEXP (*reg_state[regno].reg_use[i].usep, 1),
+- reg_state[regno].reg_use[i].insn);
+-
+- if (reg_state[REGNO (base)].use_ruid
+- > reg_state[regno].use_ruid)
+- reg_state[REGNO (base)].use_ruid
+- = reg_state[regno].use_ruid;
+-
+- /* 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);
+-
+- reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
+- reg_state[REGNO (index_reg)].store_ruid
+- = reload_combine_ruid;
+- continue;
+- }
+- }
+- }
++ if (control_flow_insn_p (insn))
++ last_jump_ruid = reload_combine_ruid;
++
++ if (reload_combine_recognize_const_pattern (insn)
++ || reload_combine_recognize_pattern (insn))
++ continue;
+
+ note_stores (PATTERN (insn), reload_combine_note_store, NULL);
+
+@@ -967,7 +1371,8 @@
+ reg_state[i].use_index = -1;
+ }
+
+- reload_combine_note_use (&PATTERN (insn), insn);
++ reload_combine_note_use (&PATTERN (insn), insn,
++ reload_combine_ruid, NULL_RTX);
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ {
+ if (REG_NOTE_KIND (note) == REG_INC
+@@ -976,6 +1381,7 @@
+ int regno = REGNO (XEXP (note, 0));
+
+ reg_state[regno].store_ruid = reload_combine_ruid;
++ reg_state[regno].real_store_ruid = reload_combine_ruid;
+ reg_state[regno].use_index = -1;
+ }
+ }
+@@ -985,8 +1391,8 @@
+ }
+
+ /* Check if DST is a register or a subreg of a register; if it is,
+- update reg_state[regno].store_ruid and reg_state[regno].use_index
+- accordingly. Called via note_stores from reload_combine. */
++ update store_ruid, real_store_ruid and use_index in the reg_state
++ structure accordingly. Called via note_stores from reload_combine. */
+
+ static void
+ reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
+@@ -1010,14 +1416,14 @@
+ /* note_stores might have stripped a STRICT_LOW_PART, so we have to be
+ careful with registers / register parts that are not full words.
+ Similarly for ZERO_EXTRACT. */
+- if (GET_CODE (set) != SET
+- || GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
++ 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--)
+ {
+ reg_state[i].use_index = -1;
+ reg_state[i].store_ruid = reload_combine_ruid;
++ reg_state[i].real_store_ruid = reload_combine_ruid;
+ }
+ }
+ else
+@@ -1025,6 +1431,8 @@
+ for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
+ {
+ reg_state[i].store_ruid = reload_combine_ruid;
++ if (GET_CODE (set) == SET)
++ reg_state[i].real_store_ruid = reload_combine_ruid;
+ reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
+ }
+ }
+@@ -1035,7 +1443,7 @@
+ *XP is the pattern of INSN, or a part of it.
+ Called from reload_combine, and recursively by itself. */
+ static void
+-reload_combine_note_use (rtx *xp, rtx insn)
++reload_combine_note_use (rtx *xp, rtx insn, int ruid, rtx containing_mem)
+ {
+ rtx x = *xp;
+ enum rtx_code code = x->code;
+@@ -1048,7 +1456,7 @@
+ case SET:
+ if (REG_P (SET_DEST (x)))
+ {
+- reload_combine_note_use (&SET_SRC (x), insn);
++ reload_combine_note_use (&SET_SRC (x), insn, ruid, NULL_RTX);
+ return;
+ }
+ break;
+@@ -1104,6 +1512,11 @@
+ return;
+ }
+
++ /* We may be called to update uses in previously seen insns.
++ Don't add uses beyond the last store we saw. */
++ if (ruid < reg_state[regno].store_ruid)
++ return;
++
+ /* If this register is already used in some unknown fashion, we
+ can't do anything.
+ If we decrement the index from zero to -1, we can't store more
+@@ -1112,29 +1525,34 @@
+ if (use_index < 0)
+ return;
+
+- if (use_index != RELOAD_COMBINE_MAX_USES - 1)
+- {
+- /* We have found another use for a register that is already
+- used later. Check if the offsets match; if not, mark the
+- register as used in an unknown fashion. */
+- if (! rtx_equal_p (offset, reg_state[regno].offset))
+- {
+- reg_state[regno].use_index = -1;
+- return;
+- }
+- }
+- else
++ if (use_index == RELOAD_COMBINE_MAX_USES - 1)
+ {
+ /* This is the first use of this register we have seen since we
+ marked it as dead. */
+ reg_state[regno].offset = offset;
+- reg_state[regno].use_ruid = reload_combine_ruid;
+- }
++ reg_state[regno].all_offsets_match = true;
++ reg_state[regno].use_ruid = ruid;
++ }
++ else
++ {
++ if (reg_state[regno].use_ruid > ruid)
++ reg_state[regno].use_ruid = ruid;
++
++ if (! rtx_equal_p (offset, reg_state[regno].offset))
++ reg_state[regno].all_offsets_match = false;
++ }
++
+ reg_state[regno].reg_use[use_index].insn = insn;
++ reg_state[regno].reg_use[use_index].ruid = ruid;
++ reg_state[regno].reg_use[use_index].containing_mem = containing_mem;
+ reg_state[regno].reg_use[use_index].usep = xp;
+ return;
+ }
+
++ case MEM:
++ containing_mem = x;
++ break;
++
+ default:
+ break;
+ }
+@@ -1144,11 +1562,12 @@
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+- reload_combine_note_use (&XEXP (x, i), insn);
++ reload_combine_note_use (&XEXP (x, i), insn, ruid, containing_mem);
+ else if (fmt[i] == 'E')
+ {
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+- reload_combine_note_use (&XVECEXP (x, i, j), insn);
++ reload_combine_note_use (&XVECEXP (x, i, j), insn, ruid,
++ containing_mem);
+ }
+ }
+ }
+@@ -1196,9 +1615,10 @@
+ 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. */
++ It also updates the information about REG's known value.
++ Return true if we made a change. */
+
+-static void
++static bool
+ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn)
+ {
+ rtx pat = PATTERN (insn);
+@@ -1207,6 +1627,7 @@
+ rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[regno],
+ GET_MODE (reg));
+ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
++ bool changed = false;
+
+ /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
+ use (set (reg) (reg)) instead.
+@@ -1221,13 +1642,13 @@
+ (reg)), would be discarded. Maybe we should
+ try a truncMN pattern? */
+ if (INTVAL (off) == reg_offset [regno])
+- validate_change (insn, &SET_SRC (pat), reg, 0);
++ changed = validate_change (insn, &SET_SRC (pat), reg, 0);
+ }
+ else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed)
+ && have_add2_insn (reg, new_src))
+ {
+ rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
+- validate_change (insn, &SET_SRC (pat), tem, 0);
++ changed = validate_change (insn, &SET_SRC (pat), tem, 0);
+ }
+ else if (sym == NULL_RTX && GET_MODE (reg) != BImode)
+ {
+@@ -1252,8 +1673,9 @@
+ gen_rtx_STRICT_LOW_PART (VOIDmode,
+ narrow_reg),
+ narrow_src);
+- if (validate_change (insn, &PATTERN (insn),
+- new_set, 0))
++ changed = validate_change (insn, &PATTERN (insn),
++ new_set, 0);
++ if (changed)
+ break;
+ }
+ }
+@@ -1263,6 +1685,7 @@
+ reg_mode[regno] = GET_MODE (reg);
+ reg_symbol_ref[regno] = sym;
+ reg_offset[regno] = INTVAL (off);
++ return changed;
+ }
+
+
+@@ -1272,9 +1695,10 @@
+ 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
+- REG's known value. */
++ REG's known value.
++ Return true iff we made a change. */
+
+-static void
++static bool
+ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
+ {
+ rtx pat = PATTERN (insn);
+@@ -1284,6 +1708,7 @@
+ int min_regno;
+ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
+ int i;
++ bool changed = false;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (reg_set_luid[i] > move2add_last_label_luid
+@@ -1328,20 +1753,25 @@
+ GET_MODE (reg));
+ tem = gen_rtx_PLUS (GET_MODE (reg), tem, new_src);
+ }
+- validate_change (insn, &SET_SRC (pat), tem, 0);
++ if (validate_change (insn, &SET_SRC (pat), tem, 0))
++ changed = true;
+ }
+ reg_set_luid[regno] = move2add_luid;
+ reg_base_reg[regno] = -1;
+ reg_mode[regno] = GET_MODE (reg);
+ reg_symbol_ref[regno] = sym;
+ reg_offset[regno] = INTVAL (off);
++ return changed;
+ }
+
+-static void
++/* Convert move insns with constant inputs to additions if they are cheaper.
++ Return true if any changes were made. */
++static bool
+ reload_cse_move2add (rtx first)
+ {
+ int i;
+ rtx insn;
++ bool changed = false;
+
+ for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
+ {
+@@ -1402,7 +1832,7 @@
+ && reg_base_reg[regno] < 0
+ && reg_symbol_ref[regno] == NULL_RTX)
+ {
+- move2add_use_add2_insn (reg, NULL_RTX, src, insn);
++ changed |= move2add_use_add2_insn (reg, NULL_RTX, src, insn);
+ continue;
+ }
+
+@@ -1463,6 +1893,7 @@
+ }
+ if (success)
+ delete_insn (insn);
++ changed |= success;
+ insn = next;
+ reg_mode[regno] = GET_MODE (reg);
+ reg_offset[regno] =
+@@ -1508,12 +1939,12 @@
+ && reg_base_reg[regno] < 0
+ && reg_symbol_ref[regno] != NULL_RTX
+ && rtx_equal_p (sym, reg_symbol_ref[regno]))
+- move2add_use_add2_insn (reg, sym, off, insn);
++ changed |= move2add_use_add2_insn (reg, sym, off, insn);
+
+ /* Otherwise, we have to find a register whose value is sum
+ of sym and some constant value. */
+ else
+- move2add_use_add3_insn (reg, sym, off, insn);
++ changed |= move2add_use_add3_insn (reg, sym, off, insn);
+
+ continue;
+ }
+@@ -1568,6 +1999,7 @@
+ }
+ }
+ }
++ return changed;
+ }
+
+ /* SET is a SET or CLOBBER that sets DST. DATA is the insn which
+