From 80317a3dcd529bc9a0b8dd634f1c7d405bd15ecd Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Mon, 20 Dec 2010 21:53:36 -0800 Subject: gcc-4.5: Apply patches upto 2010.12 release of linaro gcc Signed-off-by: Khem Raj --- recipes/gcc/gcc-4.5.inc | 20 +- .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99421.patch | 94 ++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99423.patch | 114 ++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99424.patch | 687 +++++++++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99425.patch | 128 ++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99426.patch | 41 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99429.patch | 1257 ++++++++++++++++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch | 70 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99433.patch | 40 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99434.patch | 30 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99435.patch | 32 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99436.patch | 209 +++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99437.patch | 27 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch | 1500 ++++++++++++++++++++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch | 78 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99441.patch | 33 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99442.patch | 23 + .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch | 873 ++++++++++++ .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99444.patch | 183 +++ 19 files changed, 5438 insertions(+), 1 deletion(-) create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99421.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99423.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99424.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99425.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99426.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99429.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99433.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99434.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99435.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99436.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99437.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99441.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99442.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99444.patch (limited to 'recipes/gcc') diff --git a/recipes/gcc/gcc-4.5.inc b/recipes/gcc/gcc-4.5.inc index a44fe1a44d..d5c17e7753 100644 --- a/recipes/gcc/gcc-4.5.inc +++ b/recipes/gcc/gcc-4.5.inc @@ -8,7 +8,7 @@ DEPENDS = "mpfr gmp libmpc libelf" NATIVEDEPS = "mpfr-native gmp-native libmpc-native" -INC_PR = "r26" +INC_PR = "r27" SRCREV = "167948" PV = "4.5" @@ -136,6 +136,24 @@ SRC_URI = "svn://gcc.gnu.org/svn/gcc/branches;module=${BRANCH} \ file://linaro/gcc-4.5-linaro-r99418.patch \ file://linaro/gcc-4.5-linaro-r99419.patch \ file://linaro/gcc-4.5-linaro-r99420.patch \ + file://linaro/gcc-4.5-linaro-r99421.patch \ + file://linaro/gcc-4.5-linaro-r99423.patch \ + file://linaro/gcc-4.5-linaro-r99424.patch \ + file://linaro/gcc-4.5-linaro-r99425.patch \ + file://linaro/gcc-4.5-linaro-r99426.patch \ + file://linaro/gcc-4.5-linaro-r99429.patch \ + file://linaro/gcc-4.5-linaro-r99432.patch \ + file://linaro/gcc-4.5-linaro-r99433.patch \ + file://linaro/gcc-4.5-linaro-r99434.patch \ + file://linaro/gcc-4.5-linaro-r99435.patch \ + file://linaro/gcc-4.5-linaro-r99436.patch \ + file://linaro/gcc-4.5-linaro-r99437.patch \ + file://linaro/gcc-4.5-linaro-r99439.patch \ + file://linaro/gcc-4.5-linaro-r99440.patch \ + file://linaro/gcc-4.5-linaro-r99441.patch \ + file://linaro/gcc-4.5-linaro-r99442.patch \ + file://linaro/gcc-4.5-linaro-r99443.patch \ + file://linaro/gcc-4.5-linaro-r99444.patch \ file://gcc-scalar-widening-pr45847.patch \ file://gcc-arm-qihi-split-PR46883.patch \ " diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99421.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99421.patch new file mode 100644 index 0000000000..3a45ee5026 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99421.patch @@ -0,0 +1,94 @@ +2010-10-20 Nathan Froyd + + Issue #9781 + + Backport from mainline: + + gcc/ + 2010-10-20 Nathan Froyd + + * ifcvt.c (noce_emit_cmove): If both of the values are SUBREGs, try + emitting the conditional move in the inner mode of the SUBREG. + + +=== modified file 'gcc/ifcvt.c' +--- old/gcc/ifcvt.c 2010-10-15 10:01:07 +0000 ++++ new/gcc/ifcvt.c 2010-11-04 12:11:15 +0000 +@@ -1338,6 +1338,9 @@ + noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code, + rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue) + { ++ rtx target; ++ int unsignedp; ++ + /* If earliest == jump, try to build the cmove insn directly. + This is helpful when combine has created some complex condition + (like for alpha's cmovlbs) that we can't hope to regenerate +@@ -1372,10 +1375,62 @@ + return NULL_RTX; + + #if HAVE_conditional_move +- return emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode, +- vtrue, vfalse, GET_MODE (x), +- (code == LTU || code == GEU +- || code == LEU || code == GTU)); ++ unsignedp = (code == LTU || code == GEU ++ || code == LEU || code == GTU); ++ ++ target = emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode, ++ vtrue, vfalse, GET_MODE (x), ++ unsignedp); ++ if (target) ++ return target; ++ ++ /* We might be faced with a situation like: ++ ++ x = (reg:M TARGET) ++ vtrue = (subreg:M (reg:N VTRUE) BYTE) ++ vfalse = (subreg:M (reg:N VFALSE) BYTE) ++ ++ We can't do a conditional move in mode M, but it's possible that we ++ could do a conditional move in mode N instead and take a subreg of ++ the result. ++ ++ If we can't create new pseudos, though, don't bother. */ ++ if (reload_completed) ++ return NULL_RTX; ++ ++ if (GET_CODE (vtrue) == SUBREG && GET_CODE (vfalse) == SUBREG) ++ { ++ rtx reg_vtrue = SUBREG_REG (vtrue); ++ rtx reg_vfalse = SUBREG_REG (vfalse); ++ unsigned int byte_vtrue = SUBREG_BYTE (vtrue); ++ unsigned int byte_vfalse = SUBREG_BYTE (vfalse); ++ rtx promoted_target; ++ ++ if (GET_MODE (reg_vtrue) != GET_MODE (reg_vfalse) ++ || byte_vtrue != byte_vfalse ++ || (SUBREG_PROMOTED_VAR_P (vtrue) ++ != SUBREG_PROMOTED_VAR_P (vfalse)) ++ || (SUBREG_PROMOTED_UNSIGNED_P (vtrue) ++ != SUBREG_PROMOTED_UNSIGNED_P (vfalse))) ++ return NULL_RTX; ++ ++ promoted_target = gen_reg_rtx (GET_MODE (reg_vtrue)); ++ ++ target = emit_conditional_move (promoted_target, code, cmp_a, cmp_b, ++ VOIDmode, reg_vtrue, reg_vfalse, ++ GET_MODE (reg_vtrue), unsignedp); ++ /* Nope, couldn't do it in that mode either. */ ++ if (!target) ++ return NULL_RTX; ++ ++ target = gen_rtx_SUBREG (GET_MODE (vtrue), promoted_target, byte_vtrue); ++ SUBREG_PROMOTED_VAR_P (target) = SUBREG_PROMOTED_VAR_P (vtrue); ++ SUBREG_PROMOTED_UNSIGNED_SET (target, SUBREG_PROMOTED_UNSIGNED_P (vtrue)); ++ emit_move_insn (x, target); ++ return x; ++ } ++ else ++ return NULL_RTX; + #else + /* We'll never get here, as noce_process_if_block doesn't call the + functions involved. Ifdef code, however, should be discouraged + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99423.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99423.patch new file mode 100644 index 0000000000..80dbe3f71a --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99423.patch @@ -0,0 +1,114 @@ +2010-10-25 Jie Zhang + + Issue #9812 + + Backport from mainline: + + gcc/ + 2010-10-25 Jie Zhang + * combine.c (try_combine): If insns need to be kept around, + check that they can be copied in the merged instruction. + + gcc/testsuite/ + 2010-10-25 Jie Zhang + * g++.dg/opt/combine.c: New test. + +=== modified file 'gcc/combine.c' +--- old/gcc/combine.c 2010-09-20 22:37:32 +0000 ++++ new/gcc/combine.c 2010-11-04 12:39:28 +0000 +@@ -2809,6 +2809,17 @@ + = i1 && ! (i1_feeds_i3 ? dead_or_set_p (i3, i1dest) + : (dead_or_set_p (i3, i1dest) || dead_or_set_p (i2, i1dest))); + ++ /* We are about to copy insns for the case where they need to be kept ++ around. Check that they can be copied in the merged instruction. */ ++ ++ if (targetm.cannot_copy_insn_p ++ && ((added_sets_2 && targetm.cannot_copy_insn_p (i2)) ++ || (i1 && added_sets_1 && targetm.cannot_copy_insn_p (i1)))) ++ { ++ undo_all (); ++ return 0; ++ } ++ + /* If the set in I2 needs to be kept around, we must make a copy of + PATTERN (I2), so that when we substitute I1SRC for I1DEST in + PATTERN (I2), we are only substituting for the original I1DEST, not into + +=== added file 'gcc/testsuite/g++.dg/opt/combine.C' +--- old/gcc/testsuite/g++.dg/opt/combine.C 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/g++.dg/opt/combine.C 2010-11-04 12:39:28 +0000 +@@ -0,0 +1,72 @@ ++// { dg-do assemble { target fpic } } ++// { dg-options "-O2 -fweb -fPIC -fvisibility=hidden" } ++ ++class QBasicAtomicInt ++{ ++public: ++ volatile int _q_value; ++ inline operator int () const {return _q_value;} ++}; ++class QVariant; ++class QScriptContext; ++class QScriptEngine; ++class QScriptValue ++{ ++public: ++ QVariant toVariant () const; ++}; ++class QScriptDebuggerBackendPrivate ++{ ++ static QScriptValue trace (QScriptContext *context); ++}; ++template struct QMetaTypeId { }; ++template struct QMetaTypeId2 ++{ ++ static inline int qt_metatype_id () ++ { ++ return QMetaTypeId::qt_metatype_id () ; ++ } ++}; ++template inline int qMetaTypeId (T * = 0) ++{ ++ return QMetaTypeId2::qt_metatype_id () ; ++} ++class QVariant { }; ++template inline T qvariant_cast (const QVariant &v) ++{ ++ const int vid = qMetaTypeId ((0)) ; ++}; ++class QScriptContext ++{ ++public: ++ QScriptValue callee () const; ++}; ++class QScriptEngine ++{ ++public: ++ static bool convertV2 (const QScriptValue &value , int type , void *ptr) ; ++}; ++inline bool qscriptvalue_cast_helper (const QScriptValue &value , int type , void *ptr) ++{ ++ return QScriptEngine::convertV2 (value, type, ptr) ; ++} ++template T qscriptvalue_cast (const QScriptValue &value) ++{ ++ T t; ++ const int id = qMetaTypeId () ; ++ if ( qscriptvalue_cast_helper (value, id, &t)) ++ return qvariant_cast (value.toVariant ()) ; ++} ++template <> struct QMetaTypeId< QScriptDebuggerBackendPrivate* > ++{ ++ static int qt_metatype_id () ++ { ++ static QBasicAtomicInt metatype_id = { (0) }; ++ return metatype_id; ++ } ++}; ++QScriptValue QScriptDebuggerBackendPrivate::trace (QScriptContext *context) ++{ ++ QScriptValue data = context->callee () ; ++ QScriptDebuggerBackendPrivate *self = qscriptvalue_cast (data) ; ++} + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99424.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99424.patch new file mode 100644 index 0000000000..b6c6532661 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99424.patch @@ -0,0 +1,687 @@ + Issue #1259 + + Backport from mainline: + + gcc/ + 2010-10-22 Jie Zhang + + * expr.c (emit_group_load_1): Update calls to extract_bit_field. + (copy_blkmode_from_reg): Likewise. + (read_complex_part): Likewise. + (expand_expr_real_1): Calculate packedp and pass it to + extract_bit_field. + * expr.h (extract_bit_field): Update declaration. + * calls.c (store_unaligned_arguments_into_pseudos): Update call + to extract_bit_field. + * expmed.c (extract_fixed_bit_field): Update calls to + extract_fixed_bit_field. + (store_split_bit_field): Likewise. + (extract_bit_field_1): Add new argument packedp. + (extract_bit_field): Add new argument packedp. + (extract_fixed_bit_field): Add new argument packedp and let + packed attribute override volatile. + * stmt.c (expand_return): Update call to extract_bit_field. + + 2010-10-15 Jie Zhang + + * doc/invoke.texi: Add -fstrict-volatile-bitfields to + Option Summary and Index. + + 2010-07-13 DJ Delorie + + * config/h8300/h8300.c (h8300_init_once): Default to + -fstrict_volatile_bitfields. + + * config/sh/sh.c (sh_override_options): Default to + -fstrict_volatile_bitfields. + + * config/rx/rx.c (rx_option_override): New. + + * config/m32c/m32c.c (m32c_override_options): Default to + -fstrict_volatile_bitfields. + + 2010-06-16 DJ Delorie + + * common.opt (-fstrict-volatile-bitfields): new. + * doc/invoke.texi: Document it. + * fold-const.c (optimize_bit_field_compare): For volatile + bitfields, use the field's type to determine the mode, not the + field's size. + * expr.c (expand_assignment): Likewise. + (get_inner_reference): Likewise. + (expand_expr_real_1): Likewise. + * expmed.c (store_fixed_bit_field): Likewise. + (extract_bit_field_1): Likewise. + (extract_fixed_bit_field): Likewise. + + gcc/testsuite/ + 2010-08-19 Uros Bizjak + + PR testsuite/45324 + * gcc.target/i386/volatile-bitfields-1.c: Also scan movb. + + 2010-06-16 DJ Delorie + + * gcc.target/i386/volatile-bitfields-1.c: New. + * gcc.target/i386/volatile-bitfields-2.c: New. + +=== modified file 'gcc/calls.c' +--- old/gcc/calls.c 2010-10-04 00:50:43 +0000 ++++ new/gcc/calls.c 2010-11-04 12:43:52 +0000 +@@ -878,7 +878,7 @@ + int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD); + + args[i].aligned_regs[j] = reg; +- word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX, ++ word = extract_bit_field (word, bitsize, 0, 1, false, NULL_RTX, + word_mode, word_mode); + + /* There is no need to restrict this code to loading items + +=== modified file 'gcc/common.opt' +--- old/gcc/common.opt 2010-07-29 14:59:35 +0000 ++++ new/gcc/common.opt 2010-11-04 12:43:52 +0000 +@@ -613,6 +613,10 @@ + Common Report Var(flag_loop_block) Optimization + Enable Loop Blocking transformation + ++fstrict-volatile-bitfields ++Common Report Var(flag_strict_volatile_bitfields) Init(-1) ++Force bitfield accesses to match their type width ++ + fguess-branch-probability + Common Report Var(flag_guess_branch_prob) Optimization + Enable guessing of branch probabilities + +=== modified file 'gcc/config/h8300/h8300.c' +--- old/gcc/config/h8300/h8300.c 2010-04-02 18:54:46 +0000 ++++ new/gcc/config/h8300/h8300.c 2010-11-04 12:43:52 +0000 +@@ -403,6 +403,10 @@ + restore er6 though, so bump up the cost. */ + h8300_move_ratio = 6; + } ++ ++ /* This target defaults to strict volatile bitfields. */ ++ if (flag_strict_volatile_bitfields < 0) ++ flag_strict_volatile_bitfields = 1; + } + + /* Implement REG_CLASS_FROM_LETTER. + +=== modified file 'gcc/config/m32c/m32c.c' +--- old/gcc/config/m32c/m32c.c 2009-10-22 18:46:26 +0000 ++++ new/gcc/config/m32c/m32c.c 2010-11-04 12:43:52 +0000 +@@ -428,6 +428,10 @@ + + if (TARGET_A24) + flag_ivopts = 0; ++ ++ /* This target defaults to strict volatile bitfields. */ ++ if (flag_strict_volatile_bitfields < 0) ++ flag_strict_volatile_bitfields = 1; + } + + /* Defining data structures for per-function information */ + +=== modified file 'gcc/config/rx/rx.c' +--- old/gcc/config/rx/rx.c 2010-07-27 14:39:53 +0000 ++++ new/gcc/config/rx/rx.c 2010-11-04 12:43:52 +0000 +@@ -2187,6 +2187,14 @@ + } + } + ++static void ++rx_option_override (void) ++{ ++ /* This target defaults to strict volatile bitfields. */ ++ if (flag_strict_volatile_bitfields < 0) ++ flag_strict_volatile_bitfields = 1; ++} ++ + + static bool + rx_allocate_stack_slots_for_args (void) +@@ -2759,6 +2767,9 @@ + #undef TARGET_CC_MODES_COMPATIBLE + #define TARGET_CC_MODES_COMPATIBLE rx_cc_modes_compatible + ++#undef TARGET_OPTION_OVERRIDE ++#define TARGET_OPTION_OVERRIDE rx_option_override ++ + struct gcc_target targetm = TARGET_INITIALIZER; + + /* #include "gt-rx.h" */ + +=== modified file 'gcc/config/sh/sh.c' +--- old/gcc/config/sh/sh.c 2010-05-05 21:12:17 +0000 ++++ new/gcc/config/sh/sh.c 2010-11-04 12:43:52 +0000 +@@ -950,6 +950,10 @@ + + if (sh_fixed_range_str) + sh_fix_range (sh_fixed_range_str); ++ ++ /* This target defaults to strict volatile bitfields. */ ++ if (flag_strict_volatile_bitfields < 0) ++ flag_strict_volatile_bitfields = 1; + } + + /* Print the operand address in x to the stream. */ + +=== modified file 'gcc/doc/invoke.texi' +--- old/gcc/doc/invoke.texi 2010-10-04 00:50:43 +0000 ++++ new/gcc/doc/invoke.texi 2010-11-04 12:43:52 +0000 +@@ -922,7 +922,7 @@ + -fargument-noalias-global -fargument-noalias-anything @gol + -fleading-underscore -ftls-model=@var{model} @gol + -ftrapv -fwrapv -fbounds-check @gol +--fvisibility} ++-fvisibility -fstrict-volatile-bitfields} + @end table + + @menu +@@ -17629,6 +17629,33 @@ + An overview of these techniques, their benefits and how to use them + is at @w{@uref{http://gcc.gnu.org/wiki/Visibility}}. + ++@item -fstrict-volatile-bitfields ++@opindex fstrict-volatile-bitfields ++This option should be used if accesses to volatile bitfields (or other ++structure fields, although the compiler usually honors those types ++anyway) should use a single access in a mode of the same size as the ++container's type, aligned to a natural alignment if possible. For ++example, targets with memory-mapped peripheral registers might require ++all such accesses to be 16 bits wide; with this flag the user could ++declare all peripheral bitfields as ``unsigned short'' (assuming short ++is 16 bits on these targets) to force GCC to use 16 bit accesses ++instead of, perhaps, a more efficient 32 bit access. ++ ++If this option is disabled, the compiler will use the most efficient ++instruction. In the previous example, that might be a 32-bit load ++instruction, even though that will access bytes that do not contain ++any portion of the bitfield, or memory-mapped registers unrelated to ++the one being updated. ++ ++If the target requires strict alignment, and honoring the container ++type would require violating this alignment, a warning is issued. ++However, the access happens as the user requested, under the ++assumption that the user knows something about the target hardware ++that GCC is unaware of. ++ ++The default value of this option is determined by the application binary ++interface for the target processor. ++ + @end table + + @c man end + +=== modified file 'gcc/expmed.c' +--- old/gcc/expmed.c 2010-10-04 00:50:43 +0000 ++++ new/gcc/expmed.c 2010-11-04 12:43:52 +0000 +@@ -47,7 +47,7 @@ + static rtx extract_fixed_bit_field (enum machine_mode, rtx, + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, +- unsigned HOST_WIDE_INT, rtx, int); ++ unsigned HOST_WIDE_INT, rtx, int, bool); + static rtx mask_rtx (enum machine_mode, int, int, int); + static rtx lshift_value (enum machine_mode, rtx, int, int); + static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT, +@@ -904,8 +904,14 @@ + if (GET_MODE_BITSIZE (mode) == 0 + || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode)) + mode = word_mode; +- mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, +- MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0)); ++ ++ if (MEM_VOLATILE_P (op0) ++ && GET_MODE_BITSIZE (GET_MODE (op0)) > 0 ++ && flag_strict_volatile_bitfields > 0) ++ mode = GET_MODE (op0); ++ else ++ mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, ++ MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0)); + + if (mode == VOIDmode) + { +@@ -1099,7 +1105,7 @@ + endianness compensation) to fetch the piece we want. */ + part = extract_fixed_bit_field (word_mode, value, 0, thissize, + total_bits - bitsize + bitsdone, +- NULL_RTX, 1); ++ NULL_RTX, 1, false); + } + else + { +@@ -1110,7 +1116,7 @@ + & (((HOST_WIDE_INT) 1 << thissize) - 1)); + else + part = extract_fixed_bit_field (word_mode, value, 0, thissize, +- bitsdone, NULL_RTX, 1); ++ bitsdone, NULL_RTX, 1, false); + } + + /* If OP0 is a register, then handle OFFSET here. +@@ -1176,7 +1182,8 @@ + + static rtx + extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, +- unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target, ++ unsigned HOST_WIDE_INT bitnum, ++ int unsignedp, bool packedp, rtx target, + enum machine_mode mode, enum machine_mode tmode, + bool fallback_p) + { +@@ -1378,6 +1385,14 @@ + ? mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0) + : mode); + ++ /* If the bitfield is volatile, we need to make sure the access ++ remains on a type-aligned boundary. */ ++ if (GET_CODE (op0) == MEM ++ && MEM_VOLATILE_P (op0) ++ && GET_MODE_BITSIZE (GET_MODE (op0)) > 0 ++ && flag_strict_volatile_bitfields > 0) ++ goto no_subreg_mode_swap; ++ + if (((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode) + && bitpos % BITS_PER_WORD == 0) + || (mode1 != BLKmode +@@ -1450,7 +1465,7 @@ + rtx result_part + = extract_bit_field (op0, MIN (BITS_PER_WORD, + bitsize - i * BITS_PER_WORD), +- bitnum + bit_offset, 1, target_part, mode, ++ bitnum + bit_offset, 1, false, target_part, mode, + word_mode); + + gcc_assert (target_part); +@@ -1649,7 +1664,7 @@ + xop0 = adjust_address (op0, bestmode, xoffset); + xop0 = force_reg (bestmode, xop0); + result = extract_bit_field_1 (xop0, bitsize, xbitpos, +- unsignedp, target, ++ unsignedp, packedp, target, + mode, tmode, false); + if (result) + return result; +@@ -1663,7 +1678,7 @@ + return NULL; + + target = extract_fixed_bit_field (int_mode, op0, offset, bitsize, +- bitpos, target, unsignedp); ++ bitpos, target, unsignedp, packedp); + return convert_extracted_bit_field (target, mode, tmode, unsignedp); + } + +@@ -1674,6 +1689,7 @@ + + STR_RTX is the structure containing the byte (a REG or MEM). + UNSIGNEDP is nonzero if this is an unsigned bit field. ++ PACKEDP is nonzero if the field has the packed attribute. + MODE is the natural mode of the field value once extracted. + TMODE is the mode the caller would like the value to have; + but the value may be returned with type MODE instead. +@@ -1685,10 +1701,10 @@ + + rtx + extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, +- unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target, +- enum machine_mode mode, enum machine_mode tmode) ++ unsigned HOST_WIDE_INT bitnum, int unsignedp, bool packedp, ++ rtx target, enum machine_mode mode, enum machine_mode tmode) + { +- return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp, ++ return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp, packedp, + target, mode, tmode, true); + } + +@@ -1704,6 +1720,8 @@ + which is significant on bigendian machines.) + + UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value). ++ PACKEDP is true if the field has the packed attribute. ++ + If TARGET is nonzero, attempts to store the value there + and return TARGET, but this is not guaranteed. + If TARGET is not used, create a pseudo-reg of mode TMODE for the value. */ +@@ -1713,7 +1731,7 @@ + unsigned HOST_WIDE_INT offset, + unsigned HOST_WIDE_INT bitsize, + unsigned HOST_WIDE_INT bitpos, rtx target, +- int unsignedp) ++ int unsignedp, bool packedp) + { + unsigned int total_bits = BITS_PER_WORD; + enum machine_mode mode; +@@ -1730,8 +1748,19 @@ + includes the entire field. If such a mode would be larger than + a word, we won't be doing the extraction the normal way. */ + +- mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, +- MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0)); ++ if (MEM_VOLATILE_P (op0) ++ && flag_strict_volatile_bitfields > 0) ++ { ++ if (GET_MODE_BITSIZE (GET_MODE (op0)) > 0) ++ mode = GET_MODE (op0); ++ else if (target && GET_MODE_BITSIZE (GET_MODE (target)) > 0) ++ mode = GET_MODE (target); ++ else ++ mode = tmode; ++ } ++ else ++ mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, ++ MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0)); + + if (mode == VOIDmode) + /* The only way this should occur is if the field spans word +@@ -1752,12 +1781,67 @@ + * BITS_PER_UNIT); + } + +- /* Get ref to an aligned byte, halfword, or word containing the field. +- Adjust BITPOS to be position within a word, +- and OFFSET to be the offset of that word. +- Then alter OP0 to refer to that word. */ +- bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT; +- offset -= (offset % (total_bits / BITS_PER_UNIT)); ++ /* If we're accessing a volatile MEM, we can't do the next ++ alignment step if it results in a multi-word access where we ++ otherwise wouldn't have one. So, check for that case ++ here. */ ++ if (MEM_P (op0) ++ && MEM_VOLATILE_P (op0) ++ && flag_strict_volatile_bitfields > 0 ++ && bitpos + bitsize <= total_bits ++ && bitpos + bitsize + (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT > total_bits) ++ { ++ if (STRICT_ALIGNMENT) ++ { ++ static bool informed_about_misalignment = false; ++ bool warned; ++ ++ if (packedp) ++ { ++ if (bitsize == total_bits) ++ warned = warning_at (input_location, OPT_fstrict_volatile_bitfields, ++ "multiple accesses to volatile structure member" ++ " because of packed attribute"); ++ else ++ warned = warning_at (input_location, OPT_fstrict_volatile_bitfields, ++ "multiple accesses to volatile structure bitfield" ++ " because of packed attribute"); ++ ++ return extract_split_bit_field (op0, bitsize, ++ bitpos + offset * BITS_PER_UNIT, ++ unsignedp); ++ } ++ ++ if (bitsize == total_bits) ++ warned = warning_at (input_location, OPT_fstrict_volatile_bitfields, ++ "mis-aligned access used for structure member"); ++ else ++ warned = warning_at (input_location, OPT_fstrict_volatile_bitfields, ++ "mis-aligned access used for structure bitfield"); ++ ++ if (! informed_about_misalignment && warned) ++ { ++ informed_about_misalignment = true; ++ inform (input_location, ++ "When a volatile object spans multiple type-sized locations," ++ " the compiler must choose between using a single mis-aligned access to" ++ " preserve the volatility, or using multiple aligned accesses to avoid" ++ " runtime faults. This code may fail at runtime if the hardware does" ++ " not allow this access."); ++ } ++ } ++ } ++ else ++ { ++ ++ /* Get ref to an aligned byte, halfword, or word containing the field. ++ Adjust BITPOS to be position within a word, ++ and OFFSET to be the offset of that word. ++ Then alter OP0 to refer to that word. */ ++ bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT; ++ offset -= (offset % (total_bits / BITS_PER_UNIT)); ++ } ++ + op0 = adjust_address (op0, mode, offset); + } + +@@ -1966,7 +2050,7 @@ + extract_fixed_bit_field wants offset in bytes. */ + part = extract_fixed_bit_field (word_mode, word, + offset * unit / BITS_PER_UNIT, +- thissize, thispos, 0, 1); ++ thissize, thispos, 0, 1, false); + bitsdone += thissize; + + /* Shift this part into place for the result. */ + +=== modified file 'gcc/expr.c' +--- old/gcc/expr.c 2010-10-04 00:50:43 +0000 ++++ new/gcc/expr.c 2010-11-04 12:43:52 +0000 +@@ -1749,7 +1749,7 @@ + && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode)) + tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT, + (bytepos % slen0) * BITS_PER_UNIT, +- 1, NULL_RTX, mode, mode); ++ 1, false, NULL_RTX, mode, mode); + } + else + { +@@ -1759,7 +1759,7 @@ + mem = assign_stack_temp (GET_MODE (src), slen, 0); + emit_move_insn (mem, src); + tmps[i] = extract_bit_field (mem, bytelen * BITS_PER_UNIT, +- 0, 1, NULL_RTX, mode, mode); ++ 0, 1, false, NULL_RTX, mode, mode); + } + } + /* FIXME: A SIMD parallel will eventually lead to a subreg of a +@@ -1800,7 +1800,7 @@ + tmps[i] = src; + else + tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT, +- bytepos * BITS_PER_UNIT, 1, NULL_RTX, ++ bytepos * BITS_PER_UNIT, 1, false, NULL_RTX, + mode, mode); + + if (shift) +@@ -2213,7 +2213,7 @@ + bitpos for the destination store (left justified). */ + store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, copy_mode, + extract_bit_field (src, bitsize, +- xbitpos % BITS_PER_WORD, 1, ++ xbitpos % BITS_PER_WORD, 1, false, + NULL_RTX, copy_mode, copy_mode)); + } + +@@ -2970,7 +2970,7 @@ + } + + return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, +- true, NULL_RTX, imode, imode); ++ true, false, NULL_RTX, imode, imode); + } + + /* A subroutine of emit_move_insn_1. Yet another lowpart generator. +@@ -4233,6 +4233,13 @@ + + to_rtx = expand_normal (tem); + ++ /* If the bitfield is volatile, we want to access it in the ++ field's mode, not the computed mode. */ ++ if (volatilep ++ && GET_CODE (to_rtx) == MEM ++ && flag_strict_volatile_bitfields > 0) ++ to_rtx = adjust_address (to_rtx, mode1, 0); ++ + if (offset != 0) + { + enum machine_mode address_mode; +@@ -5993,6 +6000,12 @@ + mode = DECL_MODE (field); + else if (DECL_MODE (field) == BLKmode) + blkmode_bitfield = true; ++ else if (TREE_THIS_VOLATILE (exp) ++ && flag_strict_volatile_bitfields > 0) ++ /* Volatile bitfields should be accessed in the mode of the ++ field's type, not the mode computed based on the bit ++ size. */ ++ mode = TYPE_MODE (DECL_BIT_FIELD_TYPE (field)); + + *punsignedp = DECL_UNSIGNED (field); + } +@@ -8848,6 +8861,7 @@ + HOST_WIDE_INT bitsize, bitpos; + tree offset; + int volatilep = 0, must_force_mem; ++ bool packedp = false; + tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset, + &mode1, &unsignedp, &volatilep, true); + rtx orig_op0, memloc; +@@ -8857,6 +8871,11 @@ + infinitely recurse. */ + gcc_assert (tem != exp); + ++ if (TYPE_PACKED (TREE_TYPE (TREE_OPERAND (exp, 0))) ++ || (TREE_CODE (TREE_OPERAND (exp, 1)) == FIELD_DECL ++ && DECL_PACKED (TREE_OPERAND (exp, 1)))) ++ packedp = true; ++ + /* If TEM's type is a union of variable size, pass TARGET to the inner + computation, since it will need a temporary and TARGET is known + to have to do. This occurs in unchecked conversion in Ada. */ +@@ -8873,6 +8892,14 @@ + || modifier == EXPAND_STACK_PARM) + ? modifier : EXPAND_NORMAL); + ++ ++ /* If the bitfield is volatile, we want to access it in the ++ field's mode, not the computed mode. */ ++ if (volatilep ++ && GET_CODE (op0) == MEM ++ && flag_strict_volatile_bitfields > 0) ++ op0 = adjust_address (op0, mode1, 0); ++ + mode2 + = CONSTANT_P (op0) ? TYPE_MODE (TREE_TYPE (tem)) : GET_MODE (op0); + +@@ -8998,6 +9025,9 @@ + && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT + && modifier != EXPAND_CONST_ADDRESS + && modifier != EXPAND_INITIALIZER) ++ /* If the field is volatile, we always want an aligned ++ access. */ ++ || (volatilep && flag_strict_volatile_bitfields > 0) + /* If the field isn't aligned enough to fetch as a memref, + fetch it as a bit field. */ + || (mode1 != BLKmode +@@ -9058,7 +9088,7 @@ + if (MEM_P (op0) && REG_P (XEXP (op0, 0))) + mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0)); + +- op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp, ++ op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp, packedp, + (modifier == EXPAND_STACK_PARM + ? NULL_RTX : target), + ext_mode, ext_mode); + +=== modified file 'gcc/expr.h' +--- old/gcc/expr.h 2010-02-19 09:53:51 +0000 ++++ new/gcc/expr.h 2010-11-04 12:43:52 +0000 +@@ -802,7 +802,7 @@ + extern void store_bit_field (rtx, unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, enum machine_mode, rtx); + extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT, +- unsigned HOST_WIDE_INT, int, rtx, ++ unsigned HOST_WIDE_INT, int, bool, rtx, + enum machine_mode, enum machine_mode); + extern rtx extract_low_bits (enum machine_mode, enum machine_mode, rtx); + extern rtx expand_mult (enum machine_mode, rtx, rtx, rtx, int); + +=== modified file 'gcc/fold-const.c' +--- old/gcc/fold-const.c 2010-10-04 00:50:43 +0000 ++++ new/gcc/fold-const.c 2010-11-04 12:43:52 +0000 +@@ -4208,11 +4208,16 @@ + + /* See if we can find a mode to refer to this field. We should be able to, + but fail if we can't. */ +- nmode = get_best_mode (lbitsize, lbitpos, +- const_p ? TYPE_ALIGN (TREE_TYPE (linner)) +- : MIN (TYPE_ALIGN (TREE_TYPE (linner)), +- TYPE_ALIGN (TREE_TYPE (rinner))), +- word_mode, lvolatilep || rvolatilep); ++ if (lvolatilep ++ && GET_MODE_BITSIZE (lmode) > 0 ++ && flag_strict_volatile_bitfields > 0) ++ nmode = lmode; ++ else ++ nmode = get_best_mode (lbitsize, lbitpos, ++ const_p ? TYPE_ALIGN (TREE_TYPE (linner)) ++ : MIN (TYPE_ALIGN (TREE_TYPE (linner)), ++ TYPE_ALIGN (TREE_TYPE (rinner))), ++ word_mode, lvolatilep || rvolatilep); + if (nmode == VOIDmode) + return 0; + + +=== modified file 'gcc/stmt.c' +--- old/gcc/stmt.c 2010-08-13 11:53:46 +0000 ++++ new/gcc/stmt.c 2010-11-04 12:43:52 +0000 +@@ -1751,7 +1751,7 @@ + xbitpos for the destination store (right justified). */ + store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode, + extract_bit_field (src, bitsize, +- bitpos % BITS_PER_WORD, 1, ++ bitpos % BITS_PER_WORD, 1, false, + NULL_RTX, word_mode, word_mode)); + } + + +=== added file 'gcc/testsuite/gcc.target/i386/volatile-bitfields-1.c' +--- old/gcc/testsuite/gcc.target/i386/volatile-bitfields-1.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.target/i386/volatile-bitfields-1.c 2010-11-04 12:43:52 +0000 +@@ -0,0 +1,17 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fstrict-volatile-bitfields" } */ ++ ++typedef struct { ++ char a:1; ++ char b:7; ++ int c; ++} BitStruct; ++ ++volatile BitStruct bits; ++ ++int foo () ++{ ++ return bits.b; ++} ++ ++/* { dg-final { scan-assembler "mov(b|zbl).*bits" } } */ + +=== added file 'gcc/testsuite/gcc.target/i386/volatile-bitfields-2.c' +--- old/gcc/testsuite/gcc.target/i386/volatile-bitfields-2.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.target/i386/volatile-bitfields-2.c 2010-11-04 12:43:52 +0000 +@@ -0,0 +1,17 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fno-strict-volatile-bitfields" } */ ++ ++typedef struct { ++ char a:1; ++ char b:7; ++ int c; ++} BitStruct; ++ ++volatile BitStruct bits; ++ ++int foo () ++{ ++ return bits.b; ++} ++ ++/* { dg-final { scan-assembler "movl.*bits" } } */ + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99425.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99425.patch new file mode 100644 index 0000000000..17839c03dc --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99425.patch @@ -0,0 +1,128 @@ +2010-10-26 Jie Zhang + + Issue #1259 + + Backport from mainline: + + gcc/ + 2010-10-26 Jie Zhang + + * stor-layout.c (layout_decl): Use the field's type to + determine the mode and keep DECL_BIT_FIELD for a volatile + bit-field. + * config/arm/arm.c (arm_override_options): Default to + -fstrict-volatile-bitfields. + + gcc/testsuite/ + 2010-10-26 Jie Zhang + + * gcc.target/arm/volatile-bitfields-1.c: New test. + * gcc.target/arm/volatile-bitfields-2.c: New test. + * gcc.target/arm/volatile-bitfields-3.c: New test. + +=== modified file 'gcc/config/arm/arm.c' +--- old/gcc/config/arm/arm.c 2010-11-04 10:45:05 +0000 ++++ new/gcc/config/arm/arm.c 2010-11-04 12:49:37 +0000 +@@ -1933,6 +1933,10 @@ + calculation, which is 2 instructions. */ + set_param_value ("gcse-unrestricted-cost", 2); + ++ /* ARM EABI defaults to strict volatile bitfields. */ ++ if (TARGET_AAPCS_BASED && flag_strict_volatile_bitfields < 0) ++ flag_strict_volatile_bitfields = 1; ++ + /* Register global variables with the garbage collector. */ + arm_add_gc_roots (); + + +=== modified file 'gcc/stor-layout.c' +--- old/gcc/stor-layout.c 2010-04-02 18:54:46 +0000 ++++ new/gcc/stor-layout.c 2010-11-04 12:49:37 +0000 +@@ -593,11 +593,14 @@ + } + + /* See if we can use an ordinary integer mode for a bit-field. +- Conditions are: a fixed size that is correct for another mode +- and occupying a complete byte or bytes on proper boundary. */ ++ Conditions are: a fixed size that is correct for another mode, ++ occupying a complete byte or bytes on proper boundary, ++ and not volatile or not -fstrict-volatile-bitfields. */ + if (TYPE_SIZE (type) != 0 + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST +- && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT) ++ && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT ++ && !(TREE_THIS_VOLATILE (decl) ++ && flag_strict_volatile_bitfields > 0)) + { + enum machine_mode xmode + = mode_for_size_tree (DECL_SIZE (decl), MODE_INT, 1); + +=== added file 'gcc/testsuite/gcc.target/arm/volatile-bitfields-1.c' +--- old/gcc/testsuite/gcc.target/arm/volatile-bitfields-1.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.target/arm/volatile-bitfields-1.c 2010-11-04 12:49:37 +0000 +@@ -0,0 +1,18 @@ ++/* { dg-require-effective-target arm_eabi } */ ++/* { dg-do compile } */ ++/* { dg-options "-O2" } */ ++ ++typedef struct { ++ char a:1; ++ char b:7; ++ int c; ++} BitStruct; ++ ++volatile BitStruct bits; ++ ++int foo () ++{ ++ return bits.b; ++} ++ ++/* { dg-final { scan-assembler "ldrb\[\\t \]+\[^\n\]*,\[\\t \]*\\\[\[^\n\]*\\\]" } } */ + +=== added file 'gcc/testsuite/gcc.target/arm/volatile-bitfields-2.c' +--- old/gcc/testsuite/gcc.target/arm/volatile-bitfields-2.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.target/arm/volatile-bitfields-2.c 2010-11-04 12:49:37 +0000 +@@ -0,0 +1,18 @@ ++/* { dg-require-effective-target arm_eabi } */ ++/* { dg-do compile } */ ++/* { dg-options "-O2" } */ ++ ++typedef struct { ++ volatile unsigned long a:8; ++ volatile unsigned long b:8; ++ volatile unsigned long c:16; ++} BitStruct; ++ ++BitStruct bits; ++ ++unsigned long foo () ++{ ++ return bits.b; ++} ++ ++/* { dg-final { scan-assembler "ldr\[\\t \]+\[^\n\]*,\[\\t \]*\\\[\[^\n\]*\\\]" } } */ + +=== added file 'gcc/testsuite/gcc.target/arm/volatile-bitfields-3.c' +--- old/gcc/testsuite/gcc.target/arm/volatile-bitfields-3.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.target/arm/volatile-bitfields-3.c 2010-11-04 12:49:37 +0000 +@@ -0,0 +1,18 @@ ++/* { dg-require-effective-target arm_eabi } */ ++/* { dg-do compile } */ ++/* { dg-options "-O2" } */ ++ ++typedef struct { ++ volatile unsigned long a:8; ++ volatile unsigned long b:8; ++ volatile unsigned long c:16; ++} BitStruct; ++ ++BitStruct bits; ++ ++unsigned long foo () ++{ ++ return bits.c; ++} ++ ++/* { dg-final { scan-assembler "ldr\[\\t \]+\[^\n\]*,\[\\t \]*\\\[\[^\n\]*\\\]" } } */ + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99426.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99426.patch new file mode 100644 index 0000000000..cf06e1ff74 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99426.patch @@ -0,0 +1,41 @@ + Backport from mainline: + + gcc/ + 2010-10-26 Jie Zhang + + * doc/invoke.texi: Improve documentation of + -fstrict-volatile-bitfields. + +=== modified file 'gcc/doc/invoke.texi' +--- old/gcc/doc/invoke.texi 2010-11-04 12:43:52 +0000 ++++ new/gcc/doc/invoke.texi 2010-11-04 14:29:09 +0000 +@@ -17633,8 +17633,8 @@ + @opindex fstrict-volatile-bitfields + This option should be used if accesses to volatile bitfields (or other + structure fields, although the compiler usually honors those types +-anyway) should use a single access in a mode of the same size as the +-container's type, aligned to a natural alignment if possible. For ++anyway) should use a single access of the width of the ++field's type, aligned to a natural alignment if possible. For + example, targets with memory-mapped peripheral registers might require + all such accesses to be 16 bits wide; with this flag the user could + declare all peripheral bitfields as ``unsigned short'' (assuming short +@@ -17647,11 +17647,13 @@ + any portion of the bitfield, or memory-mapped registers unrelated to + the one being updated. + +-If the target requires strict alignment, and honoring the container ++If the target requires strict alignment, and honoring the field + type would require violating this alignment, a warning is issued. +-However, the access happens as the user requested, under the +-assumption that the user knows something about the target hardware +-that GCC is unaware of. ++If the field has @code{packed} attribute, the access is done without ++honoring the field type. If the field doesn't have @code{packed} ++attribute, the access is done honoring the field type. In both cases, ++GCC assumes that the user knows something about the target hardware ++that it is unaware of. + + The default value of this option is determined by the application binary + interface for the target processor. + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99429.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99429.patch new file mode 100644 index 0000000000..63ba95e0e3 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99429.patch @@ -0,0 +1,1257 @@ +2010-11-09 Michael Hope + + Revert: + + Backport from mainline: + + 2010-07-15 Bernd Schmidt + + 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 + + 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 + + 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 + + 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 + + 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 + + gcc/ + * postreload.c (reload_combine_recognize_const_pattern): Move test + for limiting the insn movement to the right scope. + + 2010-07-27 Bernd Schmidt + + 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-10-14 11:25:44 +0000 ++++ new/gcc/Makefile.in 2010-11-08 22:08:43 +0000 +@@ -3155,7 +3155,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) $(TARGET_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) ++ $(OBSTACK_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/postreload.c' +--- old/gcc/postreload.c 2010-10-14 11:32:02 +0000 ++++ new/gcc/postreload.c 2010-11-08 22:08:43 +0000 +@@ -44,7 +44,6 @@ + #include "toplev.h" + #include "except.h" + #include "tree.h" +-#include "target.h" + #include "timevar.h" + #include "tree-pass.h" + #include "df.h" +@@ -57,10 +56,10 @@ + static int reload_cse_simplify_operands (rtx, rtx); + + static void reload_combine (void); +-static void reload_combine_note_use (rtx *, rtx, int, rtx); ++static void reload_combine_note_use (rtx *, rtx); + static void reload_combine_note_store (rtx, const_rtx, void *); + +-static bool reload_cse_move2add (rtx); ++static void reload_cse_move2add (rtx); + static void move2add_note_store (rtx, const_rtx, void *); + + /* Call cse / combine like post-reload optimization phases. +@@ -68,16 +67,11 @@ + void + reload_cse_regs (rtx first ATTRIBUTE_UNUSED) + { +- bool moves_converted; + reload_cse_regs_1 (first); + reload_combine (); +- moves_converted = reload_cse_move2add (first); ++ reload_cse_move2add (first); + if (flag_expensive_optimizations) +- { +- if (moves_converted) +- reload_combine (); +- reload_cse_regs_1 (first); +- } ++ reload_cse_regs_1 (first); + } + + /* See whether a single set SET is a noop. */ +@@ -666,43 +660,30 @@ + + /* 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 16 ++#define RELOAD_COMBINE_MAX_USES 6 + +-/* 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; +-}; ++/* 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; }; + + /* 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 is first set or clobbered. ++ indicates where it becomes live again. + 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). +- 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. ++ 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. + STORE_RUID is always meaningful if we only want to use a value in a + register in a different place: it denotes the next insn in the insn +- stream (i.e. the last encountered) that sets or clobbers the register. +- REAL_STORE_RUID is similar, but clobbers are ignored when updating it. */ ++ stream (i.e. the last encountered) that sets or clobbers the register. */ + static struct + { + struct reg_use reg_use[RELOAD_COMBINE_MAX_USES]; ++ int use_index; + rtx offset; +- int use_index; + 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 +@@ -710,548 +691,42 @@ + 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, prev; ++ rtx insn, set; ++ int first_index_reg = -1; ++ int last_index_reg = 0; + 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. */ +- 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; +- } +- } ++ 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; + + /* Set up LABEL_LIVE and EVER_LIVE_AT_START. The register lifetime + information is a bit fuzzy immediately after reload, but it's +@@ -1278,23 +753,20 @@ + } + + /* Initialize last_label_ruid, reload_combine_ruid and reg_state. */ +- last_label_ruid = last_jump_ruid = reload_combine_ruid = 0; ++ last_label_ruid = reload_combine_ruid = 0; + for (r = 0; r < FIRST_PSEUDO_REGISTER; r++) + { +- reg_state[r].store_ruid = 0; +- reg_state[r].real_store_ruid = 0; ++ reg_state[r].store_ruid = reload_combine_ruid; + 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) ++ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) + { + 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. */ +@@ -1305,17 +777,141 @@ + if (! fixed_regs[r]) + reg_state[r].use_index = RELOAD_COMBINE_MAX_USES; + +- if (! NONDEBUG_INSN_P (insn)) ++ if (! INSN_P (insn)) + continue; + + reload_combine_ruid++; + +- 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; ++ /* 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; ++ } ++ } ++ } + + note_stores (PATTERN (insn), reload_combine_note_store, NULL); + +@@ -1371,8 +967,7 @@ + reg_state[i].use_index = -1; + } + +- reload_combine_note_use (&PATTERN (insn), insn, +- reload_combine_ruid, NULL_RTX); ++ reload_combine_note_use (&PATTERN (insn), insn); + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) + { + if (REG_NOTE_KIND (note) == REG_INC +@@ -1381,7 +976,6 @@ + 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; + } + } +@@ -1391,8 +985,8 @@ + } + + /* Check if DST is a register or a subreg of a register; if it is, +- update store_ruid, real_store_ruid and use_index in the reg_state +- structure accordingly. Called via note_stores from reload_combine. */ ++ update reg_state[regno].store_ruid and reg_state[regno].use_index ++ accordingly. Called via note_stores from reload_combine. */ + + static void + reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED) +@@ -1416,14 +1010,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_DEST (set)) == ZERO_EXTRACT ++ if (GET_CODE (set) != SET ++ || 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 +@@ -1431,8 +1025,6 @@ + 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; + } + } +@@ -1443,7 +1035,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, int ruid, rtx containing_mem) ++reload_combine_note_use (rtx *xp, rtx insn) + { + rtx x = *xp; + enum rtx_code code = x->code; +@@ -1456,7 +1048,7 @@ + case SET: + if (REG_P (SET_DEST (x))) + { +- reload_combine_note_use (&SET_SRC (x), insn, ruid, NULL_RTX); ++ reload_combine_note_use (&SET_SRC (x), insn); + return; + } + break; +@@ -1512,11 +1104,6 @@ + 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 +@@ -1525,34 +1112,29 @@ + if (use_index < 0) + return; + +- if (use_index == RELOAD_COMBINE_MAX_USES - 1) ++ 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 + { + /* 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].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].use_ruid = reload_combine_ruid; ++ } + 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; + } +@@ -1562,12 +1144,11 @@ + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') +- reload_combine_note_use (&XEXP (x, i), insn, ruid, containing_mem); ++ reload_combine_note_use (&XEXP (x, i), insn); + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) +- reload_combine_note_use (&XVECEXP (x, i, j), insn, ruid, +- containing_mem); ++ reload_combine_note_use (&XVECEXP (x, i, j), insn); + } + } + } +@@ -1615,10 +1196,9 @@ + while REG is known to already have value (SYM + offset). + This function tries to change INSN into an add instruction + (set (REG) (plus (REG) (OFF - offset))) using the known value. +- It also updates the information about REG's known value. +- Return true if we made a change. */ ++ It also updates the information about REG's known value. */ + +-static bool ++static void + move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn) + { + rtx pat = PATTERN (insn); +@@ -1627,7 +1207,6 @@ + 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. +@@ -1642,13 +1221,13 @@ + (reg)), would be discarded. Maybe we should + try a truncMN pattern? */ + if (INTVAL (off) == reg_offset [regno]) +- changed = validate_change (insn, &SET_SRC (pat), reg, 0); ++ 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); +- changed = validate_change (insn, &SET_SRC (pat), tem, 0); ++ validate_change (insn, &SET_SRC (pat), tem, 0); + } + else if (sym == NULL_RTX && GET_MODE (reg) != BImode) + { +@@ -1673,9 +1252,8 @@ + gen_rtx_STRICT_LOW_PART (VOIDmode, + narrow_reg), + narrow_src); +- changed = validate_change (insn, &PATTERN (insn), +- new_set, 0); +- if (changed) ++ if (validate_change (insn, &PATTERN (insn), ++ new_set, 0)) + break; + } + } +@@ -1685,7 +1263,6 @@ + reg_mode[regno] = GET_MODE (reg); + reg_symbol_ref[regno] = sym; + reg_offset[regno] = INTVAL (off); +- return changed; + } + + +@@ -1695,10 +1272,9 @@ + 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. +- Return true iff we made a change. */ ++ REG's known value. */ + +-static bool ++static void + move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn) + { + rtx pat = PATTERN (insn); +@@ -1708,7 +1284,6 @@ + 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 +@@ -1753,25 +1328,20 @@ + GET_MODE (reg)); + tem = gen_rtx_PLUS (GET_MODE (reg), tem, new_src); + } +- if (validate_change (insn, &SET_SRC (pat), tem, 0)) +- changed = true; ++ 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); +- return changed; + } + +-/* Convert move insns with constant inputs to additions if they are cheaper. +- Return true if any changes were made. */ +-static bool ++static void + reload_cse_move2add (rtx first) + { + int i; + rtx insn; +- bool changed = false; + + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) + { +@@ -1832,7 +1402,7 @@ + && reg_base_reg[regno] < 0 + && reg_symbol_ref[regno] == NULL_RTX) + { +- changed |= move2add_use_add2_insn (reg, NULL_RTX, src, insn); ++ move2add_use_add2_insn (reg, NULL_RTX, src, insn); + continue; + } + +@@ -1893,7 +1463,6 @@ + } + if (success) + delete_insn (insn); +- changed |= success; + insn = next; + reg_mode[regno] = GET_MODE (reg); + reg_offset[regno] = +@@ -1939,12 +1508,12 @@ + && reg_base_reg[regno] < 0 + && reg_symbol_ref[regno] != NULL_RTX + && rtx_equal_p (sym, reg_symbol_ref[regno])) +- changed |= move2add_use_add2_insn (reg, sym, off, insn); ++ 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 +- changed |= move2add_use_add3_insn (reg, sym, off, insn); ++ move2add_use_add3_insn (reg, sym, off, insn); + + continue; + } +@@ -1999,7 +1568,6 @@ + } + } + } +- return changed; + } + + /* SET is a SET or CLOBBER that sets DST. DATA is the insn which + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch new file mode 100644 index 0000000000..b63c9b35e7 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch @@ -0,0 +1,70 @@ +2010-11-03 Nathan Froyd + + Issue #10002 + + gcc/ + * config/arm/arm.c (arm_legitimate_index_p): Split + VALID_NEON_QREG_MODE and VALID_NEON_DREG_MODE cases. Permit + slightly larger constants in the latter case. + (thumb2_legitimate_index_p): Likewise. + +=== modified file 'gcc/config/arm/arm.c' +--- old/gcc/config/arm/arm.c 2010-11-04 12:49:37 +0000 ++++ new/gcc/config/arm/arm.c 2010-11-11 11:00:53 +0000 +@@ -5611,13 +5611,25 @@ + && INTVAL (index) > -1024 + && (INTVAL (index) & 3) == 0); + +- if (TARGET_NEON +- && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode))) ++ /* For quad modes, we restrict the constant offset to be slightly less ++ than what the instruction format permits. We do this because for ++ quad mode moves, we will actually decompose them into two separate ++ double-mode reads or writes. INDEX must therefore be a valid ++ (double-mode) offset and so should INDEX+8. */ ++ if (TARGET_NEON && VALID_NEON_QREG_MODE (mode)) + return (code == CONST_INT + && INTVAL (index) < 1016 + && INTVAL (index) > -1024 + && (INTVAL (index) & 3) == 0); + ++ /* We have no such constraint on double mode offsets, so we permit the ++ full range of the instruction format. */ ++ if (TARGET_NEON && VALID_NEON_DREG_MODE (mode)) ++ return (code == CONST_INT ++ && INTVAL (index) < 1024 ++ && INTVAL (index) > -1024 ++ && (INTVAL (index) & 3) == 0); ++ + if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode)) + return (code == CONST_INT + && INTVAL (index) < 1024 +@@ -5731,13 +5743,25 @@ + && (INTVAL (index) & 3) == 0); + } + +- if (TARGET_NEON +- && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode))) ++ /* For quad modes, we restrict the constant offset to be slightly less ++ than what the instruction format permits. We do this because for ++ quad mode moves, we will actually decompose them into two separate ++ double-mode reads or writes. INDEX must therefore be a valid ++ (double-mode) offset and so should INDEX+8. */ ++ if (TARGET_NEON && VALID_NEON_QREG_MODE (mode)) + return (code == CONST_INT + && INTVAL (index) < 1016 + && INTVAL (index) > -1024 + && (INTVAL (index) & 3) == 0); + ++ /* We have no such constraint on double mode offsets, so we permit the ++ full range of the instruction format. */ ++ if (TARGET_NEON && VALID_NEON_DREG_MODE (mode)) ++ return (code == CONST_INT ++ && INTVAL (index) < 1024 ++ && INTVAL (index) > -1024 ++ && (INTVAL (index) & 3) == 0); ++ + if (arm_address_register_rtx_p (index, strict_p) + && (GET_MODE_SIZE (mode) <= 4)) + return 1; + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99433.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99433.patch new file mode 100644 index 0000000000..6bc33f2be2 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99433.patch @@ -0,0 +1,40 @@ +2010-10-29 Julian Brown + + Launchpad #629671 + + gcc/ + * config/arm/arm.h (REG_CLASS_CONTENTS): Remove soft frame pointer + from CORE_REGS and GENERAL_REGS classes. + * config/arm/arm.md (*thumb1_movsi_insn): Ignore all parts of final + constraint for register preferencing. + +=== modified file 'gcc/config/arm/arm.h' +--- old/gcc/config/arm/arm.h 2010-11-04 10:45:05 +0000 ++++ new/gcc/config/arm/arm.h 2010-11-11 11:12:14 +0000 +@@ -1262,8 +1262,8 @@ + { 0x0000DF00, 0x00000000, 0x00000000, 0x00000000 }, /* HI_REGS */ \ + { 0x01000000, 0x00000000, 0x00000000, 0x00000000 }, /* CC_REG */ \ + { 0x00000000, 0x00000000, 0x00000000, 0x80000000 }, /* VFPCC_REG */ \ +- { 0x0200DFFF, 0x00000000, 0x00000000, 0x00000000 }, /* GENERAL_REGS */ \ +- { 0x0200FFFF, 0x00000000, 0x00000000, 0x00000000 }, /* CORE_REGS */ \ ++ { 0x0000DFFF, 0x00000000, 0x00000000, 0x00000000 }, /* GENERAL_REGS */ \ ++ { 0x0000FFFF, 0x00000000, 0x00000000, 0x00000000 }, /* CORE_REGS */ \ + { 0xFAFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF } /* ALL_REGS */ \ + } + + +=== modified file 'gcc/config/arm/arm.md' +--- old/gcc/config/arm/arm.md 2010-11-04 10:45:05 +0000 ++++ new/gcc/config/arm/arm.md 2010-11-11 11:12:14 +0000 +@@ -5160,8 +5160,8 @@ + }) + + (define_insn "*thumb1_movsi_insn" +- [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*lhk") +- (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,mi,l,*lhk"))] ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*l*h*k") ++ (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,mi,l,*l*h*k"))] + "TARGET_THUMB1 + && ( register_operand (operands[0], SImode) + || register_operand (operands[1], SImode))" + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99434.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99434.patch new file mode 100644 index 0000000000..adda68c62e --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99434.patch @@ -0,0 +1,30 @@ +2010-11-3 Chung-Lin Tang + + Backport from mainline: + + 2010-11-02 Chung-Lin Tang + + gcc/ + * Makefile.in (LIBGCC2_CFLAGS): Add -fno-stack-protector, to + explicitly disable stack protection when building libgcc. + (CRTSTUFF_CFLAGS): Same, for crtbegin/end. + +--- old/gcc/Makefile.in 2010-11-08 22:08:43 +0000 ++++ new/gcc/Makefile.in 2010-11-11 11:34:59 +0000 +@@ -646,6 +646,7 @@ + LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) \ + $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) \ + -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED \ ++ -fno-stack-protector \ + $(INHIBIT_LIBC_CFLAGS) + + # Additional options to use when compiling libgcc2.a. +@@ -659,6 +660,7 @@ + CRTSTUFF_CFLAGS = -O2 $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \ + -finhibit-size-directive -fno-inline -fno-exceptions \ + -fno-zero-initialized-in-bss -fno-toplevel-reorder -fno-tree-vectorize \ ++ -fno-stack-protector \ + $(INHIBIT_LIBC_CFLAGS) + + # Additional sources to handle exceptions; overridden by targets as needed. + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99435.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99435.patch new file mode 100644 index 0000000000..d66df137fa --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99435.patch @@ -0,0 +1,32 @@ +2010-11-08 Yao Qi + + Backport from mainline: + + gcc/ + 2010-08-02 Bernd Schmidt + + * config/arm/arm.c (arm_rtx_costs_1): Remove second clause from the + if statement which adds extra costs to frame-related + expressions. + +=== modified file 'gcc/config/arm/arm.c' +--- old/gcc/config/arm/arm.c 2010-11-11 11:00:53 +0000 ++++ new/gcc/config/arm/arm.c 2010-11-11 11:50:33 +0000 +@@ -6805,12 +6805,10 @@ + since then they might not be moved outside of loops. As a compromise + we allow integration with ops that have a constant as their second + operand. */ +- if ((REG_OR_SUBREG_REG (XEXP (x, 0)) +- && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))) +- && GET_CODE (XEXP (x, 1)) != CONST_INT) +- || (REG_OR_SUBREG_REG (XEXP (x, 0)) +- && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))))) +- *total = 4; ++ if (REG_OR_SUBREG_REG (XEXP (x, 0)) ++ && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))) ++ && GET_CODE (XEXP (x, 1)) != CONST_INT) ++ *total = COSTS_N_INSNS (1); + + if (mode == DImode) + { + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99436.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99436.patch new file mode 100644 index 0000000000..deb749efcb --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99436.patch @@ -0,0 +1,209 @@ +2010-11-24 Maxim Kuvyrkov + + gcc/ + * combine.c (subst, combine_simlify_rtx): Add new argument, use it + to track processing of conditionals. Update all callers. + (try_combine, simplify_if_then_else): Update. + +=== modified file 'gcc/combine.c' +--- old/gcc/combine.c 2010-11-04 12:39:28 +0000 ++++ new/gcc/combine.c 2010-11-25 11:11:45 +0000 +@@ -392,8 +392,8 @@ + static void undo_all (void); + static void undo_commit (void); + static rtx *find_split_point (rtx *, rtx); +-static rtx subst (rtx, rtx, rtx, int, int); +-static rtx combine_simplify_rtx (rtx, enum machine_mode, int); ++static rtx subst (rtx, rtx, rtx, int, int, int); ++static rtx combine_simplify_rtx (rtx, enum machine_mode, int, int); + static rtx simplify_if_then_else (rtx); + static rtx simplify_set (rtx); + static rtx simplify_logical (rtx); +@@ -2944,12 +2944,12 @@ + if (i1) + { + subst_low_luid = DF_INSN_LUID (i1); +- i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0); ++ i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0, 0); + } + else + { + subst_low_luid = DF_INSN_LUID (i2); +- i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0); ++ i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0); + } + } + +@@ -2960,7 +2960,7 @@ + to avoid self-referential rtl. */ + + subst_low_luid = DF_INSN_LUID (i2); +- newpat = subst (PATTERN (i3), i2dest, i2src, 0, ++ newpat = subst (PATTERN (i3), i2dest, i2src, 0, 0, + ! i1_feeds_i3 && i1dest_in_i1src); + substed_i2 = 1; + +@@ -2991,7 +2991,7 @@ + + n_occurrences = 0; + subst_low_luid = DF_INSN_LUID (i1); +- newpat = subst (newpat, i1dest, i1src, 0, 0); ++ newpat = subst (newpat, i1dest, i1src, 0, 0, 0); + substed_i1 = 1; + } + +@@ -3053,7 +3053,7 @@ + else + /* See comment where i2pat is assigned. */ + XVECEXP (newpat, 0, --total_sets) +- = subst (i2pat, i1dest, i1src, 0, 0); ++ = subst (i2pat, i1dest, i1src, 0, 0, 0); + } + } + +@@ -4605,11 +4605,13 @@ + + IN_DEST is nonzero if we are processing the SET_DEST of a SET. + ++ IN_COND is nonzero if we are on top level of the condition. ++ + UNIQUE_COPY is nonzero if each substitution must be unique. We do this + by copying if `n_occurrences' is nonzero. */ + + static rtx +-subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy) ++subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy) + { + enum rtx_code code = GET_CODE (x); + enum machine_mode op0_mode = VOIDmode; +@@ -4670,7 +4672,7 @@ + && GET_CODE (XVECEXP (x, 0, 0)) == SET + && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS) + { +- new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy); ++ new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, 0, unique_copy); + + /* If this substitution failed, this whole thing fails. */ + if (GET_CODE (new_rtx) == CLOBBER +@@ -4687,7 +4689,7 @@ + && GET_CODE (dest) != CC0 + && GET_CODE (dest) != PC) + { +- new_rtx = subst (dest, from, to, 0, unique_copy); ++ new_rtx = subst (dest, from, to, 0, 0, unique_copy); + + /* If this substitution failed, this whole thing fails. */ + if (GET_CODE (new_rtx) == CLOBBER +@@ -4733,8 +4735,8 @@ + } + else + { +- new_rtx = subst (XVECEXP (x, i, j), from, to, 0, +- unique_copy); ++ new_rtx = subst (XVECEXP (x, i, j), from, to, 0, 0, ++ unique_copy); + + /* If this substitution failed, this whole thing + fails. */ +@@ -4811,7 +4813,9 @@ + && (code == SUBREG || code == STRICT_LOW_PART + || code == ZERO_EXTRACT)) + || code == SET) +- && i == 0), unique_copy); ++ && i == 0), ++ code == IF_THEN_ELSE && i == 0, ++ unique_copy); + + /* If we found that we will have to reject this combination, + indicate that by returning the CLOBBER ourselves, rather than +@@ -4868,7 +4872,7 @@ + /* If X is sufficiently simple, don't bother trying to do anything + with it. */ + if (code != CONST_INT && code != REG && code != CLOBBER) +- x = combine_simplify_rtx (x, op0_mode, in_dest); ++ x = combine_simplify_rtx (x, op0_mode, in_dest, in_cond); + + if (GET_CODE (x) == code) + break; +@@ -4888,10 +4892,12 @@ + expression. + + OP0_MODE is the original mode of XEXP (x, 0). IN_DEST is nonzero +- if we are inside a SET_DEST. */ ++ if we are inside a SET_DEST. IN_COND is nonzero if we are on the top level ++ of a condition. */ + + static rtx +-combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest) ++combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest, ++ int in_cond) + { + enum rtx_code code = GET_CODE (x); + enum machine_mode mode = GET_MODE (x); +@@ -4946,8 +4952,8 @@ + false arms to store-flag values. Be careful to use copy_rtx + here since true_rtx or false_rtx might share RTL with x as a + result of the if_then_else_cond call above. */ +- true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0); +- false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0); ++ true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0, 0); ++ false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0, 0); + + /* If true_rtx and false_rtx are not general_operands, an if_then_else + is unlikely to be simpler. */ +@@ -5291,7 +5297,7 @@ + { + /* Try to simplify the expression further. */ + rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1)); +- temp = combine_simplify_rtx (tor, mode, in_dest); ++ temp = combine_simplify_rtx (tor, mode, in_dest, 0); + + /* If we could, great. If not, do not go ahead with the IOR + replacement, since PLUS appears in many special purpose +@@ -5384,7 +5390,16 @@ + ZERO_EXTRACT is indeed appropriate, it will be placed back by + the call to make_compound_operation in the SET case. */ + +- if (STORE_FLAG_VALUE == 1 ++ if (in_cond) ++ /* Don't apply below optimizations if the caller would ++ prefer a comparison rather than a value. ++ E.g., for the condition in an IF_THEN_ELSE most targets need ++ an explicit comparison. */ ++ { ++ ; ++ } ++ ++ else if (STORE_FLAG_VALUE == 1 + && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && mode == GET_MODE (op0) +@@ -5628,11 +5643,11 @@ + if (reg_mentioned_p (from, true_rtx)) + true_rtx = subst (known_cond (copy_rtx (true_rtx), true_code, + from, true_val), +- pc_rtx, pc_rtx, 0, 0); ++ pc_rtx, pc_rtx, 0, 0, 0); + if (reg_mentioned_p (from, false_rtx)) + false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code, + from, false_val), +- pc_rtx, pc_rtx, 0, 0); ++ pc_rtx, pc_rtx, 0, 0, 0); + + SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx); + SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx); +@@ -5849,11 +5864,11 @@ + { + temp = subst (simplify_gen_relational (true_code, m, VOIDmode, + cond_op0, cond_op1), +- pc_rtx, pc_rtx, 0, 0); ++ pc_rtx, pc_rtx, 0, 0, 0); + temp = simplify_gen_binary (MULT, m, temp, + simplify_gen_binary (MULT, m, c1, + const_true_rtx)); +- temp = subst (temp, pc_rtx, pc_rtx, 0, 0); ++ temp = subst (temp, pc_rtx, pc_rtx, 0, 0, 0); + temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp); + + if (extend_op != UNKNOWN) + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99437.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99437.patch new file mode 100644 index 0000000000..94d9666084 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99437.patch @@ -0,0 +1,27 @@ +2010-11-24 Richard Sandiford + + Launchpad #618684 + + Backport from mainline: + + 2010-04-10 Bernd Schmidt + + * reload1.c (eliminate_regs_in_insn): Don't restore an operand + if doing so would replace the entire pattern. + +=== modified file 'gcc/reload1.c' +--- old/gcc/reload1.c 2010-10-04 00:50:43 +0000 ++++ new/gcc/reload1.c 2010-11-24 13:40:23 +0000 +@@ -3567,7 +3567,10 @@ + { + /* Restore the old body. */ + for (i = 0; i < recog_data.n_operands; i++) +- *recog_data.operand_loc[i] = orig_operand[i]; ++ /* Restoring a top-level match_parallel would clobber the new_body ++ we installed in the insn. */ ++ if (recog_data.operand_loc[i] != &PATTERN (insn)) ++ *recog_data.operand_loc[i] = orig_operand[i]; + for (i = 0; i < recog_data.n_dups; i++) + *recog_data.dup_loc[i] = orig_operand[(int) recog_data.dup_num[i]]; + } + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch new file mode 100644 index 0000000000..cec7f57d47 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch @@ -0,0 +1,1500 @@ +2010-11-16 Chung-Lin Tang + + 2010-07-21 Richard Henderson + + 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 + + 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 + + Re-merge, backport from mainline: + + 2010-07-15 Bernd Schmidt + + 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 + + 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 + + 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 + + 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 + + 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 + + gcc/ + * postreload.c (reload_combine_recognize_const_pattern): Move test + for limiting the insn movement to the right scope. + + 2010-07-27 Bernd Schmidt + + 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 + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch new file mode 100644 index 0000000000..b7a28de658 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch @@ -0,0 +1,78 @@ +2010-11-24 Chung-Lin Tang + + 2010-07-08 Ramana Radhakrishnan + + PR bootstrap/44768 + + * cfgexpand.c (estimated_stack_frame_size): Make self-contained + with respect to current_function_decl. Pass decl of the function. + * tree-inline.h (estimated_stack_frame_size): Adjust prototype. + * ipa-inline.c (compute_inline_parameters): Pass decl to + estimated_stack_frame_size. + +=== modified file 'gcc/cfgexpand.c' +--- old/gcc/cfgexpand.c 2010-10-04 00:50:43 +0000 ++++ new/gcc/cfgexpand.c 2010-11-24 08:43:48 +0000 +@@ -1248,8 +1248,8 @@ + stack_vars_alloc = stack_vars_num = 0; + } + +-/* Make a fair guess for the size of the stack frame of the current +- function. This doesn't have to be exact, the result is only used ++/* Make a fair guess for the size of the stack frame of the decl ++ passed. This doesn't have to be exact, the result is only used + in the inline heuristics. So we don't want to run the full stack + var packing algorithm (which is quadratic in the number of stack + vars). Instead, we calculate the total size of all stack vars. +@@ -1257,11 +1257,14 @@ + vars doesn't happen very often. */ + + HOST_WIDE_INT +-estimated_stack_frame_size (void) ++estimated_stack_frame_size (tree decl) + { + HOST_WIDE_INT size = 0; + size_t i; + tree t, outer_block = DECL_INITIAL (current_function_decl); ++ tree old_cur_fun_decl = current_function_decl; ++ current_function_decl = decl; ++ push_cfun (DECL_STRUCT_FUNCTION (decl)); + + init_vars_expansion (); + +@@ -1284,7 +1287,8 @@ + size += account_stack_vars (); + fini_vars_expansion (); + } +- ++ pop_cfun (); ++ current_function_decl = old_cur_fun_decl; + return size; + } + + +=== modified file 'gcc/ipa-inline.c' +--- old/gcc/ipa-inline.c 2010-06-30 21:30:12 +0000 ++++ new/gcc/ipa-inline.c 2010-11-24 08:43:48 +0000 +@@ -1967,7 +1967,7 @@ + + /* Estimate the stack size for the function. But not at -O0 + because estimated_stack_frame_size is a quadratic problem. */ +- self_stack_size = optimize ? estimated_stack_frame_size () : 0; ++ self_stack_size = optimize ? estimated_stack_frame_size (node->decl) : 0; + inline_summary (node)->estimated_self_stack_size = self_stack_size; + node->global.estimated_stack_size = self_stack_size; + node->global.stack_frame_offset = 0; + +=== modified file 'gcc/tree-inline.h' +--- old/gcc/tree-inline.h 2009-09-14 18:18:58 +0000 ++++ new/gcc/tree-inline.h 2010-11-24 08:43:48 +0000 +@@ -187,6 +187,6 @@ + extern tree remap_type (tree type, copy_body_data *id); + extern gimple_seq copy_gimple_seq_and_replace_locals (gimple_seq seq); + +-extern HOST_WIDE_INT estimated_stack_frame_size (void); ++extern HOST_WIDE_INT estimated_stack_frame_size (tree); + + #endif /* GCC_TREE_INLINE_H */ + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99441.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99441.patch new file mode 100644 index 0000000000..5495b8d80a --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99441.patch @@ -0,0 +1,33 @@ +2010-11-25 Andrew Stubbs + + Backport from mainline: + + 2010-10-28 Andrew Stubbs + + gcc/ + * config/arm/arm.c (const_ok_for_arm): Support 0xXY00XY00 pattern + constants in thumb2. + +=== modified file 'gcc/config/arm/arm.c' +--- old/gcc/config/arm/arm.c 2010-11-11 11:50:33 +0000 ++++ new/gcc/config/arm/arm.c 2010-12-10 15:30:47 +0000 +@@ -2340,11 +2340,17 @@ + { + HOST_WIDE_INT v; + +- /* Allow repeated pattern. */ ++ /* Allow repeated patterns 0x00XY00XY or 0xXYXYXYXY. */ + v = i & 0xff; + v |= v << 16; + if (i == v || i == (v | (v << 8))) + return TRUE; ++ ++ /* Allow repeated pattern 0xXY00XY00. */ ++ v = i & 0xff00; ++ v |= v << 16; ++ if (i == v) ++ return TRUE; + } + + return FALSE; + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99442.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99442.patch new file mode 100644 index 0000000000..62c44784b6 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99442.patch @@ -0,0 +1,23 @@ +2010-11-24 Maxim Kuvyrkov + + gcc/ + * loop-iv.c (get_biv_step): Workaround loop analysis ICE. + +=== modified file 'gcc/loop-iv.c' +--- old/gcc/loop-iv.c 2009-11-25 10:55:54 +0000 ++++ new/gcc/loop-iv.c 2010-12-10 15:32:04 +0000 +@@ -796,6 +796,13 @@ + outer_step)) + return false; + ++ /* CSL local: workaround get_biv_step_1() inability to handle DU ++ chains originating at sets of subregs. Such subregs are introduced ++ by Tom's extension elimination pass. For upstream duscussion see ++ http://gcc.gnu.org/ml/gcc/2010-11/msg00552.html . */ ++ if (!((*inner_mode == *outer_mode) != (*extend != UNKNOWN))) ++ return false; ++ + gcc_assert ((*inner_mode == *outer_mode) != (*extend != UNKNOWN)); + gcc_assert (*inner_mode != *outer_mode || *outer_step == const0_rtx); + + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch new file mode 100644 index 0000000000..802c3816f1 --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch @@ -0,0 +1,873 @@ +2010-11-26 Tom de Vries + + gcc/ + * gcc/ee.c: New file. + * gcc/tree-pass.h (pass_ee): Declare. + * gcc/opts.c (decode_options): Set flag_ee at -O2. + * gcc/timevar.def (TV_EE): New timevar. + * gcc/common.opt (fextension-elimination): New option. + * gcc/Makefile.in (ee.o): New rule. + * gcc/passes.c (pass_ee): Add it. + * gcc/testsuite/gcc.dg/extend-4.c: New test. + * gcc/testsuite/gcc.dg/extend-1.c: New test. + * gcc/testsuite/gcc.dg/extend-2.c: New test. + * gcc/testsuite/gcc.dg/extend-2-64.c: New test. + * gcc/testsuite/gcc.dg/extend-3.c: New test. + +=== modified file 'gcc/Makefile.in' +--- old/gcc/Makefile.in 2010-11-16 18:05:53 +0000 ++++ new/gcc/Makefile.in 2010-12-10 15:33:37 +0000 +@@ -1194,6 +1194,7 @@ + dse.o \ + dwarf2asm.o \ + dwarf2out.o \ ++ ee.o \ + ebitmap.o \ + emit-rtl.o \ + et-forest.o \ +@@ -2965,6 +2966,11 @@ + web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h $(TOPLEV_H) \ + $(DF_H) $(OBSTACK_H) $(TIMEVAR_H) $(TREE_PASS_H) ++ee.o : ee.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ ++ hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h \ ++ $(DF_H) $(TIMEVAR_H) tree-pass.h $(RECOG_H) $(EXPR_H) \ ++ $(REGS_H) $(TREE_H) $(TM_P_H) insn-config.h $(INSN_ATTR_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) \ ++ $(TARGET_H) $(OPTABS_H) insn-codes.h rtlhooks-def.h $(PARAMS_H) $(CGRAPH_H) + gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + $(REGS_H) hard-reg-set.h $(FLAGS_H) $(REAL_H) insn-config.h $(GGC_H) \ + $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h $(TOPLEV_H) \ + +=== modified file 'gcc/common.opt' +--- old/gcc/common.opt 2010-11-04 12:43:52 +0000 ++++ new/gcc/common.opt 2010-12-10 15:33:37 +0000 +@@ -496,6 +496,10 @@ + Common Report Var(flag_early_inlining) Init(1) Optimization + Perform early inlining + ++fextension-elimination ++Common Report Var(flag_ee) Init(0) Optimization ++Perform extension elimination ++ + feliminate-dwarf2-dups + Common Report Var(flag_eliminate_dwarf2_dups) + Perform DWARF2 duplicate elimination + +=== added file 'gcc/ee.c' +--- old/gcc/ee.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/ee.c 2010-12-10 15:33:37 +0000 +@@ -0,0 +1,662 @@ ++/* Redundant extension elimination ++ Copyright (C) 2010 Free Software Foundation, Inc. ++ Contributed by Tom de Vries (tom@codesourcery.com) ++ ++This file is part of GCC. ++ ++GCC is free software; you can redistribute it and/or modify it under ++the terms of the GNU General Public License as published by the Free ++Software Foundation; either version 3, or (at your option) any later ++version. ++ ++GCC is distributed in the hope that it will be useful, but WITHOUT ANY ++WARRANTY; without even the implied warranty of MERCHANTABILITY or ++FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ ++ ++/* ++ ++ MOTIVATING EXAMPLE ++ ++ The motivating example for this pass is: ++ ++ void f(unsigned char *p, short s, int c, int *z) ++ { ++ if (c) ++ *z = 0; ++ *p ^= (unsigned char)s; ++ } ++ ++ For MIPS, compilation results in the following insns. ++ ++ (set (reg/v:SI 199) ++ (sign_extend:SI (subreg:HI (reg:SI 200) 2))) ++ ++ ... ++ ++ (set (reg:QI 203) ++ (subreg:QI (reg/v:SI 199) 3)) ++ ++ These insns are the only def and the only use of reg 199, each located in a ++ different bb. ++ ++ The sign-extension preserves the lower half of reg 200 and copies them to ++ reg 199, and the subreg use of reg 199 only reads the least significant byte. ++ The sign extension is therefore redundant (the extension part, not the copy ++ part), and can safely be replaced with a regcopy from reg 200 to reg 199. ++ ++ ++ OTHER SIGN/ZERO EXTENSION ELIMINATION PASSES ++ ++ There are other passes which eliminate sign/zero-extension: combine and ++ implicit_zee. Both attempt to eliminate extensions by combining them with ++ other instructions. The combine pass does this at bb level, ++ implicit_zee works at inter-bb level. ++ ++ The combine pass combine an extension with either: ++ - all uses of the extension, or ++ - all defs of the operand of the extension. ++ The implicit_zee pass only implements the latter. ++ ++ For our motivating example, combine doesn't work since the def and the use of ++ reg 199 are in a different bb. ++ ++ Implicit_zee does not work since it only combines an extension with the defs ++ of its operand. ++ ++ ++ INTENDED EFFECT ++ ++ This pass works by removing sign/zero-extensions, or replacing them with ++ regcopies. The idea there is that the regcopy might be eliminated by a later ++ pass. In case the regcopy cannot be eliminated, it might at least be cheaper ++ than the extension. ++ ++ ++ IMPLEMENTATION ++ ++ The pass scans twice over all instructions. ++ ++ The first scan registers all uses of a reg in the biggest_use array. After ++ that first scan, the biggest_use array contains the size in bits of the ++ biggest use of each reg. ++ ++ The second scan finds extensions, determines whether they are redundant based ++ on the biggest use, and deletes or replaces them. ++ ++ In case that the src and dest reg of the replacement are not of the same size, ++ we do not replace with a normal regcopy, but with a truncate or with the copy ++ of a paradoxical subreg instead. ++ ++ ++ LIMITATIONS ++ ++ The scope of the analysis is limited to an extension and its uses. The other ++ type of analysis (related to the defs of the operand of an extension) is not ++ done. ++ ++ Furthermore, we do the analysis of biggest use per reg. So when determining ++ whether an extension is redundant, we take all uses of a the dest reg into ++ account, also the ones that are not uses of the extension. This could be ++ overcome by calculating the def-use chains and using those for analysis ++ instead. ++ ++ Finally, during the analysis each insn is looked at in isolation. There is no ++ propagation of information during the analysis. To overcome this limitation, ++ a backward iterative bit-level liveness analysis is needed. */ ++ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "rtl.h" ++#include "tree.h" ++#include "tm_p.h" ++#include "flags.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "basic-block.h" ++#include "insn-config.h" ++#include "function.h" ++#include "expr.h" ++#include "insn-attr.h" ++#include "recog.h" ++#include "toplev.h" ++#include "target.h" ++#include "timevar.h" ++#include "optabs.h" ++#include "insn-codes.h" ++#include "rtlhooks-def.h" ++#include "output.h" ++#include "params.h" ++#include "timevar.h" ++#include "tree-pass.h" ++#include "cgraph.h" ++ ++#define SKIP_REG (-1) ++ ++/* Array to register the biggest use of a reg, in bits. */ ++ ++static int *biggest_use; ++ ++/* Forward declaration. */ ++ ++static void note_use (rtx *x, void *data); ++ ++/* The following two functions are borrowed from trunk/gcc/toplev.c. They can be ++ removed for a check-in into gcc trunk. */ ++ ++/* Given X, an unsigned number, return the number of least significant bits ++ that are zero. When X == 0, the result is the word size. */ ++ ++static int ++ctz_hwi (unsigned HOST_WIDE_INT x) ++{ ++ return x ? floor_log2 (x & -x) : HOST_BITS_PER_WIDE_INT; ++} ++ ++/* Similarly for most significant bits. */ ++ ++static int ++clz_hwi (unsigned HOST_WIDE_INT x) ++{ ++ return HOST_BITS_PER_WIDE_INT - 1 - floor_log2(x); ++} ++ ++/* Check whether this is a paradoxical subreg. */ ++ ++static bool ++paradoxical_subreg_p (rtx subreg) ++{ ++ enum machine_mode subreg_mode, reg_mode; ++ ++ if (GET_CODE (subreg) != SUBREG) ++ return false; ++ ++ subreg_mode = GET_MODE (subreg); ++ reg_mode = GET_MODE (SUBREG_REG (subreg)); ++ ++ if (GET_MODE_SIZE (subreg_mode) > GET_MODE_SIZE (reg_mode)) ++ return true; ++ ++ return false; ++} ++ ++/* Get the size and reg number of a REG or SUBREG use. */ ++ ++static bool ++reg_use_p (rtx use, int *size, unsigned int *regno) ++{ ++ rtx reg; ++ ++ if (REG_P (use)) ++ { ++ *regno = REGNO (use); ++ *size = GET_MODE_BITSIZE (GET_MODE (use)); ++ return true; ++ } ++ else if (GET_CODE (use) == SUBREG) ++ { ++ reg = SUBREG_REG (use); ++ ++ if (!REG_P (reg)) ++ return false; ++ ++ *regno = REGNO (reg); ++ ++ if (paradoxical_subreg_p (use)) ++ *size = GET_MODE_BITSIZE (GET_MODE (reg)); ++ else ++ *size = subreg_lsb (use) + GET_MODE_BITSIZE (GET_MODE (use)); ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++/* Register the use of a reg. */ ++ ++static void ++register_use (int size, unsigned int regno) ++{ ++ int *current = &biggest_use[regno]; ++ ++ if (*current == SKIP_REG) ++ return; ++ ++ *current = MAX (*current, size); ++} ++ ++/* Handle embedded uses. */ ++ ++static void ++note_embedded_uses (rtx use, rtx pattern) ++{ ++ const char *format_ptr; ++ int i, j; ++ ++ format_ptr = GET_RTX_FORMAT (GET_CODE (use)); ++ for (i = 0; i < GET_RTX_LENGTH (GET_CODE (use)); i++) ++ if (format_ptr[i] == 'e') ++ note_use (&XEXP (use, i), pattern); ++ else if (format_ptr[i] == 'E') ++ for (j = 0; j < XVECLEN (use, i); j++) ++ note_use (&XVECEXP (use, i, j), pattern); ++} ++ ++/* Get the set that has use as its SRC operand. */ ++ ++static rtx ++get_set (rtx use, rtx pattern) ++{ ++ rtx sub; ++ int i; ++ ++ if (GET_CODE (pattern) == SET && SET_SRC (pattern) == use) ++ return pattern; ++ ++ if (GET_CODE (pattern) == PARALLEL) ++ for (i = 0; i < XVECLEN (pattern, 0); ++i) ++ { ++ sub = XVECEXP (pattern, 0, i); ++ if (GET_CODE (sub) == SET && SET_SRC (sub) == use) ++ return sub; ++ } ++ ++ return NULL_RTX; ++} ++ ++/* Handle a restricted op use. In this context restricted means that a bit in an ++ operand influences only the same bit or more significant bits in the result. ++ The bitwise ops are a subclass, but PLUS is one as well. */ ++ ++static void ++note_restricted_op_use (rtx use, unsigned int nr_operands, rtx pattern) ++{ ++ unsigned int i, smallest; ++ int operand_size[2]; ++ int used_size; ++ unsigned int operand_regno[2]; ++ bool operand_reg[2]; ++ bool operand_ignore[2]; ++ rtx set; ++ ++ /* Init operand_reg, operand_size, operand_regno and operand_ignore. */ ++ for (i = 0; i < nr_operands; ++i) ++ { ++ operand_reg[i] = reg_use_p (XEXP (use, i), &operand_size[i], ++ &operand_regno[i]); ++ operand_ignore[i] = false; ++ } ++ ++ /* Handle case of reg and-masked with const. */ ++ if (GET_CODE (use) == AND && CONST_INT_P (XEXP (use, 1)) && operand_reg[0]) ++ { ++ used_size = ++ HOST_BITS_PER_WIDE_INT - clz_hwi (UINTVAL (XEXP (use, 1))); ++ operand_size[0] = MIN (operand_size[0], used_size); ++ } ++ ++ /* Handle case of reg or-masked with const. */ ++ if (GET_CODE (use) == IOR && CONST_INT_P (XEXP (use, 1)) && operand_reg[0]) ++ { ++ used_size = ++ HOST_BITS_PER_WIDE_INT - clz_hwi (~UINTVAL (XEXP (use, 1))); ++ operand_size[0] = MIN (operand_size[0], used_size); ++ } ++ ++ /* Ignore the use of a in 'a = a + b'. */ ++ set = get_set (use, pattern); ++ if (set != NULL_RTX && REG_P (SET_DEST (set))) ++ for (i = 0; i < nr_operands; ++i) ++ operand_ignore[i] = (operand_reg[i] ++ && (REGNO (SET_DEST (set)) == operand_regno[i])); ++ ++ /* Handle the case a reg is combined with don't care bits. */ ++ if (nr_operands == 2 && operand_reg[0] && operand_reg[1] ++ && operand_size[0] != operand_size[1]) ++ { ++ smallest = operand_size[0] > operand_size[1]; ++ ++ if (paradoxical_subreg_p (XEXP (use, smallest)) ++ && !SUBREG_PROMOTED_VAR_P (XEXP (use, smallest))) ++ operand_size[1 - smallest] = operand_size[smallest]; ++ } ++ ++ /* Register the operand use, if necessary. */ ++ for (i = 0; i < nr_operands; ++i) ++ if (!operand_reg[i]) ++ note_use (&XEXP (use, i), pattern); ++ else if (!operand_ignore[i]) ++ register_use (operand_size[i], operand_regno[i]); ++} ++ ++/* Handle all uses noted by note_uses. */ ++ ++static void ++note_use (rtx *x, void *data) ++{ ++ rtx use = *x; ++ rtx pattern = (rtx)data; ++ int use_size; ++ unsigned int use_regno; ++ ++ switch (GET_CODE (use)) ++ { ++ case REG: ++ case SUBREG: ++ if (!reg_use_p (use, &use_size, &use_regno)) ++ { ++ note_embedded_uses (use, pattern); ++ return; ++ } ++ register_use (use_size, use_regno); ++ return; ++ case IOR: ++ case AND: ++ case XOR: ++ case PLUS: ++ case MINUS: ++ note_restricted_op_use (use, 2, pattern); ++ return; ++ case NOT: ++ case NEG: ++ note_restricted_op_use (use, 1, pattern); ++ return; ++ case ASHIFT: ++ if (!reg_use_p (XEXP (use, 0), &use_size, &use_regno) ++ || !CONST_INT_P (XEXP (use, 1)) ++ || INTVAL (XEXP (use, 1)) <= 0 ++ || paradoxical_subreg_p (XEXP (use, 0))) ++ { ++ note_embedded_uses (use, pattern); ++ return; ++ } ++ register_use (use_size - INTVAL (XEXP (use, 1)), use_regno); ++ return; ++ default: ++ note_embedded_uses (use, pattern); ++ return; ++ } ++} ++ ++/* Check whether reg is implicitly used. */ ++ ++static bool ++implicit_use_p (int regno) ++{ ++#ifdef EPILOGUE_USES ++ if (EPILOGUE_USES (regno)) ++ return true; ++#endif ++ ++#ifdef EH_USES ++ if (EH_USES (regno)) ++ return true; ++#endif ++ ++ return false; ++} ++ ++/* Note the uses of argument registers in a call. */ ++ ++static void ++note_call_uses (rtx insn) ++{ ++ rtx link, link_expr; ++ ++ if (!CALL_P (insn)) ++ return; ++ ++ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1)) ++ { ++ link_expr = XEXP (link, 0); ++ ++ if (GET_CODE (link_expr) == USE) ++ note_use (&XEXP (link_expr, 0), link); ++ } ++} ++ ++/* Calculate the biggest use mode for all regs. */ ++ ++static void ++calculate_biggest_use (void) ++{ ++ int i; ++ basic_block bb; ++ rtx insn; ++ ++ /* Initialize biggest_use for all regs to 0. If a reg is used implicitly, we ++ handle that reg conservatively and set it to SKIP_REG instead. */ ++ for (i = 0; i < max_reg_num (); i++) ++ biggest_use[i] = ((implicit_use_p (i) || HARD_REGISTER_NUM_P (i)) ++ ? SKIP_REG : 0); ++ ++ /* For all insns, call note_use for each use in insn. */ ++ FOR_EACH_BB (bb) ++ FOR_BB_INSNS (bb, insn) ++ { ++ if (!NONDEBUG_INSN_P (insn)) ++ continue; ++ ++ note_uses (&PATTERN (insn), note_use, PATTERN (insn)); ++ ++ if (CALL_P (insn)) ++ note_call_uses (insn); ++ } ++ ++ /* Dump the biggest uses found. */ ++ if (dump_file) ++ for (i = 0; i < max_reg_num (); i++) ++ if (biggest_use[i] > 0) ++ fprintf (dump_file, "reg %d: size %d\n", i, biggest_use[i]); ++} ++ ++/* Check whether this is a sign/zero extension. */ ++ ++static bool ++extension_p (rtx insn, rtx *dest, rtx *inner, int *preserved_size) ++{ ++ rtx src, op0; ++ ++ /* Detect set of reg. */ ++ if (GET_CODE (PATTERN (insn)) != SET) ++ return false; ++ ++ src = SET_SRC (PATTERN (insn)); ++ *dest = SET_DEST (PATTERN (insn)); ++ ++ if (!REG_P (*dest)) ++ return false; ++ ++ /* Detect sign or zero extension. */ ++ if (GET_CODE (src) == ZERO_EXTEND || GET_CODE (src) == SIGN_EXTEND ++ || (GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1)))) ++ { ++ op0 = XEXP (src, 0); ++ ++ /* Determine amount of least significant bits preserved by operation. */ ++ if (GET_CODE (src) == AND) ++ *preserved_size = ctz_hwi (~UINTVAL (XEXP (src, 1))); ++ else ++ *preserved_size = GET_MODE_BITSIZE (GET_MODE (op0)); ++ ++ if (GET_CODE (op0) == SUBREG) ++ { ++ if (subreg_lsb (op0) != 0) ++ return false; ++ ++ *inner = SUBREG_REG (op0); ++ return true; ++ } ++ else if (REG_P (op0)) ++ { ++ *inner = op0; ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/* Check whether this is a redundant sign/zero extension. */ ++ ++static bool ++redundant_extension_p (rtx insn, rtx *dest, rtx *inner) ++{ ++ int biggest_dest_use; ++ int preserved_size; ++ ++ if (!extension_p (insn, dest, inner, &preserved_size)) ++ return false; ++ ++ if (dump_file) ++ fprintf (dump_file, "considering extension %u with preserved size %d\n", ++ INSN_UID (insn), preserved_size); ++ ++ biggest_dest_use = biggest_use[REGNO (*dest)]; ++ ++ if (biggest_dest_use == SKIP_REG) ++ return false; ++ ++ if (preserved_size < biggest_dest_use) ++ return false; ++ ++ if (dump_file) ++ fprintf (dump_file, "found superfluous extension %u\n", INSN_UID (insn)); ++ ++ return true; ++} ++ ++/* Try to remove or replace the redundant extension. */ ++ ++static void ++try_remove_or_replace_extension (rtx insn, rtx dest, rtx inner) ++{ ++ rtx cp_src, cp_dest, seq, one; ++ ++ if (GET_MODE_CLASS (GET_MODE (dest)) != GET_MODE_CLASS (GET_MODE (inner))) ++ return; ++ ++ /* Check whether replacement is needed. */ ++ if (dest != inner) ++ { ++ start_sequence (); ++ ++ /* Determine the proper replacement operation. */ ++ if (GET_MODE (dest) == GET_MODE (inner)) ++ { ++ cp_src = inner; ++ cp_dest = dest; ++ } ++ else if (GET_MODE_SIZE (GET_MODE (dest)) ++ > GET_MODE_SIZE (GET_MODE (inner))) ++ { ++ emit_clobber (dest); ++ cp_src = inner; ++ cp_dest = gen_lowpart_SUBREG (GET_MODE (inner), dest); ++ } ++ else ++ { ++ cp_src = gen_rtx_TRUNCATE (GET_MODE (dest), inner); ++ cp_dest = dest; ++ } ++ ++ emit_move_insn (cp_dest, cp_src); ++ ++ seq = get_insns (); ++ end_sequence (); ++ ++ /* If the replacement is not supported, bail out. */ ++ for (one = seq; one != NULL_RTX; one = NEXT_INSN (one)) ++ if (recog_memoized (one) < 0 && GET_CODE (PATTERN (one)) != CLOBBER) ++ return; ++ ++ /* Insert the replacement. */ ++ emit_insn_before (seq, insn); ++ } ++ ++ /* Note replacement/removal in the dump. */ ++ if (dump_file) ++ { ++ fprintf (dump_file, "superfluous extension %u ", INSN_UID (insn)); ++ if (dest != inner) ++ fprintf (dump_file, "replaced by %u\n", INSN_UID (seq)); ++ else ++ fprintf (dump_file, "removed\n"); ++ } ++ ++ /* Remove the extension. */ ++ delete_insn (insn); ++} ++ ++/* Find redundant extensions and remove or replace them if possible. */ ++ ++static void ++remove_redundant_extensions (void) ++{ ++ basic_block bb; ++ rtx insn, next, dest, inner; ++ ++ biggest_use = XNEWVEC (int, max_reg_num ()); ++ calculate_biggest_use (); ++ ++ /* Remove redundant extensions. */ ++ FOR_EACH_BB (bb) ++ FOR_BB_INSNS_SAFE (bb, insn, next) ++ { ++ if (!NONDEBUG_INSN_P (insn)) ++ continue; ++ ++ if (!redundant_extension_p (insn, &dest, &inner)) ++ continue; ++ ++ try_remove_or_replace_extension (insn, dest, inner); ++ } ++ ++ free (biggest_use); ++} ++ ++/* Remove redundant extensions. */ ++ ++static unsigned int ++rest_of_handle_ee (void) ++{ ++ remove_redundant_extensions (); ++ return 0; ++} ++ ++/* Run ee pass when flag_ee is set at optimization level > 0. */ ++ ++static bool ++gate_handle_ee (void) ++{ ++ return (optimize > 0 && flag_ee); ++} ++ ++struct rtl_opt_pass pass_ee = ++{ ++ { ++ RTL_PASS, ++ "ee", /* name */ ++ gate_handle_ee, /* gate */ ++ rest_of_handle_ee, /* execute */ ++ NULL, /* sub */ ++ NULL, /* next */ ++ 0, /* static_pass_number */ ++ TV_EE, /* tv_id */ ++ 0, /* properties_required */ ++ 0, /* properties_provided */ ++ 0, /* properties_destroyed */ ++ 0, /* todo_flags_start */ ++ TODO_ggc_collect | ++ TODO_dump_func | ++ TODO_verify_rtl_sharing, /* todo_flags_finish */ ++ } ++}; + +=== modified file 'gcc/opts.c' +--- old/gcc/opts.c 2010-05-17 09:13:28 +0000 ++++ new/gcc/opts.c 2010-12-10 15:33:37 +0000 +@@ -907,6 +907,7 @@ + flag_tree_switch_conversion = opt2; + flag_ipa_cp = opt2; + flag_ipa_sra = opt2; ++ flag_ee = opt2; + + /* Track fields in field-sensitive alias analysis. */ + set_param_value ("max-fields-for-field-sensitive", + +=== modified file 'gcc/passes.c' +--- old/gcc/passes.c 2010-09-01 13:29:58 +0000 ++++ new/gcc/passes.c 2010-12-10 15:33:37 +0000 +@@ -974,6 +974,7 @@ + NEXT_PASS (pass_lower_subreg); + NEXT_PASS (pass_df_initialize_opt); + NEXT_PASS (pass_cse); ++ NEXT_PASS (pass_ee); + NEXT_PASS (pass_rtl_fwprop); + NEXT_PASS (pass_rtl_cprop); + NEXT_PASS (pass_rtl_pre); + +=== added file 'gcc/testsuite/gcc.dg/extend-1.c' +--- old/gcc/testsuite/gcc.dg/extend-1.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.dg/extend-1.c 2010-12-10 15:33:37 +0000 +@@ -0,0 +1,13 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-rtl-ee" } */ ++ ++void f(unsigned char * p, short s, int c, int *z) ++{ ++ if (c) ++ *z = 0; ++ *p ^= (unsigned char)s; ++} ++ ++/* { dg-final { scan-rtl-dump-times "sign_extend:" 0 "ee" { target mips*-*-* } } } */ ++/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 1 "ee" { target mips*-*-* } } } */ ++/* { dg-final { cleanup-rtl-dump "ee" } } */ + +=== added file 'gcc/testsuite/gcc.dg/extend-2-64.c' +--- old/gcc/testsuite/gcc.dg/extend-2-64.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.dg/extend-2-64.c 2010-12-10 15:33:37 +0000 +@@ -0,0 +1,20 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-rtl-ee" } */ ++/* { dg-require-effective-target mips64 } */ ++ ++void f(unsigned char * p, short *s, int c) ++{ ++ short or = 0; ++ while (c) ++ { ++ or = or | s[c]; ++ c --; ++ } ++ *p = (unsigned char)or; ++} ++ ++/* { dg-final { scan-rtl-dump-times "zero_extend:" 1 "ee" { target mips*-*-* } } } */ ++/* { dg-final { scan-rtl-dump-times "sign_extend:" 0 "ee" { target mips*-*-* } } } */ ++/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 3 "ee" { target mips*-*-* } } } */ ++/* { dg-final { cleanup-rtl-dump "ee" } } */ ++ + +=== added file 'gcc/testsuite/gcc.dg/extend-2.c' +--- old/gcc/testsuite/gcc.dg/extend-2.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.dg/extend-2.c 2010-12-10 15:33:37 +0000 +@@ -0,0 +1,20 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-rtl-ee" } */ ++/* { dg-require-effective-target ilp32 } */ ++ ++void f(unsigned char * p, short *s, int c) ++{ ++ short or = 0; ++ while (c) ++ { ++ or = or | s[c]; ++ c --; ++ } ++ *p = (unsigned char)or; ++} ++ ++/* { dg-final { scan-rtl-dump-times "zero_extend" 0 "ee" { target mips*-*-* } } } */ ++/* { dg-final { scan-rtl-dump-times "sign_extend" 0 "ee" { target mips*-*-* } } } */ ++/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 2 "ee" { target mips*-*-* } } } */ ++/* { dg-final { cleanup-rtl-dump "ee" } } */ ++ + +=== added file 'gcc/testsuite/gcc.dg/extend-3.c' +--- old/gcc/testsuite/gcc.dg/extend-3.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.dg/extend-3.c 2010-12-10 15:33:37 +0000 +@@ -0,0 +1,12 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-rtl-ee" } */ ++ ++unsigned int f(unsigned char byte) ++{ ++ return byte << 25; ++} ++ ++/* { dg-final { scan-rtl-dump-times "zero_extend:" 0 "ee" { target mips*-*-* } } } */ ++/* { dg-final { scan-rtl-dump "superfluous extension \[0-9\]+ replaced" "ee" { target mips*-*-* } } } */ ++/* { dg-final { cleanup-rtl-dump "ee" } } */ ++ + +=== added file 'gcc/testsuite/gcc.dg/extend-4.c' +--- old/gcc/testsuite/gcc.dg/extend-4.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.dg/extend-4.c 2010-12-10 15:33:37 +0000 +@@ -0,0 +1,13 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-rtl-ee" } */ ++ ++unsigned char f(unsigned int a) ++{ ++ unsigned int b = a & 0x10ff; ++ return b; ++} ++ ++/* { dg-final { scan-rtl-dump-times "and:" 0 "ee" { target mips*-*-* } } } */ ++/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 1 "ee" { target mips*-*-* } } } */ ++/* { dg-final { cleanup-rtl-dump "ee" } } */ ++ + +=== modified file 'gcc/timevar.def' +--- old/gcc/timevar.def 2009-11-27 12:43:08 +0000 ++++ new/gcc/timevar.def 2010-12-10 15:33:37 +0000 +@@ -162,6 +162,7 @@ + DEFTIMEVAR (TV_VARCONST , "varconst") + DEFTIMEVAR (TV_LOWER_SUBREG , "lower subreg") + DEFTIMEVAR (TV_JUMP , "jump") ++DEFTIMEVAR (TV_EE , "extension elimination") + DEFTIMEVAR (TV_FWPROP , "forward prop") + DEFTIMEVAR (TV_CSE , "CSE") + DEFTIMEVAR (TV_DCE , "dead code elimination") + +=== modified file 'gcc/tree-pass.h' +--- old/gcc/tree-pass.h 2010-09-01 13:29:58 +0000 ++++ new/gcc/tree-pass.h 2010-12-10 15:33:37 +0000 +@@ -468,6 +468,7 @@ + extern struct rtl_opt_pass pass_initial_value_sets; + extern struct rtl_opt_pass pass_unshare_all_rtl; + extern struct rtl_opt_pass pass_instantiate_virtual_regs; ++extern struct rtl_opt_pass pass_ee; + extern struct rtl_opt_pass pass_rtl_fwprop; + extern struct rtl_opt_pass pass_rtl_fwprop_addr; + extern struct rtl_opt_pass pass_jump2; + diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99444.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99444.patch new file mode 100644 index 0000000000..80eebeec0c --- /dev/null +++ b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99444.patch @@ -0,0 +1,183 @@ +2010-12-02 Bernd Schmidt + + Issue #10089 + + gcc/ + * expr.c (store_field): Avoid a direct store if the mode is larger + than the size of the bit field. + * stor-layout.c (layout_decl): If flag_strict_volatile_bitfields, + treat non-volatile bit fields like volatile ones. + * toplev.c (process_options): Disallow combination of + -fstrict-volatile-bitfields and ABI versions less than 2. + * config/arm/arm.c (arm_option_override): Don't enable + flag_strict_volatile_bitfields if the ABI version is less than 2. + * config/h8300/h8300.c (h8300_option_override): Likewise. + * config/rx/rx.c (rx_option_override): Likewise. + * config/m32c/m32c.c (m32c_option_override): Likewise. + * config/sh/sh.c (sh_option_override): Likewise. + + gcc/testsuite/ + * gcc.target/arm/volatile-bitfields-4.c: New test. + * c-c++-common/abi-bf.c: New test. + +=== modified file 'gcc/config/arm/arm.c' +--- old/gcc/config/arm/arm.c 2010-12-10 15:30:47 +0000 ++++ new/gcc/config/arm/arm.c 2010-12-10 15:34:19 +0000 +@@ -1934,7 +1934,8 @@ + set_param_value ("gcse-unrestricted-cost", 2); + + /* ARM EABI defaults to strict volatile bitfields. */ +- if (TARGET_AAPCS_BASED && flag_strict_volatile_bitfields < 0) ++ if (TARGET_AAPCS_BASED && flag_strict_volatile_bitfields < 0 ++ && abi_version_at_least(2)) + flag_strict_volatile_bitfields = 1; + + /* Register global variables with the garbage collector. */ + +=== modified file 'gcc/config/h8300/h8300.c' +--- old/gcc/config/h8300/h8300.c 2010-11-04 12:43:52 +0000 ++++ new/gcc/config/h8300/h8300.c 2010-12-10 15:34:19 +0000 +@@ -405,7 +405,7 @@ + } + + /* This target defaults to strict volatile bitfields. */ +- if (flag_strict_volatile_bitfields < 0) ++ if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2)) + flag_strict_volatile_bitfields = 1; + } + + +=== modified file 'gcc/config/m32c/m32c.c' +--- old/gcc/config/m32c/m32c.c 2010-11-04 12:43:52 +0000 ++++ new/gcc/config/m32c/m32c.c 2010-12-10 15:34:19 +0000 +@@ -430,7 +430,7 @@ + flag_ivopts = 0; + + /* This target defaults to strict volatile bitfields. */ +- if (flag_strict_volatile_bitfields < 0) ++ if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2)) + flag_strict_volatile_bitfields = 1; + } + + +=== modified file 'gcc/config/rx/rx.c' +--- old/gcc/config/rx/rx.c 2010-11-04 12:43:52 +0000 ++++ new/gcc/config/rx/rx.c 2010-12-10 15:34:19 +0000 +@@ -2191,7 +2191,7 @@ + rx_option_override (void) + { + /* This target defaults to strict volatile bitfields. */ +- if (flag_strict_volatile_bitfields < 0) ++ if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2)) + flag_strict_volatile_bitfields = 1; + } + + +=== modified file 'gcc/config/sh/sh.c' +--- old/gcc/config/sh/sh.c 2010-11-04 12:43:52 +0000 ++++ new/gcc/config/sh/sh.c 2010-12-10 15:34:19 +0000 +@@ -952,7 +952,7 @@ + sh_fix_range (sh_fixed_range_str); + + /* This target defaults to strict volatile bitfields. */ +- if (flag_strict_volatile_bitfields < 0) ++ if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2)) + flag_strict_volatile_bitfields = 1; + } + + +=== modified file 'gcc/expr.c' +--- old/gcc/expr.c 2010-11-04 12:43:52 +0000 ++++ new/gcc/expr.c 2010-12-10 15:34:19 +0000 +@@ -5848,6 +5848,8 @@ + || bitpos % GET_MODE_ALIGNMENT (mode)) + && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))) + || (bitpos % BITS_PER_UNIT != 0))) ++ || (bitsize >= 0 && mode != BLKmode ++ && GET_MODE_BITSIZE (mode) > bitsize) + /* If the RHS and field are a constant size and the size of the + RHS isn't the same size as the bitfield, we must use bitfield + operations. */ + +=== modified file 'gcc/stor-layout.c' +--- old/gcc/stor-layout.c 2010-11-26 12:03:32 +0000 ++++ new/gcc/stor-layout.c 2010-12-10 15:34:19 +0000 +@@ -621,12 +621,13 @@ + /* See if we can use an ordinary integer mode for a bit-field. + Conditions are: a fixed size that is correct for another mode, + occupying a complete byte or bytes on proper boundary, +- and not volatile or not -fstrict-volatile-bitfields. */ ++ and not -fstrict-volatile-bitfields. If the latter is set, ++ we unfortunately can't check TREE_THIS_VOLATILE, as a cast ++ may make a volatile object later. */ + if (TYPE_SIZE (type) != 0 + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT +- && !(TREE_THIS_VOLATILE (decl) +- && flag_strict_volatile_bitfields > 0)) ++ && flag_strict_volatile_bitfields <= 0) + { + enum machine_mode xmode + = mode_for_size_tree (DECL_SIZE (decl), MODE_INT, 1); + +=== added file 'gcc/testsuite/c-c++-common/abi-bf.c' +--- old/gcc/testsuite/c-c++-common/abi-bf.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/c-c++-common/abi-bf.c 2010-12-10 15:34:19 +0000 +@@ -0,0 +1,3 @@ ++/* { dg-warning "incompatible" } */ ++/* { dg-do compile } */ ++/* { dg-options "-fstrict-volatile-bitfields -fabi-version=1" } */ + +=== added file 'gcc/testsuite/gcc.target/arm/volatile-bitfields-4.c' +--- old/gcc/testsuite/gcc.target/arm/volatile-bitfields-4.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.target/arm/volatile-bitfields-4.c 2010-12-10 15:34:19 +0000 +@@ -0,0 +1,30 @@ ++/* { dg-require-effective-target arm_eabi } */ ++/* { dg-do compile } */ ++/* { dg-options "-O2" } */ ++/* { dg-final { scan-assembler-times "ldr\[\\t \]+\[^\n\]*,\[\\t \]*\\\[\[^\n\]*\\\]" 2 } } */ ++/* { dg-final { scan-assembler-times "str\[\\t \]+\[^\n\]*,\[\\t \]*\\\[\[^\n\]*\\\]" 2 } } */ ++/* { dg-final { scan-assembler-not "strb" } } */ ++ ++struct thing { ++ unsigned a: 8; ++ unsigned b: 8; ++ unsigned c: 8; ++ unsigned d: 8; ++}; ++ ++struct thing2 { ++ volatile unsigned a: 8; ++ volatile unsigned b: 8; ++ volatile unsigned c: 8; ++ volatile unsigned d: 8; ++}; ++ ++void test1(volatile struct thing *t) ++{ ++ t->a = 5; ++} ++ ++void test2(struct thing2 *t) ++{ ++ t->a = 5; ++} + +=== modified file 'gcc/toplev.c' +--- old/gcc/toplev.c 2010-03-31 01:44:10 +0000 ++++ new/gcc/toplev.c 2010-12-10 15:34:19 +0000 +@@ -1851,6 +1851,13 @@ + sorry ("Graphite loop optimizations cannot be used"); + #endif + ++ if (flag_strict_volatile_bitfields > 0 && !abi_version_at_least (2)) ++ { ++ warning (0, "-fstrict-volatile-bitfield disabled; " ++ "it is incompatible with ABI versions < 2"); ++ flag_strict_volatile_bitfields = 0; ++ } ++ + /* Unrolling all loops implies that standard loop unrolling must also + be done. */ + if (flag_unroll_all_loops) + -- cgit 1.2.3-korg