[oe] [PATCH] gcc-4.5: Apply patches upto 2010.12 release of linaro gcc

Khem Raj raj.khem at gmail.com
Tue Dec 21 05:58:22 UTC 2010


This patch brings in more Linaro patches. So far I have built a x11-image
for qemuarm and it has shown no issues. I plan to test it more thoroughly
in coming days on different arches and different images and also run gcc
regression testsuite for them. But while I do this I wanted to bring it to
everyone who would be interested to try and test the patch out and report
any issues one sees and we could weed them out before installing this patch

-Khem

Signed-off-by: Khem Raj <raj.khem at gmail.com>
---
 recipes/gcc/gcc-4.5.inc                            |   20 +-
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99421.patch |   94 ++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99423.patch |  114 ++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99424.patch |  687 +++++++++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99425.patch |  128 ++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99426.patch |   41 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99429.patch | 1257 ++++++++++++++++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch |   70 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99433.patch |   40 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99434.patch |   30 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99435.patch |   32 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99436.patch |  209 +++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99437.patch |   27 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch | 1500 ++++++++++++++++++++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch |   78 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99441.patch |   33 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99442.patch |   23 +
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch |  873 ++++++++++++
 .../gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99444.patch |  183 +++
 19 files changed, 5438 insertions(+), 1 deletions(-)
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99421.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99423.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99424.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99425.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99426.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99429.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99433.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99434.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99435.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99436.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99437.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99439.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99441.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99442.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch
 create mode 100644 recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99444.patch

diff --git a/recipes/gcc/gcc-4.5.inc b/recipes/gcc/gcc-4.5.inc
index a44fe1a..d5c17e7 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 0000000..3a45ee5
--- /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 at codesourcery.com>
+
+	Issue #9781
+
+	Backport from mainline:
+
+	gcc/
+	2010-10-20  Nathan Froyd  <froydnj at 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 0000000..80dbe3f
--- /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 at codesourcery.com>
+
+	Issue #9812
+
+	Backport from mainline:
+
+	gcc/
+	2010-10-25  Jie Zhang  <jie at 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 at 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 0000000..b6c6532
--- /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 at 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 at codesourcery.com>
+
+	* doc/invoke.texi: Add -fstrict-volatile-bitfields to
+	Option Summary and Index.
+
+	2010-07-13  DJ Delorie  <dj at 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 at 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 at gmail.com>
+
+	PR testsuite/45324
+	* gcc.target/i386/volatile-bitfields-1.c: Also scan movb.
+
+	2010-06-16  DJ Delorie  <dj at 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}}.
+ 
++ at item -fstrict-volatile-bitfields
++ at 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 0000000..17839c0
--- /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 at codesourcery.com>
+
+	Issue #1259
+
+	Backport from mainline:
+
+	gcc/
+	2010-10-26  Jie Zhang  <jie at 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 at 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 0000000..cf06e1f
--- /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 at 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 0000000..63ba95e
--- /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 at linaro.org>
+
+	Revert:
+
+	Backport from mainline:
+
+	2010-07-15  Bernd Schmidt  <bernds at 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 at 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 at 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 at 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 at 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 at 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 at 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 0000000..b63c9b3
--- /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 at 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 0000000..6bc33f2
--- /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 at 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 0000000..adda68c
--- /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 at codesourcery.com>
+
+	Backport from mainline:
+
+	2010-11-02  Chung-Lin Tang <cltang at 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 0000000..d66df13
--- /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 at codesourcery.com>
+
+	Backport from mainline:
+
+	gcc/
+	2010-08-02  Bernd Schmidt  <bernds at 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 0000000..deb749e
--- /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 at 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 0000000..94d9666
--- /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 at linaro.org>
+
+	Launchpad #618684
+
+	Backport from mainline:
+
+	2010-04-10  Bernd Schmidt  <bernds at 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 0000000..cec7f57
--- /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 at codesourcery.com>
+
+	2010-07-21  Richard Henderson  <rth at 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 at 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 at codesourcery.com>
+
+	Re-merge, backport from mainline:
+
+	2010-07-15  Bernd Schmidt  <bernds at 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 at 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 at 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 at 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 at 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 at 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 at 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 0000000..b7a28de
--- /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 at codesourcery.com>
+
+	2010-07-08  Ramana Radhakrishnan  <ramana.radhakrishnan at 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 0000000..5495b8d
--- /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 at codesourcery.com>
+
+	Backport from mainline:
+
+	2010-10-28  Andrew Stubbs  <ams at 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 0000000..62c4478
--- /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 at 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 0000000..802c381
--- /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 at 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 at 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 0000000..80eebee
--- /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 at 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)
+
-- 
1.7.0.4





More information about the Openembedded-devel mailing list