diff options
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch')
-rw-r--r-- | toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch | 1500 |
1 files changed, 0 insertions, 1500 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch deleted file mode 100644 index cec7f57d479..00000000000 --- a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch +++ /dev/null @@ -1,1500 +0,0 @@ -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 (®_state[i].use_ruid, split_ruid); -+ reload_combine_split_one_ruid (®_state[i].store_ruid, split_ruid); -+ reload_combine_split_one_ruid (®_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 (®_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 - |