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