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

Koen Kooi k.kooi at student.utwente.nl
Thu Dec 23 08:33:37 UTC 2010


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 21-12-10 06:58, Khem Raj wrote:
> 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>

Acked-by: Koen Kooi <koen at openembedded.org>

Tested for armv7a


> ---
>  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)
> +

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)

iD8DBQFNEwlgMkyGM64RGpERAq80AJ4jxf9uGM4O5jsl0MnSK+AVpnB/qACcCkBl
Qt+smOkpp4x6brrHlvAmsb0=
=nKud
-----END PGP SIGNATURE-----





More information about the Openembedded-devel mailing list