diff options
Diffstat (limited to 'recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99314.patch')
-rw-r--r-- | recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99314.patch | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99314.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99314.patch new file mode 100644 index 0000000000..216fcac723 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99314.patch @@ -0,0 +1,433 @@ +2010-07-16 Jie Zhang <jie@codesourcery.com> + + Issue #7688 + + Backport from mainline: + + gcc/ + 2010-07-12 Jie Zhang <jie@codesourcery.com> + * postreload.c (reg_symbol_ref[]): New. + (move2add_use_add2_insn): New. + (move2add_use_add3_insn): New. + (reload_cse_move2add): Handle SYMBOL + OFFSET case. + (move2add_note_store): Likewise. + + 2010-07-15 Yao Qi <yao@codesourcery.com> + + Merge from Sourcery G++ 4.4: + +=== modified file 'gcc/postreload.c' +--- old/gcc/postreload.c 2010-03-16 10:50:42 +0000 ++++ new/gcc/postreload.c 2010-08-02 16:55:34 +0000 +@@ -1160,17 +1160,19 @@ + information about register contents we have would be costly, so we + use move2add_last_label_luid to note where the label is and then + later disable any optimization that would cross it. +- reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if +- reg_set_luid[n] is greater than move2add_last_label_luid. */ ++ reg_offset[n] / reg_base_reg[n] / reg_symbol_ref[n] / reg_mode[n] ++ are only valid if reg_set_luid[n] is greater than ++ move2add_last_label_luid. */ + static int reg_set_luid[FIRST_PSEUDO_REGISTER]; + + /* If reg_base_reg[n] is negative, register n has been set to +- reg_offset[n] in mode reg_mode[n] . ++ reg_offset[n] or reg_symbol_ref[n] + reg_offset[n] in mode reg_mode[n]. + If reg_base_reg[n] is non-negative, register n has been set to the + sum of reg_offset[n] and the value of register reg_base_reg[n] + before reg_set_luid[n], calculated in mode reg_mode[n] . */ + static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER]; + static int reg_base_reg[FIRST_PSEUDO_REGISTER]; ++static rtx reg_symbol_ref[FIRST_PSEUDO_REGISTER]; + static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER]; + + /* move2add_luid is linearly increased while scanning the instructions +@@ -1190,6 +1192,151 @@ + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \ + GET_MODE_BITSIZE (INMODE)))) + ++/* This function is called with INSN that sets REG to (SYM + OFF), ++ while REG is known to already have value (SYM + offset). ++ This function tries to change INSN into an add instruction ++ (set (REG) (plus (REG) (OFF - offset))) using the known value. ++ It also updates the information about REG's known value. */ ++ ++static void ++move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn) ++{ ++ rtx pat = PATTERN (insn); ++ rtx src = SET_SRC (pat); ++ int regno = REGNO (reg); ++ 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)); ++ ++ /* (set (reg) (plus (reg) (const_int 0))) is not canonical; ++ use (set (reg) (reg)) instead. ++ We don't delete this insn, nor do we convert it into a ++ note, to avoid losing register notes or the return ++ value flag. jump2 already knows how to get rid of ++ no-op moves. */ ++ if (new_src == const0_rtx) ++ { ++ /* If the constants are different, this is a ++ truncation, that, if turned into (set (reg) ++ (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); ++ } ++ 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); ++ } ++ else if (sym == NULL_RTX && GET_MODE (reg) != BImode) ++ { ++ enum machine_mode narrow_mode; ++ for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); ++ narrow_mode != VOIDmode ++ && narrow_mode != GET_MODE (reg); ++ narrow_mode = GET_MODE_WIDER_MODE (narrow_mode)) ++ { ++ if (have_insn_for (STRICT_LOW_PART, narrow_mode) ++ && ((reg_offset[regno] ++ & ~GET_MODE_MASK (narrow_mode)) ++ == (INTVAL (off) ++ & ~GET_MODE_MASK (narrow_mode)))) ++ { ++ rtx narrow_reg = gen_rtx_REG (narrow_mode, ++ REGNO (reg)); ++ rtx narrow_src = gen_int_mode (INTVAL (off), ++ narrow_mode); ++ rtx new_set = ++ gen_rtx_SET (VOIDmode, ++ gen_rtx_STRICT_LOW_PART (VOIDmode, ++ narrow_reg), ++ narrow_src); ++ if (validate_change (insn, &PATTERN (insn), ++ new_set, 0)) ++ break; ++ } ++ } ++ } ++ reg_set_luid[regno] = move2add_luid; ++ reg_base_reg[regno] = -1; ++ reg_mode[regno] = GET_MODE (reg); ++ reg_symbol_ref[regno] = sym; ++ reg_offset[regno] = INTVAL (off); ++} ++ ++ ++/* This function is called with INSN that sets REG to (SYM + OFF), ++ but REG doesn't have known value (SYM + offset). This function ++ tries to find another register which is known to already have ++ 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. */ ++ ++static void ++move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn) ++{ ++ rtx pat = PATTERN (insn); ++ rtx src = SET_SRC (pat); ++ int regno = REGNO (reg); ++ int min_cost = INT_MAX; ++ int min_regno; ++ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)); ++ int i; ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ if (reg_set_luid[i] > move2add_last_label_luid ++ && reg_mode[i] == GET_MODE (reg) ++ && reg_base_reg[i] < 0 ++ && reg_symbol_ref[i] != NULL_RTX ++ && rtx_equal_p (sym, reg_symbol_ref[i])) ++ { ++ rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[i], ++ GET_MODE (reg)); ++ /* (set (reg) (plus (reg) (const_int 0))) is not canonical; ++ use (set (reg) (reg)) instead. ++ We don't delete this insn, nor do we convert it into a ++ note, to avoid losing register notes or the return ++ value flag. jump2 already knows how to get rid of ++ no-op moves. */ ++ if (new_src == const0_rtx) ++ { ++ min_cost = 0; ++ min_regno = i; ++ break; ++ } ++ else ++ { ++ int cost = rtx_cost (new_src, PLUS, speed); ++ if (cost < min_cost) ++ { ++ min_cost = cost; ++ min_regno = i; ++ } ++ } ++ } ++ ++ if (min_cost < rtx_cost (src, SET, speed)) ++ { ++ rtx tem; ++ ++ tem = gen_rtx_REG (GET_MODE (reg), min_regno); ++ if (i != min_regno) ++ { ++ rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[min_regno], ++ GET_MODE (reg)); ++ tem = gen_rtx_PLUS (GET_MODE (reg), tem, new_src); ++ } ++ validate_change (insn, &SET_SRC (pat), tem, 0); ++ } ++ 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); ++} ++ + static void + reload_cse_move2add (rtx first) + { +@@ -1197,7 +1344,13 @@ + rtx insn; + + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) +- reg_set_luid[i] = 0; ++ { ++ reg_set_luid[i] = 0; ++ reg_offset[i] = 0; ++ reg_base_reg[i] = 0; ++ reg_symbol_ref[i] = NULL_RTX; ++ reg_mode[i] = VOIDmode; ++ } + + move2add_last_label_luid = 0; + move2add_luid = 2; +@@ -1245,65 +1398,11 @@ + (set (STRICT_LOW_PART (REGX)) (CONST_INT B)) + */ + +- if (CONST_INT_P (src) && reg_base_reg[regno] < 0) ++ if (CONST_INT_P (src) ++ && reg_base_reg[regno] < 0 ++ && reg_symbol_ref[regno] == NULL_RTX) + { +- rtx new_src = gen_int_mode (INTVAL (src) - reg_offset[regno], +- GET_MODE (reg)); +- bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)); +- +- /* (set (reg) (plus (reg) (const_int 0))) is not canonical; +- use (set (reg) (reg)) instead. +- We don't delete this insn, nor do we convert it into a +- note, to avoid losing register notes or the return +- value flag. jump2 already knows how to get rid of +- no-op moves. */ +- if (new_src == const0_rtx) +- { +- /* If the constants are different, this is a +- truncation, that, if turned into (set (reg) +- (reg)), would be discarded. Maybe we should +- try a truncMN pattern? */ +- if (INTVAL (src) == reg_offset [regno]) +- 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); +- } +- else if (GET_MODE (reg) != BImode) +- { +- enum machine_mode narrow_mode; +- for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); +- narrow_mode != VOIDmode +- && narrow_mode != GET_MODE (reg); +- narrow_mode = GET_MODE_WIDER_MODE (narrow_mode)) +- { +- if (have_insn_for (STRICT_LOW_PART, narrow_mode) +- && ((reg_offset[regno] +- & ~GET_MODE_MASK (narrow_mode)) +- == (INTVAL (src) +- & ~GET_MODE_MASK (narrow_mode)))) +- { +- rtx narrow_reg = gen_rtx_REG (narrow_mode, +- REGNO (reg)); +- rtx narrow_src = gen_int_mode (INTVAL (src), +- narrow_mode); +- rtx new_set = +- gen_rtx_SET (VOIDmode, +- gen_rtx_STRICT_LOW_PART (VOIDmode, +- narrow_reg), +- narrow_src); +- if (validate_change (insn, &PATTERN (insn), +- new_set, 0)) +- break; +- } +- } +- } +- reg_set_luid[regno] = move2add_luid; +- reg_mode[regno] = GET_MODE (reg); +- reg_offset[regno] = INTVAL (src); ++ move2add_use_add2_insn (reg, NULL_RTX, src, insn); + continue; + } + +@@ -1373,6 +1472,51 @@ + } + } + } ++ ++ /* Try to transform ++ (set (REGX) (CONST (PLUS (SYMBOL_REF) (CONST_INT A)))) ++ ... ++ (set (REGY) (CONST (PLUS (SYMBOL_REF) (CONST_INT B)))) ++ to ++ (set (REGX) (CONST (PLUS (SYMBOL_REF) (CONST_INT A)))) ++ ... ++ (set (REGY) (CONST (PLUS (REGX) (CONST_INT B-A)))) */ ++ if ((GET_CODE (src) == SYMBOL_REF ++ || (GET_CODE (src) == CONST ++ && GET_CODE (XEXP (src, 0)) == PLUS ++ && GET_CODE (XEXP (XEXP (src, 0), 0)) == SYMBOL_REF ++ && CONST_INT_P (XEXP (XEXP (src, 0), 1)))) ++ && dbg_cnt (cse2_move2add)) ++ { ++ rtx sym, off; ++ ++ if (GET_CODE (src) == SYMBOL_REF) ++ { ++ sym = src; ++ off = const0_rtx; ++ } ++ else ++ { ++ sym = XEXP (XEXP (src, 0), 0); ++ off = XEXP (XEXP (src, 0), 1); ++ } ++ ++ /* If the reg already contains the value which is sum of ++ sym and some constant value, we can use an add2 insn. */ ++ if (reg_set_luid[regno] > move2add_last_label_luid ++ && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]) ++ && 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); ++ ++ /* 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); ++ ++ continue; ++ } + } + + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) +@@ -1386,7 +1530,7 @@ + reg_set_luid[regno] = 0; + } + } +- note_stores (PATTERN (insn), move2add_note_store, NULL); ++ note_stores (PATTERN (insn), move2add_note_store, insn); + + /* If INSN is a conditional branch, we try to extract an + implicit set out of it. */ +@@ -1408,7 +1552,7 @@ + { + rtx implicit_set = + gen_rtx_SET (VOIDmode, XEXP (cnd, 0), XEXP (cnd, 1)); +- move2add_note_store (SET_DEST (implicit_set), implicit_set, 0); ++ move2add_note_store (SET_DEST (implicit_set), implicit_set, insn); + } + } + +@@ -1426,13 +1570,15 @@ + } + } + +-/* SET is a SET or CLOBBER that sets DST. ++/* SET is a SET or CLOBBER that sets DST. DATA is the insn which ++ contains SET. + Update reg_set_luid, reg_offset and reg_base_reg accordingly. + Called from reload_cse_move2add via note_stores. */ + + static void +-move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED) ++move2add_note_store (rtx dst, const_rtx set, void *data) + { ++ rtx insn = (rtx) data; + unsigned int regno = 0; + unsigned int nregs = 0; + unsigned int i; +@@ -1466,6 +1612,38 @@ + nregs = hard_regno_nregs[regno][mode]; + + if (SCALAR_INT_MODE_P (GET_MODE (dst)) ++ && nregs == 1 && GET_CODE (set) == SET) ++ { ++ rtx note, sym = NULL_RTX; ++ HOST_WIDE_INT off; ++ ++ note = find_reg_equal_equiv_note (insn); ++ if (note && GET_CODE (XEXP (note, 0)) == SYMBOL_REF) ++ { ++ sym = XEXP (note, 0); ++ off = 0; ++ } ++ else if (note && GET_CODE (XEXP (note, 0)) == CONST ++ && GET_CODE (XEXP (XEXP (note, 0), 0)) == PLUS ++ && GET_CODE (XEXP (XEXP (XEXP (note, 0), 0), 0)) == SYMBOL_REF ++ && CONST_INT_P (XEXP (XEXP (XEXP (note, 0), 0), 1))) ++ { ++ sym = XEXP (XEXP (XEXP (note, 0), 0), 0); ++ off = INTVAL (XEXP (XEXP (XEXP (note, 0), 0), 1)); ++ } ++ ++ if (sym != NULL_RTX) ++ { ++ reg_base_reg[regno] = -1; ++ reg_symbol_ref[regno] = sym; ++ reg_offset[regno] = off; ++ reg_mode[regno] = mode; ++ reg_set_luid[regno] = move2add_luid; ++ return; ++ } ++ } ++ ++ if (SCALAR_INT_MODE_P (GET_MODE (dst)) + && nregs == 1 && GET_CODE (set) == SET + && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT + && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART) +@@ -1525,6 +1703,7 @@ + case CONST_INT: + /* Start tracking the register as a constant. */ + reg_base_reg[regno] = -1; ++ reg_symbol_ref[regno] = NULL_RTX; + reg_offset[regno] = INTVAL (SET_SRC (set)); + /* We assign the same luid to all registers set to constants. */ + reg_set_luid[regno] = move2add_last_label_luid + 1; +@@ -1545,6 +1724,7 @@ + if (reg_set_luid[base_regno] <= move2add_last_label_luid) + { + reg_base_reg[base_regno] = base_regno; ++ reg_symbol_ref[base_regno] = NULL_RTX; + reg_offset[base_regno] = 0; + reg_set_luid[base_regno] = move2add_luid; + reg_mode[base_regno] = mode; +@@ -1558,6 +1738,7 @@ + /* Copy base information from our base register. */ + reg_set_luid[regno] = reg_set_luid[base_regno]; + reg_base_reg[regno] = reg_base_reg[base_regno]; ++ reg_symbol_ref[regno] = reg_symbol_ref[base_regno]; + + /* Compute the sum of the offsets or constants. */ + reg_offset[regno] = trunc_int_for_mode (offset + |